static void print_type(printbuf_t* buffer, ast_t* type) { switch(ast_id(type)) { case TK_NOMINAL: { AST_GET_CHILDREN(type, package, id, typeargs, cap, ephemeral); ast_t* origpkg = ast_sibling(ephemeral); if(origpkg != NULL && ast_id(origpkg) != TK_NONE) printbuf(buffer, "%s.", ast_name(origpkg)); ast_t* def = (ast_t*)ast_data(type); if(def != NULL) id = ast_child(def); printbuf(buffer, "%s", ast_nice_name(id)); if(ast_id(typeargs) != TK_NONE) print_typeexpr(buffer, typeargs, ", ", true); if(ast_id(cap) != TK_NONE) printbuf(buffer, " %s", token_print(cap->t)); if(ast_id(ephemeral) != TK_NONE) printbuf(buffer, "%s", token_print(ephemeral->t)); break; } case TK_UNIONTYPE: print_typeexpr(buffer, type, " | ", false); break; case TK_ISECTTYPE: print_typeexpr(buffer, type, " & ", false); break; case TK_TUPLETYPE: print_typeexpr(buffer, type, ", ", false); break; case TK_TYPEPARAMREF: { AST_GET_CHILDREN(type, id, cap, ephemeral); printbuf(buffer, "%s", ast_nice_name(id)); if(ast_id(cap) != TK_NONE) printbuf(buffer, " %s", token_print(cap->t)); if(ast_id(ephemeral) != TK_NONE) printbuf(buffer, " %s", token_print(ephemeral->t)); break; } case TK_ARROW: { AST_GET_CHILDREN(type, left, right); print_type(buffer, left); printbuf(buffer, "->"); print_type(buffer, right); break; } case TK_THISTYPE: printbuf(buffer, "this"); break; case TK_DONTCARE: printbuf(buffer, "_"); break; case TK_FUNTYPE: printbuf(buffer, "function"); break; case TK_INFERTYPE: printbuf(buffer, "to_infer"); break; case TK_ERRORTYPE: printbuf(buffer, "<type error>"); break; case TK_NONE: break; default: printbuf(buffer, "%s", token_print(type->t)); } }
bool expr_reference(pass_opt_t* opt, ast_t** astp) { typecheck_t* t = &opt->check; ast_t* ast = *astp; // Everything we reference must be in scope. const char* name = ast_name(ast_child(ast)); sym_status_t status; ast_t* def = ast_get(ast, name, &status); if(def == NULL) { const char* alt_name = suggest_alt_name(ast, name); if(alt_name == NULL) ast_error(ast, "can't find declaration of '%s'", name); else ast_error(ast, "can't find declaration of '%s', did you mean '%s'?", name, alt_name); return false; } switch(ast_id(def)) { case TK_PACKAGE: { // Only allowed if in a TK_DOT with a type. if(ast_id(ast_parent(ast)) != TK_DOT) { ast_error(ast, "a package can only appear as a prefix to a type"); return false; } ast_setid(ast, TK_PACKAGEREF); return true; } case TK_INTERFACE: case TK_TRAIT: case TK_TYPE: case TK_TYPEPARAM: case TK_PRIMITIVE: case TK_STRUCT: case TK_CLASS: case TK_ACTOR: { // It's a type name. This may not be a valid type, since it may need // type arguments. ast_t* id = ast_child(def); const char* name = ast_name(id); ast_t* type = type_sugar(ast, NULL, name); ast_settype(ast, type); ast_setid(ast, TK_TYPEREF); return expr_typeref(opt, astp); } case TK_FVAR: case TK_FLET: case TK_EMBED: { // Transform to "this.f". if(!def_before_use(def, ast, name)) return false; ast_t* dot = ast_from(ast, TK_DOT); ast_add(dot, ast_child(ast)); ast_t* self = ast_from(ast, TK_THIS); ast_add(dot, self); ast_replace(astp, dot); if(!expr_this(opt, self)) return false; return expr_dot(opt, astp); } case TK_PARAM: { if(t->frame->def_arg != NULL) { ast_error(ast, "can't reference a parameter in a default argument"); return false; } if(!def_before_use(def, ast, name)) return false; ast_t* type = ast_type(def); if(is_typecheck_error(type)) return false; if(!valid_reference(opt, ast, type, status)) return false; if(!sendable(type) && (t->frame->recover != NULL)) { ast_error(ast, "can't access a non-sendable parameter from inside a recover " "expression"); return false; } // Get the type of the parameter and attach it to our reference. // Automatically consume a parameter if the function is done. ast_t* r_type = type; if(is_method_return(t, ast)) r_type = consume_type(type, TK_NONE); ast_settype(ast, r_type); ast_setid(ast, TK_PARAMREF); return true; } case TK_NEW: case TK_BE: case TK_FUN: { // Transform to "this.f". ast_t* dot = ast_from(ast, TK_DOT); ast_add(dot, ast_child(ast)); ast_t* self = ast_from(ast, TK_THIS); ast_add(dot, self); ast_replace(astp, dot); if(!expr_this(opt, self)) return false; return expr_dot(opt, astp); } case TK_ID: { if(!def_before_use(def, ast, name)) return false; ast_t* type = ast_type(def); if(type != NULL && ast_id(type) == TK_INFERTYPE) { ast_error(ast, "cannot infer type of %s\n", ast_nice_name(def)); ast_settype(def, ast_from(def, TK_ERRORTYPE)); ast_settype(ast, ast_from(ast, TK_ERRORTYPE)); return false; } if(is_typecheck_error(type)) return false; if(!valid_reference(opt, ast, type, status)) return false; ast_t* var = ast_parent(def); switch(ast_id(var)) { case TK_VAR: ast_setid(ast, TK_VARREF); break; case TK_LET: case TK_MATCH_CAPTURE: ast_setid(ast, TK_LETREF); break; default: assert(0); return false; } if(!sendable(type)) { if(t->frame->recover != NULL) { ast_t* def_recover = ast_nearest(def, TK_RECOVER); if(t->frame->recover != def_recover) { ast_error(ast, "can't access a non-sendable local defined outside " "of a recover expression from within that recover expression"); return false; } } } // Get the type of the local and attach it to our reference. // Automatically consume a local if the function is done. ast_t* r_type = type; if(is_method_return(t, ast)) r_type = consume_type(type, TK_NONE); ast_settype(ast, r_type); return true; } default: {} } assert(0); return false; }
// Write the given type to the current type file static void doc_type(docgen_t* docgen, ast_t* type, bool generate_links) { assert(docgen != NULL); assert(docgen->type_file != NULL); assert(type != NULL); switch(ast_id(type)) { case TK_NOMINAL: { AST_GET_CHILDREN(type, package, id, tparams, cap, ephemeral); // Generate links only if directed to and if the type is not anonymous (as // indicated by a name created by package_hygienic_id). if(generate_links && *ast_name(id) != '$') { // Find type we reference so we can link to it ast_t* target = (ast_t*)ast_data(type); assert(target != NULL); size_t link_len; char* tqfn = write_tqfn(target, NULL, &link_len); // Links are of the form: [text](target) fprintf(docgen->type_file, "[%s](%s)", ast_nice_name(id), tqfn); ponyint_pool_free_size(link_len, tqfn); doc_type_list(docgen, tparams, "\\[", ", ", "\\]", true, false); } else { fprintf(docgen->type_file, "%s", ast_nice_name(id)); doc_type_list(docgen, tparams, "[", ", ", "]", false, false); } const char* cap_text = doc_get_cap(cap); if(cap_text != NULL) fprintf(docgen->type_file, " %s", cap_text); if(ast_id(ephemeral) != TK_NONE) fprintf(docgen->type_file, "%s", ast_get_print(ephemeral)); break; } case TK_UNIONTYPE: doc_type_list(docgen, type, "(", " | ", ")", generate_links, true); break; case TK_ISECTTYPE: doc_type_list(docgen, type, "(", " & ", ")", generate_links, false); break; case TK_TUPLETYPE: doc_type_list(docgen, type, "(", " , ", ")", generate_links, false); break; case TK_TYPEPARAMREF: { AST_GET_CHILDREN(type, id, cap, ephemeral); fprintf(docgen->type_file, "%s", ast_nice_name(id)); const char* cap_text = doc_get_cap(cap); if(cap_text != NULL) fprintf(docgen->type_file, " %s", cap_text); if(ast_id(ephemeral) != TK_NONE) fprintf(docgen->type_file, "%s", ast_get_print(ephemeral)); break; } case TK_ARROW: { AST_GET_CHILDREN(type, left, right); doc_type(docgen, left, generate_links); fprintf(docgen->type_file, "->"); doc_type(docgen, right, generate_links); break; } case TK_THISTYPE: fprintf(docgen->type_file, "this"); break; case TK_ISO: case TK_TRN: case TK_REF: case TK_VAL: case TK_BOX: case TK_TAG: fprintf(docgen->type_file, "%s", ast_get_print(type)); break; default: assert(0); } }