def processInheritances(self, inheritances): # process each inheritance, stores a dict with each subclass as the key # and a list of tuples (superclass, priority) as the value. The priority # tells us which class to inherit from first for multiple inheritance. Gives # a WARNING with a given inheritance order if two priorities are the same for i in inheritances : self.super_classes.append((i.get("class",""),i.get("priority",1))) try: self.super_classes.sort(lambda a, b: cmp(b[1], a[1])) # sort from high priority to low priority except TypeError: self.super_classes = sorted(self.super_classes, key=lambda x: x[1], reverse = True) priorityChecker = {} for super_class, priority in self.super_classes: if priority in priorityChecker: checkIt = priorityChecker[priority] else: checkIt = [] if super_class not in checkIt: checkIt.append(super_class) priorityChecker[priority] = checkIt for priority, checkIt in list(priorityChecker.items()): if len(checkIt) > 1: Logger.showWarning("Class <" + self.name + "> inherits from classes <" + ", ".join(checkIt) + "> with same priority <" + str(priority) + ">. Document inheritance order is used.") self.super_classes = [entry[0] for entry in self.super_classes]
def visit_Class(self, c): # replace super class names by super class objects for s in c.super_classes: super_class = None for clas in c.class_diagram.classes: if clas.name == s: super_class = clas if super_class == None: Logger.showWarning("Class <" + c.name + "> has undefined super class <" + s + ">.") else: c.super_class_objs[s] = super_class # calculate list of abstract methods c.abstract_method_names = getClassAbstractMethodNames(c) # check if <super> tags exist for all inherited classes for name, obj in list(c.super_class_objs.items()): if obj: if name not in c.constructors[0].super_class_parameters: num_params = len(obj.constructors[0].parameters) if num_params > 0: raise CompilerException( "Class <" + c.name + "> inherits <" + name + "> and <" + name + ">'s constructor has " + str(num_params) + " parameter(s), but there's no <super> entry for that class in <" + c.name + ">'s constructor.")
def sccdToGeneric(sccd, platform): succesfull_generation = False generator = GenericGenerator(platform) sccd.accept(generator) generic = generator.get() Logger.showInfo("Classes <" + ", ".join(sccd.class_names) + "> have been converted to generic language constructs.") return generic
def genericToTarget(generic, target_language, output_file): try: f = FileWriter(output_file) if target_language == "javascript": writer = JavascriptWriter(f) elif target_language == "python": writer = PythonWriter(f) else: raise Exception("Language not supported") generic.accept(writer) Logger.showInfo( "Generic language constructs have been converted to target language constructs and have been written to file '" + output_file + "'.") finally: f.close()
def __init__(self, xml_element): self.event = xml_element.get("event","").strip() scope_string = xml_element.get("scope","").strip().lower() self.target = xml_element.get("target","").strip() self.port = xml_element.get("port","").strip() if scope_string == "local" : self.scope = self.LOCAL_SCOPE elif scope_string == "broad" : self.scope = self.BROAD_SCOPE elif scope_string == "output" : self.scope = self.OUTPUT_SCOPE elif scope_string == "narrow" : self.scope = self.NARROW_SCOPE elif scope_string == "cd" : self.scope = self.CD_SCOPE elif scope_string == "" : #Calculate scope depending on present attributes if self.target and self.port : raise CompilerException("Both target and port attribute detected without a scope defined.") elif self.port : self.scope = self.OUTPUT_SCOPE elif self.target : self.scope = self.NARROW_SCOPE else : self.scope = self.LOCAL_SCOPE else : raise CompilerException("Illegal scope attribute; needs to be one of the following : local, broad, narrow, output, cd or nothing."); if self.scope == self.LOCAL_SCOPE or self.scope == self.BROAD_SCOPE or self.scope == self.CD_SCOPE: if self.target : Logger.showWarning("Raise event target detected, not matching with scope. Ignored.") self.target = "" if self.port : Logger.showWarning("Raise event port detected, not matching with scope. Ignored.") self.port = "" if self.scope == self.NARROW_SCOPE and self.port : Logger.showWarning("Raise event port detected, not matching with scope. Ignored.") self.port = "" if self.scope == self.OUTPUT_SCOPE and self.target : Logger.showWarning("Raise event target detected, not matching with scope. Ignored.") self.target = "" self.params = [] parameters = xml_element.findall('parameter') for p in parameters : value = p.get("expr","") if not value : raise CompilerException("Parameter without value detected.") self.params.append(Expression(value))
def generate(input_file, output_file, target_language, platform): sccd = xmlToSccd(input_file) if not target_language: if sccd.language: target_language = sccd.language else: target_language = "python" # default elif sccd.language and target_language != sccd.language: Logger.showError( "Diagram specifies target language as \"" + sccd.language + "\", but language option of compiler has been set to \"" + target_language + "\". No output has been generated.") return if target_language == "python" and not output_file.endswith(".py"): output_file += ".py" elif target_language == "javascript" and not output_file.endswith(".js"): output_file += ".js" generic = sccdToGeneric(sccd, platform) genericToTarget(generic, target_language, output_file)
def __init__(self, class_obj, statechart_xml): """ Gives the module information on the statechart by listing its basic, orthogonal, composite and history states as well as mapping triggers to names making the appropriate conversion from AFTER() triggers to event names """ self.class_obj = class_obj self.root = StateChartNode(self, statechart_xml); #creates the whole statechart structure recursively self.states = [] self.basics = [] self.composites = [] self.histories = [] self.nr_of_after_transitions = 0 def getSemanticOption(name, allowed_values, default_value): result = statechart_xml.get(name, default_value) if result not in allowed_values: raise CompilerException("Illegal value for semantic option " + name + ": '" + result + "'. Allowed values are ['" + "', '".join(allowed_values) + "'], default value is '" + default_value + "'.") return result self.big_step_maximality = getSemanticOption("big_step_maximality", ["take_one", "take_many"], "take_many") self.internal_event_lifeline = getSemanticOption("internal_event_lifeline", ["next_small_step", "next_combo_step", "queue"], "queue") self.input_event_lifeline = getSemanticOption("input_event_lifeline", ["first_small_step", "first_combo_step", "whole"], "first_combo_step") self.priority = getSemanticOption("priority", ["source_parent", "source_child"], "source_parent") self.concurrency = getSemanticOption("concurrency", ["single", "many"], "single") if self.internal_event_lifeline == "next_combo_step": if self.big_step_maximality == "take_one": Logger.showWarning("Using 'Next Combo Step' internal event lifeline semantics and 'Take One' big step maximality semantics simultaneously doesn't make sense.") self.extractFromHierarchy(self.root) # recursively extracts the basics, composites, histories and nr_of_after_transitions # Calculate the history that needs to be taken care of. self.shallow_history_parents = [] self.deep_history_parents = [] self.combined_history_parents = [] #All nodes that need state saved on leaving for node in self.histories: self.calculateHistory(node.parent, node.is_history_deep)
def main(): parser = argparse.ArgumentParser(prog="python -m sccd.compiler.sccdc") parser.add_argument('input', help='The path to the XML file to be compiled.') parser.add_argument( '-o', '--output', type=str, help= 'The path to the generated code. Defaults to the same name as the input file but with matching extension.' ) parser.add_argument( '-v', '--verbose', type=int, help= '2 = all output; 1 = only warnings and errors; 0 = only errors; -1 = no output. Defaults to 2.', default=2) parser.add_argument( '-p', '--platform', type=str, help= "Let the compiled code run on top of threads, gameloop or eventloop. The default is eventloop." ) parser.add_argument( '-l', '--language', type=str, help= 'Target language, either "javascript" or "python". Defaults to the latter.' ) args = vars(parser.parse_args()) #Set verbose if args['verbose'] is not None: if args['verbose'] in [-1, 0, 1, 2]: Logger.verbose = args['verbose'] else: Logger.showError("Invalid verbose argument.") else: Logger.verbose = 2 #Set source file source = args['input'] if not source.endswith(".xml"): Logger.showError("Input file not valid.") return #Set target language if args['language']: target_language = args['language'] else: target_language = "" #Set output file if args['output']: output = args['output'] else: output = os.path.splitext(os.path.split(source)[1])[0] #Set platform if args['platform']: args['platform'] = args['platform'].lower() if args['platform'] == "threads": platform = Platforms.Threads elif args['platform'] == "gameloop": platform = Platforms.GameLoop elif args['platform'] == "eventloop": platform = Platforms.EventLoop else: Logger.showError("Invalid platform.") return else: platform = Platforms.EventLoop #Compile try: generate(source, output, target_language, platform) except CompilerException as exception: Logger.showError(str(exception)) return 1 return 0
def __init__(self, input_file): diagram_dir = os.path.dirname(input_file) tree = ET.parse(input_file) self.root = tree.getroot() self.name = self.root.get("name", "") self.author = self.root.get("author", "") descriptions = self.root.findall("description") self.language = self.root.get("language", "") if descriptions : self.description = descriptions[0].text else : self.description = "" xml_classes = self.root.findall("class") # make sure at least one class is given if not xml_classes : raise CompilerException("Found no classes to compile.") # check if class diagram is valid # unique class names self.class_names = [] substituted_xml_classes = [] default_substituted_xml_classes = [] for xml_class in xml_classes : class_src = xml_class.get("src", "") class_default = xml_class.get("default", "") if class_src != "": if not os.path.isabs(class_src): class_src = os.path.join(diagram_dir, class_src) substituted_xml_class = ET.parse(class_src).getroot() else: substituted_xml_class = xml_class if class_default.lower() == "true": default_substituted_xml_classes.append(substituted_xml_class) name = substituted_xml_class.get("name", "") if name == "" : raise CompilerException("Missing or emtpy class name.") if name in self.class_names : raise CompilerException("Found 2 classes with the same name : " + name + ".") self.class_names.append(name) substituted_xml_classes.append(substituted_xml_class) # process in and output ports inports = self.root.findall("inport") names = [] for xml_inport in inports : name = xml_inport.get("name", "") if name in names : raise CompilerException("Found 2 INPorts with the same name : " + name + ".") names.append(name) self.inports = names outports = self.root.findall("outport") names = [] for xml_outport in outports : name = xml_outport.get("name", "") if name in names : raise CompilerException("Found 2 OUTPorts with the same name : " + name + ".") names.append(name) self.outports = names # any inital import code that has to come at the top of the generate file tops = self.root.findall("top") self.includes = [] if len(tops) == 1 : self.top = tops[0].text elif len(tops) > 1 : raise CompilerException("Class diagram can only have one <top> element.") else : self.top = "" # process each class in diagram self.classes = [] default_classes = [] for xml_class in substituted_xml_classes: processed_class = None try : processed_class = Class(xml_class, self) except CompilerException as e : e.message = "Class <" + xml_class.get("name", "") + "> failed compilation. " + e.message raise e # let user know this class was successfully loaded Logger.showInfo("Class <" + processed_class.name + "> has been successfully loaded.") self.classes.append(processed_class) if xml_class in default_substituted_xml_classes: default_classes.append(processed_class) if not default_classes or len(default_classes) > 1: if len(self.classes) == 1 : Logger.showInfo("Only one class given. Using <" + self.classes[0].getName() + "> as the default class.") default_classes.append(self.classes[0]) else : raise CompilerException("Provide one and only one default class to instantiate on start up.") self.default_class = default_classes[0] # check if there's a test self.test = None test_nodes = self.root.findall("test") if test_nodes: test_node = test_nodes[0] input_nodes = test_node.findall("input") if input_nodes: input_node = input_nodes[0] test_input = DiagramTestInput(input_node) else: test_input = None expected_nodes = test_node.findall("expected") if expected_nodes: expected_node = expected_nodes[0] test_expected = DiagramTestExpected(expected_node) else: test_expected = None self.test = DiagramTest(test_input, test_expected)
def generic_visit(self, node): Logger.showWarning( "GenericGenerator has no visit method for node of type '" + str(type(node)) + "'.")
def main(): mapper = SCCD_ASG_Mapper() parser = argparse.ArgumentParser() parser.add_argument('input', help='The path to the XML file to be compiled.') parser.add_argument( '-o', '--output', type=str, help= 'The path to the generated code. Defaults to the same name as the input file but with matching extension.' ) parser.add_argument( '-v', '--verbose', type=int, help= '2 = all output; 1 = only warnings and errors; 0 = only errors; -1 = no output. Defaults to 2.', default=2) parser.add_argument( '-p', '--platform', type=str, help= "Let the compiled code run on top of threads, gameloop or eventloop. The default is eventloop." ) parser.add_argument( '-l', '--language', type=str, help= 'Target language, either "javascript" or "python". Defaults to the latter.' ) #parser.add_argument('-m', '--mvklocation', type=str, help='Location in the Modelverse. After compilation the modelverse shell is opened.') parser.add_argument('-justxml', dest='justxml', action='store_true') parser.set_defaults(justxml=False) args = vars(parser.parse_args()) #Set verbose if args['verbose'] is not None: if args['verbose'] in [-1, 0, 1, 2]: Logger.verbose = args['verbose'] else: Logger.showError("Invalid verbose argument.") else: Logger.verbose = 2 #Set source file source = args['input'].lower() if not source.endswith(".sccd"): Logger.showError("Input file not valid.") return #Set target language if args['language']: target_language = args['language'] else: target_language = "" #Set output file if args['output']: output = args['output'] else: output = os.path.splitext(os.path.split(source)[1])[0] #Set platform if args['platform']: args['platform'] = args['platform'].lower() if args['platform'] == "threads": platform = Platforms.Threads elif args['platform'] == "gameloop": platform = Platforms.GameLoop elif args['platform'] == "eventloop": platform = Platforms.EventLoop else: Logger.showError("Invalid platform.") return else: platform = Platforms.Threads mvklocation = 'unused_location' """ if args['mvklocation'] : mvklocation = args['mvklocation'] modelverseshell = True else: mvklocation = 'temporaryLocation' modelverseshell = False """ if args['justxml']: try: generate(output + '.xml', output, target_language, platform) except CompilerException as exception: Logger.showError(str(exception)) return context = MvKLoader(mapper.rules, mapper.metamodel_location, mapper.metamodel_path, mvklocation).load(source) if (target_language == "javascript"): compiler = SCCD_to_XML(XML2JavaScriptRules().rules, context.mvk) else: compiler = SCCD_to_XML(XML2PythonRules().rules, context.mvk) compiler.compile(context.target + '.' + context.modelname) if os.path.exists(output + '.xml'): os.remove(output + '.xml') compiler.outputTo(output + '.xml') #Compile try: generate(output + '.xml', output, target_language, platform) except CompilerException as exception: Logger.showError(str(exception)) """