Exemplo n.º 1
0
    def create_type(self, name, pos):
        if name in self.types:
            error_text = 'Classes may not be redefined.'
            raise SemanticError(error_text, *pos)
        typex = self.types[name] = Type(name, pos)

        return typex
Exemplo n.º 2
0
 def define_attribute(self, name: str, typex, pos):
     try:
         self.attributes[name]
     except KeyError:
         try:
             self.get_attribute(name, pos)
         except:
             self.attributes[name] = attribute = Attribute(
                 name, typex, len(self.attributes))
             return attribute
         else:
             error_msg = f'Attribute {name} is an attribute of an inherit class.'
             raise SemanticError(error_msg, *pos)
     else:
         error_msg = f'Attribute {name} is multiply defined in class.'
         raise SemanticError(error_msg, *pos)
Exemplo n.º 3
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)
Exemplo n.º 4
0
    def visit(self, node: FuncDeclarationNode):
        args_names = []
        args_types = []
        for name, type_ in node.params:
            if name in args_names:
                error_text = SemanticError.PARAMETER_MULTY_DEFINED % name
                self.errors.append(SemanticError(error_text, *type_.pos))
            args_names.append(name)

            try:
                arg_type = self.context.get_type(type_.value, type_.pos)
            except SemanticError:
                error_text = TypesError.PARAMETER_UNDEFINED % (type_.value,
                                                               type_.value)
                self.errors.append(TypesError(error_text, *type_.pos))
                arg_type = ErrorType()
            args_types.append(arg_type)

        try:
            return_type = self.context.get_type(node.type, node.type_pos)
        except SemanticError as e:
            error_text = TypesError.RETURN_TYPE_UNDEFINED % (node.type,
                                                             node.id)
            self.errors.append(TypesError(error_text, *node.type_pos))
            return_type = ErrorType(node.type_pos)

        try:
            self.current_type.define_method(node.id, args_names, args_types,
                                            return_type, node.pos)
        except SemanticError as e:
            self.errors.append(e)
Exemplo n.º 5
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)
Exemplo n.º 6
0
    def _check_args(self, meth: Method, scope: Scope, args, pos):
        arg_types = [self.visit(arg, scope) for arg in args]

        if len(arg_types) > len(meth.param_types):
            error_text = SemanticError.ARGUMENT_ERROR % meth.name
            self.errors.append(SemanticError(error_text, *pos))
        elif len(arg_types) < len(meth.param_types):
            for arg, arg_info in zip(meth.param_names[len(arg_types):],
                                     args[len(arg_types):]):
                error_text = SemanticError.ARGUMENT_ERROR % (meth.name)
                self.errors.append(SemanticError(error_text, *arg_info.pos))

        for atype, ptype, param_name in zip(arg_types, meth.param_types,
                                            meth.param_names):
            if not atype.conforms_to(ptype):
                error_text = TypesError.INCOSISTENT_ARG_TYPE % (
                    meth.name, atype.name, param_name, ptype.name)
                self.errors.append(TypesError(error_text, *pos))
Exemplo n.º 7
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)
 def visit(self, node: ClassDeclarationNode):
     if node.id in ['String', 'Int', 'Object', 'Bool', 'SELF_TYPE', 'IO']:
         error = SemanticError.REDEFINITION_ERROR % node.id
         self.errors.append(SemanticError(error, *node.pos))
     try:
         self.context.create_type(node.id, node.pos)
     except SemanticError as e:
         self.errors.append(e)
     # añade un como padre Object si este no tiene
     if not node.parent:
         node.parent = 'Object'
Exemplo n.º 9
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
Exemplo n.º 10
0
    def visit(self, funcDeclarationNode, scope):
        parent = self.currentType.parent
        self.currentMethod = self.currentType.get_method(
            funcDeclarationNode.id,
            (funcDeclarationNode.line, funcDeclarationNode.col))

        method = self.currentMethod
        if parent is not None:
            try:
                oldMethod = parent.get_method(
                    funcDeclarationNode.id,
                    (funcDeclarationNode.line, funcDeclarationNode.col))
                if oldMethod.return_type.name != method.return_type.name:
                    errorText = f'In redefined method {funcDeclarationNode.id}, return type {method.return_type.name} is different from original return type {oldMethod.return_type.name}.'
                    self.errors.append(
                        SemanticError(errorText, funcDeclarationNode.typeLine,
                                      funcDeclarationNode.typeCol))
                if len(method.param_names) != len(oldMethod.param_names):
                    errorText = f'Incompatible number of formal parameters in redefined method {funcDeclarationNode.id}.'
                    self.errors.append(
                        SemanticError(errorText, funcDeclarationNode.line,
                                      funcDeclarationNode.col))
                for (name, ptype, pline,
                     pcol), type1, type2 in zip(funcDeclarationNode.params,
                                                method.param_types,
                                                oldMethod.param_types):
                    if type1.name != type2.name:
                        errorText = f'In redefined method {name}, parameter type {type1.name} is different from original type {type2.name}.'
                        self.errors.append(
                            SemanticError(errorText, pline, pcol))
            except:
                pass

        result = self.visit(funcDeclarationNode.body, scope)
        returnType = get_type(method.return_type, self.currentType)

        if not result.conforms_to(returnType):
            errorText = f'Inferred return type {result.name} of method test does not conform to declared return type {returnType.name}.'
            self.errors.append(
                TypexError(errorText, funcDeclarationNode.typeLine,
                           funcDeclarationNode.typeCol))
Exemplo n.º 11
0
    def visit(self, node: ClassDeclarationNode):
        if Utils.IsBasicType(node.id):
            error_text = SemanticError.REDEFINITION_ERROR % node.id
            self.errors.append(SemanticError(*node.pos, error_text))

        try:
            self.context.create_type(node.id, node.pos)
        except SemanticError as exception:
            self.errors.append(exception)

        if not node.parent:
            node.parent = 'Object'
Exemplo n.º 12
0
    def define_method(self,
                      name: str,
                      param_names: list,
                      param_types: list,
                      return_type,
                      pos=(0, 0)):
        if name in self.methods:
            error_msg = f'Method {name} is multiply defined'
            raise SemanticError(error_msg, *pos)

        method = self.methods[name] = Method(name, param_names, param_types,
                                             return_type)
        return method
Exemplo n.º 13
0
    def visit(self, node: FuncDeclarationNode, scope: Scope):
        parent = self.current_type.parent

        self.current_method = method = self.current_type.get_method(
            node.id, node.pos)
        if parent is not None:
            try:
                old_meth = parent.get_method(node.id, node.pos)
                if old_meth.return_type.name != method.return_type.name:
                    error_text = SemanticError.WRONG_SIGNATURE_RETURN % (
                        node.id, method.return_type.name,
                        old_meth.return_type.name)
                    self.errors.append(
                        SemanticError(error_text, *node.type_pos))
                if len(method.param_names) != len(old_meth.param_names):
                    error_text = SemanticError.WRONG_NUMBER_PARAM % node.id
                    self.errors.append(SemanticError(error_text, *node.pos))
                for (name, param), type1, type2 in zip(node.params,
                                                       method.param_types,
                                                       old_meth.param_types):
                    if type1.name != type2.name:
                        error_text = SemanticError.WRONG_SIGNATURE_PARAMETER % (
                            name, type1.name, type2.name)
                        self.errors.append(
                            SemanticError(error_text, *param.pos))
            except SemanticError:
                pass

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

        return_type = get_type(method.return_type, self.current_type)

        if not result.conforms_to(return_type):
            error_text = TypesError.RETURN_TYPE_ERROR % (result.name,
                                                         return_type.name)
            self.errors.append(TypesError(error_text, *node.type_pos))
Exemplo n.º 14
0
    def visit(self, caseNode, scope):
        exprType = self.visit(caseNode.expr, scope)
        newScope = scope.expr_dict[caseNode]
        types = []
        checkDuplicate = []
        for option, optionScope in zip(caseNode.optionList, newScope.children):
            optionType = self.visit(option, optionScope)
            types.append(optionType)
            if option.type in checkDuplicate:
                errorText = f'Duplicate branch {option.type} in case statement.'
                self.errors.append(
                    SemanticError(errorText, option.typeLine, option.typeCol))
            checkDuplicate.append(option.type)

        caseNode.computed_type = get_common_basetype(types)
        return caseNode.computed_type
Exemplo n.º 15
0
    def visit(self, node: AttrDeclarationNode):
        try:
            attr_type = self.context.get_type(node.type, node.pos)
        except SemanticError as e:
            error_text = TypesError.ATTR_TYPE_UNDEFINED % (node.type, node.id)
            attr_type = ErrorType(node.type_pos)
            self.errors.append(TypesError(error_text, *node.type_pos))

        if node.id == 'self':
            self.errors.append(
                SemanticError(SemanticError.SELF_ATTR, *node.pos))

        try:
            self.current_type.define_attribute(node.id, attr_type, node.pos)
        except SemanticError as e:
            self.errors.append(e)
Exemplo n.º 16
0
    def visit(self, classDeclarationNode):
        if classDeclarationNode.id in [
                'Int', 'String', 'Bool', 'Object', 'SELF_TYPE', 'IO'
        ]:
            errorText = f'Redefinition of basic class {classDeclarationNode.id}'
            self.errors.append(
                SemanticError(errorText, classDeclarationNode.line,
                              classDeclarationNode.col))
        try:
            self.context.create_type(
                classDeclarationNode.id,
                (classDeclarationNode.line, classDeclarationNode.col))
        except SemanticError as error:
            self.errors.append(error)

        if not classDeclarationNode.parent:
            classDeclarationNode.parent = 'Object'
Exemplo n.º 17
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)
Exemplo n.º 18
0
    def visit(self, funcDeclarationNode, scope):
        parent = self.currentType.parent
        pnames = [param[0] for param in funcDeclarationNode.params]
        ptypes = [param[1] for param in funcDeclarationNode.params]

        self.currentMethod = self.currentType.get_method(
            funcDeclarationNode.id,
            (funcDeclarationNode.line, funcDeclarationNode.col))

        newScope = scope.create_child()
        scope.functions[funcDeclarationNode.id] = newScope

        for pname, ptype, pline, pcol in funcDeclarationNode.params:
            if pname == 'self':
                errorText = "'self' cannot be the name of a formal parameter."
                self.errors.append(SemanticError(errorText, pline, pcol))
            newScope.define_variable(pname,
                                     self._get_type(ptype, (pline, pcol)))

        self.visit(funcDeclarationNode.body, newScope)
Exemplo n.º 19
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)
Exemplo n.º 20
0
 def set_parent(self, parent):
     if type(self.parent) != ObjectType and self.parent is not None:
         error_msg = f'Parent type is already set for {self.name}.'
         raise SemanticError(error_msg, *self.pos)
     self.parent = parent
Exemplo n.º 21
0
 def get_type(self, name: str, pos=None):
     try:
         return self.types[name]
     except KeyError:
         error_text = f'Type {name} is not defined.'
         raise SemanticError(error_text, *pos)
Exemplo n.º 22
0
 def create_type(self, name: str, pos) -> Type:
     if name in self.types:
         error_text = SemanticError.TYPE_ALREADY_DEFINED
         raise SemanticError(error_text, *pos)
     typex = self.types[name] = Type(name, pos)
     return typex