semantics_visitor.py 25 KB

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