I am trying to build a state machine for microwave oven. I am designing it such that it has only two functionalities as of now : bake and clean. It will have 3 states: idle, baking and cleaning. While transitioning into a state, the state machine will perform actions. The actions are commands like run the timer, lock the door, turn on light inside, etc. I am trying to group many of such commands into a command group and pass that command group to the actions. Events are user performed events events like start baking, start cleaning, etc.
My command grouping logic is returning syntax errors. I am stuck on how to make sense out of the error and how to fix the issue.
PFB my meta model and oven model.
Meta-model:
StateMachine:
'events'
events+=Event
'end'
'commands'
commands+=Command
'end'
('commandgroups'
commandGroupBlocks+=CommandGroupBlock
'end')?
states+=State
;
Keyword:
'end' | 'events' | 'state' | 'actions' | 'commandgroups' | 'group' | 'groupend'
;
Event:
name=SMID code=ID
;
Command:
name=SMID code=ID
;
CommandGroupBlock:
'group' name=SMID
groupCommands+=[Command|SMID]
'groupend'
;
State:
'state' name=ID
('actions' '{' actions+=[CommandGroupBlock|Command] '}')?
(transitions+=Transition)?
'end'
;
Transition:
event=[Event|SMID] '=>' to_state=[State]
;
SMID:
!Keyword ID
;
Comment:
/\/\*(.|\n)*?\*\//
;
Oven model:
events
bakeOn E_BKON
cleanOn E_CLON
cleanOff E_CLOF
end
commands
timerInitial C_TMIN
timerRunning C_TMRN
lockDoor C_D1LK
unlockDoor C_D1UL
magnetronOn C_MGON
magnetronOff C_MGOF
internalLightOn C_ILON
internalLightOff C_ILOF
turnTableOn C_TTON
turnTableOff C_TTOF
cleanerOn C_CLON
cleanerOff C_CLOF
end
commandgroups
group resetCommands
unlockDoor
timerInitial
magnetronOff
internalLightOff
turnTableOff
cleanerOff
groupend
group commonActiveCommands
lockDoor
internalLightOn
timerRunning
groupend
end
state idle
actions {resetCommands}
bakeOn => baking
cleanOn => cleaning
end
state baking
actions {commonActiveCommand magnetronOn turnTableOn}
end
state cleaning
actions {commonActiveCommand cleanerOn turnTableOff}
cleanOff => idle
end
The error i am getting is :
Traceback (most recent call last):
File "state_machine.py", line 70, in <module>
model = meta_model.model_from_file(sys.argv[1])
File "/workspace/dsl-state-machine-oven/demo/lib/python3.8/site-packages/textx/metamodel.py", line 661, in model_from_file
return self.internal_model_from_file(
File "/workspace/dsl-state-machine-oven/demo/lib/python3.8/site-packages/textx/metamodel.py", line 709, in internal_model_from_file
model = self._parser_blueprint.clone().get_model_from_str(
File "/workspace/dsl-state-machine-oven/demo/lib/python3.8/site-packages/textx/model.py", line 372, in get_model_from_str
self.parse(model_str, file_name=file_name)
File "/workspace/dsl-state-machine-oven/demo/lib/python3.8/site-packages/arpeggio/__init__.py", line 1525, in parse
self.parse_tree = self._parse()
File "/workspace/dsl-state-machine-oven/demo/lib/python3.8/site-packages/textx/model.py", line 332, in _parse
raise TextXSyntaxError(message=e.message,
textx.exceptions.TextXSyntaxError: /workspace/dsl-state-machine-oven/oven.sm:39:25: Expected ID => 'etCommands*} bakeOn'
Please help me out with the issue.
You were close. The problem is that you are trying to reference either a command or command group from the state actions. But the syntax is not correct.
State:
'state' name=ID
('actions' '{' actions+=[CommandGroupBlock|Command] '}')?
(transitions+=Transition)?
'end'
;
Part actions+=[CommandGroupBlock|Command]
would mean match one or more CommandGroupBlock using Command to match the name
.
What you actually wanted is:
GroupOrCommand: Command | CommandGroupBlock;
State:
'state' name=ID
('actions' '{' actions+=[GroupOrCommand|SMID] '}')?
(transitions+=Transition)?
'end'
;
Here we introduced a new abstract rule CommandOrGroup
and then we are linking to this rule using SMID
to parse names.
BTW, there is also a typo in the model: commonActiveCommand
-> commonActiveCommands
.