Przeglądaj źródła

added suppoert for isActive and isFinal tests to Java code generator
(issue #105)

Axel Terfloth 10 lat temu
rodzic
commit
d6d57bf3de

+ 18 - 6
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/IStatemachine.xtend

@@ -37,20 +37,32 @@ class IStatemachine {
 		public interface IStatemachine {
 		
 			/**
-			* Initializes the statemachine. Use to init internal variables etc.
-			*/
+			 * Initializes the statemachine. Use to init internal variables etc.
+			 */
 			public void init();
 		
 			/**
-			* Enters the statemachine. Sets the statemachine in a defined state.
-			*/
+			 * Enters the statemachine. Sets the statemachine in a defined state.
+			 */
 			public void enter();
 		
 			/**
-			* Exits the statemachine. Leaves the statemachine with a defined state.
-			*/
+			 * Exits the statemachine. Leaves the statemachine with a defined state.
+			 */
 			public void exit();
 		
+			/**
+			 * Checks if the statemachine is active. 
+			 * A statemachine is active if it was entered. It is inactive if it has nt been entered at all or if it was exited.
+			 */
+			public boolean isActive();
+		
+			/**
+			 * Checks if all active states are final. 
+			 * If there are no active states then the statemachine is considered as incative and this method returns false.
+			 */
+			public boolean isFinal();
+		
 			/**
 			* Start a run-to-completion cycle.
 			*/

+ 18 - 0
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/RunnableWrapper.xtend

@@ -96,6 +96,24 @@ class RunnableWrapper {
 				}
 			}
 			
+			/**
+			 * isActive() will be delegated thread safe to the wrapped statemachine.  
+			 */ 
+			public boolean isActive() {
+				synchronized(statemachine) {
+					return statemachine.isActive();
+				}
+			}
+			
+			/**
+			 * isFinal() will be delegated thread safe to the wrapped statemachine.  
+			 */ 
+			public boolean isFinal() {
+				synchronized(statemachine) {
+					return statemachine.isFinal();
+				}
+			}
+			
 			
 			/**
 			 * runCycle() will be delegated thread safe to the wrapped statemachine.  

+ 106 - 0
plugins/org.yakindu.sct.generator.java/src/org/yakindu/sct/generator/java/Statemachine.xtend

@@ -24,6 +24,9 @@ import org.yakindu.sct.model.sgen.GeneratorEntry
 import org.yakindu.sct.model.stext.stext.EventDefinition
 import org.yakindu.sct.model.stext.stext.InterfaceScope
 import org.yakindu.sct.model.stext.stext.VariableDefinition
+import org.yakindu.sct.model.sexec.ExecutionState
+import org.yakindu.sct.model.sgraph.FinalState
+import java.util.ArrayList
 
 class Statemachine {
 	
@@ -59,6 +62,10 @@ class Statemachine {
 			
 			«flow.exitFunction»
 			
+			«flow.activeFunction»
+			
+			«flow.finalFunction»
+			
 			«flow.clearInEventsFunction»
 			
 			«flow.clearOutEventsFunction»
@@ -230,6 +237,105 @@ class Statemachine {
 		}
 	'''
 	
+	def protected isActiveFunction(ExecutionFlow flow) '''
+		/**
+		 * @see IStatemachine#isActive()
+		 */
+		@Override
+		public boolean isActive(){
+			
+			return 
+				«FOR i : 0 ..< flow.stateVector.size SEPARATOR '||'»
+				stateVector[«i»] != State.«nullStateName» 
+				«ENDFOR»;
+		}
+	'''
+
+	def protected isFinalFunction(ExecutionFlow flow) {
+		val finalStateImpactVector = flow.finalStateImpactVector
+
+		'''
+			/** 
+			«IF !finalStateImpactVector.isCompletelyCovered»
+			 * Always returns 'false' since this state machine can never become final.
+			 *
+			«ENDIF»
+			 * @see IStatemachine#isFinal() 
+			 */
+			@Override
+			public boolean isFinal(){
+		''' +
+		
+		// only if the impact vector is completely covered by final states the state machine 
+		// can become final
+		{if (flow.finalStateImpactVector.isCompletelyCovered) {'''
+			return «FOR i : 0 ..<finalStateImpactVector.size SEPARATOR ' && '»
+				(«FOR fs : finalStateImpactVector.get(i) SEPARATOR ' || '» 
+					stateVector[«i»] == «
+					IF fs.stateVector.offset == i
+						»State.«fs.stateName.asEscapedIdentifier»«
+					ELSE
+						»State.«nullStateName»«
+					ENDIF»«
+				ENDFOR»)
+			«ENDFOR»;
+		'''} else {'''
+			return false;
+		'''} }
+		
+		+ '''}'''
+	}
+	
+	/**
+	 * This function calculates the final state impact vector.
+	 * This vector is an array of the size of the state machines state vector. 
+	 * Each array slot holds a List of ExecutionState instances that map to FinalState elements
+	 * in the orginal model. The assignment of a final state to a slot means that if this state is 
+	 * active it has impact on the vector slot. Here two cases have to be distinguished:
+	 * 
+	 * 1. The final state is directly assigned to the slot (the states vector offset). If the state is active
+	 *    then the slot will contain a reference to this state
+	 * 2. If the parent region contains orthogonal states then all other vector positions covered by the region
+	 *    are empty (refer to no state) if the state is active so there is an indirect impact on the vector. 
+	 * 
+	 * TODO: move to sexec package/utils 
+	 */
+	def protected List<ExecutionState>[] finalStateImpactVector(ExecutionFlow flow) {
+
+		// we use a vector of list of states to mark which final state has impact on the different slots.
+		val List<ExecutionState>[] vector = newArrayOfSize(flow.stateVector.size)
+		
+		// process all final states and mark all vector positions with the states 
+		flow.states.filter[s | s.sourceElement instanceof FinalState].forEach[ fs |
+			// the state vector of the final states region is relevant since the final state has impact on its 
+			// own vector position and all other positions covered by the region.
+			// > if a final state is active then all other positions must contain the null state.
+			var regionVector = fs.superScope.stateVector
+			for ( i : regionVector.offset ..< regionVector.offset + regionVector.size) {
+				// create a list for the slot if it does not already exist.
+				if (vector.get(i) == null) {
+					vector.set(i, new ArrayList<ExecutionState>())
+				}
+				// and add the final state to it.
+				vector.get(i).add(fs);  
+				// so all vector positions are marked with all those final states that have impact on the slot.
+			}
+		]			
+				
+		return vector
+	}
+	
+	
+	/** 
+	 * Checks if all state vector positions are covered by states. 
+	 * 
+	 * TODO: move
+	 */
+	def protected boolean isCompletelyCovered(List<ExecutionState>[] finalStateImpactVector) {
+		finalStateImpactVector.forall[ l | (l != null) && (!l.isEmpty) ]
+	}
+	
+	
 	def protected timingFunctions(ExecutionFlow flow) '''
 		«IF flow.timed»
 			/**