diff --git a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/SnakesHelper.java b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/SnakesHelper.java index f79d66ae..b7231eaf 100644 --- a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/SnakesHelper.java +++ b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/generator/SnakesHelper.java @@ -19,6 +19,7 @@ import nl.esi.xtext.actions.actions.ActionList; import nl.esi.xtext.actions.actions.AssignmentAction; import nl.esi.xtext.actions.actions.ForAction; +import nl.esi.xtext.actions.actions.FunctionCall; import nl.esi.xtext.actions.actions.IfAction; import nl.esi.xtext.actions.actions.RecordFieldAssignmentAction; import nl.esi.xtext.expressions.expression.Expression; @@ -273,22 +274,19 @@ static String action(Action action, Function variableRename) { } private static String action(Action action, Function variableRename, String indent) { - if (action instanceof AssignmentAction) { - AssignmentAction a = (AssignmentAction) action; + if (action instanceof AssignmentAction a) { // String variable = String.format("%s%s", variablePrefix.apply(a.getAssignment().getName()), a.getAssignment().getName()); String variable = String.format("%s", variableRename.apply(a.getAssignment().getName())); // if(a.isSymbolic()) return String.format("%s = %s%s%s", variable, QUOTE, expression(a.getExp(), variablePrefix).replace("\"", "\\\""), QUOTE); return String.format("%s = %s", variable, expression(a.getExp(), variableRename)); - } else if (action instanceof RecordFieldAssignmentAction) { - RecordFieldAssignmentAction a = (RecordFieldAssignmentAction) action; + } else if (action instanceof RecordFieldAssignmentAction a) { ExpressionRecordAccess access = (ExpressionRecordAccess) a.getFieldAccess(); String record = expression(access.getRecord(), variableRename); String field = access.getField().getName(); String value = expression(a.getExp(), variableRename); return String.format("%s[\"%s\"] = %s", record, field, value); - } else if(action instanceof IfAction) { + } else if(action instanceof IfAction act) { var txt = new String(); - var act = (IfAction) action; txt += String.format("if %s:\n",expression(act.getGuard(), variableRename)); txt += indentActionList(act.getThenList(), variableRename, indent); if(act.getElseList()!= null) { @@ -296,14 +294,16 @@ private static String action(Action action, Function variableRen txt += indentActionList(act.getElseList(), variableRename, indent); } return txt.trim(); - } else if(action instanceof ForAction) { + } else if(action instanceof ForAction act) { var txt = new String(); - var act = (ForAction) action; txt += String.format("for %s in %s:\n", act.getVar().getName(), expression(act.getExp(), variableRename)); txt += indentActionList(act.getDoList(), variableRename, indent); return txt.trim(); - } - + } else if(action instanceof FunctionCall functionCall) { + var txt = new String(); + txt += expression(functionCall.getExp()); + return txt.trim(); + } throw new RuntimeException("Not supported"); } diff --git a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/validation/ProductValidator.xtend b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/validation/ProductValidator.xtend index 46c5a379..0262ff12 100644 --- a/bundles/nl.asml.matala.product/src/nl/asml/matala/product/validation/ProductValidator.xtend +++ b/bundles/nl.asml.matala.product/src/nl/asml/matala/product/validation/ProductValidator.xtend @@ -50,6 +50,7 @@ import static extension nl.esi.xtext.common.lang.utilities.EcoreUtil3.* import static extension nl.esi.xtext.types.utilities.TypeUtilities.* import static extension org.eclipse.lsat.common.xtend.Queries.* import static extension org.eclipse.xtext.EcoreUtil2.* +import nl.esi.xtext.actions.actions.FunctionCall /** * This class contains custom validation rules. @@ -129,7 +130,7 @@ class ProductValidator extends AbstractProductValidator { * All variables occurring in a guard expression must have been defined as inputs of an action */ @Check - def preventIlligalVariableAccess(Function function) { + def preventIllegalVariableAccess(Function function) { for (update : function.updates) { if (update.guard !== null) { val Set inputs = newHashSet @@ -157,60 +158,64 @@ class ProductValidator extends AbstractProductValidator { * Note that attributes of this variable may be referenced in the LHS expression (record field access) */ @Check - def void preventIlligalVariableAccess(Update update) { + def void preventIllegalVariableAccess(Update update) { /* Variables occurring in the RHS of an update expression must have been defined as inputs of an action. */ for (updateOutVar : update.updateOutputVar.reject[act === null]) { val inputs = update.fnInp.map[ref].toSet val outputs = updateOutVar.fnOut.map[ref].toSet - updateOutVar.act.actions.forEach[preventIlligalVariableAccess(inputs, outputs)] + updateOutVar.act.actions.forEach[preventIllegalVariableAccess(inputs, outputs)] } } - private dispatch def void preventIlligalVariableAccess(AssignmentAction action, Set inputs, Set outputs) { + private dispatch def void preventIllegalVariableAccess(AssignmentAction action, Set inputs, Set outputs) { if (!outputs.contains(action.assignment)) { error('''Variable '«action.assignment.name»' is not defined as an output''', action, ActionsPackage.Literals.ASSIGNMENT_ACTION__ASSIGNMENT) } - action.exp?.preventIlligalExpressionVariableAccess(inputs, Direction::input) + action.exp?.preventIllegalExpressionVariableAccess(inputs, Direction::input) // As the variable is now assigned, we can also use it as input (imperative programming) inputs += action.assignment } - private dispatch def void preventIlligalVariableAccess(RecordFieldAssignmentAction action, Set inputs, Set outputs) { - action.fieldAccess?.preventIlligalExpressionVariableAccess(outputs, Direction::output) - action.exp?.preventIlligalExpressionVariableAccess(inputs, Direction::input) + private dispatch def void preventIllegalVariableAccess(RecordFieldAssignmentAction action, Set inputs, Set outputs) { + action.fieldAccess?.preventIllegalExpressionVariableAccess(outputs, Direction::output) + action.exp?.preventIllegalExpressionVariableAccess(inputs, Direction::input) } - private dispatch def void preventIlligalVariableAccess(ForAction action, Set inputs, Set outputs) { - action.exp?.preventIlligalExpressionVariableAccess(inputs, Direction::input) + private dispatch def void preventIllegalVariableAccess(ForAction action, Set inputs, Set outputs) { + action.exp?.preventIllegalExpressionVariableAccess(inputs, Direction::input) if (action.doList !== null) { val doInputs = new HashSet(inputs) doInputs += action.^var - action.doList.actions.forEach[preventIlligalVariableAccess(doInputs, outputs)] + action.doList.actions.forEach[preventIllegalVariableAccess(doInputs, outputs)] } } - private dispatch def void preventIlligalVariableAccess(IfAction action, Set inputs, Set outputs) { - action.guard?.preventIlligalExpressionVariableAccess(inputs, Direction::input) + private dispatch def void preventIllegalVariableAccess(IfAction action, Set inputs, Set outputs) { + action.guard?.preventIllegalExpressionVariableAccess(inputs, Direction::input) if (action.thenList !== null) { - action.thenList.actions.forEach[preventIlligalVariableAccess(inputs, outputs)] + action.thenList.actions.forEach[preventIllegalVariableAccess(inputs, outputs)] } if (action.thenList !== null) { - action.thenList.actions.forEach[preventIlligalVariableAccess(inputs, outputs)] + action.thenList.actions.forEach[preventIllegalVariableAccess(inputs, outputs)] } } + private dispatch def void preventIllegalVariableAccess(FunctionCall action, Set inputs, Set outputs) { + action.exp?.preventIllegalExpressionVariableAccess(inputs, Direction::input) + } + private enum Direction { input, output } - private dispatch def void preventIlligalExpressionVariableAccess(ExpressionVariable exprVar, Set variables, Direction direction) { + private dispatch def void preventIllegalExpressionVariableAccess(ExpressionVariable exprVar, Set variables, Direction direction) { if (!variables.contains(exprVar.variable)) { error('''Variable '«exprVar.variable.name»' is not defined as an «direction»''', exprVar, ExpressionPackage.Literals.EXPRESSION_VARIABLE__VARIABLE) } } - private dispatch def void preventIlligalExpressionVariableAccess(Expression expr, Set variables, Direction direction) { + private dispatch def void preventIllegalExpressionVariableAccess(Expression expr, Set variables, Direction direction) { // Finds child expressions, but allows other classes in between (e.g. Record Field) val subExpressions = #[expr as EObject].walkTree[eContents].findNearest(Expression) - subExpressions.forEach[preventIlligalExpressionVariableAccess(variables, direction)] + subExpressions.forEach[preventIllegalExpressionVariableAccess(variables, direction)] } /** @@ -305,6 +310,10 @@ class ProductValidator extends AbstractProductValidator { action.exp.reportWarningOnAccess(RecordFieldKind::SYMBOLIC)[ field | '''Symbolic record field should not be used in «property»'''] } + dispatch def private void doCheckConcreteVariableUpdate(FunctionCall action, String property) { + action.exp.reportWarningOnAccess(RecordFieldKind::SYMBOLIC)[ field | '''Symbolic record field should not be used in «property»'''] + } + private def reportWarningOnAccess(Expression expression, RecordFieldKind accessKind, (RecordField)=>String messageProducer) { Iterators.concat(#[expression].iterator, expression.eAllContents).forEach [ eObject | switch (it: eObject) {