# DEVS Generator by Sam Pieters. Inspired on the generatic generator by Joeri Excelmans # # Visits SCCD-domain constructs (see sccd_constructs.py) and converts them # to a DEVS language AST (see generic_language_constructs.py), that can # then be visited by a target language writer (only supports Python). from sccd.compiler.utils import Enum, Logger from sccd.compiler.visitor import Visitor from sccd.compiler.sccd_constructs import FormalParameter from sccd.compiler.stateful_writer import StatefulWriter import sccd.compiler.generic_language_constructs as GLC class DEVSGenerator(Visitor): def __init__(self, platform): self.platform = platform self.writer = StatefulWriter() def generic_visit(self, node): Logger.showWarning("GenericGenerator has no visit method for node of type '" + str(type(node)) + "'.") def get(self): return self.writer.get() def visit_ClassDiagram(self, class_diagram): """ Generate code for Class Diagram """ header = ("Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, " "and Yentl Van Tendeloo (for the inspiration) and Sam Pieters (DEVS)\n") if class_diagram.name or class_diagram.author or class_diagram.description: header += "\n" if class_diagram.author: header += "Model author: " + class_diagram.author + "\n" if class_diagram.name: header += "Model name: " + class_diagram.name + "\n" if class_diagram.description.strip(): header += "Model description:\n" header += class_diagram.description.strip() self.writer.addMultiLineComment(header) self.writer.addVSpace() self.writer.addInclude(([GLC.RuntimeModuleIdentifier(), "DEVS_statecharts_core"])) if class_diagram.top.strip(): self.writer.addRawCode(class_diagram.top) self.writer.addVSpace() self.writer.beginPackage(class_diagram.name) ################################ # Visit children (Classes) ################################ for c in class_diagram.classes: c.accept(self) ################################ # Object Manager State (instantiate function) ################################ self.writer.beginMethod("instantiate") self.writer.addFormalParameter("class_name") self.writer.addFormalParameter("construct_params") self.writer.beginMethodBody() self.writer.addAssignment("instance", "{}") self.writer.addAssignment(GLC.ArrayIndexedExpression("instance", GLC.String("name")), "class_name") for c in class_diagram.classes: self.writer.beginElseIf(GLC.EqualsExpression("class_name", GLC.String(c.name))) if c.isAbstract(): # cannot instantiate abstract class self.writer.add(GLC.ThrowExceptionStatement(GLC.String("Cannot instantiate abstract class \"" + c.name + "\" with unimplemented methods \"" + "\", \"".join(c.abstract_method_names) + "\"."))) else: self.writer.addAssignment(GLC.SelfProperty("narrow_cast_id"), GLC.SelfProperty(f"narrow_cast_id + {len(c.inports)}")) self.writer.addAssignment( "instance[\"associations\"]", GLC.MapExpression()) for a in c.associations: a.accept(self) self.writer.endElseIf() self.writer.beginElse() self.writer.add( GLC.ThrowExceptionStatement( GLC.AdditionExpression( GLC.String("Cannot instantiate class "), "class_name" ) ) ) self.writer.endElse() self.writer.add(GLC.ReturnStatement("instance")) self.writer.endMethodBody() self.writer.endMethod() self.writer.addStaticAttribute("ObjectManagerState.instantiate", "instantiate") ################################ # Object Manager ################################ self.writer.beginClass("ObjectManager", ["ObjectManagerBase"]) self.writer.beginConstructor() self.writer.addFormalParameter("name") self.writer.beginMethodBody() self.writer.beginSuperClassConstructorCall("ObjectManagerBase") self.writer.addActualParameter("name") self.writer.endSuperClassConstructorCall() self.writer.addAssignment(GLC.SelfProperty("state"), GLC.FunctionCall("ObjectManagerState")) self.writer.addAssignment(GLC.SelfProperty("input"), GLC.FunctionCall(GLC.SelfProperty("addInPort"), [GLC.String("input")])) for class_name in class_diagram.class_names: self.writer.addAssignment(GLC.SelfProperty(f"output[\"{class_name}\"]"), GLC.FunctionCall(GLC.SelfProperty("addOutPort"))) self.writer.add(GLC.FunctionCall(GLC.SelfProperty("state.createInstance"), [GLC.String(class_diagram.default_class.name), GLC.ArrayExpression()])) self.writer.endMethodBody() self.writer.endConstructor() self.writer.endClass() ################################ # Controller ################################ self.writer.beginClass("Controller", ["CoupledDEVS"]) self.writer.beginConstructor() self.writer.addFormalParameter("name") for p in class_diagram.default_class.constructors[0].parameters: p.accept(self) self.writer.beginMethodBody() self.writer.beginSuperClassConstructorCall("CoupledDEVS") self.writer.addActualParameter("name") self.writer.endSuperClassConstructorCall() for i in class_diagram.inports: self.writer.addAssignment(GLC.SelfProperty("in_" + i), GLC.FunctionCall(GLC.SelfProperty("addInPort"), [GLC.String(i)])) for o in class_diagram.outports: self.writer.addAssignment(GLC.SelfProperty("out_" + o), GLC.FunctionCall(GLC.SelfProperty("addOutPort"), [GLC.String(o)])) # Add AtomicDEVS models self.writer.addAssignment(GLC.SelfProperty("objectmanager"), (GLC.FunctionCall(GLC.SelfProperty("addSubModel"), [GLC.FunctionCall( "ObjectManager", GLC.ActualParameters([ GLC.String( "ObjectManager")]))]))) self.writer.addAssignment(GLC.SelfProperty("atomics"), GLC.ArrayExpression()) for (i, class_name) in enumerate(class_diagram.class_names): self.writer.add(GLC.ArrayPushBack( GLC.SelfProperty("atomics"), GLC.FunctionCall(GLC.SelfProperty("addSubModel"), [GLC.FunctionCall(class_name, GLC.ActualParameters([GLC.String(class_name)]))]))) # Add links between the models for (i, the_class) in enumerate(class_diagram.classes): # Add links between the classes and the object manager self.writer.add((GLC.FunctionCall(GLC.SelfProperty("connectPorts"), [GLC.SelfProperty(f"atomics[{i}].obj_manager_out"), GLC.SelfProperty(f"objectmanager.input")]))) self.writer.add((GLC.FunctionCall(GLC.SelfProperty("connectPorts"), [GLC.SelfProperty(f"objectmanager.output[\"{the_class.name}\"]"), GLC.SelfProperty(f"atomics[{i}].obj_manager_in")]))) # Add links between the global in-/outputs and the classes for (i, the_class) in enumerate(class_diagram.classes): for o in class_diagram.outports: self.writer.add(GLC.FunctionCall(GLC.SelfProperty("connectPorts"), [GLC.SelfProperty(f"atomics[{i}].glob_outputs[\"{o}\"]"), GLC.SelfProperty(f"out_{o}")])) for inp in class_diagram.inports: self.writer.add(GLC.FunctionCall(GLC.SelfProperty("connectPorts"), [GLC.SelfProperty(f"in_{inp}"), GLC.SelfProperty(f"atomics[{i}].input")])) self.writer.endMethodBody() self.writer.endConstructor() self.writer.endClass() # End Controller Class # visit test node if there is one if class_diagram.test: class_diagram.test.accept(self) self.writer.endPackage() # CLASS def visit_Class(self, class_node): """ Generate code for Class construct """ super_classes = [] if not class_node.super_class_objs: if class_node.statechart: super_classes.append("RuntimeClassBase") if class_node.super_classes: for super_class in class_node.super_classes: super_classes.append(super_class + "Instance") ################################ # State Instance (statechart) ################################ self.writer.beginClass(f"{class_node.name}Instance", super_classes) # visit constructor class_node.constructors[0].accept(self) # visit destructor class_node.destructors[0].accept(self) # visit methods for i in class_node.methods: i.accept(self) # compile and initialize Statechart if class_node.statechart: class_node.statechart.accept(self) self.writer.beginMethod("initializeStatechart") self.writer.beginMethodBody() self.writer.addComment("enter default state") # get effective target of initial transition self.writer.addAssignment( GLC.SelfProperty("default_targets"), GLC.FunctionCall( GLC.Property( GLC.MapIndexedExpression( GLC.SelfProperty("states"), GLC.String(class_node.statechart.root.initial) ), "getEffectiveTargetStates" ) ) ) self.writer.add(GLC.SuperClassMethodCall( "RuntimeClassBase", "initializeStatechart", [] )) self.writer.endMethodBody() self.writer.endMethod() self.writer.endClass() ################################ # Class (Type) ################################ self.writer.beginClass(class_node.name, ["ClassBase"]) ################################ # Constructor of Class AtomicDEVS ################################ self.writer.beginConstructor() self.writer.addFormalParameter("name") self.writer.beginMethodBody() # constructor body self.writer.beginSuperClassConstructorCall("ClassBase") self.writer.addActualParameter("name") self.writer.endSuperClassConstructorCall() self.writer.addAssignment(GLC.SelfProperty("input"), GLC.FunctionCall(GLC.SelfProperty("addInPort"), [GLC.String("input")])) for global_outport in class_node.class_diagram.outports: self.writer.addAssignment(GLC.SelfProperty(f"glob_outputs[\"{global_outport}\"]"), GLC.FunctionCall(GLC.SelfProperty("addOutPort"), [GLC.String(global_outport)])) for p in class_node.inports: self.writer.addAssignment(GLC.SelfProperty(p), GLC.FunctionCall(GLC.SelfProperty("addInPort"), [GLC.String(p)])) for p in class_node.outports: self.writer.addAssignment( GLC.MapIndexedExpression(GLC.SelfProperty("outports"), GLC.String(p)), GLC.FunctionCall(GLC.Property("controller", "addOutputPort"), [GLC.String(p), GLC.SelfExpression()])) if class_node.name == class_node.class_diagram.default_class.name: self.writer.addAssignment("new_instance", GLC.SelfProperty("constructObject(0, 0, [])")) self.writer.addAssignment(GLC.SelfProperty("state.instances[new_instance.instance_id]"), "new_instance") self.writer.add(GLC.FunctionCall("new_instance.start")) self.writer.addAssignment(GLC.SelfProperty("state.next_time"), "0") self.writer.endMethodBody() self.writer.endConstructor() self.writer.beginMethod("constructObject") parameters = [GLC.SelfExpression(), "id", "start_port_id"] for i, _ in enumerate(class_node.constructors[0].parameters): parameters.append(f"parameters[{i+1}]") self.writer.addFormalParameter("id") self.writer.addFormalParameter("start_port_id") self.writer.addFormalParameter("parameters") self.writer.beginMethodBody() self.writer.addAssignment("new_instance", GLC.FunctionCall(f"{class_node.name}Instance", parameters)) self.writer.add(GLC.ReturnStatement("new_instance")) self.writer.endMethodBody() self.writer.endMethod() self.writer.endClass() # CLASS -- CONSTRUCTOR def visit_Constructor(self, constructor): # visit constructor self.writer.beginConstructor() self.writer.addFormalParameter("atomdevs") self.writer.addFormalParameter("id") self.writer.addFormalParameter("start_port_id") for p in constructor.getParams(): self.writer.addFormalParameter(p.getIdent(), p.getDefault()) self.writer.beginMethodBody() self.writer.beginSuperClassConstructorCall("RuntimeClassBase") self.writer.addActualParameter("atomdevs") self.writer.addActualParameter("id") self.writer.endSuperClassConstructorCall() if constructor.parent_class.statechart: self.writer.addVSpace() if constructor.parent_class.statechart.big_step_maximality == "take_one": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeOne")) elif constructor.parent_class.statechart.big_step_maximality == "take_many": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeMany")) if constructor.parent_class.statechart.internal_event_lifeline == "queue": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "Queue")) elif constructor.parent_class.statechart.internal_event_lifeline == "next_small_step": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextSmallStep")) elif constructor.parent_class.statechart.internal_event_lifeline == "next_combo_step": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextComboStep")) if constructor.parent_class.statechart.input_event_lifeline == "first_small_step": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstSmallStep")) elif constructor.parent_class.statechart.input_event_lifeline == "first_combo_step": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstComboStep")) elif constructor.parent_class.statechart.input_event_lifeline == "whole": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "Whole")) if constructor.parent_class.statechart.priority == "source_parent": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceParent")) elif constructor.parent_class.statechart.priority == "source_child": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceChild")) if constructor.parent_class.statechart.concurrency == "single": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Single")) elif constructor.parent_class.statechart.concurrency == "many": self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Many")) self.writer.addVSpace() self.writer.addComment("build Statechart structure") self.writer.add(GLC.FunctionCall(GLC.SelfProperty("build_statechart_structure"), [])) if constructor.parent_class.attributes: self.writer.addVSpace() self.writer.addComment("user defined attributes") for attribute in constructor.parent_class.attributes: if attribute.init_value is None : self.writer.addAssignment(GLC.SelfProperty(attribute.name), GLC.NoneExpression()) else : self.writer.addAssignment(GLC.SelfProperty(attribute.name), attribute.init_value) self.writer.addVSpace() self.writer.addComment("call user defined constructor") self.writer.beginSuperClassMethodCall(f"{constructor.parent_class.name}Instance", "user_defined_constructor") for p in constructor.getParams(): # we can't do p.accept(self) here because 'p' is a FormalParameter # and we want to write it as an actual parameter self.writer.addActualParameter(p.getIdent()) self.writer.endSuperClassMethodCall() for inp in constructor.parent_class.class_diagram.inports: self.writer.addAssignment("port_name", GLC.FunctionCall("addInputPort", [GLC.String(inp), "start_port_id", "True"])) self.writer.addAssignment("atomdevs.state.port_mappings[port_name]", "None") self.writer.addAssignment("port_name", GLC.FunctionCall("addInputPort", [GLC.String(""), "start_port_id"])) self.writer.addAssignment("atomdevs.state.port_mappings[port_name]", "id") for index, inp in enumerate(constructor.parent_class.inports): self.writer.addAssignment("port_name", GLC.FunctionCall("addInputPort", [GLC.String(inp), f"start_port_id + {index + 1}"])) self.writer.addAssignment("atomdevs.state.port_mappings[port_name]", "id") self.writer.addAssignment(GLC.SelfProperty(f"inports[\"{inp}\"]"), "port_name") self.writer.endMethodBody() self.writer.endConstructor() # user defined constructor self.writer.beginMethod("user_defined_constructor") for p in constructor.getParams(): p.accept(self) self.writer.beginMethodBody() for super_class in constructor.parent_class.super_classes: # begin call if super_class in constructor.parent_class.super_class_objs: self.writer.beginSuperClassMethodCall(super_class + "Instance", "user_defined_constructor") else: self.writer.beginSuperClassConstructorCall(super_class) # write actual parameters if super_class in constructor.super_class_parameters: for p in constructor.super_class_parameters[super_class]: self.writer.addActualParameter(p) # end call if super_class in constructor.parent_class.super_class_objs: self.writer.endSuperClassMethodCall() else: self.writer.endSuperClassConstructorCall() self.writer.addRawCode(constructor.body) self.writer.endMethodBody() self.writer.endMethod() def visit_FormalParameter(self, formal_parameter): self.writer.addFormalParameter(formal_parameter.getIdent(), formal_parameter.getDefault()) ### CLASS -- DESTRUCTOR def visit_Destructor(self, destructor): self.writer.beginMethod("user_defined_destructor") self.writer.beginMethodBody() if destructor.body.strip(): self.writer.addRawCode(destructor.body) if destructor.parent_class.super_classes: self.writer.addComment("call super class destructors") for super_class in destructor.parent_class.super_classes: # begin call if super_class in destructor.parent_class.super_class_objs: self.writer.beginSuperClassMethodCall(super_class + "Instance", "user_defined_destructor") self.writer.endSuperClassMethodCall() else: self.writer.beginSuperClassDestructorCall(super_class) self.writer.endSuperClassDestructorCall() pass self.writer.endMethodBody() self.writer.endMethod() # CLASS -- METHOD def visit_Method(self, method): self.writer.addVSpace() self.writer.beginMethod(method.name, "user defined method") for p in method.parameters: p.accept(self) self.writer.beginMethodBody() self.writer.addRawCode(method.body) self.writer.endMethodBody() self.writer.endMethod() # CLASS -- ASSOCIATION def visit_Association(self, association): self.writer.addAssignment( GLC.MapIndexedExpression( "instance[\"associations\"]", GLC.String(association.name)), GLC.NewExpression("Association", [GLC.String(association.to_class), str(association.min), str(association.max)])) # CLASS -- STATECHART def visit_StateChart(self, statechart): self.writer.addVSpace() self.writer.beginMethod("build_statechart_structure", "builds Statechart structure") self.writer.beginMethodBody() def writeState(s, i): self.writer.addVSpace() self.writer.addComment("state %s" % ("" if s.is_root else s.new_full_name)) index_expr = GLC.MapIndexedExpression(GLC.SelfProperty("states"), GLC.String(s.new_full_name)) clazz = "State" if s.is_parallel_state: clazz = "ParallelState" elif s.is_history: if s.is_history_deep: clazz = "DeepHistoryState" else: clazz = "ShallowHistoryState" self.writer.addAssignment( index_expr, GLC.NewExpression(clazz, [str(i), GLC.String(s.new_full_name), GLC.SelfExpression()]) ) if not s.is_root: if s.enter_action.action or s.has_timers: self.writer.add( GLC.FunctionCall( GLC.Property( index_expr, "setEnter" ), [GLC.SelfProperty(s.friendly_name + "_enter")] ) ) if s.exit_action.action or s.has_timers: self.writer.add( GLC.FunctionCall( GLC.Property( index_expr, "setExit" ), [GLC.SelfProperty(s.friendly_name + "_exit")] ) ) # write all states for (i, s) in enumerate(statechart.states): writeState(s, i) # add children to composite states self.writer.addVSpace() self.writer.addComment("add children") for (i, s) in enumerate(statechart.composites): for c in s.children: self.writer.add( GLC.FunctionCall( GLC.Property( GLC.MapIndexedExpression( GLC.SelfProperty("states"), GLC.String(s.new_full_name) ), "addChild"), [GLC.MapIndexedExpression(GLC.SelfProperty("states"), GLC.String(c.new_full_name))] ) ) # fix tree at root, such that 'descendants' and 'ancestors' fields are filled in self.writer.add( GLC.FunctionCall( GLC.Property( GLC.MapIndexedExpression( GLC.SelfProperty("states"), GLC.String("") ), "fixTree" ) ) ) # defaults for (i, s) in enumerate(statechart.composites): if not s.is_parallel_state: self.writer.addAssignment( GLC.Property( GLC.MapIndexedExpression( GLC.SelfProperty("states"), GLC.String(s.new_full_name) ), "default_state" ), GLC.MapIndexedExpression( GLC.SelfProperty("states"), GLC.String(s.initial) ) ) # transitions for s in statechart.basics + statechart.composites: if s.transitions: self.writer.addVSpace() self.writer.addComment("transition %s" % s.new_full_name) for (i, t) in enumerate(s.transitions + s.else_transitions): # instantiate new Transition instance self.writer.addAssignment( GLC.LocalVariableDeclaration( "%s_%i" % (s.friendly_name, i) ), GLC.NewExpression( "Transition", [ GLC.SelfExpression(), GLC.MapIndexedExpression( GLC.SelfProperty("states"), GLC.String(s.new_full_name), ), GLC.ArrayExpression( [ GLC.MapIndexedExpression( GLC.SelfProperty("states"), GLC.String(target_node.new_full_name) ) for target_node in t.target.target_nodes ] ) ] ) ) # if any action associated with transition: set executable_content to correct function (generated later) if t.action.sub_actions: self.writer.add( GLC.FunctionCall( GLC.Property( "%s_%i" % (s.friendly_name, i), "setAction" ), [GLC.SelfProperty("%s_%i_exec" % (s.friendly_name, i))] ) ) # if any trigger associated with transition: instantiate correct Event instance trigger = None if t.trigger.is_after: trigger = GLC.NewExpression("Event", [GLC.String("_%iafter" % (t.trigger.getAfterIndex()))]) elif t.trigger.event: trigger = GLC.NewExpression("Event", [ GLC.String(t.trigger.event), GLC.NoneExpression() if t.trigger.port is None else GLC.FunctionCall( GLC.SelfProperty("getInPortName"), [GLC.String(t.trigger.port)] ) ] ) else: trigger = GLC.NoneExpression() if trigger: self.writer.add( GLC.FunctionCall( GLC.Property( "%s_%i" % (s.friendly_name, i), "setTrigger" ), [trigger] ) ) # if any guard associated with transition: set guard to correct function (generated later) if t.guard: self.writer.add( GLC.FunctionCall( GLC.Property( "%s_%i" % (s.friendly_name, i), "setGuard" ), [GLC.SelfProperty("%s_%i_guard" % (s.friendly_name, i))] ) ) self.writer.add( GLC.FunctionCall( GLC.Property( GLC.MapIndexedExpression( GLC.SelfProperty("states"), GLC.String(s.new_full_name) ), "addTransition" ), ["%s_%i" % (s.friendly_name, i)] ) ) self.writer.endMethodBody() self.writer.endMethod() # enter/exit actions for (i, s) in enumerate(statechart.composites + statechart.basics): if not s.is_root: if s.enter_action.action or s.has_timers: s.enter_action.accept(self) if s.exit_action.action or s.has_timers: s.exit_action.accept(self) # transition actions and guards for s in statechart.composites + statechart.basics: for (i, t) in enumerate(s.transitions): if t.action.sub_actions: self.writeTransitionAction(t, i) if t.hasGuard(): self.writeTransitionGuard(t, i) def visit_FormalEventParameter(self, formal_event_parameter): self.writer.add(formal_event_parameter.name) def writeFormalEventParameters(self, transition): parameters = transition.getTrigger().getParameters() if (len(parameters) > 0): for index, parameter in enumerate(parameters): self.writer.startRecordingExpression() parameter.accept(self) parameter_expr = self.writer.stopRecordingExpression() self.writer.addAssignment( GLC.LocalVariableDeclaration(parameter_expr), GLC.ArrayIndexedExpression("parameters", str(index))) def writeTransitionAction(self, transition, index): self.writer.beginMethod("%s_%i_exec" % (transition.parent_node.friendly_name, index)) # parameters, start method self.writer.addFormalParameter("parameters") self.writer.beginMethodBody() # handle parameters to actually use them self.writeFormalEventParameters(transition) # write action transition.getAction().accept(self) # end method self.writer.endMethodBody() self.writer.endMethod() def writeTransitionGuard(self, transition, index): self.writer.beginMethod("%s_%i_guard" % (transition.parent_node.friendly_name, index)) # parameters, start method self.writer.addFormalParameter("parameters") self.writer.beginMethodBody() # handle parameters to actually use them self.writeFormalEventParameters(transition) # get guard condition self.writer.startRecordingExpression() transition.getGuard().accept(self) # --> visit_Expression expr = self.writer.stopRecordingExpression() # return statement, end method self.writer.add(GLC.ReturnStatement(expr)) self.writer.endMethodBody() self.writer.endMethod() def visit_EnterAction(self, enter_method): parent_node = enter_method.parent_node self.writer.beginMethod(parent_node.friendly_name + "_enter") self.writer.beginMethodBody() if enter_method.action: enter_method.action.accept(self) # take care of any AFTER events for transition in parent_node.transitions: trigger = transition.getTrigger() if trigger.isAfter(): self.writer.startRecordingExpression() trigger.after.accept(self) after = self.writer.stopRecordingExpression() self.writer.add(GLC.FunctionCall(GLC.SelfProperty("addTimer"), [str(trigger.getAfterIndex()), after])) self.writer.endMethodBody() self.writer.endMethod() def visit_ExitAction(self, exit_method): parent_node = exit_method.parent_node self.writer.beginMethod(parent_node.friendly_name + "_exit") self.writer.beginMethodBody() # take care of any AFTER events for transition in parent_node.transitions: trigger = transition.getTrigger() if trigger.isAfter(): self.writer.add(GLC.FunctionCall(GLC.SelfProperty("removeTimer"), [str(trigger.getAfterIndex())])) # execute user-defined exit action if present if exit_method.action: exit_method.action.accept(self) self.writer.endMethodBody() self.writer.endMethod() # helper method def writeEnterHistory(self, entered_node, is_deep): ### OLD CODE (TODO) self.writer.beginMethod("enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + entered_node.full_name) self.writer.beginMethodBody() self.writer.beginIf(GLC.EqualsExpression( GLC.ArrayLength( GLC.MapIndexedExpression( GLC.SelfProperty("history_state"), GLC.SelfProperty(entered_node.full_name))), "0")) defaults = entered_node.defaults for node in defaults: if node.is_basic: self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + node.full_name))) elif node.is_composite: self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_" + node.full_name))) self.writer.endIf() self.writer.beginElse() children = entered_node.children if entered_node.is_parallel_state: for child in children: if not child.is_history: self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + child.full_name))) self.writer.add(GLC.FunctionCall( GLC.SelfProperty("enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + child.full_name))) else: for child in children: if not child.is_history: self.writer.beginIf(GLC.ArrayContains( GLC.MapIndexedExpression( GLC.SelfProperty("history_state"), GLC.SelfProperty(entered_node.full_name)), GLC.SelfProperty(child.full_name))) if child.is_composite: if is_deep: self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + child.full_name))) self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryDeep_" + child.full_name))) else: self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_" + child.full_name))) else: self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + child.full_name))) self.writer.endIf() self.writer.endElse() self.writer.endMethodBody() self.writer.endMethod() def visit_SelfReference(self, self_reference): self.writer.add(GLC.SelfExpression()) def visit_StateReference(self, state_ref): self.writer.beginArray() for node in state_ref.getNodes(): self.writer.add(GLC.SelfProperty(node.full_name)) self.writer.endArray() def visit_InStateCall(self, in_state_call): self.writer.add( GLC.FunctionCall( GLC.SelfProperty("inState"), [ GLC.ArrayExpression( [GLC.String(target_node.new_full_name) for target in in_state_call.targets for target_node in target.target_nodes] ) ] ) ) def visit_ElseGuard(self, else_guard): self.writer.add( GLC.String("ELSE_GUARD") ) def visit_Expression(self, expression): self.writer.startRecordingExpression() self.writer.beginGlue() for part in expression.expression_parts: part.accept(self) self.writer.endGlue() expr = self.writer.stopRecordingExpression() self.writer.add(expr) def visit_ExpressionPartString(self, e): self.writer.add(e.string) def visit_RaiseEvent(self, raise_event): self.writer.startRecordingExpression() self.writer.begin(GLC.NewExpression("Event")) self.writer.addActualParameter(GLC.String(raise_event.getEventName())) if raise_event.isOutput(): self.writer.addActualParameter( GLC.FunctionCall( GLC.SelfProperty("getOutPortName"), [GLC.String(raise_event.getPort())] ) ) else: self.writer.addActualParameter(GLC.NoneExpression()) self.writer.end() new_event_expr = self.writer.stopRecordingExpression() self.writer.startRecordingExpression() self.writer.beginArray() if raise_event.isCD(): self.writer.add(GLC.SelfExpression()) for param in raise_event.getParameters(): param.accept(self) # -> visit_Expression will cause expressions to be added to array self.writer.endArray() parameters_array_expr = self.writer.stopRecordingExpression() new_event_expr.getActualParameters().add(parameters_array_expr) if raise_event.isNarrow(): self.writer.add(GLC.FunctionCall( GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"), [ GLC.NewExpression("Event", [ GLC.String("narrow_cast"), GLC.NoneExpression(), GLC.ArrayExpression([ GLC.SelfExpression(), raise_event.getTarget(), new_event_expr])])])) elif raise_event.isLocal(): self.writer.add(GLC.FunctionCall( GLC.SelfProperty("raiseInternalEvent"), [new_event_expr])) elif raise_event.isOutput(): self.writer.add(GLC.FunctionCall( GLC.Property(GLC.SelfProperty("big_step"), "outputEvent"), [new_event_expr])) elif raise_event.isCD(): self.writer.add(GLC.FunctionCall( GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"), [new_event_expr])) elif raise_event.isBroad(): self.writer.add(GLC.FunctionCall( GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"), [GLC.NewExpression("Event", [ GLC.String("broad_cast"), GLC.NoneExpression(), GLC.ArrayExpression([ GLC.SelfExpression(), new_event_expr])])])) def visit_Script(self, script): self.writer.addRawCode(script.code) def visit_Log(self, log): self.writer.add(GLC.LogStatement(log.message)) def visit_Assign(self, assign): self.writer.startRecordingExpression() assign.lvalue.accept(self) # --> visit_Expression lvalue = self.writer.stopRecordingExpression() self.writer.startRecordingExpression() assign.expression.accept(self) # --> visit_Expression rvalue = self.writer.stopRecordingExpression() self.writer.addAssignment(lvalue, rvalue)