primitives_visitor.py 16 KB

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