from hutn_compiler.visitor import Visitor from hutn_compiler.hutnparser import Tree from hutn_compiler.compiler import main as do_compile import os import uuid def empty(s): return None class ModelBootstrapVisitor(Visitor): def __init__(self, args): Visitor.__init__(self, args) model_name = [arg.split(":", 1)[1] for arg in args if arg.startswith("--modelname:")][0] self.code = "Void function initialize_%s():\n" % model_name self.free_id = 0 self.names = set() self.current_model = None self.current_element = [] self.includes = [] def dump(self): return self.code + "\treturn!" def __getattr__(self, attr): if attr.startswith("visit_"): return empty else: raise AttributeError() def visit_start(self, tree): for t in Tree.get_tail(tree): self.visit(t) self.code += '\tdict_overwrite(%s, "types", get_type_mapping(%s))\n' % (self.current_model, self.current_model) def visit_include_files(self, tree): self.includes.append('include %s' % Tree.get_text(Tree.get_children(tree, "STRVALUE")[0])) def visit_import(self, tree): url = Tree.get_children(tree, "MV_URL")[0] target = Tree.get_children(tree, "MODEL_ID")[0] #self.constructors.extend(["import_node", url.get_text(), target.get_text()]) self.code += '\tElement %s\n' % Tree.get_text(target) self.code += '\t%s = import_node("%s")\n' % (Tree.get_text(target), Tree.get_text(url)) def visit_export(self, tree): url = Tree.get_children(tree, "MV_URL")[0] target = Tree.get_children(tree, "MODEL_ID")[0] #self.constructors.extend(["export_node", target.get_text(), url.get_text()]) self.code += '\texport_node("%s", %s)\n' % (Tree.get_text(url), Tree.get_text(target)) def visit_model(self, tree): children = Tree.get_children(tree, "MODEL_ID") model_type = Tree.get_text(children[0]) model_name = Tree.get_text(children[-1]) #self.constructors.extend(["instantiate_model", model_type, model_name]) self.code += "\tElement %s\n" % model_name self.code += '\t%s = instantiate_model(%s)\n' % (model_name, model_type) self.current_model = model_name self.names = set() for element in Tree.get_children(tree, "model_element"): self.visit(element) def visit_model_element(self, tree): children = Tree.get_children(tree, "MODEL_ID") element_type = Tree.get_text(children[0]) if len(children) == 2 or len(children) == 4: element_name = Tree.get_text(children[1]) else: element_name = "__%s" % self.free_id self.free_id += 1 if element_name in self.names: raise Exception("Redefinition of element %s" % element_name) 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 = Tree.get_text(children[-2]) target_name = Tree.get_text(children[-1]) if source_name not in self.names: raise Exception("Source of link %s unknown: %s" % (element_name, source_name)) if target_name not in self.names: raise Exception("Target of link %s unknown: %s" % (element_name, target_name)) #self.constructors.extend(["instantiate_link", self.current_model, element_type, element_name, source_name, target_name]) self.code += '\tinstantiate_link(%s, "%s", "%s", "%s", "%s")\n' % (self.current_model, element_type, element_name, source_name, target_name) else: #self.constructors.extend(["instantiate_node", self.current_model, element_type, element_name]) self.code += '\tinstantiate_node(%s, "%s", "%s")\n' % (self.current_model, element_type, element_name) self.names.add(element_name) self.current_element.append(element_name) if Tree.get_children(tree, "inheritance"): self.visit(Tree.get_children(tree, "inheritance")[0]) for attr in Tree.get_children(tree, "model_attribute"): self.visit(attr) self.current_element.pop() return element_name def visit_inheritance(self, tree): for token in Tree.get_children(tree, "MODEL_ID"): superclass = Tree.get_text(token) if superclass not in self.names: raise Exception("Superclass %s is undefined" % superclass) #self.constructors.extend(["instantiate_link", self.current_model, "Inheritance", "%s_inherits_from_%s" % (self.current_element[-1], superclass), self.current_element[-1], superclass]) self.code += '\tinstantiate_link(%s, "Inheritance", "%s_inherits_from_%s", "%s", "%s")\n' % (self.current_model, self.current_element[-1], superclass, self.current_element[-1], superclass) self.names.add("%s_inherits_from_%s" % (self.current_element[-1], superclass)) def visit_model_attribute(self, tree): children = Tree.get_children(tree, "MODEL_ID") is_definition = bool(Tree.get_children(tree, "COLON")) is_assign = bool(Tree.get_children(tree, "model_attr_instance")) is_nested = bool(Tree.get_children(tree, "model_element")) if is_definition: attr_name = Tree.get_text(children[0]) attr_optional = len(Tree.get_children(tree, "OPTIONAL")) > 0 attr_type = Tree.get_text(children[1]) #self.constructors.extend(["model_define_attribute", self.current_model, self.current_element[-1], attr_name, attr_optional, attr_type]) self.code += '\tmodel_define_attribute(%s, "%s", "%s", %s, "%s")\n' % (self.current_model, self.current_element[-1], attr_name, attr_optional, attr_type) full_attribute_name = self.current_element[-1] + "_" + attr_name if is_assign: # There are also some attributes to set! self.current_element.append(full_attribute_name) for f in Tree.get_children(tree, "model_attr_instance"): self.visit(f) self.current_element.pop() elif is_assign: self.visit(Tree.get_children(tree, "model_attr_instance")[0]) elif is_nested: if Tree.get_children(tree, "MODEL_ID"): contains_link = Tree.get_text(Tree.get_children(tree, "MODEL_ID")[0]) else: contains_link = "" entry = self.visit(Tree.get_children(tree, "model_element")[0]) #self.constructors.extend(["instantiate_link", self.current_model, contains_link, "__%s" % self.free_id, self.current_element[-1], entry]) self.code += '\tinstantiate_link(%s, "%s", "__%s", "%s", "%s")\n' % (self.current_model, contains_link, self.free_id, self.current_element[-1], entry) self.names.add("__%s" % self.free_id) self.free_id += 1 def visit_model_attr_instance(self, tree): def constructors_compile(code): code_fragments = code.split("\n") code_fragments = [i for i in code_fragments if i.strip() != ""] code_fragments = [i.replace(" ", "\t") for i in code_fragments] initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments]) code_fragments = self.includes + [i[initial_tabs:] for i in code_fragments] code = "\n".join(code_fragments) code += "\n" with open(".code.alc", 'w') as f: f.write(code) f.flush() directory = os.path.realpath(__file__).rsplit(os.sep, 1)[0] compiled = do_compile(".code.alc", directory + "/../grammars/actionlanguage.g", "CS") return compiled children = Tree.get_children(tree, "MODEL_ID") attr_name = Tree.get_text(children[0]) if Tree.get_children(tree, "value"): # Value attribute attr_value = Tree.get_tail(Tree.get_children(tree, "value")[0])[0] if attr_value['head'] == "STRVALUE": attr_value = '"%s"' % Tree.get_text(attr_value)[1:-1] elif attr_value['head'] == "TRUE": attr_value = True elif attr_value['head'] == "FALSE": attr_value = False elif attr_value['head'] == "DEC_NUMBER": attr_value = int(Tree.get_text(attr_value)) elif attr_value.head == "FLOAT_NUMBER": attr_value = float(Tree.get_text(attr_value)) else: raise Exception(attr_value['head']) #self.constructors.extend(["instantiate_attribute", self.current_model, self.current_element[-1], attr_name, attr_value]) self.code += '\tinstantiate_attribute(%s, "%s", "%s", %s)\n' % (self.current_model, self.current_element[-1], attr_name, attr_value) elif Tree.get_children(tree, "DOLLAR"): # Coded attribute raise Exception("Code is no longer allowed in bootstrap files, as the HUTN parser is not initialized yet") #self.constructors.extend(["instantiate_attribute_code", self.current_model, self.current_element[-1], attr_name]) #self.constructors.extend(constructors_compile(tree.get_children("ANYTHING_EXCEPT_DOLLAR")[0].get_text())) code = Tree.get_text(Tree.get_children(tree, "ANYTHING_EXCEPT_DOLLAR")[0]) code_fragments = code.split("\n") code_fragments = [i for i in code_fragments if i.strip() != ""] code_fragments = [i.replace(" ", "\t") for i in code_fragments] initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments]) code_fragments = [i[initial_tabs:] for i in code_fragments] code_fragments.append("") code = "\n".join(code_fragments) func_name = "__code__%s" % abs(hash(code)) self.code += '\tinstantiate_attribute_code(%s, "%s", "%s", %s)\n' % (self.current_model, self.current_element[-1], attr_name, func_name) # Rewrite the name of the function to func_name prepend = code before, after = prepend.split("function ", 1) before = before + "function " after = "(" + after.split("(", 1)[1] prepend = before + func_name + after + "\n" # And prepend the actual code block self.code = prepend + self.code