Пример #1
0
    def visit(self, attrDeclarationNode):
        try:
            attrType = self.context.get_type(
                attrDeclarationNode.type,
                (attrDeclarationNode.line, attrDeclarationNode.col))
        except SemanticError:
            errorText = f'Class {attrDeclarationNode.type} of attribute {attrDeclarationNode.id} is undefined.'
            self.errors.append(
                TypexError(errorText, attrDeclarationNode.typeLine,
                           attrDeclarationNode.typeCol))
            attrType = ErrorType(
                (attrDeclarationNode.line, attrDeclarationNode.col))

        if attrDeclarationNode.id == 'self':
            errorText = f"'self' cannot be the name of an attribute."
            self.errors.append(
                SemanticError(errorText, attrDeclarationNode.line,
                              attrDeclarationNode.col))

        try:
            self.currentType.define_attribute(
                attrDeclarationNode.id, attrType,
                (attrDeclarationNode.line, attrDeclarationNode.col))
        except SemanticError as error:
            self.errors.append(error)
Пример #2
0
    def visit(self, varDeclarationNode, scope):
        if varDeclarationNode.id == 'self':
            errorText = '\'self\' cannot be bound in a \'let\' expression.'
            self.errors.append(
                SemanticError(errorText, varDeclarationNode.line,
                              varDeclarationNode.col))
            return

        try:
            vType = self.context.get_type(
                varDeclarationNode.type,
                (varDeclarationNode.line, varDeclarationNode.col))
        except:
            errorText = f'Class {varDeclarationNode.type} of let-bound identifier {varDeclarationNode.id} is undefined.'
            self.errors.append(
                TypexError(errorText, varDeclarationNode.typeLine,
                           varDeclarationNode.typeCol))
            vType = ErrorType()

        vType = self._get_type(
            varDeclarationNode.type,
            (varDeclarationNode.typeLine, varDeclarationNode.typeCol))
        varInfo = scope.define_variable(varDeclarationNode.id, vType)

        if varDeclarationNode.expr is not None:
            self.visit(varDeclarationNode.expr, scope)
        else:
            self.define_default_value(vType, varDeclarationNode)
Пример #3
0
 def _get_method(self, typex, name, pos):
     typex = self.context.get_type(typex.name)
     try:
         return typex.get_method(name, pos)
     except SemanticError:
         if type(typex) != ErrorType and type(typex) != AutoType:
             errorText = f'Dispatch to undefined method {name}.'
             self.errors.append(AttributexError(errorText, *pos))
         return MethodError(name, [], [], ErrorType())
Пример #4
0
    def visit(self, negationNode, scope):
        exprType = self.visit(negationNode.expr, scope)
        if exprType != IntType():
            errorText = f'Argument of \'~\' has type {exprType.name} instead of {IntType().name}.'
            self.errors.append(
                TypexError(errorText, negationNode.line, negationNode.col))
            return ErrorType()

        negationNode.computed_type = IntType()
        return IntType()
Пример #5
0
    def visit(self, lessEq, scope):
        leftType = self.visit(lessEq.lvalue, scope)
        rightType = self.visit(lessEq.rvalue, scope)
        if leftType != IntType() or rightType != IntType():
            errorText = f'non-Int arguments: {leftType.name} <= {rightType.name} .'
            self.errors.append(TypexError(errorText, lessEq.line, lessEq.col))
            return ErrorType()

        lessEq.computed_type = BoolType()
        return BoolType()
Пример #6
0
    def visit(self, classDeclarationNode):
        try:
            self.currentType = self.context.get_type(
                classDeclarationNode.id,
                (classDeclarationNode.line, classDeclarationNode.col))
        except SemanticError as error:
            self.currentType = ErrorType()
            self.errors.append(error)

        if classDeclarationNode.parent is not None:
            if classDeclarationNode.parent in ['String', 'Int', 'Bool']:
                errorText = f'Class {classDeclarationNode.id} cannot inherit class {classDeclarationNode.parent}.'
                self.errors.append(
                    SemanticError(errorText, classDeclarationNode.line,
                                  classDeclarationNode.col))
            try:
                parent = self.context.get_type(
                    classDeclarationNode.parent,
                    (classDeclarationNode.parentLine,
                     classDeclarationNode.parentCol))
            except:
                errorText = f'Class {classDeclarationNode.id} inherits from an undefined class {classDeclarationNode.parent}'
                self.errors.append(
                    TypexError(errorText, classDeclarationNode.line,
                               classDeclarationNode.col))
                parent = None
            try:
                current = parent
                while current is not None:
                    if current.name == self.currentType.name:
                        errorText = f'Class {self.currentType.name}, or an ancestor of {self.currentType.name}, is involved in an inheritance cycle.'
                        raise SemanticError(errorText,
                                            classDeclarationNode.line,
                                            classDeclarationNode.col)
                    current = current.parent
            except SemanticError as error:
                parent = ErrorType()
                self.errors.append(error)

            self.currentType.set_parent(parent)

        for feature in classDeclarationNode.features:
            self.visit(feature)
Пример #7
0
    def visit(self, logicNegationNode, scope):
        exprType = self.visit(logicNegationNode.expr, scope)
        if exprType != BoolType():
            errorText = f'Argument of \'not\' has type {exprType.name} instead of {BoolType().name}.'
            self.errors.append(
                TypexError(errorText, logicNegationNode.line,
                           logicNegationNode.col))
            return ErrorType()

        logicNegationNode.computed_type = BoolType()
        return BoolType()
Пример #8
0
    def visit(self, divNode, scope):
        leftType = self.visit(divNode.lvalue, scope)
        rightType = self.visit(divNode.rvalue, scope)
        if leftType != IntType() or rightType != IntType():
            errorText = f'non-Int arguments: {leftType.name} / {rightType.name} .'
            self.errors.append(TypexError(errorText, divNode.line,
                                          divNode.col))
            return ErrorType()

        divNode.computed_type = IntType()
        return IntType()
Пример #9
0
    def visit(self, caseOptionNode, scope):
        try:
            typex = self.context.get_type(
                caseOptionNode.type, (caseOptionNode.line, caseOptionNode.col))
        except:
            errorText = f'Class {caseOptionNode.type} of case branch is undefined.'
            self.errors.append(
                TypexError(errorText, caseOptionNode.line, caseOptionNode.col))
            typex = ErrorType()

        scope.define_variable(caseOptionNode.id, typex)
        self.visit(caseOptionNode.expr, scope)
Пример #10
0
    def visit(self, newNode, scope):
        try:
            typex = self.context.get_type(newNode.id,
                                          (newNode.line, newNode.col))
        except:
            typex = ErrorType()
            errorText = f'\'new\' used with undefined class {newNode.id}.'
            self.errors.append(TypexError(errorText, newNode.line,
                                          newNode.col))

        typex = get_type(typex, self.currentType)
        newNode.computed_type = typex
        return typex
Пример #11
0
    def visit(self, equalNode, scope):
        leftType = self.visit(equalNode.lvalue, scope)
        rightType = self.visit(equalNode.rvalue, scope)
        if (leftType != rightType) and (leftType in [
                IntType(), StringType(), BoolType()
        ] or rightType in [IntType(), StringType(),
                           BoolType()]):
            errorText = 'Illegal comparison with a basic type.'
            self.errors.append(
                TypexError(errorText, equalNode.line, equalNode.col))
            return ErrorType()

        equalNode.computed_type = BoolType()
        return BoolType()
Пример #12
0
    def visit(self, funcDeclarationNode):
        argsNames = []
        argsTypes = []
        for name, typex, line, col in funcDeclarationNode.params:
            if name in argsNames:
                errorText = f'Formal parameter {name} is multiply defined.'
                self.errors.append(SemanticError(errorText, line, col))

            argsNames.append(name)

            try:
                argType = self.context.get_type(typex, (line, col))
            except SemanticError:
                errorText = f'Class {typex} of formal parameter {typex} is undefined.'
                self.errors.append(TypexError(errorText, line, col))
                argType = ErrorType()

            argsTypes.append(argType)

        try:
            returnType = self.context.get_type(
                funcDeclarationNode.type,
                (funcDeclarationNode.typeLine, funcDeclarationNode.typeCol))
        except SemanticError:
            errorText = f'Undefined return type {funcDeclarationNode.type} in method {funcDeclarationNode.id}.'
            self.errors.append(
                TypexError(errorText, funcDeclarationNode.typeLine,
                           funcDeclarationNode.typeCol))
            returnType = ErrorType(
                (funcDeclarationNode.typeLine, funcDeclarationNode.typeCol))

        try:
            self.currentType.define_method(
                funcDeclarationNode.id, argsNames, argsTypes, returnType,
                (funcDeclarationNode.line, funcDeclarationNode.col))
        except SemanticError as error:
            self.errors.append(error)
Пример #13
0
    def visit(self, idNode, scope):
        try:
            return self.currentType.get_attribute(
                idNode.id, (idNode.line, idNode.col)).type
        except:
            if not scope.is_defined(idNode.id):
                errorText = f'Undeclared identifier {idNode.id}.'
                self.errors.append(
                    NamexError(errorText, idNode.line, idNode.col))
                vInfo = scope.define_variable(
                    idNode.id, ErrorType((idNode.line, idNode.col)))
            else:
                vInfo = scope.find_variable(idNode.id)

            return vInfo.type
Пример #14
0
    def visit(self, attrDeclarationNode, scope):
        attr = self.currentType.get_attribute(
            attrDeclarationNode.id,
            (attrDeclarationNode.line, attrDeclarationNode.col))
        attrType = get_type(attr.type, self.currentType)
        self.currentIndex = attr.index
        typex = self.visit(attrDeclarationNode.expr, scope)
        self.currentIndex = None

        if not typex.conforms_to(attrType):
            errorText = f'Inferred type {typex.name} of initialization of attribute {attr.name} does not conform to declared type {attrType.name}.'
            self.errors.append(
                TypexError(errorText, attrDeclarationNode.line,
                           attrDeclarationNode.col))
            return ErrorType()

        return typex
Пример #15
0
    def visit(self, assignNode, scope):
        if assignNode.id == 'self':
            errorText = 'Cannot assign to \'self\'.'
            self.errors.append(
                SemanticError(errorText, assignNode.line, assignNode.col))
            return

        vInfo = scope.find_variable(assignNode.id)
        if vInfo is None:
            varInfo = scope.find_attribute(assignNode.id)
            if varInfo is None:
                errorText = f'Undeclared identifier {assignNode.id}.'
                self.errors.append(
                    NamexError(errorText, assignNode.line, assignNode.col))
                vType = ErrorType()
                scope.define_variable(assignNode.id, vType)

        self.visit(assignNode.expr, scope)
Пример #16
0
    def visit(self, arrobaCallNode, scope):
        objType = self.visit(arrobaCallNode.obj, scope)
        typex = self._get_type(
            arrobaCallNode.type,
            (arrobaCallNode.typeLine, arrobaCallNode.typeCol))

        if not objType.conforms_to(typex):
            errorText = f'Expression type {typex.name} does not conform to declared static dispatch type {objType.name}.'
            self.errors.append(
                TypexError(errorText, arrobaCallNode.typeLine,
                           arrobaCallNode.typeCol))
            return ErrorType()

        method = self._get_method(typex, arrobaCallNode.id,
                                  (arrobaCallNode.line, arrobaCallNode.col))
        if not isinstance(method, MethodError):
            # check the args
            argTypes = [self.visit(arg, scope) for arg in arrobaCallNode.args]

            if len(argTypes) > len(method.param_types):
                errorText = f'Method {method.name} called with wrong number of arguments.'
                self.errors.append(
                    SemanticError(errorText, arrobaCallNode.line,
                                  arrobaCallNode.col))
            elif len(argTypes) < len(method.param_types):
                for arg, argInfo in zip(method.param_names[len(argTypes):],
                                        arrobaCallNode.args[len(argTypes):]):
                    errorText = f'Method {method.name} called with wrong number of arguments.'
                    self.errors.append(SemanticError(errorText, *argInfo.pos))

            for argType, paramType, paramName in zip(argTypes,
                                                     method.param_types,
                                                     method.param_names):
                if not argType.conforms_to(paramType):
                    errorText = f'In call of method {method.name}, type {argType.name} of parameter {paramName} does not conform to declared type {paramType.name}.'
                    self.errors.append(
                        TypexError(errorText, arrobaCallNode.line,
                                   arrobaCallNode.col))

        arrobaCallNode.computed_type = get_type(method.return_type, TypexError)
        return arrobaCallNode.computed_type
Пример #17
0
class TypeBuilder:
    def __init__(self, context, errors):
        self.context = context
        self.currentType = None
        self.errors = errors

    @visitor.on('node')
    def visit(self, node):
        pass

    @visitor.when(ProgramNode)
    def visit(self, programNode):
        for declaration in programNode.declarations:
            self.visit(declaration)

    @visitor.when(ClassDeclarationNode)
    def visit(self, classDeclarationNode):
        try:
            self.currentType = self.context.get_type(
                classDeclarationNode.id,
                (classDeclarationNode.line, classDeclarationNode.col))
        except SemanticError as error:
            self.currentType = ErrorType()
            self.errors.append(error)

        if classDeclarationNode.parent is not None:
            if classDeclarationNode.parent in ['String', 'Int', 'Bool']:
                errorText = f'Class {classDeclarationNode.id} cannot inherit class {classDeclarationNode.parent}.'
                self.errors.append(
                    SemanticError(errorText, classDeclarationNode.line,
                                  classDeclarationNode.col))
            try:
                parent = self.context.get_type(
                    classDeclarationNode.parent,
                    (classDeclarationNode.parentLine,
                     classDeclarationNode.parentCol))
            except:
                errorText = f'Class {classDeclarationNode.id} inherits from an undefined class {classDeclarationNode.parent}'
                self.errors.append(
                    TypexError(errorText, classDeclarationNode.line,
                               classDeclarationNode.col))
                parent = None
            try:
                current = parent
                while current is not None:
                    if current.name == self.currentType.name:
                        errorText = f'Class {self.currentType.name}, or an ancestor of {self.currentType.name}, is involved in an inheritance cycle.'
                        raise SemanticError(errorText,
                                            classDeclarationNode.line,
                                            classDeclarationNode.col)
                    current = current.parent
            except SemanticError as error:
                parent = ErrorType()
                self.errors.append(error)

            self.currentType.set_parent(parent)

        for feature in classDeclarationNode.features:
            self.visit(feature)

    @visitor.when(FuncDeclarationNode)
    def visit(self, funcDeclarationNode):
        argsNames = []
        argsTypes = []
        for name, typex, line, col in funcDeclarationNode.params:
            if name in argsNames:
                errorText = f'Formal parameter {name} is multiply defined.'
                self.errors.append(SemanticError(errorText, line, col))

            argsNames.append(name)

            try:
                argType = self.context.get_type(typex, (line, col))
            except SemanticError:
                errorText = f'Class {typex} of formal parameter {typex} is undefined.'
                self.errors.append(TypexError(errorText, line, col))
                argType = ErrorType()

            argsTypes.append(argType)

        try:
            returnType = self.context.get_type(
                funcDeclarationNode.type,
                (funcDeclarationNode.typeLine, funcDeclarationNode.typeCol))
        except SemanticError:
            errorText = f'Undefined return type {funcDeclarationNode.type} in method {funcDeclarationNode.id}.'
            self.errors.append(
                TypexError(errorText, funcDeclarationNode.typeLine,
                           funcDeclarationNode.typeCol))
            returnType = ErrorType(
                (funcDeclarationNode.typeLine, funcDeclarationNode.typeCol))

        try:
            self.currentType.define_method(
                funcDeclarationNode.id, argsNames, argsTypes, returnType,
                (funcDeclarationNode.line, funcDeclarationNode.col))
        except SemanticError as error:
            self.errors.append(error)

    @visitor.when(AttrDeclarationNode)
    def visit(self, attrDeclarationNode):
        try:
            attrType = self.context.get_type(
                attrDeclarationNode.type,
                (attrDeclarationNode.line, attrDeclarationNode.col))
        except SemanticError:
            errorText = f'Class {attrDeclarationNode.type} of attribute {attrDeclarationNode.id} is undefined.'
            self.errors.append(
                TypexError(errorText, attrDeclarationNode.typeLine,
                           attrDeclarationNode.typeCol))
            attrType = ErrorType(
                (attrDeclarationNode.line, attrDeclarationNode.col))

        if attrDeclarationNode.id == 'self':
            errorText = f"'self' cannot be the name of an attribute."
            self.errors.append(
                SemanticError(errorText, attrDeclarationNode.line,
                              attrDeclarationNode.col))

        try:
            self.currentType.define_attribute(
                attrDeclarationNode.id, attrType,
                (attrDeclarationNode.line, attrDeclarationNode.col))
        except SemanticError as error:
            self.errors.append(error)
Пример #18
0
 def _get_type(self, ntype, pos):
     try:
         return self.context.get_type(ntype, pos)
     except SemanticError as e:
         self.errors.append(e)
         return ErrorType()