constructors_visitor.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. from hutn_compiler.visitor import Visitor
  2. from hutn_compiler.hutnparser import Tree
  3. class ConstructorsVisitor(Visitor):
  4. def __init__(self, args):
  5. Visitor.__init__(self, args)
  6. self.constructors = []
  7. self.free_id = 0
  8. def dump(self):
  9. return [len(self.constructors)] + self.constructors
  10. def add_constructors(self, *constructors):
  11. self.constructors.extend(constructors)
  12. # a visit_* method for each non-terminal in the grammar
  13. def visit_start(self, tree):
  14. # declare all functions
  15. for child in Tree.get_children(tree, "funcdecl"):
  16. if self.pre_visit_funcdecl(child):
  17. self.add_constructors(True)
  18. tail = Tree.get_tail_without(tree, ["newline"])
  19. last = tail[-1]
  20. for child in tail[:-1]:
  21. if child['head'] in ["return", "break", "continue"]:
  22. last = child
  23. break
  24. else:
  25. # funcdecl may add no constructors
  26. new_constructors_were_added = self.visit(child)
  27. if child['head'] == "func_call": # pop 'false'
  28. self.constructors.pop()
  29. if new_constructors_were_added:
  30. self.add_constructors(True)
  31. new_constructors_were_added = self.visit(last)
  32. if last['head'] == "func_call": # pop 'false'
  33. self.constructors.pop()
  34. if new_constructors_were_added:
  35. if last['head'] not in ["return", "break", "continue"]:
  36. self.add_constructors(False)
  37. elif self.constructors:
  38. self.constructors.pop() # pop 'true'
  39. self.add_constructors(False)
  40. def declare(self, symbol):
  41. if symbol['is_global']:
  42. symbol['node'] = symbol['name']
  43. self.add_constructors("global", symbol['node'])
  44. else:
  45. symbol['node'] = str(self.free_id)
  46. self.add_constructors("declare", symbol['node'])
  47. self.free_id += 1
  48. def visit_assignment(self, tree):
  49. self.add_constructors("assign")
  50. self.visit(Tree.get_tail(tree)[0])
  51. self.visit(Tree.get_tail(tree)[2])
  52. return True
  53. def visit_expression(self, tree):
  54. self.visit_children(tree)
  55. def visit_binary_operation(self, tree):
  56. self.visit_children(tree)
  57. def visit_disjunction(self, tree):
  58. self.visit_children(tree)
  59. def visit_conjunction(self, tree):
  60. self.visit_children(tree)
  61. def visit_comparison(self, tree):
  62. self.visit_children(tree)
  63. def visit_relation(self, tree):
  64. self.visit_children(tree)
  65. def visit_sum(self, tree):
  66. self.visit_children(tree)
  67. def visit_term(self, tree):
  68. self.visit_children(tree)
  69. def visit_factor(self, tree):
  70. self.visit_children(tree)
  71. def visit_primary(self, tree):
  72. self.visit_children(tree)
  73. def visit_parenthesized(self, tree):
  74. self.visit_children(tree)
  75. def visit_atomvalue(self, tree):
  76. self.visit_children(tree)
  77. def visit_type_specifier(self, tree):
  78. self.add_constructors("const", {"value": Tree.get_text(tree)})
  79. def visit_actionname(self, tree):
  80. self.add_constructors("const", {"value": Tree.get_text(Tree.get_tail(tree)[0])[1:]})
  81. def visit_string(self, tree):
  82. v = Tree.get_text(tree)[1:-1]
  83. v = v.replace("\\n", "\n")
  84. v = v.replace("\\t", "\t")
  85. v = v.replace("\\\"", "\"")
  86. self.add_constructors("const", v)
  87. def visit_integer(self, tree):
  88. self.add_constructors("const", int(Tree.get_text(tree)))
  89. def visit_float(self, tree):
  90. self.add_constructors("const", float(Tree.get_text(tree)))
  91. def visit_rvalue(self, tree):
  92. self.add_constructors("access")
  93. self.visit_lvalue(tree)
  94. def visit_lvalue(self, tree):
  95. symbol = self.get_symbol(tree)
  96. # TODO: split visit_funcdecl in pre_visit_funcdecl and visit_funcdecl
  97. if symbol['node'] is None:
  98. raise Exception("Undefined variable: %s" % (symbol['name']))
  99. self.add_constructors("resolve", symbol['node'])
  100. def visit_func_call(self, tree):
  101. symbol = self.get_symbol(Tree.get_tail(tree)[0])
  102. self.add_constructors("call")
  103. if "pathmv" in symbol:
  104. self.add_constructors("deref", symbol['pathmv'])
  105. else:
  106. self.visit(Tree.get_tail(tree)[0])
  107. expressions = Tree.get_children(tree, "expression")
  108. self.add_constructors(len(expressions))
  109. for expression in expressions:
  110. self.visit(expression)
  111. self.add_constructors(False)
  112. return True
  113. def visit_input(self, tree):
  114. self.add_constructors("input")
  115. return True
  116. def visit_output(self, tree):
  117. self.add_constructors("output")
  118. self.visit(Tree.get_child(tree, "expression"))
  119. return True
  120. def visit_dictionary(self, tree):
  121. pass # TODO: list and dictionary
  122. def visit_list(self, tree):
  123. pass # TODO: list and dictionary
  124. def visit_dict_item(self, tree):
  125. pass # TODO: list and dictionary
  126. def visit_ifelse(self, tree):
  127. self.add_constructors("if")
  128. expressions = Tree.get_children(tree, "expression")
  129. blocks = Tree.get_children(tree, "block")
  130. self.visit(expressions[0]) # condition
  131. self.visit(blocks[0]) # then-clause
  132. for e, b in zip(expressions[1:], blocks[1:]):
  133. self.add_constructors(True, "if") # else-if-clause
  134. self.visit(e)
  135. self.visit(b)
  136. if len(expressions) != len(blocks):
  137. self.add_constructors(True) # else-clause
  138. self.visit(blocks[-1])
  139. else:
  140. self.add_constructors(False) # no else_clause
  141. for i in range(len(expressions)-1):
  142. self.add_constructors(False) # no next
  143. return True
  144. def visit_while(self, tree):
  145. self.add_constructors("while")
  146. self.visit(Tree.get_child(tree, "expression"))
  147. self.visit(Tree.get_child(tree, "block"))
  148. return True
  149. def visit_block(self, tree):
  150. tail = Tree.get_tail_without(tree, ["newline", "indent"])
  151. last = tail[-1]
  152. for child in tail[:-1]:
  153. if child['head'] in ["return", "break", "continue"]:
  154. last = child
  155. break
  156. else:
  157. self.visit(child)
  158. if child['head'] == "func_call": # pop 'false'
  159. self.constructors.pop()
  160. self.add_constructors(True)
  161. self.visit(last)
  162. if last['head'] == "func_call": # pop 'false'
  163. self.constructors.pop()
  164. if last['head'] not in ["return", "break", "continue"]:
  165. self.add_constructors(False)
  166. def visit_func_body(self, tree):
  167. self.visit_children(tree)
  168. def pre_visit_funcdecl(self, tree):
  169. func_body = Tree.get_child(tree, "func_body")
  170. symbol = self.get_symbol(tree)
  171. symbol['node'] = symbol['name']
  172. return False
  173. def visit_funcdecl(self, tree):
  174. func_body = Tree.get_child(tree, "func_body")
  175. symbol = self.get_symbol(tree)
  176. if func_body:
  177. if symbol['name'] in ["input", "output"]:
  178. return False
  179. if Tree.get_children(tree, "MUTABLE"):
  180. self.add_constructors("mutable_funcdef")
  181. else:
  182. self.add_constructors("funcdef")
  183. self.add_constructors(symbol['node'],
  184. len(symbol['params']))
  185. for p in Tree.get_children(tree, "parameter"):
  186. self.visit(p)
  187. self.visit(func_body)
  188. return True
  189. elif Tree.get_child(tree, "ASSIGN"):
  190. # TODO: fix funcdecl special case: "X function f(...) = ..."
  191. # Note: replicates "Element x; x = ?primiteves/a" behavior
  192. # Dangerous: SemanticsVisitor handles it as a function
  193. # pathmv is needed in visit_func_call(self, tree)
  194. symbol['pathmv'] = Tree.get_text(Tree.get_child(tree, "ANYTHING"))
  195. self.add_constructors("global", symbol['node'], "deref", symbol['pathmv'])
  196. # reason: "X function f(Y) = Z" adds no constructors
  197. return True
  198. else:
  199. # Just a declaration, so skip
  200. return False
  201. def visit_parameter(self, tree):
  202. symbol = self.get_symbol(tree)
  203. symbol['node'] = str(self.free_id)
  204. self.add_constructors(symbol['node'])
  205. self.free_id += 1
  206. def visit_continue(self, tree):
  207. self.add_constructors("continue")
  208. return True
  209. def visit_break(self, tree):
  210. self.add_constructors("break")
  211. return True
  212. def visit_return(self, tree):
  213. self.add_constructors("return")
  214. if len(Tree.get_tail(tree)) > 2:
  215. self.add_constructors(True)
  216. self.visit(Tree.get_tail(tree)[1])
  217. else:
  218. self.add_constructors(False)
  219. return True
  220. def visit_bool(self, tree):
  221. if Tree.get_text(tree) == "True":
  222. self.add_constructors("const", True)
  223. else:
  224. self.add_constructors("const", False)
  225. def visit_definition(self, tree):
  226. # First declare it
  227. symbol = self.get_symbol(tree)
  228. self.declare(symbol)
  229. if Tree.get_children(tree, "ASSIGN"):
  230. # Determine whether it is just a constant, or a deref
  231. atom = Tree.get_child(tree, "atomvalue")
  232. if Tree.get_child(atom, "deref"):
  233. # Deref
  234. dest = Tree.get_child(Tree.get_child(atom, "deref"), "ANYTHING")
  235. if dest is None:
  236. # Just an empty questionmark!
  237. self.add_constructors("empty")
  238. else:
  239. self.add_constructors("deref", Tree.get_text(dest))
  240. else:
  241. # Constant
  242. self.visit(atom)
  243. else:
  244. self.add_constructors("none")
  245. return True