xtext @ profict summer camp
TRANSCRIPT
Domain-Specific Languages with
Sven Efftinge
copyright 2008 by itemis AG
Kiel, Germany
Peter
Dennis
Jan
“... won’t talk about
model-driven stuff”
You’re lucky!
No UML!
No MDA!
No meta meta meta meta ...
taken from Martin Fowler’s upcoming Book on DSLs
Hands-on a
concrete example
You’re working for a company specialized on systems for
secret compartments
Your customer:
Mrs. H she likes secrets
To open the secret compartment, she has to
To open the secret compartment, she has to
close the door,
To open the secret compartment, she has to
close the door,
open the second draw in her chest,
turn her bedside light on.
To open the secret compartment, she has to
close the door,
open the second draw in her chest,
events doorClosed drawOpened lightOn doorOpened panelClosedend
resetEvents doorOpenedend
commands unlockPanel lockPanel lockDoor unlockDoor end
state idle actions {unlockDoor lockPanel} doorClosed => activeend
state active drawOpened => waitingForLight lightOn => waitingForDrawend
state waitingForLight lightOn => unlockedPanelend
state waitingForDraw drawOpened => unlockedPanelend
state unlockedPanel actions {unlockPanel lockDoor} panelClosed => idleend
events doorClosed drawOpened lightOn doorOpened panelClosedend
resetEvents doorOpenedend
commands unlockPanel lockPanel lockDoor unlockDoor end
state idle actions {unlockDoor lockPanel} doorClosed => activeend
state active drawOpened => waitingForLight lightOn => waitingForDrawend
state waitingForLight lightOn => unlockedPanelend
state waitingForDraw drawOpened => unlockedPanelend
state unlockedPanel actions {unlockPanel lockDoor} panelClosed => idleend
event :doorClosedevent :drawOpenedevent :lightOnevent :doorOpenedevent :panelClosed
command :unlockPanelcommand :lockPanelcommand :lockDoorcommand :unlockDoor
resetEvents :doorOpened
state :idle do actions :unlockDoor, :lockPanel transitions :doorClosed => :activeend
state :active do transitions :drawOpened => :waitingForLight, :lightOn => :waitingForDrawend
state :waitingForLight do transitions :lightOn => :unlockedPanelend
state :waitingForDraw do transitions :drawOpened => :unlockedPanelend
state :unlockedPanel do actions :unlockPanel, :lockDoor transitions :panelClosed => :idleend
External DSL Internal DSL
events doorClosed drawOpened lightOn doorOpened panelClosedend
resetEvents doorOpenedend
commands unlockPanel lockPanel lockDoor unlockDoor end
state idle actions {unlockDoor lockPanel} doorClosed => activeend
state active drawOpened => waitingForLight lightOn => waitingForDrawend
state waitingForLight lightOn => unlockedPanelend
state waitingForDraw drawOpened => unlockedPanelend
state unlockedPanel actions {unlockPanel lockDoor} panelClosed => idleend
event :doorClosedevent :drawOpenedevent :lightOnevent :doorOpenedevent :panelClosed
command :unlockPanelcommand :lockPanelcommand :lockDoorcommand :unlockDoor
resetEvents :doorOpened
state :idle do actions :unlockDoor, :lockPanel transitions :doorClosed => :activeend
state :active do transitions :drawOpened => :waitingForLight, :lightOn => :waitingForDrawend
state :waitingForLight do transitions :lightOn => :unlockedPanelend
state :waitingForDraw do transitions :drawOpened => :unlockedPanelend
state :unlockedPanel do actions :unlockPanel, :lockDoor transitions :panelClosed => :idleend
External DSL Internal DSL
On top of external DSLs
no compromises
On top of external DSLs
domain-specific static analysis
no compromises
On top of external DSLs
domain-specific static analysisgraphical views
no compromises
On top of external DSLs
domain-specific static analysisgraphical views
no compromises
closed scope
Implementing anexternal DSLis complicated
... to develop DSLs?
Why not using a DSL ...
Statemachine : 'events' (events+=Event)+ 'end' 'resetEvents' (resetEvents+=[Event])+ 'end' 'commands' (commands+=Command)+ 'end' (states+=State)+;Event : name=ID;Command : name=ID;State : 'state' name=ID ('actions' '{' (actions+=[Command])+ '}')? (transitions+=Transition)* 'end';Transition : event=[Event] '=>' state=[State];
Statemachine : 'events' (events+=Event)+ 'end' 'resetEvents' (resetEvents+=[Event])+ 'end' 'commands' (commands+=Command)+ 'end' (states+=State)+;Event : name=ID;Command : name=ID;State : 'state' name=ID ('actions' '{' (actions+=[Command])+ '}')? (transitions+=Transition)* 'end';Transition : event=[Event] '=>' state=[State];
starts with keyword ‘events’
Statemachine : 'events' (events+=Event)+ 'end' 'resetEvents' (resetEvents+=[Event])+ 'end' 'commands' (commands+=Command)+ 'end' (states+=State)+;Event : name=ID;Command : name=ID;State : 'state' name=ID ('actions' '{' (actions+=[Command])+ '}')? (transitions+=Transition)* 'end';Transition : event=[Event] '=>' state=[State];
followed by at least one definition of Event
which is defined here and consists of just one
identifier (ID)
Statemachine : 'events' (events+=Event)+ 'end' 'resetEvents' (resetEvents+=[Event])+ 'end' 'commands' (commands+=Command)+ 'end' (states+=State)+;Event : name=ID;Command : name=ID;State : 'state' name=ID ('actions' '{' (actions+=[Command])+ '}')? (transitions+=Transition)* 'end';Transition : event=[Event] '=>' state=[State];
this is a cross reference, referencing Events
declared in the previous section.
Statemachine : 'events' (events+=Event)+ 'end' 'resetEvents' (resetEvents+=[Event])+ 'end' 'commands' (commands+=Command)+ 'end' (states+=State)+;Event : name=ID;Command : name=ID;State : 'state' name=ID ('actions' '{' (actions+=[Command])+ '}')? (transitions+=Transition)* 'end';Transition : event=[Event] '=>' state=[State];
commands are very similar to events
Statemachine : 'events' (events+=Event)+ 'end' 'resetEvents' (resetEvents+=[Event])+ 'end' 'commands' (commands+=Command)+ 'end' (states+=State)+;Event : name=ID;Command : name=ID;State : 'state' name=ID ('actions' '{' (actions+=[Command])+ '}')? (transitions+=Transition)* 'end';Transition : event=[Event] '=>' state=[State];
States have a name (ID)
Statemachine : 'events' (events+=Event)+ 'end' 'resetEvents' (resetEvents+=[Event])+ 'end' 'commands' (commands+=Command)+ 'end' (states+=State)+;Event : name=ID;Command : name=ID;State : 'state' name=ID ('actions' '{' (actions+=[Command])+ '}')? (transitions+=Transition)* 'end';Transition : event=[Event] '=>' state=[State];
States have a name (ID)
optional action block
Statemachine : 'events' (events+=Event)+ 'end' 'resetEvents' (resetEvents+=[Event])+ 'end' 'commands' (commands+=Command)+ 'end' (states+=State)+;Event : name=ID;Command : name=ID;State : 'state' name=ID ('actions' '{' (actions+=[Command])+ '}')? (transitions+=Transition)* 'end';Transition : event=[Event] '=>' state=[State];
States have a name (ID)
optional action block
any number of Transitions
This was the example DSL implemented in
So what do we get from such a description?
Antlr based Parser
Eclipse based Editor
Antlr based Parser
Statemachine
name:StringCommand
name:StringState
name:StringEvent
Transition
** *
*
*
stateseventscommands
actions
stateevent
resetStates
EMF based Semantic Model
Eclipse based Editor
Antlr based Parser
Demo
oaw.itemis.comThank you very much!
the eclipse distro can be downloaded from
http://oaw.itemis.com