char* CFCGoClass_boilerplate_funcs(CFCGoClass *self) { char *content = NULL; if (!self->client) { CFCUtil_die("Can't find class for %s", self->class_name); } else if (CFCClass_inert(self->client)) { content = CFCUtil_strdup(""); } else { const char *clownfish_dot = CFCParcel_is_cfish(self->parcel) ? "" : "clownfish."; const char *short_struct = CFCClass_get_struct_sym(self->client); char pattern[] = "func WRAP%s(ptr unsafe.Pointer) %s {\n" "\tobj := &%sIMP{}\n" "\tobj.INITOBJ(ptr)\n" "\treturn obj\n" "}\n" "\n" "func WRAP%sASOBJ(ptr unsafe.Pointer) %sObj {\n" "\treturn WRAP%s(ptr)\n" "}\n" ; content = CFCUtil_sprintf(pattern, short_struct, short_struct, short_struct, short_struct, clownfish_dot, short_struct); } return content; }
char* CFCGoClass_gen_wrap_func_reg(CFCGoClass *self) { if (CFCClass_inert(self->client)) { return CFCUtil_strdup(""); } char pattern[] = "\t\tunsafe.Pointer(C.%s): WRAP%sASOBJ,\n"; const char *short_struct = CFCClass_get_struct_sym(self->client); const char *class_var = CFCClass_full_class_var(self->client); return CFCUtil_sprintf(pattern, class_var, short_struct); }
static char* S_gen_type_linkups(CFCPython *self, CFCParcel *parcel, CFCClass **ordered) { char *handles = CFCUtil_strdup(""); char *py_types = CFCUtil_strdup(""); int num_items = 0; for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; if (CFCClass_included(klass) || CFCClass_inert(klass)) { continue; } const char *class_var = CFCClass_full_class_var(klass); const char *struct_sym = CFCClass_get_struct_sym(klass); char *handles_temp = CFCUtil_sprintf("%s handles[%d] = &%s;\n", handles, num_items, class_var); char *py_types_temp = CFCUtil_sprintf("%s py_types[%d] = &%s_pytype_struct;\n", py_types, num_items, struct_sym); FREEMEM(handles); FREEMEM(py_types); handles = handles_temp; py_types = py_types_temp; num_items++; } char pattern[] = "static void\n" "S_link_py_types(void) {\n" " const int num_items = %d;\n" " size_t handles_size = num_items * sizeof(cfish_Class**);\n" " size_t py_types_size = num_items * sizeof(PyTypeObject*);\n" " cfish_Class ***handles = (cfish_Class***)CFISH_MALLOCATE(handles_size);\n" " PyTypeObject **py_types = (PyTypeObject**)CFISH_MALLOCATE(py_types_size);\n" "%s\n" "%s\n" " CFBind_assoc_py_types(handles, py_types, num_items);\n" " CFISH_FREEMEM(handles);\n" " CFISH_FREEMEM(py_types);\n" "}\n" ; char *content = CFCUtil_sprintf(pattern, num_items, handles, py_types); FREEMEM(handles); FREEMEM(py_types); return content; }
char* CFCGoClass_go_typing(CFCGoClass *self) { char *content = NULL; if (!self->client) { CFCUtil_die("Can't find class for %s", self->class_name); } else if (CFCClass_inert(self->client)) { content = CFCUtil_strdup(""); } else { const char *short_struct = CFCClass_get_struct_sym(self->client); CFCClass *parent = CFCClass_get_parent(self->client); char *parent_type_str = NULL; if (parent) { const char *parent_struct = CFCClass_get_struct_sym(parent); CFCParcel *parent_parcel = CFCClass_get_parcel(parent); if (parent_parcel == self->parcel) { parent_type_str = CFCUtil_strdup(parent_struct); } else { char *parent_package = CFCGoTypeMap_go_short_package(parent_parcel); parent_type_str = CFCUtil_sprintf("%s.%s", parent_package, parent_struct); FREEMEM(parent_package); } } char *go_struct_def; if (parent && !self->suppress_struct) { go_struct_def = CFCUtil_sprintf("type %sIMP struct {\n\t%sIMP\n}\n", short_struct, parent_type_str); } else { go_struct_def = CFCUtil_strdup(""); } char *parent_iface; if (parent) { parent_iface = CFCUtil_sprintf("\t%s\n", parent_type_str); } else { parent_iface = CFCUtil_strdup(""); } char *novel_iface = CFCUtil_strdup(""); S_lazy_init_method_bindings(self); for (int i = 0; self->method_bindings[i] != NULL; i++) { CFCGoMethod *meth_binding = self->method_bindings[i]; CFCMethod *method = CFCGoMethod_get_client(meth_binding); if (method) { if (!CFCMethod_novel(method)) { continue; } const char *sym = CFCMethod_get_name(method); if (!CFCClass_fresh_method(self->client, sym)) { continue; } } const char *sig = CFCGoMethod_get_sig(meth_binding, self->client); novel_iface = CFCUtil_cat(novel_iface, "\t", sig, "\n", NULL); } char pattern[] = "type %s interface {\n" "%s" "%s" "}\n" "\n" "%s" ; content = CFCUtil_sprintf(pattern, short_struct, parent_iface, novel_iface, go_struct_def); FREEMEM(parent_type_str); FREEMEM(go_struct_def); FREEMEM(parent_iface); } return content; }
/* Write the "parcel.h" header file, which contains common symbols needed by * all classes, plus typedefs for all class structs. */ static void S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) { CFCHierarchy *hierarchy = self->hierarchy; const char *prefix = CFCParcel_get_prefix(parcel); const char *PREFIX = CFCParcel_get_PREFIX(parcel); const char *privacy_sym = CFCParcel_get_privacy_sym(parcel); // Declare object structs and class singletons for all instantiable // classes. char *typedefs = CFCUtil_strdup(""); char *class_decls = CFCUtil_strdup(""); CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy); for (int i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; const char *class_prefix = CFCClass_get_prefix(klass); if (strcmp(class_prefix, prefix) != 0) { continue; } if (!CFCClass_inert(klass)) { const char *full_struct = CFCClass_full_struct_sym(klass); typedefs = CFCUtil_cat(typedefs, "typedef struct ", full_struct, " ", full_struct, ";\n", NULL); const char *class_var = CFCClass_full_class_var(klass); class_decls = CFCUtil_cat(class_decls, "extern ", PREFIX, "VISIBLE cfish_Class *", class_var, ";\n", NULL); } } FREEMEM(ordered); // Special includes and macros for Clownfish parcel. const char *cfish_includes = "#include <stdarg.h>\n" "#include <stddef.h>\n" "\n" "#include \"cfish_platform.h\"\n" "#include \"cfish_hostdefs.h\"\n"; // Special definitions for Clownfish parcel. const char *cfish_defs_1 = "#define CFISH_UNUSED_VAR(var) ((void)var)\n" "#define CFISH_UNREACHABLE_RETURN(type) return (type)0\n" "\n" "/* Generic method pointer.\n" " */\n" "typedef void\n" "(*cfish_method_t)(const void *vself);\n" "\n" "/* Access the function pointer for a given method from the class.\n" " */\n" "#define CFISH_METHOD_PTR(_class, _full_meth) \\\n" " ((_full_meth ## _t)cfish_method(_class, _full_meth ## _OFFSET))\n" "\n" "static CFISH_INLINE cfish_method_t\n" "cfish_method(const void *klass, uint32_t offset) {\n" " union { char *cptr; cfish_method_t *fptr; } ptr;\n" " ptr.cptr = (char*)klass + offset;\n" " return ptr.fptr[0];\n" "}\n" "\n" "typedef struct cfish_Dummy {\n" " CFISH_OBJ_HEAD\n" " void *klass;\n" "} cfish_Dummy;\n" "\n" "/* Access the function pointer for a given method from the object.\n" " */\n" "static CFISH_INLINE cfish_method_t\n" "cfish_obj_method(const void *object, uint32_t offset) {\n" " cfish_Dummy *dummy = (cfish_Dummy*)object;\n" " return cfish_method(dummy->klass, offset);\n" "}\n" "\n" "/* Access the function pointer for the given method in the\n" " * superclass. */\n" "#define CFISH_SUPER_METHOD_PTR(_class, _full_meth) \\\n" " ((_full_meth ## _t)cfish_super_method(_class, \\\n" " _full_meth ## _OFFSET))\n" "\n" "extern CFISH_VISIBLE uint32_t cfish_Class_offset_of_parent;\n" "static CFISH_INLINE cfish_method_t\n" "cfish_super_method(const void *klass, uint32_t offset) {\n" " char *class_as_char = (char*)klass;\n" " cfish_Class **parent_ptr\n" " = (cfish_Class**)(class_as_char + cfish_Class_offset_of_parent);\n" " return cfish_method(*parent_ptr, offset);\n" "}\n" "\n" "typedef void\n" "(*cfish_destroy_t)(void *vself);\n" "extern CFISH_VISIBLE uint32_t CFISH_Obj_Destroy_OFFSET;\n" "\n" "/** Invoke the [](.Destroy) method found in `klass` on\n" " * `self`.\n" " *\n" " * TODO: Eliminate this function if we can arrive at a proper SUPER syntax.\n" " */\n" "static CFISH_INLINE void\n" "cfish_super_destroy(void *vself, cfish_Class *klass) {\n" " cfish_Obj *self = (cfish_Obj*)vself;\n" " if (self != NULL) {\n" " cfish_destroy_t super_destroy\n" " = (cfish_destroy_t)cfish_super_method(klass, CFISH_Obj_Destroy_OFFSET);\n" " super_destroy(self);\n" " }\n" "}\n" "\n" "#define CFISH_SUPER_DESTROY(_self, _class) \\\n" " cfish_super_destroy(_self, _class)\n" "\n" "extern CFISH_VISIBLE cfish_Obj*\n" "cfish_inc_refcount(void *vself);\n" "\n" "/** NULL-safe invocation invocation of `cfish_inc_refcount`.\n" " *\n" " * @return NULL if `self` is NULL, otherwise the return value\n" " * of `cfish_inc_refcount`.\n" " */\n" "static CFISH_INLINE cfish_Obj*\n" "cfish_incref(void *vself) {\n" " if (vself != NULL) { return cfish_inc_refcount(vself); }\n" " else { return NULL; }\n" "}\n" "\n" "#define CFISH_INCREF(_self) cfish_incref(_self)\n" "#define CFISH_INCREF_NN(_self) cfish_inc_refcount(_self)\n" "\n" "extern CFISH_VISIBLE uint32_t\n" "cfish_dec_refcount(void *vself);\n" "\n" "/** NULL-safe invocation of `cfish_dec_refcount`.\n" " *\n" " * @return NULL if `self` is NULL, otherwise the return value\n" " * of `cfish_dec_refcount`.\n" " */\n" "static CFISH_INLINE uint32_t\n" "cfish_decref(void *vself) {\n" " if (vself != NULL) { return cfish_dec_refcount(vself); }\n" " else { return 0; }\n" "}\n" "\n" "#define CFISH_DECREF(_self) cfish_decref(_self)\n" "#define CFISH_DECREF_NN(_self) cfish_dec_refcount(_self)\n" "\n" "extern CFISH_VISIBLE uint32_t\n" "cfish_get_refcount(void *vself);\n" "\n" "#define CFISH_REFCOUNT_NN(_self) \\\n" " cfish_get_refcount(_self)\n" "\n" "/* Flags for internal use. */\n" "#define CFISH_fREFCOUNTSPECIAL 0x00000001\n" "#define CFISH_fFINAL 0x00000002\n" ; const char *cfish_defs_2 = "#ifdef CFISH_USE_SHORT_NAMES\n" " #define UNUSED_VAR CFISH_UNUSED_VAR\n" " #define UNREACHABLE_RETURN CFISH_UNREACHABLE_RETURN\n" " #define METHOD_PTR CFISH_METHOD_PTR\n" " #define SUPER_METHOD_PTR CFISH_SUPER_METHOD_PTR\n" " #define SUPER_DESTROY(_self, _class) CFISH_SUPER_DESTROY(_self, _class)\n" " #define INCREF(_self) CFISH_INCREF(_self)\n" " #define INCREF_NN(_self) CFISH_INCREF_NN(_self)\n" " #define DECREF(_self) CFISH_DECREF(_self)\n" " #define DECREF_NN(_self) CFISH_DECREF_NN(_self)\n" " #define REFCOUNT_NN(_self) CFISH_REFCOUNT_NN(_self)\n" "#endif\n" "\n"; char *extra_defs; char *extra_includes; if (CFCParcel_is_cfish(parcel)) { const char *spec_typedefs = CFCBindSpecs_get_typedefs(); extra_defs = CFCUtil_sprintf("%s%s%s", cfish_defs_1, spec_typedefs, cfish_defs_2); extra_includes = CFCUtil_strdup(cfish_includes); } else { extra_defs = CFCUtil_strdup(""); extra_includes = CFCUtil_strdup(""); // Include parcel.h of prerequisite parcels. CFCParcel **prereq_parcels = CFCParcel_prereq_parcels(parcel); for (size_t i = 0; prereq_parcels[i]; ++i) { const char *prereq_prefix = CFCParcel_get_prefix(prereq_parcels[i]); extra_includes = CFCUtil_cat(extra_includes, "#include \"", prereq_prefix, "parcel.h\"\n", NULL); } FREEMEM(prereq_parcels); } const char pattern[] = "%s\n" "#ifndef CFISH_%sPARCEL_H\n" "#define CFISH_%sPARCEL_H 1\n" "\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n" "\n" "%s" // Extra includes. "\n" "#ifdef %s\n" " #define %sVISIBLE CFISH_EXPORT\n" "#else\n" " #define %sVISIBLE CFISH_IMPORT\n" "#endif\n" "\n" "%s" // Typedefs. "\n" "%s" // Class singletons. "\n" "%s" // Extra definitions. "%sVISIBLE void\n" "%sbootstrap_inheritance();\n" "\n" "%sVISIBLE void\n" "%sbootstrap_parcel();\n" "\n" "void\n" "%sinit_parcel();\n" "\n" "#ifdef __cplusplus\n" "}\n" "#endif\n" "\n" "#endif /* CFISH_%sPARCEL_H */\n" "\n" "%s\n" "\n"; char *file_content = CFCUtil_sprintf(pattern, self->c_header, PREFIX, PREFIX, extra_includes, privacy_sym, PREFIX, PREFIX, typedefs, class_decls, extra_defs, PREFIX, prefix, PREFIX, prefix, prefix, PREFIX, self->c_footer); // Unlink then write file. const char *inc_dest = CFCHierarchy_get_include_dest(hierarchy); char *filepath = CFCUtil_sprintf("%s" CHY_DIR_SEP "%sparcel.h", inc_dest, prefix); remove(filepath); CFCUtil_write_file(filepath, file_content, strlen(file_content)); FREEMEM(filepath); FREEMEM(typedefs); FREEMEM(class_decls); FREEMEM(extra_defs); FREEMEM(extra_includes); FREEMEM(file_content); }
static void S_write_module_file(CFCPython *self, CFCParcel *parcel, const char *dest) { const char *parcel_name = CFCParcel_get_name(parcel); char *pymod_name = CFCUtil_strdup(parcel_name); // TODO: Stop lowercasing when parcels are restricted to lowercase. for (int i = 0; pymod_name[i] != '\0'; i++) { pymod_name[i] = tolower(pymod_name[i]); } const char *last_dot = strrchr(pymod_name, '.'); const char *last_component = last_dot != NULL ? last_dot + 1 : pymod_name; char *helper_mod_name = CFCUtil_sprintf("%s._%s", pymod_name, last_component); for (int i = 0; helper_mod_name[i] != '\0'; i++) { helper_mod_name[i] = tolower(helper_mod_name[i]); } CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); CFCParcel **parcels = CFCParcel_all_parcels(); char *callbacks = S_gen_callbacks(self, parcel, ordered); char *type_linkups = S_gen_type_linkups(self, parcel, ordered); char *pound_includes = CFCUtil_strdup(""); char *class_bindings = S_gen_class_bindings(self, parcel, pymod_name, ordered); char *parcel_boots = CFCUtil_strdup(""); char *pytype_ready_calls = CFCUtil_strdup(""); char *module_adds = CFCUtil_strdup(""); // Add parcel bootstrapping calls. for (size_t i = 0; parcels[i]; ++i) { if (!CFCParcel_included(parcels[i])) { const char *prefix = CFCParcel_get_prefix(parcels[i]); parcel_boots = CFCUtil_cat(parcel_boots, " ", 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 *struct_sym = CFCClass_get_struct_sym(klass); const char *include_h = CFCClass_include_h(klass); pound_includes = CFCUtil_cat(pound_includes, "#include \"", include_h, "\"\n", NULL); // The PyType_Ready invocations for instantiable classes are handled // via bootstrapping of Clownfish Class objects. Since inert classes // do not at present have Class objects, we need to handle their // PyType_Ready calls independently. if (CFCClass_inert(klass)) { pytype_ready_calls = CFCUtil_cat(pytype_ready_calls, " if (PyType_Ready(&", struct_sym, "_pytype_struct) < 0) { return NULL; }\n", NULL); } module_adds = CFCUtil_cat(module_adds, " PyModule_AddObject(module, \"", struct_sym, "\", (PyObject*)&", struct_sym, "_pytype_struct);\n", NULL); } const char pattern[] = "%s\n" "\n" "#include \"Python.h\"\n" "#include \"cfish_parcel.h\"\n" "#include \"CFBind.h\"\n" "%s\n" "\n" "%s\n" // callbacks "\n" "static PyModuleDef module_def = {\n" " PyModuleDef_HEAD_INIT,\n" " \"%s\",\n" // module name " NULL,\n" // docstring " -1,\n" " NULL, NULL, NULL, NULL, NULL\n" "};\n" "\n" "%s" // class bindings "\n" "%s" // S_link_py_types function "\n" "PyMODINIT_FUNC\n" "PyInit__%s(void) {\n" " cfish_Class_bootstrap_hook1 = CFBind_class_bootstrap_hook1;\n" "\n" "%s\n" // PyType_Ready calls "\n" " S_link_py_types();\n" "\n" "%s\n" // parcel boots "\n" " PyObject *module = PyModule_Create(&module_def);\n" "%s\n" // Add types to module "\n" " return module;\n" "}\n" "\n" "%s\n" "\n"; char *content = CFCUtil_sprintf(pattern, self->header, pound_includes, callbacks, helper_mod_name, class_bindings, type_linkups, last_component, pytype_ready_calls, parcel_boots, module_adds, self->footer); char *filepath = CFCUtil_sprintf("%s" CHY_DIR_SEP "_%s.c", dest, last_component); CFCUtil_write_if_changed(filepath, content, strlen(content)); FREEMEM(filepath); FREEMEM(content); FREEMEM(module_adds); FREEMEM(pytype_ready_calls); FREEMEM(parcel_boots); FREEMEM(class_bindings); FREEMEM(helper_mod_name); FREEMEM(pymod_name); FREEMEM(pound_includes); FREEMEM(type_linkups); FREEMEM(callbacks); FREEMEM(ordered); }
static char* S_gen_callbacks(CFCPython *self, CFCParcel *parcel, CFCClass **ordered) { char *callbacks = CFCUtil_strdup(""); // Generate implementation files containing callback definitions. for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; if (CFCClass_included(klass) || CFCClass_inert(klass) //|| CFCClass_get_parcel(klass) != parcel ) { continue; } 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 = CFCPyMethod_callback_def(method, klass); callbacks = CFCUtil_cat(callbacks, cb_def, "\n", NULL); FREEMEM(cb_def); } } } static const char helpers[] = "static PyObject*\n" "S_pack_tuple(int num_args, ...) {\n" " PyObject *tuple = PyTuple_New(num_args);\n" " va_list args;\n" " va_start(args, num_args);\n" " for (int i = 0; i < num_args; i++) {\n" " PyObject *arg = va_arg(args, PyObject*);\n" " PyTuple_SET_ITEM(tuple, i, arg);\n" " }\n" " va_end(args);\n" " return tuple;\n" "}\n" "#define CFBIND_TRY(routine) \\\n" " do { \\\n" " jmp_buf env; \\\n" " jmp_buf *prev_env = CFBind_swap_env(&env); \\\n" " if (!setjmp(env)) { \\\n" " routine; \\\n" " } \\\n" " CFBind_swap_env(prev_env); \\\n" " } while (0)\n" "\n" "static PyObject*\n" "S_call_pymeth(PyObject *self, const char *meth_name, PyObject *args,\n" " const char *file, int line, const char *func) {\n" " PyObject *callable = PyObject_GetAttrString(self, meth_name);\n" " if (!PyCallable_Check(callable)) {\n" " cfish_String *mess\n" " = cfish_Err_make_mess(file, line, func, \"Attr '%s' not callable\",\n" " meth_name);\n" " cfish_Err_throw_mess(CFISH_ERR, mess);\n" " }\n" " PyObject *result = PyObject_CallObject(callable, args);\n" " Py_DECREF(args);\n" " if (result == NULL) {\n" " cfish_String *mess\n" " = cfish_Err_make_mess(file, line, func,\n" " \"Callback to '%s' failed\", meth_name);\n" " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" " }\n" " return result;\n" "}\n" "\n" "#define CALL_PYMETH_VOID(self, meth_name, args) \\\n" " S_call_pymeth_void(self, meth_name, args, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" "\n" "static void\n" "S_call_pymeth_void(PyObject *self, const char *meth_name, PyObject *args,\n" " const char *file, int line, const char *func) {\n" " PyObject *py_result\n" " = S_call_pymeth(self, meth_name, args, file, line, func);\n" " if (py_result == NULL) {\n" " cfish_String *mess\n" " = cfish_Err_make_mess(file, line, func, \"Call to %s failed\",\n" " meth_name);\n" " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" " }\n" " Py_DECREF(py_result);\n" "}\n" "\n" "#define CALL_PYMETH_BOOL(self, meth_name, args) \\\n" " S_call_pymeth_bool(self, meth_name, args, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" "\n" "static bool\n" "S_call_pymeth_bool(PyObject *self, const char *meth_name, PyObject *args,\n" " const char *file, int line, const char *func) {\n" " PyObject *py_result\n" " = S_call_pymeth(self, meth_name, args, file, line, func);\n" " int truthiness = py_result != NULL\n" " ? PyObject_IsTrue(py_result)\n" " : -1;\n" " if (truthiness == -1) {\n" " cfish_String *mess\n" " = cfish_Err_make_mess(file, line, func, \"Call to %s failed\",\n" " meth_name);\n" " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" " }\n" " Py_DECREF(py_result);\n" " return !!truthiness;\n" "}\n" "\n" "#define CALL_PYMETH_OBJ(self, meth_name, args, ret_class, nullable) \\\n" " S_call_pymeth_obj(self, meth_name, args, ret_class, nullable, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" "\n" "static cfish_Obj*\n" "S_call_pymeth_obj(PyObject *self, const char *meth_name,\n" " PyObject *args, cfish_Class *ret_class, bool nullable,\n" " const char *file, int line, const char *func) {\n" " PyObject *py_result\n" " = S_call_pymeth(self, meth_name, args, file, line, func);\n" " cfish_Obj *result = CFBind_py_to_cfish(py_result, ret_class);\n" " Py_DECREF(py_result);\n" " if (!nullable && result == NULL) {\n" " CFISH_THROW(CFISH_ERR, \"%s cannot return NULL\", meth_name);\n" " }\n" " else if (!cfish_Obj_is_a(result, ret_class)) {\n" " cfish_Class *result_class = cfish_Obj_get_class(result);\n" " CFISH_DECREF(result);\n" " CFISH_THROW(CFISH_ERR, \"%s returned %o instead of %o\", meth_name,\n" " CFISH_Class_Get_Name(result_class),\n" " CFISH_Class_Get_Name(ret_class));\n" " }\n" " return result;\n" "}\n" "\n" "#define CALL_PYMETH_DOUBLE(self, meth_name, args) \\\n" " S_call_pymeth_f64(self, meth_name, args, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" "#define CALL_PYMETH_FLOAT(self, meth_name, args) \\\n" " ((float)S_call_pymeth_f64(self, meth_name, args, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "\n" "static double\n" "S_call_pymeth_f64(PyObject *self, const char *meth_name, PyObject *args,\n" " const char *file, int line, const char *func) {\n" " PyObject *py_result\n" " = S_call_pymeth(self, meth_name, args, file, line, func);\n" " PyErr_Clear();\n" " double result = PyFloat_AsDouble(py_result);\n" " if (PyErr_Occurred()) {\n" " cfish_String *mess\n" " = cfish_Err_make_mess(file, line, func,\n" " \"Converting result of '%s' to double failed\",\n" " meth_name);\n" " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" " }\n" " Py_DECREF(py_result);\n" " return result;\n" "}\n" "\n" "#define CALL_PYMETH_INT64_T(self, meth_name, args) \\\n" " S_call_pymeth_i64(self, meth_name, args, INT64_MAX, INT64_MIN, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" "#define CALL_PYMETH_INT32_T(self, meth_name, args) \\\n" " ((int32_t)S_call_pymeth_i64(self, meth_name, args, INT32_MAX, INT32_MIN, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_INT16_T(self, meth_name, args) \\\n" " ((int16_t)S_call_pymeth_i64(self, meth_name, args, INT16_MAX, INT16_MIN, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_INT8_T(self, meth_name, args) \\\n" " ((int8_t)S_call_pymeth_i64(self, meth_name, args, INT8_MAX, INT8_MIN, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_CHAR(self, meth_name, args) \\\n" " ((char)S_call_pymeth_i64(self, meth_name, args, CHAR_MAX, CHAR_MIN, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_SHORT(self, meth_name, args) \\\n" " ((short)S_call_pymeth_i64(self, meth_name, args, SHRT_MAX, SHRT_MIN, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_INT(self, meth_name, args) \\\n" " ((int16_t)S_call_pymeth_i64(self, meth_name, args, INT_MAX, INT_MIN, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_LONG(self, meth_name, args) \\\n" " ((int16_t)S_call_pymeth_i64(self, meth_name, args, LONG_MAX, LONG_MIN, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "\n" "static int64_t\n" "S_call_pymeth_i64(PyObject *self, const char *meth_name, PyObject *args,\n" " int64_t max, int64_t min,\n" " const char *file, int line, const char *func) {\n" " PyObject *py_result\n" " = S_call_pymeth(self, meth_name, args, file, line, func);\n" " PyErr_Clear();\n" " int64_t result = PyLong_AsLongLong(py_result);\n" " if (PyErr_Occurred() || result > max || result < min) {\n" " cfish_String *mess\n" " = cfish_Err_make_mess(file, line, func,\n" " \"Converting result of '%s' to int64_t failed\",\n" " meth_name);\n" " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" " }\n" " Py_DECREF(py_result);\n" " return result;\n" "}\n" "\n" "#define CALL_PYMETH_UINT64_T(self, meth_name, args) \\\n" " S_call_pymeth_u64(self, meth_name, args, UINT64_MAX, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" "#define CALL_PYMETH_UINT32_T(self, meth_name, args) \\\n" " ((uint32_t)S_call_pymeth_u64(self, meth_name, args, UINT32_MAX, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_UINT16_T(self, meth_name, args) \\\n" " ((uint32_t)S_call_pymeth_u64(self, meth_name, args, UINT16_MAX, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_UINT8_T(self, meth_name, args) \\\n" " ((uint32_t)S_call_pymeth_u64(self, meth_name, args, UINT8_MAX, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO))\n" "#define CALL_PYMETH_SIZE_T(self, meth_name, args) \\\n" " S_call_pymeth_u64(self, meth_name, args, SIZE_MAX, \\\n" " __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)\n" "\n" "static uint64_t\n" "S_call_pymeth_u64(PyObject *self, const char *meth_name, PyObject *args,\n" " uint64_t max,\n" " const char *file, int line, const char *func) {\n" " PyObject *py_result\n" " = S_call_pymeth(self, meth_name, args, file, line, func);\n" " PyErr_Clear();\n" " uint64_t result = PyLong_AsUnsignedLongLong(py_result);\n" " if (PyErr_Occurred()) {\n" " cfish_String *mess\n" " = cfish_Err_make_mess(file, line, func,\n" " \"Converting result of '%s' to uint64_t failed\",\n" " meth_name);\n" " CFBind_reraise_pyerr(CFISH_ERR, mess);\n" " }\n" " Py_DECREF(py_result);\n" " return result;\n" "}\n" ; static const char pattern[] = "%s\n" "\n" "%s" ; char *content = CFCUtil_sprintf(pattern, helpers, callbacks); FREEMEM(callbacks); return content; }
void CFCPerl_write_bindings(CFCPerl *self, const char *boot_class, CFCParcel **parcels) { CFCUTIL_NULL_CHECK(boot_class); CFCUTIL_NULL_CHECK(parcels); CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); CFCPerlClass **registry = CFCPerlClass_registry(); char *privacy_syms = CFCUtil_strdup(""); char *includes = CFCUtil_strdup(""); char *generated_xs = CFCUtil_strdup(""); char *class_specs = CFCUtil_strdup(""); char *xsub_specs = CFCUtil_strdup(""); char *bootstrap_calls = CFCUtil_strdup(""); char *hand_rolled_xs = CFCUtil_strdup(""); for (size_t i = 0; parcels[i]; ++i) { CFCParcel *parcel = parcels[i]; // Set host_module_name for parcel. if (!CFCParcel_included(parcel) && CFCParcel_is_installed(parcel)) { CFCParcel_set_host_module_name(parcel, boot_class); } // Bake the parcel privacy defines into the XS, so it can be compiled // without any extra compiler flags. const char *privacy_sym = CFCParcel_get_privacy_sym(parcel); privacy_syms = CFCUtil_cat(privacy_syms, "#define ", privacy_sym, "\n", NULL); // Bootstrap calls. const char *prefix = CFCParcel_get_prefix(parcel); includes = CFCUtil_cat(includes, "#include \"", prefix, "perl.h\"\n", NULL); bootstrap_calls = CFCUtil_cat(bootstrap_calls, " ", prefix, "bootstrap_perl();\n", NULL); } for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; CFCParcel *parcel = CFCClass_get_parcel(klass); int found = false; for (size_t j = 0; parcels[j]; j++) { if (parcel == parcels[j]) { found = true; break; } } if (!found) { continue; } // Pound-includes for generated headers. const char *include_h = CFCClass_include_h(klass); includes = CFCUtil_cat(includes, "#include \"", include_h, "\"\n", NULL); if (CFCClass_inert(klass)) { continue; } int num_xsubs = 0; // Constructors. CFCPerlConstructor **constructors = CFCPerlClass_constructor_bindings(klass); for (size_t j = 0; constructors[j] != NULL; j++) { CFCPerlSub *xsub = (CFCPerlSub*)constructors[j]; // Add the XSUB function definition. char *xsub_def = CFCPerlConstructor_xsub_def(constructors[j], klass); generated_xs = CFCUtil_cat(generated_xs, xsub_def, "\n", NULL); FREEMEM(xsub_def); // Add XSUB initialization at boot. xsub_specs = S_add_xsub_spec(xsub_specs, xsub); num_xsubs += 1; CFCBase_decref((CFCBase*)constructors[j]); } FREEMEM(constructors); // Methods. CFCPerlMethod **methods = CFCPerlClass_method_bindings(klass); for (size_t j = 0; methods[j] != NULL; j++) { CFCPerlSub *xsub = (CFCPerlSub*)methods[j]; // Add the XSUB function definition. char *xsub_def = CFCPerlMethod_xsub_def(methods[j], klass); generated_xs = CFCUtil_cat(generated_xs, xsub_def, "\n", NULL); FREEMEM(xsub_def); // Add XSUB initialization at boot. xsub_specs = S_add_xsub_spec(xsub_specs, xsub); num_xsubs += 1; CFCBase_decref((CFCBase*)methods[j]); } FREEMEM(methods); // Append XSBind_ClassSpec entry. const char *class_name = CFCClass_get_name(klass); CFCClass *parent = CFCClass_get_parent(klass); char *parent_name; if (parent) { parent_name = CFCUtil_sprintf("\"%s\"", CFCClass_get_name(parent)); } else { parent_name = CFCUtil_strdup("NULL"); } char *class_spec = CFCUtil_sprintf("{ \"%s\", %s, %d }", class_name, parent_name, num_xsubs); const char *sep = class_specs[0] == '\0' ? "" : ",\n"; class_specs = CFCUtil_cat(class_specs, sep, " ", class_spec, NULL); FREEMEM(class_spec); FREEMEM(parent_name); } // Hand-rolled XS. for (size_t i = 0; registry[i] != NULL; i++) { CFCPerlClass *perl_class = registry[i]; CFCParcel *parcel = CFCPerlClass_get_parcel(perl_class); int found = false; for (size_t j = 0; parcels[j]; j++) { if (parcel == parcels[j]) { found = true; break; } } if (!found) { continue; } const char *xs = CFCPerlClass_get_xs_code(perl_class); hand_rolled_xs = CFCUtil_cat(hand_rolled_xs, xs, "\n", NULL); } const char pattern[] = "%s" // Header. "\n" "%s" // Privacy syms. "\n" "#include \"XSBind.h\"\n" "%s" // Includes. "\n" "#ifndef XS_INTERNAL\n" " #define XS_INTERNAL XS\n" "#endif\n" "\n" "%s" // Generated XS. "\n" "MODULE = %s PACKAGE = %s\n" // Boot class. "\n" "BOOT:\n" "{\n" " static const cfish_XSBind_ClassSpec class_specs[] = {\n" "%s\n" // Class specs. " };\n" " static const cfish_XSBind_XSubSpec xsub_specs[] = {\n" "%s\n" // XSUB specs. " };\n" " size_t num_classes\n" " = sizeof(class_specs) / sizeof(class_specs[0]);\n" " const char* file = __FILE__;\n" "\n" "%s" // Bootstrap calls. "\n" " cfish_XSBind_bootstrap(aTHX_ num_classes, class_specs,\n" " xsub_specs, file);\n" "}\n" "\n" "%s" // Hand-rolled XS. "\n" "%s"; // Footer char *contents = CFCUtil_sprintf(pattern, self->c_header, privacy_syms, includes, generated_xs, boot_class, boot_class, class_specs, xsub_specs, bootstrap_calls, hand_rolled_xs, self->c_footer); // Derive path to generated .xs file. char *xs_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.xs", self->lib_dir, boot_class); S_replace_double_colons(xs_path, CHY_DIR_SEP_CHAR); // Write out if there have been any changes. CFCUtil_write_if_changed(xs_path, contents, strlen(contents)); FREEMEM(xs_path); FREEMEM(contents); FREEMEM(hand_rolled_xs); FREEMEM(bootstrap_calls); FREEMEM(xsub_specs); FREEMEM(class_specs); FREEMEM(generated_xs); FREEMEM(includes); FREEMEM(privacy_syms); FREEMEM(ordered); }
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_callbacks_c(CFCPerl *self) { CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); static const char pattern[] = "%s" "\n" "#include \"XSBind.h\"\n" "#include \"callbacks.h\"\n" "\n" "static void\n" "S_finish_callback_void(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(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(const char *meth_name) {\n" " SV *return_sv = SI_do_callback_sv(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(const char *meth_name) {\n" " SV *return_sv = SI_do_callback_sv(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(void *vself, const char *meth_name,\n" " int nullable) {\n" " SV *return_sv = SI_do_callback_sv(meth_name);\n" " cfish_Obj *retval = XSBind_perl_to_cfish(return_sv);\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"; char *content = CFCUtil_sprintf(pattern, self->header); for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; if (CFCClass_inert(klass)) { continue; } 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); content = CFCUtil_cat(content, cb_def, "\n", NULL); FREEMEM(cb_def); } } FREEMEM(fresh_methods); } content = CFCUtil_cat(content, self->footer, NULL); // Write if changed. const char *src_dest = CFCHierarchy_get_source_dest(self->hierarchy); char *filepath = CFCUtil_sprintf("%s" CHY_DIR_SEP "callbacks.c", src_dest); CFCUtil_write_if_changed(filepath, content, strlen(content)); FREEMEM(filepath); FREEMEM(content); 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); }
void CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) { if (CFCClass_inert(klass)) { return; } const char *class_name = CFCClass_get_name(klass); const char *class_var = CFCClass_full_class_var(klass); const char *ivars_offset_name = CFCClass_full_ivars_offset(klass); const char *flags = CFCClass_final(klass) ? "cfish_ClassSpec_FINAL" : "0"; char *ivars_size = S_ivars_size(klass); char *parent_ptr = NULL; CFCClass *parent = CFCClass_get_parent(klass); if (!parent) { parent_ptr = CFCUtil_strdup("NULL"); } else { if (CFCClass_in_same_parcel(klass, parent)) { parent_ptr = CFCUtil_sprintf("&%s", CFCClass_full_class_var(parent)); } else { parent_ptr = CFCUtil_strdup("NULL"); const char *class_name = CFCClass_get_name(klass); const char *parent_var = CFCClass_full_class_var(parent); const char *pattern = " /* %s */\n" " class_specs[%d].parent = &%s;\n"; char *init_code = CFCUtil_sprintf(pattern, class_name, self->num_specs, parent_var); self->init_code = CFCUtil_cat(self->init_code, init_code, NULL); FREEMEM(init_code); } } int num_new_novel = 0; int num_new_overridden = 0; int num_new_inherited = 0; CFCMethod **methods = CFCClass_methods(klass); for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) { CFCMethod *method = methods[meth_num]; if (CFCMethod_is_fresh(method, klass)) { if (CFCMethod_novel(method)) { int meth_index = self->num_novel + num_new_novel; S_add_novel_meth(self, method, klass, meth_index); ++num_new_novel; } else { int meth_index = self->num_overridden + num_new_overridden; S_add_overridden_meth(self, method, klass, meth_index); ++num_new_overridden; } } else { int meth_index = self->num_inherited + num_new_inherited; S_add_inherited_meth(self, method, klass, meth_index); ++num_new_inherited; } } char pattern[] = " {\n" " &%s, /* class */\n" " %s, /* parent */\n" " \"%s\", /* name */\n" " %s, /* ivars_size */\n" " &%s, /* ivars_offset_ptr */\n" " %d, /* num_novel */\n" " %d, /* num_overridden */\n" " %d, /* num_inherited */\n" " %s /* flags */\n" " }"; char *class_spec = CFCUtil_sprintf(pattern, class_var, parent_ptr, class_name, ivars_size, ivars_offset_name, num_new_novel, num_new_overridden, num_new_inherited, flags); const char *sep = self->num_specs == 0 ? "" : ",\n"; self->class_specs = CFCUtil_cat(self->class_specs, sep, class_spec, NULL); self->num_novel += num_new_novel; self->num_overridden += num_new_overridden; self->num_inherited += num_new_inherited; self->num_specs += 1; FREEMEM(class_spec); FREEMEM(parent_ptr); FREEMEM(ivars_size); }