|
|
@@ -1,7 +1,6 @@
|
|
|
import hutn_compiler.hutnparser as hp
|
|
|
import hutn_compiler.symbol_table as st
|
|
|
import sys
|
|
|
-import hutn_compiler.types_mv as types_mv
|
|
|
from hutn_compiler.declare_functions_visitor import DeclareFunctionsVisitor
|
|
|
from hutn_compiler.hutnparser import Tree
|
|
|
from hutn_compiler.visitor import Visitor
|
|
|
@@ -26,11 +25,11 @@ class SemanticsVisitor(Visitor):
|
|
|
@staticmethod
|
|
|
def incompatible_types(l_type, r_type):
|
|
|
if type(l_type) != type(r_type):
|
|
|
- if types_mv.Void in (type(l_type), type(r_type)):
|
|
|
+ if "Void" in (type(l_type), type(r_type)):
|
|
|
return True
|
|
|
- if types_mv.Element in (type(l_type), type(r_type)):
|
|
|
+ if "Element" in (type(l_type), type(r_type)):
|
|
|
return False
|
|
|
- if l_type.isNotNumber() or r_type.isNotNumber():
|
|
|
+ if l_type not in ["Integer", "Float", "Boolean"] or r_type not in ["Integer", "Float", "Boolean"]:
|
|
|
return True
|
|
|
return False
|
|
|
|
|
|
@@ -52,12 +51,17 @@ class SemanticsVisitor(Visitor):
|
|
|
def generalize_binary_ops_arithmetic(self, tree):
|
|
|
l, r = Tree.get_tail(tree)[0], Tree.get_tail(tree)[2]
|
|
|
l_type, r_type = self.get_type(l), self.get_type(r)
|
|
|
- return types_mv.generalize_arithmetic(l_type, r_type)
|
|
|
+ if l_type == "Float" or r_type == "Float":
|
|
|
+ return "Float"
|
|
|
+ elif l_type == "Integer" or r_type == "Integer":
|
|
|
+ return "Integer"
|
|
|
+ else:
|
|
|
+ return "Boolean"
|
|
|
|
|
|
def check_unary_ops_arithmetic(self, tree, operator_name):
|
|
|
l = Tree.get_tail(tree)[1]
|
|
|
l_type = self.get_type(l)
|
|
|
- if l_type.isNotNumber():
|
|
|
+ if l_type not in ["Boolean", "Integer", "Float"]:
|
|
|
raise RuntimeError(
|
|
|
"{}:{}:{}: error: wrong type argument to unary {} "
|
|
|
"({})".format(self.inputfiles[0],
|
|
|
@@ -70,7 +74,12 @@ class SemanticsVisitor(Visitor):
|
|
|
l = Tree.get_tail(tree)[1]
|
|
|
l_type = self.get_type(l)
|
|
|
try:
|
|
|
- return types_mv.promote_arithmetic(l_type)
|
|
|
+ if l_type == "Boolean":
|
|
|
+ return "Integer"
|
|
|
+ elif l_type == "Integer" or l_type == "Float":
|
|
|
+ return l_type
|
|
|
+ else:
|
|
|
+ raise RuntimeError("You cannot promote {} to a numeric type".format(str(l_type)))
|
|
|
except RuntimeError:
|
|
|
raise RuntimeError(
|
|
|
"Pathological situation in promote_unary_ops_arithmetic: "
|
|
|
@@ -103,7 +112,7 @@ class SemanticsVisitor(Visitor):
|
|
|
r_type = None
|
|
|
else:
|
|
|
r = None
|
|
|
- r_type = types_mv.Void()
|
|
|
+ r_type = "Void"
|
|
|
|
|
|
if l:
|
|
|
self.do_check_assignment(l, r, r_type)
|
|
|
@@ -115,9 +124,9 @@ class SemanticsVisitor(Visitor):
|
|
|
tree['startpos']['column']))
|
|
|
|
|
|
def check_predicate(self, tree):
|
|
|
- if isinstance(self.get_type(tree), types_mv.Element):
|
|
|
+ if self.get_type(tree) == "Element":
|
|
|
return
|
|
|
- if self.get_type(tree).isNotNumber():
|
|
|
+ if self.get_type(tree) not in ["Boolean", "Integer", "Float"]:
|
|
|
raise RuntimeError(
|
|
|
"{}:{}:{}: error: predicates of type '{}' are not allowed"
|
|
|
.format(self.inputfiles[0],
|
|
|
@@ -150,8 +159,7 @@ class SemanticsVisitor(Visitor):
|
|
|
try:
|
|
|
self.visit(call_tree)
|
|
|
except RuntimeError:
|
|
|
- call_signature = "{0} function {1}({2}, {2})".format(
|
|
|
- str(types_mv.Boolean()), call_name, l_type)
|
|
|
+ call_signature = "Boolean function {1}({2}, {2})".format(call_name, l_type)
|
|
|
raise RuntimeError(
|
|
|
"{}:{}:{}: error: cannot perform {}: function '{}' is "
|
|
|
"not found".format(
|
|
|
@@ -180,8 +188,7 @@ class SemanticsVisitor(Visitor):
|
|
|
try:
|
|
|
self.visit(call_tree)
|
|
|
except RuntimeError:
|
|
|
- call_signature = "{0} function {1}({2})".format(
|
|
|
- str(types_mv.Boolean()), call_name, l_type)
|
|
|
+ call_signature = "Boolean function {1}({2})".format(call_name, l_type)
|
|
|
raise RuntimeError(
|
|
|
"{}:{}:{}: error: cannot perform {}: function '{}' is "
|
|
|
"not found".format(
|
|
|
@@ -197,15 +204,20 @@ class SemanticsVisitor(Visitor):
|
|
|
l, op, r = Tree.get_tail(tree)
|
|
|
l_type, r_type = self.get_type(l), self.get_type(r)
|
|
|
if type(l_type) != type(r_type): # if two different numeric types
|
|
|
- g_type = types_mv.generalize_arithmetic(l_type, r_type)
|
|
|
+ if l_type == "Float" or r_type == "Float":
|
|
|
+ g_type = "Float"
|
|
|
+ elif l_type == "Integer" or r_type == "Integer":
|
|
|
+ g_type = "Integer"
|
|
|
+ else:
|
|
|
+ g_type = "Boolean"
|
|
|
self.perform_implicit_cast(tree, l, l_type, g_type)
|
|
|
self.perform_implicit_cast(tree, r, r_type, g_type)
|
|
|
|
|
|
def cast_binary_ops_logical(self, tree):
|
|
|
l, op, r = Tree.get_tail(tree)
|
|
|
l_type, r_type = self.get_type(l), self.get_type(r)
|
|
|
- self.perform_implicit_cast(tree, l, l_type, types_mv.Boolean())
|
|
|
- self.perform_implicit_cast(tree, r, r_type, types_mv.Boolean())
|
|
|
+ self.perform_implicit_cast(tree, l, l_type, "Boolean")
|
|
|
+ self.perform_implicit_cast(tree, r, r_type, "Boolean")
|
|
|
|
|
|
def cast_unary_ops_arithmetic(self, tree):
|
|
|
l = Tree.get_tail(tree)[1]
|
|
|
@@ -263,9 +275,9 @@ class SemanticsVisitor(Visitor):
|
|
|
cast_signature))
|
|
|
|
|
|
def perform_implicit_cast(self, tree, child, from_type, to_type):
|
|
|
- if types_mv.Element in (type(from_type), type(to_type)):
|
|
|
+ if "Element" in (from_type, to_type):
|
|
|
return
|
|
|
- if type(from_type) == type(to_type):
|
|
|
+ if from_type == to_type:
|
|
|
return
|
|
|
cast_name = SemanticsVisitor.cast_name(from_type, to_type)
|
|
|
cast_tree = self.func_call(cast_name, [child], tree)
|
|
|
@@ -356,7 +368,7 @@ class SemanticsVisitor(Visitor):
|
|
|
type_spec = Tree.get_child(tree, "type_specifier")
|
|
|
var_id = Tree.get_child(tree, "ID")
|
|
|
|
|
|
- var_type = types_mv.string_to_type(Tree.get_text(type_spec))
|
|
|
+ var_type = Tree.get_text(type_spec)
|
|
|
var_name = Tree.get_text(var_id)
|
|
|
|
|
|
symbol = {"name": var_name, "type": var_type, "is_global": self.current_funcdecl is None, "node": None, "params": None}
|
|
|
@@ -390,7 +402,7 @@ class SemanticsVisitor(Visitor):
|
|
|
else:
|
|
|
self.replace_child_binary_op_with_call(tree, 2)
|
|
|
self.cast_binary_ops_logical(tree)
|
|
|
- self.set_type(tree, types_mv.Boolean())
|
|
|
+ self.set_type(tree, "Boolean")
|
|
|
|
|
|
def visit_conjunction(self, tree):
|
|
|
self.visit_children(tree)
|
|
|
@@ -399,7 +411,7 @@ class SemanticsVisitor(Visitor):
|
|
|
else:
|
|
|
self.replace_child_binary_op_with_call(tree, 2)
|
|
|
self.cast_binary_ops_logical(tree)
|
|
|
- self.set_type(tree, types_mv.Boolean())
|
|
|
+ self.set_type(tree, "Boolean")
|
|
|
|
|
|
def visit_comparison(self, tree):
|
|
|
self.visit_children(tree)
|
|
|
@@ -409,7 +421,7 @@ class SemanticsVisitor(Visitor):
|
|
|
self.replace_child_binary_op_with_call(tree, 2)
|
|
|
self.check_binary_ops_arithmetic(tree)
|
|
|
self.cast_binary_ops_arithmetic(tree)
|
|
|
- self.set_type(tree, types_mv.Boolean())
|
|
|
+ self.set_type(tree, "Boolean")
|
|
|
|
|
|
def visit_relation(self, tree):
|
|
|
self.visit_children(tree)
|
|
|
@@ -419,7 +431,7 @@ class SemanticsVisitor(Visitor):
|
|
|
self.replace_child_binary_op_with_call(tree, 2)
|
|
|
self.check_binary_ops_arithmetic(tree)
|
|
|
self.cast_binary_ops_arithmetic(tree)
|
|
|
- self.set_type(tree, types_mv.Boolean())
|
|
|
+ self.set_type(tree, "Boolean")
|
|
|
|
|
|
def visit_sum(self, tree):
|
|
|
self.visit_children(tree)
|
|
|
@@ -454,7 +466,7 @@ class SemanticsVisitor(Visitor):
|
|
|
|
|
|
l = Tree.get_tail(tree)[1]
|
|
|
l_type = self.get_type(l)
|
|
|
- self.perform_implicit_cast(tree, l, l_type, types_mv.Boolean())
|
|
|
+ self.perform_implicit_cast(tree, l, l_type, "Boolean")
|
|
|
|
|
|
self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
|
|
|
|
|
|
@@ -487,19 +499,19 @@ class SemanticsVisitor(Visitor):
|
|
|
self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
|
|
|
|
|
|
def visit_type_specifier(self, tree):
|
|
|
- self.set_type(tree, types_mv.Type())
|
|
|
+ self.set_type(tree, "Type")
|
|
|
|
|
|
def visit_actionname(self, tree):
|
|
|
- self.set_type(tree, types_mv.Action())
|
|
|
+ self.set_type(tree, "Action")
|
|
|
|
|
|
def visit_string(self, tree):
|
|
|
- self.set_type(tree, types_mv.String())
|
|
|
+ self.set_type(tree, "String")
|
|
|
|
|
|
def visit_integer(self, tree):
|
|
|
- self.set_type(tree, types_mv.Integer())
|
|
|
+ self.set_type(tree, "Integer")
|
|
|
|
|
|
def visit_float(self, tree):
|
|
|
- self.set_type(tree, types_mv.Float())
|
|
|
+ self.set_type(tree, "Float")
|
|
|
|
|
|
# there is no such rule in the grammar, we just avoid code duplicates
|
|
|
def visit_id(self, tree):
|
|
|
@@ -541,7 +553,7 @@ class SemanticsVisitor(Visitor):
|
|
|
self.set_type(tree, symbol['type'])
|
|
|
|
|
|
if not st.Symbol.is_func(symbol):
|
|
|
- if isinstance(symbol['type'], types_mv.Element):
|
|
|
+ if symbol['type'] == "Element":
|
|
|
#sys.stderr.write("{}:{}:{}: warning: calling a variable of type "
|
|
|
# "'Element'\n".format(self.inputfiles[0],
|
|
|
# tree.startpos['line'],
|
|
|
@@ -597,10 +609,10 @@ class SemanticsVisitor(Visitor):
|
|
|
pass # no need to visit it again
|
|
|
|
|
|
def visit_dictionary(self, tree):
|
|
|
- self.set_type(tree, types_mv.Element)
|
|
|
+ self.set_type(tree, "Element")
|
|
|
|
|
|
def visit_list(self, tree):
|
|
|
- self.set_type(tree, types_mv.Element)
|
|
|
+ self.set_type(tree, "Element")
|
|
|
|
|
|
def visit_dict_item(self, tree):
|
|
|
pass
|
|
|
@@ -642,7 +654,7 @@ class SemanticsVisitor(Visitor):
|
|
|
param_id = Tree.get_child(tree, "ID")
|
|
|
type_spec = Tree.get_child(tree, "type_specifier")
|
|
|
|
|
|
- param_type = types_mv.string_to_type(Tree.get_text(type_spec))
|
|
|
+ param_type = Tree.get_text(type_spec)
|
|
|
param_name = Tree.get_text(param_id)
|
|
|
|
|
|
symbol = {"name": param_name, "type": param_type, "is_global": False, "node": None, "params": None}
|
|
|
@@ -662,7 +674,7 @@ class SemanticsVisitor(Visitor):
|
|
|
self.check_return(tree)
|
|
|
|
|
|
def visit_bool(self, tree):
|
|
|
- self.set_type(tree, types_mv.Boolean())
|
|
|
+ self.set_type(tree, "Boolean")
|
|
|
|
|
|
def visit_break(self, tree):
|
|
|
if self.while_counter == 0:
|