if not eventSymbol := GetSlot(eventFrame, 'declareSelf) then
begin
eventSymbol := 'unknown;
print("A protoEvent in the '|" & stateSymbol & "| state of the '|" & fsmSymbol & "| protoFSM implementation is unnamed (you forgot the declareSelf slot).");
end;
if stateFrame.(eventSymbol) then
print("The '|" & eventSymbol & "| protoEvent in the '|" & stateSymbol & "| protoState in the '|" & fsmSymbol & "| protoFSM implementation already exists (duplicate declareSelf slot value).");
else
stateFrame.(eventSymbol) := eventFrame;
RemoveSlot(eventFrame, 'declareSelf);
end;
RemoveSlot(stateFrame, 'declareSelf);
RemoveSlot(stateFrame, 'stepChildren);
hasGenesisState := hasGenesisState or stateSymbol = 'Genesis;
end;
if not hasGenesisState then
print("The '|" & fsmSymbol & "| protoFSM implementation is missing the required '|Genesis| state.");
if not kDebugOn then // GoToState is a debug-only function!
func() // SELF is the finite state machine instance frame
begin
fsm_private_context.pendingEventQueue:Reset();
fsm_private_context.pendingParamsQueue:Reset();
foreach slot in fsm_private_context do fsm_private_context.slot := nil;
currentStateFrame := currentEventFrame := fsm_private_context := nil; // guaranteed to return nil so that the caller can conveniently nil out the FSM container variable
end,
DoEvent_Loop:
func() // SELF is the finite state machine instance frame
begin
local x := fsm_private_context;
if not x then // this catches the situation where the FSM is disposed before a pending delayed action/call/send executes
return;
local ok;
local pendingStateFrame;
if x.pendingState then
if fsm_private_states.(x.pendingState) then
if fsm_private_states.(x.pendingState).(x.pendingEventQueue:Peek()) then
ok := true;
else
begin
if kDebugOn then :?DebugFSM('UnknownEvent, x.pendingState, x.pendingEventQueue:Peek(), x.pendingParamsQueue:Peek()); // ignore if event not programmed
end;
else
begin
if kDebugOn then :?DebugFSM('UnknownState, x.pendingState, x.pendingEventQueue:Peek(), x.pendingParamsQueue:Peek()); // error --> remain in current state
end;
else
begin
if kDebugOn then :?DebugFSM('NilState, x.pendingState, x.pendingEventQueue:Peek(), x.pendingParamsQueue:Peek()); // machine halted
end;
if not ok then
begin
currentStateFrame := nil;
currentEventFrame := nil;
x.pendingEventQueue:DeQueue(); // there is a problem with this state or event
x.pendingParamsQueue:DeQueue(); // so remove the offending pending queue elements