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))
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())