generic_generator.py 38 KB

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