def __check_scope_and_type(self, _class): """ Check scope and type for each class. If it's a method, goes recursively inside the body. When a scope is created? With a new block, let, case, OBS: Every attribute is private and every method is public. """ for feature in _class.feature_list: _type = returned_type(feature, _class) if isAttribute(feature): value_type = get_expression_type(feature.body, _class, self.scope) # Test if the attribute value type is the same as declared. if feature.type != value_type: raise AttributeTypeError(feature, value_type) self.scope.add(feature.name, _type) elif isMethod(feature): self.scope.add(feature.name, _type) # Add arguments to scope. name:type for formal in feature.formal_list: self.scope.add(formal[0], formal[1]) self.__check_children(feature.body, _class)
def __check_scope_and_type(self, _class): """ Check scope and type for each class. If it's a method, goes recursively inside the body. When a scope is created? With a new block, let, case, OBS: Every attribute is private and every method is public. """ for feature in _class.feature_list: _type = returned_type(feature, _class) if isAttribute(feature): value_type = get_expression_type( feature.body, _class, self.scope ) # Test if the attribute value type is the same as declared. if feature.type != value_type: raise AttributeTypeError(feature, value_type) self.scope.add(feature.name, _type) elif isMethod(feature): self.scope.add(feature.name, _type) # Add arguments to scope. name:type for formal in feature.formal_list: self.scope.add(formal[0], formal[1]) self.__check_children(feature.body, _class)
def __check_children(self, expression, _class): if isinstance(expression, Block): self.scope.new() for expr in expression.body: self.__check_children(expr, _class) self.scope.destroy() elif isinstance(expression, Dispatch): self.__check_children(expression.body, _class) # Get return type if expression.body == 'self': _class_name = _class.name else: try: _class_name = expression.body.return_type except AttributeError: # If the expression is an Object and there is no # return_type variable, so, need get the type. _class_name = get_expression_type( expression.body, _class, self.scope ) # Get the whole class' structure _class_content = self.classes[_class_name] called_method = False # Parse the structure untill match the method name for feature in _class_content.feature_list: if isMethod(feature) and feature.name == expression.method: called_method = True if len(feature.formal_list) != len(expression.expr_list): raise NumberOfArgumentError(feature.name, _class_name) formals = zip( feature.formal_list, expression.expr_list, ) # Test if the arguments types are not equals for feat, called in formals: expression_type = get_expression_type( called, _class, self.scope ) # feat[0] is the name and feat[1] the type if feat[1] != expression_type: raise ArgumentTypeError(feature, _class_name) # For default, the method returns the host class. SELF_TYPE last_type = _class_name feature_type = returned_type(feature, _class) # If exists a body, means that exists one or more # expressions inside the method. if feature.body: try: # If have a Block, must look the last expression, # because it is the type that will be returned. last_expression = feature.body.body[-1] except AttributeError: last_expression = feature.body last_type = get_expression_type( last_expression, _class, self.scope ) # If the returns types are not equals, raise an error if feature_type != last_type: raise ReturnedTypeError( feature.name, _class_name, feature_type, last_type ) # If didn't match the method name... if not called_method: raise UndefinedMethodError(expression.method, _class_name) elif isinstance(expression, Let): self.scope.new() self.scope.add(expression.object, expression.type) # Test if the declared type is the same type as # the given value value_type = get_expression_type( expression.init, _class, self.scope ) if expression.type != value_type: raise DeclaredTypeError(expression.type, value_type) self.__check_children(expression.body, _class) self.scope.destroy() elif isinstance(expression, While): self.__check_children(expression.predicate, _class) self.__check_children(expression.body, _class) # If the methods above did not raise an error, means that # the body's type is Int or an Object. # If is an Object and the root type is not a Bool, # must raise an error. self.__raise_if_not_bool(expression, _class, 'While') elif isinstance(expression, Lt) or isinstance(expression, Le): first_type, second_type = self.__get_params_types( expression, _class ) if first_type != 'Int' or second_type != 'Int': raise TypeCheckError(first_type, second_type, _class) elif isinstance(expression, Eq): """ The comparison = is a special case. If either <expr1> or <expr2> has static type Int, Bool, or String, then the other must have the same static type. """ first_type, second_type = self.__get_params_types( expression, _class ) types = ['String', 'Int', 'Bool'] if first_type not in types or second_type not in types: raise EqualTypeCheckError(first_type, second_type, _class) if first_type != second_type: raise EqualCheckError(first_type, second_type, _class) elif any(isinstance(expression, X) for X in [Plus, Sub, Mult, Div]): """ The static types of the two sub-expressions must be Int. Cool has only integer division. """ first_type, second_type = self.__get_params_types( expression, _class ) if first_type != 'Int' or second_type != 'Int': raise ArithmeticError(first_type, second_type, _class) elif isinstance(expression, Assign): self.__check_children(expression.body, _class) # If the method above did not raise an error, means that # the body type is Int. Just need to test name type now. name_type = get_expression_type( expression.name, _class, self.scope ) if name_type != 'Int': raise AssignError(name_type, 'Int', _class) elif isinstance(expression, If): self.__check_children(expression.predicate, _class) self.__check_children(expression.then_body, _class) self.__check_children(expression.else_body, _class) # If the methods above did not raise an error, means that # the body type is Int or an Object. # If is an Object and the root type is not a Bool, # must raise an error. self.__raise_if_not_bool(expression, _class, 'If')
def __get_methods(self, _class): return [i for i in _class.feature_list if isMethod(i)]
def __check_children(self, expression, _class): if isinstance(expression, Block): self.scope.new() for expr in expression.body: self.__check_children(expr, _class) self.scope.destroy() elif isinstance(expression, Dispatch): self.__check_children(expression.body, _class) # Get return type if expression.body == 'self': _class_name = _class.name else: _class_name = expression.body.return_type # Get the whole class' structure _class_content = self.classes[_class_name] called_method = False # Parse the structure untill match the method name for feature in _class_content.feature_list: if isMethod(feature) and feature.name == expression.method: called_method = True if len(feature.formal_list) != len(expression.expr_list): raise NumberOfArgumentError(feature.name, _class_name) formals = zip( feature.formal_list, expression.expr_list, ) # Test if the arguments types are not equals for feat, called in formals: expression_type = get_expression_type( called, _class, self.scope) # feat[0] is the name and feat[1] the type if feat[1] != expression_type: raise ArgumentTypeError(feature, _class_name) # Test if the returns types are not equals called_method_type = _class_name feature_type = returned_type(feature, _class) if feature_type != called_method_type: raise ReturnedTypeError(feature.name, _class_name) # If didn't match the method name... if not called_method: raise UndefinedMethodError(expression.method, _class_name) elif isinstance(expression, Let): self.scope.new() self.scope.add(expression.object, expression.type) # Test if the declared type is the same type as # the given value value_type = get_expression_type(expression.init, _class, self.scope) if expression.type != value_type: raise DeclaredTypeError(expression.type, value_type) self.__check_children(expression.body, _class) self.scope.destroy() elif isinstance(expression, While): self.__check_children(expression.predicate, _class) self.__check_children(expression.body, _class) # If the methods above did not raise an error, means that # the body type is Int or an Object. # If is an Object and is not a Bool, must raise an error. self.__raise_if_not_bool(expression, _class, 'While') elif isinstance(expression, Lt) or isinstance(expression, Le): first_type, second_type = self.__get_params_types( expression, _class) if first_type != 'Int' or second_type != 'Int': raise TypeCheckError(first_type, second_type, _class) elif isinstance(expression, Eq): """ The comparison = is a special case. If either <expr1> or <expr2> has static type Int, Bool, or String, then the other must have the same static type. """ first_type, second_type = self.__get_params_types( expression, _class) types = ['String', 'Int', 'Bool'] if first_type not in types or second_type not in types: raise EqualTypeCheckError(first_type, second_type, _class) if first_type != second_type: raise EqualCheckError(first_type, second_type, _class) elif any(isinstance(expression, X) for X in [Plus, Sub, Mult, Div]): """ The static types of the two sub-expressions must be Int. Cool has only integer division. """ first_type, second_type = self.__get_params_types( expression, _class) if first_type != 'Int' or second_type != 'Int': raise ArithmeticError(first_type, second_type, _class) elif isinstance(expression, Assign): self.__check_children(expression.body, _class) # If the method above did not raise an error, means that # the body type is Int. Just need to test name type now. name_type = get_expression_type(expression.name, _class, self.scope) if name_type != 'Int': raise AssignError(name_type, 'Int', _class) elif isinstance(expression, If): self.__check_children(expression.predicate, _class) self.__check_children(expression.then_body, _class) self.__check_children(expression.else_body, _class) # If the methods above did not raise an error, means that # the body type is Int or an Object. # If is an Object and is not a Bool, must raise an error. self.__raise_if_not_bool(expression, _class, 'If')