def visit(self, node: ast.Program, _): scope_root = Scope(None, None) for classDef in node.classes: new_type = ctype(classDef.name) scope_root.createType(new_type) for classDef in node.classes: a = scope_root.getType(classDef.name) a.parent = scope_root.getType(classDef.parent) new_types = self.sort_type(scope_root.get_types()) node.classes = list( map(lambda x: self.get_node_by_type(x, node.classes), list(new_types.keys())[6:])) scope_root.set_types(new_types) self.check_ciclic_inheritance(scope_root.get_types()) scopes = [] for j in node.classes: scope = Scope(j.name, scope_root) methods = filter(lambda x: type(x) is ast.ClassMethod, j.features) methods = list(methods) attribs = filter(lambda x: type(x) is ast.ClassAttribute, j.features) attribs = list(attribs) p_type = scope.getType(j.parent) if p_type.name in ['Int', 'Bool', 'String']: raise CheckSemanticError( f'Any type can\'t inheriths from {p_type}') for i in p_type.attributes: try: scope.getType(j.name).add_attrib(i) except Exception as e: raise e try: scope.defineAttrib(list(i.keys())[0], list(i.values())[0]) except Exception as e: raise e for i in attribs: try: scope.getType(j.name).add_attrib( {i.name: scope.getType(i.attr_type)}) except Exception as e: raise e try: scope.defineAttrib(i.name, scope.getType(i.attr_type)) except Exception as e: raise e for i in methods: try: scope.getType(j.name).add_method({ i.name: { 'formal_params': { t.name: scope.getType(t.param_type) for t in i.formal_params }, 'return_type': scope.getType(i.return_type), 'body': i.body } }) except Exception as e: raise e scopes.append(scope) for i in range(len(node.classes)): self.visit(node.classes[i], scopes[i]) return scope_root
def visit(self, node: ast.ClassAttribute, scope: Scope, errors): try: scope.defineAttrib(node.name, scope.getType(node.attr_type)) except Exception as e: print(e) @visitor.when(ast.ClassMethod) def visit(self, node:ast.ClassMethod, scope:Scope, errors): for i in node.formal_params: try: scope.defineSymbol(i.name, scope.getType(i.param_type)) except Exception as e: print(e) tb = self.visit(node.body, scope, error) if not tb < scope.getType(node.return_type): raise CheckSemanticError(f'{tb} doesn\'t conform {node.return_type}') return scope.getType(node.return_type) @visitor.when(ast.Integer) def visit(self, node:ast.Integer, scope:Scope, errors): return scope.getType("Int") @visitor.when(ast.String) def visit(self, node:ast.String, scope:Scope, errors): return scope.getType("String") @visitor.when(ast.Boolean) def visit(self, node:ast.Boolean, scope:Scope, errors): return scope.getType("Bool") @visitor.when(ast.Object) def visit(self, node:ast.Object, scope:Scope, errors): return scope.getTypeFor(node.name) @visitor.when(ast.Self) def visit(self, node:ast.Self, scope:Scope, errors): return scope.getType(scope.classname) @visitor.when(ast.NewObject) def visit(self, node:ast.NewObject, scope:Scope, errors): return scope.getType(node.type) @visitor.when(ast.IsVoid) def visit(self, node:ast.IsVoid, scope:Scope, errors): self.visit(node.expr) return scope.getType("Bool") @visitor.when(ast.Assignment) def visit(self, node:ast.Assignment, scope:Scope, errors): try: instanceType = scope.getTypeFor(node.instance.name) exprType = self.visit(node.expr, scope, errors) if not instanceType < exprType : raise CheckSemanticError(f'{tb} doesn\'t conform {node.return_type}') return exprType except: raise CheckSemanticError(f'Symbol {node.instance.name} not defined in the Scope.') @visitor.when(ast.Block) def visit(self, node:ast.Block, scope:Scope, errors): for item in node.expr_list: self.visit(item, scope, errors) return self.visit(node.expr_list[-1], scope, errors) @visitor.when(ast.DynamicDispatch) def visit(self, node:ast.DynamicDispatch, scope:Scope, errors): instanceType = scope.getTypeFor(node.instance) if not instanceType.is_method(node.method): raise CheckSemanticError(f'method {node.method} not defined') argsType = instanceType.get_method_args(node.method) if len(argsType) != len(node.arguments): raise CheckSemanticError(f'{node.method} require {len(argsType)} arguments') for x, y in argsType, node.arguments: t = self.visit(y, scope, errors) if not t < x: raise CheckSemanticError(f'{str(t)} doesn\'t conform {str(x)}') method = instanceType.get_method(node.method) return method.return_type @visitor.when(ast.StaticDispatch) def visit(self, node:ast.StaticDispatch, scope:Scope, errors): instanceType = scope.getTypeFor(node.instance) classType = scope.getType(node.dispatch_type) if not instanceType < : raise CheckSemanticError(f'type {instanceType} is not a {node.dispatch_type}') if not classType.is_method(node.method): raise CheckSemanticError(f'method {node.method} not defined') argsType = classType.get_method_args(node.method) if len(argsType) != len(node.arguments): raise CheckSemanticError(f'{node.method} require {len(argsType)} arguments') for x, y in argsType, node.arguments: t = self.visit(y, scope, errors) if not t < x: raise CheckSemanticError(f'{str(t)} doesn\'t conform {str(x)}') method = classType.get_method(node.method) return method.return_type @visitor.when(ast.Let) def visit(self, node:ast.Let, scope:Scope, errors): newScope = Scope(scope.classname, scope) for decl in node.init_expr : try: self.visit(decl, newScope, errors) except Exception as e: print(e) return self.visit(node.body, newScope, errors) @visitor.when(ast.Formal) def visit(self, node:ast.Formal, scope:Scope, errors): scope.defineSymbol(node.name, scope.getType(node.param_type), True) t = self.visit(node.init_expr, scope) if not t < node.param_type: raise CheckSemanticError(f'{str(t)} doesn\'t conform {str(node.param_type)}') @visitor.when(ast.If) def visit(self, node:ast.If, scope:Scope, errors): predType = self.visit(node.predicate, scope, errors) if not predType.name == "Bool": raise CheckSemanticError(f'you can\'t match {predType.name} with Bool') ifType = self.visit(node.then_body, scope, errors) elseType = self.visit(node.else_body, scope, errors) return scope.join(ifType, elseType) @visitor.when(ast.WhileLoop) def visit(self, node:ast.WhileLoop, scope:Scope, errors): predType = self.visit(node.predicate, scope, errors) if not predType.name == "Bool": raise CheckSemanticError(f'you can\'t match {predType.name} with Bool') self.visit(node.body, scope, errors) return scope.getType('Object') @visitor.when(ast.Case) def visit(self, node:ast.Case, scope:Scope, errors): self.visit(node.expr, scope, errors) listType = [] for item in node.actions: try: scope.getType(item.action_type) except Exception as e: print(e) listType.append(self.visit(item, scope, errors)) returnType = listType[0] for item in listType[1:]: returnType = scope.join(returnType, item) return returnType @visitor.when(ast.Action) def visit(self, node:ast.Action, scope:Scope, errors): newScope = Scope(scope.classname, scope) newScope.defineSymbol(node.name, scope.getType(node.action_type)) return self.visit(node.body, newScope, errors) @visitor.when(ast.IntegerComplement) def visit(self, node:ast.IntegerComplement, scope:Scope, errors): exprType = self.visit(node.integer_expr, scope, errors) if not exprType.name == "Int": raise CheckSemanticError(f'{exprType.name} doest\' match wiht Int') return scope.getType('Int') @visitor.when(ast.BooleanComplement) def visit(self, node:ast.BooleanComplement, scope:Scope, errors): exprType = self.visit(node.integer_expr, scope, errors) if not exprType.name == 'Bool': raise CheckSemanticError(f'{exprType.name} doest\' match wiht Int') return scope.getType('Bool') @visitor.when(ast.Addition) def visit(self, node:ast.Addition, scope:Scope, errors): leftType = self.visit(node.first, scope, errors) rigthType = self.visit(node.second, scope, errors) if not leftType.name == 'Int' or not rigth.name == 'Int': raise CheckSemanticError(f'expressions type must to be Int') return scope.getType('Int') @visitor.when(ast.Subtraction) def visit(self, node:ast.Subtraction, scope:Scope, errors): leftType = self.visit(node.first, scope, errors) rigthType = self.visit(node.second, scope, errors) if not leftType.name == 'Int' or not rigth.name == 'Int': raise CheckSemanticError(f'expressions type must to be Int') return scope.getType('Int') @visitor.when(ast.Multiplication) def visit(self, node:ast.Multiplication, scope:Scope, errors): leftType = self.visit(node.first, scope, errors) rigthType = self.visit(node.second, scope, errors) if not leftType.name == 'Int' or not rigth.name == 'Int': raise CheckSemanticError(f'expressions type must to be Int') return scope.getType('Int') @visitor.when(ast.Division) def visit(self, node:ast.Division, scope:Scope, errors): leftType = self.visit(node.first, scope, errors) rigthType = self.visit(node.second, scope, errors) if not leftType.name == 'Int' or not rigth.name == 'Int': raise CheckSemanticError(f'expressions type must be Int') return scope.getType('Int') @visitor.when(ast.Equal) def visit(self, node:ast.Equal, scope:Scope, errors): leftType = self.visit(node.first, scope, errors) rigthType = self.visit(node.second, scope, errors) if not leftType.name == rigth.name: raise CheckSemanticError(f'expressions type must be the same type') return scope.getType('Bool') @visitor.when(ast.LessThan) def visit(self, node:ast.LessThan, scope:Scope, errors): leftType = self.visit(node.first, scope, errors) rigthType = self.visit(node.second, scope, errors) if not leftType.name == 'Int' or not rigth.name == 'Int': raise CheckSemanticError(f'expressions type must be Int') return scope.getType('Int') @visitor.when(ast.LessThanOrEqual) def visit(self, node:ast.LessThanOrEqual, scope:Scope, errors): leftType = self.visit(node.first, scope, errors) rigthType = self.visit(node.second, scope, errors) if not leftType.name == 'Int' or not rigth.name == 'Int': raise CheckSemanticError(f'expressions type must be Int') return scope.getType('Int')