bool genexe(compile_t* c, ast_t* program) { // The first package is the main package. It has to have a Main actor. const char* main_actor = stringtab("Main"); const char* env_class = stringtab("Env"); ast_t* package = ast_child(program); ast_t* main_def = ast_get(package, main_actor, NULL); if(main_def == NULL) { errorf(NULL, "no Main actor found in package '%s'", c->filename); return false; } // Generate the Main actor and the Env class. ast_t* main_ast = type_builtin(c->opt, main_def, main_actor); ast_t* env_ast = type_builtin(c->opt, main_def, env_class); genprim_reachable_init(c, program); reach(c->reachable, main_ast, stringtab("create"), NULL); reach(c->reachable, env_ast, stringtab("_create"), NULL); paint(c->reachable); gentype_t main_g; gentype_t env_g; bool ok = gentype(c, main_ast, &main_g) && gentype(c, env_ast, &env_g); if(ok) gen_main(c, &main_g, &env_g); ast_free_unattached(main_ast); ast_free_unattached(env_ast); if(!ok) return false; if(!genopt(c)) return false; const char* file_o = genobj(c); if(file_o == NULL) return false; if(c->opt->limit < PASS_ALL) return true; if(!link_exe(c, program, file_o)) return false; #ifdef PLATFORM_IS_WINDOWS _unlink(file_o); #else unlink(file_o); #endif return true; }
bool codegen_gen_test(compile_t* c, ast_t* program, pass_opt_t* opt, pass_id last_pass) { if(last_pass < PASS_REACH) { memset(c, 0, sizeof(compile_t)); genned_strings_init(&c->strings, 64); ffi_decls_init(&c->ffi_decls, 64); if(!init_module(c, program, opt)) return false; init_runtime(c); genprim_reachable_init(c, program); const char* main_actor = c->str_Main; const char* env_class = c->str_Env; ast_t* package = ast_child(program); ast_t* main_def = ast_get(package, main_actor, NULL); if(main_def == NULL) return false; ast_t* main_ast = type_builtin(opt, main_def, main_actor); ast_t* env_ast = type_builtin(opt, main_def, env_class); if(lookup(opt, main_ast, main_ast, c->str_create) == NULL) return false; reach(c->reach, main_ast, c->str_create, NULL, opt); reach(c->reach, env_ast, c->str__create, NULL, opt); reach_done(c->reach, c->opt); } if(opt->limit == PASS_REACH) return true; if(last_pass < PASS_PAINT) paint(&c->reach->types); if(opt->limit == PASS_PAINT) return true; if(!gentypes(c)) return false; return true; }
static bool reachable_methods(compile_t* c, ast_t* ast) { ast_t* id = ast_child(ast); ast_t* type = type_builtin(c->opt, ast, ast_name(id)); ast_t* def = (ast_t*)ast_data(type); ast_t* members = ast_childidx(def, 4); ast_t* member = ast_child(members); while(member != NULL) { switch(ast_id(member)) { case TK_NEW: case TK_BE: case TK_FUN: { AST_GET_CHILDREN(member, cap, m_id, typeparams); // Mark all non-polymorphic methods as reachable. if(ast_id(typeparams) == TK_NONE) reach(c->reach, type, ast_name(m_id), NULL, c->opt); break; } default: {} } member = ast_sibling(member); } ast_free_unattached(type); return true; }
bool expr_digestof(pass_opt_t* opt, ast_t* ast) { ast_t* expr = ast_child(ast); switch(ast_id(expr)) { case TK_FVARREF: case TK_FLETREF: case TK_EMBEDREF: case TK_VARREF: case TK_LETREF: case TK_PARAMREF: case TK_THIS: break; default: ast_error(opt->check.errors, ast, "can only get the digest of a field, local, parameter or this"); return false; } // Set the type to U64. ast_t* type = type_builtin(opt, expr, "U64"); ast_settype(ast, type); return true; }
bool expr_identityof(pass_opt_t* opt, ast_t* ast) { ast_t* expr = ast_child(ast); switch(ast_id(expr)) { case TK_FVARREF: case TK_FLETREF: case TK_EMBEDREF: case TK_VARREF: case TK_LETREF: case TK_PARAMREF: case TK_THIS: break; default: ast_error(ast, "identity must be for a field, local, parameter or this"); return false; } // Set the type to U64. ast_t* type = type_builtin(opt, expr, "U64"); ast_settype(ast, type); return true; }
// Fill the given UIF type cache static bool uif_type(pass_opt_t* opt, ast_t* literal, ast_t* type, lit_chain_t* chain_head, bool report_errors) { pony_assert(chain_head != NULL); pony_assert(chain_head->cardinality == CHAIN_CARD_BASE); chain_head->formal = NULL; int r = uifset(opt, type, chain_head->next); if(r == UIF_ERROR) return false; if(r == UIF_NO_TYPES) { if(report_errors) ast_error(opt->check.errors, literal, "could not infer literal type, no valid types found"); return false; } pony_assert(type != NULL); if((r & UIF_CONSTRAINED) != 0) { // Type is a formal parameter pony_assert(chain_head->formal != NULL); pony_assert(chain_head->name != NULL); pony_assert(chain_head->cached_uif_index < 0); BUILD(uif_type, type, NODE(TK_TYPEPARAMREF, DATA(chain_head->formal) ID(chain_head->name) NODE(TK_VAL) NONE)); chain_head->cached_type = uif_type; chain_head->valid_for_float = ((r & UIF_INT_MASK) == 0); return true; } // Type is one or more UIFs for(int i = 0; i < UIF_COUNT; i++) { if(r == (1 << i)) { chain_head->valid_for_float = (((1 << i) & UIF_INT_MASK) == 0); chain_head->cached_type = type_builtin(opt, type, _str_uif_types[i].name); //ast_setid(ast_childidx(chain_head->cached_type, 4), TK_EPHEMERAL); chain_head->name = _str_uif_types[i].name; chain_head->cached_uif_index = i; return true; } } ast_error(opt->check.errors, literal, "Multiple possible types for literal"); return false; }
bool expr_literal(pass_opt_t* opt, ast_t* ast, const char* name) { ast_t* type = type_builtin(opt, ast, name); if(is_typecheck_error(type)) return false; ast_settype(ast, type); return true; }
void genprim_reachable_init(compile_t* c, ast_t* program) { // Look for primitives in all packages that have _init or _final methods. // Mark them as reachable. ast_t* package = ast_child(program); while(package != NULL) { ast_t* module = ast_child(package); while(module != NULL) { ast_t* entity = ast_child(module); while(entity != NULL) { if(ast_id(entity) == TK_PRIMITIVE) { AST_GET_CHILDREN(entity, id, typeparams); if(ast_id(typeparams) == TK_NONE) { ast_t* type = type_builtin(c->opt, entity, ast_name(id)); ast_t* finit = ast_get(entity, c->str__init, NULL); ast_t* ffinal = ast_get(entity, c->str__final, NULL); if(finit != NULL) { reach(c->reach, type, c->str__init, NULL, c->opt); ast_free_unattached(finit); } if(ffinal != NULL) { reach(c->reach, type, c->str__final, NULL, c->opt); ast_free_unattached(ffinal); } ast_free_unattached(type); } } entity = ast_sibling(entity); } module = ast_sibling(module); } package = ast_sibling(package); } }
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; }
bool is_signed(pass_opt_t* opt, ast_t* type) { if(type == NULL) return false; ast_t* builtin = type_builtin(opt, type, "Signed"); if(builtin == NULL) return false; bool ok = is_subtype(type, builtin); ast_free_unattached(builtin); return ok; }
// Determine the UIF types that satisfy the given "simple" type. // Here a simple type is defined as a non-tuple type that does not depend on // any formal parameters. static int uifset_simple_type(pass_opt_t* opt, ast_t* type) { assert(type != NULL); int set = 0; for(int i = 0; i < UIF_COUNT; i++) { ast_t* uif = type_builtin(opt, type, _str_uif_types[i].name); ast_setid(ast_childidx(uif, 3), TK_VAL); ast_setid(ast_childidx(uif, 4), TK_EPHEMERAL); if(is_subtype(uif, type)) set |= (1 << i); ast_free(uif); } return set; }
bool expr_addressof(pass_opt_t* opt, ast_t* ast) { // Check if we're in an FFI call. ast_t* parent = ast_parent(ast); if(ast_id(parent) == TK_SEQ) { parent = ast_parent(parent); if(ast_id(parent) == TK_POSITIONALARGS) { parent = ast_parent(parent); if(ast_id(parent) == TK_FFICALL) return expr_addressof_ffi(opt, ast); } } ast_t* expr = ast_child(ast); switch(ast_id(expr)) { case TK_FVARREF: case TK_VARREF: case TK_FLETREF: case TK_LETREF: case TK_PARAMREF: break; default: ast_error(ast, "identity must be for a field, local or parameter"); return false; } // Turn this into an identity operation. Set the type to U64. ast_t* type = type_builtin(opt, expr, "U64"); ast_settype(ast, type); ast_setid(ast, TK_IDENTITY); return true; }
// Determine the UIF types that the given formal parameter may be static int uifset_formal_param(pass_opt_t* opt, ast_t* type_param_ref, lit_chain_t* chain) { assert(type_param_ref != NULL); assert(ast_id(type_param_ref) == TK_TYPEPARAMREF); ast_t* type_param = (ast_t*)ast_data(type_param_ref); assert(type_param != NULL); assert(ast_id(type_param) == TK_TYPEPARAM); assert(chain != NULL); ast_t* constraint = ast_childidx(type_param, 1); assert(constraint != NULL); // If the constraint is not a subtype of (Real[A] & Number) then there are no // legal types in the set ast_t* number = type_builtin(opt, type_param, "Number"); ast_t* real = type_builtin(opt, type_param, "Real"); ast_setid(ast_childidx(real, 3), TK_BOX); ast_t* p_ref = ast_childidx(real, 2); REPLACE(&p_ref, NODE(TK_TYPEARGS, NODE(TK_TYPEPARAMREF, DATA(type_param) ID(ast_name(ast_child(type_param))) NODE(TK_VAL) NONE))); bool is_real = is_subtype(constraint, real); bool is_number = is_subtype(constraint, number); ast_free(number); ast_free(real); if(!is_real || !is_number) // The formal param is not a subset of (Real[A] & Number) return UIF_NO_TYPES; int uif_set = 0; for(int i = 0; i < UIF_COUNT; i++) { ast_t* uif = type_builtin(opt, type_param, _str_uif_types[i].name); BUILD(params, type_param, NODE(TK_TYPEPARAMS, TREE(ast_dup(type_param)))); BUILD(args, type_param, NODE(TK_TYPEARGS, TREE(uif))); if(check_constraints(params, args, false)) uif_set |= (1 << i); ast_free(args); ast_free(params); } if(uif_set == 0) // No legal types return UIF_NO_TYPES; // Given formal parameter is legal to coerce to if(chain->formal != NULL && chain->formal != type_param) { ast_error(type_param_ref, "Cannot infer a literal type with multiple formal parameters"); return UIF_ERROR; } chain->formal = type_param; chain->name = ast_name(ast_child(type_param)); return uif_set | UIF_CONSTRAINED; }
bool expr_location(pass_opt_t* opt, ast_t* ast) { ast_settype(ast, type_builtin(opt, ast, "SourceLoc")); return true; }
bool expr_addressof(pass_opt_t* opt, ast_t* ast) { // Check if we're in an FFI call. ast_t* parent = ast_parent(ast); bool ok = false; if(ast_id(parent) == TK_SEQ) { parent = ast_parent(parent); if(ast_id(parent) == TK_POSITIONALARGS) { parent = ast_parent(parent); if(ast_id(parent) == TK_FFICALL) ok = true; } } if(!ok) { ast_error(ast, "the & operator can only be used for FFI arguments"); return false; } ast_t* expr = ast_child(ast); switch(ast_id(expr)) { case TK_FVARREF: case TK_VARREF: case TK_FUNREF: case TK_BEREF: break; case TK_FLETREF: ast_error(ast, "can't take the address of a let field"); return false; case TK_EMBEDREF: ast_error(ast, "can't take the address of an embed field"); return false; case TK_LETREF: ast_error(ast, "can't take the address of a let local"); return false; case TK_PARAMREF: ast_error(ast, "can't take the address of a function parameter"); return false; default: ast_error(ast, "can only take the address of a local, field or method"); return false; } // Set the type to Pointer[ast_type(expr)]. Set to Pointer[None] for function // pointers. ast_t* expr_type = ast_type(expr); if(is_typecheck_error(expr_type)) return false; switch(ast_id(expr)) { case TK_FUNREF: case TK_BEREF: expr_type = type_builtin(opt, ast, "None"); break; default: {} } ast_t* type = type_pointer_to(opt, expr_type); ast_settype(ast, type); return true; }
bool expr_identity(pass_opt_t* opt, ast_t* ast) { ast_settype(ast, type_builtin(opt, ast, "Bool")); return literal_is(ast, opt); }
bool expr_identity(pass_opt_t* opt, ast_t* ast) { ast_settype(ast, type_builtin(opt, ast, "Bool")); ast_inheritflags(ast); return true; }
bool genexe(compile_t* c, ast_t* program) { errors_t* errors = c->opt->check.errors; // The first package is the main package. It has to have a Main actor. const char* main_actor = c->str_Main; const char* env_class = c->str_Env; ast_t* package = ast_child(program); ast_t* main_def = ast_get(package, main_actor, NULL); if(main_def == NULL) { errorf(errors, NULL, "no Main actor found in package '%s'", c->filename); return false; } // Generate the Main actor and the Env class. ast_t* main_ast = type_builtin(c->opt, main_def, main_actor); ast_t* env_ast = type_builtin(c->opt, main_def, env_class); if(lookup(NULL, main_ast, main_ast, c->str_create) == NULL) return false; if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Reachability\n"); reach(c->reach, main_ast, c->str_create, NULL, c->opt); reach(c->reach, env_ast, c->str__create, NULL, c->opt); if(c->opt->limit == PASS_REACH) return true; if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Selector painting\n"); paint(&c->reach->types); if(c->opt->limit == PASS_PAINT) return true; if(!gentypes(c)) return false; if(c->opt->verbosity >= VERBOSITY_ALL) reach_dump(c->reach); reach_type_t* t_main = reach_type(c->reach, main_ast); reach_type_t* t_env = reach_type(c->reach, env_ast); if((t_main == NULL) || (t_env == NULL)) return false; gen_main(c, t_main, t_env); if(!genopt(c)) return false; const char* file_o = genobj(c); if(file_o == NULL) return false; if(c->opt->limit < PASS_ALL) return true; if(!link_exe(c, program, file_o)) return false; #ifdef PLATFORM_IS_WINDOWS _unlink(file_o); #else unlink(file_o); #endif return true; }
bool genexe(compile_t* c, ast_t* program) { errors_t* errors = c->opt->check.errors; // The first package is the main package. It has to have a Main actor. const char* main_actor = c->str_Main; const char* env_class = c->str_Env; ast_t* package = ast_child(program); ast_t* main_def = ast_get(package, main_actor, NULL); if(main_def == NULL) { errorf(errors, NULL, "no Main actor found in package '%s'", c->filename); return false; } // Generate the Main actor and the Env class. ast_t* main_ast = type_builtin(c->opt, main_def, main_actor); ast_t* env_ast = type_builtin(c->opt, main_def, env_class); if(lookup(c->opt, main_ast, main_ast, c->str_create) == NULL) return false; if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Reachability\n"); reach(c->reach, main_ast, c->str_create, NULL, c->opt); reach(c->reach, env_ast, c->str__create, NULL, c->opt); if(c->opt->limit == PASS_REACH) return true; if(c->opt->verbosity >= VERBOSITY_INFO) fprintf(stderr, " Selector painting\n"); paint(&c->reach->types); if(c->opt->limit == PASS_PAINT) return true; if(!gentypes(c)) return false; if(c->opt->verbosity >= VERBOSITY_ALL) reach_dump(c->reach); reach_type_t* t_main = reach_type(c->reach, main_ast); reach_type_t* t_env = reach_type(c->reach, env_ast); if((t_main == NULL) || (t_env == NULL)) return false; gen_main(c, t_main, t_env); if(!genopt(c, true)) return false; if(c->opt->runtimebc) { if(!codegen_merge_runtime_bitcode(c)) return false; // Rerun the optimiser without the Pony-specific optimisation passes. // Inlining runtime functions can screw up these passes so we can't // run the optimiser only once after merging. if(!genopt(c, false)) return false; } const char* file_o = genobj(c); if(file_o == NULL) return false; if(c->opt->limit < PASS_ALL) return true; if(!link_exe(c, program, file_o)) return false; #ifdef PLATFORM_IS_WINDOWS _unlink(file_o); #else unlink(file_o); #endif return true; }