void CFCPerlTypeMap_write_xs_typemap(CFCHierarchy *hierarchy) { CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy); char *start = CFCUtil_strdup(""); char *input = CFCUtil_strdup(""); char *output = CFCUtil_strdup(""); for (int i = 0; classes[i] != NULL; i++) { CFCClass *klass = classes[i]; if (CFCClass_included(klass)) { continue; } const char *full_struct_sym = CFCClass_full_struct_sym(klass); const char *vtable_var = CFCClass_full_vtable_var(klass); start = CFCUtil_cat(start, full_struct_sym, "*\t", vtable_var, "_\n", NULL); input = CFCUtil_cat(input, vtable_var, "_\n" " $var = (", full_struct_sym, "*)XSBind_sv_to_cfish_obj($arg, ", vtable_var, ", NULL);\n\n", NULL); output = CFCUtil_cat(output, vtable_var, "_\n" " $arg = (SV*)Cfish_Obj_To_Host((cfish_Obj*)$var);\n" " CFISH_DECREF($var);\n" "\n", NULL); } char *content = CFCUtil_strdup(""); content = CFCUtil_cat(content, typemap_start, start, "\n\n", typemap_input, input, "\n\n", typemap_output, output, "\n\n", NULL); CFCUtil_write_if_changed("typemap", content, strlen(content)); FREEMEM(content); FREEMEM(output); FREEMEM(input); FREEMEM(start); FREEMEM(classes); }
static void S_add_load_method(CFCClass *klass) { CFCMethod *method = S_make_method_obj(klass, "Load"); CFCClass_add_method(klass, method); CFCBase_decref((CFCBase*)method); const char *full_func_sym = CFCMethod_implementing_func_sym(method); const char *full_struct = CFCClass_full_struct_sym(klass); const char *vtable_var = CFCClass_full_vtable_var(klass); CFCClass *parent = CFCClass_get_parent(klass); const char *prefix = CFCClass_get_prefix(klass); const char *class_cnick = CFCClass_get_cnick(klass); char buf[BUF_SIZE]; if (parent && CFCClass_has_attribute(parent, "dumpable")) { char *full_typedef = CFCMethod_full_typedef(method, klass); char *full_meth = CFCMethod_full_method_sym(method, klass); const char pattern[] = "cfish_Obj*\n" "%s(%s *self, cfish_Obj *dump)\n" "{\n" " cfish_Hash *source = (cfish_Hash*)CFISH_CERTIFY(dump, CFISH_HASH);\n" " %s super_load = CFISH_SUPER_METHOD_PTR(%s, %s);\n" " %s *loaded = (%s*)super_load(self, dump);\n" " %sIVARS *ivars = %s%s_IVARS(loaded);\n"; char *autocode = CFCUtil_sprintf(pattern, full_func_sym, full_struct, full_typedef, vtable_var, full_meth, full_struct, full_struct, full_struct, prefix, class_cnick); CFCClass_append_autocode(klass, autocode); FREEMEM(full_meth); FREEMEM(full_typedef); FREEMEM(autocode); CFCVariable **fresh = CFCClass_fresh_member_vars(klass); for (size_t i = 0; fresh[i] != NULL; i++) { S_process_load_member(klass, fresh[i], buf, BUF_SIZE); } FREEMEM(fresh); } else { const char pattern[] = "cfish_Obj*\n" "%s(%s *self, cfish_Obj *dump)\n" "{\n" " cfish_Hash *source = (cfish_Hash*)CFISH_CERTIFY(dump, CFISH_HASH);\n" " cfish_CharBuf *class_name = (cfish_CharBuf*)CFISH_CERTIFY(\n" " Cfish_Hash_Fetch_Str(source, \"_class\", 6), CFISH_CHARBUF);\n" " cfish_VTable *vtable = cfish_VTable_singleton(class_name, NULL);\n" " %s *loaded = (%s*)Cfish_VTable_Make_Obj(vtable);\n" " %sIVARS *ivars = %s%s_IVARS(loaded);\n" " CHY_UNUSED_VAR(self);\n"; char *autocode = CFCUtil_sprintf(pattern, full_func_sym, full_struct, full_struct, full_struct, full_struct, prefix, class_cnick); CFCClass_append_autocode(klass, autocode); FREEMEM(autocode); CFCVariable **members = CFCClass_member_vars(klass); for (size_t i = 0; members[i] != NULL; i++) { S_process_load_member(klass, members[i], buf, BUF_SIZE); } } CFCClass_append_autocode(klass, " return (cfish_Obj*)loaded;\n}\n\n"); }
static void S_add_dump_method(CFCClass *klass) { CFCMethod *method = S_make_method_obj(klass, "Dump"); CFCClass_add_method(klass, method); CFCBase_decref((CFCBase*)method); const char *full_func_sym = CFCMethod_implementing_func_sym(method); const char *full_struct = CFCClass_full_struct_sym(klass); const char *vtable_var = CFCClass_full_vtable_var(klass); const char *prefix = CFCClass_get_prefix(klass); const char *class_cnick = CFCClass_get_cnick(klass); CFCClass *parent = CFCClass_get_parent(klass); char buf[BUF_SIZE]; if (parent && CFCClass_has_attribute(parent, "dumpable")) { char *full_typedef = CFCMethod_full_typedef(method, klass); char *full_meth = CFCMethod_full_method_sym(method, klass); const char pattern[] = "cfish_Obj*\n" "%s(%s *self)\n" "{\n" " %sIVARS *ivars = %s%s_IVARS(self);\n" " %s super_dump = CFISH_SUPER_METHOD_PTR(%s, %s);\n" " cfish_Hash *dump = (cfish_Hash*)super_dump(self);\n"; char *autocode = CFCUtil_sprintf(pattern, full_func_sym, full_struct, full_struct, prefix, class_cnick, full_typedef, vtable_var, full_meth); CFCClass_append_autocode(klass, autocode); FREEMEM(full_meth); FREEMEM(full_typedef); FREEMEM(autocode); CFCVariable **fresh = CFCClass_fresh_member_vars(klass); for (size_t i = 0; fresh[i] != NULL; i++) { S_process_dump_member(klass, fresh[i], buf, BUF_SIZE); } FREEMEM(fresh); } else { const char pattern[] = "cfish_Obj*\n" "%s(%s *self)\n" "{\n" " %sIVARS *ivars = %s%s_IVARS(self);\n" " cfish_Hash *dump = cfish_Hash_new(0);\n" " Cfish_Hash_Store_Str(dump, \"_class\", 6,\n" " (cfish_Obj*)Cfish_CB_Clone(Cfish_Obj_Get_Class_Name((cfish_Obj*)self)));\n"; char *autocode = CFCUtil_sprintf(pattern, full_func_sym, full_struct, full_struct, prefix, class_cnick); CFCClass_append_autocode(klass, autocode); FREEMEM(autocode); CFCVariable **members = CFCClass_member_vars(klass); for (size_t i = 0; members[i] != NULL; i++) { S_process_dump_member(klass, members[i], buf, BUF_SIZE); } } CFCClass_append_autocode(klass, " return (cfish_Obj*)dump;\n}\n\n"); }
static char* S_xsub_body(CFCPerlMethod *self) { CFCMethod *method = self->method; CFCParamList *param_list = CFCMethod_get_param_list(method); CFCVariable **arg_vars = CFCParamList_get_variables(param_list); const char *name_list = CFCParamList_name_list(param_list); char *body = CFCUtil_strdup(""); CFCParcel *parcel = CFCMethod_get_parcel(method); const char *class_name = CFCMethod_get_class_name(method); CFCClass *klass = CFCClass_fetch_singleton(parcel, class_name); if (!klass) { CFCUtil_die("Can't find a CFCClass for '%s'", class_name); } // Extract the method function pointer. char *full_typedef = CFCMethod_full_typedef(method, klass); char *full_meth = CFCMethod_full_method_sym(method, klass); char *method_ptr = CFCUtil_sprintf("%s method = CFISH_METHOD_PTR(%s, %s);\n ", full_typedef, CFCClass_full_vtable_var(klass), full_meth); body = CFCUtil_cat(body, method_ptr, NULL); FREEMEM(full_typedef); FREEMEM(full_meth); FREEMEM(method_ptr); // Compensate for functions which eat refcounts. for (int i = 0; arg_vars[i] != NULL; i++) { CFCVariable *var = arg_vars[i]; CFCType *type = CFCVariable_get_type(var); if (CFCType_is_object(type) && CFCType_decremented(type)) { body = CFCUtil_cat(body, "CFISH_INCREF(", CFCVariable_micro_sym(var), ");\n ", NULL); } } if (CFCType_is_void(CFCMethod_get_return_type(method))) { // Invoke method in void context. body = CFCUtil_cat(body, "method(", name_list, ");\n XSRETURN(0);", NULL); } else { // Return a value for method invoked in a scalar context. CFCType *return_type = CFCMethod_get_return_type(method); const char *type_str = CFCType_to_c(return_type); char *assignment = CFCPerlTypeMap_to_perl(return_type, "retval"); if (!assignment) { CFCUtil_die("Can't find typemap for '%s'", type_str); } body = CFCUtil_cat(body, type_str, " retval = method(", name_list, ");\n ST(0) = ", assignment, ";", NULL); if (CFCType_is_object(return_type) && CFCType_incremented(return_type) ) { body = CFCUtil_cat(body, "\n CFISH_DECREF(retval);", NULL); } body = CFCUtil_cat(body, "\n sv_2mortal( ST(0) );\n XSRETURN(1);", NULL); FREEMEM(assignment); } return body; }
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); }