public override void PrtEnqueueEvent(PrtValue e, PrtValue arg, PrtMachine source, PrtMachineValue target = null) { int numOfStepsTaken = 0; // set the currentTrigger and currentPayload fields // so that we can reuse the common functions currentPayload = arg.Clone(); currentTrigger = e; PrtValue currEventValue; PrtFun currAction; bool hasMoreWork = false; try { Start: switch (nextSMOperation) { case PrtNextStatemachineOperation.ExecuteFunctionOperation: goto DoExecuteFunction; case PrtNextStatemachineOperation.HandleEventOperation: goto DoHandleEvent; } DoExecuteFunction: if (invertedFunStack.TopOfStack == null) { //Trace: entered state PrtFun entryFun = CurrentState.entryFun; if (entryFun.IsAnonFun) { PrtPushFunStackFrame(entryFun, entryFun.CreateLocals(currentPayload)); } else { PrtPushFunStackFrame(entryFun, entryFun.CreateLocals()); } } //invoke the function invertedFunStack.TopOfStack.fun.Execute(stateImpl, this); goto CheckFunLastOperation; DoAction: currAction = PrtFindActionHandler(eventValue); if (currAction == PrtFun.IgnoreFun) { //Trace: Performed ignore action for the event currentTrigger = PrtValue.@null; currentPayload = PrtValue.@null; } else { if (invertedFunStack.TopOfStack == null) { //Trace: executed the action handler for event if (currAction.IsAnonFun) { PrtPushFunStackFrame(currAction, currAction.CreateLocals(currentPayload)); } else { PrtPushFunStackFrame(currAction, currAction.CreateLocals()); } } //invoke the action handler invertedFunStack.TopOfStack.fun.Execute(stateImpl, this); } goto CheckFunLastOperation; CheckFunLastOperation: switch (continuation.reason) { case PrtContinuationReason.Goto: { stateExitReason = PrtStateExitReason.OnGotoStatement; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; PrtPushExitFunction(); goto DoExecuteFunction; } case PrtContinuationReason.Raise: { nextSMOperation = PrtNextStatemachineOperation.HandleEventOperation; hasMoreWork = true; goto Finish; } case PrtContinuationReason.Return: { switch (stateExitReason) { case PrtStateExitReason.NotExit: { nextSMOperation = PrtNextStatemachineOperation.HandleEventOperation; hasMoreWork = false; goto Finish; } case PrtStateExitReason.OnGotoStatement: { PrtChangeState(destOfGoto); currentTemperature = destOfGoto.temperature; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; stateExitReason = PrtStateExitReason.NotExit; hasMoreWork = true; goto Finish; } case PrtStateExitReason.OnUnhandledEvent: { hasMoreWork = !PrtPopState(false); nextSMOperation = PrtNextStatemachineOperation.HandleEventOperation; stateExitReason = PrtStateExitReason.NotExit; goto Finish; } case PrtStateExitReason.OnTransition: { stateExitReason = PrtStateExitReason.OnTransitionAfterExit; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; PrtPushTransitionFun(eventValue); goto DoExecuteFunction; } case PrtStateExitReason.OnTransitionAfterExit: { // The parameter to an anonymous transition function is always passed as swap. // Update currentPayload to the latest value of the parameter so that the correct // value gets passed to the entry function of the target state. PrtTransition transition = CurrentState.transitions[eventValue]; PrtFun transitionFun = transition.transitionFun; if (transitionFun.IsAnonFun) { currentPayload = continuation.retLocals[0]; } PrtChangeState(transition.gotoState); currentTemperature = transition.gotoState.temperature; hasMoreWork = true; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; stateExitReason = PrtStateExitReason.NotExit; goto Finish; } default: { Debug.Assert(false, "Unexpected value for exit reason"); goto Finish; } } } default: { Debug.Assert(false, "Unexpected value for continuation reason"); goto Finish; } } DoHandleEvent: if (!currentTrigger.Equals(PrtValue.@null)) { currEventValue = currentTrigger; currentTrigger = PrtValue.@null; } else { currEventValue = eventValue; } if (PrtIsTransitionPresent(currEventValue)) { stateExitReason = PrtStateExitReason.OnTransition; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; eventValue = currEventValue; PrtPushExitFunction(); goto DoExecuteFunction; } else if (PrtIsActionInstalled(currEventValue)) { eventValue = currEventValue; goto DoAction; } else { stateExitReason = PrtStateExitReason.OnUnhandledEvent; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; eventValue = currEventValue; PrtPushExitFunction(); goto DoExecuteFunction; } Finish: if (hasMoreWork) { if (numOfStepsTaken > 100000) { throw new PrtInfiniteRaiseLoop("Infinite loop in spec machine"); } else { numOfStepsTaken++; goto Start; } } else { return; } } catch (PrtException ex) { stateImpl.Exception = ex; } }
public bool PrtStepStateMachine() { PrtValue currEventValue; PrtFun currAction; bool hasMoreWork = false; switch (nextSMOperation) { case PrtNextStatemachineOperation.ExecuteFunctionOperation: goto DoExecuteFunction; case PrtNextStatemachineOperation.DequeueOperation: goto DoDequeue; case PrtNextStatemachineOperation.HandleEventOperation: goto DoHandleEvent; case PrtNextStatemachineOperation.ReceiveOperation: goto DoReceive; } DoExecuteFunction: /* * Note that we have made an assumption that when a state is pushed on state stack or a transition is taken (update to a state) * the action set and deferred set is updated appropriately */ if (invertedFunStack.TopOfStack == null) { stateImpl.TraceLine("<StateLog> Machine {0}-{1} entering State {2}", this.Name, this.instanceNumber, CurrentState.name); if (CurrentState.entryFun.IsAnonFun) { PrtPushFunStackFrame(CurrentState.entryFun, CurrentState.entryFun.CreateLocals(currentPayload)); } else { PrtPushFunStackFrame(CurrentState.entryFun, CurrentState.entryFun.CreateLocals()); } } //invoke the function invertedFunStack.TopOfStack.fun.Execute(stateImpl, this); goto CheckFunLastOperation; DoAction: currAction = PrtFindActionHandler(eventValue); if (currAction == PrtFun.IgnoreFun) { stateImpl.TraceLine("<ActionLog> Machine {0}-{1} ignoring Event '{2}' in State {3}", this.Name, this.instanceNumber, eventValue, CurrentState.name); PrtResetTriggerAndPayload(); nextSMOperation = PrtNextStatemachineOperation.DequeueOperation; hasMoreWork = true; goto Finish; } else { if (invertedFunStack.TopOfStack == null) { stateImpl.TraceLine("<ActionLog> Machine {0}-{1} executing action for Event '{2}' in State {3}", this.Name, this.instanceNumber, eventValue, CurrentState.name); if (currAction.IsAnonFun) { PrtPushFunStackFrame(currAction, currAction.CreateLocals(currentPayload)); } else { PrtPushFunStackFrame(currAction, currAction.CreateLocals()); } } //invoke the action handler invertedFunStack.TopOfStack.fun.Execute(stateImpl, this); } goto CheckFunLastOperation; CheckFunLastOperation: switch (continuation.reason) { case PrtContinuationReason.Pop: { //clear the fun stack on pop invertedFunStack.Clear(); stateExitReason = PrtStateExitReason.OnPopStatement; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; PrtPushExitFunction(); goto DoExecuteFunction; } case PrtContinuationReason.Goto: { //clear fun stack on goto invertedFunStack.Clear(); stateExitReason = PrtStateExitReason.OnGotoStatement; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; PrtPushExitFunction(); goto DoExecuteFunction; } case PrtContinuationReason.Raise: { //clear fun stack on raise invertedFunStack.Clear(); nextSMOperation = PrtNextStatemachineOperation.HandleEventOperation; hasMoreWork = true; goto Finish; } case PrtContinuationReason.NewMachine: { hasMoreWork = false; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; goto Finish; } case PrtContinuationReason.Nondet: { stateImpl.SetPendingChoicesAsBoolean(this); continuation.nondet = ((Boolean)stateImpl.GetSelectedChoiceValue(this)); hasMoreWork = false; goto Finish; } case PrtContinuationReason.Receive: { nextSMOperation = PrtNextStatemachineOperation.ReceiveOperation; hasMoreWork = true; goto Finish; } case PrtContinuationReason.Send: { hasMoreWork = false; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; goto Finish; } case PrtContinuationReason.Return: { switch (stateExitReason) { case PrtStateExitReason.NotExit: { nextSMOperation = PrtNextStatemachineOperation.DequeueOperation; hasMoreWork = true; goto Finish; } case PrtStateExitReason.OnPopStatement: { var cs = CurrentState; hasMoreWork = !PrtPopState(true); stateImpl.StateTransitionCallback?.Invoke(this, cs, CurrentState, "pop"); nextSMOperation = PrtNextStatemachineOperation.DequeueOperation; stateExitReason = PrtStateExitReason.NotExit; goto Finish; } case PrtStateExitReason.OnGotoStatement: { stateImpl.StateTransitionCallback?.Invoke(this, CurrentState, destOfGoto, "goto"); PrtChangeState(destOfGoto); nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; stateExitReason = PrtStateExitReason.NotExit; hasMoreWork = true; goto Finish; } case PrtStateExitReason.OnUnhandledEvent: { hasMoreWork = !PrtPopState(false); nextSMOperation = PrtNextStatemachineOperation.HandleEventOperation; stateExitReason = PrtStateExitReason.NotExit; goto Finish; } case PrtStateExitReason.OnTransition: { stateImpl.StateTransitionCallback?.Invoke(this, CurrentState, CurrentState.transitions[eventValue].gotoState, eventValue.ToString()); stateExitReason = PrtStateExitReason.OnTransitionAfterExit; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; PrtPushTransitionFun(eventValue); goto DoExecuteFunction; } case PrtStateExitReason.OnTransitionAfterExit: { stateImpl.StateTransitionCallback?.Invoke(this, CurrentState, CurrentState.transitions[eventValue].gotoState, eventValue.ToString()); // The parameter to an anonymous transition function is always passed as swap. // Update currentPayload to the latest value of the parameter so that the correct // value gets passed to the entry function of the target state. PrtTransition transition = CurrentState.transitions[eventValue]; PrtFun transitionFun = transition.transitionFun; if (transitionFun.IsAnonFun) { currentPayload = continuation.retLocals[0]; } PrtChangeState(transition.gotoState); stateExitReason = PrtStateExitReason.NotExit; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; hasMoreWork = true; goto Finish; } default: { Debug.Assert(false, "Unexpected value for exit reason"); goto Finish; } } } default: { Debug.Assert(false, "Unexpected value for continuation reason"); goto Finish; } } DoDequeue: Debug.Assert(receiveSet.Count == 0, "Machine cannot be blocked at receive when here"); var dequeueStatus = PrtDequeueEvent(CurrentState.hasNullTransition); if (dequeueStatus == PrtDequeueReturnStatus.BLOCKED) { nextSMOperation = PrtNextStatemachineOperation.DequeueOperation; hasMoreWork = false; goto Finish; } else if (dequeueStatus == PrtDequeueReturnStatus.SUCCESS) { nextSMOperation = PrtNextStatemachineOperation.HandleEventOperation; hasMoreWork = true; goto Finish; } else // NULL transition { nextSMOperation = PrtNextStatemachineOperation.HandleEventOperation; hasMoreWork = false; eventValue = PrtValue.@null; goto Finish; } DoHandleEvent: Debug.Assert(receiveSet.Count == 0, "The machine must not be blocked on a receive"); if (!currentTrigger.Equals(PrtValue.@null)) { currEventValue = currentTrigger; currentTrigger = PrtValue.@null; } else { currEventValue = eventValue; } if (PrtIsPushTransitionPresent(currEventValue)) { eventValue = currEventValue; stateImpl.StateTransitionCallback?.Invoke(this, CurrentState, CurrentState.transitions[currEventValue].gotoState, currEventValue.ToString()); PrtPushState(CurrentState.transitions[currEventValue].gotoState); goto DoExecuteFunction; } else if (PrtIsTransitionPresent(currEventValue)) { stateExitReason = PrtStateExitReason.OnTransition; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; eventValue = currEventValue; PrtPushExitFunction(); goto DoExecuteFunction; } else if (PrtIsActionInstalled(currEventValue)) { eventValue = currEventValue; goto DoAction; } else { stateExitReason = PrtStateExitReason.OnUnhandledEvent; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; eventValue = currEventValue; PrtPushExitFunction(); goto DoExecuteFunction; } DoReceive: if (receiveSet.Count == 0) { stateExitReason = PrtStateExitReason.NotExit; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; goto DoExecuteFunction; } dequeueStatus = PrtDequeueEvent(false); if (dequeueStatus == PrtDequeueReturnStatus.BLOCKED) { nextSMOperation = PrtNextStatemachineOperation.ReceiveOperation; hasMoreWork = false; goto Finish; } else if (dequeueStatus == PrtDequeueReturnStatus.SUCCESS) { stateExitReason = PrtStateExitReason.NotExit; nextSMOperation = PrtNextStatemachineOperation.ExecuteFunctionOperation; goto DoExecuteFunction; } else // NULL case { nextSMOperation = PrtNextStatemachineOperation.ReceiveOperation; hasMoreWork = false; goto Finish; } Finish: Debug.Assert(!hasMoreWork || currentStatus == PrtMachineStatus.Enabled, "hasMoreWork is true but the statemachine is blocked"); return(hasMoreWork); }