def visit(self, node, scope: Scope): try: node_type = self.context.get_type( node.type) if node.type != "SELF_TYPE" else self.current_type except SemanticError as err: self.errors.append(err.text) node_type = [ErrorType()] self.check_id(node.id) if node.define and scope.is_local(node.id): var = scope.find_variable(node.id) var.type = self.all_pos_types(var.type) if node.expr: self.visit(node.expr, scope) expr_type = node.expr.computed_type node_type = self.all_pos_types(node_type) error_expr = expr_type.copy() error_type = node_type.copy() self.establish_conform(expr_type, node_type) if len(expr_type) * len(node_type) == 0: self.AddError( f"Declaring Let Variable {node.id}. Incompatible types between possible declared types (" + ", ".join([typex.name for typex in error_type]) + ") and possible expression types (" + ", ".join([typex.name for typex in error_expr]) + ")") node_type = [ErrorType()] node.computed_type = node_type
def visit(self, node, scope=None, type_suggested=None): self.changed = False self.errors = [] scope = Scope() for declaration in node.declarations: self.visit(declaration, scope.create_child()) return scope, self.errors
def defined_info(name: str, scope: Scope, only_local=True): if only_local and not scope.is_local(name): return f"<Variable \"{name}\" not defined locally>" var = scope.find_variable(name) if not only_local and not var: return f"<Variable \"{name}\" not defined>" try: return f"{var.name}:{var.type.name}" except AttributeError: return f"<Error while accessing Variable \"{var.name}\" type: \"{var.type}\">"
def visit(self, node): scope = Scope() self.context = copy.copy(node.context) #visit classes in order (from tree root to leaves) parent_children_dict = {} initial_nodes = [] visited = {} self.class_to_visit = [] self.class_visited = {} for declaration in node.declarations: try: visited[declaration.id.lex] # checking if visited except: visited[declaration.id.lex] = True self.class_visited[declaration.id.lex] = False self.class_to_visit.append(declaration) if declaration.parent is None or declaration.parent.lex in [ "IO", "Int", "String", "Bool" ]: # is node has no parent, mark it to visit it first later initial_nodes.append(declaration) else: try: self.context.get_type(declaration.parent.lex) try: parent_children_dict[ declaration.parent.lex].append(declaration) except: parent_children_dict[declaration.parent.lex] = [ declaration ] except: # add declarations where parent is not defined initial_nodes.append(declaration) # initialize a list for classDeclNodes of typed ast self.tast_class_nodes = [] for declaration in initial_nodes: # first visit root nodes self.visit(declaration, scope.create_child(), parent_children_dict) while self.class_to_visit: # visiting classes involved in ciclyc heritage declaration = self.class_to_visit[0] self.visit(declaration, scope.create_child(), parent_children_dict) program_node = (scope, cool_type_nodes.ProgramNode(self.tast_class_nodes, copy.copy(self.context))) self.context = None self.current_type = None self.current_method = None return program_node
def visit(self, node, scope: Scope): self.current_attrb = self.current_type.get_attribute(node.id) node_type = self.all_pos_types(self.current_attrb.type) if not node.expr: node.computed_type = node_type self.current_attrb = None return self.visit(node.expr, scope) expr_type = node.expr.computed_type error_type = node_type.copy() error_expr = expr_type.copy() self.establish_conform(expr_type, node_type) if len(expr_type) * len(node_type) == 0: self.errors.append( f"Declaring Attribute {node.id} in class {self.current_type.name}. Incompatible types between possible declared types (" + ", ".join([typex.name for typex in error_type]) + ") and possible expression types (" + ", ".join([typex.name for typex in error_expr]) + ")") node.computed_type = ErrorType() else: node.computed_type = node_type var = scope.find_variable(node.id) var.type = node.computed_type self.current_attrb = None
def visit(self, node, scopex: Scope): scope = scopex.next_child() self.current_method = self.current_type.get_method(node.id) self.current_method.return_type = self.all_pos_types( self.current_method.return_type) for i in range(len(self.current_method.param_names)): idx, typex = (self.current_method.param_names[i], self.current_method.param_types[i]) var = scope.find_variable(idx) var.type = self.all_pos_types(var.type) self.current_method.param_types[i] = var.type self.visit(node.body, scope) ret_type_expr = node.body.computed_type ret_type_decl = self.current_method.return_type error_type = ret_type_decl.copy() error_expr = ret_type_expr.copy() self.establish_conform(ret_type_expr, ret_type_decl) if len(ret_type_decl) * len(ret_type_expr) == 0: self.errors.append( f"Declaring Function {node.id} in class {self.current_type.name}: incompatible types between possible declared return types (" + ", ".join([typex.name for typex in error_type]) + ") and possible expression return types (" + ", ".join([typex.name for typex in error_expr]) + ")") node.computed_type = ErrorType() else: node.computed_type = ret_type_decl self.current_method = None
def visit(self, node, scopex: Scope()): scope: Scope = scopex.next_child() self.current_method = self.current_type.get_method(node.id) for idx, typex in zip(self.current_method.param_names, self.current_method.param_types): var = scope.find_variable(idx) var.type = self.compare_types(var.type, typex) decl_inferred = node.inferenced_type expr_inferred = node.body.inferenced_type ret_type_decl = self.update_type(self.current_method.return_type) self.visit(node.body, scope) ret_type_expr = self.update_type(node.body.inferenced_type) conforms(ret_type_expr, ret_type_decl) print("Comapring inferenced type in FuncDecl") node.inferenced_type = self.compare_types(decl_inferred, ret_type_decl) print("Comapring Body inferenced type in FuncDecl") node.body.inferenced_type = self.compare_types(expr_inferred, ret_type_expr) if isinstance(self.current_method.return_type, AutoType): auto_return = self.current_method.return_type ret_type_decl = conforms(ret_type_decl, ret_type_expr) print("Comapring inferenced type in FuncDecl Once Agagin") node.inferenced_type = self.compare_types(decl_inferred, ret_type_decl) if is_subset(ret_type_decl, auto_return): self.current_method.return_type = ret_type_decl self.current_method = None
def visit(self, node, scope: Scope): self.current_method = self.current_type.get_method(node.id) for idx, typex in zip(self.current_method.param_names, self.current_method.param_types): scope.define_variable(idx, typex) self.visit(node.body, scope) ret_type_decl = self.update_type(self.current_method.return_type) ret_type_expr = self.update_type(node.body.computed_type) if not ret_type_expr.conforms_to(ret_type_decl): self.AddError( "Incompatible Return Types", INCOMPATIBLE_TYPES.replace('%s', ret_type_decl.name, 1).replace('%s', ret_type_expr.name, 1)) self.current_method = None
def visit(self, node, scope: Scope, tabs=0): extra = computed_info(node) header = '\t' * tabs + f'\\__CaseDeclarationNode: case <expr> of ( <var> => <expr> ...){extra}\n' caseexpr = self.visit(node.expr, scope, tabs + 1) case = '\t' * (tabs + 1) + f'case:\n{caseexpr}\n' casevars = '\n'.join( self.visit(child, scope.next_child(), tabs + 1) for child in node.casevars) of = '\t' * (tabs + 1) + f'of:\n{casevars}' return header + case + of
def visit(self, node, scope: Scope): self.visit(node.expr, scope) self.update_type(node.expr.inferenced_type) type_list = [] for var in node.casevars: child = scope.create_child() self.visit(var, child) type_list.append(var.inferenced_type) node_type = join_list(type_list) node.inferenced_type = node_type
def visit(self, node, scope: Scope): self.visit(node.expr, scope) var_types = [] for var in node.casevars: child = scope.next_child() self.visit(var, child) var_types.append(var.inferenced_type) node_inferred = node.inferenced_type auto = join_list(var_types) if is_subset(auto, node_inferred): node.inferenced_type = self.compare_types(node_inferred, auto)
def visit(self, node, scope: Scope): if node.define: node_type = scope.find_variable(node.id).type else: node_type = ErrorType() if node.expr: expr_inferr = node.expr.inferenced_type self.visit(node.expr, scope) expr_type = self.update_type(node.expr.inferenced_type) expr_type = conforms(expr_type, node_type) node.expr.inferenced_type = self.compare_types( expr_inferr, expr_type) node.inferenced_type = self.compare_types(node.inferenced_type, node_type)
def visit(self, node, scope: Scope): var = scope.find_variable(node.id) if not var: node.define = False var_type = ErrorType() else: node.define = True var_type = var.type self.visit(node.expr, scope) node_expr = self.update_type(node.expr.inferenced_type) if var and var.name != "self": node_expr = conforms(node_expr, var_type) node.expr.inferenced_type = node_expr if isinstance(var_type, AutoType): var_type = conforms(var_type, node_expr) var.type = var_type node.inferenced_type = var_type
def visit(self, node: CaseDeclarationNode, scope: Scope): self.visit(node.expr, scope) case_expr_type = node.expr.computed_type if not isinstance( node.expr.computed_type, SelfType) else self.current_type if isinstance(case_expr_type, VoidType): self.AddError(f"Case expression evaluated void.") case_expr_type = ErrorType() var_names = set() general_type = None found = False for var in node.casevars: child = scope.create_child() self.visit(var, child) var_type = var.computed_type if var_type.name in var_names: self.AddError( f"Equal types of \"{var_type.name}\" detected on case expression." ) else: var_names.add(var.computed_type.name) try: general_type = general_type.least_common_ancestor( var_type) if general_type else var_type except SemanticError as err: self.AddError( f"In Case Expression, in branch \"{var.id}:{var.type}\":", err.text) if not found and case_expr_type.conforms_to(var.computed_type): found = True if not found: self.AddError( f"No branch conforms to Case Expresion Type \"{case_expr_type.name}\"" ) node.computed_type = ErrorType() else: node.computed_type = general_type
def visit(self, node: CaseDeclarationNode, scope: Scope): self.visit(node.expr, scope) case_expr_type = node.expr.computed_type if isinstance(case_expr_type, VoidType): #arreglar esto case expr es ahora una lista self.AddError(f"Case expression evaluated void.") case_expr_type = [ErrorType()] node.expr.computed_type = case_expr_type var_types = set() found = False for case_var in node.casevars: child = scope.next_child() self.visit(case_var, child) var = child.find_variable(case_var.id) var.type = self.all_pos_types(var.type) var_type = var.type if var_type[0] in var_types: self.AddError( f"Equal types of \"{var_type.name}\" detected on case expression." ) else: assert len(var_type) == 1, "Var type mayor que 1 big oof" var_types.add(var_type[0]) for typex in var_types: for expr in case_expr_type: if expr.conforms_to(typex): found = True break if found: break else: self.AddError(f"No branch(" + ",".join(typex.name for typex in var_types) + ") conforms to possible Case Expresion types: " + ", ".join([typex.name for typex in case_expr_type])) node.computed_type = [ErrorType()] return node.computed_type = self.all_pos_types(node.inferenced_type)
def visit(self, node, scope: Scope): self.current_attrb = self.current_type.get_attribute(node.id) node_type = self.update_type(self.context.get_type(node.type)) if not node.expr: node.computed_type = node_type self.current_attrb = None return self.visit(node.expr, scope) expr_type = self.update_type(node.expr.computed_type) if not expr_type.conforms_to(node_type): self.errors.append( "Declaring Attribute:", INCOMPATIBLE_TYPES.replace('%s', expr_type.name, 1).replace('%s', node_type.name, 1)) node.computed_type = ErrorType() else: node.computed_type = node_type var = scope.find_variable(node.id) var.type = node.computed_type self.current_attrb = None
def visit(self, node, scope: Scope): if not node.define: var = None var_type = ErrorType() else: var = scope.find_variable(node.id) var_type = var.type expr_inferred = node.expr.inferenced_type self.visit(node.expr, scope) node_expr = self.update_type(node.expr.inferenced_type) if node.define: node_expr = conforms(node_expr, var_type) node.expr.inferenced_type = self.compare_types( expr_inferred, node_expr) if isinstance(var_type, AutoType): var_type = conforms(var_type, node_expr) var.type = self.compare_types(var.type, var_type) node.inferenced_type = self.compare_types(node.inferenced_type, var_type)
def visit(self, node, scope=None): scope = Scope() for declaration in node.declarations: self.visit(declaration, scope.create_child()) return scope
def visit(self, node: LetDeclarationNode, scopex: Scope): scope = scopex.create_child() for var in node.letvars: self.visit(var, scope) self.visit(node.expr, scope) node.computed_type = node.expr.computed_type
def visit(self, node: ProgramNode) -> Scope: scope = Scope() for declaration in node.declarations: self.visit(declaration, scope.create_child()) return scope
def visit(self, node, scope: Scope): for declaration in node.declarations: self.visit(declaration, scope.next_child()) scope.reset()
def visit(self, node, scope: Scope, tabs=0): ans = '\t' * tabs + f'\\__ProgramNode [<class> ... <class>]' statements = '\n'.join( self.visit(child, scope.next_child(), tabs + 1) for child in node.declarations) return f'{ans}\n{statements}'
def visit(self, node: ProgramNode, scope: Scope): self.types_updated = False for declaration in node.declarations: self.visit(declaration, scope.next_child()) scope.reset() return self.types_updated