diff --git a/plugins/core/hu.bme.mit.gamma.eventpriority.transformation/src/hu/bme/mit/gamma/eventpriority/transformation/CompletenessTrapStateInjector.xtend b/plugins/core/hu.bme.mit.gamma.eventpriority.transformation/src/hu/bme/mit/gamma/eventpriority/transformation/CompletenessTrapStateInjector.xtend index f361eec4b..dd341b14a 100644 --- a/plugins/core/hu.bme.mit.gamma.eventpriority.transformation/src/hu/bme/mit/gamma/eventpriority/transformation/CompletenessTrapStateInjector.xtend +++ b/plugins/core/hu.bme.mit.gamma.eventpriority.transformation/src/hu/bme/mit/gamma/eventpriority/transformation/CompletenessTrapStateInjector.xtend @@ -67,7 +67,7 @@ class CompletenessTrapStateInjector { } else { val defaultGuard = outgoingTransitions.createDefaultGuard - trapTransition.trigger = createOnCycleTrigger + trapTransition.trigger = statechartFactory.createOnCycleTrigger trapTransition.guard = defaultGuard } } diff --git a/plugins/core/hu.bme.mit.gamma.expression.model/src/hu/bme/mit/gamma/expression/util/ExpressionUtil.java b/plugins/core/hu.bme.mit.gamma.expression.model/src/hu/bme/mit/gamma/expression/util/ExpressionUtil.java index 0140c3d5f..4f9d6aedd 100644 --- a/plugins/core/hu.bme.mit.gamma.expression.model/src/hu/bme/mit/gamma/expression/util/ExpressionUtil.java +++ b/plugins/core/hu.bme.mit.gamma.expression.model/src/hu/bme/mit/gamma/expression/util/ExpressionUtil.java @@ -692,6 +692,16 @@ public Set getReferredValues(Expression expression) { return referred; } + public EnumerationLiteralDefinition getEnumerationLiteralDefinitionByName(EnumerationTypeDefinition typeDefinition, String name) { + for (EnumerationLiteralDefinition literal : typeDefinition.getLiterals()) { + String enumLiteralName = literal.getName(); + if (enumLiteralName.equals(name)) { + return literal; + } + } + throw new IllegalArgumentException("No EnumerationLiteralDefinition found in: " + typeDefinition + " for name: " + name); + } + // Extract parameters public List extractParameters(ParametricElement parametricElement, @@ -1719,6 +1729,12 @@ public EnumerationLiteralExpression createEnumerationLiteralExpression( return literalExpression; } + public EnumerationLiteralExpression createEnumerationLiteralExpression( + EnumerationTypeDefinition typeDefinition, String name) { + EnumerationLiteralDefinition enumLiteralDefinition = getEnumerationLiteralDefinitionByName(typeDefinition, name); + return createEnumerationLiteralExpression(enumLiteralDefinition); + } + public SubtractExpression createSubtractExpression(Expression lhs, Expression rhs) { SubtractExpression subtractExpression = factory.createSubtractExpression(); subtractExpression.setLeftOperand(lhs); diff --git a/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/StatechartLanguage.xtext b/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/StatechartLanguage.xtext index c1a27ed6f..ef51a8de2 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/StatechartLanguage.xtext +++ b/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/StatechartLanguage.xtext @@ -441,8 +441,9 @@ DeepHistoryState returns DeepHistoryState: Component returns InterfaceModel::Component: SynchronousComponent | - AsynchronousComponent | - CoordinationStatechartDefinition + AsynchronousComponent | + SynchronousCoordinationStatechartDefinition | + AsynchronousCoordinationStatechartDefinition ; SynchronousComponent returns CompositeModel::SynchronousComponent: @@ -748,7 +749,7 @@ ComponentInstanceReflectiveElementReferenceExpression returns CompositeModel::Co // -CoordinationStatechartDefinition returns CoordinationStatechartDefinition: +SynchronousCoordinationStatechartDefinition returns SynchronousCoordinationStatechartDefinition: '@Coordination' ( ('@RegionSchedule' '=' schedulingOrder=SchedulingOrder)? & @@ -759,20 +760,91 @@ CoordinationStatechartDefinition returns CoordinationStatechartDefinition: annotations+=StatechartContractAnnotation )* ) - 'statechart' name=ID + 'coordination-statechart' name=ID ('(' ((parameterDeclarations+=ParameterDeclaration)(',' parameterDeclarations+=ParameterDeclaration)*)? ')')? - ('[' ((ports+=Port)((',')? ports+=Port)*)? ']')? '{' - ( - variableDeclarations+=VariableDeclaration | - timeoutDeclarations+=TimeoutDeclaration | - ('invariant' invariants+=Expression) - )* - ( - regions+=Region | - transitions+=Transition - )* - functionDeclarations+=FunctionDeclaration* + ('[' ((ports+=Port)((',')? ports+=Port)*)? ']')? + '{' + ( + components+=SynchronousComponentInstance | + portBindings+=PortBinding | + channels+=Channel + )* '}' + '<' + ( + variableDeclarations+=VariableDeclaration | + timeoutDeclarations+=TimeoutDeclaration | + ('invariant' invariants+=Expression) + )* + ( + regions+=Region | + coordinationTransitions+=CoordinationTransition + )* + functionDeclarations+=FunctionDeclaration* + '>' +; + +AsynchronousCoordinationStatechartDefinition returns AsynchronousCoordinationStatechartDefinition: + '@Coordination' + '@Asynchronous' + ( + ('@RegionSchedule' '=' schedulingOrder=SchedulingOrder)? & + ('@OrthogonalRegionSchedule' '=' orthogonalRegionSchedulingOrder=OrthogonalRegionSchedulingOrder)? & + ('@TransitionPriority' '=' transitionPriority=TransitionPriority)? & + ('@GuardEvaluation' '=' guardEvaluation=GuardEvaluation)? & + ( annotations+=ComponentAnnotation | + annotations+=StatechartContractAnnotation + )* + ) + 'coordination-statechart' name=ID + ('(' ((parameterDeclarations+=ParameterDeclaration)(',' parameterDeclarations+=ParameterDeclaration)*)? ')')? + ('[' ((ports+=Port)((',')? ports+=Port)*)? ']')? + '{' + ( + components+=AsynchronousComponentInstance | + portBindings+=PortBinding | + channels+=Channel + )* + '}' + '<' + ( + variableDeclarations+=VariableDeclaration | + timeoutDeclarations+=TimeoutDeclaration | + ('invariant' invariants+=Expression) + )* + ( + regions+=Region | + coordinationTransitions+=CoordinationTransition + )* + functionDeclarations+=FunctionDeclaration* + '>' +; + +AbstractCoordinationReferenceExpression returns AbstractCoordinationReferenceExpression: + SequentialCoordinationReferenceExpression + | UnorderedCoordinationReferenceExpression +; + +SequentialCoordinationReferenceExpression returns SequentialCoordinationReferenceExpression: + 'seq' '{' instances+=ComponentInstanceReferenceExpression ((',') instances+=ComponentInstanceReferenceExpression)* '}' + | instances+=ComponentInstanceReferenceExpression +; + +UnorderedCoordinationReferenceExpression returns UnorderedCoordinationReferenceExpression: + 'unord' '{' instances+=ComponentInstanceReferenceExpression ((',') instances+=ComponentInstanceReferenceExpression)* '}' +; + +CoordinationTransition returns CoordinationTransition: + + (annotations+=TransitionAnnotation)* + 'transition' ('(' priority=INTEGER ')')? + 'from' sourceState=[StateNode] 'to' targetState=[StateNode] + + ('when' trigger=Trigger)? + ('[' guard=Expression ']')? + ('execute' coordinatedComponent=AbstractCoordinationReferenceExpression)? + ('/' ( => effects+=Action)* )? + ; // \ No newline at end of file diff --git a/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/scoping/StatechartLanguageScopeProvider.java b/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/scoping/StatechartLanguageScopeProvider.java index f00fc8bfe..409778081 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/scoping/StatechartLanguageScopeProvider.java +++ b/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/scoping/StatechartLanguageScopeProvider.java @@ -377,7 +377,7 @@ public IScope getScope(final EObject context, final EReference reference) { return super.getScope(context, reference); } catch (Exception e) { e.printStackTrace(); - } + } return super.getScope(context, reference); } diff --git a/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/validation/StatechartLanguageValidator.java b/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/validation/StatechartLanguageValidator.java index 908fde9a4..df58d0053 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/validation/StatechartLanguageValidator.java +++ b/plugins/core/hu.bme.mit.gamma.statechart.language/src/hu/bme/mit/gamma/statechart/language/validation/StatechartLanguageValidator.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2018-2024 Contributors to the Gamma project + * Copyright (c) 2018-2025 Contributors to the Gamma project * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 diff --git a/plugins/core/hu.bme.mit.gamma.statechart.model/model/statechart.ecore b/plugins/core/hu.bme.mit.gamma.statechart.model/model/statechart.ecore index 6d4349831..e51d46af0 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.model/model/statechart.ecore +++ b/plugins/core/hu.bme.mit.gamma.statechart.model/model/statechart.ecore @@ -166,6 +166,28 @@ - - + + + + + + + + + + + + + + diff --git a/plugins/core/hu.bme.mit.gamma.statechart.model/model/statechart.genmodel b/plugins/core/hu.bme.mit.gamma.statechart.model/model/statechart.genmodel index ddc96687b..fc69a42df 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.model/model/statechart.genmodel +++ b/plugins/core/hu.bme.mit.gamma.statechart.model/model/statechart.genmodel @@ -402,7 +402,19 @@ - - + + + + + + + + + + + + + + diff --git a/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/derivedfeatures/StatechartModelDerivedFeatures.java b/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/derivedfeatures/StatechartModelDerivedFeatures.java index e59ec411c..2973cc9b6 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/derivedfeatures/StatechartModelDerivedFeatures.java +++ b/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/derivedfeatures/StatechartModelDerivedFeatures.java @@ -50,6 +50,7 @@ import hu.bme.mit.gamma.expression.model.TypeDeclaration; import hu.bme.mit.gamma.expression.model.TypeDefinition; import hu.bme.mit.gamma.expression.model.TypeReference; +import hu.bme.mit.gamma.expression.model.VariableDeclaration; import hu.bme.mit.gamma.statechart.composite.AbstractAsynchronousCompositeComponent; import hu.bme.mit.gamma.statechart.composite.AbstractSynchronousCompositeComponent; import hu.bme.mit.gamma.statechart.composite.AsynchronousAdapter; @@ -108,11 +109,14 @@ import hu.bme.mit.gamma.statechart.phase.MissionPhaseAnnotation; import hu.bme.mit.gamma.statechart.phase.MissionPhaseStateAnnotation; import hu.bme.mit.gamma.statechart.statechart.AnyPortEventReference; +import hu.bme.mit.gamma.statechart.statechart.AsynchronousCoordinationStatechartDefinition; import hu.bme.mit.gamma.statechart.statechart.AsynchronousStatechartDefinition; import hu.bme.mit.gamma.statechart.statechart.BinaryTrigger; import hu.bme.mit.gamma.statechart.statechart.ChoiceState; import hu.bme.mit.gamma.statechart.statechart.ClockTickReference; import hu.bme.mit.gamma.statechart.statechart.CompositeElement; +import hu.bme.mit.gamma.statechart.statechart.CoordinationStatechartDefinition; +import hu.bme.mit.gamma.statechart.statechart.CoordinationVariableDeclarationAnnotation; import hu.bme.mit.gamma.statechart.statechart.DeepHistoryState; import hu.bme.mit.gamma.statechart.statechart.EntryState; import hu.bme.mit.gamma.statechart.statechart.ForkState; @@ -132,6 +136,7 @@ import hu.bme.mit.gamma.statechart.statechart.StateNode; import hu.bme.mit.gamma.statechart.statechart.StatechartAnnotation; import hu.bme.mit.gamma.statechart.statechart.StatechartDefinition; +import hu.bme.mit.gamma.statechart.statechart.SynchronousCoordinationStatechartDefinition; import hu.bme.mit.gamma.statechart.statechart.SynchronousStatechartDefinition; import hu.bme.mit.gamma.statechart.statechart.TimeoutDeclaration; import hu.bme.mit.gamma.statechart.statechart.TimeoutEventReference; @@ -142,6 +147,7 @@ import hu.bme.mit.gamma.statechart.statechart.UnaryTrigger; import hu.bme.mit.gamma.statechart.util.StatechartUtil; + public class StatechartModelDerivedFeatures extends ActionModelDerivedFeatures { protected static final StatechartUtil statechartUtil = StatechartUtil.INSTANCE; @@ -825,8 +831,10 @@ else if (component instanceof AbstractSynchronousCompositeComponent synchronousC for (SynchronousComponentInstance instance : synchronousCompositeComponent.getComponents()) { instances.add(instance); SynchronousComponent type = instance.getType(); - instances.addAll( - getAllInstances(type)); + if (!(type instanceof CoordinationStatechartDefinition)) { + // The instances of the components of a CoordinationStatechart are already visited + instances.addAll(getAllInstances(type)); + } } } return instances; @@ -2290,6 +2298,12 @@ public static List getDerivedComponents(CompositeCo if (composite instanceof AbstractAsynchronousCompositeComponent asynchronousCompositeComponent) { return asynchronousCompositeComponent.getComponents(); } + if (composite instanceof SynchronousCoordinationStatechartDefinition synchronousCoordinationStatechart) { + return synchronousCoordinationStatechart.getComponents(); + } + if (composite instanceof AsynchronousCoordinationStatechartDefinition asynchronousCoordinationStatechart) { + return asynchronousCoordinationStatechart.getComponents(); + } throw new IllegalArgumentException("Not known type: " + composite); } @@ -2386,6 +2400,11 @@ public static boolean needsWrapping(Component component) { if (component instanceof AsynchronousAdapter adapter) { return !isSimplifiable(adapter); } + else if (component instanceof SynchronousCoordinationStatechartDefinition) { + // CoordinationStatechartDefinitions are composite components as well + return false; + } + // TODO check again when implementing AsynchronousCoordinationStatechartDefinition return isStatechart(component); } @@ -2461,6 +2480,11 @@ public static List getSiblingTransitions(Transition transition) { public static List getOutgoingTransitions(StateNode node) { StatechartDefinition statechart = getContainingStatechart(node); + if (statechart instanceof CoordinationStatechartDefinition coordinationStatechart) { + // TODO CoordinationStatechart Validation + return coordinationStatechart.getCoordinationTransitions().stream() + .filter(it -> it.getSourceState() == node).collect(Collectors.toList()); + } return statechart.getTransitions().stream().filter(it -> it.getSourceState() == node) .collect(Collectors.toList()); } @@ -2508,6 +2532,12 @@ public static List getOutgoingTransitionsUntilState(StateNode node) public static List getIncomingTransitions(StateNode node) { StatechartDefinition statechart = getContainingStatechart(node); + if (statechart instanceof CoordinationStatechartDefinition coordinationStatechart) { + // TODO CoordinationStatechart Validation + return coordinationStatechart.getCoordinationTransitions().stream() + .filter(it -> it.getTargetState() == node).collect(Collectors.toList()); + } + return statechart.getTransitions().stream().filter(it -> it.getTargetState() == node) .collect(Collectors.toList()); } @@ -2516,6 +2546,12 @@ public static List getAllIncomingTransitions(StateNode node) { List allStateNodes = ecoreUtil .getSelfAndAllContentsOfType(node, StateNode.class); StatechartDefinition statechart = getContainingStatechart(node); + if (statechart instanceof CoordinationStatechartDefinition coordinationStatechart) { + // TODO CoordinationStatechart Validation + return coordinationStatechart.getCoordinationTransitions().stream() + .filter(it -> allStateNodes.contains(it.getTargetState())) + .collect(Collectors.toList()); + } return statechart.getTransitions().stream() .filter(it -> allStateNodes.contains(it.getTargetState())) .collect(Collectors.toList()); @@ -4012,4 +4048,15 @@ public static List mapInterfaceInvariantsToPort(Port port) { return interfaceInvariants; } + // Coordination + + public static List getCoordinationVariables(StatechartDefinition statechart) { + return filterVariablesByAnnotation(statechart.getVariableDeclarations(), + CoordinationVariableDeclarationAnnotation.class); + } + + public static boolean isCoordinationStatechart(StatechartDefinition statechart) { + return statechart instanceof CoordinationStatechartDefinition; + } + } \ No newline at end of file diff --git a/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/ExpressionSerializer.java b/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/ExpressionSerializer.java index 32d177940..eee9f76c3 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/ExpressionSerializer.java +++ b/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/ExpressionSerializer.java @@ -206,6 +206,9 @@ public String serialize(Expression expression) { if (expression instanceof ComponentInstanceEventParameterReferenceExpression reference) { return _serialize(reference); } + if (expression instanceof TimeoutReferenceExpression reference) { + return _serialize(reference); + } String string = super.serialize(expression); return javaUtil.deparenthesize(string); } diff --git a/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/StatechartModelValidator.java b/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/StatechartModelValidator.java index c14cb7377..8473286c1 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/StatechartModelValidator.java +++ b/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/StatechartModelValidator.java @@ -110,6 +110,7 @@ import hu.bme.mit.gamma.statechart.statechart.ChoiceState; import hu.bme.mit.gamma.statechart.statechart.ClockTickReference; import hu.bme.mit.gamma.statechart.statechart.ComplexTrigger; +import hu.bme.mit.gamma.statechart.statechart.CoordinationTransition; import hu.bme.mit.gamma.statechart.statechart.EntryState; import hu.bme.mit.gamma.statechart.statechart.ForkState; import hu.bme.mit.gamma.statechart.statechart.InitialState; @@ -748,6 +749,10 @@ public Collection checkElseTransitionPriority(Transitio public Collection checkTransitionTriggers(Transition transition) { Collection validationResultMessages = new ArrayList(); + if (transition instanceof CoordinationTransition) { + // TODO + return validationResultMessages; + } if (!StatechartModelDerivedFeatures.needsTrigger(transition)) { return validationResultMessages; } @@ -1604,11 +1609,12 @@ public Collection checkComponentInstances(ComponentInst } Collection unusedPorts = StatechartModelDerivedFeatures.getUnusedPorts(instance); if (!unusedPorts.isEmpty()) { - validationResultMessages.add( - new ValidationResultMessage(ValidationResult.WARNING, - "The following ports are used neither in a system port binding nor a channel: " + - unusedPorts.stream().map(it -> it.getName()).collect(Collectors.toSet()), - new ReferenceInfo(ExpressionModelPackage.Literals.NAMED_ELEMENT__NAME))); + for (Port port : unusedPorts) { + var msg = new ValidationResultMessage(ValidationResult.WARNING, + "The following port are used neither in a system port binding nor a channel: " + instance.getName() + "." + port.getName(), + new ReferenceInfo(ExpressionModelPackage.Literals.NAMED_ELEMENT__NAME)); + validationResultMessages.add(msg); + } } return validationResultMessages; } diff --git a/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/StatechartUtil.java b/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/StatechartUtil.java index baf65fb1a..5bb4a84c9 100644 --- a/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/StatechartUtil.java +++ b/plugins/core/hu.bme.mit.gamma.statechart.model/src/hu/bme/mit/gamma/statechart/util/StatechartUtil.java @@ -91,21 +91,28 @@ import hu.bme.mit.gamma.statechart.statechart.BinaryType; import hu.bme.mit.gamma.statechart.statechart.ChoiceState; import hu.bme.mit.gamma.statechart.statechart.CompositeElement; +import hu.bme.mit.gamma.statechart.statechart.CoordinationStatechartDefinition; +import hu.bme.mit.gamma.statechart.statechart.CoordinationTransition; import hu.bme.mit.gamma.statechart.statechart.EntryState; import hu.bme.mit.gamma.statechart.statechart.InitialState; +import hu.bme.mit.gamma.statechart.statechart.OnCycleTrigger; import hu.bme.mit.gamma.statechart.statechart.PortEventReference; import hu.bme.mit.gamma.statechart.statechart.RaiseEventAction; import hu.bme.mit.gamma.statechart.statechart.Region; +import hu.bme.mit.gamma.statechart.statechart.SequentialCoordinationReferenceExpression; import hu.bme.mit.gamma.statechart.statechart.State; import hu.bme.mit.gamma.statechart.statechart.StateNode; import hu.bme.mit.gamma.statechart.statechart.StateReferenceExpression; import hu.bme.mit.gamma.statechart.statechart.StatechartDefinition; import hu.bme.mit.gamma.statechart.statechart.StatechartModelFactory; import hu.bme.mit.gamma.statechart.statechart.SynchronousStatechartDefinition; +import hu.bme.mit.gamma.statechart.statechart.TimeoutDeclaration; +import hu.bme.mit.gamma.statechart.statechart.TimeoutReferenceExpression; import hu.bme.mit.gamma.statechart.statechart.Transition; import hu.bme.mit.gamma.statechart.statechart.TransitionPriority; import hu.bme.mit.gamma.statechart.statechart.UnaryTrigger; import hu.bme.mit.gamma.statechart.statechart.UnaryType; +import hu.bme.mit.gamma.statechart.statechart.UnorderedCoordinationReferenceExpression; public class StatechartUtil extends ActionUtil { // Singleton @@ -441,6 +448,10 @@ public UnaryTrigger createUnaryTrigger(Trigger trigger, UnaryType type) { return unaryTrigger; } + public OnCycleTrigger createOnCycleTrigger() { + return statechartFactory.createOnCycleTrigger(); + } + public void extendGuard(Transition transition, Expression guard) { extendGuard(transition, guard, factory.createAndExpression()); } @@ -1332,4 +1343,55 @@ public void removeRegions(CompositeElement element) { ecoreUtil.removeAll(element.getRegions()); } + // Coordination + + public void addCoordinationVariableAnnotation(VariableDeclaration variable) { + addAnnotation(variable, statechartFactory.createCoordinationVariableDeclarationAnnotation()); + } + + public CoordinationTransition createSequentialCoordinationTransition(StateNode source, StateNode target, + List coordinatedComponents) { + CoordinationTransition transition = statechartFactory.createCoordinationTransition(); + transition.setSourceState(source); + transition.setTargetState(target); + SequentialCoordinationReferenceExpression expression = statechartFactory + .createSequentialCoordinationReferenceExpression(); + expression.getInstances().addAll(ecoreUtil.clone(coordinatedComponents)); + + transition.setCoordinatedComponent(expression); + + CoordinationStatechartDefinition statechart = (CoordinationStatechartDefinition) StatechartModelDerivedFeatures + .getContainingStatechart(source); + if (statechart != null) { + statechart.getCoordinationTransitions().add(transition); + } + return transition; + } + + public CoordinationTransition createUnorderedCoordinationTransition(StateNode source, StateNode target, + List coordinatedComponents) { + CoordinationTransition transition = statechartFactory.createCoordinationTransition(); + transition.setSourceState(source); + transition.setTargetState(target); + UnorderedCoordinationReferenceExpression expression = statechartFactory + .createUnorderedCoordinationReferenceExpression(); + expression.getInstances().addAll(coordinatedComponents); + transition.setCoordinatedComponent(expression); + + CoordinationStatechartDefinition statechart = (CoordinationStatechartDefinition) StatechartModelDerivedFeatures + .getContainingStatechart(source); + if (statechart != null) { + statechart.getCoordinationTransitions().add(transition); + } + return transition; + } + + // TimeoutReferenceExpression + + public TimeoutReferenceExpression createTimeoutReferenceExpression(TimeoutDeclaration timeout) { + TimeoutReferenceExpression expression = statechartFactory.createTimeoutReferenceExpression(); + expression.setTimeout(timeout); + + return expression; + } } \ No newline at end of file diff --git a/plugins/core/hu.bme.mit.gamma.trace.environment.transformation/src/hu/bme/mit/gamma/trace/environment/transformation/OriginalEnvironmentBehaviorCreator.xtend b/plugins/core/hu.bme.mit.gamma.trace.environment.transformation/src/hu/bme/mit/gamma/trace/environment/transformation/OriginalEnvironmentBehaviorCreator.xtend index 0141a73e1..d079fd791 100644 --- a/plugins/core/hu.bme.mit.gamma.trace.environment.transformation/src/hu/bme/mit/gamma/trace/environment/transformation/OriginalEnvironmentBehaviorCreator.xtend +++ b/plugins/core/hu.bme.mit.gamma.trace.environment.transformation/src/hu/bme/mit/gamma/trace/environment/transformation/OriginalEnvironmentBehaviorCreator.xtend @@ -85,7 +85,7 @@ class OriginalEnvironmentBehaviorCreator { val inOutCycleState = environmentModel.createRegionWithState(inOutCycleRegionName, inOutCycleInitialStateName, inOutCycleStateName) val inOutCycleTransition = inOutCycleState.createTransition(inOutCycleState) - inOutCycleTransition.trigger = createOnCycleTrigger + inOutCycleTransition.trigger = statechartModelFactory.createOnCycleTrigger inOutCycleTransition.effects += inOutCycleVariable.createAssignment( inOutCycleVariable.createReferenceExpression.createNotExpression) } @@ -136,7 +136,7 @@ class OriginalEnvironmentBehaviorCreator { region.stateNodes += lastTargetState val firstTransition = createTransition => [ - it.trigger = createOnCycleTrigger + it.trigger = statechartModelFactory.createOnCycleTrigger ] firstTransition.sourceState = internalLastState firstTransition.targetState = lastTargetState diff --git a/plugins/core/hu.bme.mit.gamma.trace.environment.transformation/src/hu/bme/mit/gamma/trace/environment/transformation/TriggerTransformer.xtend b/plugins/core/hu.bme.mit.gamma.trace.environment.transformation/src/hu/bme/mit/gamma/trace/environment/transformation/TriggerTransformer.xtend index 8f996ecfb..66123746f 100644 --- a/plugins/core/hu.bme.mit.gamma.trace.environment.transformation/src/hu/bme/mit/gamma/trace/environment/transformation/TriggerTransformer.xtend +++ b/plugins/core/hu.bme.mit.gamma.trace.environment.transformation/src/hu/bme/mit/gamma/trace/environment/transformation/TriggerTransformer.xtend @@ -128,7 +128,7 @@ class TriggerTransformer { } else if (transition.trigger === null) { // The old transition has to have a trigger - transition.trigger = createOnCycleTrigger + transition.trigger = statechartModelFactory.createOnCycleTrigger } } diff --git a/plugins/core/hu.bme.mit.gamma.transformation.util/src/hu/bme/mit/gamma/transformation/util/preprocessor/ModelUnfolder.xtend b/plugins/core/hu.bme.mit.gamma.transformation.util/src/hu/bme/mit/gamma/transformation/util/preprocessor/ModelUnfolder.xtend index 347478d18..cba29c746 100644 --- a/plugins/core/hu.bme.mit.gamma.transformation.util/src/hu/bme/mit/gamma/transformation/util/preprocessor/ModelUnfolder.xtend +++ b/plugins/core/hu.bme.mit.gamma.transformation.util/src/hu/bme/mit/gamma/transformation/util/preprocessor/ModelUnfolder.xtend @@ -25,6 +25,7 @@ import hu.bme.mit.gamma.statechart.interface_.EventTrigger import hu.bme.mit.gamma.statechart.interface_.InterfaceModelFactory import hu.bme.mit.gamma.statechart.interface_.Package import hu.bme.mit.gamma.statechart.statechart.AnyPortEventReference +import hu.bme.mit.gamma.statechart.statechart.AsynchronousCoordinationStatechartDefinition import hu.bme.mit.gamma.statechart.statechart.AsynchronousStatechartDefinition import hu.bme.mit.gamma.statechart.statechart.ClockTickReference import hu.bme.mit.gamma.statechart.statechart.PortEventReference @@ -32,6 +33,7 @@ import hu.bme.mit.gamma.statechart.statechart.RunUponExternalEventAnnotation import hu.bme.mit.gamma.statechart.statechart.RunUponExternalEventOrInternalTimeoutAnnotation import hu.bme.mit.gamma.statechart.statechart.StatechartDefinition import hu.bme.mit.gamma.statechart.statechart.StatechartModelFactory +import hu.bme.mit.gamma.statechart.statechart.SynchronousCoordinationStatechartDefinition import hu.bme.mit.gamma.statechart.util.StatechartUtil import hu.bme.mit.gamma.util.GammaEcoreUtil import hu.bme.mit.gamma.util.JavaUtil @@ -204,6 +206,60 @@ class ModelUnfolder { // No tracing as it handles only instances } + private dispatch def void copyComponents(SynchronousCoordinationStatechartDefinition component, + Package gammaPackage, Trace trace) { + for (instance : component.components) { + val type = instance.type + val clonedPackage = type.containingPackage.clone + val clonedComponent = clonedPackage.components + .findFirst[it.helperEquals(type)] as SynchronousComponent // Sync composite or Statechart + clonedComponent.removeAnnotations // To prevent importing unnecessary resources into the resource set + gammaPackage.components += clonedComponent // Adding it to the "Instance container" + instance.type = clonedComponent // Setting the type to the new declaration + // Declarations must be copied AFTER moving component instances to enable reference changes + gammaPackage.addDeclarations(clonedPackage) + + // Changing the port binding + fixPortBindings(component, instance) + // Changing the providedPort references of Channels + fixChannelProvidedPorts(component, instance) + // Changing the requiredPort references of Channels + fixChannelRequiredPorts(component, instance) + if (clonedComponent instanceof AbstractSynchronousCompositeComponent) { + clonedComponent.copyComponents(gammaPackage, trace) // Cloning the contained CompositeSystems recursively + } + // Tracing + type.traceComponentInstances(clonedComponent, trace) + } + } + + private dispatch def void copyComponents(AsynchronousCoordinationStatechartDefinition component, + Package gammaPackage, Trace trace) { + for (instance : component.components) { + val type = instance.type + + val clonedPackage = type.containingPackage.clone + val clonedComponent = clonedPackage.components + .findFirst[it.helperEquals(type)] as AsynchronousComponent + gammaPackage.components += clonedComponent + + instance.type = clonedComponent + // Declarations must be copied AFTER moving component instances to enable reference changes + gammaPackage.addDeclarations(clonedPackage) + + clonedComponent.copyComponents(gammaPackage, trace) // Cloning the contained CompositeSystems recursively + + // Tracing + type.traceComponentInstances(clonedComponent, trace) + // Changing the port binding + fixPortBindings(component, instance) + // Changing the providedPort references of Channels + fixChannelProvidedPorts(component, instance) + // Changing the requiredPort references of Channels + fixChannelRequiredPorts(component, instance) + } + } + protected def void removeAnnotations(Component component) { if (component instanceof StatechartDefinition) { val keepableAnnotations = #[ RunUponExternalEventAnnotation, RunUponExternalEventOrInternalTimeoutAnnotation ] diff --git a/plugins/core/hu.bme.mit.gamma.transformation.util/src/hu/bme/mit/gamma/transformation/util/reducer/SystemReducer.xtend b/plugins/core/hu.bme.mit.gamma.transformation.util/src/hu/bme/mit/gamma/transformation/util/reducer/SystemReducer.xtend index 7e90b6ba7..f89cee7b5 100644 --- a/plugins/core/hu.bme.mit.gamma.transformation.util/src/hu/bme/mit/gamma/transformation/util/reducer/SystemReducer.xtend +++ b/plugins/core/hu.bme.mit.gamma.transformation.util/src/hu/bme/mit/gamma/transformation/util/reducer/SystemReducer.xtend @@ -20,6 +20,7 @@ import hu.bme.mit.gamma.statechart.composite.SimpleChannel import hu.bme.mit.gamma.statechart.composite.SynchronousComponentInstance import hu.bme.mit.gamma.statechart.composite.SynchronousCompositeComponent import hu.bme.mit.gamma.statechart.interface_.Package +import hu.bme.mit.gamma.statechart.statechart.CoordinationStatechartDefinition import hu.bme.mit.gamma.statechart.statechart.EntryState import hu.bme.mit.gamma.statechart.statechart.GuardEvaluation import hu.bme.mit.gamma.statechart.statechart.OrthogonalRegionSchedulingOrder @@ -101,7 +102,8 @@ class SystemReducer implements Reducer { } // Statechart optimizing for (statechart : statecharts) { - if (statechart.regions.empty || !simpleInstancesMatcher.hasMatch(null, statechart)) { + // TODO note: a coordination automaton is not a simple instance we have to handle this somewhere! + if ((statechart.regions.empty || !simpleInstancesMatcher.hasMatch(null, statechart)) && !(statechart.isCoordinationStatechart)) { statechart.regions.clear statechart.variableDeclarations.clear statechart.timeoutDeclarations.clear @@ -172,12 +174,15 @@ class SystemReducer implements Reducer { } private def void removeUnnecessaryStateNodes(Region region) { + info("Removing states of region " + region.name + " of " + + region.containingStatechart.name) val consideredStateNodes = region.stateNodes.reject(EntryState).toSet // To avoid concurrent mod exception for (stateNode : consideredStateNodes) { if (stateNode.allIncomingTransitions.empty) { for (outgoingTransitions : stateNode.outgoingTransitions) { outgoingTransitions.removeTransition } + info("|- Removing state " + stateNode.name) stateNode.remove } } diff --git a/plugins/core/hu.bme.mit.gamma.util/src/hu/bme/mit/gamma/util/JavaUtil.xtend b/plugins/core/hu.bme.mit.gamma.util/src/hu/bme/mit/gamma/util/JavaUtil.xtend index 780a38813..f039931e5 100644 --- a/plugins/core/hu.bme.mit.gamma.util/src/hu/bme/mit/gamma/util/JavaUtil.xtend +++ b/plugins/core/hu.bme.mit.gamma.util/src/hu/bme/mit/gamma/util/JavaUtil.xtend @@ -12,6 +12,7 @@ package hu.bme.mit.gamma.util import java.io.UnsupportedEncodingException import java.util.AbstractMap.SimpleEntry +import java.util.ArrayList import java.util.Arrays import java.util.Collection import java.util.List @@ -572,4 +573,28 @@ class JavaUtil { // && causeMessage.contains("error") // CreateProcess error=2, but not sure about the literal in other OS } + def List> getAllPermutations(List original) { + val workingCopy = original.clone + val List> result = new ArrayList> + + if (workingCopy.size == 1) { + val List innerResult = newArrayList + innerResult.add(workingCopy.get(0)) + result += innerResult + return result + } + + val firstElement = workingCopy.get(0) + val permutations = getAllPermutations(workingCopy.subList(1, workingCopy.size)) + for (permutation : permutations) { + val permutationSize = permutation.size + for (var i = 0; i <= permutationSize; i++) { + val permutationCopy = newArrayList(permutation.clone) + permutationCopy.add(i, firstElement) + result += permutationCopy + } + } + + return result + } } \ No newline at end of file diff --git a/plugins/mutation/hu.bme.mit.gamma.mutation/src/hu/bme/mit/gamma/mutation/ModelElementMutator.xtend b/plugins/mutation/hu.bme.mit.gamma.mutation/src/hu/bme/mit/gamma/mutation/ModelElementMutator.xtend index 2422b1d8f..a173289c3 100644 --- a/plugins/mutation/hu.bme.mit.gamma.mutation/src/hu/bme/mit/gamma/mutation/ModelElementMutator.xtend +++ b/plugins/mutation/hu.bme.mit.gamma.mutation/src/hu/bme/mit/gamma/mutation/ModelElementMutator.xtend @@ -115,7 +115,7 @@ class ModelElementMutator { def removeTransitionTrigger(Transition transition) { val trigger = transition.trigger - val onCycleTrigger = createOnCycleTrigger + val onCycleTrigger = statechartFactory.createOnCycleTrigger onCycleTrigger.replace(trigger) diff --git a/plugins/nuxmv/hu.bme.mit.gamma.xsts.nuxmv.transformation/src/hu/bme/mit/gamma/xsts/nuxmv/transformation/serializer/ExpressionSerializer.xtend b/plugins/nuxmv/hu.bme.mit.gamma.xsts.nuxmv.transformation/src/hu/bme/mit/gamma/xsts/nuxmv/transformation/serializer/ExpressionSerializer.xtend index 8edf7f0f4..3accf12a4 100644 --- a/plugins/nuxmv/hu.bme.mit.gamma.xsts.nuxmv.transformation/src/hu/bme/mit/gamma/xsts/nuxmv/transformation/serializer/ExpressionSerializer.xtend +++ b/plugins/nuxmv/hu.bme.mit.gamma.xsts.nuxmv.transformation/src/hu/bme/mit/gamma/xsts/nuxmv/transformation/serializer/ExpressionSerializer.xtend @@ -28,6 +28,7 @@ import hu.bme.mit.gamma.statechart.util.ExpressionTypeDeterminator import hu.bme.mit.gamma.util.GammaEcoreUtil import static extension hu.bme.mit.gamma.expression.derivedfeatures.ExpressionModelDerivedFeatures.* +import hu.bme.mit.gamma.statechart.statechart.TimeoutReferenceExpression class ExpressionSerializer extends hu.bme.mit.gamma.expression.util.ExpressionSerializer { // Singleton @@ -43,7 +44,11 @@ class ExpressionSerializer extends hu.bme.mit.gamma.expression.util.ExpressionSe override String _serialize(EnumerationLiteralExpression expression) '''«expression.reference.name»''' override String serialize(Expression expression) { - return super.serialize(expression) + if (expression instanceof TimeoutReferenceExpression) { + return expression.serialize + } else { + return super.serialize(expression) + } } override String _serialize(TrueExpression expression) '''TRUE''' @@ -89,4 +94,6 @@ class ExpressionSerializer extends hu.bme.mit.gamma.expression.util.ExpressionSe return smvArrayLiteral.toString } + def String serialize(TimeoutReferenceExpression expression) '''«expression.timeout.name»''' + } \ No newline at end of file diff --git a/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/META-INF/MANIFEST.MF b/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/META-INF/MANIFEST.MF index 13f59f47c..37208ffe9 100644 --- a/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/META-INF/MANIFEST.MF +++ b/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/META-INF/MANIFEST.MF @@ -8,6 +8,7 @@ Automatic-Module-Name: hu.bme.mit.gamma.statechart.plantuml.commandhandler Bundle-RequiredExecutionEnvironment: JavaSE-21 Require-Bundle: org.eclipse.emf.ecore, org.eclipse.jface, + org.eclipse.ui, org.eclipse.ui.ide, org.eclipse.equinox.registry, net.sourceforge.plantuml.eclipse, diff --git a/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/plugin.xml b/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/plugin.xml index 54483c8cf..9f8d8ce3c 100644 --- a/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/plugin.xml +++ b/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/plugin.xml @@ -1,5 +1,5 @@ - + @@ -9,4 +9,131 @@ providerClass="hu.bme.mit.gamma.plantuml.commandhandler.TextProvider"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/src/hu/bme/mit/gamma/plantuml/commandhandler/CoordinationLayoutHandler.java b/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/src/hu/bme/mit/gamma/plantuml/commandhandler/CoordinationLayoutHandler.java new file mode 100644 index 000000000..0f6cda7af --- /dev/null +++ b/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/src/hu/bme/mit/gamma/plantuml/commandhandler/CoordinationLayoutHandler.java @@ -0,0 +1,24 @@ +package hu.bme.mit.gamma.plantuml.commandhandler; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.ui.handlers.RadioState; + +public class CoordinationLayoutHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + if (HandlerUtil.matchesRadioState(event)) + return null; // we are already in the updated state - do nothing + + String currentState = event.getParameter(RadioState.PARAMETER_ID); + // update the current state + HandlerUtil.updateRadioState(event.getCommand(), currentState); + + return null; + } + +} \ No newline at end of file diff --git a/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/src/hu/bme/mit/gamma/plantuml/commandhandler/TextProvider.java b/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/src/hu/bme/mit/gamma/plantuml/commandhandler/TextProvider.java index 92ff8a19e..6c620f273 100644 --- a/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/src/hu/bme/mit/gamma/plantuml/commandhandler/TextProvider.java +++ b/plugins/vis/hu.bme.mit.gamma.plantuml.textprovider/src/hu/bme/mit/gamma/plantuml/commandhandler/TextProvider.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.stream.Collectors; +import org.eclipse.core.commands.Command; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IPath; import org.eclipse.emf.common.util.URI; @@ -24,12 +25,16 @@ import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.RadioState; import hu.bme.mit.gamma.expression.model.EnumerationTypeDefinition; import hu.bme.mit.gamma.expression.model.FunctionDeclaration; import hu.bme.mit.gamma.expression.model.RecordTypeDefinition; import hu.bme.mit.gamma.plantuml.transformation.AdapterToPlantUmlTransformer; import hu.bme.mit.gamma.plantuml.transformation.CompositeToPlantUmlTransformer; +import hu.bme.mit.gamma.plantuml.transformation.CoordinationToPlantUmlTransformer; import hu.bme.mit.gamma.plantuml.transformation.InterfaceToPlantUmlTransformer; import hu.bme.mit.gamma.plantuml.transformation.StatechartToPlantUmlTransformer; import hu.bme.mit.gamma.plantuml.transformation.TraceToPlantUmlTransformer; @@ -38,6 +43,7 @@ import hu.bme.mit.gamma.statechart.interface_.Component; import hu.bme.mit.gamma.statechart.interface_.Interface; import hu.bme.mit.gamma.statechart.interface_.Package; +import hu.bme.mit.gamma.statechart.statechart.CoordinationStatechartDefinition; import hu.bme.mit.gamma.statechart.statechart.StatechartDefinition; import hu.bme.mit.gamma.trace.model.ExecutionTrace; import net.sourceforge.plantuml.eclipse.utils.WorkbenchPartDiagramIntentProviderContext; @@ -121,8 +127,17 @@ private String getComponentPlantUmlCode(Resource resource) { List interfaces = _package.getInterfaces(); if (!components.isEmpty()) { Component component = components.get(0); - if (component instanceof StatechartDefinition statechart) { - StatechartToPlantUmlTransformer transformer = new StatechartToPlantUmlTransformer(statechart); + if (component instanceof CoordinationStatechartDefinition statechartDefinition) { + ICommandService commandService = + PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = commandService.getCommand("hu.bme.mit.gamma.plantuml.coordinationLayoutCommand"); + String state = (String)command.getState(RadioState.STATE_ID).getValue(); + CoordinationToPlantUmlTransformer transformer = new CoordinationToPlantUmlTransformer( + statechartDefinition, state); + return transformer.execute(); + } else if (component instanceof StatechartDefinition statechartDefinition) { + StatechartToPlantUmlTransformer transformer = new StatechartToPlantUmlTransformer( + statechartDefinition); return transformer.execute(); } else if (component instanceof CompositeComponent composite) { diff --git a/plugins/vis/hu.bme.mit.gamma.plantuml.transformation/src/hu/bme/mit/gamma/plantuml/transformation/CoordinationToPlantUmlTransformer.xtend b/plugins/vis/hu.bme.mit.gamma.plantuml.transformation/src/hu/bme/mit/gamma/plantuml/transformation/CoordinationToPlantUmlTransformer.xtend new file mode 100644 index 000000000..25ff2e950 --- /dev/null +++ b/plugins/vis/hu.bme.mit.gamma.plantuml.transformation/src/hu/bme/mit/gamma/plantuml/transformation/CoordinationToPlantUmlTransformer.xtend @@ -0,0 +1,200 @@ +package hu.bme.mit.gamma.plantuml.transformation + +import hu.bme.mit.gamma.statechart.statechart.AbstractCoordinationReferenceExpression +import hu.bme.mit.gamma.statechart.statechart.CoordinationStatechartDefinition +import hu.bme.mit.gamma.statechart.statechart.CoordinationTransition +import hu.bme.mit.gamma.statechart.statechart.EntryState +import hu.bme.mit.gamma.statechart.statechart.PseudoState +import hu.bme.mit.gamma.statechart.statechart.SequentialCoordinationReferenceExpression +import hu.bme.mit.gamma.statechart.statechart.State +import hu.bme.mit.gamma.statechart.statechart.UnorderedCoordinationReferenceExpression + +import static extension hu.bme.mit.gamma.statechart.derivedfeatures.StatechartModelDerivedFeatures.* + +class CoordinationToPlantUmlTransformer extends StatechartToPlantUmlTransformer { + protected final CoordinationStatechartDefinition statechart + + protected final CompositeToPlantUmlTransformer compositeTransformer + + enum CoordinationLayoutType { + COORDINATION, + COMPOSITION, + COORDINATION_COMPOSITION + } + + protected CoordinationLayoutType layoutType + + new(CoordinationStatechartDefinition statechart) { + super(statechart) + this.statechart = statechart + this.compositeTransformer = new CompositeToPlantUmlTransformer(statechart) + this.layoutType = CoordinationLayoutType.COORDINATION + } + + new(CoordinationStatechartDefinition statechart, String layoutType) { + super(statechart) + this.statechart = statechart + this.compositeTransformer = new CompositeToPlantUmlTransformer(statechart) + this.layoutType = CoordinationLayoutType.valueOf(layoutType) + } + + /** + * execute() + * + * This method combines the functionality of the StatechartToPlantUmlTransformer and the functionality of the + * CompositeToPlantUmlTransformer + * + */ + override String execute() { + switch (layoutType) { + case COORDINATION: { + return executeCoordinationLayout + } + case COMPOSITION: { + return executeCompositionLayout + } + case COORDINATION_COMPOSITION: { + return executeCoordinationCompositionLayout + } + default: { + return executeCoordinationLayout + } + } + } + + def String executeCoordinationLayout() ''' + @startuml + + skin rose + skinparam backgroundcolor transparent + skinparam legend { + BackgroundColor lightgrey + } + + skinparam nodesep 30 + skinparam ranksep 30 + skinparam padding 5 + «statechart.listVariablesInNote()» + «statechart.mainRegionSearch» + + @enduml + ''' + + def String executeCompositionLayout() ''' + «compositeTransformer.execute()» + ''' + + // TODO Better solution for replacing the @startuml and @enduml tags + def String executeCoordinationCompositionLayout() ''' + @startuml + left to right direction + + package Components [ + {{ + «compositeTransformer.execute().replace("@startuml","").replace("@enduml","")» + }} + ] + + package Coordination [ + {{ + skin rose + skinparam backgroundcolor transparent + skinparam legend { + BackgroundColor lightgrey + } + + skinparam nodesep 30 + skinparam ranksep 30 + skinparam padding 5 + «statechart.listVariablesInNote()» + «statechart.mainRegionSearch» + }} + ] + + @enduml + ''' + + /** + * mainRegionSearch(CoordinationStatechartDefinition) + * + * This method has the same functionality as the mainRegionSearch function of the StatechartToPlantUmlTransformer, but using + * CoordinationTransitions + * + */ + protected def mainRegionSearch(CoordinationStatechartDefinition statechart) { + val mainString = ''' + «IF statechart.regions.size > 1»state «statechart.name» {«ENDIF» + «FOR main : statechart.regions» + «FOR pseudo: main.stateNodes» + «IF pseudo instanceof PseudoState» + «pseudo.transformPseudoState» + «ENDIF» + «ENDFOR» + «FOR mainstate: main.stateNodes.filter(State)» + «regionSearch(mainstate, statechart)» + «IF !(mainstate instanceof PseudoState)» + «IF stateActionsSearch(mainstate) !== null» + «stateActionsSearch(mainstate)» + «ENDIF» + «ENDIF» + «ENDFOR» + «FOR transition : statechart.coordinationTransitions» + «FOR mainstate: main.stateNodes» + «IF transition.sourceState == mainstate» + «stateSearch(transition)» + «ENDIF» + «ENDFOR» + «ENDFOR» + + «IF !(isLastRegion(statechart.regions, main))» + -- + «ENDIF» + + «ENDFOR» + «IF statechart.regions.size > 1» + } + [*] -> «statechart.name» + «ENDIF» + ''' + return mainString + } + + /** + * stateSearch(CoordinationTransition) + * + * This method searches the source and target state of the transition received as parameter. + * This is where the visualization of the initial and history states is handled, as well as + * the obtaining of the guards and triggers of transitions. + * The end result will look like this: + * + * State1 -> State2 : trigger [guard] / action + * + */ + protected def stateSearch(CoordinationTransition transition) { + val source = transition.sourceState + val trigger = transition.trigger + val guard = transition.guard + val effects = transition.effects + val target = transition.targetState + var arrow = "" + if (source instanceof EntryState || (source.parentRegion.orthogonal && target.state)) { + arrow = "->" + } else { + arrow = "-->" + } + return ''' + «transition.sourceText» «arrow» «target.name»«IF !transition.empty» : «ENDIF»«IF trigger !== null»«trigger.transformTrigger»«ENDIF» «IF guard !== null»\n[«guard.serialize + .replaceAll("\\|\\|", "||\\\\n").replaceAll("\\&\\&", "&&\\\\n")»]«ENDIF»«FOR effect : effects BEFORE ' /\\n' SEPARATOR '\\n'»«effect.transformAction»«ENDFOR»«transition.coordinatedComponent.serializeCoordinatedComponent» + ''' + } + + protected def serializeCoordinatedComponent (AbstractCoordinationReferenceExpression expression) { + if (expression instanceof SequentialCoordinationReferenceExpression) { + return ''' \n / execute: «IF expression.instances.length > 1»SEQ{«ENDIF»«FOR instance : expression.instances SEPARATOR ','»«instance.componentInstance.name»«ENDFOR»«IF expression.instances.length > 1»}«ENDIF»''' + } else if (expression instanceof UnorderedCoordinationReferenceExpression) { + return ''' \n / execute: UNORD{«FOR instance : expression.instances SEPARATOR ','»«instance.componentInstance.name»«ENDFOR»}''' + } + + return '''''' + } +} \ No newline at end of file diff --git a/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/ExpressionTransformer.xtend b/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/ExpressionTransformer.xtend index aa02b8a66..82e21f7d9 100644 --- a/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/ExpressionTransformer.xtend +++ b/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/ExpressionTransformer.xtend @@ -496,7 +496,7 @@ class ExpressionTransformer { // - private def Expression getValueOfTimeout(TimeoutDeclaration timeoutDeclaration) { + protected def Expression getValueOfTimeout(TimeoutDeclaration timeoutDeclaration) { val gammaStatechart = timeoutDeclaration.containingStatechart val timeoutSettings = gammaStatechart.getAllContentsOfType(SetTimeoutAction) val correctTimeoutSetting = timeoutSettings.filter[it.timeoutDeclaration == timeoutDeclaration] diff --git a/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/GammaToLowlevelTransformer.xtend b/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/GammaToLowlevelTransformer.xtend index b85ed5c2a..e26e47bba 100644 --- a/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/GammaToLowlevelTransformer.xtend +++ b/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/GammaToLowlevelTransformer.xtend @@ -13,6 +13,7 @@ package hu.bme.mit.gamma.statechart.lowlevel.transformation import hu.bme.mit.gamma.statechart.interface_.TimeUnit import hu.bme.mit.gamma.statechart.lowlevel.model.Package import hu.bme.mit.gamma.statechart.statechart.StatechartDefinition +import hu.bme.mit.gamma.statechart.statechart.SynchronousCoordinationStatechartDefinition import static com.google.common.base.Preconditions.checkState @@ -62,6 +63,10 @@ class GammaToLowlevelTransformer { return statechart.execute } + def hu.bme.mit.gamma.statechart.lowlevel.model.StatechartDefinition transform(SynchronousCoordinationStatechartDefinition statechart) { + return statechart.execute + } + def Package transformAndWrap(StatechartDefinition statechart) { val gammaPackage = statechart.containingPackage diff --git a/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/StatechartToLowlevelTransformer.xtend b/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/StatechartToLowlevelTransformer.xtend index 8bcd01ce1..fe6c5f98c 100644 --- a/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/StatechartToLowlevelTransformer.xtend +++ b/plugins/xsts/hu.bme.mit.gamma.statechart.lowlevel.transformation/src/hu/bme/mit/gamma/statechart/lowlevel/transformation/StatechartToLowlevelTransformer.xtend @@ -11,6 +11,7 @@ package hu.bme.mit.gamma.statechart.lowlevel.transformation import hu.bme.mit.gamma.action.model.ActionModelFactory +import hu.bme.mit.gamma.expression.model.EnumerationTypeDefinition import hu.bme.mit.gamma.expression.model.Expression import hu.bme.mit.gamma.expression.model.ExpressionModelFactory import hu.bme.mit.gamma.expression.model.TrueExpression @@ -26,6 +27,9 @@ import hu.bme.mit.gamma.statechart.lowlevel.model.EventDeclaration import hu.bme.mit.gamma.statechart.lowlevel.model.StateNode import hu.bme.mit.gamma.statechart.lowlevel.model.StatechartModelFactory import hu.bme.mit.gamma.statechart.lowlevel.util.LowlevelStatechartUtil +import hu.bme.mit.gamma.statechart.statechart.AsynchronousCoordinationStatechartDefinition +import hu.bme.mit.gamma.statechart.statechart.CoordinationStatechartDefinition +import hu.bme.mit.gamma.statechart.statechart.CoordinationTransition import hu.bme.mit.gamma.statechart.statechart.DeepHistoryState import hu.bme.mit.gamma.statechart.statechart.GuardEvaluation import hu.bme.mit.gamma.statechart.statechart.InitialState @@ -35,14 +39,19 @@ import hu.bme.mit.gamma.statechart.statechart.Region import hu.bme.mit.gamma.statechart.statechart.RunUponExternalEventAnnotation import hu.bme.mit.gamma.statechart.statechart.RunUponExternalEventOrInternalTimeoutAnnotation import hu.bme.mit.gamma.statechart.statechart.SchedulingOrder +import hu.bme.mit.gamma.statechart.statechart.SequentialCoordinationReferenceExpression import hu.bme.mit.gamma.statechart.statechart.ShallowHistoryState import hu.bme.mit.gamma.statechart.statechart.State import hu.bme.mit.gamma.statechart.statechart.StatechartDefinition +import hu.bme.mit.gamma.statechart.statechart.SynchronousCoordinationStatechartDefinition import hu.bme.mit.gamma.statechart.statechart.TimeoutAction import hu.bme.mit.gamma.statechart.statechart.TimeoutDeclaration import hu.bme.mit.gamma.statechart.statechart.TimeoutEventReference import hu.bme.mit.gamma.statechart.statechart.Transition +import hu.bme.mit.gamma.statechart.statechart.UnorderedCoordinationReferenceExpression +import hu.bme.mit.gamma.statechart.util.StatechartUtil import hu.bme.mit.gamma.util.GammaEcoreUtil +import hu.bme.mit.gamma.util.JavaUtil import java.util.List import static com.google.common.base.Preconditions.checkState @@ -62,12 +71,16 @@ class StatechartToLowlevelTransformer { protected final extension GammaEcoreUtil gammaEcoreUtil = GammaEcoreUtil.INSTANCE protected final extension LowlevelStatechartUtil lowlevelUtil = LowlevelStatechartUtil.INSTANCE protected final extension EventAttributeTransformer eventAttributeTransformer = EventAttributeTransformer.INSTANCE + protected final StatechartUtil statechartUtil = StatechartUtil.INSTANCE + protected final extension JavaUtil javaUtil = JavaUtil.INSTANCE // Low-level statechart model factory protected final extension StatechartModelFactory factory = StatechartModelFactory.eINSTANCE protected final extension ExpressionModelFactory constraintFactory = ExpressionModelFactory.eINSTANCE protected final extension ActionModelFactory actionFactory = ActionModelFactory.eINSTANCE // Trace object for storing the mappings protected final Trace trace + // Coordination automata + protected VariableDeclaration scheduledCtrlVar new() { this(null) @@ -98,6 +111,14 @@ class StatechartToLowlevelTransformer { // return statechart.transformComponent as hu.bme.mit.gamma.statechart.lowlevel.model.StatechartDefinition } + + def hu.bme.mit.gamma.statechart.lowlevel.model.StatechartDefinition execute(SynchronousCoordinationStatechartDefinition statechart) { + // Eliminating merge states + val mergeStateEliminator = new MergeStateEliminator(statechart) + mergeStateEliminator.execute + // + return statechart.transformCoordinationAutomaton + } protected def hu.bme.mit.gamma.statechart.lowlevel.model.Package transform(Package _package) { if (trace.isMapped(_package)) { @@ -461,4 +482,326 @@ class StatechartToLowlevelTransformer { return trace } + // Coordination automaton + + protected def hu.bme.mit.gamma.statechart.lowlevel.model.StatechartDefinition transformCoordinationAutomaton(CoordinationStatechartDefinition statechart) { + if (trace.isMapped(statechart)) { + // It is already transformed + return trace.get(statechart) as hu.bme.mit.gamma.statechart.lowlevel.model.StatechartDefinition + } + val lowlevelStatechart = createStatechartDefinition => [ + it.name = getName(statechart) + it.schedulingOrder = statechart.schedulingOrder.transform + it.guardEvaluation = statechart.guardEvaluation.transform + it.orthogonalRegionSchedulingOrder = statechart.orthogonalRegionSchedulingOrder.transform + ] + if (!statechart.hasOrthogonalRegions) { + // If there are no orthogonal regions, then the guard evaluation policy is irrelevant; + // on the fly is the faster option, though + lowlevelStatechart.guardEvaluation = hu.bme.mit.gamma.statechart.lowlevel.model.GuardEvaluation.ON_THE_FLY + } + if (statechart.hasAnnotation(RunUponExternalEventAnnotation)) { + lowlevelStatechart.addRunUponExternalEventAnnotation + } + if (statechart.hasAnnotation(RunUponExternalEventOrInternalTimeoutAnnotation)) { + lowlevelStatechart.addRunUponExternalEventOrInternalTimeoutAnnotation + } + trace.put(statechart, lowlevelStatechart) // Saving in trace + // create scheduled control variable for each subcomponent + val scheduledComponentEnum = createEnumerationTypeDefinition + + // create default value, when no component is scheduled + val noComponentLiteral = createEnumerationLiteralDefinition + noComponentLiteral.name = "__nothing__" + scheduledComponentEnum.literals += noComponentLiteral + + // TODO is differentiation between SynchronousCoordinationStatechartDefinition and AsynchronousCoordinationStatechartDefinition necessary? + if (statechart.synchronous) { + for (subcomponent : (statechart as SynchronousCoordinationStatechartDefinition).components) { + val componentLiteral = createEnumerationLiteralDefinition + componentLiteral.name = subcomponent.name + scheduledComponentEnum.literals += componentLiteral + } + } else if (statechart.asynchronous) { + for (subcomponent : (statechart as AsynchronousCoordinationStatechartDefinition).components) { + val componentLiteral = createEnumerationLiteralDefinition + componentLiteral.name = subcomponent.name + scheduledComponentEnum.literals += componentLiteral + } + } else { + throw new IllegalArgumentException("CoordinationStateChart: " + statechart.name + + " is neither synchronous nor asynchronous!") + } + val schedulableComponentsTypeDeclaration = scheduledComponentEnum.createTypeDeclaration("schedulableComponents") + statechart.typeDeclarations += schedulableComponentsTypeDeclaration + + val schedulableComponentsTypeReference = createTypeReference(schedulableComponentsTypeDeclaration) + + // TODO add ctrl var annotation + scheduledCtrlVar = createVariableDeclaration(schedulableComponentsTypeReference, "scheduledComponent") + statechartUtil.addCoordinationVariableAnnotation(scheduledCtrlVar) + statechart.variableDeclarations += scheduledCtrlVar + + // Transforming UnorderedCoordinationTransitions to SequentialCoordinationTransitions, + // Generating all possible permutations + for (transition : statechart.coordinationTransitions.clone.filter [ + it.coordinatedComponent instanceof UnorderedCoordinationReferenceExpression + ]) { + transition.transformCoordinationTransition(scheduledComponentEnum) + } + // Transforming CoordinationTransitions to regular transitions, possibly creating VariableDeclarations and States + for (transition : statechart.coordinationTransitions.filter [ + !(it.coordinatedComponent instanceof UnorderedCoordinationReferenceExpression) + ]) { + transition.transformCoordinationTransition(scheduledComponentEnum) + } + + // Constants + val gammaPackage = statechart.containingPackage + for (constantDeclaration : gammaPackage.selfAndImports // During code generation, imported constants can be referenced + .map[it.constantDeclarations].flatten) { + lowlevelStatechart.variableDeclarations += constantDeclaration.transform + } + // No parameter declarations mapping + for (parameterDeclaration : statechart.parameterDeclarations) { + val lowlevelParameterDeclaration = parameterDeclaration.transformComponentParameter + lowlevelStatechart.variableDeclarations += lowlevelParameterDeclaration + lowlevelStatechart.parameterDeclarations += lowlevelParameterDeclaration + } + for (variableDeclaration : statechart.variableDeclarations) { + lowlevelStatechart.variableDeclarations += variableDeclaration.transform + } + for (timeoutDeclaration : statechart.timeoutDeclarations) { + // Timeout declarations are transformed to integer variable declarations + val lowlevelTimeoutDeclaration = timeoutDeclaration.transform + lowlevelStatechart.variableDeclarations += lowlevelTimeoutDeclaration + lowlevelStatechart.timeoutDeclarations += lowlevelTimeoutDeclaration + } + + for (port : statechart.ports) { + // Both in and out events are transformed to a boolean VarDecl with additional parameters + for (eventDeclaration : port.allEventDeclarations) { + val lowlevelEventDeclarations = eventDeclaration.transform(port) + lowlevelStatechart.eventDeclarations += lowlevelEventDeclarations + if (eventDeclaration.direction == EventDirection.INTERNAL) { + // Tracing + lowlevelStatechart.internalEventDeclarations += lowlevelEventDeclarations + } + } + } + for (region : statechart.regions) { + lowlevelStatechart.regions += region.transform + } + + for (transition : statechart.transitions) { + // Prioritizing transitions is done here + val lowlevelTransition = transition.transform + lowlevelStatechart.transitions += lowlevelTransition + } + + // Mapping port and interface invariants (now, not before, because we want to refer to e.g., state nodes and variables) + // First the interface invariants must be mapped to the ports realizing the interface + for (port : statechart.ports) { + val mappedInvariants = port.mapInterfaceInvariantsToPort + if (!mappedInvariants.empty) { + lowlevelStatechart.environmentalInvariants += mappedInvariants.map[it.transformSimpleExpression] + } + val invariants = port.invariants + if (!invariants.empty) { + lowlevelStatechart.environmentalInvariants += invariants.map[it.transformSimpleExpression] + } + } + + // Mapping statechart invariants + val statechartInvariants = statechart.invariants + if (!statechartInvariants.empty) { + lowlevelStatechart.invariants += statechartInvariants.map[it.transformSimpleExpression] + } + + return lowlevelStatechart + } + + protected def void transformCoordinationTransition(CoordinationTransition coordinationTransition, + EnumerationTypeDefinition scheduledComponentEnum) { + + var gammaSource = coordinationTransition.sourceState + val sourceName = gammaSource.name + val containingStatechart = gammaSource.containingStatechart + val containingCoordinationStatechart = gammaSource.containingStatechart as CoordinationStatechartDefinition + val region = gammaSource.getParentRegion + + val gammaTarget = coordinationTransition.targetState + + if (coordinationTransition.coordinatedComponent instanceof SequentialCoordinationReferenceExpression) { + if (!coordinationTransition.coordinatedComponent.instances.empty) { + for (var i = 0; i < coordinationTransition.coordinatedComponent.instances.size; i++) { + val componentInstanceReference = coordinationTransition.coordinatedComponent.instances.get(i) + val componentName = componentInstanceReference.componentInstance.name + + if (i == coordinationTransition.coordinatedComponent.instances.size - 1) { + + val internalTransition = statechartUtil.createTransition(gammaSource, gammaTarget) + internalTransition.trigger = coordinationTransition.trigger.clone + internalTransition.guard = coordinationTransition.guard.clone + internalTransition.effects += + createAssignment(scheduledCtrlVar, + createEnumerationLiteralExpression(scheduledComponentEnum, componentName)) + internalTransition.effects += coordinationTransition.effects.clone + + containingStatechart.transitions += internalTransition + } else { + val internalState = statechartUtil.createState(region, + sourceName + "_" + i + "_" + containingCoordinationStatechart.coordinationTransitions.indexOf(coordinationTransition) + ) + if (gammaTarget instanceof State) { + internalState.invariants += gammaTarget.invariants.clone + internalState.entryActions += gammaTarget.entryActions.clone + internalState.exitActions += gammaTarget.exitActions.clone + internalState.annotations += gammaTarget.annotations.clone + } + + val internalTransition = statechartUtil.createTransition(gammaSource, internalState) + internalTransition.trigger = coordinationTransition.trigger.clone + internalTransition.guard = coordinationTransition.guard.clone + internalTransition.effects += + createAssignment(scheduledCtrlVar, + createEnumerationLiteralExpression(scheduledComponentEnum, componentName)) + + gammaSource = internalState + containingStatechart.transitions += internalTransition + } + } + } + } else if (coordinationTransition.coordinatedComponent instanceof UnorderedCoordinationReferenceExpression && true) { + + val permutations = coordinationTransition.coordinatedComponent.instances.allPermutations + + for (permutation : permutations) { + val sequentialTransition = statechartUtil.createSequentialCoordinationTransition(gammaSource, gammaTarget, permutation); + sequentialTransition.trigger = coordinationTransition.trigger.clone + sequentialTransition.guard = coordinationTransition.guard.clone + sequentialTransition.effects += coordinationTransition.effects.clone + } + + } else if (coordinationTransition.coordinatedComponent instanceof UnorderedCoordinationReferenceExpression && false) { + // TODO need some measurements which case is better + val unordName = "unord_" + gammaSource.name + gammaTarget.name + val unordBoolVariables = newHashMap + + /* XSTS: + * + * ctrl var unord_q0q3 : enum{Sensor1, Sensor2, Sensor3, Sensor4} + * ctrl var unord_q0q3_Sensor1 : boolean = false + * ctrl var unord_q0q3_Sensor2 : boolean = false + * ctrl var unord_q0q3_Sensor3 : boolean = false + * ctrl var unord_q0q3_Sensor4 : boolean = false + */ + + for (componentInstanceReference : coordinationTransition.coordinatedComponent.instances) { + unordBoolVariables += + componentInstanceReference.componentInstance -> + createVariableDeclarationWithDefaultInitialValue(createBooleanTypeDefinition, + unordName + "_" + componentInstanceReference.componentInstance.name) + } + + // TODO add ctrl var annotation + containingStatechart.variableDeclarations += unordBoolVariables.values + + /* XSTS: + * if (coordState == q0) { + * assume c1 > 1 && c1 <= 2; + * havoc unord_q0q3; TODO initializing! + * choice { + * assume unord_q0q3 == Sensor1 && !unord_q0q3_Sensor1; + * unord_q0q3_Sensor1 := true; + * scheduled := Sensor1; + * } or { + * assume unord_q0q3 == Sensor2 && !unord_q0q3_Sensor2; + * unord_q0q3_Sensor2 := true; + * scheduled := Sensor2; + * } or { + * ... // Sensor3 + * } or { + * ... // Sensor4 + * } + * if (unord_q0q3_Sensor1 && unord_q0q3_Sensor2 && unord_q0q3_Sensor3 && unord_q0q3_Sensor4) { + * c1 := 0; + * coordState := q3; + * unord_q0q3_Sensor1 := false; + * unord_q0q3_Sensor2 := false; + * ... // Sensor3, Sensor4 + * } + * } + */ + + // creating new transition sourceState->sourceState for every componentInstance + for (componentInstanceReference : coordinationTransition.coordinatedComponent.instances) { + val componentName = componentInstanceReference.componentInstance.name + + val internalTransition = statechartUtil.createTransition(gammaSource, gammaSource) + + // if the trigger is a timeout event, then create an invariant and on onCycleTrigger + if (coordinationTransition.trigger.containsType(TimeoutEventReference)) { + val timeout = coordinationTransition.trigger.getFirstOfAllContentsOfType(TimeoutEventReference).timeout + if (gammaSource instanceof State) { + gammaSource.invariants += createGreaterEqualExpression( + statechartUtil.createTimeoutReferenceExpression(timeout), + timeout.valueOfTimeout + ) + } + internalTransition.trigger = statechartUtil.createOnCycleTrigger + } else { + internalTransition.trigger = coordinationTransition.trigger.clone + } + + internalTransition.guard = createAndExpression => [ + if (coordinationTransition.guard !== null) { + it.operands += coordinationTransition.guard.clone + } + it.operands += + createEqualityExpression(unordBoolVariables.get(componentInstanceReference.componentInstance), + createFalseExpression) + ] + internalTransition.effects += + createAssignment(scheduledCtrlVar, + createEnumerationLiteralExpression(scheduledCtrlVar.typeDefinition as EnumerationTypeDefinition, componentName)) + internalTransition.effects += + createAssignment(unordBoolVariables.get(componentInstanceReference.componentInstance), + createTrueExpression) + containingStatechart.transitions += internalTransition + } + + // creating new transition sourceState->targetState if every component was executed, reset action for each bool + + val finalTransition = statechartUtil.createTransition(gammaSource, gammaTarget) + finalTransition.trigger = coordinationTransition.trigger.clone + + val guardExpression = createAndExpression => [ + if (coordinationTransition.guard !== null) { + it.operands += coordinationTransition.guard.clone + } + ] + finalTransition.guard = guardExpression + + for (componentInstanceReference : coordinationTransition.coordinatedComponent.instances) { + guardExpression.operands += + createEqualityExpression(unordBoolVariables.get(componentInstanceReference.componentInstance), + createTrueExpression) + finalTransition.effects += + createAssignment(unordBoolVariables.get(componentInstanceReference.componentInstance), + createFalseExpression) + } + containingStatechart.transitions += finalTransition + + } else { + val transition = statechartUtil.createTransition(gammaSource, gammaTarget) + transition.trigger = coordinationTransition.trigger.clone + transition.guard = coordinationTransition.guard.clone + transition.effects += coordinationTransition.effects.clone + transition.annotations += coordinationTransition.annotations.clone + containingStatechart.transitions += transition + } + } + + } \ No newline at end of file diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.model/META-INF/MANIFEST.MF b/plugins/xsts/hu.bme.mit.gamma.xsts.model/META-INF/MANIFEST.MF index 8cd534973..b03bf0b2b 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.model/META-INF/MANIFEST.MF +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.model/META-INF/MANIFEST.MF @@ -6,7 +6,8 @@ Bundle-Version: 2.13.0.qualifier Bundle-ClassPath: . Require-Bundle: org.eclipse.core.runtime, org.eclipse.emf.ecore;visibility:=reexport, - hu.bme.mit.gamma.expression.model;visibility:=reexport + hu.bme.mit.gamma.expression.model;visibility:=reexport, + hu.bme.mit.gamma.statechart.model Bundle-ActivationPolicy: lazy Bundle-Vendor: BME-FTSRG Bundle-Localization: plugin diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.model/model/model.ecore b/plugins/xsts/hu.bme.mit.gamma.xsts.model/model/model.ecore index 7297e393e..da3c8129c 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.model/model/model.ecore +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.model/model/model.ecore @@ -170,4 +170,5 @@ eSuperTypes="../../hu.bme.mit.gamma.expression.model/model/expression.ecore#//VariableDeclarationAnnotation"/> + diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.model/model/model.genmodel b/plugins/xsts/hu.bme.mit.gamma.xsts.model/model/model.genmodel index 963f72e79..011fb01be 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.model/model/model.genmodel +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.model/model/model.genmodel @@ -121,5 +121,6 @@ + diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.model/src/hu/bme/mit/gamma/xsts/derivedfeatures/XstsDerivedFeatures.java b/plugins/xsts/hu.bme.mit.gamma.xsts.model/src/hu/bme/mit/gamma/xsts/derivedfeatures/XstsDerivedFeatures.java index 7280fa1a2..82ab6e0af 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.model/src/hu/bme/mit/gamma/xsts/derivedfeatures/XstsDerivedFeatures.java +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.model/src/hu/bme/mit/gamma/xsts/derivedfeatures/XstsDerivedFeatures.java @@ -40,6 +40,7 @@ import hu.bme.mit.gamma.expression.model.ReferenceExpression; import hu.bme.mit.gamma.expression.model.TupleReferenceExpression; import hu.bme.mit.gamma.expression.model.VariableDeclaration; +import hu.bme.mit.gamma.statechart.statechart.CoordinationVariableDeclarationAnnotation; import hu.bme.mit.gamma.util.Triple; import hu.bme.mit.gamma.xsts.model.AbstractAssignmentAction; import hu.bme.mit.gamma.xsts.model.Action; @@ -48,6 +49,7 @@ import hu.bme.mit.gamma.xsts.model.AssumeAction; import hu.bme.mit.gamma.xsts.model.AsynchronousSystemAnnotation; import hu.bme.mit.gamma.xsts.model.AtomicAction; +import hu.bme.mit.gamma.xsts.model.DelayAction; import hu.bme.mit.gamma.xsts.model.EmptyAction; import hu.bme.mit.gamma.xsts.model.EnvironmentalInvariantAnnotation; import hu.bme.mit.gamma.xsts.model.FunctionCallAction; @@ -660,6 +662,10 @@ private static Set _getReadVariables(MultiaryAction action) return variableList; } + private static Set _getReadVariables(DelayAction action) { + return Collections.emptySet(); + } + private static Set _getExternallyReadVariables(AssignmentAction action) { Set readVariables = new HashSet(); @@ -794,6 +800,10 @@ private static Set _getWrittenVariables(MultiaryAction acti return variableList; } + + private static Set _getWrittenVariables(DelayAction action) { + return Collections.emptySet(); // Empty, as this is a declaration, not a "writing" + } public static Set getReadVariables(Action action) { if (action instanceof AssignmentAction _action) { @@ -829,6 +839,10 @@ else if (action instanceof FunctionCallAction _action) { else if (action instanceof OpaqueAction) { return Set.of(); } + else if (action instanceof DelayAction _action) { + return _getReadVariables(_action); + } + else { throw new IllegalArgumentException("Unhandled action type: " + action); } @@ -868,6 +882,9 @@ else if (action instanceof FunctionCallAction _action) { else if (action instanceof OpaqueAction) { return Set.of(); } + else if (action instanceof DelayAction _action) { + return _getReadVariables(_action); + } else { throw new IllegalArgumentException("Unhandled action type: " + action); } @@ -904,6 +921,9 @@ else if (action instanceof FunctionCallAction _action) { else if (action instanceof OpaqueAction) { return Set.of(); } + else if (action instanceof DelayAction _action) { + return _getWrittenVariables(_action); + } else { throw new IllegalArgumentException("Unhandled action type: " + action); } @@ -1421,5 +1441,13 @@ else if (firstExpr instanceof TupleReferenceExpression) { Set>( literalVariableAssignments, variableVariableAssignments, notLiteralVariables); } + + // Coordination -} \ No newline at end of file + public static List getCoordinationVariables(XSTS xSts) { + return filterVariablesByAnnotation(xSts.getVariableDeclarations(), + CoordinationVariableDeclarationAnnotation.class); + } + +} + diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation.util/src/hu/bme/mit/gamma/xsts/transformation/serializer/ActionSerializer.xtend b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation.util/src/hu/bme/mit/gamma/xsts/transformation/serializer/ActionSerializer.xtend index 9d5124d5e..8991e91e3 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation.util/src/hu/bme/mit/gamma/xsts/transformation/serializer/ActionSerializer.xtend +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation.util/src/hu/bme/mit/gamma/xsts/transformation/serializer/ActionSerializer.xtend @@ -13,6 +13,7 @@ package hu.bme.mit.gamma.xsts.transformation.serializer import hu.bme.mit.gamma.expression.model.DirectReferenceExpression import hu.bme.mit.gamma.xsts.model.AssignmentAction import hu.bme.mit.gamma.xsts.model.AssumeAction +import hu.bme.mit.gamma.xsts.model.DelayAction import hu.bme.mit.gamma.xsts.model.EmptyAction import hu.bme.mit.gamma.xsts.model.FunctionCallAction import hu.bme.mit.gamma.xsts.model.HavocAction @@ -138,4 +139,8 @@ class ActionSerializer { ««« } ''' + def dispatch String serialize(DelayAction action) ''' + __delay; + ''' + } \ No newline at end of file diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/ComponentTransformer.xtend b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/ComponentTransformer.xtend index 2c696fb04..4b5ee176e 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/ComponentTransformer.xtend +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/ComponentTransformer.xtend @@ -12,10 +12,12 @@ package hu.bme.mit.gamma.xsts.transformation import hu.bme.mit.gamma.expression.model.ArrayTypeDefinition import hu.bme.mit.gamma.expression.model.EnumerationTypeDefinition +import hu.bme.mit.gamma.expression.model.EqualityExpression import hu.bme.mit.gamma.expression.model.Expression import hu.bme.mit.gamma.expression.model.ExpressionModelFactory import hu.bme.mit.gamma.expression.model.TypeDeclaration import hu.bme.mit.gamma.expression.model.TypeReference +import hu.bme.mit.gamma.expression.model.VariableDeclaration import hu.bme.mit.gamma.expression.util.ExpressionEvaluator import hu.bme.mit.gamma.lowlevel.xsts.transformation.LowlevelToXstsTransformer import hu.bme.mit.gamma.lowlevel.xsts.transformation.TransitionMerging @@ -36,7 +38,10 @@ import hu.bme.mit.gamma.statechart.lowlevel.model.Package import hu.bme.mit.gamma.statechart.lowlevel.transformation.GammaToLowlevelTransformer import hu.bme.mit.gamma.statechart.lowlevel.transformation.Trace import hu.bme.mit.gamma.statechart.lowlevel.transformation.ValueDeclarationTransformer +import hu.bme.mit.gamma.statechart.statechart.AsynchronousCoordinationStatechartDefinition import hu.bme.mit.gamma.statechart.statechart.StatechartDefinition +import hu.bme.mit.gamma.statechart.statechart.SynchronousCoordinationStatechartDefinition +import hu.bme.mit.gamma.statechart.util.StatechartUtil import hu.bme.mit.gamma.util.GammaEcoreUtil import hu.bme.mit.gamma.util.JavaUtil import hu.bme.mit.gamma.xsts.model.AbstractAssignmentAction @@ -88,6 +93,7 @@ class ComponentTransformer { protected final extension EventConnector eventConnector = EventConnector.INSTANCE protected final extension InternalEventHandler internalEventHandler = InternalEventHandler.INSTANCE protected final extension SystemReducer systemReducer = SystemReducer.INSTANCE + protected final StatechartUtil statechartUtil = StatechartUtil.INSTANCE protected final extension ExpressionModelFactory expressionModelFactory = ExpressionModelFactory.eINSTANCE protected final extension XSTSModelFactory xStsModelFactory = XSTSModelFactory.eINSTANCE @@ -1378,6 +1384,209 @@ class ComponentTransformer { return xSts } + def dispatch XSTS transform(SynchronousCoordinationStatechartDefinition component, Package lowlevelPackage) { + val name = component.name + logger.info( "Transforming Synchronous Coordination Statechart " + name) + + val xSts = name.createXsts + val componentMergedActions = newHashMap // To handle multiple schedulings in CascadeCompositeComponents + val components = component.components + + if (components.empty) { + logger.warning("No components in Synchronous Coordination Statechart " + name) + return xSts + } + + val coordinationInstance = this.statechartUtil.instantiateSynchronousComponent(component) + + val lowlevelStatechart = gammaToLowlevelTransformer.transform(component) + lowlevelPackage.components += lowlevelStatechart + val lowlevelToXSTSTransformer = new LowlevelToXstsTransformer( + lowlevelPackage, optimize, transitionMerging) + val xStsEntry = lowlevelToXSTSTransformer.execute + lowlevelPackage.components -= lowlevelStatechart // So that next time the matches do not return elements from this statechart + val coordinationXSts = xStsEntry.key + val coordinationXStsTrace = xStsEntry.value + // getting the xsts variable of the scheduled component + + var VariableDeclaration xstsScheduledCtrlVar = null + val coordinationVariables = coordinationXSts.coordinationVariables + if (!coordinationVariables.empty) { + // There must be only one + xstsScheduledCtrlVar = coordinationVariables.get(0) + } + coordinationXSts.customizeDeclarationNames(coordinationInstance) + + // Adding new elements + xSts.merge(coordinationXSts) + + // Initializing action + val coordinationVariableInitAction = createSequentialAction + coordinationVariableInitAction.actions += coordinationXSts.variableInitializingTransition.action + xSts.variableInitializingTransition = coordinationVariableInitAction.wrap + val coordinationConfigInitAction = createSequentialAction + coordinationConfigInitAction.actions += coordinationXSts.configurationInitializingTransition.action + xSts.configurationInitializingTransition = coordinationConfigInitAction.wrap + val coordinationEntryAction = createSequentialAction + coordinationEntryAction.actions += coordinationXSts.entryEventTransition.action + xSts.entryEventTransition = coordinationEntryAction.wrap + + component.components.add(coordinationInstance) + + // In and Out actions - using sequential actions to make sure they are composite actions + // Methods reset... and delete... require this + + // The coordination automata needs to be executed in the env step + val newCoordinationInEventAction = createSequentialAction => [ + it.actions += coordinationXSts.inEventTransition.action + it.actions += coordinationXSts.mergedAction + ] + + coordinationXSts.inEventTransition = newCoordinationInEventAction.wrap + val newCoordinationOutEventAction = createSequentialAction => [ it.actions += coordinationXSts.outEventTransition.action ] + coordinationXSts.outEventTransition = newCoordinationOutEventAction.wrap + // Resetting channel events + // 1) the Sync ort semantics: Resetting channel IN events AFTER schedule would result in a deadlock + // 2) the Casc semantics: Resetting channel OUT events BEFORE schedule would delete in events of subsequent components + // Note, System in and out events are reset in the env action + // 3) Coordination automata semantics: following the the Casc semantics resetting IN events AFTER schedule + + for (subcomponent : components.reject[it == coordinationInstance]) { + val subcomponentType = subcomponent.type + + // Normal transformation + subcomponentType.extractParameters(subcomponent.arguments) // Change the reference from parameters to constants + val newXSts = subcomponentType.transform(lowlevelPackage) + newXSts.customizeDeclarationNames(subcomponent) + + // Internal event handling here as EventReferenceHandler cannot be used without customizeDeclarationNames + if (subcomponentType.statechart) { + newXSts.addInternalEventHandlingActions(subcomponentType) + } + // + + // Adding new elements + xSts.merge(newXSts) + + // Initializing action + val variableInitAction = createSequentialAction + variableInitAction.actions += xSts.variableInitializingTransition.action + variableInitAction.actions += newXSts.variableInitializingTransition.action + xSts.variableInitializingTransition = variableInitAction.wrap + val configInitAction = createSequentialAction + configInitAction.actions += xSts.configurationInitializingTransition.action + configInitAction.actions += newXSts.configurationInitializingTransition.action + xSts.configurationInitializingTransition = configInitAction.wrap + val entryAction = createSequentialAction + entryAction.actions += xSts.entryEventTransition.action + entryAction.actions += newXSts.entryEventTransition.action + xSts.entryEventTransition = entryAction.wrap + + // Merged action + val actualComponentMergedAction = createSequentialAction => [ + it.actions += newXSts.mergedAction + ] + // In and Out actions - using sequential actions to make sure they are composite actions + // Methods reset... and delete... require this + val newSeqAction = createSequentialAction => [ it.actions += newXSts.inEventTransition.action ] + val newInEventAction = createIfAction(createComponentScheduledEqualityExpression(xstsScheduledCtrlVar, subcomponent.name), newSeqAction) + newXSts.inEventTransition = newInEventAction.wrap + val newOutEventAction = createSequentialAction => [ it.actions += newXSts.outEventTransition.action ] + newXSts.outEventTransition = newOutEventAction.wrap + // Resetting channel events + // 1) the Sync ort semantics: Resetting channel IN events AFTER schedule would result in a deadlock + // 2) the Casc semantics: Resetting channel OUT events BEFORE schedule would delete in events of subsequent components + // Note, System in and out events are reset in the env action + // 3) Coordination automata semantics: following the the Casc semantics resetting IN events AFTER schedule + + + val clonedNewInEventAction = newInEventAction.clone. + resetEverythingExceptPersistentParameters(subcomponentType) // Clone is important + actualComponentMergedAction.actions += clonedNewInEventAction // Putting the new action AFTER + // Tracing merged action + componentMergedActions += subcomponentType -> actualComponentMergedAction.clone + + // In event + newInEventAction.deleteEverythingExceptSystemEventsAndParameters(component) + if (xSts !== newXSts) { // Only if this is not the first component + val inEventAction = createSequentialAction + inEventAction.actions += xSts.inEventTransition.action + inEventAction.actions += newInEventAction + xSts.inEventTransition = inEventAction.wrap + } + // Out event + newOutEventAction.deleteEverythingExceptSystemEventsAndParameters(component) + if (xSts !== newXSts) { // Only if this is not the first component + val outEventAction = createSequentialAction + outEventAction.actions += xSts.outEventTransition.action + outEventAction.actions += newOutEventAction + xSts.outEventTransition = outEventAction.wrap + } + } + + val nondetAction = createNonDeterministicAction + + for (subcomponent : components.reject[it == coordinationInstance]) { + val subcomponentType = subcomponent.type + logger.info( "Checking subcomponent type " + subcomponentType + " in merged actions") + checkState(componentMergedActions.containsKey(subcomponentType)) + val componentMergedAction = componentMergedActions.get(subcomponentType).clone + nondetAction.extendChoiceWithBranch(createComponentScheduledEqualityExpression(xstsScheduledCtrlVar, subcomponent.name), componentMergedAction) + } + xSts.changeTransitions(nondetAction.wrap) + + logger.info( "Deleting unused instance ports in " + name) + xSts.deleteUnusedPorts(component) // Deleting variable assignments for unused ports + + // Connect only after "xSts.mergedTransition.action = mergedAction" / "xSts.changeTransitions" + logger.info( "Connecting events through channels in " + name) + xSts.connectEventsThroughChannels(component) // Event (variable setting) connecting across channels + + logger.info( "Binding event to system port events in " + name) + val oldInEventAction = xSts.inEventTransition.action + val bindingAssignments = xSts.createEventAndParameterAssignmentsBoundToTheSameSystemPort(component) + // Optimization: removing old NonDeterministicActions + bindingAssignments.removeNonDeterministicActionsReferencingAssignedVariables(oldInEventAction) + + val newInEventAction = createSequentialAction => [ + // Add delay -> new DelayAction -> transformed in GammaToXstsTransformer.setClockVariables + val delayAction = xStsModelFactory.createDelayAction + it.actions += delayAction + it.actions += newCoordinationInEventAction + it.actions += delayAction.clone + it.actions += oldInEventAction + // Bind together ports connected to the same system port + it.actions += bindingAssignments + ] + + xSts.inEventTransition = newInEventAction.wrap + + if (transformOrthogonalActions) { + // After connectEventsThroughChannels + logger.info( "Transforming orthogonal actions in XSTS " + name) + xSts.mergedAction.transform(xSts) + // Before optimize actions + } + +// if (optimize) { +// // Optimization: system in events (but not PERSISTENT parameters) can be reset after the merged transition +// // E.g., synchronous components do not reset system events +// xSts.resetInEventsAfterMergedAction(component) +// } + + // After in event optimization + logger.info( "Adding internal event handlings in " + name) + xSts.addInternalEventHandlingActions(component) + + return xSts + } + + def dispatch XSTS transform(AsynchronousCoordinationStatechartDefinition component, Package lowlevelPackage) { + logger.info( "Transforming Asynchronous Coordination Statechart " + component.name) + // TODO + return null + } + // Utils private def void extractAllParameters(AbstractAsynchronousCompositeComponent component) { @@ -1521,4 +1730,9 @@ class ComponentTransformer { } } + protected def EqualityExpression createComponentScheduledEqualityExpression(VariableDeclaration scheduledCtrlVar, String name) { + val enumTypeDefinition = scheduledCtrlVar.typeDefinition as EnumerationTypeDefinition + return createEqualityExpression(scheduledCtrlVar, createEnumerationLiteralExpression(enumTypeDefinition, name)) + } + } \ No newline at end of file diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/GammaToXstsTransformer.xtend b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/GammaToXstsTransformer.xtend index 148805f19..a218411de 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/GammaToXstsTransformer.xtend +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/GammaToXstsTransformer.xtend @@ -31,6 +31,8 @@ import hu.bme.mit.gamma.statechart.interface_.SchedulingConstraintAnnotation import hu.bme.mit.gamma.statechart.lowlevel.transformation.GammaToLowlevelTransformer import hu.bme.mit.gamma.transformation.util.preprocessor.AnalysisModelPreprocessor import hu.bme.mit.gamma.util.GammaEcoreUtil +import hu.bme.mit.gamma.xsts.model.DelayAction +import hu.bme.mit.gamma.xsts.model.SequentialAction import hu.bme.mit.gamma.xsts.model.SystemInEventGroup import hu.bme.mit.gamma.xsts.model.SystemInEventParameterGroup import hu.bme.mit.gamma.xsts.model.SystemOutEventGroup @@ -240,6 +242,14 @@ class GammaToXstsTransformer { // Denoting variable as scheduled clock variable xStsClockVariable.addScheduledClockAnnotation } + + val inAction = xSts.inEventTransition.action + if (inAction instanceof SequentialAction) { + for (delayAction : inAction.actions.filter[it instanceof DelayAction]) { + xStsClockSettingAction.clone.replace(delayAction) + } + } + // Putting it in merged transition as it does not work in environment action xStsClockSettingAction.actions += xSts.mergedAction diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/SystemReducer.xtend b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/SystemReducer.xtend index dc6aa555e..a0519a0d8 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/SystemReducer.xtend +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/SystemReducer.xtend @@ -80,6 +80,7 @@ class SystemReducer { val xStsDeletableAssignmentActions = newHashSet for (instance : component.derivedComponents) { for (instancePort : instance.unusedPorts) { + logger.info("Unused port: " + component.name + "." + instancePort.name) // In events on required port for (inputEvent : instancePort.inputEvents) { val inEventName = inputEvent.customizeInputName(instancePort, instance) diff --git a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/api/Gamma2XstsTransformerSerializer.xtend b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/api/Gamma2XstsTransformerSerializer.xtend index bba870f75..4a35492e7 100644 --- a/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/api/Gamma2XstsTransformerSerializer.xtend +++ b/plugins/xsts/hu.bme.mit.gamma.xsts.transformation/src/hu/bme/mit/gamma/xsts/transformation/api/Gamma2XstsTransformerSerializer.xtend @@ -30,6 +30,7 @@ import java.io.File import java.util.List import static extension hu.bme.mit.gamma.statechart.derivedfeatures.StatechartModelDerivedFeatures.* +import hu.bme.mit.gamma.statechart.statechart.CoordinationStatechartDefinition class Gamma2XstsTransformerSerializer { @@ -153,6 +154,17 @@ class Gamma2XstsTransformerSerializer { val xSts = gammaToXSTSTransformer.execute(newGammaPackage) // EMF xSts.normalSave(targetFolderUri, fileName.emfXStsFileName) + + if (newTopComponent instanceof CoordinationStatechartDefinition) { + /* This is needed because during the transformation new ComponentInstances, States and Transitions are created, + * and the updated .gsm is needed for the trace and the property language + * + * note: might be worth to makes this generic, e.g. create a definition which means that the model changed during the + * transformation as is needed to be saved again + */ + + newGammaPackage.eResource.save + } // String xSts.serializeAndSaveXSts } diff --git a/tests/hu.bme.mit.gamma.tests/model/Coordination/Interfaces/Interfaces.gcd b/tests/hu.bme.mit.gamma.tests/model/Coordination/Interfaces/Interfaces.gcd new file mode 100644 index 000000000..7e1024f6c --- /dev/null +++ b/tests/hu.bme.mit.gamma.tests/model/Coordination/Interfaces/Interfaces.gcd @@ -0,0 +1,5 @@ +package coordination_tests + +interface SimpleInterface { + out event simpleEvent +} diff --git a/tests/hu.bme.mit.gamma.tests/model/Coordination/Statechart/Statechart.gcd b/tests/hu.bme.mit.gamma.tests/model/Coordination/Statechart/Statechart.gcd new file mode 100644 index 000000000..cecfea75a --- /dev/null +++ b/tests/hu.bme.mit.gamma.tests/model/Coordination/Statechart/Statechart.gcd @@ -0,0 +1,26 @@ +package coordination_tests +// import interfaces_package + +import "Interfaces/Interfaces.gcd" + +statechart SimpleStatechart ( + // Declaration of parameters +) [ + // Declaration of ports + port inPort : requires SimpleInterface + port outPort : provides SimpleInterface +] { + // Definition of states, regions and transitions + timeout c1 + + + region main_region_1 { + initial init_1 + state state_1 { + entry / set c1 := 5 s; + } + } + transition from init_1 to state_1 + transition from state_1 to state_1 when inPort.simpleEvent + transition from state_1 to state_1 when timeout c1 / raise outPort.simpleEvent; +} diff --git a/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-nondet.gcd b/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-nondet.gcd new file mode 100644 index 000000000..3c062a1fd --- /dev/null +++ b/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-nondet.gcd @@ -0,0 +1,43 @@ +package coordination_tests + +import "Interfaces/Interfaces.gcd" +import "Statechart/Statechart.gcd" + +@Coordination +coordination-statechart CoordinationNondet ( + // parameters +) [ + // system ports + port SystemIn1 : requires SimpleInterface + port SystemIn2 : requires SimpleInterface + port SystemOut1 : provides SimpleInterface + port SystemOut2 : provides SimpleInterface +] { + // system composition + component Component1 : SimpleStatechart + component Component2 : SimpleStatechart + + bind SystemIn1 -> Component1.inPort + bind SystemIn2 -> Component2.inPort + bind SystemOut1 -> Component1.outPort + bind SystemOut2 -> Component2.outPort +} < + // system coordination + timeout c1 + + region main { + initial init + state q0 { + invariant (time-elapsed(c1) < 4) + entry / set c1 := 1 s; + } + state q1 { + invariant (time-elapsed(c1) < 4) + entry / set c1 := 1 s; + } + } + + transition from init to q0 + transition from q0 to q1 when timeout c1 execute Component1 + transition from q0 to q1 when timeout c1 execute Component2 +> \ No newline at end of file diff --git a/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-seq.gcd b/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-seq.gcd new file mode 100644 index 000000000..a4e1b504f --- /dev/null +++ b/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-seq.gcd @@ -0,0 +1,42 @@ +package coordination_tests + +import "Interfaces/Interfaces.gcd" +import "Statechart/Statechart.gcd" + +@Coordination +coordination-statechart CoordinationSeq ( + // parameters +) [ + // system ports + port SystemIn1 : requires SimpleInterface + port SystemIn2 : requires SimpleInterface + port SystemOut1 : provides SimpleInterface + port SystemOut2 : provides SimpleInterface +] { + // system composition + component Component1 : SimpleStatechart + component Component2 : SimpleStatechart + + bind SystemIn1 -> Component1.inPort + bind SystemIn2 -> Component2.inPort + bind SystemOut1 -> Component1.outPort + bind SystemOut2 -> Component2.outPort +} < + // system coordination + timeout c1 + + region main { + initial init + state q0 { + invariant (time-elapsed(c1) < 4) + entry / set c1 := 1 s; + } + state q1 { + invariant (time-elapsed(c1) < 4) + entry / set c1 := 1 s; + } + } + + transition from init to q0 + transition from q0 to q1 when timeout c1 execute seq{Component1, Component2} +> \ No newline at end of file diff --git a/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-unord.gcd b/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-unord.gcd new file mode 100644 index 000000000..47224bdd2 --- /dev/null +++ b/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Coordination-unord.gcd @@ -0,0 +1,42 @@ +package coordination_tests + +import "Interfaces/Interfaces.gcd" +import "Statechart/Statechart.gcd" + +@Coordination +coordination-statechart CoordinationUnord ( + // parameters +) [ + // system ports + port SystemIn1 : requires SimpleInterface + port SystemIn2 : requires SimpleInterface + port SystemOut1 : provides SimpleInterface + port SystemOut2 : provides SimpleInterface +] { + // system composition + component Component1 : SimpleStatechart + component Component2 : SimpleStatechart + + bind SystemIn1 -> Component1.inPort + bind SystemIn2 -> Component2.inPort + bind SystemOut1 -> Component1.outPort + bind SystemOut2 -> Component2.outPort +} < + // system coordination + timeout c1 + + region main { + initial init + state q0 { + invariant (time-elapsed(c1) < 4) + entry / set c1 := 1 s; + } + state q1 { + invariant (time-elapsed(c1) < 4) + entry / set c1 := 1 s; + } + } + + transition from init to q0 + transition from q0 to q1 when timeout c1 execute unord{Component1, Component2} +> \ No newline at end of file diff --git a/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Generation.ggen b/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Generation.ggen new file mode 100644 index 000000000..2bbaf3b58 --- /dev/null +++ b/tests/hu.bme.mit.gamma.tests/model/Coordination/System/Generation.ggen @@ -0,0 +1,63 @@ +import "Coordination-nondet.gcd" +import "Coordination-seq.gcd" +import "Coordination-unord.gcd" + +analysis { + component : CoordinationNondet + language : XSTS + folder : "model-gen-coordination-timed" + optimize : false + state-coverage +} + +analysis { + component : CoordinationNondet + language : XSTS + folder : "model-gen-coordination" + optimize : false + state-coverage + constraint : { + minimum-orchestrating-period : 0 s + maximum-orchestrating-period : 4 s + } +} + +analysis { + component : CoordinationSeq + language : XSTS + folder : "model-gen-coordination-timed" + optimize : false + state-coverage +} + +analysis { + component : CoordinationSeq + language : XSTS + folder : "model-gen-coordination" + optimize : false + state-coverage + constraint : { + minimum-orchestrating-period : 0 s + maximum-orchestrating-period : 4 s + } +} + +analysis { + component : CoordinationUnord + language : XSTS + folder : "model-gen-coordination-timed" + optimize : false + state-coverage +} + +analysis { + component : CoordinationUnord + language : XSTS + folder : "model-gen-coordination" + optimize : false + state-coverage + constraint : { + minimum-orchestrating-period : 0 s + maximum-orchestrating-period : 4 s + } +} \ No newline at end of file