void CFCPerlClass_add_to_registry(CFCPerlClass *self) { if (registry_size == registry_cap) { size_t new_cap = registry_cap + 10; registry = (CFCPerlClass**)REALLOCATE(registry, (new_cap + 1) * sizeof(CFCPerlClass*)); for (size_t i = registry_cap; i <= new_cap; i++) { registry[i] = NULL; } registry_cap = new_cap; } CFCPerlClass *existing = CFCPerlClass_singleton(self->class_name); if (existing) { CFCUtil_die("Class '%s' already registered", self->class_name); } registry[registry_size] = (CFCPerlClass*)CFCBase_incref((CFCBase*)self); registry_size++; qsort(registry, registry_size, sizeof(CFCPerlClass*), S_compare_cfcperlclass); }
char* CFCPerlClass_create_pod(CFCPerlClass *self) { CFCPerlPod *pod_spec = self->pod_spec; const char *class_name = self->class_name; CFCClass *client = self->client; if (!pod_spec) { return NULL; } if (!client) { CFCUtil_die("No client for %s", class_name); } CFCDocuComment *docucom = CFCClass_get_docucomment(client); if (!docucom) { CFCUtil_die("No DocuComment for %s", class_name); } // Get the class's brief description. const char *raw_brief = CFCDocuComment_get_brief(docucom); char *brief = CFCPerlPod_md_to_pod(pod_spec, client, raw_brief); // Get the class's long description. char *description; const char *pod_description = CFCPerlPod_get_description(pod_spec); if (pod_description && strlen(pod_description)) { description = CFCUtil_sprintf("%s\n", pod_description); } else { const char *raw_description = CFCDocuComment_get_long(docucom); description = CFCPerlPod_md_to_pod(pod_spec, client, raw_description); } // Create SYNOPSIS. const char *raw_synopsis = CFCPerlPod_get_synopsis(pod_spec); char *synopsis = CFCUtil_strdup(""); if (raw_synopsis && strlen(raw_synopsis)) { synopsis = CFCUtil_cat(synopsis, "=head1 SYNOPSIS\n\n", raw_synopsis, "\n", NULL); } // Create CONSTRUCTORS. char *constructor_pod = CFCPerlPod_constructors_pod(pod_spec, client); // Create METHODS, possibly including an ABSTRACT METHODS section. char *methods_pod = CFCPerlPod_methods_pod(pod_spec, client); // Build an INHERITANCE section describing class ancestry. char *inheritance = CFCUtil_strdup(""); if (CFCClass_get_parent(client)) { inheritance = CFCUtil_cat(inheritance, "=head1 INHERITANCE\n\n", class_name, NULL); CFCClass *ancestor = client; while (NULL != (ancestor = CFCClass_get_parent(ancestor))) { const char *ancestor_klass = CFCClass_get_class_name(ancestor); if (CFCPerlClass_singleton(ancestor_klass)) { inheritance = CFCUtil_cat(inheritance, " isa L<", ancestor_klass, ">", NULL); } else { inheritance = CFCUtil_cat(inheritance, " isa ", ancestor_klass, NULL); } } inheritance = CFCUtil_cat(inheritance, ".\n\n", NULL); } // Put it all together. const char pattern[] = "=head1 NAME\n" "\n" "%s - %s" "%s" "=head1 DESCRIPTION\n" "\n" "%s" "%s" "%s" "%s" "=cut\n" "\n"; char *pod = CFCUtil_sprintf(pattern, class_name, brief, synopsis, description, constructor_pod, methods_pod, inheritance); FREEMEM(brief); FREEMEM(synopsis); FREEMEM(description); FREEMEM(constructor_pod); FREEMEM(methods_pod); FREEMEM(inheritance); return pod; }
static void S_write_host_c(CFCPerl *self, CFCParcel *parcel) { CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); const char *prefix = CFCParcel_get_prefix(parcel); const char *privacy_sym = CFCParcel_get_privacy_sym(parcel); char *includes = CFCUtil_strdup(""); char *cb_defs = CFCUtil_strdup(""); char *alias_adds = CFCUtil_strdup(""); for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; if (CFCClass_inert(klass)) { continue; } const char *class_prefix = CFCClass_get_prefix(klass); if (strcmp(class_prefix, prefix) != 0) { continue; } const char *class_name = CFCClass_get_name(klass); const char *include_h = CFCClass_include_h(klass); includes = CFCUtil_cat(includes, "#include \"", include_h, "\"\n", NULL); // Callbacks. CFCMethod **fresh_methods = CFCClass_fresh_methods(klass); for (int meth_num = 0; fresh_methods[meth_num] != NULL; meth_num++) { CFCMethod *method = fresh_methods[meth_num]; // Define callback. if (CFCMethod_novel(method) && !CFCMethod_final(method)) { char *cb_def = CFCPerlMethod_callback_def(method, klass); cb_defs = CFCUtil_cat(cb_defs, cb_def, "\n", NULL); FREEMEM(cb_def); } } // Add class aliases. CFCPerlClass *class_binding = CFCPerlClass_singleton(class_name); if (class_binding) { const char *class_var = CFCClass_full_class_var(klass); const char **aliases = CFCPerlClass_get_class_aliases(class_binding); for (size_t j = 0; aliases[j] != NULL; j++) { const char *alias = aliases[j]; int alias_len = (int)strlen(alias); const char pattern[] = " cfish_Class_add_alias_to_registry(" "%s, \"%s\", %d);\n"; char *alias_add = CFCUtil_sprintf(pattern, class_var, alias, alias_len); alias_adds = CFCUtil_cat(alias_adds, alias_add, NULL); FREEMEM(alias_add); } char *metadata_code = CFCPerlClass_method_metadata_code(class_binding); alias_adds = CFCUtil_cat(alias_adds, metadata_code, NULL); FREEMEM(metadata_code); } } const char pattern[] = "%s" "\n" "#define %s\n" // privacy_sym "\n" "#include \"%sperl.h\"\n" "#include \"XSBind.h\"\n" "#include \"Clownfish/Class.h\"\n" "#include \"Clownfish/Err.h\"\n" "#include \"Clownfish/Obj.h\"\n" "%s" "\n" "/* Avoid conflicts with Clownfish bool type. */\n" "#define HAS_BOOL\n" "#define PERL_NO_GET_CONTEXT\n" "#include \"EXTERN.h\"\n" "#include \"perl.h\"\n" "#include \"XSUB.h\"\n" "\n" "static void\n" "S_finish_callback_void(pTHX_ const char *meth_name) {\n" " int count = call_method(meth_name, G_VOID | G_DISCARD);\n" " if (count != 0) {\n" " CFISH_THROW(CFISH_ERR, \"Bad callback to '%%s': %%i32\",\n" " meth_name, (int32_t)count);\n" " }\n" " FREETMPS;\n" " LEAVE;\n" "}\n" "\n" "static CFISH_INLINE SV*\n" "SI_do_callback_sv(pTHX_ const char *meth_name) {\n" " int count = call_method(meth_name, G_SCALAR);\n" " if (count != 1) {\n" " CFISH_THROW(CFISH_ERR, \"Bad callback to '%%s': %%i32\",\n" " meth_name, (int32_t)count);\n" " }\n" " dSP;\n" " SV *return_sv = POPs;\n" " PUTBACK;\n" " return return_sv;\n" "}\n" "\n" "static int64_t\n" "S_finish_callback_i64(pTHX_ const char *meth_name) {\n" " SV *return_sv = SI_do_callback_sv(aTHX_ meth_name);\n" " int64_t retval;\n" " if (sizeof(IV) == 8) {\n" " retval = (int64_t)SvIV(return_sv);\n" " }\n" " else {\n" " if (SvIOK(return_sv)) {\n" " // It's already no more than 32 bits, so don't convert.\n" " retval = SvIV(return_sv);\n" " }\n" " else {\n" " // Maybe lossy.\n" " double temp = SvNV(return_sv);\n" " retval = (int64_t)temp;\n" " }\n" " }\n" " FREETMPS;\n" " LEAVE;\n" " return retval;\n" "}\n" "\n" "static double\n" "S_finish_callback_f64(pTHX_ const char *meth_name) {\n" " SV *return_sv = SI_do_callback_sv(aTHX_ meth_name);\n" " double retval = SvNV(return_sv);\n" " FREETMPS;\n" " LEAVE;\n" " return retval;\n" "}\n" "\n" "static cfish_Obj*\n" "S_finish_callback_obj(pTHX_ void *vself, const char *meth_name,\n" " int nullable) {\n" " SV *return_sv = SI_do_callback_sv(aTHX_ meth_name);\n" " cfish_Obj *retval\n" " = XSBind_perl_to_cfish_nullable(aTHX_ return_sv, CFISH_OBJ);\n" " FREETMPS;\n" " LEAVE;\n" " if (!nullable && !retval) {\n" " CFISH_THROW(CFISH_ERR, \"%%o#%%s cannot return NULL\",\n" " cfish_Obj_get_class_name((cfish_Obj*)vself),\n" " meth_name);\n" " }\n" " return retval;\n" "}\n" "\n" "%s" "\n" "void\n" "%sbootstrap_perl() {\n" " dTHX;\n" " %sbootstrap_parcel();\n" "\n" "%s" "}\n" "\n" "%s"; char *content = CFCUtil_sprintf(pattern, self->c_header, privacy_sym, prefix, includes, cb_defs, prefix, prefix, alias_adds, self->c_footer); const char *src_dest = CFCHierarchy_get_source_dest(self->hierarchy); char *host_c_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%sperl.c", src_dest, prefix); CFCUtil_write_file(host_c_path, content, strlen(content)); FREEMEM(host_c_path); FREEMEM(content); FREEMEM(alias_adds); FREEMEM(cb_defs); FREEMEM(includes); FREEMEM(ordered); }
static void S_write_boot_c(CFCPerl *self) { CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); CFCParcel **parcels = CFCParcel_all_parcels(); char *pound_includes = CFCUtil_strdup(""); char *bootstrap_code = CFCUtil_strdup(""); char *alias_adds = CFCUtil_strdup(""); char *isa_pushes = CFCUtil_strdup(""); for (size_t i = 0; parcels[i]; ++i) { if (!CFCParcel_included(parcels[i])) { const char *prefix = CFCParcel_get_prefix(parcels[i]); bootstrap_code = CFCUtil_cat(bootstrap_code, " ", prefix, "bootstrap_parcel();\n", NULL); } } for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; if (CFCClass_included(klass)) { continue; } const char *class_name = CFCClass_get_class_name(klass); const char *include_h = CFCClass_include_h(klass); pound_includes = CFCUtil_cat(pound_includes, "#include \"", include_h, "\"\n", NULL); if (CFCClass_inert(klass)) { continue; } // Add aliases for selected KinoSearch classes which allow old indexes // to be read. CFCPerlClass *class_binding = CFCPerlClass_singleton(class_name); if (class_binding) { const char *vtable_var = CFCClass_full_vtable_var(klass); const char **aliases = CFCPerlClass_get_class_aliases(class_binding); for (size_t j = 0; aliases[j] != NULL; j++) { const char *alias = aliases[j]; size_t alias_len = strlen(alias); const char pattern[] = " cfish_VTable_add_alias_to_registry(" "%s, \"%s\", %u);\n"; char *alias_add = CFCUtil_sprintf(pattern, vtable_var, alias, (unsigned)alias_len); alias_adds = CFCUtil_cat(alias_adds, alias_add, NULL); FREEMEM(alias_add); } char *metadata_code = CFCPerlClass_method_metadata_code(class_binding); alias_adds = CFCUtil_cat(alias_adds, metadata_code, NULL); FREEMEM(metadata_code); } CFCClass *parent = CFCClass_get_parent(klass); if (parent) { const char *parent_class_name = CFCClass_get_class_name(parent); isa_pushes = CFCUtil_cat(isa_pushes, " isa = get_av(\"", class_name, "::ISA\", 1);\n", NULL); isa_pushes = CFCUtil_cat(isa_pushes, " av_push(isa, newSVpv(\"", parent_class_name, "\", 0));\n", NULL); } } const char pattern[] = "%s\n" "\n" "#include \"cfish_parcel.h\"\n" "#include \"EXTERN.h\"\n" "#include \"perl.h\"\n" "#include \"XSUB.h\"\n" "#include \"boot.h\"\n" "#include \"Clownfish/String.h\"\n" "#include \"Clownfish/VTable.h\"\n" "%s\n" "\n" "void\n" "%s() {\n" "%s" "\n" "%s" "\n" " AV *isa;\n" "%s" "}\n" "\n" "%s\n" "\n"; char *content = CFCUtil_sprintf(pattern, self->header, pound_includes, self->boot_func, bootstrap_code, alias_adds, isa_pushes, self->footer); const char *src_dest = CFCHierarchy_get_source_dest(self->hierarchy); char *boot_c_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "boot.c", src_dest); CFCUtil_write_file(boot_c_path, content, strlen(content)); FREEMEM(boot_c_path); FREEMEM(content); FREEMEM(isa_pushes); FREEMEM(alias_adds); FREEMEM(bootstrap_code); FREEMEM(pound_includes); FREEMEM(parcels); FREEMEM(ordered); }