from visitor import Visitor from compiler import main as do_compile import os def jsonstr(s): return '"%s"' % s def empty(s): return None class ModelVisitor(Visitor): def __init__(self, args): Visitor.__init__(self, args) self.constructors = [] self.free_id = 0 self.name_maps = {} self.current_model = None self.current_element = None self.includes = [] def dump(self): print(self.constructors) return self.constructors def __getattr__(self, attr): if attr.startswith("visit_"): return empty else: raise AttributeError() def visit_start(self, tree): self.constructors.append('"model"') for t in tree.get_tail(): self.visit(t) self.constructors.append('"exit"') def visit_include_files(self, tree): self.includes.append(tree.get_children("STRVALUE")[0].get_text()) def visit_import(self, tree): url = tree.get_children("MV_URL")[0] target = tree.get_children("MODEL_ID")[0] self.constructors.extend(['"import_node"', jsonstr(url.get_text()), jsonstr(target.get_text())]) def visit_export(self, tree): url = tree.get_children("MV_URL")[0] target = tree.get_children("MODEL_ID")[0] self.constructors.extend(['"export_node"', jsonstr(target.get_text()), jsonstr(url.get_text())]) def visit_model(self, tree): children = tree.get_children("MODEL_ID") model_type = children[0].get_text() model_name = children[1].get_text() self.constructors.extend(['"instantiate_model"', jsonstr(model_type), jsonstr(model_name)]) self.constructors.extend(['"define_inheritance"', jsonstr(model_name), jsonstr("Inheritance")]) self.current_model = model_name for element in tree.get_children("model_element"): self.visit(element) def visit_model_element(self, tree): children = tree.get_children("MODEL_ID") element_type = children[0].get_text() if len(children) == 2 or len(children) == 4: element_name = children[1].get_text() else: element_name = "__%s" % self.free_id self.free_id += 1 if len(children) > 2: # So we have a source and target; but aren't sure which is which, because the name is optional! source_name = children[-2].get_text() target_name = children[-1].get_text() self.constructors.extend(['"instantiate_link"', jsonstr(self.current_model), jsonstr(element_type), jsonstr(element_name), jsonstr(source_name), jsonstr(target_name)]) else: self.constructors.extend(['"instantiate_node"', jsonstr(self.current_model), jsonstr(element_type), jsonstr(element_name)]) self.current_element = element_name for attr in tree.get_children("model_attribute"): self.visit(attr) def visit_model_attribute(self, tree): children = tree.get_children("MODEL_ID") is_definition = bool(tree.get_children("COLON")) is_constraint = bool(tree.get_children("DOLLAR")) is_assign = bool(tree.get_children("ASSIGN")) if is_definition: attr_name = children[0].get_text() attr_type = children[1].get_text() self.constructors.extend(['"instantiate_link"', jsonstr(self.current_model), jsonstr("Association"), jsonstr(self.current_element + "_" + attr_name), jsonstr(self.current_element), jsonstr(attr_type)]) self.constructors.extend(['"instantiate_attribute"', jsonstr(self.current_model), jsonstr(self.current_element + "_" + attr_name), jsonstr("name"), jsonstr(attr_name)]) elif is_assign: attr_name = children[0].get_text() attr_value = tree.get_children("value")[0] self.constructors.extend(['"instantiate_attribute"', jsonstr(self.current_model), jsonstr(self.current_element), jsonstr(attr_name), jsonstr(attr_value.get_text()) if attr_value.head == "STRVALUE" else attr_value.get_text()]) elif is_constraint: constraint = tree.get_children("ANYTHING_EXCEPT_DOLLAR")[0].get_text() whitespaces = len(constraint) - len(constraint.lstrip()) constraint = "\n".join(["\t" + line[whitespaces-1:].replace(" ", "\t") for line in constraint.split("\n") if len(line.strip()) != 0]) constraint = "".join(["include %s\n" % i for i in self.includes]) + \ "String function constraint(model : Element, element : String):\n" + \ "\tElement self\n" + \ '\tself = model["model"][element]\n' + \ constraint + "\n" with open(".constraint.alc", 'w') as f: f.write(constraint) f.flush() directory = os.path.realpath(__file__).rsplit(os.sep, 1)[0] self.constructors.extend(['"add_constraint"', jsonstr(self.current_model), jsonstr(self.current_element)] + do_compile(".constraint.alc", directory + "/../grammars/actionlanguage.g", "CS"))