| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- from hutn_compiler.visitor import Visitor
- from hutn_compiler.hutnparser import Tree
- class ConstructorsVisitor(Visitor):
- def __init__(self, args):
- Visitor.__init__(self, args)
- self.constructors = []
- self.free_id = 0
- def dump(self):
- return [len(self.constructors)] + 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(tree, "funcdecl"):
- if self.pre_visit_funcdecl(child):
- self.add_constructors(True)
- tail = Tree.get_tail_without(tree, ["newline"])
- last = tail[-1]
- for child in tail[:-1]:
- if child['head'] in ["return", "break", "continue"]:
- 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'] not in ["return", "break", "continue"]:
- 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_assignment(self, tree):
- self.add_constructors("assign")
- self.visit(Tree.get_tail(tree)[0])
- self.visit(Tree.get_tail(tree)[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(tree)})
- def visit_actionname(self, tree):
- self.add_constructors("const", {"value": Tree.get_text(Tree.get_tail(tree)[0])[1:]})
- def visit_string(self, tree):
- v = Tree.get_text(tree)[1:-1]
- v = v.replace("\\n", "\n")
- v = v.replace("\\t", "\t")
- v = v.replace("\\\"", "\"")
- self.add_constructors("const", v)
- def visit_integer(self, tree):
- self.add_constructors("const", int(Tree.get_text(tree)))
- def visit_float(self, tree):
- self.add_constructors("const", float(Tree.get_text(tree)))
- 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(tree)[0])
- self.add_constructors("call")
- if "pathmv" in symbol:
- self.add_constructors("deref", symbol['pathmv'])
- else:
- self.visit(Tree.get_tail(tree)[0])
- expressions = Tree.get_children(tree, "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(tree, "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(tree, "expression")
- blocks = Tree.get_children(tree, "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(tree, "expression"))
- self.visit(Tree.get_child(tree, "block"))
- return True
- def visit_block(self, tree):
- tail = Tree.get_tail_without(tree, ["newline", "indent"])
- last = tail[-1]
- for child in tail[:-1]:
- if child['head'] in ["return", "break", "continue"]:
- 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'] not in ["return", "break", "continue"]:
- 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(tree, "func_body")
- symbol = self.get_symbol(tree)
- symbol['node'] = symbol['name']
- return False
- def visit_funcdecl(self, tree):
- func_body = Tree.get_child(tree, "func_body")
- symbol = self.get_symbol(tree)
- if func_body:
- if symbol['name'] in ["input", "output"]:
- return False
- if Tree.get_children(tree, "MUTABLE"):
- self.add_constructors("mutable_funcdef")
- else:
- self.add_constructors("funcdef")
- self.add_constructors(symbol['node'],
- len(symbol['params']))
- for p in Tree.get_children(tree, "parameter"):
- self.visit(p)
- self.visit(func_body)
- return True
- elif Tree.get_child(tree, "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_text(Tree.get_child(tree, "ANYTHING"))
- 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_continue(self, tree):
- self.add_constructors("continue")
- return True
- def visit_break(self, tree):
- self.add_constructors("break")
- return True
-
- def visit_return(self, tree):
- self.add_constructors("return")
- if len(Tree.get_tail(tree)) > 2:
- self.add_constructors(True)
- self.visit(Tree.get_tail(tree)[1])
- else:
- self.add_constructors(False)
- return True
- def visit_bool(self, tree):
- if Tree.get_text(tree) == "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)
- self.declare(symbol)
- if Tree.get_children(tree, "ASSIGN"):
- # Determine whether it is just a constant, or a deref
- atom = Tree.get_child(tree, "atomvalue")
- if Tree.get_child(atom, "deref"):
- # Deref
- dest = Tree.get_child(Tree.get_child(atom, "deref"), "ANYTHING")
- if dest is None:
- # Just an empty questionmark!
- self.add_constructors("empty")
- else:
- self.add_constructors("deref", Tree.get_text(dest))
- else:
- # Constant
- self.visit(atom)
- else:
- self.add_constructors("none")
- return True
|