예제 #1
0
    def visit(self, node, scope):
        if node.id == "self":
            node_row, node_col = node.token.location
            self.errors.append(
                SemanticError(
                    node_row, node_col,
                    "'self' cannot be bound in a 'let' expression. " +
                    SELF_IS_READONLY))

        static_type = None
        try:
            static_type = self.context.get_type(node.type.lex)
            if static_type.name == "SELF_TYPE":
                static_type = self.current_type

        except SError as e:
            node_row, node_col = node.type.location
            self.errors.append(TypeError(node_row, node_col, e.text))
            static_type = ErrorType()

        if node.expr != None:
            typex, node_exp = self.visit(node.expr, scope)
            if not typex.conforms_to(static_type):
                line, col = node.expr.token.location
                self.errors.append(
                    TypeError(
                        line, col,
                        INCOMPATIBLE_TYPES % (typex.name, static_type.name)))
        else:
            node_exp = None

        scope.define_variable(node.id, static_type)
        return (static_type,
                cool_type_nodes.VarDeclarationNode(node.id, node.type.lex,
                                                   node_exp, static_type))
예제 #2
0
 def get_type(self, ntype, comp_error_mesg):
     try:
         return self.context.get_type(ntype.lex)
     except SError as error:
         node_row, node_col = ntype.location
         self.errors.append(TypeError(node_row, node_col, f"Type {ntype.lex} " + comp_error_mesg + " is not defined."))
         return ErrorType()
예제 #3
0
    def visit(self, node, scope):
        if node.id.lex == "self":
            node_row, node_col = node.token.location
            self.errors.append(
                SemanticError(node_row, node_col,
                              "Cannot assign to 'self'. " + SELF_IS_READONLY))
        var_type = None
        if not scope.is_defined(node.id.lex):
            node_row, node_col = node.id.location
            self.errors.append(
                NameError(
                    node_row, node_col, VARIABLE_NOT_DEFINED %
                    (node.id.lex, self.current_method.name)))
            var_type = ErrorType()
        else:
            var_type = scope.find_variable(node.id.lex).type

        expr_type, exp_node = self.visit(node.expr, scope)
        if not expr_type.conforms_to(var_type):
            node_row, node_col = node.token.location
            self.errors.append(
                TypeError(
                    node_row, node_col,
                    f"Inferred type {expr_type.name} of assigned expression does not conforms to type {var_type.name} of variable '{node.id.lex}'"
                ))

        return (expr_type,
                cool_type_nodes.AssignNode(node.id.lex, exp_node, expr_type))
예제 #4
0
    def visit(self, node, scope):
        type_not_found = False
        try:
            typex = self.context.get_type(node.type.lex)

            if typex.name == "SELF_TYPE":
                typex = self.current_type

        except SError as e:
            # ERROR already reported in type builder
            type_not_found = True

        if node.init_exp != None:
            init_expr_type, init_exp = self.visit(node.init_exp, scope)
            if type_not_found:
                return cool_type_nodes.AttrDeclarationNode(
                    node.id.lex, node.type.lex, init_exp)

            if not init_expr_type.conforms_to(typex):
                line, col = node.token.location
                self.errors.append(
                    TypeError(
                        line, col, INCOMPATIBLE_TYPES %
                        (init_expr_type.name, typex.name)))
        else:
            init_exp = None
        return cool_type_nodes.AttrDeclarationNode(node.id.lex, node.type.lex,
                                                   init_exp)
예제 #5
0
    def visit(self, node, scope):
        int_type = self.context.get_type("Int")
        typex, exp_node = self.visit(node.expr, scope)

        if typex != int_type and not typex.name == "AUTO_TYPE":
            node_row, node_col = node.expr.token.location
            self.errors.append(
                TypeError(
                    node_row, node_col,
                    f"Expression after '~' must be Int, current is {typex.name}"
                ))
            return (ErrorType(),
                    cool_type_nodes.NegNode(exp_node, ErrorType()))

        return (int_type, cool_type_nodes.NegNode(exp_node, int_type))
예제 #6
0
    def visit(self, node, scope):
        bool_type = self.context.get_type("Bool")
        typex, exp_node = self.visit(node.expr, scope)

        if typex != bool_type and not typex.name == "AUTO_TYPE":
            line, col = node.expr.token.location
            self.errors.append(
                TypeError(
                    line, col,
                    f"Expression after 'not' must be Bool, current is {typex.name}"
                ))
            return (ErrorType(),
                    cool_type_nodes.NotNode(exp_node, ErrorType()))

        return (bool_type, cool_type_nodes.NotNode(exp_node, bool_type))
예제 #7
0
    def visit(self, node, scope):
        int_type = self.context.get_type("Int")
        left_type, left_exp_node = self.visit(node.left, scope)
        right_type, right_exp_node = self.visit(node.right, scope)

        if (left_type != int_type and left_type.name != "AUTO_TYPE") or (
                right_type != int_type and right_type.name != "AUTO_TYPE"):
            node_row, node_col = node.token.location
            self.errors.append(
                TypeError(
                    node_row, node_col,
                    INVALID_OPERATION % (left_type.name, right_type.name)))

        return (int_type,
                cool_type_nodes.DivNode(left_exp_node, right_exp_node,
                                        int_type))
예제 #8
0
    def visit(self, node, scope):
        try:
            typex = self.context.get_type(node.lex.lex)
            if typex.name == "SELF_TYPE":
                return self.current_type
            return (typex,
                    cool_type_nodes.InstantiateNode(node.lex.lex, typex))

        except SError as error:
            node_row, node_col = node.lex.location
            self.errors.append(
                TypeError(
                    node_row, node_col,
                    f"Type {node.lex.lex} of 'new' expression is not defined.")
            )
            return (ErrorType(),
                    cool_type_nodes.InstantiateNode(node.lex.lex, ErrorType()))
예제 #9
0
    def visit(self, node, scope):
        condition_type, condition_node = self.visit(node.condition, scope)
        body_type, body_node = self.visit(node.body, scope)
        bool_type = self.context.get_type("Bool")

        if condition_type != bool_type and condition_type.name != "AUTO_TYPE":
            node_row, node_col = node.condition.token.location
            self.errors.append(
                TypeError(
                    node_row, node_col,
                    f"Expression in 'while' condition must be bool, current type is {condition_type.name}"
                ))
            return (ErrorType(),
                    cool_type_nodes.WhileNode(condition_node, body_node,
                                              ErrorType()))

        obj_type = self.context.get_type("Object")
        return (obj_type,
                cool_type_nodes.WhileNode(condition_node, body_node, obj_type))
예제 #10
0
    def visit(self, node, scope):
        predicate_type, if_node = self.visit(node.if_expr, scope)
        then_type, then_node = self.visit(node.then_expr, scope)
        else_type, else_node = self.visit(node.else_expr, scope)

        if predicate_type.name != "Bool" and predicate_type.name != "AUTO_TYPE":
            node_row, node_col = node.if_expr.token.location
            self.errors.append(
                TypeError(
                    node_row, node_col,
                    f"Expression after 'if' must be Bool, current type is {predicate_type.name}"
                ))
            return (ErrorType(),
                    cool_type_nodes.IfNode(if_node, then_node, else_node,
                                           ErrorType()))

        least_type = find_least_type(then_type, else_type, self.context)
        return (least_type,
                cool_type_nodes.IfNode(if_node, then_node, else_node,
                                       least_type))
예제 #11
0
    def visit(self, node, scope):
        int_type = self.context.get_type("Int")
        string_type = self.context.get_type("String")
        bool_type = self.context.get_type("Bool")
        built_in_types = [int_type, string_type, bool_type]

        left_type, left_exp_node = self.visit(node.left, scope)
        right_type, right_exp_node = self.visit(node.right, scope)

        if left_type in built_in_types or right_type in built_in_types:
            if (left_type != right_type and left_type.name != "AUTO_TYPE"
                    and right_type.name != "AUTO_TYPE"):
                node_row, node_col = node.token.location
                self.errors.append(
                    TypeError(
                        node_row, node_col,
                        f"One of the expressions of '=' operator is of type Int, String or Bool, the other must have the same static type. Left type: {left_type.name}. Right type: {right_type.name}"
                    ))

        return (bool_type,
                cool_type_nodes.EqualNode(left_exp_node, right_exp_node,
                                          bool_type))
예제 #12
0
    def visit(self, node, scope):
        if node.id.lex == "self":
            node_row, node_col = node.id.location
            self.errors.append(
                SemanticError(
                    node_row, node_col,
                    "'self' cannot be bound in a 'case' expression. " +
                    SELF_IS_READONLY))

        try:
            static_type = self.context.get_type(node.type.lex)
            scope.define_variable(node.id.lex, static_type)
        except SError as e:
            node_row, node_col = node.type.location
            self.errors.append(
                TypeError(
                    node_row, node_col,
                    f"Type {node.type.lex} of case branch is undefined."))

        typex, node_exp = self.visit(node.expr, scope)
        return (typex,
                cool_type_nodes.CaseItemNode(node.id.lex, node.type.lex,
                                             node_exp, typex))
예제 #13
0
    def visit(self, node, scope):
        auto_type = self.context.get_type("AUTO_TYPE")
        typex = None
        if node.obj is not None:
            typex, obj_exp = self.visit(node.obj, scope)
            if typex == auto_type:
                return auto_type

        else:
            typex = self.current_type
            obj_exp = None

        new_args = []
        arg_types = []
        for arg in node.args:  # visiting arguments in case of earlier return
            arg_type, arg_node = self.visit(arg, scope)
            new_args.append(arg_node)
            arg_types.append(arg_type)

        method = None
        try:
            if not (node.at_type is None):
                at_type = node.at_type.lex
                node_at_type = self.context.get_type(node.at_type.lex)
                method = node_at_type.get_method(node.id.lex)
                if not typex.conforms_to(node_at_type):
                    node_row, node_col = node.at_type.location  # maybe in node.obj
                    self.errors.append(
                        TypeError(
                            node_row, node_col,
                            f"Expression type {typex.name} does not conform to declared static dispatch type {node_at_type.name}."
                        ))
                    return (ErrorType(),
                            cool_type_nodes.CallNode(node.id.lex, new_args,
                                                     obj_exp, at_type, typex,
                                                     ErrorType()))

            else:
                at_type = None
                method = typex.get_method(node.id.lex)
        except SError as error:
            node_col, node_row = node.token.location
            self.errors.append(AttributeError(node_col, node_row, error.text))
            return (ErrorType(),
                    cool_type_nodes.CallNode(node.id.lex, new_args, obj_exp,
                                             at_type, typex, ErrorType()))

        if len(method.param_names) != len(node.args):
            node_row, node_col = node.id.location
            self.errors.append(
                SemanticError(
                    node_row, node_col,
                    f"There is no definition of {method.name} that takes {len(node.args)} arguments "
                ))

        n_method_args = len(method.param_names)
        for i, arg in enumerate(node.args):
            if n_method_args == i:
                break
            arg_type = arg_types[i]
            ptype = method.param_types[i]
            if not arg_type.conforms_to(ptype):
                node_row, node_col = arg.token.location
                self.errors.append(
                    TypeError(
                        node_row, node_col,
                        f"In call of method {node.id.lex} parameter of type {arg_type.name} does not conforms to declared type {ptype.name}"
                    ))

        if method.return_type == self.context.get_type("SELF_TYPE"):
            return (typex,
                    cool_type_nodes.CallNode(node.id.lex, new_args, obj_exp,
                                             at_type, typex, typex))

        return (method.return_type,
                cool_type_nodes.CallNode(node.id.lex, new_args, obj_exp,
                                         at_type, typex, method.return_type))
예제 #14
0
    def visit(self, node, scope):
        self.current_method = self.current_type.get_method(node.id.lex)
        method_return_type = self.current_method.return_type
        if method_return_type.name == "SELF_TYPE":
            method_return_type = self.current_type

        child_scope = scope.create_child()

        # ------------parameters most have differente names------------
        param_names = self.current_method.param_names
        param_types = self.current_method.param_types
        param_used = {}
        new_params = []

        for i, param_name in enumerate(param_names):
            param_n, param_t = node.params[i]
            new_params.append((param_n.lex, param_t.lex))
            if param_name == "self":
                node_row, node_col = param_n.location  # location of param name
                self.errors.append(
                    SemanticError(
                        node_row, node_col,
                        f"'self' cannot be the name of a formal parameter."))
            try:
                param_used[param_name]
                node_row, node_col = param_n.location
                self.errors.append(
                    SemanticError(
                        node_row, node_col,
                        f"Formal parameter '{param_name}' multiply defined in method '{node.id.lex}'"
                    ))
            except:
                param_used[param_name] = True
                child_scope.define_variable(param_name, param_types[i])

        # -------------------------------------------------------------

        body_type, body_exp = self.visit(node.body, child_scope)

        if not body_type.conforms_to(method_return_type):
            node_row, node_col = node.body.token.location
            self.errors.append(
                TypeError(
                    node_row, node_col,
                    f"Inferred return type '{body_type.name}' of method '{node.id.lex}' (the type of the last expression) does not conform to declared return type '{method_return_type.name}'."
                ))

        if self.current_type.parent is not None:
            try:
                parent_method = self.current_type.parent.get_method(
                    self.current_method.name)
                # ensure same return type of redefined method
                if parent_method.return_type != self.current_method.return_type:
                    node_row, node_col = node.type.location
                    self.errors.append(
                        SemanticError(
                            node_row, node_col,
                            f"In redefined method '{node.id.lex}', return type {self.current_method.return_type.name} is different from original return type {parent_method.return_type.name}."
                        ))

                # redefined method most have same number of parameters
                if len(parent_method.param_names) != len(
                        self.current_method.param_names):
                    node_row, node_col = node.id.location
                    self.errors.append(
                        SemanticError(
                            node_row, node_col,
                            f"Incompatible number of formal parameters in redefined method '{node.id.lex}'."
                        ))
                    len_parent_params = len(parent_method.param_names)
                    len_current_params = len(self.current_method.param_names)
                    if len_current_params >= len_parent_params:
                        max_len = len_parent_params
                    else:
                        max_len = len_current_params
                else:
                    max_len = len(parent_method.param_names)

                # check that each param has the same type as in the original method
                for i in range(0, max_len):
                    if self.current_method.param_types[
                            i] != parent_method.param_types[i]:
                        param_i_name, param_i_type = node.params[i]
                        node_row, node_col = param_i_name.location
                        self.errors.append(
                            SemanticError(
                                node_row, node_col,
                                f"In redefined method '{node.id.lex}', type {self.current_method.param_types[i].name} of parameter {param_i_name.lex} is different from original type {parent_method.param_types[i].name}."
                            ))

            except SError:
                pass  # parent has no method named like this

        return cool_type_nodes.FuncDeclarationNode(node.id.lex, new_params,
                                                   node.type.lex, body_exp)