DEVS_generator.py 42 KB

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