constructors_visitor.py 9.7 KB

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