import cPickle as pickle from visitor import Visitor class ConstructorsVisitor(Visitor): def __init__(self, args): Visitor.__init__(self, args) self.constructors = [] self.free_id = 0 def dump(self): return self.constructors # return pickle.dumps(self.constructors, pickle.HIGHEST_PROTOCOL) # return '\n'.join([repr(x) for x in self.constructors]) def add_constructors(self, *constructors): self.constructors.extend(constructors) # a visit_* method for each non-terminal in the grammar def visit_start(self, tree): # declare all functions for child in tree.get_children("funcdecl"): if self.pre_visit_funcdecl(child): self.add_constructors(True) tail = tree.get_tail_without(["newline"]) # tail = tree.get_children("funcdecl") +\ # tree.get_tail_without(["newline", "funcdecl"]) last = tail[-1] for child in tail[:-1]: if child.head == "return": last = child break else: # funcdecl may add no constructors new_constructors_were_added = self.visit(child) if child.head == "func_call": # pop 'false' self.constructors.pop() if new_constructors_were_added: self.add_constructors(True) new_constructors_were_added = self.visit(last) if last.head == "func_call": # pop 'false' self.constructors.pop() if new_constructors_were_added: if last.head != "return": self.add_constructors(False) elif self.constructors: self.constructors.pop() # pop 'true' self.add_constructors(False) def declare(self, symbol): if symbol.is_global: symbol.node = symbol.name self.add_constructors("global", symbol.node) else: symbol.node = str(self.free_id) self.add_constructors("declare", symbol.node) self.free_id += 1 def visit_vardecl(self, tree): symbol = self.get_symbol(tree) self.declare(symbol) return True def visit_assignment(self, tree): self.add_constructors("assign") self.visit(tree.get_tail()[0]) self.visit(tree.get_tail()[2]) return True def visit_expression(self, tree): self.visit_children(tree) def visit_binary_operation(self, tree): self.visit_children(tree) def visit_disjunction(self, tree): self.visit_children(tree) def visit_conjunction(self, tree): self.visit_children(tree) def visit_comparison(self, tree): self.visit_children(tree) def visit_relation(self, tree): self.visit_children(tree) def visit_sum(self, tree): self.visit_children(tree) def visit_term(self, tree): self.visit_children(tree) def visit_factor(self, tree): self.visit_children(tree) def visit_primary(self, tree): self.visit_children(tree) def visit_parenthesized(self, tree): self.visit_children(tree) def visit_atomvalue(self, tree): self.visit_children(tree) def visit_type_specifier(self, tree): self.add_constructors("const", {"value": tree.get_text()}) def visit_actionname(self, tree): self.add_constructors("const", {"value": tree.get_tail()[0].get_text()[1:]}) def visit_string(self, tree): self.add_constructors("const", tree.get_text()[1:-1]) def visit_integer(self, tree): self.add_constructors("const", int(tree.get_text())) def visit_float(self, tree): self.add_constructors("const", float(tree.get_text())) def visit_rvalue(self, tree): self.add_constructors("access") self.visit_lvalue(tree) def visit_lvalue(self, tree): symbol = self.get_symbol(tree) # TODO: split visit_funcdecl in pre_visit_funcdecl and visit_funcdecl if symbol.node is None: raise Exception("Undefined variable: %s" % (symbol.name)) self.add_constructors("resolve", symbol.node) def visit_func_call(self, tree): symbol = self.get_symbol(tree.get_tail()[0]) self.add_constructors("call") if hasattr(symbol, "pathmv"): self.add_constructors("deref", symbol.pathmv) else: self.visit(tree.get_tail()[0]) expressions = tree.get_children("expression") self.add_constructors(len(expressions)) for expression in expressions: self.visit(expression) self.add_constructors(False) return True def visit_input(self, tree): self.add_constructors("input") return True def visit_output(self, tree): self.add_constructors("output") self.visit(tree.get_child("expression")) return True def visit_dictionary(self, tree): pass # TODO: list and dictionary def visit_list(self, tree): pass # TODO: list and dictionary def visit_dict_item(self, tree): pass # TODO: list and dictionary def visit_ifelse(self, tree): self.add_constructors("if") expressions = tree.get_children("expression") blocks = tree.get_children("block") self.visit(expressions[0]) # condition self.visit(blocks[0]) # then-clause for e, b in zip(expressions[1:], blocks[1:]): self.add_constructors(True, "if") # else-if-clause self.visit(e) self.visit(b) if len(expressions) != len(blocks): self.add_constructors(True) # else-clause self.visit(blocks[-1]) else: self.add_constructors(False) # no else_clause for i in range(len(expressions)-1): self.add_constructors(False) # no next return True def visit_while(self, tree): self.add_constructors("while") self.visit(tree.get_child("expression")) self.visit(tree.get_child("block")) return True def visit_block(self, tree): tail = tree.get_tail_without(["newline", "indent"]) last = tail[-1] for child in tail[:-1]: if child.head == "return": last = child break else: self.visit(child) if child.head == "func_call": # pop 'false' self.constructors.pop() self.add_constructors(True) self.visit(last) if last.head == "func_call": # pop 'false' self.constructors.pop() if last.head != "return": self.add_constructors(False) def visit_func_body(self, tree): self.visit_children(tree) def pre_visit_funcdecl(self, tree): func_body = tree.get_child("func_body") symbol = self.get_symbol(tree) symbol.node = symbol.name return False def visit_funcdecl(self, tree): func_body = tree.get_child("func_body") symbol = self.get_symbol(tree) if func_body: if symbol.name in ["input", "output"]: return False self.add_constructors("funcdef", symbol.node, len(symbol.params)) for p in tree.get_children("parameter"): self.visit(p) self.visit(func_body) return True elif tree.get_child("ASSIGN"): # TODO: fix funcdecl special case: "X function f(...) = ..." # Note: replicates "Element x; x = ?primiteves/a" behavior # Dangerous: SemanticsVisitor handles it as a function # pathmv is needed in visit_func_call(self, tree) symbol.pathmv = tree.get_child("ANYTHING").get_text() self.add_constructors("global", symbol.node, "deref", symbol.pathmv) # reason: "X function f(Y) = Z" adds no constructors return True else: # Just a declaration, so skip return False def visit_parameter(self, tree): symbol = self.get_symbol(tree) symbol.node = str(self.free_id) self.add_constructors(symbol.node) self.free_id += 1 def visit_return(self, tree): self.add_constructors("return") if len(tree.get_tail()) > 2: self.add_constructors(True) self.visit(tree.get_tail()[1]) else: self.add_constructors(False) return True def visit_bool(self, tree): if tree.get_text() == "True": self.add_constructors("const", True) else: self.add_constructors("const", False) def visit_definition(self, tree): # First declare it symbol = self.get_symbol(tree) symbol.node = symbol.name # Now generate constructors self.add_constructors("global", symbol.name) # Determine whether it is just a constant, or a deref atom = tree.get_child("atomvalue") if atom.get_child("deref"): # Deref dest = atom.get_child("deref").get_child("ANYTHING") if dest is None: # Just an empty questionmark! self.add_constructors("empty") else: self.add_constructors("deref", dest.get_text()) else: # Constant self.visit(atom) return True