def visit(self, node: ClassDeclarationNode):
        self.current_type = self.context.get_type(node.id)

        # check parent
        if node.parent is not None:
            if node.parent in ('SELF_TYPE', 'String', 'Int', 'Bool', node.id):
                self.current_type.set_parent(ErrorType())
                self.errors.append(err.CANNOT_INHERIT %
                                   (node.parent_pos, node.parent))
            else:
                try:
                    parent_type = self.context.get_type(node.parent)
                except SemanticError:  # the parent type is not defined
                    parent_type = ErrorType()
                    self.errors.append(err.UNDEFINED_TYPE %
                                       (node.parent_pos, node.parent))
                try:
                    self.current_type.set_parent(parent_type)
                except SemanticError:  # this node already has a parent
                    self.errors.append(err.CANNOT_INHERIT %
                                       (node.pos, node.id, node.parent))
        else:
            try:
                self.current_type.set_parent(self.context.get_type('Object'))
            except SemanticError:
                pass

        # visit features
        for feature in node.features:
            self.visit(feature)
Exemple #2
0
 def visit(self, node: InstantiateNode, _: Scope):
     try:
         return self.context.get_type(
             node.lex) if node.lex != 'SELF_TYPE' else self.current_type
     except SemanticError:
         self.errors.append(err.UNDEFINED_TYPE % (node.pos, node.lex))
         return ErrorType()
Exemple #3
0
    def visit(self, node: FuncDeclarationNode, scope: Scope):
        self.current_method = self.current_type.get_method(node.id)

        # Check method override
        try:
            method, method_owner = self.current_type.parent.get_method(
                node.id, get_owner=True)
            if method != self.current_method:
                self.errors.append(err.WRONG_SIGNATURE %
                                   (node.pos, node.id, method_owner.name))
        except SemanticError:
            pass

        scope.define_variable('self', self.current_type, is_param=True)

        for param_node in node.params:
            self.visit(param_node, scope)

        try:
            ret_type = self.context.get_type(
                node.return_type
            ) if node.return_type != 'SELF_TYPE' else self.current_type
        except SemanticError:
            # this error is logged by type builder
            # self.errors.append(err.UNDEFINED_TYPE % (node.pos, node.return_type))
            ret_type = ErrorType()

        expr_type = self.visit(node.body, scope)
        if not expr_type.conforms_to(ret_type):
            self.errors.append(err.INCOMPATIBLE_TYPES %
                               (node.pos, expr_type.name, ret_type.name))
Exemple #4
0
    def visit(self, node: AttrDeclarationNode, scope: Scope):
        # Check attribute override
        try:
            attr = self.current_type.parent.get_attribute(
                node.id, self.current_type.name)
            self.errors.append(err.ATTRIBUTE_DEFINED_IN_PARENT %
                               (node.pos, attr.name))
        except SemanticError:
            pass

        if node.id == 'self':
            self.errors.append(err.SELF_INVALID_ID % (node.pos, ))

        try:
            attr_type = self.context.get_type(
                node.type) if node.type != 'SELF_TYPE' else self.current_type
        except SemanticError:
            attr_type = ErrorType()
            self.errors.append(err.UNDEFINED_TYPE % (node.type_pos, node.type))

        if node.expr is not None:
            expr_type = self.visit(node.expr, scope)
            if not expr_type.conforms_to(attr_type):
                self.errors.append(
                    err.INCOMPATIBLE_TYPES %
                    (node.expr_pos, expr_type.name, attr_type.name))

        self.current_type.get_attribute(node.id).scope = scope
    def visit(self, node: AttrDeclarationNode):
        try:
            attr_type = self.context.get_type(node.type)
        except SemanticError:
            attr_type = ErrorType()
            self.errors.append(err.UNDEFINED_TYPE % (node.pos, node.type))

        # add a default initialization expr to the node if it doesn't have one
        if node.expr is None:
            if attr_type == self.context.get_type('Int'):
                node.expr = IntegerNode('0')
            elif attr_type == self.context.get_type('String'):
                node.expr = StringNode('""')
            elif attr_type == self.context.get_type('Bool'):
                node.expr = BooleanNode('false')
            else:
                node.expr = VariableNode('void')

        try:
            self.current_type.define_attribute(
                node.id, attr_type, node.expr or VariableNode('void'),
                self.current_type.name)
        except SemanticError:
            self.errors.append(err.ATTRIBUTE_ALREADY_DEFINED %
                               (node.pos, node.id, self.current_type.name))
Exemple #6
0
    def visit(self, node: CallNode, scope: Scope):
        if node.obj is None:
            obj_type = self.current_type
        else:
            obj_type = self.visit(node.obj, scope)

        try:
            _, owner = obj_type.get_method(node.id, get_owner=True)
            node.update_obj_dynamic_type(owner.name)
        except SemanticError:
            pass

        if node.type is not None:
            try:
                anc_type = self.context.get_type(node.type)
            except SemanticError:
                anc_type = ErrorType()
                self.errors.append(err.UNDEFINED_TYPE %
                                   (node.parent_pos, node.type))
            if not obj_type.conforms_to(anc_type):
                self.errors.append(err.INVALID_ANCESTOR %
                                   (node.pos, obj_type.name, anc_type.name))
        else:
            anc_type = obj_type

        try:
            method = anc_type.get_method(node.id)
        except SemanticError:
            self.errors.append(err.UNDEFINED_METHOD %
                               (node.pos, node.id, anc_type.name))
            for arg in node.args:
                self.visit(arg, scope)
            return ErrorType()

        if len(node.args) != len(method.param_names):
            self.errors.append(err.WRONG_SIGNATURE %
                               (node.pos, method.name, obj_type.name))
        else:
            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.pos, arg_type.name, method.param_types[i].name))

        return method.return_type if method.return_type.name != 'SELF_TYPE' else anc_type
Exemple #7
0
 def visit(self, node: ParamNode, scope: Scope):
     if not scope.is_local(node.id):
         if node.type == 'SELF_TYPE':
             type_ = ErrorType()
             self.errors.append(err.SELF_TYPE_INVALID_PARAM_TYPE %
                                (node.type_pos, ))
         else:
             try:
                 type_ = self.context.get_type(node.type)
             except SemanticError:
                 # this error is logged by the type builder
                 # self.errors.append(err.UNDEFINED_TYPE % (node.type_pos, node.type))
                 type_ = ErrorType()
         scope.define_variable(node.id, type_, is_param=True)
     else:
         self.errors.append(err.LOCAL_ALREADY_DEFINED %
                            (node.pos, node.id, self.current_method.name))
Exemple #8
0
 def collect_features(self, node: AttrDeclarationNode, scope: Scope):
     try:
         attr_type = self.context.get_type(
             node.type) if node.type != 'SELF_TYPE' else self.current_type
     except SemanticError:
         attr_type = ErrorType()
         self.errors.append(err.UNDEFINED_TYPE % (node.type_pos, node.type))
     scope.define_variable(node.id, attr_type, is_attr=True)
 def visit(self, node: ClassDeclarationNode):
     type_ = self.context.get_type(node.id)
     try:
         type_.get_ancestors(node.id)
     except SemanticError:
         self.errors.append(err.CYCLIC_INHERITANCE %
                            (node.parent_pos, node.parent))
         type_.parent = None
         type_.set_parent(ErrorType())
Exemple #10
0
 def _check_unary_node(self, node: UnaryNode, scope: Scope, oper: str,
                       expected_type: Type):
     type_ = self.visit(node.expr, scope)
     if type_ == expected_type:
         return type_
     else:
         self.errors.append(err.INVALID_UNARY_OPERATOR %
                            (node.pos, oper, type_.name))
         return ErrorType()
Exemple #11
0
 def visit(self, node: VariableNode, scope: Scope):
     var = scope.find_variable(node.lex)
     if var is None:
         self.errors.append(
             err.VARIABLE_NOT_DEFINED %
             (node.pos, node.lex, self.current_method.name if
              self.current_method is not None else self.current_type.name))
         return ErrorType()
     return var.type
Exemple #12
0
 def _check_binary_node(self, node: BinaryNode, scope: Scope, oper: str,
                        ret_type: Type):
     int_type = self.context.get_type('Int')
     left_type = self.visit(node.left, scope)
     right_type = self.visit(node.right, scope)
     if left_type == right_type == int_type:
         return ret_type
     else:
         self.errors.append(
             err.INVALID_BINARY_OPERATOR %
             (node.pos, oper, left_type.name, right_type.name))
         return ErrorType()
Exemple #13
0
    def visit(self, node: CaseBranchNode, scope: Scope):
        child_scope = scope.create_child('_case_branch')
        try:
            id_type = self.context.get_type(node.type)
        except SemanticError:
            self.errors.append(err.UNDEFINED_TYPE % (node.type_pos, node.type))
            id_type = ErrorType()

        if node.id == 'self':
            self.errors.append(err.SELF_INVALID_ID % (node.pos, ))
        else:
            child_scope.define_variable(node.id, id_type)

        return self.visit(node.expr, child_scope)
    def visit(self, node: FuncDeclarationNode):
        param_names = []
        param_types = []
        for param_node in node.params:
            param_names.append(param_node.id)
            try:
                param_types.append(self.context.get_type(param_node.type))
            except SemanticError:
                param_types.append(ErrorType())
                self.errors.append(err.UNDEFINED_TYPE %
                                   (param_node.type_pos, param_node.type))
        try:
            ret_type = self.context.get_type(node.return_type)
        except SemanticError:
            self.errors.append(err.UNDEFINED_TYPE %
                               (node.pos, node.return_type))
            ret_type = ErrorType()

        try:
            self.current_type.define_method(node.id, param_names, param_types,
                                            ret_type)
        except SemanticError:
            self.errors.append(err.METHOD_ALREADY_DEFINED %
                               (node.pos, node.id, self.current_type.name))
Exemple #15
0
    def visit(self, node: LetDeclarationNode, scope: Scope):
        try:
            type_ = self.context.get_type(
                node.type) if node.type != 'SELF_TYPE' else self.current_type
        except SemanticError:
            self.errors.append(err.UNDEFINED_TYPE % (node.type_pos, node.type))
            type_ = ErrorType()

        if node.id == 'self':
            self.errors.append(err.SELF_INVALID_ID % (node.pos, ))
        else:
            scope.define_variable(node.id, type_)

        expr_type: Type = self.visit(node.expr,
                                     scope) if node.expr is not None else None
        if expr_type is not None and not expr_type.conforms_to(type_):
            self.errors.append(err.INCOMPATIBLE_TYPES %
                               (node.expr_pos, expr_type.name, type_.name))

        return type_
    def visit(self, node: ast.ProgramNode):
        self.context = Context()

        # Default types definition
        self.context.types['<error>'] = ErrorType()
        void = self.context.types['Void'] = VoidType()
        self_ = self.context.create_type('SELF_TYPE')
        object_ = self.context.create_type('Object')
        io = self.context.create_type('IO')
        string = self.context.create_type('String')
        int_ = self.context.types['Int'] = IntType()
        bool_ = self.context.create_type('Bool')

        # Default types inheritance
        void.set_parent(object_)
        io.set_parent(object_)
        string.set_parent(object_)
        int_.set_parent(object_)
        bool_.set_parent(object_)

        # Default types attributes
        object_.define_attribute('void', void, ast.VariableNode('void'))

        # Default types methods
        object_.define_method('abort', [], [], object_)
        object_.define_method('type_name', [], [], string)
        object_.define_method('copy', [], [], self_)

        io.define_method('out_string', ['x'], [string], self_)
        io.define_method('out_int', ['x'], [int_], self_)
        io.define_method('in_string', [], [], string)
        io.define_method('in_int', [], [], int_)

        string.define_method('length', [], [], int_)
        string.define_method('concat', ['s'], [string], string)
        string.define_method('substr', ['i', 'l'], [int_, int_], string)

        for declaration in node.declarations:
            self.visit(declaration)
Exemple #17
0
 def visit(self, node: BlockNode, scope: Scope):
     ret_type = ErrorType()
     for expr in node.expressions:
         ret_type = self.visit(expr, scope)
     return ret_type