def visit(self, node: VariableNode, scope: Scope): try: typex = scope.find_local(node.lex).type name = self.to_var_name(node.lex) return name, get_type(typex, self.current_type) except: var_info = scope.find_attribute(node.lex) local_var = self.register_local(var_info.name) self.register_instruction( cil.GetAttribNode('self', var_info.name, self.current_type.name, local_var, var_info.type.name)) return local_var, get_type(var_info.type, self.current_type)
def visit(self, memberCallNode, scope): typex = self.currentType method = self._get_method(typex, memberCallNode.id, (memberCallNode.line, memberCallNode.col)) if not isinstance(method, MethodError): # check the args argTypes = [self.visit(arg, scope) for arg in memberCallNode.args] if len(argTypes) > len(method.param_types): errorText = f'Method {method.name} called with wrong number of arguments.' self.errors.append( SemanticError(errorText, memberCallNode.line, memberCallNode.col)) elif len(argTypes) < len(method.param_types): for arg, argInfo in zip(method.param_names[len(argTypes):], memberCallNode.args[len(argTypes):]): errorText = f'Method {method.name} called with wrong number of arguments.' self.errors.append(SemanticError(errorText, *argInfo.pos)) for argType, paramType, paramName in zip(argTypes, method.param_types, method.param_names): if not argType.conforms_to(paramType): errorText = f'In call of method {method.name}, type {argType.name} of parameter {paramName} does not conform to declared type {paramType.name}.' self.errors.append( TypexError(errorText, memberCallNode.line, memberCallNode.col)) memberCallNode.static_type = typex memberCallNode.computed_type = get_type(method.return_type, typex) return memberCallNode.computed_type
def visit(self, node: VarDeclarationNode, scope: Scope): var_info = scope.find_variable(node.id) vtype = get_type(var_info.type, self.current_type) local_var = self.register_local(var_info.name) value, typex = self.visit(node.expr, scope) if vtype.name == 'Object' and typex.name in ['String', 'Int', 'Bool']: self.register_instruction(cil.BoxingNode(local_var, typex.name)) else: self.register_instruction(cil.AssignNode(local_var, value)) return local_var, vtype
def visit(self, assignNode, scope): varInfo = self.find_variable(scope, assignNode.id) varType = get_type(varInfo.type, self.currentType) typex = self.visit(assignNode.expr, scope) if not typex.conforms_to(varType): errorText = f'Inferred type {typex.name} of initialization of {assignNode.id} does not conform to identifier\'s declared type {varType.name}.' self.errors.append( TypexError(errorText, assignNode.line, assignNode.col)) assignNode.computed_type = typex return typex
def visit(self, newNode, scope): try: typex = self.context.get_type(newNode.id, (newNode.line, newNode.col)) except: typex = ErrorType() errorText = f'\'new\' used with undefined class {newNode.id}.' self.errors.append(TypexError(errorText, newNode.line, newNode.col)) typex = get_type(typex, self.currentType) newNode.computed_type = typex return typex
def visit(self, node: InstantiateNode, scope: Scope): instance = self.define_internal_local() typex = self.context.get_type(node.lex, node.pos) typex = get_type(typex, self.current_type) self.register_instruction(cil.AllocateNode(typex.name, instance)) # calling the constructor to load all attributes # Si tiene atributos entonces tendrĂ¡ constructor (esto se deberia optimizar mas) if typex.all_attributes(): self.register_instruction( cil.StaticCallNode(typex.name, typex.name, instance, [cil.ArgNode(instance)], typex.name)) return instance, typex
def visit(self, varDeclarationNode, scope): varType = self._get_type( varDeclarationNode.type, (varDeclarationNode.line, varDeclarationNode.col)) varType = get_type(varType, self.currentType) if varDeclarationNode.expr == None: return varType else: typex = self.visit(varDeclarationNode.expr, scope) if not typex.conforms_to(varType): errorText = f'Inferred type {typex.name} of initialization of {varDeclarationNode.id} does not conform to identifier\'s declared type {varType.name}.' self.errors.append( TypexError(errorText, varDeclarationNode.typeLine, varDeclarationNode.typeCol)) return typex
def visit(self, attrDeclarationNode, scope): attr = self.currentType.get_attribute( attrDeclarationNode.id, (attrDeclarationNode.line, attrDeclarationNode.col)) attrType = get_type(attr.type, self.currentType) self.currentIndex = attr.index typex = self.visit(attrDeclarationNode.expr, scope) self.currentIndex = None if not typex.conforms_to(attrType): errorText = f'Inferred type {typex.name} of initialization of attribute {attr.name} does not conform to declared type {attrType.name}.' self.errors.append( TypexError(errorText, attrDeclarationNode.line, attrDeclarationNode.col)) return ErrorType() return typex
def visit(self, funcDeclarationNode, scope): parent = self.currentType.parent self.currentMethod = self.currentType.get_method( funcDeclarationNode.id, (funcDeclarationNode.line, funcDeclarationNode.col)) method = self.currentMethod if parent is not None: try: oldMethod = parent.get_method( funcDeclarationNode.id, (funcDeclarationNode.line, funcDeclarationNode.col)) if oldMethod.return_type.name != method.return_type.name: errorText = f'In redefined method {funcDeclarationNode.id}, return type {method.return_type.name} is different from original return type {oldMethod.return_type.name}.' self.errors.append( SemanticError(errorText, funcDeclarationNode.typeLine, funcDeclarationNode.typeCol)) if len(method.param_names) != len(oldMethod.param_names): errorText = f'Incompatible number of formal parameters in redefined method {funcDeclarationNode.id}.' self.errors.append( SemanticError(errorText, funcDeclarationNode.line, funcDeclarationNode.col)) for (name, ptype, pline, pcol), type1, type2 in zip(funcDeclarationNode.params, method.param_types, oldMethod.param_types): if type1.name != type2.name: errorText = f'In redefined method {name}, parameter type {type1.name} is different from original type {type2.name}.' self.errors.append( SemanticError(errorText, pline, pcol)) except: pass result = self.visit(funcDeclarationNode.body, scope) returnType = get_type(method.return_type, self.currentType) if not result.conforms_to(returnType): errorText = f'Inferred return type {result.name} of method test does not conform to declared return type {returnType.name}.' self.errors.append( TypexError(errorText, funcDeclarationNode.typeLine, funcDeclarationNode.typeCol))
def visit(self, arrobaCallNode, scope): objType = self.visit(arrobaCallNode.obj, scope) typex = self._get_type( arrobaCallNode.type, (arrobaCallNode.typeLine, arrobaCallNode.typeCol)) if not objType.conforms_to(typex): errorText = f'Expression type {typex.name} does not conform to declared static dispatch type {objType.name}.' self.errors.append( TypexError(errorText, arrobaCallNode.typeLine, arrobaCallNode.typeCol)) return ErrorType() method = self._get_method(typex, arrobaCallNode.id, (arrobaCallNode.line, arrobaCallNode.col)) if not isinstance(method, MethodError): # check the args argTypes = [self.visit(arg, scope) for arg in arrobaCallNode.args] if len(argTypes) > len(method.param_types): errorText = f'Method {method.name} called with wrong number of arguments.' self.errors.append( SemanticError(errorText, arrobaCallNode.line, arrobaCallNode.col)) elif len(argTypes) < len(method.param_types): for arg, argInfo in zip(method.param_names[len(argTypes):], arrobaCallNode.args[len(argTypes):]): errorText = f'Method {method.name} called with wrong number of arguments.' self.errors.append(SemanticError(errorText, *argInfo.pos)) for argType, paramType, paramName in zip(argTypes, method.param_types, method.param_names): if not argType.conforms_to(paramType): errorText = f'In call of method {method.name}, type {argType.name} of parameter {paramName} does not conform to declared type {paramType.name}.' self.errors.append( TypexError(errorText, arrobaCallNode.line, arrobaCallNode.col)) arrobaCallNode.computed_type = get_type(method.return_type, TypexError) return arrobaCallNode.computed_type
def visit(self, idNode, scope): varType = self.find_variable(scope, idNode.id).type typex = get_type(varType, self.currentType) idNode.computed_type = typex return typex
def _return_type(self, typex: Type, node): meth = typex.get_method(node.id, node.pos) return get_type(meth.return_type, self.current_type)