def visit(self, node: ast.MethodDeclarationNode):
        param_names = []
        param_types = []

        for i, (name, typex) in enumerate(node.params):
            param_names.append(name)
            try:
                param_types.append(self.context.get_type(typex))
            except SemanticError:
                param_types.append(ErrorType())
                line, column = node.param_types_positions[i]
                self.errors.append(
                    err.UNDEFINED_PARAM_TYPE %
                    (line, column, typex, node.id, self.current_type.name))

        try:
            return_type = self.context.get_type(node.return_type)
        except SemanticError:
            return_type = ErrorType()
            line, column = node.return_type_position
            self.errors.append(err.UNDEFINED_RETURN_TYPE %
                               (line, column, node.return_type, node.id,
                                self.current_type.name))

        try:
            self.current_type.define_method(node.id, param_names, param_types,
                                            return_type)
        except SemanticError:
            self.errors.append(
                err.METHOD_ALREADY_DEFINED %
                (node.line, node.column, node.id, self.current_type.name))
예제 #2
0
    def visit(self, node: ast.MethodCallNode, scope: Scope):
        if node.obj is None:
            node.obj = ast.VariableNode("self")
        obj_type = self.visit(node.obj, scope)

        if node.type is not None:
            try:
                ancestor_type = self.context.get_type(node.type)
            except SemanticError:
                ancestor_type = ErrorType()
                line, column = node.type_position
                self.errors.append(err.UNDEFINED_TYPE %
                                   (line, column, node.type))

            if not obj_type.conforms_to(ancestor_type):
                line, column = node.type_position
                self.errors.append(
                    err.INVALID_ANCESTOR %
                    (line, column, obj_type.name, ancestor_type.name))
        else:
            ancestor_type = obj_type

        try:
            method = ancestor_type.get_method(node.id)
        except SemanticError:
            line, column = node.id_position
            self.errors.append(err.DISPATCH_UNDEFINED_METHOD %
                               (line, column, node.id, obj_type.name))

            for arg in node.args:
                self.visit(arg, scope)
            return ErrorType()

        args_count = len(node.args)
        params_count = len(method.param_names)
        if args_count != params_count:
            line, column = node.id_position
            self.errors.append(err.DISPATCH_WITH_WRONG_NUMBER_OF_ARGS %
                               (line, column, method.name, obj_type.name,
                                params_count, args_count))

        number_of_args = min(args_count, params_count)
        for i, arg in enumerate(node.args[:number_of_args]):
            arg_type = self.visit(arg, scope)
            if not arg_type.conforms_to(method.param_types[i]):
                line, column = node.args_positions[i]
                self.errors.append(err.INCOMPATIBLE_TYPES % (
                    line,
                    column,
                    arg_type.name,
                    method.param_types[i].name,
                ))

        return (method.return_type
                if method.return_type.name != "SELF_TYPE" else ancestor_type)
예제 #3
0
    def visit(self, node: ast.SwitchCaseNode, scope: Scope):
        self.visit(node.expr, scope)
        types = []
        visited = set()
        for i, (identifier, type_name, expr) in enumerate(node.cases):
            new_scope = scope.create_child()
            try:
                if type_name != "SELF_TYPE":
                    new_scope.define_variable(identifier,
                                              self.context.get_type(type_name))
                else:
                    self.errors.append(err.INVALID_CASE_TYPE % type_name)
            except SemanticError:
                new_scope.define_variable(identifier, ErrorType())
                line, column = node.cases_positions[i]
                self.errors.append(err.UNDEFINED_TYPE_IN_BRANCH %
                                   (line, column, type_name))

            # Cannot be dublicate Branches types
            if type_name in visited:
                line, column = node.cases_positions[i]
                self.errors.append(err.DUPLICATE_BARNCH_IN_CASE %
                                   (line, column, type_name))

            visited.add(type_name)
            types.append(self.visit(expr, new_scope))

        return Type.multi_join(types)
예제 #4
0
    def visit(self, node: ast.LetNode, scope: Scope):
        for i, (_id, _type, _expr) in enumerate(node.declarations):
            if _id == "self":
                line, column = node.declaration_names_positions[i]
                self.errors.append(err.SELF_USED_IN_LET % (line, column))
                continue

            try:
                var_static_type = (self.context.get_type(_type) if
                                   _type != "SELF_TYPE" else self.current_type)
            except SemanticError:
                line, column = node.declaration_types_positions[i]
                self.errors.append(err.UNDEFINED_TYPE % (line, column, _type))
                var_static_type = ErrorType()

            # if scope.is_local(_id):
            #     feature = self.current_method or self.current_attribute
            #     self.errors.append(
            #         err.LOCAL_ALREADY_DEFINED
            #         % (node.line, node.column, _id, feature.name)
            #     )
            # else:
            scope.define_variable(_id, var_static_type)

            expr_type = (self.visit(_expr, scope.create_child())
                         if _expr is not None else None)
            if expr_type is not None and not expr_type.conforms_to(
                    var_static_type):
                self.errors.append(err.INCOMPATIBLE_TYPES %
                                   (node.line, node.column, expr_type.name,
                                    var_static_type.name))

        return self.visit(node.expr, scope.create_child())
예제 #5
0
    def visit(self, node: ast.LetNode, scope: Scope):
        for _id, _type, _expr in node.declarations:
            try:
                # Define and get the var_info
                var_info = scope.define_variable(_id,
                                                 self.context.get_type(_type))
            except SemanticError:
                var_info = scope.define_variable(_id, ErrorType())
            var_info_node = self.variables[var_info] = VariableInfoNode(
                var_info.type, var_info)

            expr_node = (self.visit(_expr, scope.create_child())
                         if _expr is not None else None)

            if var_info.type.name == "AUTO_TYPE":
                # Create an edge or add an new node only if it is AutoType
                if expr_node is not None:
                    self.graph.add_edge(expr_node, var_info_node)
                    if expr_node.type.name == "AUTO_TYPE":
                        self.graph.add_edge(var_info_node, expr_node)
                else:
                    self.graph.add_node(var_info_node)
            elif expr_node is not None and expr_node.type.name == "AUTO_TYPE":
                self.graph.add_edge(var_info_node, expr_node)

        return self.visit(node.expr, scope.create_child())
예제 #6
0
 def visit(self, node: ast.AttrDeclarationNode):
     try:
         self.current_type.define_attribute(
             node.id, self.context.get_type(node.type))
     except SemanticError as e:
         self.errors.append(e.text)
         self.current_type.define_attribute(node.id, ErrorType())
예제 #7
0
 def visit(self, node: ast.InstantiateNode, scope: Scope):
     try:
         return self.context.get_type(
             node.lex) if node.lex != 'SELF_TYPE' else self.current_type
     except SemanticError as e:
         self.errors.append(e.text)
         return ErrorType()
예제 #8
0
    def visit(self, node: ast.MethodDeclarationNode, scope: Scope):
        self.current_method = self.current_type.get_method(node.id)

        # Parameters can hide the attribute declaration, that's why we are not checking if there is defined,
        # instead we are checking for local declaration. Also it is checked that the static type of a parameter is
        # different of SELF_TYPE.

        scope.define_variable('self', self.current_type)

        for param_name, param_type in zip(self.current_method.param_names,
                                          self.current_method.param_types):
            if not scope.is_local(param_name):
                if param_type.name == 'SELF_TYPE':
                    self.errors.append(err.INVALID_PARAM_TYPE % 'SELF_TYPE')
                    scope.define_variable(param_name, ErrorType())
                else:
                    scope.define_variable(
                        param_name, self.context.get_type(param_type.name))
            else:
                self.errors.append(err.LOCAL_ALREADY_DEFINED %
                                   (param_name, self.current_method.name))

        return_type = self.context.get_type(
            node.return_type
        ) if node.return_type != 'SELF_TYPE' else self.current_type

        expr_type = self.visit(node.body, scope)

        if not expr_type.conforms_to(return_type):
            self.errors.append(err.INCOMPATIBLE_TYPES %
                               (expr_type.name, return_type.name))
예제 #9
0
    def visit(self, node: ast.AttrDeclarationNode, scope: Scope):
        if node.id == "self":
            self.errors.append(err.SELF_INVALID_ATTRIBUTE_ID %
                               (node.line, node.column))

        try:
            attr_type = (self.context.get_type(node.type)
                         if node.type != "SELF_TYPE" else self.current_type)
        except SemanticError:
            attr_type = ErrorType()

        scope.define_variable("self", self.current_type)

        # set the current attribute for analyze the body
        # and set the self.current_method variable to None
        self.current_attribute = self.current_type.get_attribute(node.id)
        self.current_method = None

        if node.expr is not None:
            expr_type = self.visit(node.expr, scope.create_child())
            if not expr_type.conforms_to(attr_type):
                line, column = node.expr_position
                self.errors.append(
                    err.INCOMPATIBLE_TYPES %
                    (line, column, expr_type.name, attr_type.name))
        scope.define_variable(node.id, attr_type)
예제 #10
0
 def visit(self, node: ast.VariableNode, scope: Scope):
     variable = scope.find_variable(node.lex)
     if variable is None:
         self.errors.append(err.VARIABLE_NOT_DEFINED %
                            (node.lex, self.current_method.name))
         return ErrorType()
     return variable.type
예제 #11
0
 def _check_unary_operation(self, node: ast.UnaryNode, scope: Scope,
                            operation: str, expected_type: Type):
     typex = self.visit(node.expr, scope)
     if typex == expected_type:
         return typex
     self.errors.append(err.INVALID_UNARY_OPERATION %
                        (operation, typex.name))
     return ErrorType()
예제 #12
0
 def visit(self, node: ast.InstantiateNode, scope: Scope):
     try:
         return (self.context.get_type(node.lex)
                 if node.lex != "SELF_TYPE" else self.current_type)
     except SemanticError as e:
         line, column = node.type_position
         self.errors.append(err.UNDEFINED_NEW_TYPE %
                            (line, column, node.lex))
         return ErrorType()
예제 #13
0
    def _check_int_binary_operation(self, node: ast.BinaryNode, scope: Scope,
                                    operation: str, return_type: Type):
        left_type = self.visit(node.left, scope)
        right_type = self.visit(node.right, scope)

        if left_type == right_type == self.context.get_type('Int'):
            return return_type
        self.errors.append(err.INVALID_BINARY_OPERATION %
                           (operation, left_type.name, right_type.name))
        return ErrorType()
예제 #14
0
    def visit(self, node: ast.MethodDeclarationNode):
        param_names = []
        param_types = []
        for name, typex in node.params:
            param_names.append(name)
            try:
                param_types.append(self.context.get_type(typex))
            except SemanticError as e:
                param_types.append(ErrorType())
                self.errors.append(e.text)

        try:
            return_type = self.context.get_type(node.return_type)
        except SemanticError as e:
            return_type = ErrorType()
            self.errors.append(e.text)

        self.current_type.define_method(node.id, param_names, param_types,
                                        return_type)
예제 #15
0
    def visit(self, node: ast.VariableNode, scope: Scope):
        variable = scope.find_variable(node.lex)
        if variable is None:
            if self.current_attribute is not None:
                name = self.current_attribute.name
            else:
                name = self.current_method.name

            self.errors.append(err.UNDEFINED_VARIABLE %
                               (node.line, node.column, node.lex, name))
            return ErrorType()
        return variable.type
예제 #16
0
    def visit(self, node: ast.MethodCallNode, scope: Scope):
        if node.obj is None:
            node.obj = ast.VariableNode('self')
        obj_type = self.visit(node.obj, scope)

        if node.type is not None:
            try:
                ancestor_type = self.context.get_type(node.type)
            except SemanticError as e:
                ancestor_type = ErrorType()
                self.errors.append(e.text)

            if not obj_type.conforms_to(ancestor_type):
                self.errors.append(err.INVALID_ANCESTOR %
                                   (obj_type.name, ancestor_type.name))
        else:
            ancestor_type = obj_type

        try:
            method = ancestor_type.get_method(node.id)
        except SemanticError as e:
            self.errors.append(e.text)
            for arg in node.args:
                self.visit(arg, scope)
            return ErrorType()

        if len(node.args) != len(method.param_names):
            self.errors.append(err.METHOD_OVERRIDE_ERROR %
                               (method.name, obj_type.name))

        for i, arg in enumerate(node.args):
            arg_type = self.visit(arg, scope)
            if not arg_type.conforms_to(method.param_types[i]):
                self.errors.append(err.INCOMPATIBLE_TYPES %
                                   (arg_type.name, method.param_types[i].name))

        return method.return_type if method.return_type.name != 'SELF_TYPE' else ancestor_type
    def visit(self, node: ast.AttrDeclarationNode):
        try:
            attr_type = self.context.get_type(node.type)
        except SemanticError:
            attr_type = ErrorType()
            line, column = node.type_position
            self.errors.append(
                err.UNDEFINED_ATTRIBUTE_TYPE %
                (line, column, node.type, node.id, self.current_type.name))

        try:
            self.current_type.define_attribute(node.id, attr_type)
        except SemanticError:
            self.errors.append(
                err.ATTRIBUTE_ALREADY_DEFINED %
                (node.line, node.column, node.id, self.current_type.name))
예제 #18
0
    def visit(self, node: ast.SwitchCaseNode, scope: Scope):
        self.visit(node.expr, scope)
        types = []
        for _id, _type, _expr in node.cases:
            new_scope = scope.create_child()
            try:
                if _type != 'SELF_TYPE':
                    new_scope.define_variable(_id,
                                              self.context.get_type(_type))
                else:
                    self.errors.append(err.INVALID_CASE_TYPE % _type)
            except SemanticError as e:
                new_scope.define_variable(_id, ErrorType())
                self.errors.append(e.text)

            types.append(self.visit(_expr, new_scope))

        return Type.multi_join(types)
예제 #19
0
    def visit(self, node: ast.LetNode, scope: Scope):
        for _id, _type, _expr in node.declarations:
            try:
                var_static_type = self.context.get_type(
                    _type) if _type != 'SELF_TYPE' else self.current_type
            except SemanticError as e:
                self.errors.append(e.text)
                var_static_type = ErrorType()

            if scope.is_local(_id):
                self.errors.append(err.LOCAL_ALREADY_DEFINED %
                                   (_id, self.current_method.name))
            else:
                scope.define_variable(_id, var_static_type)

            expr_type = self.visit(
                _expr, scope.create_child()) if _expr is not None else None
            if expr_type is not None and not expr_type.conforms_to(
                    var_static_type):
                self.errors.append(err.INCOMPATIBLE_TYPES %
                                   (expr_type.name, var_static_type.name))

        return self.visit(node.expr, scope.create_child())
예제 #20
0
 def visit(self, node: ast.BlockNode, scope: Scope):
     child_scope = scope.create_child()
     return_type = ErrorType()
     for expr in node.expressions:
         return_type = self.visit(expr, child_scope)
     return return_type