Rework URI resolution Add CFCMethod_get_docucomment to get inherited CFCDocuComment.
Use correct base class when resolving URIs. Only search parcel and prereqs for full struct symbols. Also search prereqs for short struct symbols. Search all source parcels and their prereqs for standalone .md documents. Minor cleanups. Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/81cdda1a Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/81cdda1a Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/81cdda1a Branch: refs/heads/master Commit: 81cdda1a5257b27c9f652f54a2e989f18394b150 Parents: a0e051a Author: Nick Wellnhofer <[email protected]> Authored: Mon Feb 27 23:46:41 2017 +0100 Committer: Nick Wellnhofer <[email protected]> Committed: Thu Mar 2 20:08:04 2017 +0100 ---------------------------------------------------------------------- compiler/perl/lib/Clownfish/CFC.xs | 9 +- compiler/src/CFCCHtml.c | 218 ++++++++++++++++---------------- compiler/src/CFCCMan.c | 52 ++++---- compiler/src/CFCCallable.c | 5 - compiler/src/CFCCallable.h | 3 - compiler/src/CFCMethod.c | 23 ++++ compiler/src/CFCMethod.h | 7 + compiler/src/CFCParcel.c | 5 + compiler/src/CFCParcel.h | 3 + compiler/src/CFCPerlPod.c | 75 ++++++----- compiler/src/CFCPerlPod.h | 8 +- compiler/src/CFCTestDocuComment.c | 103 ++++++++++++++- compiler/src/CFCUri.c | 95 +++++++++++--- 13 files changed, 394 insertions(+), 212 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/perl/lib/Clownfish/CFC.xs ---------------------------------------------------------------------- diff --git a/compiler/perl/lib/Clownfish/CFC.xs b/compiler/perl/lib/Clownfish/CFC.xs index b6b7939..775d46c 100644 --- a/compiler/perl/lib/Clownfish/CFC.xs +++ b/compiler/perl/lib/Clownfish/CFC.xs @@ -2423,17 +2423,18 @@ CODE: OUTPUT: RETVAL SV* -_gen_subroutine_pod(func, alias, klass, code_sample, class_name, is_constructor) +_gen_subroutine_pod(func, alias, klass, code_sample, class_name, is_constructor, docucomment, base_class) CFCCallable *func; const char *alias; CFCClass *klass; const char *code_sample; - const char *class_name; int is_constructor; + CFCDocuComment *docucomment; + CFCClass *base_class; CODE: char *value = CFCPerlPod_gen_subroutine_pod(func, alias, klass, - code_sample, class_name, - is_constructor); + code_sample, is_constructor, + docucomment, base_class); RETVAL = S_sv_eat_c_string(value); OUTPUT: RETVAL http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCCHtml.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCCHtml.c b/compiler/src/CFCCHtml.c index 6383ada..6c39946 100644 --- a/compiler/src/CFCCHtml.c +++ b/compiler/src/CFCCHtml.c @@ -129,32 +129,31 @@ static int S_compare_doc_path(const void *va, const void *vb); static char* -S_html_create_name(CFCClass *klass); +S_html_create_name(CFCClass *klass, int dir_level); static char* -S_html_create_synopsis(CFCClass *klass); +S_html_create_description(CFCClass *klass, int dir_level); static char* -S_html_create_description(CFCClass *klass); +S_html_create_functions(CFCClass *klass, int dir_level); static char* -S_html_create_functions(CFCClass *klass); +S_html_create_methods(CFCClass *klass, int dir_level); static char* -S_html_create_methods(CFCClass *klass); +S_html_create_fresh_methods(CFCClass *klass, CFCClass *ancestor, + int dir_level); static char* -S_html_create_fresh_methods(CFCClass *klass, CFCClass *ancestor); +S_html_create_func(CFCClass *klass, CFCCallable *func, const char *short_sym, + CFCDocuComment *docucomment, CFCClass *base_class, + int dir_level); static char* -S_html_create_func(CFCClass *klass, CFCClass *doc_class, CFCCallable *func, - const char *prefix, const char *short_sym); +S_html_create_param_list(CFCClass *klass, CFCCallable *func, int dir_level); static char* -S_html_create_param_list(CFCClass *klass, CFCCallable *func); - -static char* -S_html_create_inheritance(CFCClass *klass); +S_html_create_inheritance(CFCClass *klass, int dir_level); static char* S_md_to_html(const char *md, CFCClass *klass, int dir_level); @@ -169,19 +168,20 @@ static void S_transform_link(cmark_node *link, CFCClass *klass, int dir_level); static char* -S_type_to_html(CFCType *type, const char *sep, CFCClass *doc_class); +S_type_to_html(CFCType *type, const char *sep, CFCClass *doc_class, + int dir_level); static char* -S_cfc_uri_to_url(CFCUri *uri_obj, CFCClass *base, int dir_level); +S_cfc_uri_to_url(CFCUri *uri_obj, int dir_level); static char* -S_class_to_url(CFCClass *klass, CFCClass *base, int dir_level); +S_class_to_url(CFCClass *klass, int dir_level); static char* -S_document_to_url(CFCDocument *doc, CFCClass *base, int dir_level); +S_document_to_url(CFCDocument *doc, int dir_level); static char* -S_relative_url(const char *url, CFCClass *base, int dir_level); +S_relative_url(const char *url, int dir_level); CFCCHtml* CFCCHtml_new(CFCHierarchy *hierarchy, const char *header, const char *footer) { @@ -378,7 +378,7 @@ S_create_index_doc(CFCCHtml *self, CFCDocument **docs) { if (!CFCClass_public(klass)) { continue; } const char *class_name = CFCClass_get_name(klass); - char *url = S_class_to_url(klass, NULL, 0); + char *url = S_class_to_url(klass, 0); class_list = CFCUtil_cat(class_list, "<li><a href=\"", url, "\">", class_name, "</a></li>\n", NULL); @@ -527,33 +527,38 @@ CFCCHtml_create_html_body(CFCCHtml *self, CFCClass *klass) { const char *struct_sym = CFCClass_get_struct_sym(klass); const char *include_h = CFCClass_include_h(klass); - // Create NAME. - char *name = S_html_create_name(klass); + size_t dir_level = 0; + for (size_t i = 0; class_name[i]; i++) { + if (class_name[i] == ':' && class_name[i+1] == ':') { + dir_level++; + i++; + } + } - // Create SYNOPSIS. - char *synopsis = S_html_create_synopsis(klass); + // Create NAME. + char *name = S_html_create_name(klass, dir_level); // Create DESCRIPTION. - char *description = S_html_create_description(klass); + char *description = S_html_create_description(klass, dir_level); // Create CONSTRUCTORS. - char *functions_html = S_html_create_functions(klass); + char *functions_html = S_html_create_functions(klass, dir_level); // Create METHODS, possibly including an ABSTRACT METHODS section. - char *methods_html = S_html_create_methods(klass); + char *methods_html = S_html_create_methods(klass, dir_level); // Build an INHERITANCE section describing class ancestry. - char *inheritance = S_html_create_inheritance(klass); + char *inheritance = S_html_create_inheritance(klass, dir_level); - char *index_url = S_relative_url(self->index_filename, klass, 0); + char *index_url = S_relative_url(self->index_filename, dir_level); // Put it all together. const char pattern[] = - "<h1>%s</h1>\n" + "<h1>%s</h1>\n" // Class name "<table>\n" "<tr>\n" "<td class=\"label\">parcel</td>\n" - "<td><a href=\"%s\">%s</a></td>\n" + "<td><a href=\"%s\">%s</a></td>\n" // Index URL, parcel name "</tr>\n" "<tr>\n" "<td class=\"label\">class variable</td>\n" @@ -572,22 +577,21 @@ CFCCHtml_create_html_body(CFCCHtml *self, CFCClass *klass) { "<td><code>%s</code></td>\n" "</tr>\n" "</table>\n" - "%s" - "%s" - "%s" - "%s" - "%s" - "%s"; + "%s" // Name + "%s" // Description + "%s" // Functions + "%s" // Methods + "%s" // Inheritance + ; char *html_body = CFCUtil_sprintf(pattern, class_name, index_url, parcel_name, PREFIX, class_var, prefix, struct_sym, - prefix, class_nickname, include_h, name, synopsis, + prefix, class_nickname, include_h, name, description, functions_html, methods_html, inheritance); FREEMEM(index_url); FREEMEM(name); - FREEMEM(synopsis); FREEMEM(description); FREEMEM(functions_html); FREEMEM(methods_html); @@ -613,7 +617,7 @@ S_compare_doc_path(const void *va, const void *vb) { } static char* -S_html_create_name(CFCClass *klass) { +S_html_create_name(CFCClass *klass, int dir_level) { const char *class_name = CFCClass_get_name(klass); char *md = CFCUtil_strdup(class_name); CFCDocuComment *docucom = CFCClass_get_docucomment(klass); @@ -625,7 +629,7 @@ S_html_create_name(CFCClass *klass) { } } - char *html = S_md_to_html(md, klass, 0); + char *html = S_md_to_html(md, klass, dir_level); const char *format = "<h2>Name</h2>\n" @@ -638,20 +642,14 @@ S_html_create_name(CFCClass *klass) { } static char* -S_html_create_synopsis(CFCClass *klass) { - CHY_UNUSED_VAR(klass); - return CFCUtil_strdup(""); -} - -static char* -S_html_create_description(CFCClass *klass) { +S_html_create_description(CFCClass *klass, int dir_level) { CFCDocuComment *docucom = CFCClass_get_docucomment(klass); char *desc = NULL; if (docucom) { const char *raw_desc = CFCDocuComment_get_long(docucom); if (raw_desc && raw_desc[0] != '\0') { - desc = S_md_to_html(raw_desc, klass, 0); + desc = S_md_to_html(raw_desc, klass, dir_level); } } @@ -664,9 +662,8 @@ S_html_create_description(CFCClass *klass) { } static char* -S_html_create_functions(CFCClass *klass) { +S_html_create_functions(CFCClass *klass, int dir_level) { CFCFunction **functions = CFCClass_functions(klass); - const char *prefix = CFCClass_get_prefix(klass); char *result = CFCUtil_strdup(""); for (int func_num = 0; functions[func_num] != NULL; func_num++) { @@ -681,9 +678,12 @@ S_html_create_functions(CFCClass *klass) { result = CFCUtil_cat(result, "<dt id=\"func_", name, "\">", name, "</dt>\n", NULL); + CFCDocuComment *comment = CFCFunction_get_docucomment(func); + char *short_sym = CFCFunction_short_func_sym(func, klass); - char *func_html = S_html_create_func(klass, klass, (CFCCallable*)func, - prefix, short_sym); + char *func_html + = S_html_create_func(klass, (CFCCallable*)func, short_sym, + comment, klass, dir_level); result = CFCUtil_cat(result, func_html, NULL); FREEMEM(func_html); FREEMEM(short_sym); @@ -697,7 +697,7 @@ S_html_create_functions(CFCClass *klass) { } static char* -S_html_create_methods(CFCClass *klass) { +S_html_create_methods(CFCClass *klass, int dir_level) { char *methods_html = CFCUtil_strdup(""); char *result; @@ -711,7 +711,8 @@ S_html_create_methods(CFCClass *klass) { break; } - char *fresh_html = S_html_create_fresh_methods(klass, ancestor); + char *fresh_html + = S_html_create_fresh_methods(klass, ancestor, dir_level); if (fresh_html[0] != '\0') { if (ancestor == klass) { methods_html = CFCUtil_cat(methods_html, fresh_html, NULL); @@ -736,12 +737,12 @@ S_html_create_methods(CFCClass *klass) { return result; } -/** Return HTML for the fresh methods of `ancestor`. +/** Return HTML for the methods of `klass` inherited from `ancestor`. */ static char* -S_html_create_fresh_methods(CFCClass *klass, CFCClass *ancestor) { +S_html_create_fresh_methods(CFCClass *klass, CFCClass *ancestor, + int dir_level) { CFCMethod **fresh_methods = CFCClass_fresh_methods(ancestor); - const char *prefix = CFCClass_get_prefix(klass); char *result = CFCUtil_strdup(""); for (int meth_num = 0; fresh_methods[meth_num] != NULL; meth_num++) { @@ -775,10 +776,25 @@ S_html_create_fresh_methods(CFCClass *klass, CFCClass *ancestor) { } result = CFCUtil_cat(result, "</dt>\n", NULL); + // Get documentation, which may be inherited. + // + // This means that there can be three classes in the inheritance + // chain that are involved in the whole process. + // + // klass (doc_class): The class for which the documentation is + // created. + // ancestor: A superclass from which the method is + // inherited. + // base_class: Another superclass with the actual docucomment. + // This class must be used to resolve URIs. + CFCClass *base_class; + CFCDocuComment *comment + = CFCMethod_get_docucomment(method, &base_class); + char *short_sym = CFCMethod_short_method_sym(method, klass); char *method_html - = S_html_create_func(klass, ancestor, (CFCCallable*)method, prefix, - short_sym); + = S_html_create_func(klass, (CFCCallable*)method, short_sym, + comment, base_class, dir_level); result = CFCUtil_cat(result, method_html, NULL); FREEMEM(method_html); FREEMEM(short_sym); @@ -792,10 +808,12 @@ S_html_create_fresh_methods(CFCClass *klass, CFCClass *ancestor) { } static char* -S_html_create_func(CFCClass *klass, CFCClass *doc_class, CFCCallable *func, - const char *prefix, const char *short_sym) { +S_html_create_func(CFCClass *klass, CFCCallable *func, const char *short_sym, + CFCDocuComment *docucomment, CFCClass *base_class, + int dir_level) { + const char *prefix = CFCClass_get_prefix(klass); CFCType *ret_type = CFCCallable_get_return_type(func); - char *ret_html = S_type_to_html(ret_type, "", klass); + char *ret_html = S_type_to_html(ret_type, "", klass, dir_level); const char *ret_array = CFCType_get_array(ret_type); const char *ret_array_str = ret_array ? ret_array : ""; const char *incremented = ""; @@ -804,7 +822,7 @@ S_html_create_func(CFCClass *klass, CFCClass *doc_class, CFCCallable *func, incremented = " <span class=\"comment\">// incremented</span>"; } - char *param_list = S_html_create_param_list(klass, func); + char *param_list = S_html_create_param_list(klass, func, dir_level); const char *pattern = "<dd>\n" @@ -815,24 +833,10 @@ S_html_create_func(CFCClass *klass, CFCClass *doc_class, CFCCallable *func, FREEMEM(param_list); - // Get documentation, which may be inherited. - CFCDocuComment *docucomment = CFCCallable_get_docucomment(func); - if (!docucomment) { - const char *name = CFCCallable_get_name(func); - CFCClass *parent = klass; - while (NULL != (parent = CFCClass_get_parent(parent))) { - CFCCallable *parent_func - = (CFCCallable*)CFCClass_method(parent, name); - if (!parent_func) { break; } - docucomment = CFCCallable_get_docucomment(parent_func); - if (docucomment) { break; } - } - } - if (docucomment) { // Description const char *raw_desc = CFCDocuComment_get_description(docucomment); - char *desc = S_md_to_html(raw_desc, doc_class, 0); + char *desc = S_md_to_html(raw_desc, base_class, dir_level); result = CFCUtil_cat(result, desc, NULL); FREEMEM(desc); @@ -844,7 +848,7 @@ S_html_create_func(CFCClass *klass, CFCClass *doc_class, CFCCallable *func, if (param_names[0]) { result = CFCUtil_cat(result, "<dl>\n", NULL); for (size_t i = 0; param_names[i] != NULL; i++) { - char *doc = S_md_to_html(param_docs[i], doc_class, 0); + char *doc = S_md_to_html(param_docs[i], base_class, dir_level); result = CFCUtil_cat(result, "<dt>", param_names[i], "</dt>\n<dd>", doc, "</dd>\n", NULL); @@ -857,7 +861,7 @@ S_html_create_func(CFCClass *klass, CFCClass *doc_class, CFCCallable *func, const char *retval_doc = CFCDocuComment_get_retval(docucomment); if (retval_doc && strlen(retval_doc)) { char *md = CFCUtil_sprintf("**Returns:** %s", retval_doc); - char *html = S_md_to_html(md, doc_class, 0); + char *html = S_md_to_html(md, base_class, dir_level); result = CFCUtil_cat(result, html, NULL); FREEMEM(html); FREEMEM(md); @@ -871,7 +875,7 @@ S_html_create_func(CFCClass *klass, CFCClass *doc_class, CFCCallable *func, } static char* -S_html_create_param_list(CFCClass *klass, CFCCallable *func) { +S_html_create_param_list(CFCClass *klass, CFCCallable *func, int dir_level) { CFCParamList *param_list = CFCCallable_get_param_list(func); CFCVariable **variables = CFCParamList_get_variables(param_list); @@ -899,7 +903,7 @@ S_html_create_param_list(CFCClass *klass, CFCCallable *func) { type_html = CFCUtil_sprintf(pattern, prefix, struct_sym); } else { - type_html = S_type_to_html(type, " ", klass); + type_html = S_type_to_html(type, " ", klass, dir_level); } const char *sep = variables[i+1] ? "," : ""; @@ -924,7 +928,7 @@ S_html_create_param_list(CFCClass *klass, CFCCallable *func) { } static char* -S_html_create_inheritance(CFCClass *klass) { +S_html_create_inheritance(CFCClass *klass, int dir_level) { CFCClass *ancestor = CFCClass_get_parent(klass); char *result = CFCUtil_strdup(""); @@ -935,7 +939,7 @@ S_html_create_inheritance(CFCClass *klass) { NULL); while (ancestor) { const char *ancestor_name = CFCClass_get_name(ancestor); - char *ancestor_url = S_class_to_url(ancestor, klass, 0); + char *ancestor_url = S_class_to_url(ancestor, dir_level); result = CFCUtil_cat(result, " is a <a href=\"", ancestor_url, "\">", ancestor_name, "</a>", NULL); FREEMEM(ancestor_url); @@ -947,11 +951,11 @@ S_html_create_inheritance(CFCClass *klass) { } static char* -S_md_to_html(const char *md, CFCClass *klass, int dir_level) { +S_md_to_html(const char *md, CFCClass *base_class, int dir_level) { int options = CMARK_OPT_SMART | CMARK_OPT_VALIDATE_UTF8; cmark_node *doc = cmark_parse_document(md, strlen(md), options); - S_transform_doc(doc, klass, dir_level); + S_transform_doc(doc, base_class, dir_level); char *html = cmark_render_html(doc, CMARK_OPT_SAFE); cmark_node_free(doc); @@ -959,7 +963,7 @@ S_md_to_html(const char *md, CFCClass *klass, int dir_level) { } static void -S_transform_doc(cmark_node *node, CFCClass *klass, int dir_level) { +S_transform_doc(cmark_node *node, CFCClass *base_class, int dir_level) { int found_matching_code_block = false; cmark_iter *iter = cmark_iter_new(node); cmark_event_type ev_type; @@ -976,7 +980,7 @@ S_transform_doc(cmark_node *node, CFCClass *klass, int dir_level) { case CMARK_NODE_LINK: if (ev_type == CMARK_EVENT_EXIT) { - S_transform_link(cur, klass, dir_level); + S_transform_link(cur, base_class, dir_level); } break; @@ -1016,15 +1020,15 @@ S_transform_code_block(cmark_node *code_block, int found_matching_code_block) { } static void -S_transform_link(cmark_node *link, CFCClass *doc_class, int dir_level) { +S_transform_link(cmark_node *link, CFCClass *base_class, int dir_level) { const char *uri_string = cmark_node_get_url(link); if (!uri_string || !CFCUri_is_clownfish_uri(uri_string)) { return; } - CFCUri *uri_obj = CFCUri_new(uri_string, doc_class); + CFCUri *uri_obj = CFCUri_new(uri_string, base_class); CFCUriType uri_type = CFCUri_get_type(uri_obj); - char *url = S_cfc_uri_to_url(uri_obj, doc_class, dir_level); + char *url = S_cfc_uri_to_url(uri_obj, dir_level); if (uri_type == CFC_URI_NULL || uri_type == CFC_URI_ERROR) { // Replace link with text. @@ -1066,7 +1070,8 @@ S_transform_link(cmark_node *link, CFCClass *doc_class, int dir_level) { } static char* -S_type_to_html(CFCType *type, const char *sep, CFCClass *doc_class) { +S_type_to_html(CFCType *type, const char *sep, CFCClass *doc_class, + int dir_level) { const char *specifier = CFCType_get_specifier(type); char *specifier_html = NULL; @@ -1096,7 +1101,7 @@ S_type_to_html(CFCType *type, const char *sep, CFCClass *doc_class) { specifier_html = CFCUtil_sprintf(pattern, prefix, struct_sym); } else { - char *url = S_class_to_url(klass, doc_class, 0); + char *url = S_class_to_url(klass, dir_level); const char *pattern = "<span class=\"prefix\">%s</span>" "<a href=\"%s\">%s</a>"; @@ -1126,14 +1131,15 @@ S_type_to_html(CFCType *type, const char *sep, CFCClass *doc_class) { // Return a relative URL for a CFCUri object. static char* -S_cfc_uri_to_url(CFCUri *uri_obj, CFCClass *doc_class, int dir_level) { +S_cfc_uri_to_url(CFCUri *uri_obj, int dir_level) { char *url = NULL; CFCUriType type = CFCUri_get_type(uri_obj); switch (type) { case CFC_URI_CLASS: { + // TODO: Don't link to the HTML document itself. CFCClass *klass = CFCUri_get_class(uri_obj); - url = S_class_to_url(klass, doc_class, dir_level); + url = S_class_to_url(klass, dir_level); break; } @@ -1141,7 +1147,7 @@ S_cfc_uri_to_url(CFCUri *uri_obj, CFCClass *doc_class, int dir_level) { case CFC_URI_METHOD: { CFCClass *klass = CFCUri_get_class(uri_obj); const char *name = CFCUri_get_callable_name(uri_obj); - char *class_url = S_class_to_url(klass, doc_class, dir_level); + char *class_url = S_class_to_url(klass, dir_level); url = CFCUtil_sprintf("%s#func_%s", class_url, name); FREEMEM(class_url); break; @@ -1149,7 +1155,7 @@ S_cfc_uri_to_url(CFCUri *uri_obj, CFCClass *doc_class, int dir_level) { case CFC_URI_DOCUMENT: { CFCDocument *doc = CFCUri_get_document(uri_obj); - url = S_document_to_url(doc, doc_class, dir_level); + url = S_document_to_url(doc, dir_level); break; } @@ -1162,11 +1168,11 @@ S_cfc_uri_to_url(CFCUri *uri_obj, CFCClass *doc_class, int dir_level) { // Return a relative URL to a class. static char* -S_class_to_url(CFCClass *klass, CFCClass *base, int dir_level) { +S_class_to_url(CFCClass *klass, int dir_level) { const char *class_name = CFCClass_get_name(klass); char *path = CFCUtil_global_replace(class_name, "::", CHY_DIR_SEP); char *url = CFCUtil_sprintf("%s.html", path); - char *rel_url = S_relative_url(url, base, dir_level); + char *rel_url = S_relative_url(url, dir_level); FREEMEM(url); FREEMEM(path); @@ -1175,11 +1181,11 @@ S_class_to_url(CFCClass *klass, CFCClass *base, int dir_level) { // Return a relative URL to a document. static char* -S_document_to_url(CFCDocument *doc, CFCClass *base, int dir_level) { +S_document_to_url(CFCDocument *doc, int dir_level) { const char *path_part = CFCDocument_get_path_part(doc); char *slashy = CFCUtil_global_replace(path_part, CHY_DIR_SEP, "/"); char *url = CFCUtil_sprintf("%s.html", slashy); - char *rel_url = S_relative_url(url, base, dir_level); + char *rel_url = S_relative_url(url, dir_level); FREEMEM(url); FREEMEM(slashy); @@ -1187,17 +1193,7 @@ S_document_to_url(CFCDocument *doc, CFCClass *base, int dir_level) { } static char* -S_relative_url(const char *url, CFCClass *base, int dir_level) { - if (base) { - const char *base_name = CFCClass_get_name(base); - for (size_t i = 0; base_name[i]; i++) { - if (base_name[i] == ':' && base_name[i+1] == ':') { - dir_level++; - i++; - } - } - } - +S_relative_url(const char *url, int dir_level) { // Create path back to root size_t bytes = (size_t)(dir_level * 3); char *prefix = (char*)MALLOCATE(bytes + 1); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCCMan.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCCMan.c b/compiler/src/CFCCMan.c index b271702..ed94a6c 100644 --- a/compiler/src/CFCCMan.c +++ b/compiler/src/CFCCMan.c @@ -58,7 +58,8 @@ static char* S_man_create_fresh_methods(CFCClass *klass, CFCClass *ancestor); static char* -S_man_create_func(CFCClass *klass, CFCCallable *func, const char *full_sym); +S_man_create_func(CFCClass *klass, CFCCallable *func, const char *full_sym, + CFCDocuComment *docucomment, CFCClass *base_class); static char* S_man_create_param_list(CFCClass *klass, CFCCallable *func); @@ -67,10 +68,10 @@ static char* S_man_create_inheritance(CFCClass *klass); static char* -S_md_to_man(CFCClass *klass, const char *md, int level); +S_md_to_man(const char *md, CFCClass *base_class, int level); static char* -S_nodes_to_man(CFCClass *klass, cmark_node *node, int level); +S_nodes_to_man(cmark_node *node, CFCClass *base_class, int level); static char* S_man_escape(const char *content); @@ -131,7 +132,7 @@ S_man_create_name(CFCClass *klass) { raw_brief = CFCDocuComment_get_brief(docucom); } if (raw_brief && raw_brief[0] != '\0') { - char *brief = S_md_to_man(klass, raw_brief, 0); + char *brief = S_md_to_man(raw_brief, klass, 0); result = CFCUtil_cat(result, " \\- ", brief, NULL); FREEMEM(brief); } @@ -158,7 +159,7 @@ S_man_create_description(CFCClass *klass) { const char *raw_description = CFCDocuComment_get_long(docucom); if (!raw_description || raw_description[0] == '\0') { return result; } - char *description = S_md_to_man(klass, raw_description, 0); + char *description = S_md_to_man(raw_description, klass, 0); result = CFCUtil_cat(result, ".SH DESCRIPTION\n", description, NULL); FREEMEM(description); @@ -181,9 +182,10 @@ S_man_create_functions(CFCClass *klass) { const char *name = CFCFunction_get_name(func); result = CFCUtil_cat(result, ".TP\n.B ", name, "\n", NULL); + CFCDocuComment *comment = CFCFunction_get_docucomment(func); char *full_func_sym = CFCFunction_full_func_sym(func, klass); char *function_man = S_man_create_func(klass, (CFCCallable*)func, - full_func_sym); + full_func_sym, comment, klass); result = CFCUtil_cat(result, function_man, NULL); FREEMEM(function_man); FREEMEM(full_func_sym); @@ -256,9 +258,14 @@ S_man_create_fresh_methods(CFCClass *klass, CFCClass *ancestor) { } result = CFCUtil_cat(result, "\n", NULL); + // Get documentation, which may be inherited. + CFCClass *base_class = NULL; + CFCDocuComment *comment + = CFCMethod_get_docucomment(method, &base_class); + char *full_sym = CFCMethod_full_method_sym(method, klass); char *method_man = S_man_create_func(klass, (CFCCallable*)method, - full_sym); + full_sym, comment, base_class); result = CFCUtil_cat(result, method_man, NULL); FREEMEM(method_man); FREEMEM(full_sym); @@ -268,7 +275,8 @@ S_man_create_fresh_methods(CFCClass *klass, CFCClass *ancestor) { } static char* -S_man_create_func(CFCClass *klass, CFCCallable *func, const char *full_sym) { +S_man_create_func(CFCClass *klass, CFCCallable *func, const char *full_sym, + CFCDocuComment *docucomment, CFCClass *base_class) { CFCType *return_type = CFCCallable_get_return_type(func); const char *return_type_c = CFCType_to_c(return_type); const char *incremented = ""; @@ -291,24 +299,10 @@ S_man_create_func(CFCClass *klass, CFCCallable *func, const char *full_sym) { FREEMEM(param_list); - // Get documentation, which may be inherited. - CFCDocuComment *docucomment = CFCCallable_get_docucomment(func); - if (!docucomment) { - const char *name = CFCCallable_get_name(func); - CFCClass *parent = klass; - while (NULL != (parent = CFCClass_get_parent(parent))) { - CFCCallable *parent_func - = (CFCCallable*)CFCClass_method(parent, name); - if (!parent_func) { break; } - docucomment = CFCCallable_get_docucomment(parent_func); - if (docucomment) { break; } - } - } - if (docucomment) { // Description const char *raw_desc = CFCDocuComment_get_description(docucomment); - char *desc = S_md_to_man(klass, raw_desc, 1); + char *desc = S_md_to_man(raw_desc, base_class, 1); result = CFCUtil_cat(result, ".IP\n", desc, NULL); FREEMEM(desc); @@ -320,7 +314,7 @@ S_man_create_func(CFCClass *klass, CFCCallable *func, const char *full_sym) { if (param_names[0]) { result = CFCUtil_cat(result, ".RS\n", NULL); for (size_t i = 0; param_names[i] != NULL; i++) { - char *doc = S_md_to_man(klass, param_docs[i], 1); + char *doc = S_md_to_man(param_docs[i], base_class, 1); result = CFCUtil_cat(result, ".TP\n.I ", param_names[i], "\n", doc, NULL); FREEMEM(doc); @@ -331,7 +325,7 @@ S_man_create_func(CFCClass *klass, CFCCallable *func, const char *full_sym) { // Return value const char *retval_doc = CFCDocuComment_get_retval(docucomment); if (retval_doc && strlen(retval_doc)) { - char *doc = S_md_to_man(klass, retval_doc, 1); + char *doc = S_md_to_man(retval_doc, base_class, 1); result = CFCUtil_cat(result, ".IP\n.B Returns:\n", doc, NULL); FREEMEM(doc); } @@ -409,12 +403,12 @@ S_man_create_inheritance(CFCClass *klass) { } static char* -S_md_to_man(CFCClass *klass, const char *md, int level) { +S_md_to_man(const char *md, CFCClass *base_class, int level) { int options = CMARK_OPT_NORMALIZE | CMARK_OPT_SMART | CMARK_OPT_VALIDATE_UTF8; cmark_node *doc = cmark_parse_document(md, strlen(md), options); - char *result = S_nodes_to_man(klass, doc, level); + char *result = S_nodes_to_man(doc, base_class, level); cmark_node_free(doc); return result; @@ -448,7 +442,7 @@ S_md_to_man(CFCClass *klass, const char *md, int level) { #define ADJUST_VSPACE 2 static char* -S_nodes_to_man(CFCClass *klass, cmark_node *node, int level) { +S_nodes_to_man(cmark_node *node, CFCClass *base_class, int level) { char *result = CFCUtil_strdup(""); int needs_adjust = 0; int found_matching_code_block = false; @@ -612,7 +606,7 @@ S_nodes_to_man(CFCClass *klass, cmark_node *node, int level) { && !cmark_node_first_child(node) ) { // Empty link text. - CFCUri *uri_obj = CFCUri_new(url, klass); + CFCUri *uri_obj = CFCUri_new(url, base_class); char *link_text = CFCC_link_text(uri_obj); if (link_text) { result = CFCUtil_cat(result, link_text, NULL); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCCallable.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCCallable.c b/compiler/src/CFCCallable.c index 8071761..3376966 100644 --- a/compiler/src/CFCCallable.c +++ b/compiler/src/CFCCallable.c @@ -91,11 +91,6 @@ CFCCallable_get_param_list(CFCCallable *self) { return self->param_list; } -CFCDocuComment* -CFCCallable_get_docucomment(CFCCallable *self) { - return self->docucomment; -} - const char* CFCCallable_get_name(CFCCallable *self) { return CFCSymbol_get_name((CFCSymbol*)self); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCCallable.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCCallable.h b/compiler/src/CFCCallable.h index 0848f11..2f0558a 100644 --- a/compiler/src/CFCCallable.h +++ b/compiler/src/CFCCallable.h @@ -76,9 +76,6 @@ CFCCallable_get_return_type(CFCCallable *self); struct CFCParamList* CFCCallable_get_param_list(CFCCallable *self); -struct CFCDocuComment* -CFCCallable_get_docucomment(CFCCallable *self); - const char* CFCCallable_get_name(CFCCallable *self); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCMethod.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCMethod.c b/compiler/src/CFCMethod.c index 1fd6557..fb806d0 100644 --- a/compiler/src/CFCMethod.c +++ b/compiler/src/CFCMethod.c @@ -453,6 +453,29 @@ CFCMethod_short_imp_func(CFCMethod *self, CFCClass *klass) { return S_short_method_sym(self, klass, "_IMP"); } +CFCDocuComment* +CFCMethod_get_docucomment(CFCMethod *self, CFCClass **class_ptr) { + CFCMethod *method = self; + const char *name = CFCMethod_get_name(self); + + do { + CFCClass *klass = S_fresh_class(method); + + CFCDocuComment *comment = method->callable.docucomment; + if (comment) { + if (class_ptr) { *class_ptr = klass; } + return comment; + } + + CFCClass *parent = CFCClass_get_parent(klass); + if (!parent) { break; } + method = CFCClass_method(parent, name); + } while (method); + + if (class_ptr) { *class_ptr = NULL; } + return NULL; +} + static CFCClass* S_fresh_class(CFCMethod *self) { return (CFCClass*)CFCWeakPtr_deref(self->fresh_class); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCMethod.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCMethod.h b/compiler/src/CFCMethod.h index 3a97c7a..382e26f 100644 --- a/compiler/src/CFCMethod.h +++ b/compiler/src/CFCMethod.h @@ -231,6 +231,13 @@ CFCMethod_imp_func(CFCMethod *self, struct CFCClass *klass); char* CFCMethod_short_imp_func(CFCMethod *self, struct CFCClass *klass); +/** Return the DocuComment for the method, which may be inherited. If + * `class_ptr` is non-NULL, use it to store the class where the comment + * found. + */ +struct CFCDocuComment* +CFCMethod_get_docucomment(CFCMethod *self, struct CFCClass **class_ptr); + #ifdef __cplusplus } #endif http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCParcel.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCParcel.c b/compiler/src/CFCParcel.c index ff8e0ed..b126a29 100644 --- a/compiler/src/CFCParcel.c +++ b/compiler/src/CFCParcel.c @@ -427,6 +427,11 @@ CFCParcel_is_installed(CFCParcel *self) { return self->is_installed; } +void +CFCParcel_set_installed(CFCParcel *self, int is_installed) { + self->is_installed = is_installed; +} + CFCVersion* CFCParcel_get_version(CFCParcel *self) { return self->version; http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCParcel.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCParcel.h b/compiler/src/CFCParcel.h index 125364e..96fe074 100644 --- a/compiler/src/CFCParcel.h +++ b/compiler/src/CFCParcel.h @@ -100,6 +100,9 @@ CFCParcel_set_host_module_name(CFCParcel *self, const char *name); int CFCParcel_is_installed(CFCParcel *self); +void +CFCParcel_set_installed(CFCParcel *self, int is_installed); + struct CFCVersion* CFCParcel_get_version(CFCParcel *self); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCPerlPod.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCPerlPod.c b/compiler/src/CFCPerlPod.c index 0d1ca0b..a5965a0 100644 --- a/compiler/src/CFCPerlPod.c +++ b/compiler/src/CFCPerlPod.c @@ -84,16 +84,16 @@ static char* S_camel_to_lower(const char *camel); static char* -S_nodes_to_pod(cmark_node *node, CFCClass *klass, int header_level); +S_nodes_to_pod(cmark_node *node, CFCClass *base_class, int header_level); static char* -S_node_to_pod(cmark_node *node, CFCClass *klass, int header_level); +S_node_to_pod(cmark_node *node, CFCClass *base_class, int header_level); static char* S_pod_escape(const char *content); static char* -S_convert_link(cmark_node *link, CFCClass *klass, int header_level); +S_convert_link(cmark_node *link, CFCClass *base_class, int header_level); static char* S_pod_link(const char *text, const char *name); @@ -189,7 +189,6 @@ CFCPerlPod_get_description(CFCPerlPod *self) { char* CFCPerlPod_methods_pod(CFCPerlPod *self, CFCClass *klass) { - const char *class_name = CFCClass_get_name(klass); char *abstract_pod = CFCUtil_strdup(""); char *methods_pod = CFCUtil_strdup(""); @@ -222,6 +221,10 @@ CFCPerlPod_methods_pod(CFCPerlPod *self, CFCClass *klass) { } } + CFCClass *base_class = NULL; + CFCDocuComment *comment + = CFCMethod_get_docucomment(method, &base_class); + if (meth_spec) { // Found custom POD. if (meth_spec->pod) { @@ -231,8 +234,8 @@ CFCPerlPod_methods_pod(CFCPerlPod *self, CFCClass *klass) { meth_pod = CFCPerlPod_gen_subroutine_pod((CFCCallable*)method, meth_spec->alias, klass, - meth_spec->sample, - class_name, false); + meth_spec->sample, false, + comment, base_class); } } else { @@ -257,8 +260,8 @@ CFCPerlPod_methods_pod(CFCPerlPod *self, CFCClass *klass) { char *perl_name = CFCPerlMethod_perl_name(method); meth_pod = CFCPerlPod_gen_subroutine_pod((CFCCallable*)method, - perl_name, klass, NULL, - class_name, false); + perl_name, klass, NULL, false, + comment, base_class); FREEMEM(perl_name); } @@ -289,7 +292,6 @@ CFCPerlPod_constructors_pod(CFCPerlPod *self, CFCClass *klass) { if (!self->num_constructors) { return CFCUtil_strdup(""); } - const char *class_name = CFCClass_get_name(klass); char *pod = CFCUtil_strdup("=head1 CONSTRUCTORS\n\n"); for (size_t i = 0; i < self->num_constructors; i++) { NamePod slot = self->constructors[i]; @@ -303,10 +305,11 @@ CFCPerlPod_constructors_pod(CFCPerlPod *self, CFCClass *klass) { CFCUtil_die("Can't find constructor '%s' in class '%s'", func_name, CFCClass_get_name(klass)); } + CFCDocuComment *comment = CFCFunction_get_docucomment(pod_func); char *sub_pod = CFCPerlPod_gen_subroutine_pod((CFCCallable*)pod_func, slot.alias, klass, slot.sample, - class_name, true); + true, comment, klass); pod = CFCUtil_cat(pod, sub_pod, NULL); FREEMEM(sub_pod); } @@ -317,9 +320,11 @@ CFCPerlPod_constructors_pod(CFCPerlPod *self, CFCClass *klass) { char* CFCPerlPod_gen_subroutine_pod(CFCCallable *func, const char *alias, CFCClass *klass, - const char *code_sample, - const char *class_name, int is_constructor) { - const char *func_name = CFCCallable_get_name(func); + const char *code_sample, int is_constructor, + CFCDocuComment *docucomment, + CFCClass *base_class) { + const char *class_name = CFCClass_get_name(klass); + const char *func_name = CFCCallable_get_name(func); // Only allow "public" subs to be exposed as part of the public API. if (!CFCCallable_public(func)) { @@ -339,18 +344,6 @@ CFCPerlPod_gen_subroutine_pod(CFCCallable *func, pod = CFCUtil_cat(pod, code_sample, "\n", NULL); } - // Get documentation, which may be inherited. - CFCDocuComment *docucomment = CFCCallable_get_docucomment(func); - if (!docucomment) { - CFCClass *parent = klass; - while (NULL != (parent = CFCClass_get_parent(parent))) { - CFCCallable *parent_func - = (CFCCallable*)CFCClass_method(parent, func_name); - if (!parent_func) { break; } - docucomment = CFCCallable_get_docucomment(parent_func); - if (docucomment) { break; } - } - } if (!docucomment) { return pod; } @@ -358,7 +351,7 @@ CFCPerlPod_gen_subroutine_pod(CFCCallable *func, // Incorporate "description" text from DocuComment. const char *long_doc = CFCDocuComment_get_description(docucomment); if (long_doc && strlen(long_doc)) { - char *perlified = CFCPerlPod_md_to_pod(long_doc, klass, 3); + char *perlified = CFCPerlPod_md_to_pod(long_doc, base_class, 3); pod = CFCUtil_cat(pod, perlified, NULL); FREEMEM(perlified); } @@ -369,7 +362,8 @@ CFCPerlPod_gen_subroutine_pod(CFCCallable *func, if (param_names[0]) { pod = CFCUtil_cat(pod, "=over\n\n", NULL); for (size_t i = 0; param_names[i] != NULL; i++) { - char *perlified = CFCPerlPod_md_to_pod(param_docs[i], klass, 3); + char *perlified + = CFCPerlPod_md_to_pod(param_docs[i], base_class, 3); pod = CFCUtil_cat(pod, "=item *\n\nB<", param_names[i], "> - ", perlified, NULL); FREEMEM(perlified); @@ -380,7 +374,7 @@ CFCPerlPod_gen_subroutine_pod(CFCCallable *func, // Add return value description, if any. const char *retval_doc = CFCDocuComment_get_retval(docucomment); if (retval_doc && strlen(retval_doc)) { - char *perlified = CFCPerlPod_md_to_pod(retval_doc, klass, 3); + char *perlified = CFCPerlPod_md_to_pod(retval_doc, base_class, 3); pod = CFCUtil_cat(pod, "Returns: ", perlified, NULL); FREEMEM(perlified); } @@ -635,11 +629,11 @@ CFCPerlPod_md_doc_to_pod(const char *module, const char *md) { } char* -CFCPerlPod_md_to_pod(const char *md, CFCClass *klass, int header_level) { +CFCPerlPod_md_to_pod(const char *md, CFCClass *base_class, int header_level) { int options = CMARK_OPT_SMART | CMARK_OPT_VALIDATE_UTF8; cmark_node *doc = cmark_parse_document(md, strlen(md), options); - char *pod = S_node_to_pod(doc, klass, header_level); + char *pod = S_node_to_pod(doc, base_class, header_level); cmark_node_free(doc); return pod; @@ -647,11 +641,11 @@ CFCPerlPod_md_to_pod(const char *md, CFCClass *klass, int header_level) { // Convert a node and its siblings. static char* -S_nodes_to_pod(cmark_node *node, CFCClass *klass, int header_level) { +S_nodes_to_pod(cmark_node *node, CFCClass *base_class, int header_level) { char *result = CFCUtil_strdup(""); while (node != NULL) { - char *pod = S_node_to_pod(node, klass, header_level); + char *pod = S_node_to_pod(node, base_class, header_level); result = CFCUtil_cat(result, pod, NULL); FREEMEM(pod); @@ -663,7 +657,7 @@ S_nodes_to_pod(cmark_node *node, CFCClass *klass, int header_level) { // Convert a single node. static char* -S_node_to_pod(cmark_node *node, CFCClass *klass, int header_level) { +S_node_to_pod(cmark_node *node, CFCClass *base_class, int header_level) { char *result = CFCUtil_strdup(""); if (node == NULL) { return result; @@ -795,7 +789,7 @@ S_node_to_pod(cmark_node *node, CFCClass *klass, int header_level) { case CMARK_NODE_LINK: if (ev_type == CMARK_EVENT_ENTER) { - char *pod = S_convert_link(node, klass, header_level); + char *pod = S_convert_link(node, base_class, header_level); result = CFCUtil_cat(result, pod, NULL); FREEMEM(pod); cmark_iter_reset(iter, node, CMARK_EVENT_EXIT); @@ -887,12 +881,15 @@ S_pod_escape(const char *content) { } static char* -S_convert_link(cmark_node *link, CFCClass *doc_class, int header_level) { +S_convert_link(cmark_node *link, CFCClass *base_class, int header_level) { cmark_node *child = cmark_node_first_child(link); const char *uri = cmark_node_get_url(link); - char *text = S_nodes_to_pod(child, doc_class, header_level); + char *text = S_nodes_to_pod(child, base_class, header_level); char *retval; + // TODO: Pass real pod_class as argument. + CFCClass *pod_class = base_class; + if (!CFCUri_is_clownfish_uri(uri)) { retval = S_pod_link(text, uri); FREEMEM(text); @@ -901,7 +898,7 @@ S_convert_link(cmark_node *link, CFCClass *doc_class, int header_level) { char *new_uri = NULL; char *new_text = NULL; - CFCUri *uri_obj = CFCUri_new(uri, doc_class); + CFCUri *uri_obj = CFCUri_new(uri, base_class); CFCUriType type = CFCUri_get_type(uri_obj); switch (type) { @@ -919,7 +916,7 @@ S_convert_link(cmark_node *link, CFCClass *doc_class, int header_level) { case CFC_URI_CLASS: { CFCClass *klass = CFCUri_get_class(uri_obj); - if (klass != doc_class) { + if (klass != pod_class) { const char *class_name = CFCClass_get_name(klass); new_uri = CFCUtil_strdup(class_name); } @@ -962,7 +959,7 @@ S_convert_link(cmark_node *link, CFCClass *doc_class, int header_level) { } } - if (klass == doc_class) { + if (klass == pod_class) { new_uri = CFCUtil_sprintf("/%s", perl_name); } else { http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCPerlPod.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCPerlPod.h b/compiler/src/CFCPerlPod.h index c42a34d..14306f2 100644 --- a/compiler/src/CFCPerlPod.h +++ b/compiler/src/CFCPerlPod.h @@ -27,6 +27,7 @@ extern "C" { typedef struct CFCPerlPod CFCPerlPod; struct CFCCallable; struct CFCClass; +struct CFCDocuComment; CFCPerlPod* CFCPerlPod_new(void); @@ -128,12 +129,15 @@ CFCPerlPod_md_to_pod(const char *md, struct CFCClass *klass, int header_level); * @param code_sample Optional example usage code. * @param is_construtor Indicate whether this is a constructor, as the default * argument handling is different for constructors. + * @param docucomment An optional docucomment. + * @param base_class The class to resolve relative URIs in the docucomment. */ char* CFCPerlPod_gen_subroutine_pod(struct CFCCallable *func, const char *alias, struct CFCClass *klass, - const char *code_sample, - const char *class_name, int is_constructor); + const char *code_sample, int is_constructor, + struct CFCDocuComment *docucomment, + struct CFCClass *base_class); #ifdef __cplusplus } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCTestDocuComment.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCTestDocuComment.c b/compiler/src/CFCTestDocuComment.c index d08568a..eca0fe4 100644 --- a/compiler/src/CFCTestDocuComment.c +++ b/compiler/src/CFCTestDocuComment.c @@ -39,7 +39,7 @@ S_run_tests(CFCTest *test); const CFCTestBatch CFCTEST_BATCH_DOCU_COMMENT = { "Clownfish::CFC::Model::DocuComment", - 19, + 34, S_run_tests }; @@ -319,9 +319,110 @@ S_test_generator(CFCTest *test) { } static void +S_test_hierarchy(CFCTest *test) { + CFCHierarchy *hierarchy = CFCHierarchy_new("autogen"); + CFCParser *parser = CFCParser_new(); + + CFCParcel *base_parcel + = CFCTest_parse_parcel(test, parser, "parcel Base;"); + CFCClass *base_class = CFCTest_parse_class(test, parser, + "public class Base {\n" + " /** [](Linked)\n" + " */\n" + " public void\n" + " Method(Base *self);\n" + "}\n" + ); + CFCClass *linked_class = CFCTest_parse_class(test, parser, + "public class Linked {}" + ); + + // Override method without DocuComment. + CFCParcel *override_parcel + = CFCTest_parse_parcel(test, parser, "parcel Override;"); + CFCClass *override_class = CFCTest_parse_class(test, parser, + "public class Override inherits Base {\n" + " public void\n" + " Method(Override *self);\n" + "}\n" + ); + + CFCParcel *inherit_parcel + = CFCTest_parse_parcel(test, parser, "parcel Inherit;"); + CFCParcel_set_installed(inherit_parcel, true); + CFCClass *inherit_class = CFCTest_parse_class(test, parser, + "public class Inherit inherits Override {}" + ); + + CFCClass_add_child(base_class, override_class); + CFCClass_add_child(override_class, inherit_class); + CFCClass_grow_tree(base_class); + + CFCCHtml *chtml = CFCCHtml_new(hierarchy, "", ""); + char *html = CFCCHtml_create_html_body(chtml, inherit_class); + const char *expected_html = + "<h1>Inherit</h1>\n" + "<table>\n" + "<tr>\n" + "<td class=\"label\">parcel</td>\n" + "<td><a href=\"inherit.html\">Inherit</a></td>\n" + "</tr>\n" + "<tr>\n" + "<td class=\"label\">class variable</td>\n" + "<td><code><span class=\"prefix\">INHERIT_</span>INHERIT</code></td>\n" + "</tr>\n" + "<tr>\n" + "<td class=\"label\">struct symbol</td>\n" + "<td><code><span class=\"prefix\">inherit_</span>Inherit</code></td>\n" + "</tr>\n" + "<tr>\n" + "<td class=\"label\">class nickname</td>\n" + "<td><code><span class=\"prefix\">inherit_</span>Inherit</code></td>\n" + "</tr>\n" + "<tr>\n" + "<td class=\"label\">header file</td>\n" + "<td><code>class.h</code></td>\n" + "</tr>\n" + "</table>\n" + "<h2>Name</h2>\n" + "<p>Inherit</p>\n" + "<h2>Methods</h2>\n" + "<h3>Methods inherited from Override</h3>\n" + "<dl>\n" + "<dt id=\"func_Method\">Method</dt>\n" + "<dd>\n" + "<pre><code>void\n" + "<span class=\"prefix\">inherit_</span><strong>Inherit_Method</strong>(\n" + " <span class=\"prefix\">inherit_</span>Inherit *<strong>self</strong>\n" + ");\n" + "</code></pre>\n" + "<p><a href=\"Linked.html\">Linked</a></p>\n" + "</dd>\n" + "</dl>\n" + "<h2>Inheritance</h2>\n" + "<p>Inherit is a <a href=\"Override.html\">Override</a> is a <a href=\"Base.html\">Base</a>.</p>\n"; + STR_EQ(test, html, expected_html, "create HTML"); + + FREEMEM(html); + CFCBase_decref((CFCBase*)chtml); + CFCBase_decref((CFCBase*)inherit_class); + CFCBase_decref((CFCBase*)inherit_parcel); + CFCBase_decref((CFCBase*)override_class); + CFCBase_decref((CFCBase*)override_parcel); + CFCBase_decref((CFCBase*)linked_class); + CFCBase_decref((CFCBase*)base_class); + CFCBase_decref((CFCBase*)base_parcel); + CFCBase_decref((CFCBase*)parser); + CFCBase_decref((CFCBase*)hierarchy); + + CFCDocument_clear_registry(); +} + +static void S_run_tests(CFCTest *test) { S_test_parser(test); S_test_md_to_pod(test); S_test_generator(test); + S_test_hierarchy(test); } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/81cdda1a/compiler/src/CFCUri.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCUri.c b/compiler/src/CFCUri.c index c16c43e..aa0eea4 100644 --- a/compiler/src/CFCUri.c +++ b/compiler/src/CFCUri.c @@ -24,12 +24,13 @@ #include "CFCDocument.h" #include "CFCFunction.h" #include "CFCMethod.h" +#include "CFCParcel.h" #include "CFCUtil.h" struct CFCUri { CFCBase base; char *string; - CFCClass *doc_class; + CFCClass *base_class; CFCUriType type; CFCClass *klass; CFCDocument *document; @@ -50,6 +51,12 @@ static void S_resolve(CFCUri *self, const char *prefix, const char *struct_sym, const char *callable); +static CFCClass* +S_find_class_full(CFCUri *self, const char *parcel, const char *struct_sym); + +static CFCClass* +S_find_class_short(CFCUri *self, const char *struct_sym); + static void S_set_error(CFCUri *self, const char *error); @@ -62,17 +69,17 @@ CFCUri_is_clownfish_uri(const char *uri) { } CFCUri* -CFCUri_new(const char *uri, CFCClass *doc_class) { +CFCUri_new(const char *uri, CFCClass *base_class) { CFCUri *self = (CFCUri*)CFCBase_allocate(&CFCURI_META); - return CFCUri_init(self, uri, doc_class); + return CFCUri_init(self, uri, base_class); } CFCUri* -CFCUri_init(CFCUri *self, const char *uri, CFCClass *doc_class) { +CFCUri_init(CFCUri *self, const char *uri, CFCClass *base_class) { CFCUTIL_NULL_CHECK(uri); - self->string = CFCUtil_strdup(uri); - self->doc_class = (CFCClass*)CFCBase_incref((CFCBase*)doc_class); + self->string = CFCUtil_strdup(uri); + self->base_class = (CFCClass*)CFCBase_incref((CFCBase*)base_class); return self; } @@ -82,7 +89,7 @@ CFCUri_destroy(CFCUri *self) { FREEMEM(self->string); FREEMEM(self->callable); FREEMEM(self->error); - CFCBase_decref((CFCBase*)self->doc_class); + CFCBase_decref((CFCBase*)self->base_class); CFCBase_decref((CFCBase*)self->klass); CFCBase_decref((CFCBase*)self->document); CFCBase_destroy((CFCBase*)self); @@ -147,24 +154,17 @@ done: static void S_resolve(CFCUri *self, const char *parcel, const char *struct_sym, const char *callable) { - // Try to find a CFCClass. - CFCClass *doc_class = self->doc_class; CFCClass *klass = NULL; if (parcel) { - char *full_struct_sym = CFCUtil_sprintf("%s_%s", parcel, struct_sym); - klass = CFCClass_fetch_by_struct_sym(full_struct_sym); - FREEMEM(full_struct_sym); + klass = S_find_class_full(self, parcel, struct_sym); } - else if (struct_sym && doc_class) { - const char *prefix = CFCClass_get_prefix(doc_class); - char *full_struct_sym = CFCUtil_sprintf("%s%s", prefix, struct_sym); - klass = CFCClass_fetch_by_struct_sym(full_struct_sym); - FREEMEM(full_struct_sym); + else if (struct_sym) { + klass = S_find_class_short(self, struct_sym); } else if (callable) { - klass = doc_class; + klass = self->base_class; } if (klass) { @@ -228,6 +228,65 @@ S_resolve(CFCUri *self, const char *parcel, const char *struct_sym, S_set_error(self, "Couldn't resolve Clownfish URI"); } +static CFCClass* +S_find_class_full(CFCUri *self, const char *parcel, const char *struct_sym) { + char *full_struct_sym = CFCUtil_sprintf("%s_%s", parcel, struct_sym); + CFCClass *klass = NULL; + + if (self->base_class) { + // Only look in parcel of base class. + CFCParcel *parcel = CFCClass_get_parcel(self->base_class); + klass = CFCParcel_class_by_full_sym(parcel, full_struct_sym); + } + else { + // Search all source parcels For standalone .md docs. + CFCParcel **parcels = CFCParcel_all_parcels(); + for (size_t i = 0; parcels[i]; i++) { + CFCParcel *parcel = parcels[i]; + if (CFCParcel_included(parcel)) { continue; } + klass = CFCParcel_class_by_full_sym(parcel, full_struct_sym); + if (klass) { break; } + } + } + + FREEMEM(full_struct_sym); + return klass; +} + +static CFCClass* +S_find_class_short(CFCUri *self, const char *struct_sym) { + CFCClass *klass = NULL; + + if (self->base_class) { + // Only look in parcel of base class. + CFCParcel *parcel = CFCClass_get_parcel(self->base_class); + klass = CFCParcel_class_by_short_sym(parcel, struct_sym); + } + else { + // Search all source parcels For standalone .md docs. + CFCParcel **parcels = CFCParcel_all_parcels(); + for (size_t i = 0; parcels[i]; i++) { + CFCParcel *parcel = parcels[i]; + if (CFCParcel_included(parcel)) { continue; } + CFCClass *candidate + = CFCParcel_class_by_short_sym(parcel, struct_sym); + if (candidate && candidate != klass) { + if (klass) { + // Found in multiple parcels. + CFCUtil_warn("Ambiguous class name '%s' in URI. Do you" + " mean '%s' or '%s'?", struct_sym, + CFCClass_full_struct_sym(klass), + CFCClass_full_struct_sym(candidate)); + return NULL; + } + klass = candidate; + } + } + } + + return klass; +} + static void S_set_error(CFCUri *self, const char *error) { self->type = CFC_URI_ERROR;
