def visit(self, node: cool_ast.CaseNode, scope: Scope):
        self.visit(node.case_expr, scope.create_child())
        case_types = []
        var_case_types = []
        for option in node.options:
            child_scope = scope.create_child()
            try:
                option_type = self.context.get_type(option.type)
            except SemanticError as error:
                self.errors.append(str(error))
                option_type = ErrorType()
            if option_type.name == 'SELF_TYPE':
                option_type = self.current_type
                self.errors.append(FORBIDDEN_SELF_TYPE %
                                   self.current_type.name)
            child_scope.define_variable(option.id, option_type)
            typex = self.visit(option.expr, child_scope)
            if typex.name == 'SELF_TYPE':
                typex = self.current_type
            case_types.append(typex)
            var_case_types.append(option_type)

        if len(var_case_types) != len(set(var_case_types)):
            self.errors.append(
                'The variables declared on each branch of a case must all have distinct types. '
            )

        return Type.join_types(*case_types)
Esempio n. 2
0
 def visit(self, node: cool_ast.MethodDeclarationNode,
           scope: Scope) -> None:
     function = self.functions.get_function(self.current_type,
                                            self.current_method.name)
     for param_type, param in zip(function.params_types, node.params):
         scope.define_variable(param.id, param_type)
     body_type = self.visit(node.body, scope)
     self.unify(function.return_type, body_type)
    def visit(self, node: cool_ast.LoopNode, scope: Scope):
        condition_type = self.visit(node.condition, scope.create_child())
        bool_type = self.context.get_type('Bool')
        if condition_type != bool_type:
            self.errors.append(INCOMPATIBLE_TYPES %
                               (condition_type.name, bool_type.name))

        self.visit(node.body, scope.create_child())
        return self.context.get_type('Object')
    def visit(self, node: cool_ast.ConditionalNode, scope: Scope):
        condition_type = self.visit(node.condition, scope.create_child())
        bool_type = self.context.get_type('Bool')
        if condition_type != bool_type:
            self.errors.append(INCOMPATIBLE_TYPES %
                               (condition_type.name, bool_type.name))

        then_type = self.visit(node.then_body, scope.create_child())
        else_type = self.visit(node.else_body, scope.create_child())

        return Type.join_types(then_type, else_type)
Esempio n. 5
0
 def visit(self, node: cool_ast.VarDeclarationNode, scope: Scope) -> Type:
     try:
         var_type = self.context.get_type(node.typex)
     except SemanticError:
         return TypeVariable()
     if node.typex == "AUTO_TYPE":
         var_type = TypeVariable()
     if node.expr is not None:
         expr_type = self.visit(node.expr, scope)
         self.unify(var_type, expr_type)
     scope.define_variable(node.id, var_type)
     return var_type
 def visit(self, node: cool_ast.VariableNode, scope: Scope):
     if scope.is_defined(node.lex):
         var = scope.find_variable(node.lex)
         return var.type
     try:
         att = self.current_type.get_attribute(node.lex)
         if att.type.name == 'SELF_TYPE':
             return self.current_type
         return att.type
     except SemanticError:
         self.errors.append(VARIABLE_NOT_DEFINED %
                            (node.lex, self.current_type.name))
         return ErrorType()
 def visit(self, node: cool_ast.AssignNode, scope: Scope):
     expr_type = self.visit(node.expr, scope)
     if scope.is_defined(node.id):
         var_type = scope.find_variable(node.id).type
     else:
         try:
             att = self.current_type.get_attribute(node.id)
             var_type = att.type
         except SemanticError:
             self.errors.append(VARIABLE_NOT_DEFINED %
                                (node.id, self.current_method.name))
             var_type = ErrorType()
     if not expr_type.conforms_to(var_type):
         self.errors.append(INCOMPATIBLE_TYPES %
                            (expr_type.name, var_type.name))
     return expr_type
Esempio n. 8
0
    def visit(self, node: cool_ast.ClassDeclarationNode, scope: Scope) -> None:
        attrs = [
            feature for feature in node.features
            if isinstance(feature, cool_ast.AttrDeclarationNode)
        ]
        methods = [
            feature for feature in node.features
            if isinstance(feature, cool_ast.MethodDeclarationNode)
        ]

        scope.define_variable('self', self.current_type)
        for attr in attrs:
            self.visit(attr, scope)

        for method in methods:
            self.current_method = self.current_type.get_method(method.id)
            self.visit(method, scope.create_child())
    def visit(self, node: cool_ast.VarDeclarationNode, scope: Scope):
        try:
            var_type = self.context.get_type(node.typex)
        except SemanticError as error:
            self.errors.append(str(error))
            var_type = ErrorType()

        if scope.is_defined(node.id):
            self.errors.append(LOCAL_ALREADY_DEFINED %
                               (node.id, self.current_method.name))
        else:
            scope.define_variable(node.id, var_type)

        expr_type = self.visit(node.expr, scope)
        if not expr_type.conforms_to(var_type):
            self.errors.append(INCOMPATIBLE_TYPES %
                               (expr_type.name, var_type.name))
Esempio n. 10
0
    def visit(self, node: cool_ast.VariableNode, scope: Scope) -> Type:
        var_info = scope.find_variable(node.lex)
        if var_info is not None:
            return var_info.type
        var_type = self.attributes.get_attribute(self.current_type, node.lex)

        if var_type is None:
            return TypeVariable()
        return var_type
Esempio n. 11
0
    def visit(self, node: cool_ast.AssignNode, scope: Scope) -> Type:
        expr_type = self.visit(node.expr, scope)
        var_info = scope.find_variable(node.id)
        if var_info is None:
            var_type = self.attributes.get_attribute(self.current_type,
                                                     node.id)
            if var_type is None:
                return TypeVariable()
        else:
            var_type = var_info.type

        self.unify(var_type, expr_type)
        return expr_type
Esempio n. 12
0
    def visit(self, node: cool_ast.MethodDeclarationNode, scope: Scope):
        try:
            self.current_method = self.current_type.get_method(node.id)
        except SemanticError as error:
            self.errors.append(str(error))
            return
        try:
            parent_method = self.current_type.get_method(node.id)
            if parent_method.return_type != self.current_method.return_type:
                self.errors.append(WRONG_SIGNATURE %
                                   (node.id, self.current_type.parent.name))

            if len(parent_method.param_types) != len(
                    self.current_method.param_types):
                self.errors.append(WRONG_SIGNATURE %
                                   (node.id, self.current_type.parent.name))
            else:
                for i, j in zip(parent_method.param_types,
                                self.current_method.param_types):
                    if i != j:
                        self.errors.append(
                            WRONG_SIGNATURE %
                            (node.id, self.current_type.parent.name))
        except SemanticError:
            pass

        child_scope = scope.create_child()
        for param in node.params:
            try:
                typex = self.context.get_type(param.typex)
            except SemanticError as error:
                self.errors.append(str(error))
                return
            if typex.name == 'SELF_TYPE':
                self.errors.append(FORBIDDEN_SELF_TYPE %
                                   self.current_type.name)
            child_scope.define_variable(param.id, typex)

        expr_type = self.context.get_type('Void')
        return_type = self.current_method.return_type
        if return_type.name == 'SELF_TYPE':
            return_type = self.current_type

        if node.body is not None:
            expr_type = self.visit(node.body, child_scope)
        if self.current_method.return_type != self.context.get_type('Void') \
                and not expr_type.conforms_to(return_type):
            self.errors.append(
                INCOMPATIBLE_TYPES %
                (expr_type.name, self.current_method.return_type.name))
Esempio n. 13
0
    def visit(self, node: cool_ast.VarDeclarationNode, scope: Scope,
              index: int) -> int:
        if node.typex == 'AUTO_TYPE':
            var_info = scope.find_variable(node.id)
            if isinstance(var_info.type, TypeVariable):
                try:
                    node.typex = self.subst[var_info.type.name].name
                    self.change = True
                except KeyError:
                    pass
            else:
                node.typex = var_info.type.name

        if node.expr is not None:
            index = self.visit(node.expr, scope, index)
        return index
Esempio n. 14
0
    def visit(self, node: cool_ast.MethodCallNode, scope: Scope):
        object_type = typex = self.current_type
        if node.expr is not None:
            object_type = self.visit(node.expr, scope)
            if object_type.name == 'SELF_TYPE':
                object_type = self.current_type
            if node.type is not None:
                try:
                    node_type = self.context.get_type(node.type)
                except SemanticError as error:
                    self.errors.append(str(error))
                    return ErrorType()
                if node_type.name == 'SELF_TYPE':
                    node_type = object_type
                if object_type.conforms_to(node_type):
                    object_type = node_type
                else:
                    self.errors.append(f'Invalid method call')
        elif node.type is not None:
            self.errors.append('Invalid method call')
        try:
            typex = object_type
            if object_type.name == 'SELF_TYPE':
                typex = self.current_type
            method = typex.get_method(node.id)
            return_type = method.return_type
            if return_type.name == 'SELF_TYPE':  # and object_type.name != 'SELF_TYPE':
                return_type = object_type

            if len(method.param_types) != len(node.args):
                self.errors.append(UNEXPECTED_NUMBER_OF_ARGUMENT %
                                   (self.current_type.name, node.id))

            arg_types = []
            for arg in node.args:
                arg_types.append(self.visit(arg, scope.create_child()))
            for arg_type, typex in zip(arg_types, method.param_types):
                if not arg_type.conforms_to(typex):
                    self.errors.append(
                        f'Incorrect argument type in method {self.current_type.name}.{node.id}:'
                        + INCOMPATIBLE_TYPES % (arg_type.name, typex.name))
        except SemanticError:
            return_type = ErrorType()
            self.errors.append(METHOD_NOT_DEFINED % (node.id, typex.name))
        return return_type
Esempio n. 15
0
    def visit(self, node: cool_ast.ConditionalNode, scope: Scope) -> Type:
        bool_type = self.context.get_type('Bool')
        cond_type = self.visit(node.condition, scope)
        self.unify(bool_type, cond_type)
        then_type = self.visit(node.then_body, scope.create_child())
        else_type = self.visit(node.else_body, scope.create_child())

        if isinstance(then_type, TypeVariable) and isinstance(
                else_type, TypeVariable):
            return then_type

        if isinstance(then_type, TypeVariable):
            self.unify(then_type, else_type)
            return else_type

        if isinstance(else_type, TypeVariable):
            self.unify(else_type, then_type)
            return then_type

        return Type.join_types(then_type, else_type)
Esempio n. 16
0
    def visit(self, node: cool_ast.CaseNode, scope: Scope) -> Type:
        self.visit(node.case_expr, scope)
        types = []
        for option in node.options:
            child_scope = scope.create_child()
            try:
                option_type = self.context.get_type(option.type)
            except SemanticError:
                option_type = TypeVariable()

            if option_type.name == 'AUTO_TYPE':
                option_type = TypeVariable()

            child_scope.define_variable(option.id, option_type)
            option_expr_type = self.visit(option.expr, child_scope)

            if option_expr_type.name == 'SELF_TYPE':
                option_expr_type = self.current_type

            types.append(option_expr_type)

        if all(isinstance(typex, TypeVariable) for typex in types):
            return types[0]

        known_types = []
        unknown_types = []

        for case_type in types:
            if isinstance(case_type, TypeVariable):
                unknown_types.append(case_type)
            else:
                known_types.append(case_type)

        typex = Type.join_types(*known_types)
        for case_type in unknown_types:
            self.unify(case_type, typex)

        return typex
Esempio n. 17
0
    def visit(self, node: cool_ast.LetNode, scope: Scope):
        child_scope = scope.create_child()
        for var in node.var_decl_list:
            try:
                var_type = self.context.get_type(var.typex)
            except SemanticError as error:
                self.errors.append(str(error))
                var_type = ErrorType()
            if child_scope.is_local(var.id):
                self.errors.append(LOCAL_ALREADY_DEFINED %
                                   (var.id, self.current_method.name))
            else:
                child_scope.define_variable(var.id, var_type)
            if var.expr is not None:
                var_expr_type = self.visit(var.expr, child_scope)
                if not var_expr_type.conforms_to(var_type):
                    self.errors.append(INCOMPATIBLE_TYPES %
                                       (var_expr_type.name, var_type.name))

        return_type = self.context.get_type('Void')
        if node.in_expr is not None:
            return_type = self.visit(node.in_expr, child_scope)

        return return_type
Esempio n. 18
0
            parse, operations = parser(tokens, get_shift_reduce=True)

            if show_parsing:
                st.markdown('### Parsing')
                st.write([str(prod) + '\n' for prod in reversed(parse)])

            ast = evaluate_reverse_parse(parse, operations, tokens)
        except ParsingException as syntax_error:
            ast = None
            st.error(f"{syntax_error}")

        if ast is not None:
            formatter = FormatVisitor()
            errors = []
            context = Context()
            scope = Scope()

            collector = TypeCollector(context, errors)
            collector.visit(ast)
            builder = TypeBuilder(context, errors)
            builder.visit(ast)

            if show_ast:
                st.markdown('### Abstract Syntax Tree')
                st.text(formatter.visit(ast, 1))
            if show_context:
                st.markdown('### Context')
                st.text(builder.context)

            # Types Inference
            #######################################################
Esempio n. 19
0
 def visit(self, node: cool_ast.BlocksNode, scope: Scope) -> Type:
     child_scope = scope.create_child()
     expr_type = self.context.get_type('Void')
     for expr in node.expr_list:
         expr_type = self.visit(expr, child_scope)
     return expr_type
Esempio n. 20
0
 def visit(self, node: cool_ast.LoopNode, scope: Scope) -> Type:
     cond_type = self.visit(node.condition, scope)
     body_type = self.visit(node.body, scope.create_child())
     self.unify(self.context.get_type('Bool'), cond_type)
     return self.context.get_type('Object')
Esempio n. 21
0
    def visit(self, node: cool_ast.ClassDeclarationNode, scope: Scope):
        self.current_type: Type = self.context.get_type(node.id)
        scope.define_variable('self', self.current_type)

        for feature in node.features:
            self.visit(feature, scope)
Esempio n. 22
0
 def visit(self, node: cool_ast.BlocksNode, scope: Scope):
     return_type = self.context.get_type('Void')
     for expr in node.expr_list:
         return_type = self.visit(expr, scope.create_child())
     return return_type
Esempio n. 23
0
 def visit(self, node: cool_ast.ProgramNode, scope: Scope) -> None:
     for class_decl in node.declarations:
         self.current_type = self.context.get_type(class_decl.id)
         self.visit(class_decl, scope.create_child())
Esempio n. 24
0
 def visit(self, node: cool_ast.ProgramNode, scope: Scope = None):
     if scope is None:
         scope = Scope()
     for declaration in node.declarations:
         self.visit(declaration, scope.create_child())
     return scope
Esempio n. 25
0
 def visit(self, node: cool_ast.AttrDeclarationNode, scope: Scope) -> None:
     if node.expression is not None:
         expr_type = self.visit(node.expression, scope.create_child())
         attr_type = self.attributes.get_attribute(self.current_type,
                                                   node.id)
         self.unify(attr_type, expr_type)
Esempio n. 26
0
 def visit(self, node: cool_ast.LetNode, scope: Scope):
     child_scope = scope.create_child()
     for var in node.var_decl_list:
         var_type = self.visit(var, child_scope)
     body_type = self.visit(node.in_expr, child_scope)
     return body_type