void dwarf_field(dwarf_t* dwarf, gentype_t* composite, gentype_t* field, int index) { char buf[32]; memset(buf, 0, sizeof(buf)); dwarf_meta_t meta; setup_dwarf(dwarf, &meta, field, false, true); meta.typearg = field->type_name; if(composite->underlying == TK_TUPLETYPE) { meta.flags |= DWARF_CONSTANT; snprintf(buf, sizeof(buf), "_%d", index + 1); meta.name = buf; } else { ast_t* def = (ast_t*)ast_data(composite->ast); ast_t* members = ast_childidx(def, 4); ast_t* fld = ast_childidx(members, index); meta.name = ast_name(ast_child(fld)); if(ast_id(fld) == TK_FLET) meta.flags |= DWARF_CONSTANT; } if(meta.name[0] == '_') meta.flags |= DWARF_PRIVATE; LLVMTypeRef structure = composite->primitive; int offset = 0; if(composite->underlying != TK_TUPLETYPE) { structure = composite->structure; if(composite->underlying != TK_STRUCT) offset++; if(composite->underlying == TK_ACTOR) offset++; } meta.offset = 8 * LLVMOffsetOfElement(dwarf->target_data, structure, offset + index); symbols_field(dwarf->symbols, &meta); }
// Determine which body to use for the given method static bool resolve_body(ast_t* entity, ast_t* method, pass_opt_t* options) { assert(entity != NULL); assert(method != NULL); method_t* info = (method_t*)ast_data(method); assert(info != NULL); if(info->local_def) // Local defs just use their own body return true; token_id e_id = ast_id(entity); bool concrete = (e_id == TK_PRIMITIVE) || (e_id == TK_STRUCT) || (e_id == TK_CLASS) || (e_id == TK_ACTOR); const char* name = ast_name(ast_childidx(method, 1)); assert(name != NULL); // NExt try a delegate body ast_t* r = resolve_delegate_body(entity, method, info, name); if(r == BODY_ERROR) return false; if(r == NULL) // And finally a default body r = resolve_default_body(entity, method, info, name, concrete); if(r == BODY_ERROR) return false; if(r != NULL) { // We have a body, use it and patch up symbol tables ast_t* old_body = ast_childidx(method, 6); ast_replace(&old_body, r); ast_visit(&method, rescope, NULL, options, PASS_ALL); return true; } // Nowhere left to get a body from if(concrete) { ast_error(entity, "no body found for method %s", name); ast_error(method, "provided from here"); return false; } return true; }
static bool generate_actor(compile_t* c, ast_t* ast) { ast_t* id = ast_child(ast); ast_t* type = type_builtin(c->opt, ast, ast_name(id)); if(type == NULL) return false; gentype_t g; bool ok = gentype(c, type, &g); ast_free_unattached(type); return ok; }
static int check_call_send(ast_t* ast, bool in_final) { AST_GET_CHILDREN(ast, positional, named, question, lhs); AST_GET_CHILDREN(lhs, receiver, method); switch(ast_id(receiver)) { case TK_NEWREF: case TK_FUNREF: case TK_FUNCHAIN: // Qualified. Get the real receiver. receiver = ast_child(receiver); method = ast_sibling(receiver); break; default: {} } ast_t* type = ast_type(receiver); // If we don't know the final type, we can't be certain of what all // implementations of the method do. Leave it as might send. if(!is_known(type)) return FINAL_CAN_SEND; ast_t* def = receiver_def(type); pony_assert(def != NULL); const char* method_name = ast_name(method); ast_t* fun = ast_get(def, method_name, NULL); pony_assert(fun != NULL); AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error, body); int r = check_body_send(body, false); if(r == FINAL_NO_SEND) { // Mark the call as no send. ast_clearmightsend(ast); } else if(in_final && (r == FINAL_RECURSE)) { // If we're in the finaliser, which can't recurse, we treat a recurse as // a no send. ast_clearmightsend(ast); } else if((r & FINAL_CAN_SEND) != 0) { // Mark the call as can send. ast_setsend(ast); } return r; }
static LLVMValueRef special_case_platform(compile_t* c, ast_t* ast) { AST_GET_CHILDREN(ast, positional, named, postfix); AST_GET_CHILDREN(postfix, receiver, method); const char* method_name = ast_name(method); bool is_target; if(os_is_target(method_name, c->opt->release, &is_target, c->opt)) return LLVMConstInt(c->ibool, is_target ? 1 : 0, false); ast_error(c->opt->check.errors, ast, "unknown Platform setting"); return NULL; }
static bool package_access(pass_opt_t* opt, ast_t** astp) { ast_t* ast = *astp; // Left is a packageref, right is an id. ast_t* left = ast_child(ast); ast_t* right = ast_sibling(left); assert(ast_id(left) == TK_PACKAGEREF); assert(ast_id(right) == TK_ID); // Must be a type in a package. const char* package_name = ast_name(ast_child(left)); ast_t* package = ast_get(left, package_name, NULL); if(package == NULL) { ast_error(right, "can't access package '%s'", package_name); return false; } assert(ast_id(package) == TK_PACKAGE); const char* type_name = ast_name(right); ast_t* type = ast_get(package, type_name, NULL); if(type == NULL) { ast_error(right, "can't find type '%s' in package '%s'", type_name, package_name); return false; } ast_settype(ast, type_sugar(ast, package_name, type_name)); ast_setid(ast, TK_TYPEREF); return expr_typeref(opt, astp); }
static bool is_nominal_sub_interface(ast_t* sub, ast_t* super) { ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* super_def = (ast_t*)ast_data(super); ast_t* sub_typeargs = ast_childidx(sub, 2); ast_t* super_typeargs = ast_childidx(super, 2); ast_t* sub_typeparams = ast_childidx(sub_def, 1); ast_t* super_typeparams = ast_childidx(super_def, 1); ast_t* super_members = ast_childidx(super_def, 4); ast_t* super_member = ast_child(super_members); while(super_member != NULL) { ast_t* super_member_id = ast_childidx(super_member, 1); ast_t* sub_member = ast_get(sub_def, ast_name(super_member_id), NULL); if(sub_member == NULL) return false; ast_t* r_sub_member = reify(sub_typeargs, sub_member, sub_typeparams, sub_typeargs); if(r_sub_member== NULL) return false; ast_t* r_super_member = reify(super_typeargs, super_member, super_typeparams, super_typeargs); if(r_super_member == NULL) { ast_free_unattached(r_sub_member); return false; } bool ok = is_fun_sub_fun(r_sub_member, r_super_member, sub, super); ast_free_unattached(r_sub_member); ast_free_unattached(r_super_member); if(!ok) return false; super_member = ast_sibling(super_member); } return true; }
bool expr_fieldref(pass_opt_t* opt, ast_t* ast, ast_t* find, token_id tid) { AST_GET_CHILDREN(ast, left, right); ast_t* l_type = ast_type(left); if(is_typecheck_error(l_type)) return false; AST_GET_CHILDREN(find, id, f_type, init); // Viewpoint adapted type of the field. ast_t* type = viewpoint_type(l_type, f_type); if(ast_id(type) == TK_ARROW) { ast_t* upper = viewpoint_upper(type); if(upper == NULL) { ast_error(ast, "can't read a field through %s", ast_print_type(l_type)); return false; } ast_free_unattached(upper); } // Set the unadapted field type. ast_settype(right, f_type); // Set the type so that it isn't free'd as unattached. ast_setid(ast, tid); ast_settype(ast, type); if(ast_id(left) == TK_THIS) { // Handle symbol status if the left side is 'this'. ast_t* id = ast_child(find); const char* name = ast_name(id); sym_status_t status; ast_get(ast, name, &status); if(!valid_reference(opt, ast, type, status)) return false; } return true; }
// Find the declaration for the given FFI call that is valid for the given // build config, within the specified ifdef condition (NULL for none). // Returns: true on success, false on failure. static bool find_ffi_decl(ast_t* ast, ast_t* package, ast_t* ifdef_cond, ast_t** out_decl, pass_opt_t* opt) { pony_assert(ast != NULL); pony_assert(package != NULL); pony_assert(out_decl != NULL); const char* ffi_name = ast_name(ast_child(ast)); buildflagset_t* config = buildflagset_create(); // Find all the relevant build flags. if(ifdef_cond != NULL) find_flags_in_cond(ifdef_cond, config); if(!find_decl_flags(package, ffi_name, config)) { // There are no declarations for this FFI. buildflagset_free(config); *out_decl = NULL; return true; } check_config_count(config, ast); ffi_decl_t decl_info = { NULL, NULL }; buildflagset_startenum(config); while(buildflagset_next(config)) { if(ifdef_cond == NULL || cond_eval(ifdef_cond, config, false, opt)) { // ifdef condition true, or not in an ifdef. // Look for valid FFI declaration. if(!find_decl_for_config(ast, package, ffi_name, config, &decl_info, opt)) { // Config has failed. buildflagset_free(config); return false; } pony_assert(decl_info.decl != NULL); } } buildflagset_free(config); pony_assert(decl_info.decl != NULL); *out_decl = decl_info.decl; return true; }
// Find the index of the handler for the given URI static int find_handler(pass_opt_t* opt, ast_t* uri, const char** out_locator) { assert(uri != NULL); assert(out_locator != NULL); assert(ast_id(uri) == TK_STRING); const char* text = ast_name(uri); const char* colon = strchr(text, ':'); if(colon == NULL) { // No scheme specified, use default *out_locator = stringtab(text); return 0; } size_t scheme_len = colon - text + 1; // +1 for colon // Search for matching handler for(int i = 0; handlers[i].scheme != NULL; i++) { if(handlers[i].scheme_len == scheme_len && strncmp(handlers[i].scheme, text, scheme_len) == 0) { if(handlers[i].handler == NULL) // No handler provided (probably test:) break; // Matching scheme found *out_locator = stringtab(colon + 1); return i; } } // No match found #ifdef PLATFORM_IS_WINDOWS if(colon == text + 1) { // Special case error message ast_error(opt->check.errors, uri, "Use scheme %c: not found. " "If this is an absolute path use prefix \"package:\"", text[0]); return -1; } #endif ast_error(opt->check.errors, uri, "Use scheme %.*s not found", (int)scheme_len, text); return -1; }
static void name_params(compile_t* c, reachable_type_t* t, reachable_method_t* m, ast_t* params, LLVMValueRef func) { // Name the receiver 'this'. name_param(c, t, m, func, c->str_this, 0, ast_line(params), ast_pos(params)); // Name each parameter. ast_t* param = ast_child(params); for(size_t i = 0; i < m->param_count; i++) { name_param(c, m->params[i], m, func, ast_name(ast_child(param)), (unsigned)i + 1, ast_line(param), ast_pos(param)); param = ast_sibling(param); } }
LLVMValueRef gen_localdecl(compile_t* c, ast_t* ast) { ast_t* id = ast_child(ast); ast_t* type = ast_type(id); const char* name = ast_name(id); // If this local has already been generated, don't create another copy. This // can happen when the same ast node is generated more than once, such as // the condition block of a while expression. LLVMValueRef value = codegen_getlocal(c, name); if(value != NULL) return GEN_NOVALUE; reach_type_t* t = reach_type(c->reach, type); // All alloca should happen in the entry block of a function. LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(codegen_fun(c)); LLVMValueRef inst = LLVMGetFirstInstruction(entry_block); if(inst != NULL) LLVMPositionBuilderBefore(c->builder, inst); else LLVMPositionBuilderAtEnd(c->builder, entry_block); LLVMValueRef alloc = LLVMBuildAlloca(c->builder, t->use_type, name); // Store the alloca to use when we reference this local. codegen_setlocal(c, name, alloc); LLVMMetadataRef file = codegen_difile(c); LLVMMetadataRef scope = codegen_discope(c); LLVMMetadataRef info = LLVMDIBuilderCreateAutoVariable(c->di, scope, name, file, (unsigned)ast_line(ast), t->di_type); LLVMMetadataRef expr = LLVMDIBuilderCreateExpression(c->di, NULL, 0); LLVMDIBuilderInsertDeclare(c->di, alloc, info, expr, (unsigned)ast_line(ast), (unsigned)ast_pos(ast), scope, LLVMGetInsertBlock(c->builder)); // Put the builder back where it was. LLVMPositionBuilderAtEnd(c->builder, this_block); return GEN_NOVALUE; }
static bool check_finaliser(ast_t* ast) { AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body); if(strcmp(ast_name(id), "_final")) return true; bool ok = true; if(ast_id(ast) != TK_FUN) { ast_error(ast, "_final must be a function"); ok = false; } if(ast_id(cap) != TK_BOX) { ast_error(cap, "_final must be box"); ok = false; } if(ast_id(typeparams) != TK_NONE) { ast_error(typeparams, "_final must not be polymorphic"); ok = false; } if(ast_childcount(params) != 0) { ast_error(params, "_final must not have parameters"); ok = false; } if(!is_none(result)) { ast_error(result, "_final must return None"); ok = false; } if(ast_id(can_error) != TK_NONE) { ast_error(can_error, "_final cannot raise an error"); ok = false; } return ok; }
// Write the given package home page to its own file static void doc_package_home(docgen_t* docgen, ast_t* package, ast_t* doc_string) { assert(docgen != NULL); assert(docgen->index_file != NULL); assert(docgen->home_file != NULL); assert(docgen->type_file == NULL); assert(package != NULL); assert(ast_id(package) == TK_PACKAGE); // First open a file size_t tqfn_len; char* tqfn = write_tqfn(package, "-index", &tqfn_len); // Package group fprintf(docgen->index_file, "- package %s:\n", package_qualified_name(package)); docgen->type_file = doc_open_file(docgen, true, tqfn, ".md"); if(docgen->type_file == NULL) return; // Add reference to new file to index file fprintf(docgen->index_file, " - Package: \"%s.md\"\n", tqfn); // Add reference to package to home file fprintf(docgen->home_file, "* [%s](%s)\n", package_qualified_name(package), tqfn); // Now we can write the actual documentation for the package if(doc_string != NULL) { assert(ast_id(doc_string) == TK_STRING); fprintf(docgen->type_file, "%s", ast_name(doc_string)); } else { fprintf(docgen->type_file, "No package doc string provided for %s.", package_qualified_name(package)); } pool_free_size(tqfn_len, tqfn); fclose(docgen->type_file); docgen->type_file = NULL; }
static const char* suggest_alt_name(ast_t* ast, const char* name) { assert(ast != NULL); assert(name != NULL); size_t name_len = strlen(name); if(is_name_private(name)) { // Try without leading underscore const char* try_name = stringtab(name + 1); if(ast_get(ast, try_name, NULL) != NULL) return try_name; } else { // Try with a leading underscore char* buf = (char*)ponyint_pool_alloc_size(name_len + 2); buf[0] = '_'; strncpy(buf + 1, name, name_len + 1); const char* try_name = stringtab_consume(buf, name_len + 2); if(ast_get(ast, try_name, NULL) != NULL) return try_name; } // Try with a different case (without crossing type/value boundary) ast_t* case_ast = ast_get_case(ast, name, NULL); if(case_ast != NULL) { ast_t* id = case_ast; if(ast_id(id) != TK_ID) id = ast_child(id); assert(ast_id(id) == TK_ID); const char* try_name = ast_name(id); if(ast_get(ast, try_name, NULL) != NULL) return try_name; } // Give up return NULL; }
ast_t* type_for_this(typecheck_t* t, ast_t* ast, token_id cap, token_id ephemeral) { bool make_arrow = false; if(cap == TK_BOX) { cap = TK_REF; make_arrow = true; } AST_GET_CHILDREN(t->frame->type, id, typeparams); BUILD(typeargs, ast, NODE(TK_NONE)); BUILD(type, ast, NODE(TK_NOMINAL, NODE(TK_NONE) TREE(id) TREE(typeargs) NODE(cap) NODE(ephemeral))); if(ast_id(typeparams) == TK_TYPEPARAMS) { ast_setid(typeargs, TK_TYPEARGS); ast_t* typeparam = ast_child(typeparams); while(typeparam != NULL) { ast_t* typeparam_id = ast_child(typeparam); ast_t* typearg = type_sugar(ast, NULL, ast_name(typeparam_id)); ast_append(typeargs, typearg); typeparam = ast_sibling(typeparam); } } if(make_arrow) { BUILD(arrow, ast, NODE(TK_ARROW, NODE(TK_THISTYPE) TREE(type))); return arrow; } return type; }
static bool is_constructed_from(pass_opt_t* opt, ast_t* ast, ast_t* type) { ast_t* parent = ast_parent(ast); if(ast_id(parent) != TK_DOT) return false; AST_GET_CHILDREN(parent, left, right); ast_t* find = lookup_try(opt, parent, type, ast_name(right)); if(find == NULL) return false; bool ok = ast_id(find) == TK_NEW; ast_free_unattached(find); return ok; }
// Check that the given entity, if concrete, has bodies for all methods. static bool check_concrete_bodies(ast_t* entity, pass_opt_t* opt) { assert(entity != NULL); token_id variety = ast_id(entity); if((variety != TK_PRIMITIVE) && (variety != TK_STRUCT) && (variety != TK_CLASS) && (variety != TK_ACTOR)) return true; bool r = true; ast_t* members = ast_childidx(entity, 4); assert(members != NULL); for(ast_t* p = ast_child(members); p != NULL; p = ast_sibling(p)) { if(is_method(p)) { method_t* info = (method_t*)ast_data(p); assert(info != NULL); if(!info->failed) { const char* name = ast_name(ast_childidx(p, 1)); if(ast_checkflag(p, AST_FLAG_AMBIGUOUS)) { // Concrete types must not have ambiguous bodies. ast_error(opt->check.errors, entity, "multiple possible bodies for " "method %s, local disambiguation required", name); r = false; } else if(info->body_donor == NULL) { // Concrete types must have method bodies. assert(info->trait_ref != NULL); ast_error(opt->check.errors, info->trait_ref, "no body found for method %s", name); r = false; } } } } return r; }
static void name_params(compile_t* c, ast_t* type, ast_t* params, LLVMValueRef func) { int count = 0; // Name the receiver 'this'. name_param(c, func, stringtab("this"), type, count++); // Name each parameter. ast_t* param = ast_child(params); while(param != NULL) { AST_GET_CHILDREN(param, id, type); name_param(c, func, ast_name(id), type, count++); param = ast_sibling(param); } }
// 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; }
// Write the given list of type parameters to the current type file, with // surrounding []. If the given list is empty nothing is written. static void doc_type_params(docgen_t* docgen, ast_t* t_params, bool generate_links) { assert(docgen != NULL); assert(docgen->type_file != NULL); assert(t_params != NULL); if(ast_id(t_params) == TK_NONE) return; assert(ast_id(t_params) == TK_TYPEPARAMS); if(generate_links) fprintf(docgen->type_file, "\\["); else fprintf(docgen->type_file, "["); ast_t* first = ast_child(t_params); for(ast_t* t_param = first; t_param != NULL; t_param = ast_sibling(t_param)) { if(t_param != first) fprintf(docgen->type_file, ", "); AST_GET_CHILDREN(t_param, id, constraint, default_type); const char* name = ast_name(id); assert(name != NULL); if(ast_id(default_type) != TK_NONE) fprintf(docgen->type_file, "optional "); fprintf(docgen->type_file, "%s: ", name); if(ast_id(constraint) != TK_NONE) doc_type(docgen, constraint, generate_links); else fprintf(docgen->type_file, "no constraint"); } if(generate_links) fprintf(docgen->type_file, "\\]"); else fprintf(docgen->type_file, "]"); }
static bool check_fields_defined(pass_opt_t* opt, ast_t* ast) { assert(ast_id(ast) == TK_NEW); ast_t* members = ast_parent(ast); ast_t* member = ast_child(members); bool result = true; while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { sym_status_t status; ast_t* id = ast_child(member); ast_t* def = ast_get(ast, ast_name(id), &status); if((def != member) || (status != SYM_DEFINED)) { ast_error(opt->check.errors, def, "field left undefined in constructor"); result = false; } break; } default: {} } member = ast_sibling(member); } if(!result) ast_error(opt->check.errors, ast, "constructor with undefined fields is here"); return result; }
static void list_doc_params(docgen_t* docgen, ast_t* params) { assert(docgen != NULL); assert(docgen->type_file != NULL); assert(params != NULL); ast_t* first = ast_child(params); for(ast_t* param = first; param != NULL; param = ast_sibling(param)) { if(param == first) fprintf(docgen->type_file, "#### Parameters\n\n"); fprintf(docgen->type_file, "* "); AST_GET_CHILDREN(param, id, type, def_val); const char* name = ast_name(id); assert(name != NULL); fprintf(docgen->type_file, " %s: ", name); doc_type(docgen, type, true); // if we have a default value, add it to the documentation if(ast_id(def_val) != TK_NONE) { switch(ast_id(def_val)) { case TK_STRING: fprintf(docgen->type_file, "= \"%s\"", ast_get_print(def_val)); break; default: fprintf(docgen->type_file, " = %s", ast_get_print(def_val)); break; } } fprintf(docgen->type_file, "\n"); } fprintf(docgen->type_file, "\n"); }
static bool make_tuple_index(ast_t** astp) { ast_t* ast = *astp; const char* name = ast_name(ast); if(!is_name_private(name)) return false; for(size_t i = 1; name[i] != '\0'; i++) { if((name[i] < '0') || (name[i] > '9')) return false; } size_t index = strtol(&name[1], NULL, 10) - 1; ast_t* node = ast_from_int(ast, index); ast_replace(astp, node); return true; }
static const char* suggest_alt_name(ast_t* ast, const char* name) { assert(ast != NULL); assert(name != NULL); size_t name_len = strlen(name); VLA(char, buf, name_len + 2); if(name[0] == '_') { // Try without leading underscore const char* try_name = stringtab(name + 1); if(ast_get(ast, try_name, NULL) != NULL) return try_name; } else { // Try with a leading underscore buf[0] = '_'; strncpy(buf + 1, name, name_len + 1); const char* try_name = stringtab(buf); if(ast_get(ast, try_name, NULL) != NULL) return try_name; } // Try with a different case (without crossing type/value boundary) ast_t* case_ast = ast_get_case(ast, name, NULL); if(case_ast != NULL) { assert(ast_child(case_ast) != NULL); const char* try_name = ast_name(ast_child(case_ast)); if(ast_get(ast, try_name, NULL) != NULL) return try_name; } // Give up return NULL; }
bool ffi_get_decl(typecheck_t* t, ast_t* ast, ast_t** out_decl, pass_opt_t* opt) { pony_assert(t != NULL); pony_assert(ast != NULL); pony_assert(out_decl != NULL); const char* ffi_name = ast_name(ast_child(ast)); // Get the symbol table for our containing ifdef (if any) directly. We can't // just search up through scopes as normal since FFI declarations in outer // scopes may not be valid within our ifdef. ast_t* ifdef = t->frame->ifdef_clause; pony_assert(ifdef != NULL); symtab_t* symtab = ast_get_symtab(ifdef); sym_status_t status; ast_t* decl = symtab_find(symtab, ffi_name, &status); if(status == SYM_ERROR) // We've already found an error with that FFI name in this context. return false; if(status == SYM_NONE) { // We've not looked that up yet. pony_assert(decl == NULL); if(!find_ffi_decl(ast, t->frame->package, t->frame->ifdef_cond, &decl, opt)) { // That went wrong. Record that so we don't try again. symtab_add(symtab, ffi_name, NULL, SYM_ERROR); return false; } // Store declaration found for next time, including if we found nothing. symtab_add(symtab, ffi_name, decl, SYM_FFIDECL); } *out_decl = decl; return true; }
bool is_this_incomplete(typecheck_t* t, ast_t* ast) { // If we're in a default argument, we're incomplete by definition. if(t->frame->method == NULL) return true; // If we're not in a constructor, we're complete by definition. if(ast_id(t->frame->method) != TK_NEW) return false; // Check if all fields have been marked as defined. ast_t* members = ast_childidx(t->frame->type, 4); ast_t* member = ast_child(members); while(member != NULL) { switch(ast_id(member)) { case TK_FLET: case TK_FVAR: case TK_EMBED: { sym_status_t status; ast_t* id = ast_child(member); ast_get(ast, ast_name(id), &status); if(status != SYM_DEFINED) return true; break; } default: {} } member = ast_sibling(member); } return false; }
LLVMValueRef gen_string(compile_t* c, ast_t* ast) { const char* name = ast_name(ast); genned_string_t k; k.string = name; size_t index = HASHMAP_UNKNOWN; genned_string_t* string = genned_strings_get(&c->strings, &k, &index); if(string != NULL) return string->global; ast_t* type = ast_type(ast); pony_assert(is_literal(type, "String")); reach_type_t* t = reach_type(c->reach, type); compile_type_t* c_t = (compile_type_t*)t->c_type; size_t len = ast_name_len(ast); LLVMValueRef args[4]; args[0] = c_t->desc; args[1] = LLVMConstInt(c->intptr, len, false); args[2] = LLVMConstInt(c->intptr, len + 1, false); args[3] = codegen_string(c, name, len); LLVMValueRef inst = LLVMConstNamedStruct(c_t->structure, args, 4); LLVMValueRef g_inst = LLVMAddGlobal(c->module, c_t->structure, ""); LLVMSetInitializer(g_inst, inst); LLVMSetGlobalConstant(g_inst, true); LLVMSetLinkage(g_inst, LLVMPrivateLinkage); LLVMSetUnnamedAddr(g_inst, true); string = POOL_ALLOC(genned_string_t); string->string = name; string->global = g_inst; genned_strings_putindex(&c->strings, string, index); return g_inst; }
// Collect the given type parameter static void collect_type_param(ast_t* orig_param, ast_t* params, ast_t* args) { assert(orig_param != NULL); // Get original type parameter info AST_GET_CHILDREN(orig_param, id, constraint, deflt); const char* name = ast_name(id); constraint = sanitise_type(constraint); assert(constraint != NULL); // New type parameter has the same constraint as the old one (sanitised) if(params != NULL) { BUILD(new_param, orig_param, NODE(TK_TYPEPARAM, ID(name) TREE(constraint) NONE)); ast_append(params, new_param); ast_setid(params, TK_TYPEPARAMS); } // New type arguments binds to old type parameter if(args != NULL) { BUILD(new_arg, orig_param, NODE(TK_NOMINAL, NONE // Package ID(name) NONE // Type args NONE // cap NONE)); // ephemeral ast_append(args, new_arg); ast_setid(args, TK_TYPEARGS); } }
static LLVMValueRef make_fieldptr(compile_t* c, LLVMValueRef l_value, ast_t* l_type, ast_t* right) { switch(ast_id(l_type)) { case TK_NOMINAL: { assert(ast_id(right) == TK_ID); ast_t* def = (ast_t*)ast_data(l_type); ast_t* field = ast_get(def, ast_name(right), NULL); int index = (int)ast_index(field); if(ast_id(def) != TK_STRUCT) index++; if(ast_id(def) == TK_ACTOR) index++; return LLVMBuildStructGEP(c->builder, l_value, index, ""); } case TK_TUPLETYPE: { assert(ast_id(right) == TK_INT); int index = (int)ast_int(right)->low; return LLVMBuildExtractValue(c->builder, l_value, index, ""); } case TK_ARROW: return make_fieldptr(c, l_value, ast_childidx(l_type, 1), right); default: {} } assert(0); return NULL; }