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.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.Program, scope:Scope, errors): for classDef in node.classes: attribs = filter(lambda x: type(x) is ast.ClassAttribute, classDef) attribs = list(attribs) newType = ctype(classDef.name, classDef.parent, [], []) try: scope.createType(newType) except Exception as e: print(str(e)) for i in node.classes: t = self.visit(i, Scope(i.name, scope), errors)
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.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.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.Let, scope: Scope): new_scope = Scope(scope.classname, scope) for decl in node.declarations: self.visit(decl, new_scope) b_type = self.visit(node.body, new_scope) node.static_type = b_type return b_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.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)
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.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)
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.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.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.')
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.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.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
class CheckSemantic: @visitor.on('AST') def visit(self, node, scope, errors): pass @visitor.when(ast.Program) def visit(self, node:ast.Program, scope:Scope, errors): for classDef in node.classes: attribs = filter(lambda x: type(x) is ast.ClassAttribute, classDef) attribs = list(attribs) newType = ctype(classDef.name, classDef.parent, [], []) try: scope.createType(newType) except Exception as e: print(str(e)) for i in node.classes: t = self.visit(i, Scope(i.name, scope), errors) @visitor.when(ast.Class) 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) for i in methods: tb = self.visit(i, Scope(scope.classname, scope), errors)
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.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.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.NewObject, scope: Scope): node.static_type = scope.getType(node.type) return scope.getType(node.type)
def visit(self, node: ast.Boolean, scope: Scope): node.static_type = scope.getType('Bool') return scope.getType("Bool")
def visit(self, node: ast.Object, scope: Scope): node.static_type = scope.getTypeFor(node.name) return scope.getTypeFor(node.name)
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.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.IsVoid, scope: Scope): node.static_type = scope.getType('Bool') self.visit(node.expr, scope) return scope.getType("Bool")