void generate_docs(ast_t* program, pass_opt_t* options) { assert(program != NULL); if(ast_id(program) != TK_PROGRAM) return; docgen_t docgen; docgen.errors = options->check.errors; doc_setup_dirs(&docgen, program, options); // Open the index and home files docgen.index_file = doc_open_file(&docgen, false, "mkdocs", ".yml"); docgen.home_file = doc_open_file(&docgen, true, "index", ".md"); docgen.type_file = NULL; // Write documentation files if(docgen.index_file != NULL && docgen.home_file != NULL) { ast_t* package = ast_child(program); const char* name = package_filename(package); fprintf(docgen.home_file, "Packages\n\n"); fprintf(docgen.index_file, "site_name: %s\n", name); fprintf(docgen.index_file, "theme: readthedocs\n"); fprintf(docgen.index_file, "pages:\n"); fprintf(docgen.index_file, "- %s: index.md\n", name); doc_packages(&docgen, program); } // Tidy up if(docgen.index_file != NULL) fclose(docgen.index_file); if(docgen.home_file != NULL) fclose(docgen.home_file); if(docgen.base_dir != NULL) ponyint_pool_free_size(docgen.base_dir_buf_len, (void*)docgen.base_dir); if(docgen.sub_dir != NULL) ponyint_pool_free_size(docgen.sub_dir_buf_len, (void*)docgen.sub_dir); }
// 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 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; }