DEVS_generator.py 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. # DEVS Generator by Sam Pieters. Inspired on the generatic generator by Joeri Excelmans
  2. #
  3. # Visits SCCD-domain constructs (see sccd_constructs.py) and converts them
  4. # to a DEVS language AST (see generic_language_constructs.py), that can
  5. # then be visited by a target language writer (only supports python).
  6. from sccd.compiler.utils import Enum, Logger
  7. from sccd.compiler.visitor import Visitor
  8. from sccd.compiler.sccd_constructs import FormalParameter
  9. from sccd.compiler.stateful_writer import StatefulWriter
  10. import sccd.compiler.generic_language_constructs as GLC
  11. Platforms = Enum("Threads", "GameLoop", "EventLoop")
  12. class DEVSGenerator(Visitor):
  13. def __init__(self, platform):
  14. self.platform = platform
  15. self.writer = StatefulWriter()
  16. def generic_visit(self, node):
  17. Logger.showWarning("GenericGenerator has no visit method for node of type '" + str(type(node)) + "'.")
  18. def get(self):
  19. return self.writer.get()
  20. def visit_ClassDiagram(self, class_diagram):
  21. header = ("Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, "
  22. "and Yentl Van Tendeloo (for the inspiration) and Sam Pieters (DEVS)\n")
  23. if class_diagram.name or class_diagram.author or class_diagram.description:
  24. header += "\n"
  25. if class_diagram.author:
  26. header += "Model author: " + class_diagram.author + "\n"
  27. if class_diagram.name:
  28. header += "Model name: " + class_diagram.name + "\n"
  29. if class_diagram.description.strip():
  30. header += "Model description:\n"
  31. header += class_diagram.description.strip()
  32. self.writer.addMultiLineComment(header)
  33. self.writer.addVSpace()
  34. self.writer.addInclude(([GLC.RuntimeModuleIdentifier(), "DEVS_statecharts_core"]))
  35. if class_diagram.top.strip():
  36. self.writer.addRawCode(class_diagram.top)
  37. self.writer.addVSpace()
  38. self.writer.beginPackage(class_diagram.name)
  39. # visit children
  40. for c in class_diagram.classes:
  41. c.accept(self)
  42. ################################
  43. # Object Manager State
  44. ################################
  45. self.writer.beginClass("ObjectManagerState")
  46. self.writer.beginConstructor()
  47. self.writer.beginMethodBody()
  48. self.writer.addAssignment(GLC.SelfProperty("to_send"), f"[(\"{class_diagram.default_class.name}\", \"{class_diagram.default_class.name}\", Event(\"start_instance\", None, [\"{class_diagram.default_class.name}[0]\"], 0))]")
  49. self.writer.endMethodBody()
  50. self.writer.endConstructor()
  51. self.writer.endClass()
  52. ################################
  53. # Object Manager
  54. ################################
  55. self.writer.beginClass("ObjectManager", ["ObjectManagerBase"])
  56. self.writer.beginConstructor()
  57. self.writer.addFormalParameter("name")
  58. self.writer.beginMethodBody()
  59. self.writer.beginSuperClassConstructorCall("ObjectManagerBase")
  60. self.writer.addActualParameter("name")
  61. self.writer.endSuperClassConstructorCall()
  62. self.writer.addAssignment(GLC.SelfProperty("state"), GLC.FunctionCall("ObjectManagerState"))
  63. self.writer.addAssignment(GLC.SelfProperty("input"),
  64. GLC.FunctionCall(GLC.SelfProperty("addInPort"), [GLC.String("input")]))
  65. for class_name in class_diagram.class_names:
  66. self.writer.addAssignment(GLC.SelfProperty(f"output[\"{class_name}\"]"),
  67. GLC.FunctionCall(GLC.SelfProperty("addOutPort")))
  68. self.writer.endMethodBody()
  69. self.writer.endConstructor()
  70. self.writer.endClass()
  71. ################################
  72. # Controller
  73. ################################
  74. self.writer.beginClass("Controller", ["CoupledDEVS"])
  75. self.writer.beginConstructor()
  76. self.writer.addFormalParameter("name")
  77. for p in class_diagram.default_class.constructors[0].parameters:
  78. p.accept(self)
  79. self.writer.beginMethodBody()
  80. self.writer.beginSuperClassConstructorCall("CoupledDEVS")
  81. self.writer.addActualParameter("name")
  82. self.writer.endSuperClassConstructorCall()
  83. for i in class_diagram.inports:
  84. self.writer.addAssignment(GLC.SelfProperty("in_" + i), GLC.FunctionCall(GLC.SelfProperty("addInPort"), [GLC.String(i)]))
  85. self.writer.add(GLC.FunctionCall("Ports.addInputPort", [GLC.String(i)]))
  86. for o in class_diagram.outports:
  87. self.writer.addAssignment(GLC.SelfProperty("out_" + o), GLC.FunctionCall(GLC.SelfProperty("addOutPort"), [GLC.String(o)]))
  88. self.writer.add(GLC.FunctionCall("Ports.addOutputPort", [GLC.String(o)]))
  89. # Add AtomicDEVS models
  90. self.writer.addAssignment(GLC.SelfProperty("objectmanager"), (GLC.FunctionCall(GLC.SelfProperty("addSubModel"),
  91. [GLC.FunctionCall(
  92. "ObjectManager",
  93. GLC.ActualParameters([
  94. GLC.String(
  95. "ObjectManager")]))])))
  96. for (i, class_name) in enumerate(class_diagram.class_names):
  97. self.writer.addAssignment(GLC.SelfProperty(f"atomic{i}"),
  98. (GLC.FunctionCall(GLC.SelfProperty("addSubModel"), [GLC.FunctionCall(class_name,
  99. GLC.ActualParameters(
  100. [
  101. GLC.String(
  102. class_name)]))])))
  103. # Add links between the models
  104. for (i, the_class) in enumerate(class_diagram.classes):
  105. self.writer.add((GLC.FunctionCall(GLC.SelfProperty("connectPorts"),
  106. [GLC.SelfProperty(f"atomic{i}.obj_manager_out"),
  107. GLC.SelfProperty(f"objectmanager.input")])))
  108. self.writer.add((GLC.FunctionCall(GLC.SelfProperty("connectPorts"),
  109. [GLC.SelfProperty(f"objectmanager.output[\"{the_class.name}\"]"),
  110. GLC.SelfProperty(f"atomic{i}.obj_manager_in")])))
  111. for association in the_class.associations:
  112. temp = class_diagram.class_names.index(association.to_class)
  113. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("connectPorts"),
  114. [GLC.SelfProperty(f"atomic{i}.outputs[\"{association.name}\"]"),
  115. GLC.SelfProperty(f"atomic{temp}.input")]))
  116. for (i, the_class) in enumerate(class_diagram.classes):
  117. for o in class_diagram.outports:
  118. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("connectPorts"), [GLC.SelfProperty(f"atomic{i}.output"), GLC.SelfProperty(f"out_{o}")]))
  119. # TODO: What to do with "actual_parameters"?
  120. # actual_parameters = [p.getIdent() for p in class_diagram.default_class.constructors[0].parameters]
  121. # self.writer.add(GLC.FunctionCall(GLC.Property(GLC.SelfProperty("object_manager"), "createInstance"), [GLC.String(class_diagram.default_class.name), GLC.ArrayExpression(actual_parameters)]))
  122. self.writer.endMethodBody()
  123. self.writer.endConstructor()
  124. self.writer.endClass()
  125. # End Controller Class
  126. # visit test node if there is one
  127. if class_diagram.test:
  128. class_diagram.test.accept(self)
  129. self.writer.endPackage()
  130. # CLASS
  131. def visit_Class(self, class_node):
  132. """
  133. Generate code for Class construct
  134. """
  135. super_classes = []
  136. if not class_node.super_class_objs:
  137. if class_node.statechart:
  138. super_classes.append("RuntimeClassBase")
  139. if class_node.super_classes:
  140. for super_class in class_node.super_classes:
  141. # Check if this is always the case (that the superclass is an instance)
  142. super_classes.append(super_class + "Instance")
  143. ################################
  144. # State Instance (statechart)
  145. ################################
  146. # TODO: RuntimeClassBase only if there are no superclasses, if there are then append the superclasses
  147. self.writer.beginClass(f"{class_node.name}Instance", super_classes)
  148. self.writer.beginConstructor()
  149. self.writer.addFormalParameter("atomdevs")
  150. for p in class_node.constructors[0].getParams():
  151. self.writer.addFormalParameter(p.getIdent(), p.getDefault())
  152. self.writer.beginMethodBody()
  153. self.writer.beginSuperClassConstructorCall("RuntimeClassBase")
  154. self.writer.addActualParameter("atomdevs")
  155. self.writer.endSuperClassConstructorCall()
  156. self.writer.addAssignment(GLC.SelfProperty("associations"), "{}")
  157. for association in class_node.associations:
  158. self.writer.addAssignment(
  159. GLC.SelfProperty(f"associations[\"{association.name}\"]"),
  160. GLC.FunctionCall("Association",
  161. [GLC.String(association.to_class), f"{association.min}", f"{association.max}"]))
  162. # TODO: Switch instance to write in constructor instead of the atomic devs because corresponds better
  163. constructor = class_node.constructors[0]
  164. if class_node.statechart:
  165. self.writer.addVSpace()
  166. if constructor.parent_class.statechart.big_step_maximality == "take_one":
  167. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeOne"))
  168. elif constructor.parent_class.statechart.big_step_maximality == "take_many":
  169. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeMany"))
  170. if constructor.parent_class.statechart.internal_event_lifeline == "queue":
  171. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "Queue"))
  172. elif constructor.parent_class.statechart.internal_event_lifeline == "next_small_step":
  173. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextSmallStep"))
  174. elif constructor.parent_class.statechart.internal_event_lifeline == "next_combo_step":
  175. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextComboStep"))
  176. if constructor.parent_class.statechart.input_event_lifeline == "first_small_step":
  177. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstSmallStep"))
  178. elif constructor.parent_class.statechart.input_event_lifeline == "first_combo_step":
  179. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstComboStep"))
  180. elif constructor.parent_class.statechart.input_event_lifeline == "whole":
  181. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "Whole"))
  182. if constructor.parent_class.statechart.priority == "source_parent":
  183. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceParent"))
  184. elif constructor.parent_class.statechart.priority == "source_child":
  185. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceChild"))
  186. if constructor.parent_class.statechart.concurrency == "single":
  187. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Single"))
  188. elif constructor.parent_class.statechart.concurrency == "many":
  189. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Many"))
  190. self.writer.addVSpace()
  191. self.writer.addComment("build Statechart structure")
  192. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("build_statechart_structure"), []))
  193. if constructor.parent_class.attributes:
  194. self.writer.addVSpace()
  195. self.writer.addComment("user defined attributes")
  196. for attribute in constructor.parent_class.attributes:
  197. if attribute.init_value is None :
  198. self.writer.addAssignment(GLC.SelfProperty(attribute.name), GLC.NoneExpression())
  199. else :
  200. self.writer.addAssignment(GLC.SelfProperty(attribute.name), attribute.init_value)
  201. self.writer.addVSpace()
  202. self.writer.addComment("call user defined constructor")
  203. self.writer.beginSuperClassMethodCall(f"{constructor.parent_class.name}Instance", "user_defined_constructor")
  204. for p in constructor.getParams():
  205. # we can't do p.accept(self) here because 'p' is a FormalParameter
  206. # and we want to write it as an actual parameter
  207. self.writer.addActualParameter(p.getIdent())
  208. self.writer.endSuperClassMethodCall()
  209. # TODO
  210. #if constructor.parent_class.name != constructor.parent_class.class_diagram.default_class.name:
  211. self.writer.addAssignment("port_name", GLC.FunctionCall("Ports.addInputPort", [GLC.String("<narrow_cast>"), "self"]))
  212. self.writer.add(GLC.FunctionCall("atomdevs.addInPort", ["port_name"]))
  213. for inp in class_node.inports:
  214. #self.writer.addAssignment(GLC.SelfProperty(f"inports[\"{inp}\"]"), f"(\'{inp}\', atomdevs.next_instance)")
  215. self.writer.addAssignment("port_name", GLC.FunctionCall("Ports.addInputPort", [GLC.String(inp), "self"]))
  216. self.writer.add(GLC.FunctionCall("atomdevs.addInPort", ["port_name"]))
  217. self.writer.addAssignment("atomdevs.state.port_mappings[port_name]", "atomdevs.state.next_instance")
  218. self.writer.addAssignment(f"self.inports[\"{inp}\"]", "port_name")
  219. self.writer.endMethodBody()
  220. self.writer.endConstructor()
  221. # visit constructor
  222. # user defined constructor
  223. self.writer.beginMethod("user_defined_constructor")
  224. for p in constructor.getParams():
  225. p.accept(self)
  226. self.writer.beginMethodBody()
  227. for super_class in constructor.parent_class.super_classes:
  228. # begin call
  229. if super_class in constructor.parent_class.super_class_objs:
  230. self.writer.beginSuperClassMethodCall(super_class + "Instance", "user_defined_constructor")
  231. else:
  232. # TODO: How to get in this?
  233. self.writer.beginSuperClassConstructorCall(super_class)
  234. # write actual parameters
  235. if super_class in constructor.super_class_parameters:
  236. for p in constructor.super_class_parameters[super_class]:
  237. self.writer.addActualParameter(p)
  238. # end call
  239. if super_class in constructor.parent_class.super_class_objs:
  240. self.writer.endSuperClassMethodCall()
  241. else:
  242. self.writer.endSuperClassConstructorCall()
  243. self.writer.addRawCode(constructor.body)
  244. self.writer.endMethodBody()
  245. self.writer.endMethod()
  246. # visit destructor
  247. class_node.destructors[0].accept(self)
  248. # visit methods
  249. for i in class_node.methods:
  250. i.accept(self)
  251. # compile and initialize Statechart
  252. if class_node.statechart:
  253. class_node.statechart.accept(self)
  254. self.writer.beginMethod("initializeStatechart")
  255. self.writer.beginMethodBody()
  256. self.writer.addComment("enter default state")
  257. # get effective target of initial transition
  258. self.writer.addAssignment(
  259. GLC.SelfProperty("default_targets"),
  260. GLC.FunctionCall(
  261. GLC.Property(
  262. GLC.MapIndexedExpression(
  263. GLC.SelfProperty("states"),
  264. GLC.String(class_node.statechart.root.initial)
  265. ),
  266. "getEffectiveTargetStates"
  267. )
  268. )
  269. )
  270. self.writer.add(GLC.SuperClassMethodCall(
  271. "RuntimeClassBase",
  272. "initializeStatechart",
  273. []
  274. ))
  275. self.writer.endMethodBody()
  276. self.writer.endMethod()
  277. self.writer.endClass()
  278. ################################
  279. # State Object (keeps list of all instances of that object + controller operations)
  280. ################################
  281. self.writer.beginClass(class_node.name, ["ClassBase"])
  282. self.writer.beginMethod("constructObject")
  283. parameters = [GLC.SelfExpression()]
  284. for i, _ in enumerate(constructor.parameters):
  285. parameters.append(f"parameters[{i+2}]")
  286. self.writer.addFormalParameter("parameters")
  287. self.writer.beginMethodBody()
  288. self.writer.addAssignment("new_instance", GLC.FunctionCall(f"{class_node.name}Instance", parameters))
  289. self.writer.add(GLC.ReturnStatement("new_instance"))
  290. self.writer.endMethodBody()
  291. self.writer.endMethod()
  292. # visit constructor
  293. class_node.constructors[0].name = class_node.name
  294. class_node.constructors[0].accept(self)
  295. self.writer.endClass()
  296. # CLASS -- CONSTRUCTOR
  297. def visit_Constructor(self, constructor):
  298. ################################
  299. # Constructor of State Object
  300. ################################
  301. self.writer.beginConstructor()
  302. self.writer.addFormalParameter("name")
  303. self.writer.beginMethodBody() # constructor body
  304. self.writer.beginSuperClassConstructorCall("ClassBase")
  305. self.writer.addActualParameter("name")
  306. self.writer.endSuperClassConstructorCall()
  307. self.writer.addAssignment(GLC.SelfProperty("input"), GLC.FunctionCall(GLC.SelfProperty("addInPort"), [GLC.String("input")]))
  308. self.writer.addAssignment(GLC.SelfProperty("output"), GLC.FunctionCall(GLC.SelfProperty("addOutPort"), [GLC.String("ui")]))
  309. for association in constructor.parent_class.associations:
  310. self.writer.addAssignment(GLC.SelfProperty(f"outputs[\"{association.name}\"]"),
  311. GLC.FunctionCall(GLC.SelfProperty("addOutPort"), [GLC.String(association.name)]))
  312. for p in constructor.parent_class.inports:
  313. self.writer.addAssignment(GLC.SelfProperty(p),
  314. GLC.FunctionCall(GLC.SelfProperty("addInPort"), [GLC.String(p)]))
  315. for p in constructor.parent_class.outports:
  316. self.writer.addAssignment(
  317. GLC.MapIndexedExpression(GLC.SelfProperty("outports"), GLC.String(p)),
  318. GLC.FunctionCall(GLC.Property("controller", "addOutputPort"), [GLC.String(p), GLC.SelfExpression()]))
  319. if constructor.parent_class.name == constructor.parent_class.class_diagram.default_class.name:
  320. self.writer.addAssignment("self.state.instances[self.state.next_instance]", f"{constructor.parent_class.name}Instance(self)")
  321. self.writer.addAssignment("self.state.next_instance", "self.state.next_instance + 1")
  322. self.writer.endMethodBody()
  323. self.writer.endConstructor()
  324. def visit_FormalParameter(self, formal_parameter):
  325. self.writer.addFormalParameter(formal_parameter.getIdent(), formal_parameter.getDefault())
  326. ### CLASS -- DESTRUCTOR
  327. def visit_Destructor(self, destructor):
  328. self.writer.beginMethod("user_defined_destructor")
  329. self.writer.beginMethodBody()
  330. if destructor.body.strip():
  331. self.writer.addRawCode(destructor.body)
  332. if destructor.parent_class.super_classes:
  333. self.writer.addComment("call super class destructors")
  334. for super_class in destructor.parent_class.super_classes:
  335. # begin call
  336. if super_class in destructor.parent_class.super_class_objs:
  337. self.writer.beginSuperClassMethodCall(super_class + "Instance", "user_defined_destructor")
  338. self.writer.endSuperClassMethodCall()
  339. else:
  340. self.writer.beginSuperClassDestructorCall(super_class)
  341. self.writer.endSuperClassDestructorCall()
  342. pass
  343. # self.writer.beginSuperClassMethodCall(super_class, "user_defined_destructor")
  344. # self.writer.endSuperClassMethodCall()
  345. self.writer.endMethodBody()
  346. self.writer.endMethod()
  347. # CLASS -- METHOD
  348. def visit_Method(self, method):
  349. self.writer.addVSpace()
  350. self.writer.beginMethod(method.name, "user defined method")
  351. for p in method.parameters:
  352. p.accept(self)
  353. self.writer.beginMethodBody()
  354. self.writer.addRawCode(method.body)
  355. self.writer.endMethodBody()
  356. self.writer.endMethod()
  357. # CLASS -- ASSOCIATION
  358. def visit_Association(self, association):
  359. self.writer.addAssignment(
  360. GLC.MapIndexedExpression(
  361. GLC.Property("instance", "associations"),
  362. GLC.String(association.name)),
  363. GLC.NewExpression("Association",
  364. [GLC.String(association.to_class), str(association.min), str(association.max)]))
  365. # CLASS -- STATECHART
  366. def visit_StateChart(self, statechart):
  367. self.writer.addVSpace()
  368. self.writer.beginMethod("build_statechart_structure", "builds Statechart structure")
  369. self.writer.beginMethodBody()
  370. def writeState(s, i):
  371. self.writer.addVSpace()
  372. self.writer.addComment("state %s" % ("<root>" if s.is_root else s.new_full_name))
  373. index_expr = GLC.MapIndexedExpression(GLC.SelfProperty("states"), GLC.String(s.new_full_name))
  374. clazz = "State"
  375. if s.is_parallel_state:
  376. clazz = "ParallelState"
  377. elif s.is_history:
  378. if s.is_history_deep:
  379. clazz = "DeepHistoryState"
  380. else:
  381. clazz = "ShallowHistoryState"
  382. self.writer.addAssignment(
  383. index_expr,
  384. GLC.NewExpression(clazz, [str(i), GLC.String(s.new_full_name), GLC.SelfExpression()])
  385. )
  386. if not s.is_root:
  387. if s.enter_action.action or s.has_timers:
  388. self.writer.add(
  389. GLC.FunctionCall(
  390. GLC.Property(
  391. index_expr,
  392. "setEnter"
  393. ),
  394. [GLC.SelfProperty(s.friendly_name + "_enter")]
  395. )
  396. )
  397. if s.exit_action.action or s.has_timers:
  398. self.writer.add(
  399. GLC.FunctionCall(
  400. GLC.Property(
  401. index_expr,
  402. "setExit"
  403. ),
  404. [GLC.SelfProperty(s.friendly_name + "_exit")]
  405. )
  406. )
  407. # write all states
  408. for (i, s) in enumerate(statechart.states):
  409. writeState(s, i)
  410. # add children to composite states
  411. self.writer.addVSpace()
  412. self.writer.addComment("add children")
  413. for (i, s) in enumerate(statechart.composites):
  414. for c in s.children:
  415. self.writer.add(
  416. GLC.FunctionCall(
  417. GLC.Property(
  418. GLC.MapIndexedExpression(
  419. GLC.SelfProperty("states"),
  420. GLC.String(s.new_full_name)
  421. ),
  422. "addChild"),
  423. [GLC.MapIndexedExpression(GLC.SelfProperty("states"), GLC.String(c.new_full_name))]
  424. )
  425. )
  426. # fix tree at root, such that 'descendants' and 'ancestors' fields are filled in
  427. self.writer.add(
  428. GLC.FunctionCall(
  429. GLC.Property(
  430. GLC.MapIndexedExpression(
  431. GLC.SelfProperty("states"),
  432. GLC.String("")
  433. ),
  434. "fixTree"
  435. )
  436. )
  437. )
  438. # defaults
  439. for (i, s) in enumerate(statechart.composites):
  440. if not s.is_parallel_state:
  441. self.writer.addAssignment(
  442. GLC.Property(
  443. GLC.MapIndexedExpression(
  444. GLC.SelfProperty("states"),
  445. GLC.String(s.new_full_name)
  446. ),
  447. "default_state"
  448. ),
  449. GLC.MapIndexedExpression(
  450. GLC.SelfProperty("states"),
  451. GLC.String(s.initial)
  452. )
  453. )
  454. # transitions
  455. for s in statechart.basics + statechart.composites:
  456. if s.transitions:
  457. self.writer.addVSpace()
  458. self.writer.addComment("transition %s" % s.new_full_name)
  459. for (i, t) in enumerate(s.transitions + s.else_transitions):
  460. # instantiate new Transition instance
  461. self.writer.addAssignment(
  462. GLC.LocalVariableDeclaration(
  463. "%s_%i" % (s.friendly_name, i)
  464. ),
  465. GLC.NewExpression(
  466. "Transition",
  467. [
  468. GLC.SelfExpression(),
  469. GLC.MapIndexedExpression(
  470. GLC.SelfProperty("states"),
  471. GLC.String(s.new_full_name),
  472. ),
  473. GLC.ArrayExpression(
  474. [
  475. GLC.MapIndexedExpression(
  476. GLC.SelfProperty("states"),
  477. GLC.String(target_node.new_full_name)
  478. )
  479. for target_node in t.target.target_nodes
  480. ]
  481. )
  482. ]
  483. )
  484. )
  485. # if any action associated with transition: set executable_content to correct function (generated later)
  486. if t.action.sub_actions:
  487. self.writer.add(
  488. GLC.FunctionCall(
  489. GLC.Property(
  490. "%s_%i" % (s.friendly_name, i),
  491. "setAction"
  492. ),
  493. [GLC.SelfProperty("%s_%i_exec" % (s.friendly_name, i))]
  494. )
  495. )
  496. # if any trigger associated with transition: instantiate correct Event instance
  497. trigger = None
  498. if t.trigger.is_after:
  499. trigger = GLC.NewExpression("Event", [GLC.String("_%iafter" % (t.trigger.getAfterIndex()))])
  500. elif t.trigger.event:
  501. trigger = GLC.NewExpression("Event",
  502. [
  503. GLC.String(t.trigger.event),
  504. GLC.NoneExpression() if t.trigger.port is None else GLC.FunctionCall(
  505. GLC.SelfProperty("getInPortName"),
  506. [GLC.String(t.trigger.port)]
  507. )
  508. ]
  509. )
  510. else:
  511. trigger = GLC.NoneExpression()
  512. if trigger:
  513. self.writer.add(
  514. GLC.FunctionCall(
  515. GLC.Property(
  516. "%s_%i" % (s.friendly_name, i),
  517. "setTrigger"
  518. ),
  519. [trigger]
  520. )
  521. )
  522. # if any guard associated with transition: set guard to correct function (generated later)
  523. if t.guard:
  524. self.writer.add(
  525. GLC.FunctionCall(
  526. GLC.Property(
  527. "%s_%i" % (s.friendly_name, i),
  528. "setGuard"
  529. ),
  530. [GLC.SelfProperty("%s_%i_guard" % (s.friendly_name, i))]
  531. )
  532. )
  533. self.writer.add(
  534. GLC.FunctionCall(
  535. GLC.Property(
  536. GLC.MapIndexedExpression(
  537. GLC.SelfProperty("states"),
  538. GLC.String(s.new_full_name)
  539. ),
  540. "addTransition"
  541. ),
  542. ["%s_%i" % (s.friendly_name, i)]
  543. )
  544. )
  545. self.writer.endMethodBody()
  546. self.writer.endMethod()
  547. # enter/exit actions
  548. for (i, s) in enumerate(statechart.composites + statechart.basics):
  549. if not s.is_root:
  550. if s.enter_action.action or s.has_timers:
  551. s.enter_action.accept(self)
  552. if s.exit_action.action or s.has_timers:
  553. s.exit_action.accept(self)
  554. # transition actions and guards
  555. for s in statechart.composites + statechart.basics:
  556. for (i, t) in enumerate(s.transitions):
  557. if t.action.sub_actions:
  558. self.writeTransitionAction(t, i)
  559. if t.hasGuard():
  560. self.writeTransitionGuard(t, i)
  561. def visit_FormalEventParameter(self, formal_event_parameter):
  562. self.writer.add(formal_event_parameter.name)
  563. def writeFormalEventParameters(self, transition):
  564. parameters = transition.getTrigger().getParameters()
  565. if (len(parameters) > 0):
  566. for index, parameter in enumerate(parameters):
  567. self.writer.startRecordingExpression()
  568. parameter.accept(self)
  569. parameter_expr = self.writer.stopRecordingExpression()
  570. self.writer.addAssignment(
  571. GLC.LocalVariableDeclaration(parameter_expr),
  572. GLC.ArrayIndexedExpression("parameters", str(index)))
  573. def writeTransitionAction(self, transition, index):
  574. self.writer.beginMethod("%s_%i_exec" % (transition.parent_node.friendly_name, index))
  575. # parameters, start method
  576. self.writer.addFormalParameter("parameters")
  577. self.writer.beginMethodBody()
  578. # handle parameters to actually use them
  579. self.writeFormalEventParameters(transition)
  580. # write action
  581. transition.getAction().accept(self)
  582. # end method
  583. self.writer.endMethodBody()
  584. self.writer.endMethod()
  585. def writeTransitionGuard(self, transition, index):
  586. self.writer.beginMethod("%s_%i_guard" % (transition.parent_node.friendly_name, index))
  587. # parameters, start method
  588. self.writer.addFormalParameter("parameters")
  589. self.writer.beginMethodBody()
  590. # handle parameters to actually use them
  591. self.writeFormalEventParameters(transition)
  592. # get guard condition
  593. self.writer.startRecordingExpression()
  594. transition.getGuard().accept(self) # --> visit_Expression
  595. expr = self.writer.stopRecordingExpression()
  596. # return statement, end method
  597. self.writer.add(GLC.ReturnStatement(expr))
  598. self.writer.endMethodBody()
  599. self.writer.endMethod()
  600. def visit_EnterAction(self, enter_method):
  601. parent_node = enter_method.parent_node
  602. self.writer.beginMethod(parent_node.friendly_name + "_enter")
  603. self.writer.beginMethodBody()
  604. if enter_method.action:
  605. enter_method.action.accept(self)
  606. # take care of any AFTER events
  607. for transition in parent_node.transitions:
  608. trigger = transition.getTrigger()
  609. if trigger.isAfter():
  610. self.writer.startRecordingExpression()
  611. trigger.after.accept(self)
  612. after = self.writer.stopRecordingExpression()
  613. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("addTimer"), [str(trigger.getAfterIndex()), after]))
  614. self.writer.endMethodBody()
  615. self.writer.endMethod()
  616. def visit_ExitAction(self, exit_method):
  617. parent_node = exit_method.parent_node
  618. self.writer.beginMethod(parent_node.friendly_name + "_exit")
  619. self.writer.beginMethodBody()
  620. # take care of any AFTER events
  621. for transition in parent_node.transitions:
  622. trigger = transition.getTrigger()
  623. if trigger.isAfter():
  624. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("removeTimer"), [str(trigger.getAfterIndex())]))
  625. # execute user-defined exit action if present
  626. if exit_method.action:
  627. exit_method.action.accept(self)
  628. self.writer.endMethodBody()
  629. self.writer.endMethod()
  630. # helper method
  631. def writeEnterHistory(self, entered_node, is_deep):
  632. ### OLD CODE (TODO)
  633. self.writer.beginMethod("enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + entered_node.full_name)
  634. self.writer.beginMethodBody()
  635. self.writer.beginIf(GLC.EqualsExpression(
  636. GLC.ArrayLength(
  637. GLC.MapIndexedExpression(
  638. GLC.SelfProperty("history_state"),
  639. GLC.SelfProperty(entered_node.full_name))),
  640. "0"))
  641. defaults = entered_node.defaults
  642. for node in defaults:
  643. if node.is_basic:
  644. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + node.full_name)))
  645. elif node.is_composite:
  646. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_" + node.full_name)))
  647. self.writer.endIf()
  648. self.writer.beginElse()
  649. children = entered_node.children
  650. if entered_node.is_parallel_state:
  651. for child in children:
  652. if not child.is_history:
  653. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + child.full_name)))
  654. self.writer.add(GLC.FunctionCall(
  655. GLC.SelfProperty("enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + child.full_name)))
  656. else:
  657. for child in children:
  658. if not child.is_history:
  659. self.writer.beginIf(GLC.ArrayContains(
  660. GLC.MapIndexedExpression(
  661. GLC.SelfProperty("history_state"),
  662. GLC.SelfProperty(entered_node.full_name)),
  663. GLC.SelfProperty(child.full_name)))
  664. if child.is_composite:
  665. if is_deep:
  666. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + child.full_name)))
  667. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryDeep_" + child.full_name)))
  668. else:
  669. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_" + child.full_name)))
  670. else:
  671. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + child.full_name)))
  672. self.writer.endIf()
  673. self.writer.endElse()
  674. self.writer.endMethodBody()
  675. self.writer.endMethod()
  676. def visit_SelfReference(self, self_reference):
  677. self.writer.add(GLC.SelfExpression())
  678. def visit_StateReference(self, state_ref):
  679. self.writer.beginArray()
  680. for node in state_ref.getNodes():
  681. self.writer.add(GLC.SelfProperty(node.full_name))
  682. self.writer.endArray()
  683. def visit_InStateCall(self, in_state_call):
  684. self.writer.add(
  685. GLC.FunctionCall(
  686. GLC.SelfProperty("inState"),
  687. [
  688. GLC.ArrayExpression(
  689. [GLC.String(target_node.new_full_name) for target in in_state_call.targets for target_node in
  690. target.target_nodes]
  691. )
  692. ]
  693. )
  694. )
  695. def visit_ElseGuard(self, else_guard):
  696. self.writer.add(
  697. GLC.String("ELSE_GUARD")
  698. )
  699. def visit_Expression(self, expression):
  700. self.writer.startRecordingExpression()
  701. self.writer.beginGlue()
  702. for part in expression.expression_parts:
  703. part.accept(self)
  704. self.writer.endGlue()
  705. expr = self.writer.stopRecordingExpression()
  706. self.writer.add(expr)
  707. def visit_ExpressionPartString(self, e):
  708. self.writer.add(e.string)
  709. def visit_RaiseEvent(self, raise_event):
  710. self.writer.startRecordingExpression()
  711. self.writer.begin(GLC.NewExpression("Event"))
  712. self.writer.addActualParameter(GLC.String(raise_event.getEventName()))
  713. if raise_event.isOutput():
  714. self.writer.addActualParameter(
  715. GLC.FunctionCall(
  716. GLC.SelfProperty("getOutPortName"),
  717. [GLC.String(raise_event.getPort())]
  718. )
  719. )
  720. else:
  721. self.writer.addActualParameter(GLC.NoneExpression())
  722. self.writer.end()
  723. new_event_expr = self.writer.stopRecordingExpression()
  724. self.writer.startRecordingExpression()
  725. self.writer.beginArray()
  726. if raise_event.isCD():
  727. self.writer.add(GLC.SelfExpression())
  728. for param in raise_event.getParameters():
  729. param.accept(self) # -> visit_Expression will cause expressions to be added to array
  730. self.writer.endArray()
  731. parameters_array_expr = self.writer.stopRecordingExpression()
  732. new_event_expr.getActualParameters().add(parameters_array_expr)
  733. if raise_event.isNarrow():
  734. self.writer.add(GLC.FunctionCall(
  735. GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"), [
  736. GLC.NewExpression("Event", [
  737. GLC.String("narrow_cast"),
  738. GLC.NoneExpression(),
  739. GLC.ArrayExpression([
  740. GLC.SelfExpression(),
  741. raise_event.getTarget(),
  742. new_event_expr])])]))
  743. elif raise_event.isLocal():
  744. self.writer.add(GLC.FunctionCall(
  745. GLC.SelfProperty("raiseInternalEvent"),
  746. [new_event_expr]))
  747. elif raise_event.isOutput():
  748. self.writer.add(GLC.FunctionCall(
  749. GLC.Property(GLC.SelfProperty("big_step"), "outputEvent"),
  750. [new_event_expr]))
  751. elif raise_event.isCD():
  752. self.writer.add(GLC.FunctionCall(
  753. GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"),
  754. [new_event_expr]))
  755. elif raise_event.isBroad():
  756. self.writer.add(GLC.FunctionCall(
  757. GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"),
  758. [GLC.NewExpression("Event", [
  759. GLC.String("broad_cast"),
  760. GLC.NoneExpression(),
  761. GLC.ArrayExpression([
  762. GLC.SelfExpression(),
  763. new_event_expr])])]))
  764. def visit_Script(self, script):
  765. self.writer.addRawCode(script.code)
  766. def visit_Log(self, log):
  767. self.writer.add(GLC.LogStatement(log.message))
  768. def visit_Assign(self, assign):
  769. self.writer.startRecordingExpression()
  770. assign.lvalue.accept(self) # --> visit_Expression
  771. lvalue = self.writer.stopRecordingExpression()
  772. self.writer.startRecordingExpression()
  773. assign.expression.accept(self) # --> visit_Expression
  774. rvalue = self.writer.stopRecordingExpression()
  775. self.writer.addAssignment(lvalue, rvalue)