def visit(self, node: ast.StaticDispatch, scope: Scope): instance_type = self.visit(node.instance, scope) class_type = scope.getType(node.dispatch_type) if instance_type.name == 'SELF_TYPE': instance_type = scope.getType(scope.classname) if not instance_type < class_type: raise CheckSemanticError( f'type {str(instance_type)} is not a {str(class_type)}') if not class_type.is_method(node.method): raise CheckSemanticError(f'method {node.method} not defined') args_type = class_type.get_method_args(node.method) if len(args_type) != len(node.arguments): raise CheckSemanticError( f'{node.method} require {len(args_type)} arguments') for i in range(len(args_type)): t = self.visit(node.arguments[i], scope) if not t < args_type[i]: raise CheckSemanticError( f'{str(t)} doesn\'t conform {str(args_type[i])}') method = class_type.get_method(node.method) r_type = method[node.method]['return_type'] if r_type.name == 'SELF_TYPE': node.static_type = class_type return class_type node.static_type = r_type return r_type
def visit(self, node: ast.Case, scope: Scope): t = list(scope.get_types().keys()) t.reverse() def get_by_(tp, l: ast.Action): for i in l: if tp == i.action_type: return i k = [] for i in t: n = get_by_(i, node.actions) if n: k.append(n) node.actions = k self.visit(node.expr, scope) list_type = [] for item in node.actions: list_type.append(self.visit(item, scope)) return_type = list_type[0] for item in list_type[1:]: if return_type.name == 'SELF_TYPE' and item.name == 'SELF_TYPE': continue elif return_type.name == 'SELF_TYPE': return_type = scope.join(scope.getType(scope.classname), item) elif item.name == 'SELF_TYPE': return_type = scope.join(scope.getType(scope.classname), return_type) else: return_type = scope.join(return_type, item) node.static_type = return_type return return_type
def visit(self, node: ast.Action, scope: Scope): scope.getType(node.action_type) new_scope = Scope(scope.classname, scope) new_scope.defineSymbol(node.name, scope.getType(node.action_type)) return_type = self.visit(node.body, new_scope) node.static_type = return_type return return_type
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)
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
def visit(self, node: ast.Equal, scope: Scope): left_type = self.visit(node.first, scope) right_type = self.visit(node.second, scope) if left_type.name == 'SELF_TYPE': left_type = scope.getType(scope.classname) if right_type.name == 'SELF_TYPE': right_type = scope.getType(scope.classname) if not left_type.name == right_type.name: raise CheckSemanticError( f'In equal expressions type must be the same type') bool_type = scope.getType('Bool') node.static_type = bool_type return bool_type
def visit(self, node: ast.LessThan, scope: Scope): left_type = self.visit(node.first, scope) right_type = self.visit(node.second, scope) if not left_type.name == 'Int' or not right_type.name == 'Int': raise CheckSemanticError(f'expressions type must be Int') bool_type = scope.getType('Bool') return bool_type
def visit(self, node: ast.IntegerComplement, scope: Scope): exp_type = self.visit(node.integer_expr, scope) if not exp_type.name == "Int": raise CheckSemanticError(f'{exp_type.name} doest\' match with Int') int_type = scope.getType('Int') node.static_type = int_type return int_type
def visit(self, node: ast.BooleanComplement, scope: Scope): exp_type = self.visit(node.boolean_expr, scope) if not exp_type.name == 'Bool': raise CheckSemanticError(f'{exp_type.name} doest\' match wiht Int') bool_type = scope.getType('Bool') node.static_type = bool_type return bool_type
def visit(self, node: ast.Division, scope: Scope): left_type = self.visit(node.first, scope) right_type = self.visit(node.second, scope) if not left_type.name == 'Int' or not right_type.name == 'Int': raise CheckSemanticError(f'expressions type must be Int') int_type = scope.getType('Int') node.static_type = int_type return int_type
def visit(self, node: ast.ClassAttribute, scope: Scope): node.static_type = scope.getType(node.attr_type) if node.init_expr: t_exp = self.visit(node.init_expr, scope) if node.attr_type != 'SELF_TYPE': if t_exp.name == 'SELF_TYPE': raise CheckSemanticError( f'You can\'t not assign a SELF_TYPE expression in a non SELF_TYPE' f'attribute') if not t_exp < scope.getType(node.attr_type): raise CheckSemanticError( f'{str(t_exp)} doesn\'t conform {str(scope.getType(node.attr_type))}' ) else: if t_exp.name == 'SELF_TYPE': raise CheckSemanticError( f'Attribute {node.name} of type {node.attr_type} must to be instanced' f' by a SELF_type expression.')
def visit(self, node: ast.WhileLoop, scope: Scope): pred_type = self.visit(node.predicate, scope) if not pred_type.name == "Bool": raise CheckSemanticError( f'you can\'t match {pred_type.name} with Bool') self.visit(node.body, scope) object_type = scope.getType('Object') node.static_type = object_type return object_type
def visit(self, node: ast.ClassMethod, scope: Scope): node.static_type = scope.getType(node.return_type) for i in node.formal_params: scope.defineSymbol(i.name, scope.getType(i.param_type)) tb = self.visit(node.body, scope) if tb.name == 'SELF_TYPE' and node.return_type == 'SELF_TYPE': return scope.classname elif tb.name == 'SELF_TYPE': if scope.getType(scope.classname) < node.static_type: return node.static_type else: raise CheckSemanticError( f'{scope.getType(scope.classname)} doesn\'t conform {node.static_type}' ) elif node.return_type == 'SELF_TYPE': raise CheckSemanticError( f'Method {node.name} returns SELF_TYPE and body doesn\'t') if not tb < scope.getType(node.return_type): raise CheckSemanticError( f'{tb} doesn\'t conform {node.return_type}') return scope.getType(node.return_type)
def visit(self, node: ast.If, scope: Scope): pred_type = self.visit(node.predicate, scope) if not pred_type.name == "Bool": raise CheckSemanticError( f'you can\'t match {pred_type.name} with Bool') if_type = self.visit(node.then_body, scope) else_type = self.visit(node.else_body, scope) if if_type.name == 'SELF_TYPE' and if_type.name == 'SELF_TYPE': node.static_type = if_type return if_type elif if_type.name == 'SELF_TYPE': return_type = scope.join(else_type, scope.getType(scope.classname)) node.static_type = return_type return return_type elif else_type.name == 'SELF_TYPE': return_type = scope.join(if_type, scope.getType(scope.classname)) node.static_type = return_type return return_type else: return_type = scope.join(if_type, else_type) node.static_type = return_type return return_type
def visit(self, node: ast.Formal, scope: Scope): scope.defineSymbol(node.name, scope.getType(node.param_type), True) t = self.visit(node.init_expr, scope) if not t: node.static_type = scope.getType( node.param_type ) if node.param_type != 'SELF_TYPE' else scope.getType( scope.classname) return if node.param_type == 'SELF_TYPE' and t.name == 'SELF_TYPE': return elif t.name == 'SELF_TYPE': if t < scope.getType(scope.classname): return else: raise CheckSemanticError( f'{node.name} doesn\'t conform {scope.classname}') elif node.param_type == 'SELF_TYPE': raise CheckSemanticError( f'Only can assign SELF_TYPE in a SELF_TYPE variable.') if not t < scope.getType(node.param_type): raise CheckSemanticError( f'{str(t)} doesn\'t conform {str(node.param_type)}')
def visit(self, node: ast.Assignment, scope: Scope): instance_type = scope.getTypeFor(node.instance.name) expr_type = self.visit(node.expr, scope) if expr_type.name == 'SELF_TYPE': r_type = scope.getType(scope.classname) if r_type < instance_type: return r_type raise CheckSemanticError( f'{r_type} doesn\'t conform {instance_type}') if not expr_type < instance_type: raise CheckSemanticError( f'{expr_type} doesn\'t conform {instance_type}') node.static_type = expr_type return expr_type
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
def visit(self, node:ast.Class, scope:Scope, errors): methods = filter(lambda x: type(x) is ast.ClassMethod, classDef) methods = list(methods) attribs = filter(lambda x: type(x) is ast.ClassAttribute, classDef) attribs = list(attribs) for i in attribs: ta = self.visit(i, scope, errors) try: scope.getType(node.name).add_attrib({i.name: scope.getType(i.attr_type)}) except Exception as e: print(e) for i in methods: try: scope.getType(node.name).add_method({i.name:{ 'formal_params':{ t.name: scope.getType(t.param_type) for j in i.formal_params }, 'return_type': scope.getType(i.return_type), 'body': i.body }}) exec Exception as e: print(e)
def visit(self, node: ast.Self, scope: Scope): node.static_type = scope.getType(scope.classname) return scope.getType('SELF_TYPE')
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')
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')
def visit(self, node:ast.Integer, scope:Scope, errors): return scope.getType("Int")
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')
def visit(self, node:ast.String, scope:Scope, errors): return scope.getType("String")
def visit(self, node: ast.Integer, scope: Scope): node.static_type = scope.getType('Int') return scope.getType("Int")
def visit(self, node: ast.String, scope: Scope): node.static_type = scope.getType('String') return scope.getType("String")
def visit(self, node: ast.Boolean, scope: Scope): node.static_type = scope.getType('Bool') return scope.getType("Bool")
def visit(self, node: ast.IsVoid, scope: Scope): node.static_type = scope.getType('Bool') self.visit(node.expr, scope) return scope.getType("Bool")
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.NewObject, scope: Scope): node.static_type = scope.getType(node.type) return scope.getType(node.type)