import string from visitor import Visitor import json class Action(): def __init__(self, value): self.value = value class PrimitivesVisitor(Visitor): def __init__(self, args): Visitor.__init__(self, args) self.output = [] self.free_id = 0 self.function_values = dict() self.debug_symbols = "--debug" in args def debug(self, node, tree, msg=""): if self.debug_symbols: self.dict(node, "__debug", self.value("[%s] %s" % (tree.get_reference_line(), msg))) def node(self): self.output.append(("N", self.free_id)) self.free_id += 1 return self.free_id - 1 def dict(self, src, val, trgt): if src is None or trgt is None: raise Exception("Got None") self.output.append(("D", (src, json.dumps(val), trgt))) def value(self, value): if isinstance(value, Action): v = value.value else: v = json.dumps(value) self.output.append(("V", (self.free_id, v))) self.free_id += 1 return self.free_id - 1 def edge(self, source, target): self.output.append(("E", (self.free_id, source, target))) self.free_id += 1 return self.free_id - 1 def dump(self): output = [] for t, data in self.output: if t == "N": output.append("N auto_%s\n" % data) elif t == "V": name, value = data name = name if self.first != name else "initial_IP" output.append("V auto_%s(%s)\n" % (name, value)) elif t == "D": source, value, target = data source = source if self.first != source else "auto_initial_IP" target = target if self.first != target else "auto_initial_IP" source = "auto_%s" % source if isinstance(source, int) else source target = "auto_%s" % target if isinstance(target, int) else target output.append("D %s,%s,%s\n" % (source, value, target)) elif t == "E": name, source, target = data source = source if self.first != source else "auto_initial_IP" target = target if self.first != target else "auto_initial_IP" name = "auto_%s" % name if isinstance(name, int) else name source = "auto_%s" % source if isinstance(source, int) else source target = "auto_%s" % target if isinstance(target, int) else target output.append("E %s(%s,%s)\n" % (name, source, target)) return "".join(output) def set_primitive(self, tree, primitive): tree.primitive = primitive def get_primitive(self, tree): return getattr(tree, 'primitive', None) def forward_primitive_of_child(self, tree, i): self.visit_children(tree) self.set_primitive(tree, self.get_primitive(tree.get_tail()[i])) # a visit_* method for each non-terminal in the grammar def visit_start(self, tree): primitives = [] for child in tree.get_children("funcdecl"): p = self.pre_visit_funcdecl(child) if p: # funcdecl returns a (global, assign) pair primitives.extend(p) for child in tree.get_tail(): self.visit(child) p = self.get_primitive(child) if p is not None: if type(p) in (list, tuple): # funcdecl returns a (global, assign) pair primitives.extend(p) else: primitives.append(p) if child.head == "return": break self.first = primitives[0] for i in range(len(primitives)-1): self.dict(primitives[i], "next", primitives[i+1]) self.last_instruction = primitives[-1] def visit_vardecl(self, tree): symbol = self.get_symbol(tree) if symbol.is_global: d = self.value(Action("global")) n = self.value(symbol.name) else: d = self.value(Action("declare")) n = self.node() symbol.node = n self.dict(d, "var", n) self.debug(d, tree) self.set_primitive(tree, d) def visit_assignment(self, tree): self.visit_children(tree) a = self.value(Action("assign")) var = self.get_primitive(tree.get_tail()[0]) value = self.get_primitive(tree.get_tail()[-1]) self.dict(a, "var", var) self.dict(a, "value", value) self.debug(a, tree) self.set_primitive(tree, a) def visit_expression(self, tree): self.forward_primitive_of_child(tree, 0) def visit_binary_operation(self, tree): self.forward_primitive_of_child(tree, 0) def visit_disjunction(self, tree): self.forward_primitive_of_child(tree, 0) def visit_conjunction(self, tree): self.forward_primitive_of_child(tree, 0) def visit_comparison(self, tree): self.forward_primitive_of_child(tree, 0) def visit_relation(self, tree): self.forward_primitive_of_child(tree, 0) def visit_sum(self, tree): self.forward_primitive_of_child(tree, 0) def visit_term(self, tree): self.forward_primitive_of_child(tree, 0) def visit_factor(self, tree): self.forward_primitive_of_child(tree, 0) def visit_primary(self, tree): self.forward_primitive_of_child(tree, 0) def visit_parenthesized(self, tree): self.forward_primitive_of_child(tree, 1) def visit_atomvalue(self, tree): self.forward_primitive_of_child(tree, 0) def visit_type_specifier(self, tree): self.visit_literal(tree) def visit_actionname(self, tree): self.visit_literal(tree.get_tail()[0]) self.set_primitive(tree, self.get_primitive(tree.get_tail()[0])) def visit_string(self, tree): self.visit_literal(tree) # there is no such rule in the grammar, we just avoid code duplicates def visit_literal(self, tree): # TODO dictionary and list # if self.no_constant: # n = self.new_value(tree.get_text()) # self.set_id(tree, n) # else: c = self.value(Action("constant")) if tree.get_text()[0] == "!": v = tree.get_text()[1:] else: v = tree.get_text() #NOTE Wrap this in an Action, even though it might not be an action: this has to be seen directly in the Mv without additional wrapping n = self.value(Action(v)) self.dict(c, "node", n) self.debug(c, tree) self.set_primitive(tree, c) def visit_integer(self, tree): self.visit_literal(tree) def visit_float(self, tree): self.visit_literal(tree) def visit_rvalue(self, tree): self.visit_lvalue(tree) r = self.get_primitive(tree) if r is None: return a = self.value(Action("access")) self.dict(a, "var", r) self.debug(a, tree) self.set_primitive(tree, a) def visit_lvalue(self, tree): symbol = self.get_symbol(tree) if symbol.name in ["input", "output"]: return r = self.value(Action("resolve")) # print symbol.name, symbol.is_func(), symbol.node self.dict(r, "var", symbol.node) self.debug(r, tree) self.set_primitive(tree, r) def visit_func_call(self, tree): self.visit_children(tree) symbol = self.get_symbol(tree.get_tail()[0]) expressions = tree.get_children("expression") arg_nodes_reversed = [] for i in reversed(range(len(expressions))): arg_name = string.ascii_lowercase[i] arg_node = self.node() name_node = self.value(arg_name) self.dict(arg_node, "name", name_node) # print expressions[i].get_text() value_node = self.get_primitive(expressions[i]) self.dict(arg_node, "value", value_node) if arg_nodes_reversed: next_node = arg_nodes_reversed[-1] self.dict(arg_node, "next_param", next_node) arg_nodes_reversed.append(arg_node) c = self.value(Action("call")) a = self.get_primitive(tree.get_tail()[0]) self.dict(c, "func", a) self.debug(c, tree) if arg_nodes_reversed: self.dict(c, "params", arg_nodes_reversed[-1]) self.dict(c, "last_param", arg_nodes_reversed[0]) self.set_primitive(tree, c) def visit_input(self, tree): self.visit_children(tree) v = self.value(Action("input")) self.debug(v, tree) self.set_primitive(tree, v) def visit_output(self, tree): self.visit_children(tree) v = self.value(Action("output")) self.debug(v, tree) value = self.get_primitive(tree.get_child("expression")) self.dict(v, "value", value) self.set_primitive(tree, v) def visit_ifelse(self, tree): self.visit_children(tree) expressions = [self.get_primitive(e) for e in tree.get_children("expression")] blocks = [self.get_primitive(b) for b in tree.get_children("block")] first = None prev = None for e, b in zip(expressions, blocks): v = self.value(Action("if")) self.debug(v, tree) if first is None: first = v self.dict(v, "cond", e) self.dict(v, "then", b) if prev: self.dict(prev, "else", v) prev = v if len(expressions) != len(blocks): self.dict(prev, "else", blocks[-1]) self.set_primitive(tree, first) def visit_while(self, tree): self.visit_children(tree) w = self.value(Action("while")) self.debug(w, tree) c = self.get_primitive(tree.get_child("expression")) b = self.get_primitive(tree.get_child("block")) self.dict(w, "cond", c) self.dict(w, "body", b) self.set_primitive(tree, w) def visit_block(self, tree): self.visit_children(tree) primitives = [] for child in tree.get_tail(): p = self.get_primitive(child) if p: primitives.append(p) if child.head == "return": break for i in range(len(primitives)-1): self.dict(primitives[i], "next", primitives[i+1]) self.set_primitive(tree, primitives[0]) def visit_func_body(self, tree): self.forward_primitive_of_child(tree, 0) def pre_visit_funcdecl(self, tree): symbol = self.get_symbol(tree) if symbol.name in ["input", "output"]: return # TODO: fix funcdecl special case: "X function f(...) = ..." # Note: replicates "Element x; x = ?primiteves/a" behavior # Dangerous: SemanticsVisitor handles it as a function if not tree.get_child("func_body"): return new_value = self.node() self.function_values[symbol.name] = new_value root = self.value(symbol.name) symbol.node = root declare = self.value(Action("global")) self.dict(declare, "var", root) resolve = self.value(Action("resolve")) self.dict(resolve, "var", root) assign = self.value(Action("assign")) self.dict(assign, "var", resolve) const = self.value(Action("constant")) self.dict(const, "node", new_value) self.dict(assign, "value", const) return declare, assign def visit_funcdecl(self, tree): symbol = self.get_symbol(tree) if symbol.name in ["input", "output"]: return func_body = tree.get_child("func_body") if func_body: self.visit_children(tree) vf = self.function_values[symbol.name] parameters = tree.get_children("parameter") if parameters: ps = self.node() self.dict(vf, "params", ps) for i in range(len(parameters)): n = self.get_primitive(parameters[i]) self.dict(ps, string.ascii_lowercase[i], n) # Add the name in case we want to pre-compile in the MvK self.dict(n, "name", self.value(string.ascii_lowercase[i])) b = self.get_primitive(func_body) self.dict(vf, "body", b) else: # TODO: fix funcdecl special case: "X function f(...) = ..." # Note: replicates "Element x; x = ?primiteves/a" behavior # Dangerous: SemanticsVisitor handles it as a function root = self.value(symbol.name) symbol.node = root if tree.get_child("ASSIGN"): new_value = "?" + tree.get_child("ANYTHING").get_text() elif tree.get_child("ASSIGN") and not tree.get_child("ANYTHING"): new_value = self.node() else: return declare = self.value(Action("global")) self.dict(declare, "var", root) self.debug(declare, tree) resolve = self.value(Action("resolve")) self.dict(resolve, "var", root) assign = self.value(Action("assign")) self.dict(assign, "var", resolve) const = self.value(Action("constant")) self.dict(const, "node", new_value) self.dict(assign, "value", const) self.set_primitive(tree, (declare, assign)) def visit_definition(self, tree): symbol = self.get_symbol(tree) root = self.value(symbol.name) declare = self.value(Action("global")) self.dict(declare, "var", root) self.debug(declare, tree) symbol.node = root resolve = self.value(Action("resolve")) self.dict(resolve, "var", root) assign = self.value(Action("assign")) self.dict(assign, "var", resolve) self.visit_atomvalue(tree.get_tail()[-1]) value = self.get_primitive(tree.get_tail()[-1]) if value is None: call = self.value(Action("call")) access = self.value(Action("access")) resolve = self.value(Action("resolve")) self.dict(call, "func", access) self.dict(access, "var", resolve) self.dict(resolve, "var", self.value("create_node")) value = call self.dict(assign, "value", value) self.set_primitive(tree, (declare, assign)) def visit_parameter(self, tree): n = self.node() symbol = self.get_symbol(tree) symbol.node = n self.set_primitive(tree, n) def visit_return(self, tree): self.visit_children(tree) r = self.value(Action("return")) self.debug(r, tree) if len(tree.get_tail()) > 2: v = self.get_primitive(tree.get_tail()[1]) self.dict(r, "value", v) self.set_primitive(tree, r) def visit_bool(self, tree): self.visit_literal(tree)