def visit(self, node): self.context = Context() bool_type = BoolType() int_type = IntType() str_type = _create_string_type(int_type) self_type = SelfType() obj_type = _create_object_type(str_type, self_type) io_type = _create_io_type(str_type, self_type, int_type) auto_type = AutoType() error_type = ErrorType() bool_type.set_parent(obj_type) int_type.set_parent(obj_type) str_type.set_parent(obj_type) self_type.set_parent(obj_type) io_type.set_parent(obj_type) auto_type.set_parent(obj_type) error_type.set_parent(obj_type) self.context.types[BasicTypes.BOOL.value] = bool_type self.context.types[BasicTypes.INT.value] = int_type self.context.types[BasicTypes.STRING.value] = str_type self.context.types[BasicTypes.SELF.value] = self_type self.context.types[BasicTypes.OBJECT.value] = obj_type self.context.types[BasicTypes.IO.value] = io_type self.context.types[BasicTypes.AUTO.value] = auto_type self.context.types[BasicTypes.ERROR.value] = error_type for class_dec_node in node.declarations: self.visit(class_dec_node)
def visit(self, node, scope): tp = self.visit(node.expression, scope.create_child()) if tp == self.context.get_type('Bool'): node.type = tp return tp self.errors.append( _TypeError % (node.token_list[0].lineno, node.token_list[0].col, f"Argument of 'not' has type {tp.name} instead of Bool.")) node.type = ErrorType() return ErrorType()
def visit(self, node, scope): tp = self.visit(node.expr, scope) if tp == self.context.get_type('Int'): node.type = tp return tp self.errors.append( _TypeError % (node.token_list[0].lineno, node.token_list[0].col, f"Argument of '~' has type {tp.name} instead of Int.")) node.type = ErrorType() return ErrorType()
def visit(self, node, scope): if node.obj is None: node.obj = VariableNode('self') obj_type = self.visit(node.obj, scope) if node.parent is not None: try: ancestor_type = self.context.get_type(node.parent) except SemanticError as e: ancestor_type = ErrorType() if not obj_type.conforms_to(ancestor_type): self.errors.append(_TypeError % ( node.token_list[0].lineno, node.token_list[0].col, f'Expression type {obj_type.name} does not conform to declared static dispatch type {ancestor_type.name}.' )) else: ancestor_type = obj_type try: method = ancestor_type.get_method(node.method, self.current_type, False) except SemanticError as e: self.errors.append( _AtributeError % (node.token_list[0].lineno, node.token_list[0].col, f'Dispatch to undefined method {node.method}')) for arg in node.args: self.visit(arg, scope) node.type = ErrorType() return ErrorType() if len(node.args) != len(method.param_types): self.errors.append(_SemanticError % ( node.token_list[1].lineno, node.token_list[1].col, f"Method {method.name} called with wrong number of arguments")) else: for i, arg in enumerate(node.args): arg_type = self.visit(arg, scope) if not arg_type.conforms_to(method.param_types[i]): self.errors.append(_TypeError % ( node.args[i].token_list[0].lineno, node.args[i].token_list[0].col, f"In call of {method.name}, type {arg_type.name} of parameter {method.param_names[i]} does not conform to declare type {method.param_types[i].name}" )) if method.return_type.name != 'SELF_TYPE': node.type = method.return_type return method.return_type else: node.type = ancestor_type return ancestor_type
def visit(self, node, scope): lt = self.visit(node.left, scope) rt = self.visit(node.right, scope) intType = self.context.get_type('Int') if lt == rt == intType: node.type = intType return intType self.errors.append( _TypeError % (node.token_list[0].lineno, node.token_list[0].col, 'non-Int arguments: ' + str(lt.name) + ' / ' + str(rt.name))) node.type = ErrorType() return ErrorType()
def visit(self, node, scope): ifT = self.visit(node.ifChunk, scope.create_child()) thenT = self.visit(node.thenChunk, scope.create_child()) elseT = self.visit(node.elseChunk, scope.create_child()) if ifT != self.context.get_type('Bool'): self.errors.append(_TypeError % (node.ifChunk.token_list[0].lineno, node.ifChunk.token_list[0].col, f"Predicate of 'if' does not have type Bool.")) try: node.type = thenT.join(elseT) return node.type except: node.type = ErrorType() return ErrorType()
def visit(self, node, scope): self.visit(node.expr, scope) types = [] t_set = set() for i, t, e, token_list in node.case_list: child_scope = scope.create_child() try: if t != 'SELF_TYPE': if t not in t_set: t_set.add(t) else: self.errors.append( _SemanticError % (token_list[2].lineno, token_list[2].col, f'Duplicate branch {t} in case statement.')) t_typo = self.context.get_type(t) child_scope.define_variable(i, t_typo) else: self.errors.append( f'SELF_TYPE is not valid as the type of a case branch.' ) except SemanticError as exc: child_scope.define_variable(i, ErrorType()) self.errors.append(_TypeError % (token_list[2].lineno, token_list[2].col, f'Class {t} of case branch is undefined.')) types.append(self.visit(e, child_scope)) node.type = Type.multi_join(types) return node.type
def visit(self, node, scope): return_type = ErrorType() for expr in node.chunk: return_type = self.visit(expr, scope.create_child()) node.type = return_type return return_type
def visit(self, node): param_names = [] param_types = [] for name, typex in node.params: param_names.append(name) try: param_types.append(self.context.get_type(typex)) except SemanticError as e: param_types.append(ErrorType()) self.errors.append(_TypeError % (node.token_list[0].lineno, node.token_list[0].col, f'Class {typex} of formal parameter {name} is undefined.')) try: return_type = self.context.get_type(node.type) except SemanticError as e: self.errors.append(_TypeError % (node.token_list[4].lineno, node.token_list[4].col, f'Undefined return type {node.type} in method {node.id}.')) return_type = ErrorType() try: self.current_type.define_method(node.id, param_names, param_types, return_type) except SemanticError as e: self.errors.append(_SemanticError % (node.token_list[0].lineno, node.token_list[0].col, f'Method {node.id} is multply defined in class {self.current_type.name}.'))
def visit(self, node, scope): if node.lex == 'self': variable = VariableInfo('self', self.current_type) else: variable = scope.find_variable(node.lex) if variable is None: try: _var = self.current_type.get_attribute( node.lex, self.current_type, False) variable = VariableInfo(_var.name, _var.type) except SemanticError as e: pass if variable is None: self.errors.append( _NameError % (node.token_list[0].lineno, node.token_list[0].col, f"Undeclared identifier {node.lex}.")) node.type = ErrorType() return ErrorType() node.type = variable.type return variable.type
def visit(self, node): try: t_attr = self.context.get_type(node.type) except SemanticError as e: self.errors.append(_TypeError % (node.token_list[0].lineno, node.token_list[2].col, f'Class {node.type} of attribute {node.id} is undefined.')) t_attr = ErrorType() try: self.current_type.define_attribute(node.id, t_attr) except SemanticError as e: attr, owner = self.current_type.get_attribute(node.id, self.current_type, False, get_owner=True) if owner == self.current_type: self.errors.append(_SemanticError % (node.token_list[0].lineno, node.token_list[0].col, f'Attribute {node.id} is multply defined in class {self.current_type.name}.'))
def visit(self, node, scope): try: if node.lex != 'SELF_TYPE': node.type = self.context.get_type(node.lex) return node.type else: node.type = self.current_type return self.current_type except SemanticError as e: self.errors.append( _TypeError % (node.token_list[1].lineno, node.token_list[1].col, f"'new' used with undefined class {node.lex}.")) node.errors = ErrorType return ErrorType()
def visit(self, node, scope): lt = self.visit(node.left, scope) rt = self.visit(node.right, scope) boolType = self.context.get_type('Bool') # quite self type de los basicos aqui if lt.name not in ("Int", "String", "Bool", "IO", "Object") and rt.name not in ("Int", "String", "Bool", "IO", "Object"): node.type = boolType return node.type if lt == rt: node.type = boolType return node.type self.errors.append(_TypeError % (node.token_list[0].lineno, node.token_list[0].col, f'Illegal comparison with a basic type.')) return ErrorType()
def visit(self, node, scope): self.current_method = self.current_type.get_method( node.id, self.current_type, False) scope.define_variable('self', self.current_type) _char = node.id[0] if _char not in ''.join(chr(n) for n in range(ord('a'), ord('z') + 1)): self.errors.append((f'Class names must be capitalized')) for i in range(len(self.current_method.param_names)): ithParamName = self.current_method.param_names[i] ithParamType = self.current_method.param_types[i] if ithParamName == 'self': self.errors.append( _SemanticError % (node.token_list[0].lineno, node.token_list[0].col, f"'self' cannot be the name of a formal parameter.")) continue if not scope.is_local(ithParamName): if ithParamType.name == 'SELF_TYPE': self.errors.append( 'SELF_TYPE cannot be the type of a parameter.') scope.define_variable(ithParamName, ErrorType()) else: scope.define_variable( ithParamName, self.context.get_type(ithParamType.name)) else: self.errors.append( _SemanticError % (node.token_list[0].lineno, node.token_list[0].col, f'Formal parameter {ithParamName} is multiply defined.')) if node.type != 'SELF_TYPE': rType = self.context.get_type(node.type) else: rType = self.current_type exprType = self.visit(node.body, scope) node.type = self.current_method.return_type if not exprType.conforms_to(rType): self.errors.append(_TypeError % ( node.body.token_list[0].lineno, node.body.token_list[0].col, f'Infered return type {exprType.name} of method {node.id} does not conform to declared return type {rType.name}.' ))
def visit(self, node, scope): iteration = 0 for nod in node.decl_list: _id = nod.id _t = nod.type _e = nod.expr if _id == 'self': self.errors.append( _SemanticError % (node.decl_list[iteration].token_list[0].lineno, node.decl_list[iteration].token_list[0].col, f"'self' cannot be bound in a 'let' expression.")) continue try: if _t != 'SELF_TYPE': var_type = self.context.get_type(_t) else: var_type = self.current_type except SemanticError as e: self.errors.append(_TypeError % ( node.decl_list[iteration].token_list[0].lineno, node.decl_list[iteration].token_list[2].col, f"Class {_t} of let-bound identifier {_id} is undefined.")) var_type = ErrorType() if _e is not None: expr = self.visit(_e, scope.create_child()) else: expr = None if expr is not None and not expr.conforms_to(var_type): self.errors.append(_TypeError % ( node.decl_list[iteration].token_list[0].lineno, node.decl_list[iteration].token_list[0].col, f"Infered type {expr.name} of initialization of {_id} does not conform to identifier's declared type {var_type.name}" )) scope.define_variable(_id, var_type) iteration += 1 expr_type = self.visit(node.expression, scope.create_child()) node.type = expr_type return node.type
def visit(self, node, scope): var_info = scope.find_variable(node.id) exprType = self.visit(node.expr, scope.create_child()) node.type = exprType if node.id == 'self': self.errors.append( _SemanticError % (node.token_list[1].lineno, node.token_list[1].col, f"Cannot assign to 'self'.")) return ErrorType() if var_info is None: raise Exception('var not found in scope') self.errors.append( f'Undefined variable {node.id} in {self.current_method.name}.') else: if not exprType.conforms_to(var_info.type): self.errors.append( f"Can't convert {exprType.name} to {var_info.name}.") return exprType