primitives_visitor.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. import string
  2. from visitor import Visitor
  3. import json
  4. class Action():
  5. def __init__(self, value):
  6. self.value = value
  7. class PrimitivesVisitor(Visitor):
  8. def __init__(self, args):
  9. Visitor.__init__(self, args)
  10. self.output = []
  11. self.free_id = 0
  12. self.function_values = dict()
  13. self.debug_symbols = "--debug" in args
  14. self.while_stack = []
  15. def debug(self, node, tree, msg=""):
  16. if self.debug_symbols:
  17. self.dict(node, "__debug", self.value("[%s] %s" % (tree.get_reference_line(), msg)))
  18. def node(self):
  19. self.output.append(("N", self.free_id))
  20. self.free_id += 1
  21. return self.free_id - 1
  22. def dict(self, src, val, trgt):
  23. if src is None or trgt is None:
  24. raise Exception("Got None")
  25. self.output.append(("D", (src, json.dumps(val), trgt)))
  26. def value(self, value):
  27. if isinstance(value, Action):
  28. v = value.value
  29. else:
  30. v = json.dumps(value)
  31. self.output.append(("V", (self.free_id, v)))
  32. self.free_id += 1
  33. return self.free_id - 1
  34. def edge(self, source, target):
  35. self.output.append(("E", (self.free_id, source, target)))
  36. self.free_id += 1
  37. return self.free_id - 1
  38. def dump(self):
  39. output = []
  40. for t, data in self.output:
  41. if t == "N":
  42. output.append("N auto_%s\n" % data)
  43. elif t == "V":
  44. name, value = data
  45. name = name if self.first != name else "initial_IP"
  46. output.append("V auto_%s(%s)\n" % (name, value))
  47. elif t == "D":
  48. source, value, target = data
  49. source = source if self.first != source else "auto_initial_IP"
  50. target = target if self.first != target else "auto_initial_IP"
  51. source = "auto_%s" % source if isinstance(source, int) else source
  52. target = "auto_%s" % target if isinstance(target, int) else target
  53. output.append("D %s,%s,%s\n" % (source, value, target))
  54. elif t == "E":
  55. name, source, target = data
  56. source = source if self.first != source else "auto_initial_IP"
  57. target = target if self.first != target else "auto_initial_IP"
  58. name = "auto_%s" % name if isinstance(name, int) else name
  59. source = "auto_%s" % source if isinstance(source, int) else source
  60. target = "auto_%s" % target if isinstance(target, int) else target
  61. output.append("E %s(%s,%s)\n" % (name, source, target))
  62. return "".join(output)
  63. def set_primitive(self, tree, primitive):
  64. tree.primitive = primitive
  65. def get_primitive(self, tree):
  66. return getattr(tree, 'primitive', None)
  67. def forward_primitive_of_child(self, tree, i):
  68. self.visit_children(tree)
  69. self.set_primitive(tree, self.get_primitive(tree.get_tail()[i]))
  70. # a visit_* method for each non-terminal in the grammar
  71. def visit_start(self, tree):
  72. primitives = []
  73. for child in tree.get_children("funcdecl"):
  74. p = self.pre_visit_funcdecl(child)
  75. if p:
  76. # funcdecl returns a (global, assign) pair
  77. primitives.extend(p)
  78. for child in tree.get_tail():
  79. self.visit(child)
  80. p = self.get_primitive(child)
  81. if p is not None:
  82. if type(p) in (list, tuple):
  83. # funcdecl returns a (global, assign) pair
  84. primitives.extend(p)
  85. else:
  86. primitives.append(p)
  87. if child.head == "return":
  88. break
  89. self.first = primitives[0]
  90. for i in range(len(primitives)-1):
  91. self.dict(primitives[i], "next", primitives[i+1])
  92. self.last_instruction = primitives[-1]
  93. def visit_vardecl(self, tree):
  94. symbol = self.get_symbol(tree)
  95. if symbol.is_global:
  96. d = self.value(Action("global"))
  97. n = self.value(symbol.name)
  98. else:
  99. d = self.value(Action("declare"))
  100. if self.debug_symbols:
  101. n = self.value("%s [%s]" % (symbol.name, tree.get_reference_line()))
  102. else:
  103. n = self.node()
  104. symbol.node = n
  105. self.dict(d, "var", n)
  106. self.debug(d, tree)
  107. self.set_primitive(tree, d)
  108. def visit_assignment(self, tree):
  109. self.visit_children(tree)
  110. a = self.value(Action("assign"))
  111. var = self.get_primitive(tree.get_tail()[0])
  112. value = self.get_primitive(tree.get_tail()[-1])
  113. self.dict(a, "var", var)
  114. self.dict(a, "value", value)
  115. self.debug(a, tree)
  116. self.set_primitive(tree, a)
  117. def visit_expression(self, tree):
  118. self.forward_primitive_of_child(tree, 0)
  119. def visit_binary_operation(self, tree):
  120. self.forward_primitive_of_child(tree, 0)
  121. def visit_disjunction(self, tree):
  122. self.forward_primitive_of_child(tree, 0)
  123. def visit_conjunction(self, tree):
  124. self.forward_primitive_of_child(tree, 0)
  125. def visit_comparison(self, tree):
  126. self.forward_primitive_of_child(tree, 0)
  127. def visit_relation(self, tree):
  128. self.forward_primitive_of_child(tree, 0)
  129. def visit_sum(self, tree):
  130. self.forward_primitive_of_child(tree, 0)
  131. def visit_term(self, tree):
  132. self.forward_primitive_of_child(tree, 0)
  133. def visit_factor(self, tree):
  134. self.forward_primitive_of_child(tree, 0)
  135. def visit_primary(self, tree):
  136. self.forward_primitive_of_child(tree, 0)
  137. def visit_parenthesized(self, tree):
  138. self.forward_primitive_of_child(tree, 1)
  139. def visit_atomvalue(self, tree):
  140. self.forward_primitive_of_child(tree, 0)
  141. def visit_type_specifier(self, tree):
  142. self.visit_literal(tree)
  143. def visit_actionname(self, tree):
  144. self.visit_literal(tree.get_tail()[0])
  145. self.set_primitive(tree, self.get_primitive(tree.get_tail()[0]))
  146. def visit_string(self, tree):
  147. self.visit_literal(tree)
  148. # there is no such rule in the grammar, we just avoid code duplicates
  149. def visit_literal(self, tree):
  150. # TODO dictionary and list
  151. # if self.no_constant:
  152. # n = self.new_value(tree.get_text())
  153. # self.set_id(tree, n)
  154. # else:
  155. c = self.value(Action("constant"))
  156. if tree.get_text()[0] == "!":
  157. v = tree.get_text()[1:]
  158. else:
  159. v = tree.get_text()
  160. #NOTE Wrap this in an Action, even though it might not be an action: this has to be seen directly in the Mv without additional wrapping
  161. n = self.value(Action(v))
  162. self.dict(c, "node", n)
  163. self.debug(c, tree)
  164. self.set_primitive(tree, c)
  165. def visit_integer(self, tree):
  166. self.visit_literal(tree)
  167. def visit_float(self, tree):
  168. self.visit_literal(tree)
  169. def visit_rvalue(self, tree):
  170. self.visit_lvalue(tree)
  171. r = self.get_primitive(tree)
  172. if r is None:
  173. return
  174. a = self.value(Action("access"))
  175. self.dict(a, "var", r)
  176. self.debug(a, tree)
  177. self.set_primitive(tree, a)
  178. def visit_lvalue(self, tree):
  179. symbol = self.get_symbol(tree)
  180. if symbol.name in ["input", "output"]:
  181. return
  182. r = self.value(Action("resolve"))
  183. # print symbol.name, symbol.is_func(), symbol.node
  184. self.dict(r, "var", symbol.node)
  185. self.debug(r, tree)
  186. self.set_primitive(tree, r)
  187. def visit_func_call(self, tree):
  188. self.visit_children(tree)
  189. symbol = self.get_symbol(tree.get_tail()[0])
  190. expressions = tree.get_children("expression")
  191. arg_nodes_reversed = []
  192. for i in reversed(range(len(expressions))):
  193. arg_name = string.ascii_lowercase[i]
  194. arg_node = self.node()
  195. name_node = self.value(arg_name)
  196. self.dict(arg_node, "name", name_node)
  197. # print expressions[i].get_text()
  198. value_node = self.get_primitive(expressions[i])
  199. self.dict(arg_node, "value", value_node)
  200. if arg_nodes_reversed:
  201. next_node = arg_nodes_reversed[-1]
  202. self.dict(arg_node, "next_param", next_node)
  203. arg_nodes_reversed.append(arg_node)
  204. c = self.value(Action("call"))
  205. a = self.get_primitive(tree.get_tail()[0])
  206. self.dict(c, "func", a)
  207. self.debug(c, tree)
  208. if arg_nodes_reversed:
  209. self.dict(c, "params", arg_nodes_reversed[-1])
  210. self.dict(c, "last_param", arg_nodes_reversed[0])
  211. self.set_primitive(tree, c)
  212. def visit_input(self, tree):
  213. self.visit_children(tree)
  214. v = self.value(Action("input"))
  215. self.debug(v, tree)
  216. self.set_primitive(tree, v)
  217. def visit_output(self, tree):
  218. self.visit_children(tree)
  219. v = self.value(Action("output"))
  220. self.debug(v, tree)
  221. value = self.get_primitive(tree.get_child("expression"))
  222. self.dict(v, "value", value)
  223. self.set_primitive(tree, v)
  224. def visit_ifelse(self, tree):
  225. self.visit_children(tree)
  226. expressions = [self.get_primitive(e) for e in
  227. tree.get_children("expression")]
  228. blocks = [self.get_primitive(b) for b in tree.get_children("block")]
  229. first = None
  230. prev = None
  231. for e, b in zip(expressions, blocks):
  232. v = self.value(Action("if"))
  233. self.debug(v, tree)
  234. if first is None:
  235. first = v
  236. self.dict(v, "cond", e)
  237. self.dict(v, "then", b)
  238. if prev:
  239. self.dict(prev, "else", v)
  240. prev = v
  241. if len(expressions) != len(blocks):
  242. self.dict(prev, "else", blocks[-1])
  243. self.set_primitive(tree, first)
  244. def visit_continue(self, tree):
  245. w = self.value(Action("continue"))
  246. self.dict(w, "while", self.while_stack[-1])
  247. self.set_primitive(tree, w)
  248. def visit_break(self, tree):
  249. w = self.value(Action("break"))
  250. self.dict(w, "while", self.while_stack[-1])
  251. self.set_primitive(tree, w)
  252. def visit_while(self, tree):
  253. w = self.value(Action("while"))
  254. self.while_stack.append(w)
  255. self.visit_children(tree)
  256. self.while_stack.pop()
  257. self.debug(w, tree)
  258. c = self.get_primitive(tree.get_child("expression"))
  259. b = self.get_primitive(tree.get_child("block"))
  260. self.dict(w, "cond", c)
  261. self.dict(w, "body", b)
  262. self.set_primitive(tree, w)
  263. def visit_block(self, tree):
  264. self.visit_children(tree)
  265. primitives = []
  266. for child in tree.get_tail():
  267. p = self.get_primitive(child)
  268. if p:
  269. primitives.append(p)
  270. if child.head == "return":
  271. break
  272. for i in range(len(primitives)-1):
  273. self.dict(primitives[i], "next", primitives[i+1])
  274. if len(primitives) == 0:
  275. raise Exception("Block with no body found at %s" % tree.get_reference_line())
  276. self.set_primitive(tree, primitives[0])
  277. def visit_func_body(self, tree):
  278. self.forward_primitive_of_child(tree, 0)
  279. def pre_visit_funcdecl(self, tree):
  280. symbol = self.get_symbol(tree)
  281. if symbol.name in ["input", "output"]:
  282. return
  283. # TODO: fix funcdecl special case: "X function f(...) = ..."
  284. # Note: replicates "Element x; x = ?primiteves/a" behavior
  285. # Dangerous: SemanticsVisitor handles it as a function
  286. if not tree.get_child("func_body"):
  287. return
  288. new_value = self.node()
  289. self.function_values[symbol.name] = new_value
  290. root = self.value(symbol.name)
  291. symbol.node = root
  292. declare = self.value(Action("global"))
  293. self.dict(declare, "var", root)
  294. resolve = self.value(Action("resolve"))
  295. self.dict(resolve, "var", root)
  296. assign = self.value(Action("assign"))
  297. self.dict(assign, "var", resolve)
  298. const = self.value(Action("constant"))
  299. self.dict(const, "node", new_value)
  300. self.dict(assign, "value", const)
  301. return declare, assign
  302. def visit_funcdecl(self, tree):
  303. symbol = self.get_symbol(tree)
  304. if symbol.name in ["input", "output"]:
  305. return
  306. func_body = tree.get_child("func_body")
  307. if func_body:
  308. self.visit_children(tree)
  309. vf = self.function_values[symbol.name]
  310. parameters = tree.get_children("parameter")
  311. if parameters:
  312. ps = self.node()
  313. self.dict(vf, "params", ps)
  314. for i in range(len(parameters)):
  315. n = self.get_primitive(parameters[i])
  316. self.dict(ps, string.ascii_lowercase[i], n)
  317. # Add the name in case we want to pre-compile in the MvK
  318. self.dict(n, "name", self.value(string.ascii_lowercase[i]))
  319. b = self.get_primitive(func_body)
  320. if tree.get_children("MUTABLE"):
  321. self.dict(vf, "mutable", self.node())
  322. self.dict(vf, "body", b)
  323. else:
  324. # TODO: fix funcdecl special case: "X function f(...) = ..."
  325. # Note: replicates "Element x; x = ?primiteves/a" behavior
  326. # Dangerous: SemanticsVisitor handles it as a function
  327. root = self.value(symbol.name)
  328. symbol.node = root
  329. if tree.get_child("ASSIGN"):
  330. new_value = "?" + tree.get_child("ANYTHING").get_text()
  331. elif tree.get_child("ASSIGN") and not tree.get_child("ANYTHING"):
  332. new_value = self.node()
  333. else:
  334. return
  335. declare = self.value(Action("global"))
  336. self.dict(declare, "var", root)
  337. self.debug(declare, tree)
  338. resolve = self.value(Action("resolve"))
  339. self.dict(resolve, "var", root)
  340. assign = self.value(Action("assign"))
  341. self.dict(assign, "var", resolve)
  342. const = self.value(Action("constant"))
  343. self.dict(const, "node", new_value)
  344. self.dict(assign, "value", const)
  345. self.set_primitive(tree, (declare, assign))
  346. def visit_definition(self, tree):
  347. symbol = self.get_symbol(tree)
  348. root = self.value(symbol.name)
  349. declare = self.value(Action("global"))
  350. self.dict(declare, "var", root)
  351. self.debug(declare, tree)
  352. symbol.node = root
  353. resolve = self.value(Action("resolve"))
  354. self.dict(resolve, "var", root)
  355. assign = self.value(Action("assign"))
  356. self.dict(assign, "var", resolve)
  357. self.visit_atomvalue(tree.get_tail()[-1])
  358. value = self.get_primitive(tree.get_tail()[-1])
  359. if value is None:
  360. call = self.value(Action("call"))
  361. access = self.value(Action("access"))
  362. resolve = self.value(Action("resolve"))
  363. self.dict(call, "func", access)
  364. self.dict(access, "var", resolve)
  365. self.dict(resolve, "var", self.value("create_node"))
  366. value = call
  367. self.dict(assign, "value", value)
  368. self.set_primitive(tree, (declare, assign))
  369. def visit_parameter(self, tree):
  370. symbol = self.get_symbol(tree)
  371. if self.debug_symbols:
  372. n = self.value("%s [%s]" % (symbol.name, tree.get_reference_line()))
  373. else:
  374. n = self.node()
  375. symbol.node = n
  376. self.set_primitive(tree, n)
  377. def visit_return(self, tree):
  378. self.visit_children(tree)
  379. r = self.value(Action("return"))
  380. self.debug(r, tree)
  381. if len(tree.get_tail()) > 2:
  382. v = self.get_primitive(tree.get_tail()[1])
  383. self.dict(r, "value", v)
  384. self.set_primitive(tree, r)
  385. def visit_bool(self, tree):
  386. self.visit_literal(tree)