from hutn_compiler.visitor import Visitor from hutn_compiler.compiler import main as do_compile from hutn_compiler.hutnparser import Tree import os def empty(s): return None class ModelVisitor(Visitor): def __init__(self, args): Visitor.__init__(self, args) self.constructors = [] self.free_id = 0 self.names = set() self.current_element = [] self.includes = [] def dump(self): return [len(self.constructors)] + self.constructors 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) def visit_include_files(self, tree): self.includes.append('include %s' % Tree.get_text(Tree.get_children(tree, "STRVALUE")[0])) 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", element_type, element_name, source_name, target_name]) else: self.constructors.extend(["instantiate_node", 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", "Inheritance", "%s_inherits_from_%s" % (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]) if attr_type not in self.names: raise Exception("Unknown Attribute type!") self.constructors.extend(["model_define_attribute", 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", contains_link, "__%s" % 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 + [code] 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 = Tree.get_text(attr_value)[1:-1] elif attr_value['head'] == "LONG_STR": attr_value = Tree.get_text(attr_value)[3:-3] 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_element[-1], attr_name, attr_value]) elif Tree.get_children(tree, "DOLLAR"): # Coded attribute self.constructors.extend(["instantiate_attribute_code", self.current_element[-1], attr_name]) self.constructors.extend(constructors_compile(Tree.get_text(Tree.get_children(tree, "ANYTHING_EXCEPT_DOLLAR")[0])))