constructors_visitor.py 9.6 KB

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