// 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->package_file == NULL); assert(docgen->test_types == NULL); assert(docgen->public_types == NULL); assert(docgen->private_types == 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)); } ponyint_pool_free_size(tqfn_len, tqfn); docgen->test_types = printbuf_new(); docgen->public_types = printbuf_new(); docgen->private_types = printbuf_new(); docgen->package_file = docgen->type_file; docgen->type_file = NULL; }
// Write a description of the given entity to its own type file. // The containing package is handed in to save looking it up again. static void doc_entity(docgen_t* docgen, ast_t* ast, ast_t* package) { assert(docgen != NULL); assert(docgen->index_file != NULL); assert(docgen->type_file == NULL); assert(ast != NULL); assert(package != NULL); // First open a file size_t tqfn_len; char* tqfn = write_tqfn(ast, NULL, &tqfn_len); docgen->type_file = doc_open_file(docgen, true, tqfn, ".md"); if(docgen->type_file == NULL) return; // Add reference to new file to index file AST_GET_CHILDREN(ast, id, tparams, cap, provides, members, c_api, doc); const char* name = ast_name(id); assert(name != NULL); fprintf(docgen->index_file, " - %s %s: \"%s.md\"\n", ast_get_print(ast), name, tqfn); pool_free_size(tqfn_len, tqfn); // Now we can write the actual documentation for the entity fprintf(docgen->type_file, "%s %s", ast_get_print(ast), name); doc_type_params(docgen, tparams); doc_type_list(docgen, provides, " is ", ", ", ""); fprintf(docgen->type_file, "\n\nIn package \"%s\".\n\n", package_qualified_name(package)); fprintf(docgen->type_file, "%s", (name[0] == '_') ? "Private" : "Public"); const char* cap_text = doc_get_cap(cap); if(cap_text != NULL) fprintf(docgen->type_file, ", default capability %s", cap_text); fprintf(docgen->type_file, ".\n\n"); if(ast_id(c_api) == TK_AT) fprintf(docgen->type_file, "May be called from C.\n"); if(ast_id(doc) != TK_NONE) fprintf(docgen->type_file, "%s\n\n", ast_name(doc)); else fprintf(docgen->type_file, "No doc string provided.\n\n"); // Sort members into varieties ast_list_t pub_fields = { NULL, NULL, NULL }; ast_list_t news = { NULL, NULL, NULL }; ast_list_t bes = { NULL, NULL, NULL }; ast_list_t funs = { NULL, NULL, NULL }; for(ast_t* p = ast_child(members); p != NULL; p = ast_sibling(p)) { switch(ast_id(p)) { case TK_FVAR: case TK_FLET: doc_list_add_named(&pub_fields, p, 0, true, false); break; case TK_NEW: doc_list_add_named(&news, p, 1, true, true); break; case TK_BE: doc_list_add_named(&bes, p, 1, true, true); break; case TK_FUN: doc_list_add_named(&funs, p, 1, true, true); break; default: assert(0); break; } } // Handle member variety lists doc_fields(docgen, &pub_fields, "Public fields"); doc_methods(docgen, &news, "Constructors"); doc_methods(docgen, &bes, "Behaviours"); doc_methods(docgen, &funs, "Functions"); doc_list_free(&pub_fields); doc_list_free(&news); doc_list_free(&bes); doc_list_free(&funs); fclose(docgen->type_file); docgen->type_file = NULL; }
// Write the given type to the current type file static void doc_type(docgen_t* docgen, ast_t* type) { 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); // 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_name(id), tqfn); pool_free_size(link_len, tqfn); doc_type_list(docgen, tparams, "\\[", ", ", "\\]"); 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, "(", " | ", ")"); break; case TK_ISECTTYPE: doc_type_list(docgen, type, "(", " & ", ")"); break; case TK_TUPLETYPE: doc_type_list(docgen, type, "(", " , ", ")"); break; case TK_TYPEPARAMREF: { AST_GET_CHILDREN(type, id, cap, ephemeral); fprintf(docgen->type_file, "%s", ast_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); fprintf(docgen->type_file, "->"); doc_type(docgen, right); break; } case TK_THISTYPE: fprintf(docgen->type_file, "this"); break; case TK_BOXTYPE: fprintf(docgen->type_file, "box"); break; default: assert(0); } }
// Write a description of the given entity to its own type file. static void doc_entity(docgen_t* docgen, ast_t* ast) { assert(docgen != NULL); assert(docgen->index_file != NULL); assert(docgen->package_file != NULL); assert(docgen->test_types != NULL); assert(docgen->public_types != NULL); assert(docgen->private_types != NULL); assert(docgen->type_file == NULL); assert(ast != NULL); // First open a file size_t tqfn_len; char* tqfn = write_tqfn(ast, NULL, &tqfn_len); docgen->type_file = doc_open_file(docgen, true, tqfn, ".md"); if(docgen->type_file == NULL) return; // Add reference to new file to index file AST_GET_CHILDREN(ast, id, tparams, cap, provides, members, c_api, doc); const char* name = ast_name(id); assert(name != NULL); fprintf(docgen->index_file, " - %s %s: \"%s.md\"\n", ast_get_print(ast), name, tqfn); // Add to appropriate package types buffer printbuf_t* buffer = docgen->public_types; if(is_for_testing(name, provides)) buffer = docgen->test_types; else if(name[0] == '_') buffer = docgen->private_types; printbuf(buffer, "* [%s %s](%s.md)\n", ast_get_print(ast), name, tqfn); ponyint_pool_free_size(tqfn_len, tqfn); // Now we can write the actual documentation for the entity fprintf(docgen->type_file, "# %s", name); doc_type_params(docgen, tparams, true); fprintf(docgen->type_file, "\n\n"); if(ast_id(doc) != TK_NONE) fprintf(docgen->type_file, "%s\n\n", ast_name(doc)); // code block fprintf(docgen->type_file, "```pony\n"); fprintf(docgen->type_file, "%s ",ast_get_print(ast)); const char* cap_text = doc_get_cap(cap); if(cap_text != NULL) fprintf(docgen->type_file, "%s ", cap_text); fprintf(docgen->type_file, "%s", name); doc_type_params(docgen, tparams, false); doc_type_list(docgen, provides, " is\n ", ",\n ", "", false); fprintf(docgen->type_file, "\n```\n\n"); if (ast_id(ast) != TK_TYPE) doc_type_list(docgen, provides, "#### Implements\n\n* ", "\n* ", "\n\n---\n\n", true); else doc_type_list(docgen, provides, "#### Type Alias For\n\n* ", "\n* ", "\n\n---\n\n", true); // Sort members into varieties ast_list_t pub_fields = { NULL, NULL, NULL }; ast_list_t news = { NULL, NULL, NULL }; ast_list_t pub_bes = { NULL, NULL, NULL }; ast_list_t priv_bes = { NULL, NULL, NULL }; ast_list_t pub_funs = { NULL, NULL, NULL }; ast_list_t priv_funs = { NULL, NULL, NULL }; for(ast_t* p = ast_child(members); p != NULL; p = ast_sibling(p)) { switch(ast_id(p)) { case TK_FVAR: case TK_FLET: case TK_EMBED: doc_list_add_named(&pub_fields, p, 0, true, false); break; case TK_NEW: doc_list_add_named(&news, p, 1, true, true); break; case TK_BE: doc_list_add_named(&pub_bes, p, 1, true, false); doc_list_add_named(&priv_bes, p, 1, false, true); break; case TK_FUN: doc_list_add_named(&pub_funs, p, 1, true, false); doc_list_add_named(&priv_funs, p, 1, false, true); break; default: assert(0); break; } } // Handle member variety lists doc_methods(docgen, &news, "Constructors"); doc_fields(docgen, &pub_fields, "Public fields"); doc_methods(docgen, &pub_bes, "Public Behaviours"); doc_methods(docgen, &pub_funs, "Public Functions"); doc_methods(docgen, &priv_bes, "Private Behaviours"); doc_methods(docgen, &priv_funs, "Private Functions"); doc_list_free(&pub_fields); doc_list_free(&news); doc_list_free(&pub_bes); doc_list_free(&priv_bes); doc_list_free(&pub_funs); doc_list_free(&priv_funs); fclose(docgen->type_file); docgen->type_file = NULL; }
// 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); } }