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): var = scope.find_variable(node.id) if node.define: var.type = self.all_pos_types(var.type) var_type = var.type self.visit(node.expr, scope) expr_type = node.expr.computed_type error_expr = expr_type.copy() error_type = var_type.copy() self.establish_conform(var_type, expr_type) if len(var_type) * len(expr_type) == 0: self.AddError( f"Cant assign new value to {node.id}. Incompatible types between defined variable declared types (" + ", ".join([typex.name for typex in error_type]) + ") and possible expression types (" + ", ".join([typex.name for typex in error_expr]) + ")") var_type = [ErrorType()] if var.name == 'self': self.AddError("Cant Assign:", SELF_IS_READONLY) var_type = [ErrorType()] else: self.AddError("Cant Assign:", VARIABLE_NOT_DEFINED.replace('%s', node.id, 1)) var_type = [ErrorType()] node.computed_type = var_type #No es necesario hacerle un al pos
def visit(self, node): self.current_type = self.context.get_type(node.id) if not node.parent is None: try: parent = self.context.get_type(node.parent) if parent in self.basic_types: self.errors.append('Class ' + node.id + ' cant inherit from ' + parent.name) parent = ErrorType() self.current_type.set_parent(parent) actual_type = self.current_type.parent while not actual_type is None: if actual_type.parent == self.current_type: self.errors.append('Circular dependency at class ' + node.id) self.current_type.set_parent(ErrorType()) actual_type = actual_type.parent except SemanticError as error: self.errors.append(error.text) else: self.current_type.set_parent(self.context.get_type('Object')) for feature in node.features: self.visit(feature)
def visit(self, node: IfDeclarationNode, scope: Scope): self.visit(node.ifexpr, scope) ifexpr_type = node.ifexpr.computed_type bool_type = self.context.get_type("Bool") if not ifexpr_type.conforms_to(bool_type): self.AddError( "If predicate is not Bool:", INCOMPATIBLE_TYPES.replace('%s', ifexpr_type.name, 1).replace('%s', bool_type.name, 1)) ifexpr_type = ErrorType() self.visit(node.thenexpr, scope) then_type = node.thenexpr.computed_type then_type = self.update_type(then_type) self.visit(node.elseexpr, scope) else_type = node.elseexpr.computed_type else_type = self.update_type(else_type) typex = else_type.least_common_ancestor(then_type) if typex == None: self.AddError( "The \"then\" and \"else\" expressions have different types with no common ancestor." ) node.computed_type = ErrorType() else: node.computed_type = typex
def visit(self, node, scope): try: node_type = self.context.get_type( node.type) # if node.type != "SELF_TYPE" else SelfType() except SemanticError as err: self.errors.append(err.text) node_type = ErrorType() if scope.is_local(node.id): self.AddError(f"Declaring Variable \"{node.id}\":", LOCAL_ALREADY_DEFINED.replace('%s', node.id, 1)) else: scope.define_variable(node.id, node_type) if node.expr: self.visit(node.expr, scope) expr_type = node.expr.computed_type if not expr_type.conforms_to(node_type): self.AddError( f"Declaring Variable \"{node.id}\":", INCOMPATIBLE_TYPES.replace('%s', expr_type.name, 1).replace( '%s', node_type.name, 1)) node_type = ErrorType() node.computed_type = node_type
def establish_conform(self, expr, decl, *common_ancestors): if len(decl) == 0: decl = [ErrorType()] if len(expr) == 0: expr = [ErrorType()] if not common_ancestors: common_ancestors = self.get_common_ancestors(expr, decl) self.conform_list(decl, common_ancestors) self.conform_list(expr, common_ancestors, left_to_right=True)
def visit(self, node, scope): var = scope.find_variable(node.id) if var: node.computed_type = self.update(node) var.type = node.computed_type else: node.computed_type = ErrorType() var.type = ErrorType() if node.expr: self.visit(node.expr, scope) self.log(f"Attribute Node {node.id} {node.computed_type.name}")
def visit(self, node, scope): var = scope.find_variable(node.id) if var and node.define: node.computed_type = self.update(node) var.type = self.update_var(var.type) else: node.computed_type = ErrorType() var.type = ErrorType() self.log(f"Let Var Node {node.id}: {node.computed_type.name}") if node.expr: self.visit(node.expr, scope)
def visit(self, node, scope): # Evaluate object obj_type = self.visit(node.obj, scope) # Check object type conforms to cast type cast_type = obj_type if node.type is not None: try: cast_type = self.context.get_type(node.type) if isinstance(cast_type, AutoType): raise SemanticError( 'AUTO_TYPE can\'t be the type on this type of dispatch' ) if isinstance(cast_type, SelfType): cast_type = SelfType(self.current_type) except SemanticError as ex: cast_type = ErrorType() self.errors.append(ex.text) if not self.check_conformance(obj_type, cast_type): self.errors.append(INCOMPATIBLE_TYPES % (obj_type.name, cast_type.name)) # if the obj that is calling the function is autotype, let it pass if isinstance(cast_type, AutoType): return cast_type if isinstance(cast_type, SelfType): cast_type = self.current_type # Check this function is defined for cast_type try: method = cast_type.get_method(node.id) if not len(node.args) == len(method.param_types): self.errors.append(INVALID_OPERATION % (method.name, cast_type.name)) return ErrorType() for i, arg in enumerate(node.args): computed_type = self.visit(arg, scope) if not self.check_conformance(computed_type, method.param_types[i]): self.errors.append( INCOMPATIBLE_TYPES % (computed_type.name, method.param_types[i].name)) # check self_type rtype = method.return_type if isinstance(rtype, SelfType): rtype = obj_type return rtype except SemanticError as ex: self.errors.append(ex.text) return ErrorType()
def visit(self, node, scope): var = scope.find_variable(node.lex) if var is None: node_row, node_col = node.token.location self.errors.append( NameError( node_row, node_col, VARIABLE_NOT_DEFINED % (node.lex, self.current_method.name))) return (ErrorType(), cool_type_nodes.VariableNode(node.lex, ErrorType())) return (var.type, cool_type_nodes.VariableNode(node.lex, var.type))
def update(self, node, strict=True): try: typex = node.computed_type except AttributeError: node.computed_type = ErrorType() return ErrorType() if isinstance(typex, Type): return typex if len(typex) == 0: return ErrorType() if strict: return self.find_lowest_ancestor(typex) return typex[-1]
def visit(self, node): ## Building param-names and param-types of the method param_names = [] param_types = [] node.index = [] for param in node.params: n, t = param node.index.append(None) # Checking param name can't be self if n == "self": self.errors.append(SELF_IS_READONLY) while True: if n in param_names: n = f'1{n}' else: param_names.append(n) break try: t = self.context.get_type(t) if isinstance(t, SelfType): t = SelfType(self.current_type) elif isinstance(t, AutoType): node.index[-1] = self.manager.assign_id(self.obj_type) except SemanticError as ex: self.errors.append(ex.text) t = ErrorType() param_types.append(t) # Checking return type try: rtype = self.context.get_type(node.type) if isinstance(rtype, SelfType): rtype = SelfType(self.current_type) except SemanticError as ex: self.errors.append(ex.text) rtype = ErrorType() node.idx = self.manager.assign_id(self.obj_type) if isinstance( rtype, AutoType) else None # Defining the method in the current type. There can not be another method with the same name. try: self.current_type.define_method(node.id, param_names, param_types, rtype, node.index, node.idx) except SemanticError as ex: self.errors.append(ex.text)
def visit(self, node, scope): int_type = self.context.get_type("Int") typex, exp_node = self.visit(node.expr, scope) if typex != int_type and not typex.name == "AUTO_TYPE": node_row, node_col = node.expr.token.location self.errors.append( TypeError( node_row, node_col, f"Expression after '~' must be Int, current is {typex.name}" )) return (ErrorType(), cool_type_nodes.NegNode(exp_node, ErrorType())) return (int_type, cool_type_nodes.NegNode(exp_node, int_type))
def visit(self, node, scope): bool_type = self.context.get_type("Bool") typex, exp_node = self.visit(node.expr, scope) if typex != bool_type and not typex.name == "AUTO_TYPE": line, col = node.expr.token.location self.errors.append( TypeError( line, col, f"Expression after 'not' must be Bool, current is {typex.name}" )) return (ErrorType(), cool_type_nodes.NotNode(exp_node, ErrorType())) return (bool_type, cool_type_nodes.NotNode(exp_node, bool_type))
def visit(self, node, scope, type_suggested=None): try: t, method = self.current_type.get_method(node.id) except SemanticError as error: self.errors.append(error.text) return ErrorType() call_args_types = [self.visit(arg, scope, None) for arg in node.args] method_args_types = [param_type for param_type in method.param_types] if not len(call_args_types) == len(method_args_types): self.errors.append(METHOD_NOT_DEFINED % (node.id, self.current_type.name)) else: for i in range(len(call_args_types)): if not call_args_types[i].conforms_to(method_args_types[i]): self.errors.append( INCOMPATIBLE_TYPES % (call_args_types[i].name, method_args_types[i].name)) ret_type = method.return_type if method.return_type.name == 'SELF_TYPE': ret_type = self.current_type else: if method.return_type == self.at: try: ret_type = self.changed_methods[(method.name, t)] except KeyError: pass return ret_type
def visit(self, node): # Checking attribute type try: attr_type = self.context.get_type(node.type) if isinstance(attr_type, SelfType): attr_type = SelfType(self.current_type) except SemanticError as ex: self.errors.append(ex.text) attr_type = ErrorType() node.idx = self.manager.assign_id(self.obj_type) if isinstance( attr_type, AutoType) else None #Checking attribute can't be named self if node.id == "self": self.errors.append(SELF_IS_READONLY) # Checking attribute name. No other attribute can have the same name flag = False try: self.current_type.define_attribute(node.id, attr_type, node.idx) flag = True except SemanticError as ex: self.errors.append(ex.text) while not flag: node.id = f'1{node.id}' try: self.current_type.define_attribute(node.id, attr_type, node.idx) flag = True except SemanticError: pass
def common_ancestor(type_list): visited = [] actual_type = type_list[0] print(type_list) for t in type_list: if t.name == '<error>': return ErrorType() if not t.name == 'AUTO_TYPE': actual_type = t visited.append(actual_type) while not actual_type.parent is None: actual_type = actual_type.parent visited.append(actual_type) for t in visited: ok = True for types in type_list: if not types.conforms_to(t): ok = False break if ok: print(t.name) return t
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, 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, scope): if node.id.lex == "self": node_row, node_col = node.token.location self.errors.append( SemanticError(node_row, node_col, "Cannot assign to 'self'. " + SELF_IS_READONLY)) var_type = None if not scope.is_defined(node.id.lex): node_row, node_col = node.id.location self.errors.append( NameError( node_row, node_col, VARIABLE_NOT_DEFINED % (node.id.lex, self.current_method.name))) var_type = ErrorType() else: var_type = scope.find_variable(node.id.lex).type expr_type, exp_node = self.visit(node.expr, scope) if not expr_type.conforms_to(var_type): node_row, node_col = node.token.location self.errors.append( TypeError( node_row, node_col, f"Inferred type {expr_type.name} of assigned expression does not conforms to type {var_type.name} of variable '{node.id.lex}'" )) return (expr_type, cool_type_nodes.AssignNode(node.id.lex, exp_node, expr_type))
def visit(self, node, scope): if_inferred = node.ifexpr.inferenced_type self.visit(node.ifexpr, scope) ifexpr_type = self.update_type(node.ifexpr.inferenced_type) bool_type = self.context.get_type("Bool") if isinstance(ifexpr_type, AutoType): ifexpr_type.set_upper_limmit([bool_type]) node.ifexpr.inferenced_type = self.compare_types( if_inferred, ifexpr_type) self.visit(node.thenexpr, scope) then_type = self.update_type(node.thenexpr.inferenced_type) self.visit(node.elseexpr, scope) else_type = self.update_type(node.elseexpr.inferenced_type) node_inferred = node.inferenced_type joined = join(then_type, else_type) if not isinstance(joined, ErrorType): type_sets, heads = joined auto = AutoType("IF", heads, type_sets) else: auto = ErrorType() if is_subset(auto, node_inferred): node.inferenced_type = self.compare_types(node_inferred, auto)
def get_type(self, ntype, comp_error_mesg): try: return self.context.get_type(ntype.lex) except SError as error: node_row, node_col = ntype.location self.errors.append(TypeError(node_row, node_col, f"Type {ntype.lex} " + comp_error_mesg + " is not defined.")) return ErrorType()
def visit(self, node, scope): if node.id == "self": node_row, node_col = node.token.location self.errors.append( SemanticError( node_row, node_col, "'self' cannot be bound in a 'let' expression. " + SELF_IS_READONLY)) static_type = None try: static_type = self.context.get_type(node.type.lex) if static_type.name == "SELF_TYPE": static_type = self.current_type except SError as e: node_row, node_col = node.type.location self.errors.append(TypeError(node_row, node_col, e.text)) static_type = ErrorType() if node.expr != None: typex, node_exp = self.visit(node.expr, scope) if not typex.conforms_to(static_type): line, col = node.expr.token.location self.errors.append( TypeError( line, col, INCOMPATIBLE_TYPES % (typex.name, static_type.name))) else: node_exp = None scope.define_variable(node.id, static_type) return (static_type, cool_type_nodes.VarDeclarationNode(node.id, node.type.lex, node_exp, static_type))
def visit(self, node, scope): nscope = scope.create_child() node.idx_list = [None] * len(node.id_list) for i, item in enumerate(node.id_list): idx, typex, expr = item # create a new_scope for every variable defined new_scope = nscope.create_child() if idx == 'self': self.errors.append(SELF_IS_READONLY) idx = f'1{idx}' node.id_list[i] = (idx, typex, expr) try: typex = self.context.get_type(typex) if isinstance(typex, SelfType): typex = SelfType(self.current_type) except SemanticError as ex: self.errors.append(ex.text) typex = ErrorType() if isinstance(typex, AutoType): node.idx_list[i] = self.manager.assign_id(self.obj_type) if expr is not None: expr_type = self.visit(expr, new_scope) if not self.check_conformance(expr_type, typex): self.errors.append(INCOMPATIBLE_TYPES % (expr_type.name, typex.name)) new_scope.define_variable(idx, typex, node.idx_list[i]) nscope = new_scope return self.visit(node.body, nscope)
def visit(self, node, scope, type_suggested=None): try: var_type = self.context.get_type(node.type) except SemanticError as error: self.errors.append(error.text) var_type = ErrorType() if scope.is_local(node.id): self.errors.append(LOCAL_ALREADY_DEFINED % (node.id, self.current_method.name)) else: scope.define_variable(node.id, var_type) if not node.expr is None: type_expr = self.visit(node.expr, scope, None) if not type_expr.conforms_to(var_type): self.errors.append(INCOMPATIBLE_TYPES % (type_expr.name, var_type.name)) if type_expr == self.at and var_type == self.at: self.errors.append(AUTO_TYPE_ERROR % (node.id)) if var_type == self.at and not type_expr == self.at: node.type = type_expr.name return type_expr return var_type
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 left_error = left_type.copy() right_error = right_type.copy() int_type = self.context.get_type("Int") self.conform_list(left_type, int_type) self.conform_list(right_type, int_type) if len(left_type) * len(right_type) == 0: s = "Performing Arithmetic Operation:" if not len(left_type): s += ("\n -None of the left memeber possible values(" + ",".join(typex.name for typex in left_error) + ") conforms to Int") if not len(right_type): s += ("\n -None of the right memeber possible values(" + ",".join(typex.name for typex in right_error) + ") conforms to Int") self.AddError(s) node_type = [ErrorType()] else: node_type = [int_type] node.computed_type = node_type
def visit(self, node, scope): try: node_type = self.context.get_type(node.lex, selftype=False, autotype=False) except SemanticError as err: node_type = ErrorType() node.inferenced_type = node_type
def visit(self, node, scope): if node.define: var = scope.find_variable(node.lex) var.type = self.all_pos_types(var.type) node.computed_type = var.type else: self.AddError(VARIABLE_NOT_DEFINED.replace('%s', node.lex, 1)) node.computed_type = [ErrorType()]
def visit(self, node, scope): try: node_type = self.context.get_type( node.lex) if node.lex != "SELF_TYPE" else SelfType() except SemanticError as err: self.AddError(f"Unable to instantiate:", err.text) node_type = ErrorType() node.computed_type = node_type
def visit(self, node, scope): try: typex = self.context.get_type(node.lex.lex) if typex.name == "SELF_TYPE": return self.current_type return (typex, cool_type_nodes.InstantiateNode(node.lex.lex, typex)) except SError as error: node_row, node_col = node.lex.location self.errors.append( TypeError( node_row, node_col, f"Type {node.lex.lex} of 'new' expression is not defined.") ) return (ErrorType(), cool_type_nodes.InstantiateNode(node.lex.lex, ErrorType()))