def joosc(targets, options): # SETUP ######## global stdlib_asts # Build a list of targets to compile. target_files = [] for target in targets: if os.path.isfile(target) and target.endswith('.java'): target_files.append(target) elif os.path.isdir(target) and options.directory_crawl == True: target_files.extend(opts.directory_crawl(target)) else: logging.error("Invalid target %s, exiting..." % target) if options.include_stdlib == True and stdlib_asts == None: target_files.extend(opts.stdlib_files) # BUILD AST ############ # Build token list for each file. token_lists = [] for target_file in target_files: token_lists.append(get_tokens(target_file, options)) if options.stage == 'scanner': sys.exit(0) # Build parse trees for each file. parse_trees = [] for i, tokens in enumerate(token_lists): parse_trees.append(get_parse_tree(tokens, target_files[i], options)) if options.stage == 'parser': sys.exit(0) # Weed each parse tree. for i, parse_tree in enumerate(parse_trees): weed_parse_tree(parse_tree, target_files[i], options) if options.stage == 'weeder': sys.exit(0) ast_list = [] from utils.node import find_nodes, Node for i, parse_tree in enumerate(parse_trees): for o, n in enumerate(find_nodes(parse_tree, [Node('FieldDeclaration'), Node('ConstructorDeclaration'), Node('MethodDeclaration')])): n.decl_order = o ast_list.append(get_ast(parse_tree, target_files[i], options)) if options.stage == 'ast': sys.exit(0) # stdlib optimization if options.include_stdlib == True: if stdlib_asts != None: ast_list.extend(stdlib_asts) else: stdlib_asts = [] for i, ast in enumerate(ast_list): if target_files[i] in opts.stdlib_files: stdlib_asts.append(ast) # TYPE RESOLUTION ################## pkg_index = build_environments(ast_list) type_index = typelink.typelink(ast_list, pkg_index) class_index = class_hierarchy.class_hierarchy(ast_list, pkg_index, type_index) if options.stage == 'hierarchy': sys.exit(0) name_resolve.name_link(pkg_index, type_index, class_index) if options.stage == 'name': for i, _ in enumerate(ast_list): if options.include_stdlib == False or target_files[i] not in opts.stdlib_files or \ options.print_stdlib == True: ast_list[i].pprint() sys.exit(0) typecheck.typecheck(type_index, class_index) if options.stage == 'typecheck': for i, _ in enumerate(ast_list): if options.include_stdlib == False or target_files[i] not in opts.stdlib_files or \ options.print_stdlib == True: ast_list[i].pprint() sys.exit(0) name_resolve.check_method_forwardreference(pkg_index, type_index, class_index) for i in ast_list: reachability.reachability(i) if options.stage == 'reachability': for i, _ in enumerate(ast_list): if options.include_stdlib == False or target_files[i] not in opts.stdlib_files or \ options.print_stdlib == True: ast_list[i].pprint() sys.exit(0) codegen.gen(options, ast_list, class_index, type_index)
def build_block_env(tree, carry, new_block=True): """ returns a list of environments sub-environments are recursively generated """ envs = [] for block in find_nodes(tree, [Node('Block'), Node('ForStatement')]): # get all the variables in this environment env = Environment(name='Block') env.node = block block.env = env # the block should point back to the env new_carry = set(carry) if block.name == 'ForStatement': if new_block: env.children.extend(build_block_env(ASTNode(children=[block]), new_carry, new_block=False)) else: # block[0] is ForInit # block[0][0] is LocalVariableDeclaration # block[0][0][1] is Identifier for LocalVariableDecl # block[3] is ForBody for_vars = list(block.select(['ForStatement', 'ForInit', 'LocalVariableDeclaration'])) if len(for_vars) != 0 and block[0][0] == Node('LocalVariableDeclaration'): name = for_vars[0][1].value.value if name in new_carry: logging.error("No two local variables=%s with overlapping scope have the same name" % name) sys.exit(42) env.names[name] = for_vars[0] new_carry.add(name) env.children.extend(build_block_env(block[3], new_carry)) else: for stmt in find_nodes(block, [Node('Block'), Node('ForStatement'), Node('LocalVariableDeclaration')]): # are we making a new block? if stmt == Node('Block') or stmt == Node('ForStatement'): env.children.extend( build_block_env(Node(children=[stmt]), new_carry)) # are we declaring a variable? elif stmt == Node('LocalVariableDeclaration'): name = list(stmt.select(['LocalVariableDeclaration', 'Identifier'])) name = name[0].value.value if name in new_carry: logging.error("No two local variables=%s with overlapping scope have the same name" % name) sys.exit(42) env.names[name] = stmt new_carry.add(name) envs.append(env) return envs
def find_and_resolve_names(type_index, cu_env, pkg_name, stmt, local_vars, disallowed_simple_names=None): for node in find_nodes(stmt, [Node('Name'), Node('MethodInvocation'), Node('FieldAccess'), Node('ArrayAccess'), Node('Assignment')]): if node == Node('MethodInvocation'): # node.children = ['MethodName', 'MethodReceiver', 'Arguments'] # resolve the receiver as much as possible meth_recv = node[1] if len(meth_recv.children) > 0: if meth_recv[0] == Node('Name'): meth_recv_name = '.'.join(meth_recv.leaf_values()) name_node = meth_recv[0] resolved_node = name_link_name(type_index, cu_env, pkg_name, local_vars, meth_recv_name.split('.'), disallowed_simple_names) canon_type = resolve_type_by_name(type_index, cu_env, pkg_name, meth_recv_name) # it could an ambig name if resolved_node != None: name_node.decl = resolved_node name_node.typ = resolved_node.find_child('Type').canon name_node.canon = node.typ # it could be a static type elif canon_type != None: name_node.canon = canon_type else: logging.error('method receiver %s could not be resolved!' % (meth_recv_name)) sys.exit(42) # iteratively resolve the method receiver's identifier -- # used during codegen iteratively_name_link_nodes(type_index, cu_env, pkg_name, local_vars, meth_recv.leafs(), disallowed_simple_names) else: # resolve some more! find_and_resolve_names(type_index, cu_env, pkg_name, meth_recv, local_vars, disallowed_simple_names) # if it has arguments, name resolve those if len(node.children) == 3: find_and_resolve_names(type_index, cu_env, pkg_name, node[2], local_vars, disallowed_simple_names) continue elif node == Node('ArrayAccess'): # node.children = ['ArrayReceiver', 'Primary'] find_and_resolve_names(type_index, cu_env, pkg_name, node[0], local_vars, {}) find_and_resolve_names(type_index, cu_env, pkg_name, node[1], local_vars, disallowed_simple_names) continue elif node == Node('FieldAccess'): # this? # node.children = ['FieldName', 'FieldReceiver'] if node[1][0] == Node('This'): name = ['this'] + node[0].leaf_values() name_nodes = [node[1][0]] + node[0].leafs() else: find_and_resolve_names(type_index, cu_env, pkg_name, node[1], local_vars, disallowed_simple_names) continue elif node == Node('Assignment'): find_and_resolve_names(type_index, cu_env, pkg_name, ASTNode(children=[node[0]]), local_vars) find_and_resolve_names(type_index, cu_env, pkg_name, ASTNode(children=[node[1]]), local_vars, disallowed_simple_names) continue elif node == Node('Name'): name = node.leaf_values() name_nodes = node.leafs() resolved_node = name_link_name(type_index, cu_env, pkg_name, local_vars, name, disallowed_simple_names) if resolved_node == None: logging.error('Could not resolve name %s in %s.%s with %s' % (name, pkg_name, cu_env['ClassDeclaration'], local_vars)) sys.exit(42) # now lets label each part of this ambiguous name iteratively_name_link_nodes(type_index, cu_env, pkg_name, local_vars, name_nodes, disallowed_simple_names) node.decl = resolved_node node.typ = resolved_node.find_child('Type').canon