blob: 9e84fe0eaee46c1edda671de708addc0848f808f [file] [log] [blame]
/*******************************************************************************
* CHESS core plugin
*
* Copyright (C) 2011-2015
* Mälardalen University, Sweden
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License
* v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.polarsys.chess.fla.flamm;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.MinimalEObjectImpl;
import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.ecore.util.InternalEList;
import org.polarsys.chess.fla.flamm.FailureTypes.FailureType;
import org.polarsys.chess.fla.flamm.analysis.FlaSystem;
/**
* <!-- begin-user-doc -->
* A representation of the model object '<em><b>Rule</b></em>'.
* <!-- end-user-doc -->
*
* <p>
* The following features are supported:
* </p>
* <ul>
* <li>{@link org.polarsys.chess.fla.flamm.Rule#getInputExpression <em>Input Expression</em>}</li>
* <li>{@link org.polarsys.chess.fla.flamm.Rule#getOutputExpression <em>Output Expression</em>}</li>
* <li>{@link org.polarsys.chess.fla.flamm.Rule#getSpecificity <em>Specificity</em>}</li>
* </ul>
*
* @see org.polarsys.chess.fla.flamm.FlammPackage#getRule()
* @model kind="class"
* @generated
*/
public class Rule extends MinimalEObjectImpl.Container implements EObject {
/**
* The cached value of the '{@link #getInputExpression() <em>Input Expression</em>}' containment reference list.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getInputExpression()
* @generated
* @ordered
*/
protected EList<Expression> inputExpression;
/**
* The cached value of the '{@link #getOutputExpression() <em>Output Expression</em>}' containment reference list.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getOutputExpression()
* @generated
* @ordered
*/
protected EList<Expression> outputExpression;
/**
* Used to keep information about failure types matched to variables.
*/
private transient Map<String, Failure> variableAssignments = new HashMap<String, Failure>();
/**
* The default value of the '{@link #getSpecificity() <em>Specificity</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getSpecificity()
* @generated
* @ordered
*/
protected static final int SPECIFICITY_EDEFAULT = -1;
/**
* The cached value of the '{@link #getSpecificity() <em>Specificity</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getSpecificity()
* @generated
* @ordered
*/
protected int specificity = SPECIFICITY_EDEFAULT;
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public Rule() {
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return FlammPackage.Literals.RULE;
}
/**
* Returns the value of the '<em><b>Input Expression</b></em>' containment reference list.
* The list contents are of type {@link org.polarsys.chess.fla.flamm.Expression}.
* <!-- begin-user-doc -->
* <p>
* If the meaning of the '<em>Input Expression</em>' containment reference list isn't clear,
* there really should be more of a description here...
* </p>
* <!-- end-user-doc -->
* @return the value of the '<em>Input Expression</em>' containment reference list.
* @see org.polarsys.chess.fla.flamm.FlammPackage#getRule_InputExpression()
* @model containment="true"
* @generated
*/
public List<Expression> getInputExpression() {
if (inputExpression == null) {
inputExpression = new EObjectContainmentEList<Expression>(Expression.class, this, FlammPackage.RULE__INPUT_EXPRESSION);
}
return inputExpression;
}
/**
* Returns the value of the '<em><b>Output Expression</b></em>' containment reference list.
* The list contents are of type {@link org.polarsys.chess.fla.flamm.Expression}.
* <!-- begin-user-doc -->
* <p>
* If the meaning of the '<em>Output Expression</em>' containment reference list isn't clear,
* there really should be more of a description here...
* </p>
* <!-- end-user-doc -->
* @return the value of the '<em>Output Expression</em>' containment reference list.
* @see org.polarsys.chess.fla.flamm.FlammPackage#getRule_OutputExpression()
* @model containment="true"
* @generated
*/
public List<Expression> getOutputExpression() {
if (outputExpression == null) {
outputExpression = new EObjectContainmentEList<Expression>(Expression.class, this, FlammPackage.RULE__OUTPUT_EXPRESSION);
}
return outputExpression;
}
/**
* Returns the value of the '<em><b>Specificity</b></em>' attribute.
* The default value is <code>"-1"</code>.
* <!-- begin-user-doc -->
* <p>
* If the meaning of the '<em>Specificity</em>' attribute isn't clear,
* there really should be more of a description here...
* </p>
* <!-- end-user-doc -->
* @return the value of the '<em>Specificity</em>' attribute.
* @see #setSpecificity(int)
* @generated NOT
*/
public int getSpecificity() {
if (specificity == -1) {
calculateSpecificity();
}
return specificity;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
switch (featureID) {
case FlammPackage.RULE__INPUT_EXPRESSION:
return ((InternalEList<?>)getInputExpression()).basicRemove(otherEnd, msgs);
case FlammPackage.RULE__OUTPUT_EXPRESSION:
return ((InternalEList<?>)getOutputExpression()).basicRemove(otherEnd, msgs);
}
return super.eInverseRemove(otherEnd, featureID, msgs);
}
protected void calculateSpecificity() {
int calculatedSpecificity = 0;
for (Expression inputExpression : inputExpression) {
if (!expressionContainsVariableOrWildcard(inputExpression)) {
calculatedSpecificity++;
}
}
this.specificity = calculatedSpecificity;
}
private boolean expressionContainsVariableOrWildcard(Expression expression) {
for (Failure failure : expression.getFailures()) {
if (FailureType.WILDCARD == failure.getType() || FailureType.VARIABLE == failure.getType()) {
return true;
}
}
return false;
}
/**
* Check if the list of failures are matched by this rule.
* @param failuresetToMatch list of PortFailureTuples to check
* @return <code>true</code> if this rule is covering the failuresetToMatch failures
*/
public boolean matchFailure(List<PortFailureTuple> failuresetToMatch) {
variableAssignments.clear();
for (PortFailureTuple failureTupleToMatch : failuresetToMatch) {
Expression portInputExpression = getInputExpressionForPort(failureTupleToMatch.getPort());
if (portInputExpression == null || portInputExpression.getFailures().isEmpty()) {
// port not present in this transformation rule
// treat as wildcard
if (FlaSystem.treatUnmentionedPortsAsWildcards()){
continue;
} else {
// TODO: warn user
return false;
}
}
List<Failure> rulePortFailures = portInputExpression.getFailures();
boolean match = false;
for (Failure ruleFailure : rulePortFailures) {
if (ruleFailure.getType() == FailureType.WILDCARD) {
match = true;
break;
} else if (ruleFailure.getType() == FailureType.VARIABLE) {
Failure prevVariableAssignment = variableAssignments.get(ruleFailure.getId());
if (prevVariableAssignment != null && ! prevVariableAssignment.isSameFailure(failureTupleToMatch.getFailure())) {
// The same variable cannot map to different failure types simultaneously
continue;
}
variableAssignments.put(ruleFailure.getId(), failureTupleToMatch.getFailure());
match = true;
break;
} else if (ruleFailure.isSameFailure(failureTupleToMatch.getFailure())) {
match = true;
break;
}
}
if (!match) {
// Failure is not matched with rule for current port.
return false;
}
}
return true;
}
protected Expression getInputExpressionForPort(Port port) {
return getExpressionForPort(inputExpression, port);
}
protected Expression getOutputExpressionForPort(Port port) {
return getExpressionForPort(outputExpression, port);
}
private Expression getExpressionForPort(List<Expression> expressions, Port port) {
if (port != null) {
for (Expression expression : expressions) {
if (port.equals(expression.getPort())) {
return expression;
}
}
}
return null;
}
/**
* Transform and propagate failures to the output ports according to this rule.
*/
public void fire() {
for (Expression expression : getOutputExpression()) {
Port port = expression.getPort();
for (Failure failure : expression.getFailures()) {
if (failure.getType() == FailureType.VARIABLE) {
port.addFailure(variableAssignments.get(failure.getId()));
} else {
port.addFailure(failure);
}
}
}
}
/**
* Transform and propagate failures to the output ports according to this rule.
*/
public void fire(Collection<Failure> previousFailures) {
for (Expression expression : getOutputExpression()) {
Port port = expression.getPort();
for (Failure failure : expression.getFailures()) {
if (failure.getType() == FailureType.VARIABLE) {
port.addFailure(variableAssignments.get(failure.getId()), previousFailures);
} else {
port.addFailure(failure, previousFailures);
}
}
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case FlammPackage.RULE__INPUT_EXPRESSION:
return getInputExpression();
case FlammPackage.RULE__OUTPUT_EXPRESSION:
return getOutputExpression();
case FlammPackage.RULE__SPECIFICITY:
return getSpecificity();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@SuppressWarnings("unchecked")
@Override
public void eSet(int featureID, Object newValue) {
switch (featureID) {
case FlammPackage.RULE__INPUT_EXPRESSION:
getInputExpression().clear();
getInputExpression().addAll((Collection<? extends Expression>)newValue);
return;
case FlammPackage.RULE__OUTPUT_EXPRESSION:
getOutputExpression().clear();
getOutputExpression().addAll((Collection<? extends Expression>)newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eUnset(int featureID) {
switch (featureID) {
case FlammPackage.RULE__INPUT_EXPRESSION:
getInputExpression().clear();
return;
case FlammPackage.RULE__OUTPUT_EXPRESSION:
getOutputExpression().clear();
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case FlammPackage.RULE__INPUT_EXPRESSION:
return inputExpression != null && !inputExpression.isEmpty();
case FlammPackage.RULE__OUTPUT_EXPRESSION:
return outputExpression != null && !outputExpression.isEmpty();
case FlammPackage.RULE__SPECIFICITY:
return specificity != SPECIFICITY_EDEFAULT;
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public String toString() {
if (eIsProxy()) return super.toString();
StringBuffer result = new StringBuffer(super.toString());
result.append(" (specificity: ");
result.append(specificity);
result.append(')');
return result.toString();
}
} // Rule