Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse')
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/CodegenHelpers.java10
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/DefaultFSMTranslationProvider.java2
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Diagnostician.java2
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/ILineOutputLogger.java2
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/IncrementalGenerationFileIo.java2
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Logger.java12
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/NullLogger.java15
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/AbstractStateMachineGenerator.xtend917
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/FSMExtensions.xtend50
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ILanguageExtensionBase.java11
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ITransitionChainVisitor.java85
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainGenerator.java147
-rw-r--r--plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainVisitor.java46
13 files changed, 759 insertions, 542 deletions
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/CodegenHelpers.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/CodegenHelpers.java
index 891c6c789..4b7d5f8a3 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/CodegenHelpers.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/CodegenHelpers.java
@@ -15,9 +15,9 @@ package org.eclipse.etrice.generator.fsm.base;
import org.eclipse.etrice.core.fsm.fSM.State;
import org.eclipse.etrice.core.fsm.fSM.StateGraphItem;
import org.eclipse.etrice.core.fsm.fSM.Transition;
+import org.eclipse.etrice.core.fsm.fSM.TransitionBase;
import org.eclipse.etrice.core.fsm.naming.FSMNameProvider;
import org.eclipse.etrice.core.fsm.util.FSMHelpers;
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.TransitionChain;
/**
* @author Henrik Rentz-Reichert
@@ -32,7 +32,7 @@ public class CodegenHelpers {
* @param t a {@link Transition}
* @return a name for the action code operation the generator will generate
*/
- public String getActionCodeOperationName(Transition t) {
+ public String getActionCodeOperationName(TransitionBase t) {
return "action_"+fsmNameProvider.getFullPath(t);
}
@@ -61,11 +61,11 @@ public class CodegenHelpers {
}
/**
- * @param tc a {@link TransitionChain}
+ * @param tc a {@link Transition}
* @return a name for the constant transition chain ID the generator will generate
*/
- public String getGenChainId(TransitionChain tc) {
- return "CHAIN_"+fsmNameProvider.getFullPath(tc.getTransition());
+ public String getGenChainId(TransitionBase tc) {
+ return "CHAIN_"+fsmNameProvider.getFullPath(tc);
}
/**
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/DefaultFSMTranslationProvider.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/DefaultFSMTranslationProvider.java
index a96374d8f..48311b750 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/DefaultFSMTranslationProvider.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/DefaultFSMTranslationProvider.java
@@ -19,7 +19,7 @@ import org.eclipse.etrice.core.fsm.fSM.AbstractInterfaceItem;
import org.eclipse.etrice.core.fsm.fSM.DetailCode;
import org.eclipse.etrice.core.fsm.naming.FSMNameProvider;
import org.eclipse.etrice.core.fsm.util.FSMHelpers;
-import org.eclipse.etrice.core.genmodel.fsm.base.ILogger;
+import org.eclipse.etrice.core.genmodel.fsm.ILogger;
import com.google.inject.Inject;
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Diagnostician.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Diagnostician.java
index a9f31a71e..832693c9e 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Diagnostician.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Diagnostician.java
@@ -15,7 +15,7 @@ package org.eclipse.etrice.generator.fsm.base;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.etrice.core.fsm.naming.FSMNameProvider;
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.IDiagnostician;
+import org.eclipse.etrice.core.genmodel.fsm.IDiagnostician;
import com.google.inject.Inject;
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/ILineOutputLogger.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/ILineOutputLogger.java
index e3bddc633..6c6379337 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/ILineOutputLogger.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/ILineOutputLogger.java
@@ -12,7 +12,7 @@
package org.eclipse.etrice.generator.fsm.base;
-import org.eclipse.etrice.core.genmodel.fsm.base.ILogger;
+import org.eclipse.etrice.core.genmodel.fsm.ILogger;
/**
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/IncrementalGenerationFileIo.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/IncrementalGenerationFileIo.java
index 8c227acdd..5a0996a90 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/IncrementalGenerationFileIo.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/IncrementalGenerationFileIo.java
@@ -17,7 +17,7 @@ import java.io.IOException;
import java.util.zip.CRC32;
import org.apache.commons.io.FileUtils;
-import org.eclipse.etrice.core.genmodel.fsm.base.ILogger;
+import org.eclipse.etrice.core.genmodel.fsm.ILogger;
import org.eclipse.xtext.generator.JavaIoFileSystemAccess;
import org.eclipse.xtext.util.RuntimeIOException;
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Logger.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Logger.java
index d18e660c5..9eadc3c07 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Logger.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/Logger.java
@@ -27,13 +27,25 @@ import org.eclipse.emf.ecore.util.EcoreUtil;
*/
public class Logger implements ILineOutputLogger {
+ private int errors = 0;
private ILineOutput output = null;
+
+ @Override
+ public boolean hasErrors() {
+ return errors!=0;
+ }
public void logInfo(String text) {
println("Info: " + text);
}
+ @Override
+ public void logError(String text) {
+ logError(text, null);
+ }
+
public void logError(String text, EObject obj) {
+ ++errors;
if (obj == null)
println("Error: " + text);
else {
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/NullLogger.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/NullLogger.java
index 73c475986..2aec3f0e7 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/NullLogger.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/base/NullLogger.java
@@ -1,16 +1,29 @@
package org.eclipse.etrice.generator.fsm.base;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.etrice.core.genmodel.fsm.base.ILogger;
+import org.eclipse.etrice.core.genmodel.fsm.ILogger;
public class NullLogger implements ILogger {
+ private int errors = 0;
+
@Override
public void logInfo(String text) {
}
@Override
public void logError(String text, EObject obj) {
+ ++errors;
}
+ @Override
+ public void logError(String text) {
+ ++errors;
+ }
+
+ @Override
+ public boolean hasErrors() {
+ return errors!=0;
+ }
+
}
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/AbstractStateMachineGenerator.xtend b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/AbstractStateMachineGenerator.xtend
index f86f9679a..64609294c 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/AbstractStateMachineGenerator.xtend
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/AbstractStateMachineGenerator.xtend
@@ -13,225 +13,232 @@
package org.eclipse.etrice.generator.fsm.generic
import com.google.inject.Inject
-import java.util.ArrayList
-import java.util.List
import org.eclipse.etrice.core.fsm.fSM.ComponentCommunicationType
import org.eclipse.etrice.core.fsm.fSM.GuardedTransition
+import org.eclipse.etrice.core.fsm.fSM.MessageFromIf
import org.eclipse.etrice.core.fsm.fSM.ModelComponent
import org.eclipse.etrice.core.fsm.fSM.State
import org.eclipse.etrice.core.fsm.fSM.Transition
import org.eclipse.etrice.core.fsm.fSM.TransitionPoint
-import org.eclipse.etrice.core.fsm.fSM.TriggeredTransition
+import org.eclipse.etrice.core.fsm.naming.FSMNameProvider
import org.eclipse.etrice.core.fsm.util.FSMHelpers
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.ActiveTrigger
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.ExpandedModelComponent
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.util.FsmGenUtil
+import org.eclipse.etrice.core.genmodel.fsm.TriggerExtensions
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.CommonTrigger
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.GraphContainer
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Link
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Node
import org.eclipse.etrice.generator.fsm.base.CodegenHelpers
import org.eclipse.xtext.util.Pair
import static org.eclipse.xtext.util.Tuples.*
+import static extension org.eclipse.etrice.core.genmodel.fsm.FsmGenExtensions.*
+import java.util.ArrayList
+
/**
* @author Henrik Rentz-Reichert
*
*/
abstract class AbstractStateMachineGenerator {
- @Inject public extension FSMHelpers
- @Inject public extension FsmGenUtil
- @Inject public extension CodegenHelpers
- @Inject public extension FSMExtensions
- @Inject public ILanguageExtensionBase langExt
- @Inject public IMessageIdGenerator msgIdGen
- @Inject public IIfItemIdGenerator itemIdGen
+ @Inject public extension FSMHelpers
+ @Inject public extension CodegenHelpers
+ @Inject public extension FSMExtensions
+ @Inject public ILanguageExtensionBase langExt
+ @Inject public IMessageIdGenerator msgIdGen
+ @Inject public IIfItemIdGenerator itemIdGen
@Inject public TransitionChainGenerator transitionChainGenerator
@Inject public IDetailCodeTranslator translator
-
- /**
- * generates trigger IDs.
- * Inheritance (if available) is used for base class IDs.
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @return the generated code
- */
- def public String genTriggerConstants(ExpandedModelComponent xpmc) {
- xpmc.genTriggerConstants(langExt.usesInheritance)
- }
-
- /**
- * generates trigger IDs.
- * Inheritance (if available) is used for base class IDs.
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param omitBase use <code>true</code> if no base class trigger constants are needed
- *
- * @return the generated code
- */
- def public String genTriggerConstants(ExpandedModelComponent xpmc, boolean omitBase) {
- val triggers = if (omitBase)
- xpmc.modelComponent.ownMessagesFromInterfaces
- else xpmc.modelComponent.allMessagesFromInterfaces
-
- val list = new ArrayList<Pair<String, String>>()
- list.add(pair("POLLING", "0"));
- for (mif : triggers) {
- if (mif.from.eventDriven) {
- list.add(pair(xpmc.getTriggerCodeName(mif), itemIdGen.getIfItemId(mif.from)+" + EVT_SHIFT*"+msgIdGen.getMessageID(mif)))
- }
- }
-
- return langExt.genEnumeration("triggers", list)
- }
-
- /**
- * generates state ID constants.
- * Inheritance (if available) is used for base class IDs.
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @return the generated code
- */
- def public genStateIdConstants(ExpandedModelComponent xpmc) {
- xpmc.genStateIdConstants(langExt.usesInheritance)
- }
-
- /**
- * generates state ID constants.
- * Inheritance (if available) is used for base class IDs.
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param omitBase use <code>true</code> if no base class state constants are needed
- *
- * @return the generated code
- */
- def public genStateIdConstants(ExpandedModelComponent xpmc, boolean omitBase) {
- val mc = xpmc.modelComponent
- // with inheritance we exclude inherited base states
- var offset = 2 + if (omitBase)
- mc.getNumberOfInheritedBaseStates() else 0
- var baseStates = if (omitBase)
- mc.stateMachine.getBaseStateList else xpmc.stateMachine.getBaseStateList
-
- baseStates = baseStates.leafStatesLast
-
- var list = new ArrayList<Pair<String, String>>()
- if (!omitBase) {
- list.add(pair("NO_STATE","0"))
- list.add(pair("STATE_TOP","1"))
- }
- for (state : baseStates) {
- list.add(pair(state.getGenStateId, offset.toString))
- offset = offset+1;
- }
- list.add(pair("STATE_MAX", offset.toString))
-
- return langExt.genEnumeration("state_ids", list)
- }
-
- /**
- * generates transition chain ID constants.
- * Inheritance can't be used used for base class IDs because of corner cases
- * where base class and derived class chain IDs deviate (see bug 501354).
- *
- * @param xpmc the {@link ExpandedModelComponent}
- *
- * @return the generated code
- */
- def public genTransitionChainConstants(ExpandedModelComponent xpmc) {
- xpmc.genTransitionChainConstants(false/*langExt.usesInheritance*/)
- }
-
- /**
- * generates transition chain ID constants.
- * Inheritance can't be used used for base class IDs because of corner cases
- * where base class and derived class chain IDs deviate.
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param omitBase use <code>true</code> if no base class transition chain constants are needed
- *
- * @return the generated code
- */
- def public genTransitionChainConstants(ExpandedModelComponent xpmc, boolean omitBase) {
- var chains = if (omitBase)
- xpmc.getOwnTransitionChains() else xpmc.transitionChains
- var offset = if (omitBase)
- xpmc.getTransitionChains().size-chains.size else 0
-
- var list = new ArrayList<Pair<String, String>>()
- for (chain : chains) {
- offset = offset+1;
- list.add(pair(chain.genChainId, offset.toString))
- }
-
- return langExt.genEnumeration("ChainIDs", list)
- }
-
- /**
- * generates entry and exit code for states
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param generateImplementation if <code>true</code> the implementation is generated, else the declaration
- *
- * @return the generated code
- */
- def public String genEntryAndExitCodes(ExpandedModelComponent xpmc, boolean generateImplementation) {
- xpmc.genEntryAndExitCodes(generateImplementation, langExt.usesInheritance)
- }
-
- /**
- * generates entry and exit code for states
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param generateImplementation if <code>true</code> the implementation is generated, else the declaration
- * @param omitBase use <code>true</code> if no base class entry and exit codes are needed
- *
- * @return the generated code
- */
- def public String genEntryAndExitCodes(ExpandedModelComponent xpmc, boolean generateImplementation, boolean omitBase) {
- '''
- «FOR state : xpmc.stateMachine.getStateList()»
- «IF !omitBase || xpmc.isOwnObject(state)»
- «xpmc.genActionCodeMethods(state, generateImplementation)»
- «ENDIF»
- «ENDFOR»
- '''
- }
-
- /**
- * generates transition action codes
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param generateImplementation if <code>true</code> the implementation is generated, else the declaration
- *
- * @return the generated code
- */
- def public String genActionCodes(ExpandedModelComponent xpmc, boolean generateImplementation) {
- xpmc.genActionCodes(generateImplementation, langExt.usesInheritance)
- }
-
- /**
- * generates transition action codes
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param generateImplementation if <code>true</code> the implementation is generated, else the declaration
- * @param omitBase use <code>true</code> if no base class action codes are needed
- *
- * @return the generated code
- */
- def public String genActionCodes(ExpandedModelComponent xpmc, boolean generateImplementation, boolean omitBase) {
- '''
- «FOR tr : xpmc.stateMachine.allTransitionsRecursive»
- «IF (!omitBase || xpmc.isOwnObject(tr)) && tr.action.hasDetailCode»
- «xpmc.genActionCodeMethod(tr, generateImplementation)»
- «ENDIF»
- «ENDFOR»
- '''
- }
-
- def public String genStateSwitchMethods(ExpandedModelComponent xpmc, boolean generateImplementation) {
- val mc = xpmc.modelComponent
+ @Inject public FSMNameProvider fsmNameProvider
+
+ /**
+ * generates trigger IDs.
+ * Inheritance (if available) is used for base class IDs.
+ *
+ * @param gc the {@link GraphContainer}
+ * @return the generated code
+ */
+ def public String genTriggerConstants(GraphContainer gc) {
+ gc.genTriggerConstants(langExt.usesInheritance)
+ }
+
+ /**
+ * generates trigger IDs.
+ * Inheritance (if available) is used for base class IDs.
+ *
+ * @param gc the {@link GraphContainer}
+ * @param omitBase use <code>true</code> if no base class trigger constants are needed
+ *
+ * @return the generated code
+ */
+ def public String genTriggerConstants(GraphContainer gc, boolean omitBase) {
+ val triggers = if (omitBase)
+ gc.component.ownMessagesFromInterfaces
+ else gc.component.allMessagesFromInterfaces
+
+ val list = <Pair<String, String>>newArrayList
+ list.add(pair("POLLING", "0"));
+ for (mif : triggers) {
+ if (mif.from.eventDriven) {
+ list.add(pair(mif.triggerCodeName, itemIdGen.getIfItemId(mif.from)+" + EVT_SHIFT*"+msgIdGen.getMessageID(mif)))
+ }
+ }
+
+ return langExt.genEnumeration("triggers", list)
+ }
+
+ def String getTriggerCodeName(MessageFromIf mif) {
+ return "TRIG_"+mif.from.name+"__"+fsmNameProvider.getMessageName(mif.message);
+ }
+
+ /**
+ * generates state ID constants.
+ * Inheritance (if available) is used for base class IDs.
+ *
+ * @param gc the {@link GraphContainer}
+ * @return the generated code
+ */
+ def public genStateIdConstants(GraphContainer gc) {
+ gc.genStateIdConstants(langExt.usesInheritance)
+ }
+
+ /**
+ * generates state ID constants.
+ * Inheritance (if available) is used for base class IDs.
+ *
+ * @param gc the {@link GraphContainer}
+ * @param omitBase use <code>true</code> if no base class state constants are needed
+ *
+ * @return the generated code
+ */
+ def public genStateIdConstants(GraphContainer gc, boolean omitBase) {
+ // with inheritance we exclude inherited states
+ val allStateNodes = gc.graph.allStateNodes.toList // TODO: without toList this didn't work - why?
+ var offset = 2 + if (omitBase)
+ allStateNodes.filter[inherited].size else 0
+ var baseStates = (if (omitBase)
+ allStateNodes.filter[!inherited] else allStateNodes).map[stateGraphNode].filter(typeof(State)).toList
+
+ baseStates = baseStates.leafStatesLast.toList
+
+ var list = <Pair<String, String>>newArrayList
+ if (!omitBase) {
+ list.add(pair("NO_STATE","0"))
+ list.add(pair("STATE_TOP","1"))
+ }
+ for (state : baseStates) {
+ list.add(pair(state.getGenStateId, offset.toString))
+ offset = offset+1;
+ }
+ list.add(pair("STATE_MAX", offset.toString))
+
+ return langExt.genEnumeration("state_ids", list)
+ }
+
+ /**
+ * generates transition chain ID constants.
+ * Inheritance can't be used used for base class IDs because of corner cases
+ * where base class and derived class chain IDs deviate (see bug 501354).
+ *
+ * @param gc the {@link GraphContainer}
+ *
+ * @return the generated code
+ */
+ def public genTransitionChainConstants(GraphContainer gc) {
+ gc.genTransitionChainConstants(false/*langExt.usesInheritance*/)
+ }
+
+ /**
+ * generates transition chain ID constants.<br/><br/>
+ *
+ * <b>Note:</b> Inheritance can't be used used for base class IDs because of corner cases
+ * where base class and derived class chain IDs deviate.
+ *
+ * @param gc the {@link GraphContainer}
+ * @param omitBase use <code>true</code> if no base class transition chain constants are needed
+ *
+ * @return the generated code
+ */
+ def public genTransitionChainConstants(GraphContainer gc, boolean omitBase) {
+ val chains = (if (omitBase)
+ gc.graph.allLinks.filter[!inherited] else gc.graph.allLinks).map[transition].filter[isChainHead].filter(typeof(Transition)).toList
+ var offset = if (omitBase)
+ gc.graph.allLinks.filter[inherited].size else 0
+
+ var list = <Pair<String, String>>newArrayList
+ for (chain : chains) {
+ offset = offset+1;
+ list.add(pair(chain.genChainId, offset.toString))
+ }
+
+ return langExt.genEnumeration("ChainIDs", list)
+ }
+
+ /**
+ * generates entry and exit code for states
+ *
+ * @param gc the {@link GraphContainer}
+ * @param generateImplementation if <code>true</code> the implementation is generated, else the declaration
+ *
+ * @return the generated code
+ */
+ def public String genEntryAndExitCodes(GraphContainer gc, boolean generateImplementation) {
+ gc.genEntryAndExitCodes(generateImplementation, langExt.usesInheritance)
+ }
+
+ /**
+ * generates entry and exit code for states
+ *
+ * @param gc the {@link GraphContainer}
+ * @param generateImplementation if <code>true</code> the implementation is generated, else the declaration
+ * @param omitBase use <code>true</code> if no base class entry and exit codes are needed
+ *
+ * @return the generated code
+ */
+ def public String genEntryAndExitCodes(GraphContainer gc, boolean generateImplementation, boolean omitBase) {
+ val states = gc.graph.allStateNodes.filter[!omitBase || !inherited].toList
+ '''
+ «FOR state : states»
+ «gc.genActionCodeMethods(state, generateImplementation)»
+ «ENDFOR»
+ '''
+ }
+
+ /**
+ * generates transition action codes
+ *
+ * @param gc the {@link GraphContainer}
+ * @param generateImplementation if <code>true</code> the implementation is generated, else the declaration
+ *
+ * @return the generated code
+ */
+ def public String genActionCodes(GraphContainer gc, boolean generateImplementation) {
+ gc.genActionCodes(generateImplementation, langExt.usesInheritance)
+ }
+
+ /**
+ * generates transition action codes
+ *
+ * @param gc the {@link GraphContainer}
+ * @param generateImplementation if <code>true</code> the implementation is generated, else the declaration
+ * @param omitBase use <code>true</code> if no base class action codes are needed
+ *
+ * @return the generated code
+ */
+ def public String genActionCodes(GraphContainer gc, boolean generateImplementation, boolean omitBase) {
+ val transitions = gc.graph.allLinks.filter[!omitBase || !inherited].filter[transition.action.hasDetailCode].toList
+ '''
+ «FOR tr : transitions»
+ «gc.genActionCodeMethod(tr, generateImplementation)»
+ «ENDFOR»
+ '''
+ }
+
+ def public String genStateSwitchMethods(GraphContainer gc, boolean generateImplementation) {
+ val mc = gc.component
val async = mc.commType==ComponentCommunicationType::ASYNCHRONOUS
val eventDriven = mc.commType==ComponentCommunicationType::EVENT_DRIVEN
- val ifItemPtr = interfaceItemType()+langExt.pointerLiteral()
+ val ifItemPtr = interfaceItemType + langExt.pointerLiteral
val handleEvents = async || eventDriven
val chainIDScope = if (langExt.usesInheritance) mc.className+langExt.scopeSeparator else ""
val opScope = langExt.operationScope(mc.className, !generateImplementation)
@@ -258,8 +265,13 @@ abstract class AbstractStateMachineGenerator {
"const "+ifItemPtr
else
ifItemPtr
- val usesHdlr = usesHandlerTrPoints(xpmc)
- '''
+ val usesHdlr = usesHandlerTrPoints(gc)
+ val nodes = gc.graph.allStateNodes.toList.sortBy[(stateGraphNode as State).genStateId]
+ val state2node = newHashMap
+ nodes.forEach[state2node.put(stateGraphNode as State, it)]
+ val states = nodes.map[stateGraphNode].filter(typeof(State)).toList
+ val transitionChains = gc.graph.allLinks.filter[isChainHead].toList.sortBy[transition.genChainId]
+ '''
/**
* calls exit codes while exiting from the current state to one of its
* parent states while remembering the history
@@ -273,11 +285,11 @@ abstract class AbstractStateMachineGenerator {
«privAccess»void «opScopePriv»exitTo(«selfPtr»«stateType» current__et, «stateType» to«IF usesHdlr», «boolType» handler__et«ENDIF») {
while (current__et!=to) {
switch (current__et) {
- «FOR state : xpmc.stateMachine.getBaseStateList()»
- case «state.getGenStateId()»:
- «IF state.hasExitCode(true)»«IF usesHdlr»if (!handler__et) «ENDIF»«state.getExitCodeOperationName()»(«langExt.selfPointer(false)»);«ENDIF»
- «setHistory(state.getParentStateId(), state.getGenStateId())»;
- current__et = «state.getParentStateId()»;
+ «FOR state : states»
+ case «state.getGenStateId»:
+ «IF state.hasExitCode(true)»«IF usesHdlr»if (!handler__et) «ENDIF»«state.exitCodeOperationName»(«langExt.selfPointer(false)»);«ENDIF»
+ «setHistory(state.parentStateId, state.genStateId)»;
+ current__et = «state.parentStateId»;
break;
«ENDFOR»
default:
@@ -300,11 +312,10 @@ abstract class AbstractStateMachineGenerator {
«IF generateImplementation»
«privAccess»«stateType» «opScopePriv»executeTransitionChain(«selfPtr»int chain__et«IF handleEvents», «constIfItemPtr» ifitem, «langExt.voidPointer» generic_data__et«ENDIF») {
switch (chain__et) {
- «var allchains = xpmc.getTransitionChains()»
- «FOR tc : allchains»
- case «chainIDScope»«tc.genChainId»:
+ «FOR tc : transitionChains»
+ case «chainIDScope»«tc.transition.genChainId»:
{
- «transitionChainGenerator.generateExecuteChain(xpmc, tc)»
+ «transitionChainGenerator.generateExecuteChain(gc, tc)»
}
«ENDFOR»
default:
@@ -327,8 +338,7 @@ abstract class AbstractStateMachineGenerator {
*/
«IF generateImplementation»
«privAccess»«stateType» «opScopePriv»enterHistory(«selfPtr»«stateType» state__et«IF usesHdlr», «boolType» handler__et«ENDIF») {
- «val baseStateList = xpmc.stateMachine.baseStateList»
- «val needsSkipVar = !baseStateList.filter(s|s.hasEntryCode(true)).empty»
+ «val needsSkipVar = !states.filter(s|s.hasEntryCode(true)).empty»
«IF needsSkipVar»
«boolType» skip_entry__et = «langExt.booleanConstant(false)»;
«ENDIF»
@@ -340,26 +350,26 @@ abstract class AbstractStateMachineGenerator {
}
while («langExt.booleanConstant(true)») {
switch (state__et) {
- «FOR state : baseStateList»
- case «state.getGenStateId()»:
- «IF state.hasEntryCode(true)»if (!(skip_entry__et«IF usesHdlr» || handler__et«ENDIF»)) «state.getEntryCodeOperationName()»(«langExt.selfPointer(false)»);«ENDIF»
- «IF state.isLeaf()»
+ «FOR state : states»
+ case «state.genStateId»:
+ «IF state.hasEntryCode(true)»if (!(skip_entry__et«IF usesHdlr» || handler__et«ENDIF»)) «state.entryCodeOperationName»(«langExt.selfPointer(false)»);«ENDIF»
+ «IF state.isLeaf»
/* in leaf state: return state id */
- return «state.getGenStateId()»;
+ return «state.getGenStateId»;
«ELSE»
/* state has a sub graph */
- «IF state.subgraph.hasInitTransition()»
+ «var sub_initt = state2node.get(state).subgraph.initialTransition»
+ «IF sub_initt!==null»
/* with init transition */
- if («getHistory(state.getGenStateId())»==NO_STATE) {
- «var sub_initt = state.subgraph.getInitTransition()»
- state__et = executeTransitionChain(«langExt.selfPointer(true)»«chainIDScope»«xpmc.getChain(sub_initt).genChainId»«IF handleEvents», «langExt.nullPointer», «langExt.nullPointer»«ENDIF»);
+ if («getHistory(state.genStateId)»==NO_STATE) {
+ state__et = executeTransitionChain(«langExt.selfPointer(true)»«chainIDScope»«sub_initt.genChainId»«IF handleEvents», «langExt.nullPointer», «langExt.nullPointer»«ENDIF»);
}
else {
- state__et = «getHistory(state.getGenStateId())»;
+ state__et = «state.genStateId.history»;
}
«ELSE»
/* without init transition */
- state__et = «getHistory(state.getGenStateId())»;
+ state__et = «state.genStateId.history»;
«ENDIF»
break;
«ENDIF»
@@ -383,8 +393,8 @@ abstract class AbstractStateMachineGenerator {
«IF generateImplementation»
«publicIf»void «opScope»executeInitTransition(«selfOnly») {
- «var initt = xpmc.stateMachine.getInitTransition()»
- int chain__et = «chainIDScope»«xpmc.getChain(initt).genChainId»;
+ «var initt = gc.graph.initialTransition»
+ int chain__et = «chainIDScope»«initt.genChainId»;
«stateType» next__et = «opScopePriv»executeTransitionChain(«langExt.selfPointer(true)»chain__et«IF handleEvents», «langExt.nullPointer», «langExt.nullPointer»«ENDIF»);
next__et = «opScopePriv»enterHistory(«langExt.selfPointer(true)»next__et«IF usesHdlr», «langExt.booleanConstant(false)»«ENDIF»);
setState(«langExt.selfPointer(true)»next__et);
@@ -412,10 +422,10 @@ abstract class AbstractStateMachineGenerator {
«IF handleEvents»
if (!handleSystemEvent(ifitem, evt, generic_data__et)) {
- «genStateSwitch(xpmc, usesHdlr)»
+ «genStateSwitch(gc, usesHdlr)»
}
«ELSE»
- «genStateSwitch(xpmc, usesHdlr)»
+ «genStateSwitch(gc, usesHdlr)»
«ENDIF»
if (chain__et != NOT_CAUGHT) {
«opScopePriv»exitTo(«langExt.selfPointer(true)»getState(«langExt.selfPointer(false)»), catching_state__et«IF usesHdlr», is_handler__et«ENDIF»);
@@ -423,7 +433,7 @@ abstract class AbstractStateMachineGenerator {
«stateType» next__et = «opScopePriv»executeTransitionChain(«langExt.selfPointer(true)»chain__et«IF handleEvents», ifitem, generic_data__et«ENDIF»);
next__et = «opScopePriv»enterHistory(«langExt.selfPointer(true)»next__et«IF usesHdlr», is_handler__et«ENDIF»);
setState(«langExt.selfPointer(true)»next__et);
- «finalAction()»
+ «finalAction»
}
}
}
@@ -440,230 +450,233 @@ abstract class AbstractStateMachineGenerator {
void «opScope»receiveEvent(«langExt.selfPointer(true)»«ifItemPtr» ifitem, int evt, «langExt.voidPointer» generic_data__et);
«ENDIF»
«ENDIF»
- '''
- }
-
- /**
- * generate the do code calls for a given state
- *
- * @param state the {@link State}
- * @return the generated code
- */
- def public String genDoCodes(State state) {'''
- «IF state.hasDoCode(true)»
- «state.getDoCodeOperationName()»(«langExt.selfPointer(false)»);
- «ENDIF»
- «IF state.eContainer.eContainer instanceof State»
- «genDoCodes(state.eContainer.eContainer as State)»
- «ENDIF»
- '''}
-
- /**
- * helper method which generates the state switch.
- * Asynchronous, data driven and event driven state machines are distinguished
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param usesHdlr if the state machine uses no handler {@link TransitionPoint}s
- * at all then unused variables can be avoided by passing <code>true</code>
- * @return the generated code
- */
- def public genStateSwitch(ExpandedModelComponent xpmc, boolean usesHdlr) {
- var async = xpmc.modelComponent.commType==ComponentCommunicationType::ASYNCHRONOUS
- var eventDriven = xpmc.modelComponent.commType==ComponentCommunicationType::EVENT_DRIVEN
- var dataDriven = xpmc.modelComponent.commType==ComponentCommunicationType::DATA_DRIVEN
- '''
- switch (getState(«langExt.selfPointer(false)»)) {
- «FOR state : xpmc.stateMachine.getLeafStateList()»
- case «state.getGenStateId()»:
- «IF async»
- «var atlist = xpmc.getActiveTriggers(state)»
- «IF !atlist.isEmpty»
- switch(trigger__et) {
- case POLLING:
- «genDataDrivenTriggers(xpmc, state, usesHdlr)»
- break;
- «genEventDrivenTriggers(xpmc, state, atlist, usesHdlr)»
- }
- «ELSE»
- «genDataDrivenTriggers(xpmc, state, usesHdlr)»
- «ENDIF»
- «ELSEIF dataDriven»
- «genDataDrivenTriggers(xpmc, state, usesHdlr)»
- «ELSEIF eventDriven»
- «var atlist = xpmc.getActiveTriggers(state)»
- «IF !atlist.isEmpty»
- switch(trigger__et) {
- «genEventDrivenTriggers(xpmc, state, atlist, usesHdlr)»
- }
- «ENDIF»
- «ENDIF»
- break;
- «ENDFOR»
- default:
- /* should not occur */
- break;
- }
- '''
- }
-
- /**
- * helper method which generates the data driven triggers
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param state the {@link State} for which the trigger if-else switch should be generated
- * @param usesHdlr if the state machine uses no handler {@link TransitionPoints}
- * at all then unused variables can be avoided by passing <code>true</code>
- * @return the generated code
- */
- def public genDataDrivenTriggers(ExpandedModelComponent xpmc, State state, boolean usesHdlr) {
- val chainIDScope = if (langExt.usesInheritance) xpmc.className+langExt.scopeSeparator else ""
- '''
- «genDoCodes(state)»
- «var transitions = xpmc.getOutgoingTransitionsHierarchical(state).filter(t|t instanceof GuardedTransition)»
- «FOR tr : transitions»
- if («guard((tr as GuardedTransition), "", xpmc)»)
- {
- «var chain = xpmc.getChain(tr)»
- chain__et = «chainIDScope»«chain.genChainId»;
- catching_state__et = «chain.stateContext.genStateId»;
- «IF chain.isHandler() && usesHdlr»
- is_handler__et = TRUE;
- «ENDIF»
- }
- «IF tr!=transitions.last»
- else
- «ENDIF»
- «ENDFOR»
- '''
- }
-
- /**
- * helper method which generates the event driven triggers
- *
- * @param xpmc the {@link ExpandedModelComponent}
- * @param state the {@link State} for which the trigger switch should be generated
- * @param atlist the list of {@link ActiveTrigger}s of this state
- * @param usesHdlr if the state machine uses no handler {@link TransitionPoints}
- * at all then unused variables can be avoided by passing <code>true</code>
- * @return the generated code
- */
- def public genEventDrivenTriggers(ExpandedModelComponent xpmc, State state, List<ActiveTrigger> atlist, boolean usesHdlr) {
- val chainIDScope = if (langExt.usesInheritance) xpmc.className+langExt.scopeSeparator else ""
- '''
- «FOR at : atlist»
- case «xpmc.getTriggerCodeName(at)»:
- «var needData = at.hasGuard»
- «IF needData»{ «langExt.getTypedDataDefinition(at.msg)»«ENDIF»
- «FOR tt : at.transitions SEPARATOR " else "»
- «var chain = xpmc.getChain(tt)»
- «guard(chain.getTransition as TriggeredTransition, at.trigger, xpmc)»
- {
- chain__et = «chainIDScope»«chain.genChainId»;
- catching_state__et = «chain.stateContext.genStateId»;
- «IF chain.isHandler() && usesHdlr»
- is_handler__et = «langExt.booleanConstant(true)»;
- «ENDIF»
- }
- «ENDFOR»
- «IF needData»}«ENDIF»
- break;
- «ENDFOR»
- default:
- /* should not occur */
- break;
- '''
- }
-
- def public getClassName(ExpandedModelComponent xpmc) {
- xpmc.modelComponent.className
- }
-
- def public getClassName(ModelComponent mc) {
- mc.componentName
- }
-
- /**
- * getter for history array
- *
- * @param state the ID of the history state
- * @return the generated code
- */
- def public getHistory(String state) {
- langExt.memberAccess+"history["+state+"]"
- }
-
- /**
- * setter for history array
- *
- * @param state the ID of the state whose history should be set
- * @param historyState the ID of the state that should be assigned
- * @return the generated code
- */
- def public setHistory(String state, String historyState) {
- langExt.memberAccess+"history["+state+"] = "+historyState
- }
-
- /**
- * @return the type of (temporary) state variables (defaults to "int")
- * and has to be signed
- */
- def public stateType() {
- "int"
- }
-
- /**
- * allow target language dependent generation of unreachable return in generated enterHistory method.
- * The default is just a comment.
- * @return the generated code
- */
- def public unreachableReturn() {
- "/* return NO_STATE; // required by CDT but detected as unreachable by JDT because of while (true) */"
- }
-
- /**
- * type of (temporary) boolean variables (defaults to "boolean")
- * @return the generated code
- */
- def public boolType() {
- return "boolean"
- }
-
- /**
- * empty, but may be overridden
- */
- def public finalAction() {
- ''''''
- }
-
- /**
- * the type of the interface item passed into the receiveEvent() method
- */
- def public interfaceItemType() {
- "InterfaceItemBase"
- }
-
- /**
- * empty, but may be overridden
- */
- def markVariableUsed(String varname) {
- ''''''
- }
-
- /**
- * helper method to determine whether this state machine uses handler transitions
- * points at all
- *
- * @param xpax the {@link ExpandedModelComponent}
- * @return <code>true</code> if the state machine uses handler transition points
- */
- def public usesHandlerTrPoints(ExpandedModelComponent xpmc) {
- if (xpmc.stateMachine.empty)
- return false
- !xpmc.stateMachine.allTrPointsRecursive.filter(t|t instanceof TransitionPoint && ((t as TransitionPoint).handler)).empty
- }
-
- def public String guard(TriggeredTransition tt, String trigger, ExpandedModelComponent mc)
- def public String guard(GuardedTransition tt, String trigger, ExpandedModelComponent mc)
- def public String genActionCodeMethod(ExpandedModelComponent xpmc, Transition tr, boolean generateImplementation)
- def public String genActionCodeMethods(ExpandedModelComponent xpmc, State state, boolean generateImplementation)
+ '''
+ }
+
+ /**
+ * generate the do code calls for a given state
+ *
+ * @param state the {@link State}
+ * @return the generated code
+ */
+ def public String genDoCodes(State state) {'''
+ «IF state.hasDoCode(true)»
+ «state.doCodeOperationName»(«langExt.selfPointer(false)»);
+ «ENDIF»
+ «IF state.eContainer.eContainer instanceof State»
+ «genDoCodes(state.eContainer.eContainer as State)»
+ «ENDIF»
+ '''}
+
+ /**
+ * helper method which generates the state switch.
+ * Asynchronous, data driven and event driven state machines are distinguished
+ *
+ * @param gc the {@link GraphContainer}
+ * @param usesHdlr if the state machine uses no handler {@link TransitionPoint}s
+ * at all then unused variables can be avoided by passing <code>true</code>
+ * @return the generated code
+ */
+ def public genStateSwitch(GraphContainer gc, boolean usesHdlr) {
+ var async = gc.component.commType==ComponentCommunicationType::ASYNCHRONOUS
+ var eventDriven = gc.component.commType==ComponentCommunicationType::EVENT_DRIVEN
+ var dataDriven = gc.component.commType==ComponentCommunicationType::DATA_DRIVEN
+ val allLeafStateNodes = gc.graph.allStateNodes.filter[isLeaf].toList.sortBy[(stateGraphNode as State).genStateId]
+ '''
+ switch (getState(«langExt.selfPointer(false)»)) {
+ «FOR stateNode : allLeafStateNodes»
+ «val state = stateNode.stateGraphNode as State»
+ case «state.genStateId»:
+ «val caughtTriggers = stateNode.caughtTriggers»
+ «IF async»
+ «IF !caughtTriggers.isEmpty»
+ switch(trigger__et) {
+ case POLLING:
+ «genDataDrivenTriggers(gc, stateNode, usesHdlr)»
+ break;
+ «genEventDrivenTriggers(gc, stateNode, usesHdlr)»
+ }
+ «ELSE»
+ «genDataDrivenTriggers(gc, stateNode, usesHdlr)»
+ «ENDIF»
+ «ELSEIF dataDriven»
+ «genDataDrivenTriggers(gc, stateNode, usesHdlr)»
+ «ELSEIF eventDriven»
+ «IF !caughtTriggers.isEmpty»
+ switch(trigger__et) {
+ «genEventDrivenTriggers(gc, stateNode, usesHdlr)»
+ }
+ «ENDIF»
+ «ENDIF»
+ break;
+ «ENDFOR»
+ default:
+ /* should not occur */
+ break;
+ }
+ '''
+ }
+
+ /**
+ * helper method which generates the data driven triggers
+ *
+ * @param gc the {@link GraphContainer}
+ * @param state the {@link State} for which the trigger if-else switch should be generated
+ * @param usesHdlr if the state machine uses no handler {@link TransitionPoints}
+ * at all then unused variables can be avoided by passing <code>true</code>
+ * @return the generated code
+ */
+ def public genDataDrivenTriggers(GraphContainer gc, Node stateNode, boolean usesHdlr) {
+ val chainIDScope = if (langExt.usesInheritance) gc.className+langExt.scopeSeparator else ""
+ val state = stateNode.stateGraphNode as State
+ '''
+ «genDoCodes(state)»
+ «var links = stateNode.getOutgoingLinksHierarchically.filter[transition instanceof GuardedTransition]»
+ «FOR l : links»
+ if («genGuardedTransitionGuard(l, "", gc)»)
+ {
+ chain__et = «chainIDScope»«l.transition.genChainId»;
+ catching_state__et = «l.transition.superState.genStateId»;
+ «IF l.isHandler && usesHdlr»
+ is_handler__et = TRUE;
+ «ENDIF»
+ }
+ «IF l!=links.last»
+ else
+ «ENDIF»
+ «ENDFOR»
+ '''
+ }
+
+ /**
+ * helper method which generates the event driven triggers
+ *
+ * @param gc the {@link GraphContainer}
+ * @param state the {@link State} for which the trigger switch should be generated
+ * @param usesHdlr if the state machine uses no handler {@link TransitionPoints}
+ * at all then unused variables can be avoided by passing <code>true</code>
+ * @return the generated code
+ */
+ def public genEventDrivenTriggers(GraphContainer gc, Node stateNode, boolean usesHdlr) {
+ val caughtTriggers = new ArrayList(stateNode.caughtTriggers).sortBy[triggerCodeName]
+ val chainIDScope = if (langExt.usesInheritance) gc.className+langExt.scopeSeparator else ""
+ '''
+ «FOR ct : caughtTriggers»
+ case «ct.triggerCodeName»:
+ «var needData = ct.hasGuard»
+ «IF needData»{ «langExt.getTypedDataDefinition(ct.msg)»«ENDIF»
+ «FOR link : ct.links SEPARATOR " else "»
+ «genTriggeredTransitionGuard(link, ct.trigger, gc)»
+ {
+ chain__et = «chainIDScope»«link.transition.genChainId»;
+ catching_state__et = «link.transition.superState.genStateId»;
+ «IF link.isHandler && usesHdlr»
+ is_handler__et = «langExt.booleanConstant(true)»;
+ «ENDIF»
+ }
+ «ENDFOR»
+ «IF needData»}«ENDIF»
+ break;
+ «ENDFOR»
+ default:
+ /* should not occur */
+ break;
+ '''
+ }
+
+ def public getClassName(GraphContainer gc) {
+ gc.component.className
+ }
+
+ def public getClassName(ModelComponent mc) {
+ mc.componentName
+ }
+
+ def getTriggerCodeName(CommonTrigger tr) {
+ val parts = tr.trigger.split(TriggerExtensions.TRIGGER_SEP)
+ return "TRIG_"+parts.get(0)+"__"+parts.get(1)
+ }
+
+ /**
+ * getter for history array
+ *
+ * @param state the ID of the history state
+ * @return the generated code
+ */
+ def public getHistory(String state) {
+ langExt.memberAccess+"history["+state+"]"
+ }
+
+ /**
+ * setter for history array
+ *
+ * @param state the ID of the state whose history should be set
+ * @param historyState the ID of the state that should be assigned
+ * @return the generated code
+ */
+ def public setHistory(String state, String historyState) {
+ langExt.memberAccess+"history["+state+"] = "+historyState
+ }
+
+ /**
+ * @return the type of (temporary) state variables (defaults to "int")
+ * and has to be signed
+ */
+ def public stateType() {
+ "int"
+ }
+
+ /**
+ * allow target language dependent generation of unreachable return in generated enterHistory method.
+ * The default is just a comment.
+ * @return the generated code
+ */
+ def public unreachableReturn() {
+ "/* return NO_STATE; // required by CDT but detected as unreachable by JDT because of while (true) */"
+ }
+
+ /**
+ * type of (temporary) boolean variables (defaults to "boolean")
+ * @return the generated code
+ */
+ def public boolType() {
+ return "boolean"
+ }
+
+ /**
+ * empty, but may be overridden
+ */
+ def public finalAction() {
+ ''''''
+ }
+
+ /**
+ * the type of the interface item passed into the receiveEvent() method
+ */
+ def public interfaceItemType() {
+ "InterfaceItemBase"
+ }
+
+ /**
+ * empty, but may be overridden
+ */
+ def markVariableUsed(String varname) {
+ ''''''
+ }
+
+ /**
+ * helper method to determine whether this state machine uses handler transitions
+ * points at all
+ *
+ * @param xpax the {@link GraphContainer}
+ * @return <code>true</code> if the state machine uses handler transition points
+ */
+ def public usesHandlerTrPoints(GraphContainer gc) {
+ !gc.graph.allTransitionPointNodes.filter(t|((t.stateGraphNode as TransitionPoint).handler)).empty
+ }
+
+ def public String genTriggeredTransitionGuard(Link link, String trigger, GraphContainer mc)
+ def public String genGuardedTransitionGuard(Link link, String trigger, GraphContainer mc)
+ def public String genActionCodeMethod(GraphContainer gc, Link link, boolean generateImplementation)
+ def public String genActionCodeMethods(GraphContainer gc, Node node, boolean generateImplementation)
} \ No newline at end of file
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/FSMExtensions.xtend b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/FSMExtensions.xtend
index 0a88f76c5..94f1a313c 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/FSMExtensions.xtend
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/FSMExtensions.xtend
@@ -12,19 +12,15 @@
package org.eclipse.etrice.generator.fsm.generic
-import org.eclipse.etrice.core.fsm.fSM.Transition
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.ExpandedModelComponent
-import java.util.List
-import org.eclipse.etrice.core.fsm.fSM.State
-import java.util.ArrayList
-import org.eclipse.etrice.core.fsm.fSM.StateGraph
-import org.eclipse.etrice.core.fsm.fSM.TransitionPoint
-import org.eclipse.etrice.core.fsm.fSM.ModelComponent
-import org.eclipse.etrice.core.fsm.util.FSMHelpers
import com.google.inject.Inject
+import java.util.ArrayList
+import java.util.List
+import org.eclipse.etrice.core.fsm.fSM.CPBranchTransition
import org.eclipse.etrice.core.fsm.fSM.DetailCode
import org.eclipse.etrice.core.fsm.fSM.Guard
-import org.eclipse.etrice.core.fsm.fSM.CPBranchTransition
+import org.eclipse.etrice.core.fsm.fSM.ModelComponent
+import org.eclipse.etrice.core.fsm.fSM.State
+import org.eclipse.etrice.core.fsm.util.FSMHelpers
/**
* @author Henrik Rentz-Reichert
@@ -75,36 +71,6 @@ class FSMExtensions {
return ret;
}
- //-------------------------------------------------------
- // state graph related methods
-
- /**
- * @param ac an {@link ExpandedActorClass}
- * @param s a {@link State}
- * @return a list of {@link Transition}s starting at the state and going up in the hierarchy
- * following the logic of evaluation of firing conditions
- */
- def List<Transition> getOutgoingTransitionsHierarchical(ExpandedModelComponent ac, State s) {
- var result = new ArrayList<Transition>()
-
- // own transitions
- result.addAll(ac.getOutgoingTransitions(s))
-
- // transition points on same level
- var sg = s.eContainer() as StateGraph
- for (tp : sg.getTrPoints()) {
- if (tp instanceof TransitionPoint)
- result.addAll(ac.getOutgoingTransitions(tp))
- }
-
- // recurse to super states
- if (sg.eContainer() instanceof State) {
- result.addAll(getOutgoingTransitionsHierarchical(ac, sg.eContainer() as State))
- }
-
- return result;
- }
-
/**
* @param states a list of {@link State}s
* @return a list ordered such that leaf states are last
@@ -113,7 +79,7 @@ class FSMExtensions {
val leaf = states.filter(s|s.leaf)
val nonLeaf = states.filter(s|!s.leaf)
- nonLeaf.union(leaf)
+ nonLeaf + leaf
}
/**
@@ -129,7 +95,7 @@ class FSMExtensions {
* @return a list of simple states with leaf states last
*/
def List<State> getAllBaseStatesLeavesLast(ModelComponent mc) {
- mc.allBaseStates.getLeafStatesLast
+ mc.allBaseStates.getLeafStatesLast.toList
}
/**
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ILanguageExtensionBase.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ILanguageExtensionBase.java
index 2c2c3be69..bc46b0d50 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ILanguageExtensionBase.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ILanguageExtensionBase.java
@@ -194,10 +194,19 @@ public interface ILanguageExtensionBase {
String superCall(String baseClassName, String method, String arguments);
/**
+ * the three results returned by {@link #org.eclipse.etrice.generator.fsm.generic.ILanguageExtensionBase.generateArglistAndTypedData(EObject)}
+ */
+ enum TypedDataKind {
+ COMMA_SEPARATED_PARAM_IN_CALL,
+ DECLARATION_AND_INITIALIZATION,
+ COMMA_SEPARATED_PARAM_IN_DECLARATION
+ }
+
+ /**
* return three strings used by the generator
*
* @param data the variable declaration
- * @return an array of three strings
+ * @return an array of three strings (see {@link #TypedDataKind})
* <ol>
* <li>the string that performs the cast from generic_data to the correct type and assigns it to a new variable</li>
* <li>the data as it appears in a method call</li>
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ITransitionChainVisitor.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ITransitionChainVisitor.java
new file mode 100644
index 000000000..2633814c8
--- /dev/null
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/ITransitionChainVisitor.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2010 protos software gmbh (http://www.protos.de).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * CONTRIBUTORS:
+ * Thomas Schuetz and Henrik Rentz-Reichert (initial contribution)
+ *
+ *******************************************************************************/
+
+package org.eclipse.etrice.generator.fsm.generic;
+
+import org.eclipse.etrice.core.fsm.fSM.CPBranchTransition;
+import org.eclipse.etrice.core.fsm.fSM.ContinuationTransition;
+import org.eclipse.etrice.core.fsm.fSM.State;
+import org.eclipse.etrice.core.fsm.fSM.TransitionBase;
+
+/**
+ * This interface describes the transition chain visitor.
+ * The visitor is used by the code generator to generate the code associated with a transition chain.
+ * It is passed in a call to
+ * {@link org.eclipse.etrice.core.genmodel.etricegen.TransitionChain#genExecuteChain(ITransitionChainVisitor)
+ * TransitionChain.genExecuteChain(ITransitionChainVisitor)}.
+ *
+ * <p>
+ * The visitor has to be implemented by the concrete target language generator.
+ * </p>
+ *
+ * @author Henrik Rentz-Reichert
+ *
+ */
+public interface ITransitionChainVisitor {
+
+ /**
+ * @param tc the transition chain
+ * @return a typed declaration of the data associated with this message
+ */
+ String genTypedData(TransitionBase tc);
+
+ /**
+ * @param tr a transition
+ * @return a call of the action operation (as generated by the generator)
+ */
+ String genActionOperationCall(TransitionBase tr);
+
+ /**
+ * @param state a state
+ * @return a call of the entry operation (as generated by the generator)
+ */
+ String genEntryOperationCall(State state);
+
+ /**
+ * @param state a state
+ * @return a call of the exit operation (as generated by the generator)
+ */
+ String genExitOperationCall(State state);
+
+ /**
+ * @param tr a choice point branch transition (not the default branch)
+ * @param isFirst <code>true</code> if this is the first of a series of if statements
+ * @return code for the [else] if statement with condition (guard) and block opening
+ */
+ String genElseIfBranch(CPBranchTransition tr, boolean isFirst);
+
+ /**
+ * @param tr the choice point default branch transition
+ * @return code for the final else with block opening
+ */
+ String genElseBranch(ContinuationTransition tr);
+
+ /**
+ * @return the final closing of the block
+ */
+ String genEndIf();
+
+ /**
+ * @param state a state
+ * @param executeEntryCode <code>true</code> if entry code of state should be executed
+ * @return a return statement with the ID of the state
+ */
+ String genReturnState(State state, boolean executeEntryCode);
+
+}
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainGenerator.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainGenerator.java
index 5d124b208..8ccc57d76 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainGenerator.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainGenerator.java
@@ -12,13 +12,30 @@
package org.eclipse.etrice.generator.fsm.generic;
-import org.eclipse.emf.ecore.EObject;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.etrice.core.fsm.fSM.CPBranchTransition;
+import org.eclipse.etrice.core.fsm.fSM.ChoicePoint;
+import org.eclipse.etrice.core.fsm.fSM.ContinuationTransition;
+import org.eclipse.etrice.core.fsm.fSM.EntryPoint;
+import org.eclipse.etrice.core.fsm.fSM.ExitPoint;
import org.eclipse.etrice.core.fsm.fSM.InitialTransition;
-import org.eclipse.etrice.core.fsm.fSM.Transition;
-import org.eclipse.etrice.core.fsm.fSM.TriggeredTransition;
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.ExpandedModelComponent;
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.TransitionChain;
+import org.eclipse.etrice.core.fsm.fSM.State;
+import org.eclipse.etrice.core.fsm.fSM.StateGraphNode;
+import org.eclipse.etrice.core.fsm.fSM.TrPoint;
+import org.eclipse.etrice.core.fsm.fSM.TransitionPoint;
+import org.eclipse.etrice.core.fsm.naming.FSMNameProvider;
+import org.eclipse.etrice.core.fsm.util.FSMHelpers;
+import org.eclipse.etrice.core.genmodel.fsm.FsmGenExtensions;
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.GraphContainer;
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Link;
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Node;
import org.eclipse.etrice.generator.fsm.base.CodegenHelpers;
+import org.eclipse.etrice.generator.fsm.generic.ILanguageExtensionBase.TypedDataKind;
import com.google.inject.Inject;
@@ -32,27 +49,125 @@ public class TransitionChainGenerator {
@Inject private ILanguageExtensionBase languageExt;
@Inject private CodegenHelpers codegenHelpers;
@Inject private IDetailCodeTranslator translator;
+ @Inject private FSMNameProvider fsmNameProvider;
+ @Inject private FSMHelpers fsmHelpers;
- public String generateExecuteChain(ExpandedModelComponent xpmc, TransitionChain tc) {
- TransitionChainVisitor tcv = new TransitionChainVisitor(xpmc, languageExt, codegenHelpers, translator);
- tcv.init(tc);
+ public String generateExecuteChain(GraphContainer gc, Link l) {
+ TransitionChainVisitor tcv = new TransitionChainVisitor(gc, languageExt, codegenHelpers, translator);
+ tcv.init(l.getTransition());
- return tc.genExecuteChain(tcv);
+ return genExecuteChain(l, tcv);
}
- public String generateArgumentList(ExpandedModelComponent xpmc, Transition t) {
- if (t instanceof InitialTransition)
+ public String generateArgumentList(GraphContainer gc, Link l) {
+ if (l.getTransition() instanceof InitialTransition)
// actually is InitialTransition
return "";
- TransitionChain chain = xpmc.getChain(t);
- if (!(chain.getTransition() instanceof TriggeredTransition))
+ if (!l.isIfitemTriggered())
return "";
- return generateTypedArgumentList(xpmc.getData(t));
+ return languageExt.generateArglistAndTypedData(l.getCommonData())[TypedDataKind.COMMA_SEPARATED_PARAM_IN_DECLARATION.ordinal()];
+ }
+
+ public String genExecuteChain(Link l, ITransitionChainVisitor tcv) {
+ StringBuilder result = new StringBuilder();
+
+ /* TODO: the next generated code declares a correctly typed variable for the generic data.
+ * It is hard to determine whether it is actually needed though.
+ * It is needed in non-initial transitions with action code that are not data driven.
+ * It might be needed in condition expressions. But this code would have to be parsed
+ * with uncertain result (because of e.g. comments).
+ */
+ result.append(tcv.genTypedData(l.getTransition()));
+
+ genChainCode(l, tcv, result);
+
+ return result.toString();
}
+
+ private void genChainCode(Link l, ITransitionChainVisitor tcv, StringBuilder result) {
+
+ result.append(tcv.genActionOperationCall(l.getTransition()));
+
+ Node target = l.getTarget();
+ StateGraphNode stateGraphNode = target.getStateGraphNode();
+ List<Link> outgoing = new ArrayList<Link>(target.getOutgoing());
+
+ // TODO: remove sorting again
+ final CodegenHelpers cgh = new CodegenHelpers();
+ Collections.sort(outgoing, new Comparator<Link>() {
+
+ @Override
+ public int compare(Link o1, Link o2) {
+ String id1 = cgh.getGenChainId(o1.getTransition());
+ String id2 = cgh.getGenChainId(o2.getTransition());
+ return id1.compareTo(id2);
+ }
+
+ });
+
+ if (stateGraphNode instanceof ChoicePoint) {
+ Link dflt = FsmGenExtensions.getChoicepointDefaultBranch(target);
+ assert(dflt!=null): "ChoicePoint "+fsmNameProvider.getFullPath(stateGraphNode)+" has no default branch!";
+
+ // first generate all choicepoint branches as if/else
+ boolean isFirst = true;
+ for (Link cond : outgoing) {
+ if (cond==dflt)
+ continue;
+
+ assert(cond.getTransition() instanceof CPBranchTransition): "The non default ChoicePoint branch "
+ +fsmNameProvider.getFullPath(cond.getTransition())+" must be of type CPBranchTransition!";
+
+ result.append(tcv.genElseIfBranch((CPBranchTransition) cond.getTransition(), isFirst));
+ isFirst = false;
- public String generateTypedArgumentList(EObject data) {
- return languageExt.generateArglistAndTypedData(data)[2];
+ genChainCode(cond, tcv, result);
+ }
+
+ // then generate the default branch
+ result.append(tcv.genElseBranch((ContinuationTransition) dflt.getTransition()));
+
+ genChainCode(dflt, tcv, result);
+
+ result.append(tcv.genEndIf());
+ }
+ else {
+ if (stateGraphNode instanceof TrPoint) {
+ if (stateGraphNode instanceof TransitionPoint) {
+ // TransitionPoint is final destination of the chain
+ result.append(tcv.genReturnState(fsmHelpers.getParentState(stateGraphNode), false));
+ return;
+ }
+ else {
+ assert(outgoing.size()<=1): "TrPoint "+fsmNameProvider.getFullPath(stateGraphNode)
+ +" is expected to have at most one outgoing transition!";
+ if (outgoing.size()==1) {
+ State state = fsmHelpers.getParentState(stateGraphNode);
+ if (stateGraphNode instanceof EntryPoint) {
+ if (state!=null && !target.isInherited() && fsmHelpers.hasEntryCode(state, true))
+ result.append(tcv.genEntryOperationCall(state));
+ }
+ else if (stateGraphNode instanceof ExitPoint) {
+ if (state!=null && !target.isInherited() && fsmHelpers.hasExitCode(state, true))
+ result.append(tcv.genExitOperationCall(state));
+ }
+ else {
+ assert(false): "unexpected sub type";
+ }
+ }
+ }
+ if (! outgoing.isEmpty()) {
+ genChainCode(outgoing.get(0), tcv, result);
+ }
+ }
+ else {
+ // the following assertion should always hold true
+ assert(stateGraphNode instanceof State): "A transition target can be a ChoicePoint, a TrPoint or a State!";
+
+ result.append(tcv.genReturnState((State) stateGraphNode, true));
+ }
+ }
}
}
diff --git a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainVisitor.java b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainVisitor.java
index 1354d593d..2e4a17115 100644
--- a/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainVisitor.java
+++ b/plugins/org.eclipse.etrice.generator.fsm/src/org/eclipse/etrice/generator/fsm/generic/TransitionChainVisitor.java
@@ -16,13 +16,15 @@ import org.eclipse.etrice.core.fsm.fSM.CPBranchTransition;
import org.eclipse.etrice.core.fsm.fSM.ContinuationTransition;
import org.eclipse.etrice.core.fsm.fSM.GuardedTransition;
import org.eclipse.etrice.core.fsm.fSM.InitialTransition;
+import org.eclipse.etrice.core.fsm.fSM.RefinedTransition;
import org.eclipse.etrice.core.fsm.fSM.State;
-import org.eclipse.etrice.core.fsm.fSM.Transition;
+import org.eclipse.etrice.core.fsm.fSM.TransitionBase;
import org.eclipse.etrice.core.fsm.util.FSMHelpers;
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.ExpandedModelComponent;
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.ITransitionChainVisitor;
-import org.eclipse.etrice.core.genmodel.fsm.fsmgen.TransitionChain;
+import org.eclipse.etrice.core.genmodel.fsm.FsmGenExtensions;
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.GraphContainer;
+import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Link;
import org.eclipse.etrice.generator.fsm.base.CodegenHelpers;
+import org.eclipse.etrice.generator.fsm.generic.ILanguageExtensionBase.TypedDataKind;
/**
* Implementation of the {@link org.eclipse.etrice.core.genmodel.fsm.fsmgen.ITransitionChainVisitor ITransitionChainVisitor} interface.
@@ -36,12 +38,11 @@ public class TransitionChainVisitor implements ITransitionChainVisitor {
private FSMHelpers fsmHelpers = new FSMHelpers();
// Initialized in constructor
- private ExpandedModelComponent xpac;
+ private GraphContainer gc;
private ILanguageExtensionBase langExt;
private CodegenHelpers codegenHelpers;
private IDetailCodeTranslator translationProvider;
- private TransitionChain tc = null;
private boolean dataDriven = false;
/**
@@ -52,42 +53,45 @@ public class TransitionChainVisitor implements ITransitionChainVisitor {
* @param languageExt
*/
protected TransitionChainVisitor(
- ExpandedModelComponent xpac,
+ GraphContainer gc,
ILanguageExtensionBase languageExt,
CodegenHelpers codegenHelpers,
IDetailCodeTranslator translationProvider
) {
- this.xpac = xpac;
+ this.gc = gc;
this.langExt = languageExt;
this.codegenHelpers = codegenHelpers;
this.translationProvider = translationProvider;
}
- protected void init(TransitionChain tc) {
- this.tc = tc;
-
- if (tc.getTransition() instanceof GuardedTransition) {
+ protected void init(TransitionBase tr) {
+ while (tr instanceof RefinedTransition) {
+ tr = ((RefinedTransition) tr).getTarget();
+ }
+ if (tr instanceof GuardedTransition) {
dataDriven = true;
}
- else if (tc.getTransition() instanceof InitialTransition) {
+ else if (tr instanceof InitialTransition) {
dataDriven = true;
}
}
// ITransitionChainVisitor interface
- public String genActionOperationCall(Transition tr) {
+ public String genActionOperationCall(TransitionBase tr) {
boolean noIfItem = dataDriven;
- for(TransitionChain tc : xpac.getChains(tr))
- noIfItem |= tc.getTransition() instanceof InitialTransition;
+ Link l = FsmGenExtensions.getLinkFor(gc, tr);
+ for (Link ch : l.getChainHeads()) {
+ noIfItem |= ch.getTransition() instanceof InitialTransition;
+ }
if (fsmHelpers.hasDetailCode(tr.getAction())) {
if (noIfItem)
return codegenHelpers.getActionCodeOperationName(tr)+"("+langExt.selfPointer(false)+");\n";
else {
String dataArg = "";
- if(xpac.getData(tr) != null)
- dataArg = langExt.generateArglistAndTypedData(tc.getData())[0];
+ if (l.getCommonData() != null)
+ dataArg = langExt.generateArglistAndTypedData(l.getCommonData())[TypedDataKind.COMMA_SEPARATED_PARAM_IN_CALL.ordinal()];
return codegenHelpers.getActionCodeOperationName(tr)+"("+langExt.selfPointer(true)+"ifitem"+dataArg+");\n";
}
}
@@ -129,9 +133,9 @@ public class TransitionChainVisitor implements ITransitionChainVisitor {
return "return " + codegenHelpers.getGenStateId(state) + " + STATE_MAX;";
}
- public String genTypedData(TransitionChain tc) {
- String[] result = langExt.generateArglistAndTypedData(tc.getData());
- return result[1];
+ public String genTypedData(TransitionBase tr) {
+ Link l = FsmGenExtensions.getLinkFor(gc, tr);
+ return langExt.generateArglistAndTypedData(l.getCommonData())[TypedDataKind.DECLARATION_AND_INITIALIZATION.ordinal()];
}
}

Back to the top