generic_generator.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. # Generic Generator by Joeri Exelmans
  2. #
  3. # Visits SCCD-domain constructs (see sccd_constructs.py) and converts them
  4. # to a generic language AST (see generic_language_constructs.py), that can
  5. # then be visited by a target language writer.
  6. import traceback
  7. import time
  8. from utils import Enum, Logger
  9. from visitor import Visitor
  10. from sccd_constructs import FormalParameter
  11. from stateful_writer import StatefulWriter
  12. import generic_language_constructs as GLC
  13. Platforms = Enum("Threads","GameLoop","EventLoop")
  14. class GenericGenerator(Visitor):
  15. def __init__(self, platform):
  16. self.platform = platform
  17. self.writer = StatefulWriter()
  18. def generic_visit(self, node):
  19. Logger.showWarning("GenericGenerator has no visit method for node of type '" + str(type(node)) + "'.")
  20. def get(self):
  21. return self.writer.get()
  22. def visit_ClassDiagram(self, class_diagram):
  23. header = ("Generated by Statechart compiler by Glenn De Jonghe and Joeri Exelmans\n"
  24. "\n"
  25. "Date: " + time.asctime() + "\n")
  26. if class_diagram.name or class_diagram.author or class_diagram.description:
  27. header += "\n"
  28. if class_diagram.author:
  29. header += "Model author: " + class_diagram.author + "\n"
  30. if class_diagram.name:
  31. header += "Model name: " + class_diagram.name + "\n"
  32. if class_diagram.description.strip():
  33. header += "Model description:\n"
  34. header += class_diagram.description.strip()
  35. self.writer.addMultiLineComment(header)
  36. self.writer.addVSpace()
  37. self.writer.addInclude(([GLC.RuntimeModuleIdentifier(), "statecharts_core"]))
  38. if class_diagram.top.strip():
  39. self.writer.addRawCode(class_diagram.top)
  40. self.writer.addVSpace()
  41. self.writer.beginPackage(class_diagram.name)
  42. #visit children
  43. for c in class_diagram.classes :
  44. c.accept(self)
  45. self.writer.beginClass("ObjectManager", ["ObjectManagerBase"])
  46. self.writer.beginConstructor()
  47. self.writer.addFormalParameter("controller")
  48. self.writer.beginMethodBody()
  49. self.writer.beginSuperClassConstructorCall("ObjectManagerBase")
  50. self.writer.addActualParameter("controller")
  51. self.writer.endSuperClassConstructorCall()
  52. self.writer.endMethodBody()
  53. self.writer.endConstructor()
  54. self.writer.beginMethod("instantiate")
  55. self.writer.addFormalParameter("class_name")
  56. self.writer.addFormalParameter("construct_params")
  57. self.writer.beginMethodBody()
  58. for index,c in enumerate(class_diagram.classes):
  59. self.writer.beginElseIf(GLC.EqualsExpression("class_name", GLC.String(c.name)))
  60. if c.isAbstract():
  61. # cannot instantiate abstract class
  62. self.writer.add(GLC.ThrowExceptionStatement(GLC.String("Cannot instantiate abstract class \"" + c.name + "\" with unimplemented methods \"" + "\", \"".join(c.abstract_method_names) + "\".")))
  63. else:
  64. new_expr = GLC.NewExpression(c.name, [GLC.SelfProperty("controller")])
  65. param_count = 0
  66. for p in c.constructors[0].parameters:
  67. new_expr.getActualParameters().add(GLC.ArrayIndexedExpression("construct_params", str(param_count)))
  68. param_count += 1
  69. self.writer.addAssignment(
  70. GLC.LocalVariableDeclaration("instance"),
  71. new_expr)
  72. self.writer.addAssignment(
  73. GLC.Property("instance", "associations"),
  74. GLC.MapExpression())
  75. for a in c.associations:
  76. a.accept(self)
  77. self.writer.endElseIf()
  78. self.writer.add(GLC.ReturnStatement("instance"))
  79. self.writer.endMethodBody()
  80. self.writer.endMethod()
  81. self.writer.endClass() # ObjectManager
  82. if self.platform == Platforms.Threads:
  83. controller_sub_class = "ThreadsControllerBase"
  84. if self.platform == Platforms.EventLoop :
  85. controller_sub_class = "EventLoopControllerBase"
  86. elif self.platform == Platforms.GameLoop :
  87. controller_sub_class = "GameLoopControllerBase"
  88. self.writer.beginClass("Controller", [controller_sub_class])
  89. self.writer.beginConstructor()
  90. for p in class_diagram.default_class.constructors[0].parameters:
  91. p.accept(self)
  92. if self.platform == Platforms.EventLoop:
  93. self.writer.addFormalParameter("event_loop_callbacks")
  94. self.writer.addFormalParameter("finished_callback", GLC.NoneExpression())
  95. elif self.platform == Platforms.Threads:
  96. self.writer.addFormalParameter("keep_running", GLC.TrueExpression())
  97. self.writer.beginMethodBody()
  98. self.writer.beginSuperClassConstructorCall(controller_sub_class)
  99. self.writer.addActualParameter(GLC.NewExpression("ObjectManager", [GLC.SelfExpression()]))
  100. if self.platform == Platforms.EventLoop:
  101. self.writer.addActualParameter("event_loop_callbacks")
  102. self.writer.addActualParameter("finished_callback")
  103. elif self.platform == Platforms.Threads:
  104. self.writer.addActualParameter("keep_running")
  105. self.writer.endSuperClassConstructorCall()
  106. for i in class_diagram.inports:
  107. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("addInputPort"), [GLC.String(i)]))
  108. for o in class_diagram.outports:
  109. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("addOutputPort"), [GLC.String(o)]))
  110. actual_parameters = [p.getIdent() for p in class_diagram.default_class.constructors[0].parameters]
  111. self.writer.add(GLC.FunctionCall(GLC.Property(GLC.SelfProperty("object_manager"), "createInstance"), [GLC.String(class_diagram.default_class.name), GLC.ArrayExpression(actual_parameters)]))
  112. self.writer.endMethodBody()
  113. self.writer.endConstructor()
  114. self.writer.endClass() # Controller
  115. # Visit test node if there is one
  116. if class_diagram.test:
  117. class_diagram.test.accept(self)
  118. self.writer.endPackage()
  119. def visit_DiagramTest(self, test):
  120. # helper class
  121. self.writer.beginClass("InputEvent")
  122. self.writer.beginConstructor()
  123. self.writer.addFormalParameter("name")
  124. self.writer.addFormalParameter("port")
  125. self.writer.addFormalParameter("parameters")
  126. self.writer.addFormalParameter("time_offset")
  127. self.writer.beginMethodBody()
  128. self.writer.addAssignment(GLC.SelfProperty("name"), "name")
  129. self.writer.addAssignment(GLC.SelfProperty("port"), "port")
  130. self.writer.addAssignment(GLC.SelfProperty("parameters"), "parameters")
  131. self.writer.addAssignment(GLC.SelfProperty("time_offset"), "time_offset")
  132. self.writer.endMethodBody()
  133. self.writer.endConstructor()
  134. self.writer.endClass()
  135. self.writer.beginClass("Test")
  136. if test.input:
  137. test.input.accept(self)
  138. else:
  139. self.writer.addStaticAttribute("input_events", GLC.ArrayExpression())
  140. if test.expected:
  141. test.expected.accept(self)
  142. else:
  143. self.writer.addStaticAttribute("expected_events", GLC.ArrayExpression())
  144. self.writer.endClass()
  145. def visit_DiagramTestInput(self, test_input):
  146. # write array of input events
  147. self.writer.startRecordingExpression()
  148. self.writer.beginArray()
  149. for e in test_input.input_events:
  150. e.accept(self)
  151. self.writer.endArray()
  152. array_expr = self.writer.stopRecordingExpression()
  153. self.writer.addStaticAttribute("input_events", array_expr)
  154. def visit_DiagramTestInputEvent(self, event):
  155. self.writer.add(GLC.NewExpression("InputEvent", [GLC.String(event.name), GLC.String(event.port), GLC.ArrayExpression(event.parameters), event.time]))
  156. def visit_DiagramTestExpected(self, test_expected):
  157. # write array of slots containing expected events
  158. self.writer.startRecordingExpression()
  159. self.writer.beginArray()
  160. for s in test_expected.slots:
  161. s.accept(self)
  162. self.writer.endArray()
  163. array_expr = self.writer.stopRecordingExpression()
  164. self.writer.addStaticAttribute("expected_events", array_expr)
  165. def visit_DiagramTestExpectedSlot(self, slot):
  166. # write slot
  167. self.writer.beginArray()
  168. for e in slot.expected_events:
  169. e.accept(self)
  170. self.writer.endArray()
  171. def visit_DiagramTestEvent(self, event):
  172. self.writer.add(GLC.NewExpression("Event", [GLC.String(event.name), GLC.String(event.port), GLC.ArrayExpression(event.parameters)]))
  173. def visit_Class(self, class_node):
  174. """
  175. Generate code for Class construct
  176. """
  177. super_classes = []
  178. if not class_node.super_class_objs:
  179. # if none of the class' super classes is defined in the diagram,
  180. # we have to inherit RuntimeClassBase
  181. if class_node.statechart:
  182. # only inherit RuntimeClassBase if class has a statechart
  183. super_classes.append("RuntimeClassBase")
  184. if class_node.super_classes:
  185. for super_class in class_node.super_classes:
  186. super_classes.append(super_class)
  187. self.writer.beginClass(class_node.name, super_classes)
  188. #visit constructor
  189. for i in class_node.constructors :
  190. i.accept(self)
  191. self.writer.beginMethod("user_defined_constructor")
  192. for p in class_node.constructors[0].getParams():
  193. p.accept(self)
  194. self.writer.beginMethodBody()
  195. for super_class in class_node.super_classes:
  196. # begin call
  197. if super_class in class_node.super_class_objs:
  198. self.writer.beginSuperClassMethodCall(super_class, "user_defined_constructor")
  199. else:
  200. self.writer.beginSuperClassConstructorCall(super_class)
  201. # write actual parameters
  202. if super_class in class_node.constructors[0].super_class_parameters:
  203. for p in class_node.constructors[0].super_class_parameters[super_class]:
  204. self.writer.addActualParameter(p)
  205. # end call
  206. if super_class in class_node.super_class_objs:
  207. self.writer.endSuperClassMethodCall()
  208. else:
  209. self.writer.endSuperClassConstructorCall()
  210. self.writer.addRawCode(class_node.constructors[0].body)
  211. self.writer.endMethodBody()
  212. self.writer.endMethod()
  213. #visit children
  214. for i in class_node.destructors :
  215. i.accept(self)
  216. for i in class_node.methods :
  217. i.accept(self)
  218. if class_node.statechart:
  219. self.writer.beginMethod("initializeStatechart")
  220. self.writer.beginMethodBody()
  221. for c in class_node.statechart.composites :
  222. self.writer.addAssignment(GLC.MapIndexedExpression(GLC.SelfProperty("current_state"), GLC.SelfProperty(c.full_name)), GLC.ArrayExpression())
  223. if class_node.statechart.histories:
  224. self.writer.addVSpace()
  225. for node in class_node.statechart.combined_history_parents:
  226. self.writer.addAssignment(GLC.MapIndexedExpression(GLC.SelfProperty("history_state"), GLC.SelfProperty(node.full_name)), GLC.ArrayExpression())
  227. self.writer.addVSpace()
  228. self.writer.addComment("Enter default state")
  229. for default_node in class_node.statechart.root.defaults:
  230. if default_node.is_composite:
  231. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_"+default_node.full_name)))
  232. elif default_node.is_basic:
  233. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+default_node.full_name)))
  234. self.writer.endMethodBody()
  235. self.writer.endMethod()
  236. class_node.statechart.accept(self)
  237. self.writer.endClass()
  238. def visit_FormalParameter(self, formal_parameter):
  239. self.writer.addFormalParameter(formal_parameter.getIdent(), formal_parameter.getDefault())
  240. def visit_Constructor(self, constructor):
  241. self.writer.beginConstructor()
  242. if constructor.parent_class.statechart:
  243. self.writer.addFormalParameter("controller")
  244. for p in constructor.getParams():
  245. self.writer.addFormalParameter(p.getIdent(), p.getDefault())
  246. self.writer.beginMethodBody() # constructor body
  247. if constructor.parent_class.statechart:
  248. self.writer.beginSuperClassConstructorCall("RuntimeClassBase")
  249. self.writer.addActualParameter("controller")
  250. self.writer.endSuperClassConstructorCall()
  251. self.writer.addVSpace()
  252. if constructor.parent_class.statechart.big_step_maximality == "take_one":
  253. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeOne"))
  254. elif constructor.parent_class.statechart.big_step_maximality == "take_many":
  255. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeMany"))
  256. if constructor.parent_class.statechart.internal_event_lifeline == "queue":
  257. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "Queue"))
  258. elif constructor.parent_class.statechart.internal_event_lifeline == "next_small_step":
  259. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextSmallStep"))
  260. elif constructor.parent_class.statechart.internal_event_lifeline == "next_combo_step":
  261. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextComboStep"))
  262. if constructor.parent_class.statechart.input_event_lifeline == "first_small_step":
  263. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstSmallStep"))
  264. elif constructor.parent_class.statechart.input_event_lifeline == "first_combo_step":
  265. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstComboStep"))
  266. elif constructor.parent_class.statechart.input_event_lifeline == "whole":
  267. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "Whole"))
  268. if constructor.parent_class.statechart.priority == "source_parent":
  269. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceParent"))
  270. elif constructor.parent_class.statechart.priority == "source_child":
  271. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceChild"))
  272. if constructor.parent_class.statechart.concurrency == "single":
  273. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Single"))
  274. elif constructor.parent_class.statechart.concurrency == "many":
  275. self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Many"))
  276. for p in constructor.parent_class.inports:
  277. self.writer.addAssignment(
  278. GLC.MapIndexedExpression(GLC.SelfProperty("inports"), GLC.String(p)),
  279. GLC.FunctionCall(GLC.Property("controller", "addInputPort"), [GLC.String(p), GLC.SelfExpression()]))
  280. if constructor.parent_class.attributes:
  281. self.writer.addVSpace()
  282. self.writer.addComment("User defined attributes")
  283. for attribute in constructor.parent_class.attributes:
  284. if attribute.init_value is None :
  285. self.writer.addAssignment(GLC.SelfProperty(attribute.name), GLC.NoneExpression())
  286. else :
  287. self.writer.addAssignment(GLC.SelfProperty(attribute.name), attribute.init_value)
  288. self.writer.addVSpace()
  289. self.writer.addComment("Call user defined constructor")
  290. self.writer.beginSuperClassMethodCall(constructor.parent_class.name, "user_defined_constructor")
  291. for p in constructor.getParams():
  292. # we can't do p.accept(self) here because 'p' is a FormalParameter
  293. # and we want to write it as an actual parameter
  294. self.writer.addActualParameter(p.getIdent())
  295. self.writer.endSuperClassMethodCall()
  296. self.writer.endMethodBody()
  297. self.writer.endConstructor()
  298. def visit_Destructor(self, destructor):
  299. self.writer.beginMethod("user_defined_destructor")
  300. self.writer.beginMethodBody()
  301. if destructor.body.strip():
  302. self.writer.addRawCode(destructor.body)
  303. if destructor.parent_class.super_classes:
  304. self.writer.addComment("Call super class destructors")
  305. for super_class in destructor.parent_class.super_classes:
  306. # begin call
  307. if super_class in destructor.parent_class.super_class_objs:
  308. self.writer.beginSuperClassMethodCall(super_class, "user_defined_destructor")
  309. self.writer.endSuperClassMethodCall()
  310. else:
  311. self.writer.beginSuperClassDestructorCall(super_class)
  312. self.writer.endSuperClassDestructorCall()
  313. pass
  314. #self.writer.beginSuperClassMethodCall(super_class, "user_defined_destructor")
  315. #self.writer.endSuperClassMethodCall()
  316. self.writer.endMethodBody()
  317. self.writer.endMethod()
  318. def visit_Method(self, method):
  319. self.writer.addVSpace()
  320. self.writer.beginMethod(method.name, "User defined method")
  321. for p in method.parameters:
  322. p.accept(self)
  323. self.writer.beginMethodBody()
  324. self.writer.addRawCode(method.body)
  325. self.writer.endMethodBody()
  326. self.writer.endMethod()
  327. def visit_Association(self, association):
  328. self.writer.addAssignment(
  329. GLC.MapIndexedExpression(
  330. GLC.Property("instance", "associations"),
  331. GLC.String(association.name)),
  332. GLC.NewExpression("Association", [GLC.String(association.to_class), str(association.min), str(association.max)]))
  333. #helper method
  334. def writeTransitionsRecursively(self, current_node):
  335. valid_children = []
  336. for child in current_node.children :
  337. if child.is_composite or child.is_basic :
  338. valid_children.append(child)
  339. has_candidates_children = (len(valid_children) > 0)
  340. has_candidates_current = (len(current_node.transitions) > 0)
  341. if has_candidates_children:
  342. self.writer.beginMethod("generateCandidatesChildren_" + current_node.full_name)
  343. self.writer.beginMethodBody()
  344. if current_node.is_parallel_state:
  345. self.writer.addAssignment(
  346. GLC.LocalVariableDeclaration("branch_done"),
  347. GLC.FalseExpression())
  348. for child in valid_children :
  349. self.writer.addAssignment(
  350. "branch_done",
  351. GLC.OrExpression(
  352. GLC.FunctionCall(GLC.SelfProperty("generateCandidates_" + child.full_name)),
  353. "branch_done"))
  354. self.writer.add(GLC.ReturnStatement("branch_done"))
  355. elif current_node.is_composite:
  356. for i, child in enumerate(valid_children) :
  357. self.writer.beginElseIf(GLC.EqualsExpression(
  358. GLC.ArrayIndexedExpression(
  359. GLC.MapIndexedExpression(
  360. GLC.SelfProperty("current_state"),
  361. GLC.SelfProperty(current_node.full_name)),
  362. "0"),
  363. GLC.SelfProperty(child.full_name)))
  364. self.writer.add(GLC.ReturnStatement(GLC.FunctionCall(GLC.SelfProperty("generateCandidates_"+child.full_name))))
  365. self.writer.endElseIf()
  366. self.writer.add(GLC.ReturnStatement(GLC.FalseExpression()))
  367. self.writer.endMethodBody()
  368. self.writer.endMethod()
  369. if has_candidates_current:
  370. self.writer.beginMethod("generateCandidatesCurrent_" + current_node.full_name)
  371. self.writer.beginMethodBody()
  372. self.writeFromTransitions(current_node)
  373. self.writer.add(GLC.ReturnStatement(GLC.FalseExpression()))
  374. self.writer.endMethodBody()
  375. self.writer.endMethod()
  376. self.writer.beginMethod("generateCandidates_" + current_node.full_name)
  377. self.writer.beginMethodBody()
  378. if not has_candidates_children and not has_candidates_current:
  379. self.writer.add(GLC.ReturnStatement(GLC.FalseExpression()))
  380. else:
  381. self.writer.beginIf(
  382. GLC.NotExpression(GLC.FunctionCall(
  383. GLC.Property(GLC.SelfProperty("combo_step"), "isArenaChanged"),
  384. [GLC.SelfProperty(current_node.full_name)])))
  385. if has_candidates_children and has_candidates_current:
  386. self.writer.addAssignment(
  387. GLC.LocalVariableDeclaration("branch_done"),
  388. GLC.FalseExpression())
  389. if not has_candidates_children and has_candidates_current:
  390. self.writer.add(GLC.ReturnStatement(GLC.FunctionCall(GLC.SelfProperty("generateCandidatesCurrent_" + current_node.full_name))))
  391. elif not has_candidates_current and has_candidates_children:
  392. self.writer.add(GLC.ReturnStatement(GLC.FunctionCall(GLC.SelfProperty("generateCandidatesChildren_" + current_node.full_name))))
  393. else:
  394. self.writer.beginElseIf(GLC.EqualsExpression(
  395. GLC.Property(GLC.SelfProperty("semantics"), "priority"),
  396. GLC.Property("StatechartSemantics", "SourceParent")))
  397. if has_candidates_current:
  398. self.writer.addAssignment("branch_done", GLC.FunctionCall(GLC.SelfProperty("generateCandidatesCurrent_" + current_node.full_name)))
  399. if has_candidates_children:
  400. self.writer.beginIf(GLC.NotExpression("branch_done"))
  401. self.writer.addAssignment("branch_done", GLC.FunctionCall(GLC.SelfProperty("generateCandidatesChildren_" + current_node.full_name)))
  402. self.writer.endIf()
  403. self.writer.endElseIf()
  404. self.writer.beginElseIf(GLC.EqualsExpression(
  405. GLC.Property(GLC.SelfProperty("semantics"), "priority"),
  406. GLC.Property("StatechartSemantics", "SourceChild")))
  407. if has_candidates_children:
  408. self.writer.addAssignment("branch_done", GLC.FunctionCall(GLC.SelfProperty("generateCandidatesChildren_" + current_node.full_name)))
  409. if has_candidates_current:
  410. self.writer.beginIf(GLC.NotExpression("branch_done"))
  411. self.writer.addAssignment("branch_done", GLC.FunctionCall(GLC.SelfProperty("generateCandidatesCurrent_" + current_node.full_name)))
  412. self.writer.endIf()
  413. self.writer.endElseIf()
  414. if has_candidates_children and has_candidates_current:
  415. self.writer.add(GLC.ReturnStatement("branch_done"))
  416. self.writer.endIf()
  417. self.writer.beginElse()
  418. self.writer.add(GLC.ReturnStatement(GLC.TrueExpression()))
  419. self.writer.endElse()
  420. self.writer.endMethodBody()
  421. self.writer.endMethod()
  422. for index, transition in enumerate(current_node.transitions, start=1):
  423. self.writeTransitionAction(transition, index)
  424. for child in valid_children :
  425. self.writeTransitionsRecursively(child)
  426. #helper method
  427. def writeFromTransitions(self, current_node):
  428. # get all transition out of this state
  429. out_transitions = current_node.transitions
  430. if len(out_transitions) == 0 :
  431. return
  432. for index, transition in enumerate(out_transitions, start=1):
  433. self.writeTransitionCondition(transition, index)
  434. def visit_FormalEventParameter(self, formal_event_parameter):
  435. self.writer.add(formal_event_parameter.name)
  436. def writeFormalEventParameters(self, transition):
  437. parameters = transition.getTrigger().getParameters()
  438. if(len(parameters) > 0) :
  439. for index, parameter in enumerate(parameters):
  440. self.writer.startRecordingExpression()
  441. parameter.accept(self)
  442. parameter_expr = self.writer.stopRecordingExpression()
  443. self.writer.addAssignment(
  444. GLC.LocalVariableDeclaration(parameter_expr),
  445. GLC.ArrayIndexedExpression("parameters", str(index)))
  446. def writeTransitionAction(self, transition, index):
  447. self.writer.beginMethod("transition_" + transition.parent_node.full_name + "_" + str(index))
  448. self.writer.addFormalParameter("parameters")
  449. self.writer.beginMethodBody()
  450. # handle parameters to actually use them
  451. self.writeFormalEventParameters(transition)
  452. exits = transition.getExitNodes()
  453. # write exit actions
  454. if not exits[-1].is_basic:
  455. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("exit_"+exits[-1].full_name)))
  456. else:
  457. for node in exits:
  458. if node.is_basic:
  459. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("exit_"+node.full_name)))
  460. # write trigger actions
  461. transition.getAction().accept(self)
  462. # add arena of transition to list of 'changed' states,
  463. # this may prevent other transitions whose arenas overlap to be taken
  464. self.writer.add(
  465. GLC.FunctionCall(
  466. GLC.Property(GLC.SelfProperty("combo_step"), "setArenaChanged"),
  467. [GLC.SelfProperty(transition.arena.full_name)]))
  468. # write enter actions
  469. for (entering_node, is_ending_node) in transition.getEnterNodes() :
  470. if is_ending_node :
  471. if entering_node.is_composite:
  472. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_" + entering_node.full_name)))
  473. elif entering_node.is_history:
  474. if (entering_node.is_history_deep) :
  475. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryDeep_" + entering_node.parent.full_name)))
  476. else :
  477. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryShallow_" + entering_node.parent.full_name)))
  478. else:
  479. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + entering_node.full_name)))
  480. else :
  481. if entering_node.is_composite:
  482. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + entering_node.full_name)))
  483. self.writer.endMethodBody()
  484. self.writer.endMethod()
  485. def writeTransitionCondition(self, transition, index):
  486. trigger = transition.getTrigger()
  487. self.writer.addAssignment(
  488. GLC.LocalVariableDeclaration("enabled_events"),
  489. GLC.FunctionCall(GLC.SelfProperty("getEnabledEvents")))
  490. if not trigger.isUC():
  491. self.writer.beginForLoopIterateArray("enabled_events", "e")
  492. condition = GLC.EqualsExpression(
  493. GLC.Property(GLC.ForLoopCurrentElement("enabled_events", "e"), "name"),
  494. GLC.String(trigger.getEvent()))
  495. if trigger.getPort() != "":
  496. condition = GLC.AndExpression(
  497. condition,
  498. GLC.EqualsExpression(
  499. GLC.Property(GLC.ForLoopCurrentElement("enabled_events", "e"), "port"),
  500. GLC.String(trigger.getPort())))
  501. self.writer.beginIf(condition)
  502. # evaluate guard
  503. if transition.hasGuard() :
  504. # handle parameters for guard evaluation
  505. if not transition.getTrigger().isUC():
  506. self.writer.addAssignment(GLC.LocalVariableDeclaration("parameters"), GLC.Property(GLC.ForLoopCurrentElement("enabled_events", "e"), "parameters"))
  507. self.writeFormalEventParameters(transition)
  508. self.writer.startRecordingExpression()
  509. transition.getGuard().accept(self) # --> visit_Expression
  510. expr = self.writer.stopRecordingExpression()
  511. self.writer.beginIf(expr)
  512. if trigger.isUC():
  513. params_expr = GLC.ArrayExpression()
  514. else:
  515. params_expr = GLC.Property(GLC.ForLoopCurrentElement("enabled_events", "e"), "parameters")
  516. self.writer.add(GLC.FunctionCall(GLC.Property(GLC.SelfProperty("small_step"), "addCandidate"), [GLC.SelfProperty("transition_" + transition.parent_node.full_name + "_" + str(index)), params_expr]))
  517. self.writer.add(GLC.ReturnStatement(GLC.TrueExpression()))
  518. if transition.hasGuard() :
  519. self.writer.endIf()
  520. if not trigger.isUC() :
  521. self.writer.endIf()
  522. self.writer.endForLoopIterateArray()
  523. def visit_EnterAction(self, enter_method):
  524. parent_node = enter_method.parent_node
  525. self.writer.beginMethod("enter_" + parent_node.full_name)
  526. self.writer.beginMethodBody()
  527. # take care of any AFTER events
  528. for transition in parent_node.transitions :
  529. trigger = transition.getTrigger()
  530. if trigger.isAfter() :
  531. self.writer.startRecordingExpression()
  532. trigger.after.accept(self)
  533. after = self.writer.stopRecordingExpression()
  534. self.writer.addAssignment(
  535. GLC.MapIndexedExpression(GLC.SelfProperty("timers"), str(trigger.getAfterIndex())),
  536. after)
  537. if enter_method.action:
  538. enter_method.action.accept(self)
  539. self.writer.add(
  540. GLC.ArrayPushBack(
  541. GLC.MapIndexedExpression(
  542. GLC.SelfProperty("current_state"),
  543. GLC.SelfProperty(parent_node.parent.full_name)),
  544. GLC.SelfProperty(parent_node.full_name)))
  545. self.writer.endMethodBody()
  546. self.writer.endMethod()
  547. #helper method
  548. def writeEnterDefault(self, entered_node):
  549. self.writer.beginMethod("enterDefault_" + entered_node.full_name)
  550. self.writer.beginMethodBody()
  551. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+entered_node.full_name)))
  552. if entered_node.is_composite:
  553. l = entered_node.defaults
  554. for i in l:
  555. if i.is_composite:
  556. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_" + i.full_name)))
  557. elif i.is_basic:
  558. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + i.full_name)))
  559. self.writer.endMethodBody()
  560. self.writer.endMethod()
  561. def visit_ExitAction(self, exit_method):
  562. exited_node = exit_method.parent_node
  563. self.writer.beginMethod("exit_" + exited_node.full_name)
  564. self.writer.beginMethodBody()
  565. #If the exited node is composite take care of potential history and the leaving of descendants
  566. if exited_node.is_composite :
  567. #handle history
  568. if exited_node.save_state_on_exit :
  569. self.writer.addAssignment(
  570. GLC.MapIndexedExpression(
  571. GLC.SelfProperty("history_state"),
  572. GLC.SelfProperty(exited_node.full_name)),
  573. GLC.MapIndexedExpression(
  574. GLC.SelfProperty("current_state"),
  575. GLC.SelfProperty(exited_node.full_name)))
  576. #Take care of leaving children
  577. children = exited_node.children
  578. if exited_node.is_parallel_state:
  579. for child in children:
  580. if not child.is_history :
  581. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("exit_"+child.full_name)))
  582. else:
  583. for child in children:
  584. if not child.is_history :
  585. self.writer.beginIf(GLC.ArrayContains(
  586. GLC.MapIndexedExpression(
  587. GLC.SelfProperty("current_state"),
  588. GLC.SelfProperty(exited_node.full_name)),
  589. GLC.SelfProperty(child.full_name)))
  590. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("exit_"+child.full_name)))
  591. self.writer.endIf()
  592. # take care of any AFTER events
  593. for transition in exited_node.transitions :
  594. trigger = transition.getTrigger()
  595. if trigger.isAfter() :
  596. self.writer.add(GLC.MapRemoveElement(
  597. GLC.SelfProperty("timers"),
  598. str(trigger.getAfterIndex())))
  599. #Execute user-defined exit action if present
  600. if exit_method.action:
  601. exit_method.action.accept(self)
  602. #Adjust state
  603. self.writer.addAssignment(
  604. GLC.MapIndexedExpression(
  605. GLC.SelfProperty("current_state"),
  606. GLC.SelfProperty(exited_node.parent.full_name)),
  607. GLC.ArrayExpression()) # SPECIAL CASE FOR ORTHOGONAL??
  608. self.writer.endMethodBody()
  609. self.writer.endMethod()
  610. #helper method
  611. def writeEnterHistory(self, entered_node, is_deep):
  612. self.writer.beginMethod("enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + entered_node.full_name)
  613. self.writer.beginMethodBody()
  614. self.writer.beginIf(GLC.EqualsExpression(
  615. GLC.ArrayLength(
  616. GLC.MapIndexedExpression(
  617. GLC.SelfProperty("history_state"),
  618. GLC.SelfProperty(entered_node.full_name))),
  619. "0"))
  620. """self.writer.beginIfBlock(GLC.EqualsExpression(
  621. GLC.ArrayLength(
  622. GLC.MapIndexedExpression(
  623. GLC.SelfProperty("history_state"),
  624. GLC.SelfProperty(entered_node.full_name))),
  625. "0"))"""
  626. defaults = entered_node.defaults
  627. for node in defaults:
  628. if node.is_basic :
  629. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+node.full_name)))
  630. elif node.is_composite :
  631. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_"+node.full_name)))
  632. self.writer.endIf()
  633. self.writer.beginElse()
  634. children = entered_node.children
  635. if entered_node.is_parallel_state:
  636. for child in children:
  637. if not child.is_history :
  638. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
  639. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistory"+("Deep" if is_deep else "Shallow")+"_"+child.full_name)))
  640. else:
  641. for child in children:
  642. if not child.is_history :
  643. self.writer.beginIf(GLC.ArrayContains(
  644. GLC.MapIndexedExpression(
  645. GLC.SelfProperty("history_state"),
  646. GLC.SelfProperty(entered_node.full_name)),
  647. GLC.SelfProperty(child.full_name)))
  648. if child.is_composite:
  649. if is_deep :
  650. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
  651. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryDeep_"+child.full_name)))
  652. else :
  653. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_"+child.full_name)))
  654. else:
  655. self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
  656. self.writer.endIf()
  657. self.writer.endElse()
  658. self.writer.endMethodBody()
  659. self.writer.endMethod()
  660. def visit_StateChart(self, statechart):
  661. # assign each node a unique ID
  662. self.writer.addVSpace()
  663. self.writer.addComment("Unique IDs for all statechart nodes")
  664. for (i,node) in enumerate(statechart.composites + statechart.basics):
  665. self.writer.addStaticAttribute(node.full_name, str(i))
  666. self.writer.addVSpace()
  667. self.writer.addComment("Statechart enter/exit action method(s)")
  668. #visit enter and exit action of children
  669. for i in statechart.composites + statechart.basics:
  670. if i is not statechart.root :
  671. i.enter_action.accept(self)
  672. i.exit_action.accept(self)
  673. # write out statecharts methods for enter/exit state
  674. if len(statechart.composites) > 1 :
  675. self.writer.addVSpace()
  676. self.writer.addComment("Statechart enter/exit default method(s)")
  677. for i in statechart.composites :
  678. if i is not statechart.root :
  679. self.writeEnterDefault(i)
  680. # write out statecharts methods for enter/exit history
  681. if statechart.histories:
  682. self.writer.addVSpace()
  683. self.writer.addComment("Statechart enter/exit history method(s)")
  684. for i in statechart.shallow_history_parents:
  685. self.writeEnterHistory(i, False)
  686. for i in statechart.deep_history_parents:
  687. self.writeEnterHistory(i, True)
  688. self.writer.addVSpace()
  689. self.writer.addComment("Statechart transitions")
  690. self.writeTransitionsRecursively(statechart.root)
  691. # write out transition function
  692. self.writer.beginMethod("generateCandidates", "Generate transition candidates for current small step")
  693. self.writer.beginMethodBody()
  694. self.writer.add(GLC.FunctionCall(
  695. GLC.SelfProperty("generateCandidates_"+statechart.root.full_name)))
  696. self.writer.endMethodBody()
  697. self.writer.endMethod()
  698. def visit_SelfReference(self, self_reference):
  699. self.writer.add(GLC.SelfExpression())
  700. def visit_StateReference(self, state_ref):
  701. self.writer.beginArray()
  702. for node in state_ref.getNodes():
  703. self.writer.add(GLC.SelfProperty(node.full_name))
  704. self.writer.endArray()
  705. def visit_InStateCall(self, in_state_call):
  706. self.writer.beginFunctionCall(GLC.SelfProperty("inState"))
  707. self.writer.startRecordingExpression()
  708. in_state_call.target.accept(self)
  709. expr = self.writer.stopRecordingExpression()
  710. self.writer.addActualParameter(expr)
  711. self.writer.endFunctionCall()
  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(GLC.String(raise_event.getPort()))
  728. else:
  729. self.writer.addActualParameter(GLC.NoneExpression())
  730. self.writer.end()
  731. new_event_expr = self.writer.stopRecordingExpression()
  732. self.writer.startRecordingExpression()
  733. self.writer.beginArray()
  734. if raise_event.isCD():
  735. self.writer.add(GLC.SelfExpression())
  736. for param in raise_event.getParameters() :
  737. param.accept(self) # -> visit_Expression will cause expressions to be added to array
  738. self.writer.endArray()
  739. parameters_array_expr = self.writer.stopRecordingExpression()
  740. new_event_expr.getActualParameters().add(parameters_array_expr)
  741. if raise_event.isNarrow():
  742. self.writer.add(GLC.FunctionCall(
  743. GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"), [
  744. GLC.NewExpression("Event", [
  745. GLC.String("narrow_cast"),
  746. GLC.NoneExpression(),
  747. GLC.ArrayExpression([
  748. GLC.SelfExpression(),
  749. raise_event.getTarget(),
  750. new_event_expr])])]))
  751. elif raise_event.isLocal():
  752. self.writer.add(GLC.FunctionCall(
  753. GLC.SelfProperty("raiseInternalEvent"),
  754. [new_event_expr]))
  755. elif raise_event.isOutput():
  756. self.writer.add(GLC.FunctionCall(
  757. GLC.Property(GLC.SelfProperty("big_step"), "outputEvent"),
  758. [new_event_expr]))
  759. elif raise_event.isCD():
  760. self.writer.add(GLC.FunctionCall(
  761. GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"),
  762. [new_event_expr]))
  763. elif raise_event.isBroad():
  764. self.writer.add(GLC.FunctionCall(
  765. GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"),
  766. [GLC.NewExpression("Event", [
  767. GLC.String("broad_cast"),
  768. GLC.NoneExpression(),
  769. GLC.ArrayExpression([
  770. new_event_expr])])]))
  771. def visit_Script(self, script):
  772. self.writer.addRawCode(script.code)
  773. def visit_Log(self, log):
  774. self.writer.add(GLC.LogStatement(log.message))
  775. def visit_Assign(self, assign):
  776. self.writer.startRecordingExpression()
  777. assign.lvalue.accept(self) # --> visit_Expression
  778. lvalue = self.writer.stopRecordingExpression()
  779. self.writer.startRecordingExpression()
  780. assign.expression.accept(self) # --> visit_Expression
  781. rvalue = self.writer.stopRecordingExpression()
  782. self.writer.addAssignment(lvalue, rvalue)