def visit(self, node: AttrDeclarationNode, scope: Scope, set_type=None): # print('attr declaration') if node.id == "self": self.errors.append(SEMANTIC_ERROR % ( node.lineno, node.colno, f'"self" is used as attribute name in class "{self.current_type.name}".' )) if node.val is not None: self.visit(node.val, scope) return var, _ = scope.my_find_var(node.id) attr_type = self.context.get_type(node.type) if var is not None: self.errors.append(ATTR_ALREADY_DEFINED % (node.lineno, node.colno, node.id)) else: scope.define_variable(node.id, attr_type) if node.val is not None: return_type = self.visit(node.val, scope) else: return_type = attr_type if attr_type.name == BasicTypes.SELF.value: attr_type = self.current_type if return_type.name == BasicTypes.SELF.value: return_type = self.current_type if not return_type.conforms_to(attr_type): self.errors.append( INCOMPATIBLE_TYPES % (node.lineno, node.colno, return_type.name, attr_type.name))
def visit(self, node, scope=None): scope = Scope() self.current_function = self.register_function('main') instance = self.define_internal_local(scope=scope, name="instance") result = self.define_internal_local(scope=scope, name="result") self.register_instruction(CIL_AST.Allocate('Main', self.context.get_type('Main').tag, instance)) self.register_instruction(CIL_AST.Call(result, 'Main_init', [CIL_AST.Arg(instance)], "Main")) self.register_instruction( CIL_AST.Call(result, self.to_function_name('main', 'Main'), [CIL_AST.Arg(instance)], "Main")) self.register_instruction(CIL_AST.Return(None)) self.current_function = None self.register_data('Abort called from class ') self.register_data('\n') self.dotdata['empty_str'] = '' # Add built-in types in .TYPES section self.register_builtin_types(scope) # Add string equals function self.build_string_equals_function(scope) for klass in node.declarations: self.visit(klass, scope.create_child()) return CIL_AST.Program(self.dottypes, self.dotdata, self.dotcode)
def visit(self, node, scope): token = self.visit(node.obj, scope) if isinstance(token, VoidPod): raise RuntimeException( 'Reference to an instance of a void object.') _o = self.context.get_type('Object') _s = self.context.get_type('String') _io = self.context.get_type('IO') if token.type.conforms_to(_o) and (_o.name, node.method) in cl_baseline: args = (token, ) + tuple( self.visit(arg, scope) for arg in node.args) + (self.context, ) return cl_baseline[_o.name, node.method](*args) if token.type.conforms_to(_s) and (_s.name, node.method) in cl_baseline: args = (token, ) + tuple( self.visit(arg, scope) for arg in node.args) + (self.context, ) return cl_baseline[_s.name, node.method](*args) if token.type.conforms_to(_io) and (_io.name, node.method) in cl_baseline: args = (token, ) + tuple( self.visit(arg, scope) for arg in node.args) + (self.context, ) return cl_baseline[_io.name, node.method](*args) #si es una instantiate.f() meter en el scope hijo todos sus atributos _funcCall_scope = Scope() #para el caso [email protected]() if not node.parent is None: parent_t = self.context.get_type(node.parent) method = parent_t.get_method(node.method, parent_t, False) else: method = token.get_method(node.method, self.currentType, False) for _id, _t, _arg in zip(method.param_names, method.param_types, node.args): _funcCall_scope.define_variable(_id, _t).token = self.visit( _arg, scope) _funcCall_scope.define_variable('self', token.type).token = token self.stack.append(self.currentPod) self.currentPod = token result = self.visit(method.expr, _funcCall_scope) self.currentPod = self.stack.pop() return result
def visit(self, node, scope=None): if scope is None: scope = Scope() for declaration in node.declarations: current = self.context.get_type(declaration.id) parent = current.parent while parent is not None: current.depth += 1 parent = parent.parent for declaration in node.declarations: self.visit(declaration, scope.create_child()) return scope
def visit(self, node, scope=None, set_type=None): to_revisit = [] scope = Scope(self.scope_id) self.scope_id += 1 for declaration in node.declarations: child_scope = scope.create_child(self.scope_id) self.scope_id += 1 visited = self.visit(declaration, child_scope) if not visited: to_revisit.append(declaration) while to_revisit: declaration = to_revisit.pop(0) visited = self.visit(declaration, None) if not visited: to_revisit.append(declaration) return scope
def visit(self, node: BranchNode, scope: Scope, types_used, return_of_case): error_type = self.context.get_type(BasicTypes.ERROR.value) try: var_type = self.context.get_type(node.type) except SemanticError as error: self.errors.append(TYPE_ERROR % (node.lineno, node.colno, error.text)) var_type = error_type if var_type.name != BasicTypes.ERROR.value: if var_type.name in types_used: self.errors.append(SEMANTIC_ERROR % ( node.lineno, node.colno, f'In method "{self.current_method.name}", type "{self.current_type.name}", more than one ' f'branch variable has type "{var_type.name}". ')) types_used.add(var_type.name) self.scope_id += 1 child_scope = scope.create_child(self.scope_id) if node.id == "self": self.errors.append(TYPE_ERROR % ( node.lineno, node.colno, f'In method "{self.current_method.name}", type "{self.current_type.name}", a branch has "self" as ' f"variable name. ")) else: child_scope.define_variable(node.id, var_type) expr_type = self.visit(node.action, child_scope) if return_of_case is None: return_of_case = expr_type return_of_case = self.context.find_first_common_ancestor( expr_type, return_of_case) return return_of_case
def visit(self, node, scope: Scope, set_type=None): # print('variable') var, scope_id = scope.my_find_var(node.lex) if var is None: self.errors.append( VARIABLE_NOT_DEFINED % (node.lineno, node.colno, node.lex, self.current_method.name)) error_type = self.context.get_type(BasicTypes.ERROR.value) return error_type else: node.computed_type = var.type return var.type
def test_execution(program_file: str, debug: bool = False): program = read_file(program_file) context = Context() errors = [] ast = parse(program, debug) if ast is None: # error en el lexer o en el parser # errors.append('Syntactic Errors') else: TypeCollector(context, errors).visit(ast) TypeBuilder(context, errors).visit(ast) # CyclicDependency(context, errors) if not errors: InferenceTypeChecker(context, errors).visit(ast, Scope()) print(CodeBuilder().visit(ast, 0)) Execution(context).visit(ast, Scope()) else: print('\n'.join(errors))
def __init__(self, program, lexer, parser, verbose=False): self.context: Context = Context() self.scope: Scope = Scope() self.program = program self.parser = parser self.lexer = lexer self.ast = self.parser.parse(self.lexer, self.program) self.errors = self.lexer.errors + self.parser.errors if len(self.errors) != 0: return if self.ast is None: return self.depicter = Depicter() if verbose: print(self.depicter.visit(self.ast, 0), '\n') print() self.typeCollector = TypeCollector(self.context, self.errors) self.typeCollector.visit(self.ast) if len(self.errors) == 0: self.typeBuilder = TypeBuilder(self.context, self.errors) self.typeBuilder.visit(self.ast) scope = Scope() if len(self.errors) == 0: self.typeChecker = TypeChecker(self.context, self.errors) self.typeChecker.visit( self.ast, scope) if len(self.errors) == 0: self.coolToCil = COOLToCILVisitor(self.context) cil_ast = self.coolToCil.visit(self.ast, scope) self.cilToMips = CILToMipsVisitor() self.mipsCode = self.cilToMips.visit(cil_ast) return
def check_semantics(program: str, debug: bool = False): context = Context() scope = Scope() errors = [] ast = parse(program, debug) if parser.errorok: errors = ['Syntactic Error'] else: TypeCollector(context, errors).visit(ast) TypeBuilder(context, errors).visit(ast) # CyclicDependency(context, errors) if not errors: TypeChecker(context, errors).visit(ast, scope) return ast, errors, context, scope
def visit(self, node, scope: Scope, set_type=None): # print('assign') error_type = self.context.get_type(BasicTypes.ERROR.value) if node.id == "self": self.errors.append( SEMANTIC_ERROR % (node.lineno, node.colno, f'"self" variable is read-only')) expr_type = self.visit(node.expr, scope) return expr_type var, scope_id = scope.my_find_var(node.id) if var is None: self.errors.append( VARIABLE_NOT_DEFINED % (node.lineno, node.colno, node.id, self.current_method.name)) var_type = error_type else: var_type = var.type expr_type = self.visit(node.expr, scope) if not expr_type.conforms_to(var_type): self.errors.append( INCOMPATIBLE_TYPES % (node.lineno, node.colno, expr_type.name, var_type.name)) node.computed_type = expr_type return expr_type
def final_execution(program_file, program_file_out, debug: bool = False, verbose=False): context = Context() scope = Scope() errors, program, tokens = tokenize(program_file, debug, verbose) if errors or lexer_errors: for (_, line, lexpos, value) in lexer_errors: totallines = program.count('\n') col = get_tokencolumn(program, lexpos) if get_tokencolumn(program, lexpos) > 1 else 2 print_errors(f'({line}, {col - 1}) - LexicographicError: ERROR \"{value}\"') for e in errors: print_errors(e) exit(1) ast = parse(program, debug=debug) # if it has no instructions if ast is None and not parser_errors: print_errors("(0, 0) - SyntacticError: ERROR at or near EOF") exit(1) if parser_errors: for (line, lexpos, _, value) in parser_errors: totallines = program.count('\n') col = get_tokencolumn(program, lexpos) if get_tokencolumn(program, lexpos) > 1 else 2 print_errors(f'({line - totallines}, {col-1}) - SyntacticError: ERROR at or near "{value}"') exit(1) else: PositionateTokensInAST(tokens).visit(ast) TypeCollector(context, errors, program).visit(ast) if errors: for item in errors: print_errors(item) exit(1) TypeBuilder(context, errors, program).visit(ast) cyclicDependency(context, errors, program, ast) if errors: for item in errors: print_errors(item) exit(1) TypeBuilderFeature(context, errors, program).visit(ast) if errors: for item in errors: print_errors(item) exit(1) # CyclicDependency(context, errors) MethodChecker(context, errors, program).visit(ast) InferenceTypeChecker(context, errors, program).visit(ast, scope) TypeChecker(context, errors, program).visit(ast, scope) if errors: for item in errors: print_errors(item) exit(1) ### code generation ### dict_attr, dict_method = {}, {} CollectDeclarationsDict(dict_attr, dict_method, context).visit(ast) get_declarations_dict(dict_attr, dict_method) COOLToCILVisitor(context).visit(ast,scope)