constructors_visitor.py 9.8 KB

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