Beispiel #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())
Beispiel #2
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())
    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())
Beispiel #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)
Beispiel #5
0
    def visit(self, node: ast.SwitchCaseNode, scope: Scope):
        self.visit(node.expr, scope)
        types = []
        visited = set()
        for i, (identifier, type_name, expr) in enumerate(node.cases):
            new_scope = scope.create_child()
            try:
                if type_name != "SELF_TYPE":
                    new_scope.define_variable(identifier,
                                              self.context.get_type(type_name))
                else:
                    self.errors.append(err.INVALID_CASE_TYPE % type_name)
            except SemanticError:
                new_scope.define_variable(identifier, ErrorType())
                line, column = node.cases_positions[i]
                self.errors.append(err.UNDEFINED_TYPE_IN_BRANCH %
                                   (line, column, type_name))

            # Cannot be dublicate Branches types
            if type_name in visited:
                line, column = node.cases_positions[i]
                self.errors.append(err.DUPLICATE_BARNCH_IN_CASE %
                                   (line, column, type_name))

            visited.add(type_name)
            types.append(self.visit(expr, new_scope))

        return Type.multi_join(types)
Beispiel #6
0
    def visit(self, node: ast.SwitchCaseNode, scope: Scope):
        self.visit(node.expr, scope)

        defined_nodes = []
        not_defined_nodes = []
        case_nodes = []
        for _id, _type, _expr in node.cases:
            new_scope = scope.create_child()
            var_info = new_scope.define_variable(_id,
                                                 self.context.get_type(_type))
            self.variables[var_info] = VariableInfoNode(
                var_info.type, var_info)

            case_node = self.visit(_expr, new_scope)
            if isinstance(case_node, AtomNode):
                defined_nodes.append(case_node)
            else:
                not_defined_nodes.append(case_node)
            case_nodes.append(case_node)

        if any(e.type.name == "AUTO_TYPE" for e in case_nodes):
            if defined_nodes:
                t = Type.multi_join([x.type for x in defined_nodes])
                for x in not_defined_nodes:
                    self.graph.add_edge(AtomNode(t), x)
            case_of_node = CaseOfNode(self.context.get_type("AUTO_TYPE"),
                                      case_nodes)
            self.graph.add_node(case_of_node)
            return case_of_node
        return AtomNode(Type.multi_join([e.type for e in case_nodes]))
Beispiel #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)
Beispiel #8
0
    def visit(self, node: ast.ConditionalNode, scope: Scope):
        if_node = self.visit(node.if_expr, scope)

        if not isinstance(if_node, AtomNode):
            self.graph.add_edge(AtomNode(self.context.get_type("Bool")),
                                if_node)

        then_node = self.visit(node.then_expr, scope.create_child())
        else_node = self.visit(node.else_expr, scope.create_child())

        if isinstance(then_node, AtomNode) and isinstance(else_node, AtomNode):
            return AtomNode(then_node.type.join(else_node.type))

        conditional_node = ConditionalNode(self.context.get_type("AUTO_TYPE"),
                                           then_node, else_node)
        if isinstance(then_node,
                      AtomNode) and not isinstance(else_node, AtomNode):
            self.graph.add_edge(then_node, else_node)
        elif not isinstance(then_node, AtomNode) and isinstance(
                else_node, AtomNode):
            self.graph.add_edge(else_node, then_node)
        else:
            self.graph.add_edge(then_node, else_node)
            self.graph.add_edge(else_node, then_node)
            self.graph.add_edge(conditional_node, then_node)
            self.graph.add_edge(conditional_node, else_node)

        return conditional_node
    def visit(self, node: ast.WhileNode, scope: Scope):
        condition = self.visit(node.condition, scope)
        if condition != self.context.get_type('Bool'):
            self.errors.append(err.INCOMPATIBLE_TYPES %
                               (condition.name, 'Bool'))

        self.visit(node.body, scope.create_child())
        return self.context.get_type('Object')
    def visit(self, node: ast.ProgramNode, scope: Scope = None):
        if scope is None:
            scope = Scope()

        for elem in node.declarations:
            self.visit(elem, scope.create_child())

        return scope
Beispiel #11
0
    def visit(self, node: ast.WhileNode, scope: Scope):
        condition = self.visit(node.condition, scope)
        if condition != self.context.get_type("Bool"):
            self.errors.append(
                err.INCOMPATIBLE_TYPES %
                (node.line, node.column, condition.name, "Bool"))

        self.visit(node.body, scope.create_child())
        return self.context.get_type("Object")
    def visit(self, node: ast.ProgramNode, scope: Scope = None):
        if scope is None:
            scope = Scope()

        for item in node.declarations:
            self.visit(item, scope.create_child())

        # print(self.graph, '\n')
        self.graph.update_dependencies(default_type=self.context.get_type('Object'))
        # print(self.graph, '\n')
        InferenceTypeSubstitute(self.context, self.errors).visit(node, scope)
    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 in attrs:
            self.visit(attr, scope)

        for method in methods:
            self.visit(method, scope.create_child())
    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())
    def visit(self, node: ast.AssignNode, scope: Scope):
        var_info = scope.find_variable(node.id)

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

        if var_info is None:
            self.errors.append(err.VARIABLE_NOT_DEFINED %
                               (node.id, self.current_method.name))
        else:
            if not expr_type.conforms_to(var_info.type):
                self.errors.append(err.INCOMPATIBLE_TYPES %
                                   (expr_type.name, var_info.type.name))

        return expr_type
    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)
    def visit(self, node: ast.AssignNode, scope: Scope):
        var_info = scope.find_variable(node.id)

        expr_node = self.visit(node.expr, scope.create_child())

        if var_info is not None:
            if expr_node.type.name != 'AUTO_TYPE' and var_info.type.name == 'AUTO_TYPE':
                self.graph.add_edge(expr_node, self.variables[var_info])
            elif var_info.type.name != 'AUTO_TYPE' and expr_node.type.name == 'AUTO_TYPE':
                self.graph.add_edge(AtomNode(self.context.get_type(var_info.type.name)), expr_node)
            elif var_info.type.name == 'AUTO_TYPE' and expr_node.type.name == 'AUTO_TYPE':
                # Create a cycle
                self.graph.add_edge(expr_node, self.variables[var_info])
                self.graph.add_edge(self.variables[var_info], expr_node)
        else:
            pass

        return expr_node
    def visit(self, node: ast.SwitchCaseNode, scope: Scope):
        self.visit(node.expr, scope)
        types = []
        for _id, _type, _expr in node.cases:
            new_scope = scope.create_child()
            try:
                if _type != 'SELF_TYPE':
                    new_scope.define_variable(_id,
                                              self.context.get_type(_type))
                else:
                    self.errors.append(err.INVALID_CASE_TYPE % _type)
            except SemanticError as e:
                new_scope.define_variable(_id, ErrorType())
                self.errors.append(e.text)

            types.append(self.visit(_expr, new_scope))

        return Type.multi_join(types)
Beispiel #19
0
    def visit(self, node: ast.AssignNode, scope: Scope):
        var_info = scope.find_variable(node.id)

        if var_info.name == "self":
            self.errors.append(err.SELF_IS_READONLY % (node.line, node.column))

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

        if var_info is None:
            self.errors.append(
                err.UNDEFINED_VARIABLE %
                (node.line, node.column, node.id, self.current_method.name))
        else:
            if not expr_type.conforms_to(var_info.type):
                self.errors.append(err.INCOMPATIBLE_TYPES %
                                   (node.line, node.column, expr_type.name,
                                    var_info.type.name))

        return expr_type
    def visit(self, node: ast.SwitchCaseNode, scope: Scope):
        instance = self.visit(node.expr, scope)

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

        types = [(i, self.context.get_type(t)) for i, (_, t, _) in enumerate(node.cases)
                 if instance.type.conforms_to(self.context.get_type(t))]

        if not types:
            raise ExecutionError(err.CASE_OF_ERROR)

        (index, most_conformable_type), *types = types
        for i, t in types:
            if t.conforms_to(most_conformable_type):
                index, most_conformable_type = i, t

        child_scope = scope.create_child()
        name, typex, expr = node.cases[index]
        child_scope.define_variable(name, self.context.get_type(typex)).instance = instance
        return self.visit(expr, child_scope)
    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())
Beispiel #22
0
 def visit(self, node: ast.WhileNode, scope: Scope):
     self.visit(node.condition, scope)
     self.visit(node.body, scope.create_child())
     return AtomNode(self.context.get_type("Object"))
Beispiel #23
0
 def visit(self, node: ast.BlockNode, scope: Scope):
     child_scope = scope.create_child()
     result_node = None
     for expr in node.expressions:
         result_node = self.visit(expr, child_scope)
     return result_node
 def visit(self, node: ast.BlockNode, scope: Scope):
     child_scope = scope.create_child()
     return_type = ErrorType()
     for expr in node.expressions:
         return_type = self.visit(expr, child_scope)
     return return_type
 def visit(self, node: ast.WhileNode, scope: Scope):
     while self.visit(node.condition, scope).value:
         self.visit(node.body, scope.create_child())
     return VoidInstance()
    def visit(self, node: ast.ConditionalNode, scope: Scope):
        if_instance = self.visit(node.if_expr, scope)

        if if_instance.value:
            return self.visit(node.then_expr, scope.create_child())
        return self.visit(node.else_expr, scope.create_child())