DEVS_generator.py 41 KB

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