Beispiel #1
0
 def visit(self, node, scope):
     if node.type in build_in_types:
         self.errors.append(f'It cannot be initialized a {node.type} with the new keyword')
         node.computed_type = ErrorType()
     else:
         try:
             node_type = self.context.get_type(node.type)
         except SemanticError as ex:
             self.errors.append(ex.text)
             node_type = ErrorType()
             
         node.computed_type = node_type
Beispiel #2
0
    def visit(self, node, scope):
        self.visit(node.expr, scope)
        expr_type = node.expr.computed_type

        if scope.is_defined(node.id):
            var = scope.find_variable(node.id)
            node_type = var.type       
            
            if var.name == 'self':
                self.errors.append(SELF_IS_READONLY)
            else: 
                if IsAuto(node_type.name):
                    if not IsAuto(expr_type.name):
                        node.type = expr_type.name
                        scope.find_variable(node.id).type = expr_type
                        node.computed_type = expr_type
                else:
                    if not IsAuto(expr_type.name):
                        if not expr_type.conforms_to(node_type):
                            self.errors.append(INCOMPATIBLE_TYPES.replace('%s', expr_type.name, 1).replace('%s', node_type.name, 1))
                    else:
                        self.update(node.expr, scope, node_type)
                        node.computed_type = node.expr.computed_type
        else:
            self.errors.append(VARIABLE_NOT_DEFINED.replace('%s', node.id, 1).replace('%s', self.current_method.name, 1))
            node.computed_type = ErrorType()
Beispiel #3
0
 def visit(self, node, scope):
     self.visit(node.expr, scope)
     if not (IsAuto(node.expr.computed_type.name) or node.expr.computed_type.name != 'Int'):
         self.errors.append("Complement works only for Int")
         node.computed_type = ErrorType()
     else:
         node.computed_type = self.context.get_type('Int')
Beispiel #4
0
    def visit(self, node, scope):
        obj_type = self.current_type
        
        try:
            obj_method = obj_type.get_method(node.id)
            
            if len(node.args) == len(obj_method.param_types):
                for idx, arg in enumerate(node.args):
                    self.visit(arg, scope)
                    arg_type = arg.computed_type
                    param_type = obj_method.param_types[idx]
                    
                    if IsAuto(param_type.name):
                    	if not IsAuto(arg_type.name):
                    		obj_method.param_types[idx] = arg_type
                    else:
                    	if IsAuto(arg_type.name):
                    		self.update(arg, scope, param_type)
                    	else:
		                    if not arg_type.conforms_to(param_type):
		                        self.errors.append(INCOMPATIBLE_TYPES.replace('%s', arg_type.name, 1).replace('%s', param_type.name, 1))
            else:
                self.errors.append(f'Method "{obj_method.name}" of "{obj_type.name}" only accepts {len(obj_method.param_types)} argument(s)')
            
            node_type = obj_method.return_type
        except SemanticError as ex:
            self.errors.append(ex.text)
            node_type = ErrorType()
            
        node.computed_type = node_type
Beispiel #5
0
 def visit(self, node, scope):
     self.visit(node.expr, scope)
     if not (IsAuto(node.expr.computed_type.name) or node.expr.computed_type.name != 'Bool'):
         self.errors.append("Not operator works only for Bool")
         node.computed_type = ErrorType()
     else:
         node.computed_type = self.context.get_type('Bool')
Beispiel #6
0
    def visit(self, node, scope):
        node.scope = scope
        try:
            node_type = self.context.get_type(node.type) if node.type != 'SELF_TYPE' else self.current_type
        except SemanticError as ex:
            self.errors.append(ex.text)
            node_type = ErrorType()
          
        if not scope.is_local(node.id):
            scope.define_variable(node.id, node_type)
        else:
            self.errors.append(LOCAL_ALREADY_DEFINED.replace('%s', node.id, 1).replace('%s', self.current_method.name, 1))
        
        if not node.expr:
            node.computed_type = node_type
            return

        self.visit(node.expr, scope)
        expr_type = node.expr.computed_type

        if IsAuto(node_type.name):
        	if not IsAuto(expr_type.name):
        		node.type = expr_type.name
        		scope.find_variable(node.id).type = expr_type
        		node.computed_type = expr_type
        else:
            if not IsAuto(expr_type.name):
                if not expr_type.conforms_to(node_type):
                    self.errors.append(INCOMPATIBLE_TYPES.replace('%s', expr_type.name, 1).replace('%s', node_type.name, 1))
            else:
                self.update(node.expr, scope, node_type)
                node.computed_type = node.expr.computed_type
Beispiel #7
0
    def visit(self, node, scope):
        self.visit(node.obj, scope)
        obj_type = node.obj.computed_type
        
        if node.type:
            try:
                if IsAuto(node.type):
                    raise SemanticError('Is not possible to use AUTO_TYPE in a cast')
                if not obj_type.conforms_to(self.context.get_type(node.type)):
                    self.errors.append(INCOMPATIBLE_TYPES.replace('%s', obj_type.name, 1).replace('%s', node.type, 1))
            except SemanticError as ex:
                self.errors.append(ex.text)

        try:
            if node.type:
                obj_method = self.context.get_type(node.type).get_method(node.id)
            else:
                obj_method = obj_type.get_method(node.id)
            
            if len(node.args) == len(obj_method.param_types):
                for arg, param_type in zip(node.args, obj_method.param_types):
                    self.visit(arg, scope)
                    arg_type = arg.computed_type
                    
                    if not (IsAuto(arg_type.name) or arg_type.conforms_to(param_type)):
                        self.errors.append(INCOMPATIBLE_TYPES.replace('%s', arg_type.name, 1).replace('%s', param_type.name, 1))
            else:
                self.errors.append(f'Method "{obj_method.name}" of "{obj_type.name}" only accepts {len(obj_method.param_types)} argument(s)')
            
            node_type = obj_method.return_type
        except SemanticError as ex:
            self.errors.append(ex.text)
            node_type = ErrorType()
            
        node.computed_type = node_type
Beispiel #8
0
 def visit(self, node, scope):
     try:
         node_type = self.context.get_type(node.type)
     except SemanticError as ex:
         self.errors.append(ex.text)
         node_type = ErrorType()
         
     node.computed_type = node_type
Beispiel #9
0
 def visit(self, node, scope):
     if scope.is_defined(node.lex):
         var = scope.find_variable(node.lex)
         node_type = var.type       
     else:
         self.errors.append(VARIABLE_NOT_DEFINED.replace('%s', node.lex, 1).replace('%s', self.current_method.name, 1))
         node_type = ErrorType()
     
     node.computed_type = node_type
Beispiel #10
0
 def visit(self, node):
     try:
         attr_type = self.context.get_type(node.type) if node.type != 'SELF_TYPE' else self.current_type
     except SemanticError as ex:
         self.errors.append(ex.text)
         attr_type = ErrorType()
         
     try:
         self.current_type.define_attribute(node.id, attr_type)
     except SemanticError as ex:
         self.errors.append(ex.text)
Beispiel #11
0
 def visit(self, node):
     arg_names, arg_types = [], []
     for idx, typex in node.params:
         try:
             arg_type = self.context.get_type(typex) if node.type != 'SELF_TYPE' else self.current_type
         except SemanticError as ex:
             self.errors.append(ex.text)
             arg_type = ErrorType()
             
         arg_names.append(idx)
         arg_types.append(arg_type)
     
     try:
         ret_type = self.context.get_type(node.type) if node.type != 'SELF_TYPE' else self.current_type
     except SemanticError as ex:
         self.errors.append(ex.text)
         ret_type = ErrorType()
     
     try:
         self.current_type.define_method(node.id, arg_names, arg_types, ret_type)
     except SemanticError as ex:
         self.errors.append(ex.text)
Beispiel #12
0
 def visit(self, node, scope):
     self.visit(node.left, scope)
     left_type = node.left.computed_type
     
     self.visit(node.right, scope)
     right_type = node.right.computed_type
     
     if not (IsAuto(left_type.name) or left_type.conforms_to(IntType())) or not (IsAuto(right_type.name) or right_type.conforms_to(IntType())):
         self.errors.append(INVALID_OPERATION.replace('%s', left_type.name, 1).replace('%s', right_type.name, 1))
         node_type = ErrorType()
     else:
         node_type = IntType()
         
     node.computed_type = node_type
Beispiel #13
0
    def visit(self, node, scope):
        self.visit(node.expr, scope)
        has_auto = has_error = False
        
        types_list = []
        for case in node.branches:
            self.visit(case.expr, scope)
            has_auto |= IsAuto(case.expr.computed_type.name)
            has_error |= case.expr.computed_type.name == '<error>'
            types_list.append(case.expr.computed_type)

        if has_error:
            node.computed_type = ErrorType()
        elif has_auto:
            node.computed_type = self.context.get_type('AUTO_TYPE')
        else:
            node.computed_type = LCA(types_list, self.context)
Beispiel #14
0
    def visit(self, node, scope):
        node.scope = scope
        if node.expr:
            self.visit(node.expr, scope)
            if IsAuto(node.type):
                if not IsAuto(node.expr.computed_type.name):
                    scope.find_variable(node.id).type = node.expr.computed_type
            else:
                if IsAuto(node.expr.computed_type.name):
                    self.update(node.expr, scope, node.type)
                else:
                    if not node.expr.computed_type.conforms_to(node.computed_type):
                        self.errors.append(INCOMPATIBLE_TYPES.replace('%s', node.expr.computed_type.name, 1).replace('%s', node.computed_type.name, 1))
                        node.computed_type = ErrorType()
                        return

            node.computed_type = node.expr.computed_type			
Beispiel #15
0
    def update(self, node, scope, ntype):
        if IsAuto(node.if_body.computed_type.name):
            self.update(node.if_body, scope, ntype)

        node.computed_type = node.if_body.computed_type

        if node.else_body:
            if IsAuto(node.else_body.computed_type.name):
                self.update(node.else_body, scope, ntype)

            names = [node.if_body.computed_type.name, node.else_body.computed_type.name]
            if 'AUTO_TYPE' not in names and '<error>' not in names:
                node.computed_type = LCA([node.if_body.computed_type, node.else_body.computed_type], self.context)
            else:
                if '<error>' in names:
                    node.computed_type = ErrorType()
                else:
                    node.computed_type = self.context.get_type('AUTO_TYPE')
Beispiel #16
0
    def visit(self, node, scope):
        self.visit(node.condition, scope)
        expr_type = node.condition.computed_type

        if not expr_type.name in ['Bool', 'AUTO_TYPE']:
            self.errors.append(CONDITION_NOT_BOOL.replace('%s', 'If', 1).replace('%s', expr_type.name, 1))

        self.visit(node.if_body, scope)
        node.computed_type = node.if_body.computed_type
        
        if node.else_body:
            self.visit(node.else_body, scope)
            if IsAuto(node.if_body.computed_type.name) or IsAuto(node.else_body.computed_type.name):
                node.computed_type = self.context.get_type('AUTO_TYPE')
            elif '<error>' in [node.if_body.computed_type.name, node.else_body.computed_type.name]:
                node.computed_type = ErrorType()
            else:
                node.computed_type = LCA([node.if_body.computed_type, node.else_body.computed_type], self.context)
Beispiel #17
0
    def visit(self, node, scope):
        try:
            node_type = self.context.get_type(node.type) if node.type != 'SELF_TYPE' else self.current_type
        except SemanticError as ex:
            self.errors.append(ex.text)
            node_type = ErrorType()

        if not node.expr:
            node.computed_type = node_type 
            return

        self.visit(node.expr, scope)
        expr_type = node.expr.computed_type

        if not (IsAuto(expr_type.name) or expr_type.conforms_to(node_type)):
            self.errors.append(INCOMPATIBLE_TYPES.replace('%s', expr_type.name, 1).replace('%s', node_type.name, 1))
        
        node.computed_type = node_type 
Beispiel #18
0
    def visit(self, node, scope):
        self.visit(node.condition, scope)
        expr_type = node.condition.computed_type

        if IsAuto(expr_type.name):
            self.update(node.condition, scope, self.context.get_type('Bool'))
            expr_type = node.condition.computed_type
        if expr_type.name not in ['Bool', 'AUTO_TYPE']:
            self.errors.append(CONDITION_NOT_BOOL.replace('%s', 'If', 1).replace('%s', expr_type.name, 1))

        self.visit(node.if_body, scope)
        node.computed_type = node.if_body.computed_type

        if node.else_body:
            self.visit(node.else_body, scope)
            names = [node.if_body.computed_type.name, node.else_body.computed_type.name]
            if 'AUTO_TYPE' not in names and '<error>' not in names:
                node.computed_type = LCA([node.if_body.computed_type, node.else_body.computed_type], self.context)
            else:
                if '<error>' in names:
                    node.computed_type = ErrorType()
                else:
                    node.computed_type = self.context.get_type('AUTO_TYPE')
Beispiel #19
0
class InferenceVisitor(object):
    def __init__(self, context, errors=[]):
        self.context = context
        self.current_type = None
        self.current_method = None
        self.errors = errors

    @visitor.on('node')
    def update(self, node, scope, ntype):
    	pass

    @visitor.when(Node)
    def update(self, node, scope, ntype):
    	pass

    @visitor.when(FunctionCallNode)
    def update(self, node, scope, ntype):
        obj_type = node.obj.computed_type

        obj_type.get_method(node.id).return_type = ntype
        node.computed_type = ntype

    @visitor.when(MemberCallNode)
    def update(self, node, scope, ntype):
        obj_type = self.current_type

        obj_type.get_method(node.id).return_type = ntype
        node.computed_type = ntype

    @visitor.when(AttrDeclarationNode)
    def update(self, node, scope, ntype):
    	scope.find_variable(node.id).type = ntype
    	node.computed_type = ntype

    @visitor.when(IdNode)
    def update(self, node, scope, ntype):
    	scope.find_variable(node.lex).type = ntype
    	node.computed_type = ntype

    @visitor.when(IfThenElseNode)
    def update(self, node, scope, ntype):
        if IsAuto(node.if_body.computed_type.name):
            self.update(node.if_body, scope, ntype)

        node.computed_type = node.if_body.computed_type

        if node.else_body:
            if IsAuto(node.else_body.computed_type.name):
                self.update(node.else_body, scope, ntype)

            names = [node.if_body.computed_type.name, node.else_body.computed_type.name]
            if 'AUTO_TYPE' not in names and '<error>' not in names:
                node.computed_type = LCA([node.if_body.computed_type, node.else_body.computed_type], self.context)
            else:
                if '<error>' in names:
                    node.computed_type = ErrorType()
                else:
                    node.computed_type = self.context.get_type('AUTO_TYPE')
    
    @visitor.when(CaseOfNode)
    def update(self, node, scope, ntype):
        types_list = []
        has_auto = has_error = False

        for case in node.branches:
            if IsAuto(case.computed_type.name):
                self.update(branch, scope, ntype)
                has_auto |= IsAuto(case.expr.computed_type.name)
                has_error |= case.expr.computed_type.name == '<error>'
                types_list.append(case.expr.computed_type)
        
        if has_error:
            node.computed_type = ErrorType()
        elif has_auto:
            node.computed_type = self.context.get_type('AUTO_TYPE')
        else:
            node.computed_type = LCA(types_list)