semantics_visitor.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. import hutn_compiler.hutnparser as hp
  2. import hutn_compiler.symbol_table as st
  3. import sys
  4. from hutn_compiler.declare_functions_visitor import DeclareFunctionsVisitor
  5. from hutn_compiler.hutnparser import Tree
  6. from hutn_compiler.visitor import Visitor
  7. class SemanticsVisitor(Visitor):
  8. def __init__(self, args):
  9. Visitor.__init__(self, args)
  10. self.symbol_table = st.SymbolTable()
  11. # there is only one input file, list is for sharing it among visitors
  12. self.inputfiles = []
  13. # Count whether we are in a while or not
  14. self.while_counter = 0
  15. # inherited attribute, set in funcdecl and used in return,
  16. # to ensure that (returned type == declared type)
  17. self.current_funcdecl = None
  18. self.declare_functions_visitor = DeclareFunctionsVisitor(self.symbol_table, self.inputfiles)
  19. @staticmethod
  20. def incompatible_types(l_type, r_type):
  21. if type(l_type) != type(r_type):
  22. if "Void" in (type(l_type), type(r_type)):
  23. return True
  24. if "Element" in (type(l_type), type(r_type)):
  25. return False
  26. if l_type not in ["Integer", "Float", "Boolean"] or r_type not in ["Integer", "Float", "Boolean"]:
  27. return True
  28. return False
  29. def do_check_binary_ops_arithmetic(self, l, r):
  30. l_type, r_type = self.get_type(l), self.get_type(r)
  31. if SemanticsVisitor.incompatible_types(l_type, r_type):
  32. raise RuntimeError(
  33. "{}:{}:{}: error: invalid operands to binary operator "
  34. "(have {} and {})".format(self.inputfiles[0],
  35. l['startpos']['line'],
  36. l['startpos']['column'],
  37. str(l_type),
  38. str(r_type)))
  39. def check_binary_ops_arithmetic(self, tree):
  40. l, r = Tree.get_tail(tree)[0], Tree.get_tail(tree)[2]
  41. self.do_check_binary_ops_arithmetic(l, r)
  42. def generalize_binary_ops_arithmetic(self, tree):
  43. l, r = Tree.get_tail(tree)[0], Tree.get_tail(tree)[2]
  44. l_type, r_type = self.get_type(l), self.get_type(r)
  45. if l_type == "Float" or r_type == "Float":
  46. return "Float"
  47. elif l_type == "Integer" or r_type == "Integer":
  48. return "Integer"
  49. else:
  50. return "Boolean"
  51. def check_unary_ops_arithmetic(self, tree, operator_name):
  52. l = Tree.get_tail(tree)[1]
  53. l_type = self.get_type(l)
  54. if l_type not in ["Boolean", "Integer", "Float"]:
  55. raise RuntimeError(
  56. "{}:{}:{}: error: wrong type argument to unary {} "
  57. "({})".format(self.inputfiles[0],
  58. l['startpos']['line'],
  59. l['startpos']['column'],
  60. operator_name,
  61. str(l_type)))
  62. def promote_unary_ops_arithmetic(self, tree):
  63. l = Tree.get_tail(tree)[1]
  64. l_type = self.get_type(l)
  65. try:
  66. if l_type == "Boolean":
  67. return "Integer"
  68. elif l_type == "Integer" or l_type == "Float":
  69. return l_type
  70. else:
  71. raise RuntimeError("You cannot promote {} to a numeric type".format(str(l_type)))
  72. except RuntimeError:
  73. raise RuntimeError(
  74. "Pathological situation in promote_unary_ops_arithmetic: "
  75. "check_unary_ops_arithmetic has not been executed")
  76. # if r_type is provided, r is not used
  77. def do_check_assignment(self, l, r, r_type = None):
  78. if r_type is not None:
  79. l_type = self.get_type(l)
  80. else:
  81. l_type, r_type = self.get_type(l), self.get_type(r)
  82. if SemanticsVisitor.incompatible_types(l_type, r_type):
  83. raise RuntimeError("{}:{}:{}: error: cannot assign a value of "
  84. "type '{}' to a variable of type '{}'"
  85. .format(self.inputfiles[0],
  86. l['startpos']['line'],
  87. l['startpos']['column'],
  88. str(r_type),
  89. str(l_type)))
  90. def check_assignment(self, tree):
  91. l, r = Tree.get_tail(tree)[0], Tree.get_tail(tree)[2]
  92. self.do_check_assignment(l, r)
  93. def check_return(self, tree):
  94. l = self.current_funcdecl
  95. if len(Tree.get_tail(tree)) > 2:
  96. r = Tree.get_tail(tree)[1]
  97. r_type = None
  98. else:
  99. r = None
  100. r_type = "Void"
  101. if l:
  102. self.do_check_assignment(l, r, r_type)
  103. else:
  104. raise RuntimeError(
  105. "{}:{}:{}: error: 'return' is used outside of a function"
  106. .format(self.inputfiles[0],
  107. tree['startpos']['line'],
  108. tree['startpos']['column']))
  109. def check_predicate(self, tree):
  110. if self.get_type(tree) == "Element":
  111. return
  112. if self.get_type(tree) not in ["Boolean", "Integer", "Float"]:
  113. raise RuntimeError(
  114. "{}:{}:{}: error: predicates of type '{}' are not allowed"
  115. .format(self.inputfiles[0],
  116. tree['startpos']['line'],
  117. tree['startpos']['column'],
  118. self.get_type(tree)))
  119. def replace_child_binary_op_with_call(self, tree, i=0):
  120. if i == -1:
  121. child = tree
  122. else:
  123. child = Tree.get_tail(tree)[i]
  124. if len(Tree.get_tail(child)) > 1:
  125. try:
  126. l, op, r = Tree.get_tail(child)
  127. except:
  128. # Something went wrong... this code is severely broken
  129. return
  130. l_type, r_type = self.get_type(l), self.get_type(r)
  131. if type(l_type) != type(r_type):
  132. print("Error: " + str(l_type) + " <-> " + str(r_type))
  133. raise RuntimeError(
  134. "{}:{}:{}: error: children were not casted".format(
  135. self.inputfiles[0],
  136. tree['startpos']['line'],
  137. tree['startpos']['column']
  138. ))
  139. call_name = SemanticsVisitor.call_name_binary(l_type, op)
  140. call_tree = self.func_call(call_name, [l, r], tree)
  141. try:
  142. self.visit(call_tree)
  143. except RuntimeError:
  144. call_signature = "Boolean function {1}({2}, {2})".format(call_name, l_type)
  145. raise RuntimeError(
  146. "{}:{}:{}: error: cannot perform {}: function '{}' is "
  147. "not found".format(
  148. self.inputfiles[0],
  149. tree['startpos']['line'],
  150. tree['startpos']['column'],
  151. child['head'],
  152. call_signature))
  153. if i == -1:
  154. tree['head'] = call_tree['head']
  155. tree['tail'] = call_tree['tail']
  156. tree['_tail'] = None
  157. else:
  158. Tree.replace_child(tree, child, call_tree)
  159. self.set_type(tree, self.get_type(Tree.get_tail(tree)[i]))
  160. def replace_child_unary_op_with_call(self, tree):
  161. child = Tree.get_tail(tree)[0]
  162. if child['head'] == "keep_sign":
  163. Tree.replace_child(tree, child, Tree.get_tail(child)[1])
  164. else:
  165. op, l = Tree.get_tail(child)
  166. l_type = self.get_type(l)
  167. call_name = SemanticsVisitor.call_name_unary(l_type, op)
  168. call_tree = self.func_call(call_name, [l], tree)
  169. try:
  170. self.visit(call_tree)
  171. except RuntimeError:
  172. call_signature = "Boolean function {1}({2})".format(call_name, l_type)
  173. raise RuntimeError(
  174. "{}:{}:{}: error: cannot perform {}: function '{}' is "
  175. "not found".format(
  176. self.inputfiles[0],
  177. tree['startpos']['line'],
  178. tree['startpos']['column'],
  179. child['head'],
  180. call_signature))
  181. Tree.replace_child(tree, child, call_tree)
  182. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  183. def cast_binary_ops_arithmetic(self, tree):
  184. l, op, r = Tree.get_tail(tree)
  185. l_type, r_type = self.get_type(l), self.get_type(r)
  186. if type(l_type) != type(r_type): # if two different numeric types
  187. if l_type == "Float" or r_type == "Float":
  188. g_type = "Float"
  189. elif l_type == "Integer" or r_type == "Integer":
  190. g_type = "Integer"
  191. else:
  192. g_type = "Boolean"
  193. self.perform_implicit_cast(tree, l, l_type, g_type)
  194. self.perform_implicit_cast(tree, r, r_type, g_type)
  195. def cast_binary_ops_logical(self, tree):
  196. l, op, r = Tree.get_tail(tree)
  197. l_type, r_type = self.get_type(l), self.get_type(r)
  198. self.perform_implicit_cast(tree, l, l_type, "Boolean")
  199. self.perform_implicit_cast(tree, r, r_type, "Boolean")
  200. def cast_unary_ops_arithmetic(self, tree):
  201. l = Tree.get_tail(tree)[1]
  202. l_type = self.get_type(l)
  203. p_type = self.promote_unary_ops_arithmetic(tree)
  204. self.perform_implicit_cast(tree, l, l_type, p_type)
  205. def func_call(self, name, params, old_tree):
  206. startpos = old_tree['startpos']
  207. endpos = old_tree['endpos']
  208. inputfile = old_tree['inputfile']
  209. tree = {"head": "func_call",
  210. "tail": [
  211. {"head": "rvalue",
  212. "tail": [
  213. {"head": "ID",
  214. "tail": [name],
  215. "startpos": startpos,
  216. "endpos": endpos,
  217. "inputfile": inputfile}],
  218. "startpos": startpos,
  219. "endpos": endpos,
  220. "inputfile": inputfile}],
  221. "startpos": startpos,
  222. "endpos": endpos,
  223. "inputfile": inputfile}
  224. for p in params:
  225. self.replace_child_binary_op_with_call(p, -1)
  226. params = [{"head": "expression", "tail": [p], "startpos": startpos, "endpos": endpos, "inputfile": inputfile} for p in params]
  227. tree['tail'].extend(params)
  228. return {"head": "expression", "tail": [tree], "startpos": startpos, "endpos": endpos, "inputfile": inputfile}
  229. @staticmethod
  230. def cast_name(from_type, to_type):
  231. to_t = str(to_type)[0].lower()
  232. cast_name = "cast_" + {"f": "float", "i": "integer", "b": "boolean", "s": "string"}[to_t]
  233. return cast_name
  234. def raise_implicit_cast_error(self, from_type, to_type, tree):
  235. cast_name = SemanticsVisitor.cast_name(from_type, to_type)
  236. cast_signature = "{} function {}({})".format(
  237. str(to_type), cast_name, str(from_type))
  238. raise RuntimeError(
  239. "{}:{}:{}: error: cannot perform implicit cast from '{}'"
  240. " to '{}': function '{}' is not found".format(
  241. self.inputfiles[0],
  242. tree['startpos']['line'],
  243. tree['startpos']['column'],
  244. str(to_type), str(from_type),
  245. cast_signature))
  246. def perform_implicit_cast(self, tree, child, from_type, to_type):
  247. if "Element" in (from_type, to_type):
  248. return
  249. if from_type == to_type:
  250. return
  251. cast_name = SemanticsVisitor.cast_name(from_type, to_type)
  252. cast_tree = self.func_call(cast_name, [child], tree)
  253. try:
  254. self.visit(cast_tree)
  255. except RuntimeError:
  256. self.raise_implicit_cast_error(from_type, to_type, child)
  257. Tree.replace_child(tree, child, cast_tree)
  258. types = {
  259. "Integer": "integer",
  260. "Float": "float",
  261. "Boolean": "bool",
  262. "String": "string",
  263. "Action": "action",
  264. "Element": "element",
  265. "Type": "type"
  266. }
  267. binary_ops = {
  268. "OR": "or",
  269. "AND": "and",
  270. "EQ": "eq",
  271. "NEQ": "neq",
  272. "LT": "lt",
  273. "GT": "gt",
  274. "LE": "lte",
  275. "GE": "gte",
  276. "PLUS": "addition",
  277. "MINUS": "subtraction",
  278. "STAR": "multiplication",
  279. "SLASH": "division"
  280. }
  281. unary_ops = {
  282. "NOT": "not",
  283. "MINUS": "neg"
  284. }
  285. @staticmethod
  286. def call_name_binary(operand_type, operator):
  287. # String joins should also be possible
  288. if str(operand_type) == "String":
  289. if operator['head'] == "PLUS":
  290. return "string_join"
  291. if operator['head'] == "EQ":
  292. return "value_eq"
  293. elif operator['head'] == "NEQ":
  294. return "value_neq"
  295. call_name = "{}_{}".format(SemanticsVisitor.types[str(operand_type)],
  296. SemanticsVisitor.binary_ops[operator['head']])
  297. return call_name
  298. @staticmethod
  299. def call_name_unary(operand_type, operator):
  300. call_name = "{}_{}".format(SemanticsVisitor.types[str(operand_type)],
  301. SemanticsVisitor.unary_ops[operator['head']])
  302. return call_name
  303. def dump(self):
  304. return Tree.get_text(self.tree, with_implicit=True)
  305. # return "No code generation here"
  306. # a visit_* method for each non-terminal in the grammar
  307. def visit_start(self, tree):
  308. self.symbol_table.open_scope()
  309. self.inputfiles.append(tree['inputfile'])
  310. for child in Tree.get_tail(tree):
  311. self.inputfiles[0] = child['inputfile']
  312. self.declare_functions_visitor.visit(child)
  313. for child in Tree.get_tail(tree):
  314. self.inputfiles[0] = child['inputfile']
  315. self.visit(child)
  316. self.inputfiles.pop()
  317. self.symbol_table.close_scope()
  318. self.tree = tree
  319. def visit_statement(self, tree):
  320. self.visit_children(tree)
  321. def visit_definition(self, tree):
  322. self.visit_vardecl(tree)
  323. def visit_vardecl(self, tree):
  324. type_spec = Tree.get_child(tree, "type_specifier")
  325. var_id = Tree.get_child(tree, "ID")
  326. var_type = Tree.get_text(type_spec)
  327. var_name = Tree.get_text(var_id)
  328. symbol = {"name": var_name, "type": var_type, "is_global": self.current_funcdecl is None, "node": None, "params": None}
  329. try:
  330. self.symbol_table.add(symbol)
  331. except Exception:
  332. raise RuntimeError(
  333. "{}:{}:{}: error: redeclaration of '{}'".format(
  334. self.inputfiles[0], tree['startpos']['line'],
  335. tree['startpos']['column'], var_name))
  336. self.set_symbol(tree, symbol)
  337. def visit_assignment(self, tree):
  338. self.visit_children(tree)
  339. self.check_assignment(tree)
  340. def visit_expression(self, tree):
  341. self.visit_children(tree)
  342. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  343. def visit_binary_operation(self, tree):
  344. self.visit_children(tree)
  345. self.replace_child_binary_op_with_call(tree)
  346. def visit_disjunction(self, tree):
  347. self.visit_children(tree)
  348. if len(Tree.get_tail(tree)) == 1:
  349. self.replace_child_binary_op_with_call(tree)
  350. else:
  351. self.replace_child_binary_op_with_call(tree, 2)
  352. self.cast_binary_ops_logical(tree)
  353. self.set_type(tree, "Boolean")
  354. def visit_conjunction(self, tree):
  355. self.visit_children(tree)
  356. if len(Tree.get_tail(tree)) == 1:
  357. self.replace_child_binary_op_with_call(tree)
  358. else:
  359. self.replace_child_binary_op_with_call(tree, 2)
  360. self.cast_binary_ops_logical(tree)
  361. self.set_type(tree, "Boolean")
  362. def visit_comparison(self, tree):
  363. self.visit_children(tree)
  364. if len(Tree.get_tail(tree)) == 1:
  365. self.replace_child_binary_op_with_call(tree)
  366. else:
  367. self.replace_child_binary_op_with_call(tree, 2)
  368. self.check_binary_ops_arithmetic(tree)
  369. self.cast_binary_ops_arithmetic(tree)
  370. self.set_type(tree, "Boolean")
  371. def visit_relation(self, tree):
  372. self.visit_children(tree)
  373. if len(Tree.get_tail(tree)) == 1:
  374. self.replace_child_binary_op_with_call(tree)
  375. else:
  376. self.replace_child_binary_op_with_call(tree, 2)
  377. self.check_binary_ops_arithmetic(tree)
  378. self.cast_binary_ops_arithmetic(tree)
  379. self.set_type(tree, "Boolean")
  380. def visit_sum(self, tree):
  381. self.visit_children(tree)
  382. if len(Tree.get_tail(tree)) == 1:
  383. self.replace_child_binary_op_with_call(tree)
  384. else:
  385. self.replace_child_binary_op_with_call(tree, 2)
  386. self.check_binary_ops_arithmetic(tree)
  387. self.cast_binary_ops_arithmetic(tree)
  388. # after the cast both parameters have the same (generalized) type:
  389. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  390. def visit_term(self, tree):
  391. self.visit_children(tree)
  392. if len(Tree.get_tail(tree)) == 1:
  393. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  394. else:
  395. self.check_binary_ops_arithmetic(tree)
  396. self.cast_binary_ops_arithmetic(tree)
  397. # after the cast both parameters have the same (generalized) type:
  398. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  399. def visit_factor(self, tree):
  400. self.visit_children(tree)
  401. if Tree.get_child(tree, "primary") is not None:
  402. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  403. else:
  404. self.replace_child_unary_op_with_call(tree)
  405. def visit_logical_not(self, tree):
  406. self.visit_children(tree)
  407. l = Tree.get_tail(tree)[1]
  408. l_type = self.get_type(l)
  409. self.perform_implicit_cast(tree, l, l_type, "Boolean")
  410. self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
  411. def visit_invert_sign(self, tree):
  412. self.visit_children(tree)
  413. self.check_unary_ops_arithmetic(tree, "minus")
  414. self.cast_unary_ops_arithmetic(tree)
  415. self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
  416. def visit_keep_sign(self, tree):
  417. self.visit_children(tree)
  418. self.check_unary_ops_arithmetic(tree, "plus")
  419. self.cast_unary_ops_arithmetic(tree)
  420. self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
  421. def visit_primary(self, tree):
  422. self.visit_children(tree)
  423. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  424. def visit_parenthesized(self, tree):
  425. self.visit_children(tree)
  426. self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
  427. def visit_atomvalue(self, tree):
  428. self.visit_children(tree)
  429. self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
  430. def visit_type_specifier(self, tree):
  431. self.set_type(tree, "Type")
  432. def visit_actionname(self, tree):
  433. self.set_type(tree, "Action")
  434. def visit_string(self, tree):
  435. self.set_type(tree, "String")
  436. def visit_integer(self, tree):
  437. self.set_type(tree, "Integer")
  438. def visit_float(self, tree):
  439. self.set_type(tree, "Float")
  440. # there is no such rule in the grammar, we just avoid code duplicates
  441. def visit_id(self, tree):
  442. name = Tree.get_text(tree)
  443. #TODO this is set to the function returnvalue, even if we use the function pointer...
  444. try:
  445. symbol = self.symbol_table.get(name)
  446. except KeyError:
  447. raise RuntimeError("{}:{}:{}: error: '{}' is not declared".format(
  448. self.inputfiles[0], tree['startpos']['line'],
  449. tree['startpos']['column'], name))
  450. self.set_type(tree, symbol['type'])
  451. self.set_symbol(tree, symbol)
  452. def visit_rvalue(self, tree):
  453. if len(Tree.get_tail(tree)) > 1:
  454. # Complex: dict_read operation needed
  455. child = Tree.get_tail(tree)[0]
  456. node = Tree.get_child(tree, "rvalue")
  457. expression = Tree.get_child(tree, "expression")
  458. operation = "dict_read"
  459. call_tree = self.func_call(operation, [node, expression], tree)
  460. self.visit(call_tree)
  461. tree['head'] = call_tree['head']
  462. tree['_tail'] = call_tree['tail']
  463. tree['tail'] = call_tree['tail']
  464. self.set_type(tree, self.get_type(node))
  465. else:
  466. # Simple
  467. self.visit_id(tree)
  468. def visit_lvalue(self, tree):
  469. self.visit_id(tree)
  470. def visit_func_call(self, tree):
  471. self.visit_children(tree)
  472. symbol = self.get_symbol(Tree.get_tail(tree)[0])
  473. self.set_type(tree, symbol['type'])
  474. if not st.Symbol.is_func(symbol):
  475. if symbol['type'] == "Element":
  476. #sys.stderr.write("{}:{}:{}: warning: calling a variable of type "
  477. # "'Element'\n".format(self.inputfiles[0],
  478. # tree.startpos['line'],
  479. # tree.startpos['column'],
  480. # symbol.name))
  481. return # allow the call without knowing the declaration
  482. raise RuntimeError(
  483. "{}:{}:{}: error: '{}' is a variable of type '{}', not a "
  484. "function".format(self.inputfiles[0],
  485. tree['startpos']['line'],
  486. tree['startpos']['column'],
  487. symbol['name'],
  488. symbol['type']))
  489. expressions = Tree.get_children(tree, "expression")
  490. if len(expressions) != len(symbol['params']):
  491. raise RuntimeError(
  492. "{}:{}:{}: error: wrong number of arguments to "
  493. "function '{}'".format(self.inputfiles[0],
  494. tree['startpos']['line'],
  495. tree['startpos']['column'],
  496. st.Symbol.signature(symbol)))
  497. """
  498. for i in range(len(expressions)):
  499. arg_type = self.get_type(expressions[i])
  500. param_type = symbol.params[i]
  501. if SemanticsVisitor.incompatible_types(arg_type, param_type):
  502. raise RuntimeError(
  503. "{}:{}:{}: error: argument {} has type '{}' instead of "
  504. "'{}', calling function '{}'".format(
  505. self.inputfiles[0],
  506. tree.startpos['line'],
  507. tree.startpos['column'],
  508. i + 1,
  509. str(arg_type),
  510. str(param_type),
  511. symbol.signature()))
  512. if type(arg_type) != type(param_type):
  513. self.perform_implicit_cast(tree, expressions[i], arg_type,
  514. param_type)
  515. """
  516. if symbol['name'] == "__input":
  517. tree['head'] = "input"
  518. elif symbol['name'] == "__output":
  519. tree['head'] = "output"
  520. def visit_input(self, tree):
  521. pass # no need to visit it again
  522. def visit_output(self, tree):
  523. pass # no need to visit it again
  524. def visit_dictionary(self, tree):
  525. self.set_type(tree, "Element")
  526. def visit_list(self, tree):
  527. self.set_type(tree, "Element")
  528. def visit_dict_item(self, tree):
  529. pass
  530. def visit_ifelse(self, tree):
  531. self.visit_children(tree)
  532. expressions = Tree.get_children(tree, "expression")
  533. for expression in expressions:
  534. self.check_predicate(expression)
  535. def visit_while(self, tree):
  536. self.while_counter += 1
  537. self.visit_children(tree)
  538. self.while_counter -= 1
  539. expression = Tree.get_child(tree, "expression")
  540. self.check_predicate(expression)
  541. def visit_block(self, tree):
  542. self.symbol_table.open_scope()
  543. self.visit_children(tree)
  544. self.symbol_table.close_scope()
  545. def visit_func_body(self, tree):
  546. self.visit_children(tree)
  547. def visit_funcdecl(self, tree):
  548. # here we only visit the body cause the declaration is already done
  549. # by declare_functions_visitor
  550. if Tree.get_child(tree, 'func_body') is not None:
  551. self.current_funcdecl = tree
  552. self.symbol_table.open_scope()
  553. self.visit_children(tree)
  554. self.symbol_table.close_scope()
  555. self.current_funcdecl = None
  556. def visit_parameter(self, tree):
  557. param_id = Tree.get_child(tree, "ID")
  558. type_spec = Tree.get_child(tree, "type_specifier")
  559. param_type = Tree.get_text(type_spec)
  560. param_name = Tree.get_text(param_id)
  561. symbol = {"name": param_name, "type": param_type, "is_global": False, "node": None, "params": None}
  562. try:
  563. self.symbol_table.add(symbol)
  564. except Exception:
  565. raise RuntimeError(
  566. "{}:{}:{}: error: redeclaration of '{}'".format(
  567. self.inputfiles[0], tree['startpos']['line'],
  568. tree['startpos']['column'], param_name))
  569. self.set_symbol(tree, symbol)
  570. def visit_return(self, tree):
  571. self.visit_children(tree)
  572. self.check_return(tree)
  573. def visit_bool(self, tree):
  574. self.set_type(tree, "Boolean")
  575. def visit_break(self, tree):
  576. if self.while_counter == 0:
  577. raise RuntimeError(
  578. "{}:{}:{}: error: break outside of while".format(
  579. self.inputfiles[0], tree['startpos']['line'],
  580. tree['startpos']['column']))
  581. def visit_continue(self, tree):
  582. if self.while_counter == 0:
  583. raise RuntimeError(
  584. "{}:{}:{}: error: continue outside of while".format(
  585. self.inputfiles[0], tree['startpos']['line'],
  586. tree['startpos']['column']))