// public class DoorContext : Context<StateRoot, DoorContext> private void WriteClass(StateType state) { if (state.Type.HasFlag(StateType.TypeFlags.TOP) == true) { string contextClassName = GetContextClassName(state); string contextParentClassName = GetContextParentClassName(state); string stateClassName = GetStateClassName(state); // class DoorContext CodeTypeDeclaration contextCode = new CodeTypeDeclaration(contextClassName); // doc contextCode.Comments.Add(new CodeCommentStatement(contextClassName)); // public contextCode.Attributes = MemberAttributes.Public; // Context<StateTop, DoorContext> or ContextAsync<StateTop, DoorContext> contextCode.BaseTypes.Add(new CodeTypeReference(GetContextBaseClassName(state), new CodeTypeReference[] { new CodeTypeReference(stateClassName), new CodeTypeReference(contextParentClassName) })); foreach (KeyValuePair <string, string> kvp in Model.EventInterfaceMap) { string interfaceName = kvp.Key; contextCode.BaseTypes.Add(new CodeTypeReference(interfaceName)); } CodeNamespace.Types.Add(contextCode); WriteFields(contextCode); WriteFieldsParallel(contextCode, state); WriteFieldsTimer(contextCode, state); WriteConstructor(contextCode, state); WriteEvents(contextCode, state); WriteMethodSetState(contextCode, state); WriteMethodEnterInitialState(contextCode, state); WriteMethodLeaveCurrentState(contextCode, state); WriteMethodEnterHistoryState(contextCode, state); WriteInitializeTimers(contextCode, state); WriteTimersStartStop(contextCode, state); WriteProperties(contextCode); WritePropertiesParallel(contextCode, state); } if (state.parallel != null) { foreach (StateType stateOrthogonal in state.parallel.state) { WriteClass(stateOrthogonal); } } if (state.state != null) { foreach (StateType stateChild in state.state) { WriteClass(stateChild); } } }
/// <summary> /// Set the current state given its name ///public override void SetState(string stateName) ///{ /// if ((stateName == "Running")) /// { /// this.SetInitialState(PersistenceParallelRunningState.Instance); /// this.ContextParallel = this.PersistenceParallelRunningParallel; /// this.ContextParallel.ActiveState = 2; /// return; /// } /// if ((stateName == "End")) /// { /// this.SetInitialState(PersistenceParallelEndState.Instance); /// return; /// } /// throw new System.ArgumentException(); ///} /// </summary> /// <param name="state"></param> /// <param name="contextCode"></param> /// <summary> private void WriteMethodSetState(CodeTypeDeclaration contextCode, StateType state) { CodeMemberMethod setStateMethod = new CodeMemberMethod(); contextCode.Members.Add(setStateMethod); setStateMethod.Comments.Add(new CodeCommentStatement("Set the current state given its name")); setStateMethod.Name = "SetState"; setStateMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override; string stateNameVar = "stateName"; setStateMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.String"), stateNameVar)); foreach (StateType subState in state.ChildList) { var codeBinaryOperatorExpression = new CodeBinaryOperatorExpression( new CodeVariableReferenceExpression(stateNameVar), CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(subState.name)); var conditionalStatement = new CodeConditionStatement(codeBinaryOperatorExpression); // PersistenceOnState.Instance string subStateClassName = GetStateClassName(subState); var stateDotInstance = new CodeFieldReferenceExpression(new CodeVariableReferenceExpression(subStateClassName), "Instance"); // SetInitialState(PersistenceOnState.Instance); CodeMethodInvokeExpression setInitialStateInvoke = new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "SetInitialState", stateDotInstance); conditionalStatement.TrueStatements.Add(setInitialStateInvoke); if (subState.Type.HasFlag(StateType.TypeFlags.PARALLEL) == true) { //this.ContextParallel = this.PersistenceParallelRunningParallel; var contextParallelVar = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "ContextParallel"); var parallelVar = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), GetParallelClassName(subState)); var statementAssignParallel = new CodeAssignStatement(contextParallelVar, parallelVar); conditionalStatement.TrueStatements.Add(statementAssignParallel); // this.ContextParallel.ActiveState; var parallelRunningDotActiveState = new CodeFieldReferenceExpression(contextParallelVar, "ActiveState"); // this.ContextParallel.ActiveState = 2; CodeStatement parallelRunningActiveStateSet = new CodeAssignStatement(parallelRunningDotActiveState, new CodePrimitiveExpression(subState.parallel.state.Length)); conditionalStatement.TrueStatements.Add(parallelRunningActiveStateSet); } conditionalStatement.TrueStatements.Add(new CodeMethodReturnStatement()); setStateMethod.Statements.Add(conditionalStatement); } var statetementThrow = new CodeThrowExceptionStatement( new CodeObjectCreateExpression( new CodeTypeReference(typeof(System.ArgumentException)), new CodeExpression[] { })); setStateMethod.Statements.Add(statetementThrow); }
/// <summary> /// Fill the state parent and Type, add the state to the map state. /// This is a recursive function. /// </summary> /// <param name="state"></param> /// <param name="stateParent"></param> private void FillState(StateType state, StateType stateParent, StateType stateParallel) { if (stateMap.ContainsKey(state.name) == true) { ts.TraceEvent(TraceEventType.Error, 1, "FillState: {0} already exist", state.name); } else { stateMap.Add(state.name, state); } state.Parent = stateParent; state.StateParallel = stateParallel; ts.TraceEvent(TraceEventType.Verbose, 1, "FillState: {0}", state.name); if (state.kindSpecified == true) { switch (state.kind) { case StateKindType.final: state.Type = state.Type | StateType.TypeFlags.FINAL; break; case StateKindType.history: state.Type = state.Type | StateType.TypeFlags.HISTORY; break; default: //Should not happen break; } } StateType stateTop = GetStateTop(state); if ((stateParent != null) && (state.Type.HasFlag(StateType.TypeFlags.HISTORY) == false)) { stateTop.ChildAdd(state); } if (state.parallel != null) { // Parallel region state.Type = state.Type | StateType.TypeFlags.PARALLEL | StateType.TypeFlags.LEAF; stateTop.ParallelList.Add(state); if (state.parallel.state != null) { foreach (StateType stateOrthogonal in state.parallel.state) { FillState(stateOrthogonal, null, state); } } } else if (state.state == null) { // No child state.Type = state.Type | StateType.TypeFlags.LEAF; } else { // Childs state.Type = state.Type | StateType.TypeFlags.COMPOSITE; if (state.HasChildHistory()) { state.Type = state.Type | StateType.TypeFlags.HAS_HISTORY; } if (stateParent == null) { state.Type = state.Type | StateType.TypeFlags.TOP; //For top states in a parallel state machines, set the flag to HAS_HISTORY, it saves the current state upon OnExit if ((state.StateParallel != null) && state.StateParallel.HasParentStateHistory()) { state.Type = state.Type | StateType.TypeFlags.HAS_HISTORY; } } if ((state.kindSpecified == true) && (state.kind == StateKindType.final)) { // TODO ERROR Composite state cannot have error or final atttribute } foreach (StateType stateChild in state.state) { FillState(stateChild, state, stateParallel); } } }
// //public DoorContext(Door door) : base(contextParent) //public DoorContext(Door door, DoorContextParent contextParent) : base(contextParent) //public MicrowaveContext(Microwave microwave) //{ // Name = "MicrowaveContext"; // this._microwave = microwave; // this.InitializeTimers(); // this._parallelOperating = new MicrowaveContextOperatingParallel(microwave, this); // this.SetInitialState(MicrowaveInitialState.Instance); //} private void WriteConstructor(CodeTypeDeclaration contextCode, StateType state) { CodeConstructor ctor = new CodeConstructor(); ctor.Attributes = MemberAttributes.Public; ctor.Comments.Add(new CodeCommentStatement("Constructor")); ObjectType[] objects = Model.settings.@object; string contextClassName = GetContextClassName(state); string contextParentClassName = GetContextParentClassName(state); foreach (ObjectType obj in Model.settings.@object) { ctor.Parameters.Add(new CodeParameterDeclarationExpression(obj.@class, obj.instance)); } if (Model.IsRoot(state) == false) { ctor.Parameters.Add(new CodeParameterDeclarationExpression(contextParentClassName, "contextParent")); ctor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("contextParent")); } // Name = "DoorContext"; ctor.Statements.Add( new CodeAssignStatement(new CodeVariableReferenceExpression("Name"), new CodePrimitiveExpression(contextClassName))); // this._door = door; foreach (ObjectType obj in Model.settings.@object) { ctor.Statements.Add( new CodeAssignStatement( new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), GetObjectFieldName(obj.instance)), new CodeVariableReferenceExpression(obj.instance))); } WriteParallelNew(ctor, state); // this.InitializeTimers() if ((Model.GetTimersAll().Count != 0) && (Model.IsRoot(state) == true)) { CodeMethodInvokeExpression initializeTimersMethod = new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "InitializeTimers"); ctor.Statements.Add(initializeTimersMethod); } // Get the initial state string stateInitialClassName = GetStateClassName(GetStateInitial(state)); // SetInitialState(StateIdle.Instance); CodeMethodInvokeExpression setInitialStateInvoke = new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "SetInitialState"); setInitialStateInvoke.Parameters.Add(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression(stateInitialClassName), "Instance")); ctor.Statements.Add(setInitialStateInvoke); contextCode.Members.Add(ctor); }
/// <summary> /// Returns the context depth between the state and the next state. /// </summary> /// <param name="state">The current state.</param> /// <param name="stateNext">The next state.</param> /// <returns></returns> public int ContextDepth(StateType state, StateType stateNext) { int depth = 0; return(ContextDepth(state, stateNext, depth)); }
/// <summary> /// Is this state the root state /// </summary> /// <param name="state"></param> /// <returns></returns> public bool IsRoot(StateType state) { return(state.Type.HasFlag(StateType.TypeFlags.ROOT)); }
/// <summary> /// Get the state class name: DoorXxxState /// </summary> /// <param name="state"></param> /// <returns></returns> protected string GetStateClassName(StateType state) { return(Model.settings.name + state.name + "State"); }
/// <summary> /// Add a state to the state map. /// </summary> /// <param name="state"></param> public void AddState(StateType state) { stateMap[state.name] = state; }
// If next state is final, invoke: // context.OnEnd(); // or // context.ContextParent.OnEnd(); protected void WriteContextOnEnd(CodeStatementCollection statements, StateType state, StateType stateNext) { //Special case when the next state is a final state. if ((stateNext != null) && (stateNext.Type.HasFlag(StateType.TypeFlags.FINAL))) { statements.Add(new CodeCommentStatement("Notify the end of this state machine.")); // context or context.ContextParent or context.ContextParent.ContextParent .... depending where is stateNext compared to state. var contextExpression = GetContextParentExpression(state, stateNext); // context.OnEnd(); CodeMethodInvokeExpression methodInvoke = new CodeMethodInvokeExpression( contextExpression, "OnEnd"); statements.Add(methodInvoke); } }
//} // StateMachineHelper.ProcessTransitionBegin<DoorContext, DoorContext, StateTop>(context, StateNext.Instance); // or // StateMachineHelper.ProcessTransitionEnd<DoorContext, DoorContext, StateTop>(context, StateNext.Instance); protected void WriteProcessTransition(CodeStatementCollection statements, StateType state, string nextStateName, string suffix) { CodeExpression[] paramsRef; StateType stateNext = Model.GetStateType(nextStateName); string stateTopClassName; string contextClassName; string contextParentClassName; // context or context.ContextParent or context.ContextParent.ContextParent .... depending where is stateNext compared to state. var contextExpression = GetContextParentExpression(state, stateNext); if (stateNext == null) { //Internal transition paramsRef = new CodeExpression[] { contextExpression, new CodePrimitiveExpression(null) }; stateTopClassName = GetStateClassName(Model.GetStateTop(state)); contextClassName = GetContextClassName(state); contextParentClassName = GetContextParentClassName(state); } else { CodeExpression nextStateExpression; if (stateNext.Type.HasFlag(StateType.TypeFlags.HISTORY)) { // context.StateHistory nextStateExpression = new CodeFieldReferenceExpression( new CodeVariableReferenceExpression(Model.settings.context.instance), "StateHistory"); } else { StateType stateLeaf = Model.GetStateLeaf(stateNext); // NextState.Instance nextStateExpression = new CodeFieldReferenceExpression( new CodeVariableReferenceExpression(GetStateClassName(stateLeaf)), "Instance"); } stateTopClassName = GetStateClassName(Model.GetStateTop(stateNext)); contextClassName = GetContextClassName(stateNext); contextParentClassName = GetContextParentClassName(stateNext); paramsRef = new CodeExpression[] { contextExpression, nextStateExpression }; } // param StateRunning.Instance var onMethodInvoke = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression( new CodeVariableReferenceExpression("StateMachineHelper"), "ProcessTransition" + suffix, new CodeTypeReference[] { new CodeTypeReference(contextClassName), new CodeTypeReference(contextParentClassName), new CodeTypeReference((stateTopClassName)) }), paramsRef); statements.Add(onMethodInvoke); }
protected string GetParallelFieldName(StateType state) { return("_parallel" + state.name); }
protected string GetParallelLocalVariableName(StateType state) { return("parallel" + state.name); }
protected string GetParallelClassName(StateType state) { return(Model.settings.name + state.name + "Parallel"); }