builder_t* builder_create(const char* description) { if(description == NULL) return NULL; source_t* source = source_open_string(description); symtab_t* symtab = symtab_new(); ast_t* ast = build_ast(source, symtab); if(ast == NULL) { // Error, tidy up source_close(source); symtab_free(symtab); return NULL; } // Success, create builder builder_t* builder = POOL_ALLOC(builder_t); builder->sources = NULL; builder->defs = symtab; builder->dummy_root = ast_blank(TK_TEST); ast_add(builder->dummy_root, ast); add_source(builder, source); return builder; }
ast_t* program_load(const char* path, pass_opt_t* options) { ast_t* program = ast_blank(TK_PROGRAM); ast_scope(program); options->program_pass = PASS_PARSE; // Always load builtin package first, then the specified one. if(package_load(program, stringtab("builtin"), options) == NULL || package_load(program, path, options) == NULL) { ast_free(program); return NULL; } // Reorder packages so specified package is first. ast_t* builtin = ast_pop(program); ast_append(program, builtin); if(!ast_passes_program(program, options)) { ast_free(program); return NULL; } return program; }
ast_t* reify_method_def(ast_t* ast, ast_t* typeparams, ast_t* typeargs, pass_opt_t* opt) { (void)opt; switch(ast_id(ast)) { case TK_FUN: case TK_BE: case TK_NEW: break; default: pony_assert(false); } // Remove the body AST to avoid duplicating it. ast_t* body = ast_childidx(ast, 6); ast_t* temp_body = ast_blank(TK_NONE); ast_swap(body, temp_body); ast_t* r_ast = reify(ast, typeparams, typeargs, opt, true); ast_swap(temp_body, body); ast_free_unattached(temp_body); return r_ast; }
// Create a package AST, set up its state and add it to the given program ast_t* create_package(ast_t* program, const char* name, const char* qualified_name, pass_opt_t* opt) { ast_t* package = ast_blank(TK_PACKAGE); uint32_t pkg_id = program_assign_pkg_id(program); package_t* pkg = POOL_ALLOC(package_t); pkg->path = name; pkg->qualified_name = qualified_name; pkg->id = id_to_string(NULL, pkg_id); const char* p = strrchr(pkg->path, PATH_SLASH); if(p == NULL) p = pkg->path; else p = p + 1; pkg->filename = stringtab(p); if(pkg_id > 1) pkg->symbol = create_package_symbol(program, pkg->filename); else pkg->symbol = NULL; pkg->ast = package; package_set_init(&pkg->dependencies, 1); pkg->group = NULL; pkg->group_index = -1; pkg->next_hygienic_id = 0; pkg->low_index = -1; ast_setdata(package, pkg); ast_scope(package); ast_append(program, package); ast_set(program, pkg->path, package, SYM_NONE, false); ast_set(program, pkg->id, package, SYM_NONE, false); strlist_t* safe = opt->safe_packages; if((safe != NULL) && (strlist_find(safe, pkg->path) == NULL)) pkg->allow_ffi = false; else pkg->allow_ffi = true; pkg->on_stack = false; return package; }
ast_t* program_load(const char* path, pass_opt_t* options) { ast_t* program = ast_blank(TK_PROGRAM); ast_scope(program); options->type_catchup_pass = PASS_PARSE; if(package_load(program, path, options) == NULL || !ast_passes_program(program, options)) { ast_free(program); return NULL; } return program; }
// Add the given method to the relevant name list in the given symbol table static bool add_method_to_list(ast_t* method, methods_t* method_info, const char *entity_name) { assert(method != NULL); assert(method_info != NULL); assert(entity_name != NULL); const char* name = ast_name(ast_childidx(method, 1)); assert(name != NULL); symtab_t* symtab = method_info->symtab; assert(symtab != NULL); // Entity doesn't yet have method, add it to our list for later ast_t* list = (ast_t*)symtab_find(symtab, name, NULL); if(list == NULL) { ast_t* case_clash = (ast_t*)symtab_find_case(symtab, name, NULL); if(case_clash != NULL) { ast_error(case_clash, "in %s method name differs only in case", entity_name); ast_error(method, "previous definition is here"); return false; } // First instance of this name list = ast_blank(TK_ID); ast_set_name(list, name); symtab_add(symtab, name, (void*)list, SYM_NONE); if(method_info->last_list == NULL) ast_add(method_info->name_lists, list); else ast_add_sibling(method_info->last_list, list); method_info->last_list = list; } ast_add(list, method); return true; }
ast_t* program_load(const char* path, pass_opt_t* options) { ast_t* program = ast_blank(TK_PROGRAM); ast_scope(program); if(package_load(program, path, options) == NULL) { ast_free(program); return NULL; } if(!program_passes(program, options)) { ast_free(program); return NULL; } return program; }
// Create a package AST, set up its state and add it to the given program static ast_t* create_package(ast_t* program, const char* name) { ast_t* package = ast_blank(TK_PACKAGE); uint32_t pkg_id = program_assign_pkg_id(program); package_t* pkg = POOL_ALLOC(package_t); pkg->path = name; pkg->id = id_to_string(NULL, pkg_id); const char* p = strrchr(pkg->path, PATH_SLASH); if(p == NULL) p = pkg->path; else p = p + 1; pkg->filename = stringtab(p); if(pkg_id > 1) pkg->symbol = create_package_symbol(program, pkg->filename); else pkg->symbol = NULL; pkg->next_hygienic_id = 0; ast_setdata(package, pkg); ast_scope(package); ast_append(program, package); ast_set(program, pkg->path, package, SYM_NONE); ast_set(program, pkg->id, package, SYM_NONE); if((safe != NULL) && (strlist_find(safe, pkg->path) == NULL)) pkg->allow_ffi = false; else pkg->allow_ffi = true; return package; }
// Add methods from provided traits into the given entity static bool build_entity_def(ast_t* entity) { assert(entity != NULL); ast_state_t state = (ast_state_t)(uint64_t)ast_data(entity); // Check for recursive definitions switch(state) { case AST_STATE_INITIAL: ast_setdata(entity, (void*)AST_STATE_INPROGRESS); break; case AST_STATE_INPROGRESS: ast_error(entity, "traits can't be recursive"); return false; case AST_STATE_DONE: return true; default: assert(0); return false; } symtab_t* symtab = symtab_new(); ast_t* name_lists = ast_blank(TK_MEMBERS); methods_t method_info = { symtab, name_lists, NULL }; bool r = process_provides(entity, &method_info); symtab_free(symtab); ast_free(name_lists); ast_setdata(entity, (void*)AST_STATE_DONE); return r; }