Exemplo n.º 1
0
    def visit(self, node: ast.LetNode, scope: Scope):
        for _id, _type, _expr in node.declarations:
            try:
                # Define and get the var_info
                var_info = scope.define_variable(_id,
                                                 self.context.get_type(_type))
            except SemanticError:
                var_info = scope.define_variable(_id, ErrorType())
            var_info_node = self.variables[var_info] = VariableInfoNode(
                var_info.type, var_info)

            expr_node = (self.visit(_expr, scope.create_child())
                         if _expr is not None else None)

            if var_info.type.name == "AUTO_TYPE":
                # Create an edge or add an new node only if it is AutoType
                if expr_node is not None:
                    self.graph.add_edge(expr_node, var_info_node)
                    if expr_node.type.name == "AUTO_TYPE":
                        self.graph.add_edge(var_info_node, expr_node)
                else:
                    self.graph.add_node(var_info_node)
            elif expr_node is not None and expr_node.type.name == "AUTO_TYPE":
                self.graph.add_edge(var_info_node, expr_node)

        return self.visit(node.expr, scope.create_child())
    def visit(self, node: ast.MethodDeclarationNode, scope: Scope):
        self.current_method = self.current_type.get_method(node.id)

        # Define 'self' as a variable in the scope
        self_var = scope.define_variable('self', self.current_type)

        # Set the reference of 'self' variable info node
        self.variables[self_var] = VariableInfoNode(self.current_type, self_var)

        param_names = self.current_method.param_names
        param_types = self.current_method.param_types

        for i, (param_name, param_type) in enumerate(zip(param_names, param_types)):
            # Define parameter as local variable in current scope
            param_var_info = scope.define_variable(param_name, param_type)

            # Set the reference to the variable info node
            param_var_info_node = self.variables[param_var_info] = VariableInfoNode(param_type, param_var_info)

            if param_type.name == 'AUTO_TYPE':
                # Get the parameter node
                parameter_node = self.methods[self.current_type.name, self.current_method.name][0][i]

                # Create the cycle of two nodes between param_var_info_node and parameter_node
                self.graph.add_edge(param_var_info_node, parameter_node)
                self.graph.add_edge(parameter_node, param_var_info_node)

        # Solve the body of the method
        body_node = self.visit(node.body, scope)

        if self.current_method.return_type.name == 'AUTO_TYPE':
            # Get the return type node and add an edge body_node -> return_type_node
            return_type_node = self.methods[self.current_type.name, self.current_method.name][1]
            self.graph.add_edge(body_node, return_type_node)
Exemplo n.º 3
0
    def visit(self, node: ast.MethodCallNode, scope: Scope):
        obj_instance = self.visit(node.obj, scope)

        if isinstance(obj_instance, VoidInstance):
            raise ExecutionError(err.VOID_EXPRESSION)

        if obj_instance.type.conforms_to(self.context.get_type('Object')) and ('Object', node.id) in defaults:
            args = (obj_instance,) + tuple(self.visit(arg, scope) for arg in node.args) + (self.context,)
            return defaults['Object', node.id](*args)

        if obj_instance.type.conforms_to(self.context.get_type('IO')) and ('IO', node.id) in defaults:
            args = (obj_instance,) + tuple(self.visit(arg, scope) for arg in node.args) + (self.context,)
            return defaults['IO', node.id](*args)

        if obj_instance.type.conforms_to(self.context.get_type('String')) and ('String', node.id) in defaults:
            args = (obj_instance,) + tuple(self.visit(arg, scope) for arg in node.args) + (self.context,)
            return defaults['String', node.id](*args)

        new_scope = Scope()

        method = obj_instance.get_method(node.id)
        new_scope.define_variable('self', obj_instance.type).instance = obj_instance
        for name, typex, arg in zip(method.param_names, method.param_types, node.args):
            new_scope.define_variable(name, typex).instance = self.visit(arg, scope)

        self.call_stack.append(self.current_instance)
        self.current_instance = obj_instance
        output = self.visit(method.expr, new_scope)
        self.current_instance = self.call_stack.pop()
        return output
Exemplo n.º 4
0
    def visit(self, node: ast.AttrDeclarationNode, scope: Scope):
        if node.id == "self":
            self.errors.append(err.SELF_INVALID_ATTRIBUTE_ID %
                               (node.line, node.column))

        try:
            attr_type = (self.context.get_type(node.type)
                         if node.type != "SELF_TYPE" else self.current_type)
        except SemanticError:
            attr_type = ErrorType()

        scope.define_variable("self", self.current_type)

        # set the current attribute for analyze the body
        # and set the self.current_method variable to None
        self.current_attribute = self.current_type.get_attribute(node.id)
        self.current_method = None

        if node.expr is not None:
            expr_type = self.visit(node.expr, scope.create_child())
            if not expr_type.conforms_to(attr_type):
                line, column = node.expr_position
                self.errors.append(
                    err.INCOMPATIBLE_TYPES %
                    (line, column, expr_type.name, attr_type.name))
        scope.define_variable(node.id, attr_type)
Exemplo n.º 5
0
    def visit(self, node: ast.LetNode, scope: Scope):
        for i, (_id, _type, _expr) in enumerate(node.declarations):
            if _id == "self":
                line, column = node.declaration_names_positions[i]
                self.errors.append(err.SELF_USED_IN_LET % (line, column))
                continue

            try:
                var_static_type = (self.context.get_type(_type) if
                                   _type != "SELF_TYPE" else self.current_type)
            except SemanticError:
                line, column = node.declaration_types_positions[i]
                self.errors.append(err.UNDEFINED_TYPE % (line, column, _type))
                var_static_type = ErrorType()

            # if scope.is_local(_id):
            #     feature = self.current_method or self.current_attribute
            #     self.errors.append(
            #         err.LOCAL_ALREADY_DEFINED
            #         % (node.line, node.column, _id, feature.name)
            #     )
            # else:
            scope.define_variable(_id, var_static_type)

            expr_type = (self.visit(_expr, scope.create_child())
                         if _expr is not None else None)
            if expr_type is not None and not expr_type.conforms_to(
                    var_static_type):
                self.errors.append(err.INCOMPATIBLE_TYPES %
                                   (node.line, node.column, expr_type.name,
                                    var_static_type.name))

        return self.visit(node.expr, scope.create_child())
Exemplo n.º 6
0
    def visit(self, node: ast.AttrDeclarationNode, scope: Scope):
        if node.id == 'self':
            self.errors.append(err.SELF_INVALID_ATTRIBUTE_ID)

        attr_type = self.context.get_type(
            node.type) if node.type != 'SELF_TYPE' else self.current_type

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

        scope.define_variable(node.id, attr_type)
Exemplo n.º 7
0
    def visit(self, node: ast.AttrDeclarationNode, scope: Scope):
        # Solve the expression of the attribute
        expr_node = (self.visit(node.expr, scope.create_child())
                     if node.expr is not None else None)

        # Define attribute in the scope
        var_info = scope.define_variable(node.id,
                                         self.context.get_type(node.type))

        # Set and get the reference to the variable info node
        var_info_node = self.variables[var_info] = VariableInfoNode(
            self.context.get_type(node.type), var_info)

        if node.type == "AUTO_TYPE":
            # Get the reference to the attribute node
            attr_node = self.attributes[self.current_type.name, node.id]

            # If the expression node is not None then two edges are creates in the graph
            if expr_node is not None:
                self.graph.add_edge(expr_node, var_info_node)
                self.graph.add_edge(expr_node, attr_node)

            # Finally a cycle of two nodes is created between var_info_node and attr_node
            self.graph.add_edge(var_info_node, attr_node)
            self.graph.add_edge(attr_node, var_info_node)
Exemplo n.º 8
0
    def visit(self, node: ast.LetNode, scope: Scope):
        default = {'String': '', 'Int': 0, 'Bool': False}
        for _id, _type, _expr in node.declarations:

            instance = self.visit(_expr, scope.create_child()) if _expr is not None else VoidInstance()

            if _expr is None and _type in default:
                instance = Instance(self.context.get_type(_type), default[_type])

            scope.define_variable(_id, instance.type).instance = instance

        return self.visit(node.expr, scope.create_child())
Exemplo n.º 9
0
    def visit(self, node: ast.ClassDeclarationNode, scope: Scope):
        self.current_type = self.context.get_type(node.id)

        attrs = [
            feature for feature in node.features
            if isinstance(feature, ast.AttrDeclarationNode)
        ]
        methods = [
            feature for feature in node.features
            if isinstance(feature, ast.MethodDeclarationNode)
        ]

        for attr, attr_owner in self.current_type.all_attributes():
            if attr_owner != self.current_type:
                scope.define_variable(attr.name, attr.type)

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

        for method in methods:
            self.visit(method, scope.create_child())
Exemplo n.º 10
0
    def visit(self, node: ast.MethodDeclarationNode, scope: Scope):
        self.current_method = self.current_type.get_method(node.id)

        # Parameters can hide the attribute declaration, that's why we are not checking if there is defined,
        # instead we are checking for local declaration. Also it is checked that the static type of a parameter is
        # different of SELF_TYPE.

        scope.define_variable('self', self.current_type)

        for param_name, param_type in zip(self.current_method.param_names,
                                          self.current_method.param_types):
            if not scope.is_local(param_name):
                if param_type.name == 'SELF_TYPE':
                    self.errors.append(err.INVALID_PARAM_TYPE % 'SELF_TYPE')
                    scope.define_variable(param_name, ErrorType())
                else:
                    scope.define_variable(
                        param_name, self.context.get_type(param_type.name))
            else:
                self.errors.append(err.LOCAL_ALREADY_DEFINED %
                                   (param_name, self.current_method.name))

        return_type = self.context.get_type(
            node.return_type
        ) if node.return_type != 'SELF_TYPE' else self.current_type

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

        if not expr_type.conforms_to(return_type):
            self.errors.append(err.INCOMPATIBLE_TYPES %
                               (expr_type.name, return_type.name))
Exemplo n.º 11
0
    def visit(self, node: ast.LetNode, scope: Scope):
        for _id, _type, _expr in node.declarations:
            try:
                var_static_type = self.context.get_type(
                    _type) if _type != 'SELF_TYPE' else self.current_type
            except SemanticError as e:
                self.errors.append(e.text)
                var_static_type = ErrorType()

            if scope.is_local(_id):
                self.errors.append(err.LOCAL_ALREADY_DEFINED %
                                   (_id, self.current_method.name))
            else:
                scope.define_variable(_id, var_static_type)

            expr_type = self.visit(
                _expr, scope.create_child()) if _expr is not None else None
            if expr_type is not None and not expr_type.conforms_to(
                    var_static_type):
                self.errors.append(err.INCOMPATIBLE_TYPES %
                                   (expr_type.name, var_static_type.name))

        return self.visit(node.expr, scope.create_child())
Exemplo n.º 12
0
    def visit(self, node: ast.InstantiateNode, scope: Scope):
        default = None
        if node.lex == 'String':
            default = ''
        elif node.lex == 'Int':
            default = 0
        elif node.lex == 'Bool':
            default = False

        instance = Instance(self.context.get_type(node.lex), default)
        self.call_stack.append(self.current_instance)
        self.current_instance = instance
        fake_scope = Scope()
        for attr, _ in instance.type.all_attributes():
            attr_instance = self.visit(attr.expr, fake_scope) if attr.expr is not None else VoidInstance()
            fake_scope.define_variable(attr.name, attr.type).instance = attr_instance
            self.current_instance.set_attribute_instance(attr.name, attr_instance)
        self.current_instance = self.call_stack.pop()
        return instance