/* Create a macro definition that aliases to a function name directly, since * this method may not be overridden. */ static char* S_final_method_def(CFCMethod *method, CFCClass *klass) { const char *self_type = CFCType_to_c(CFCMethod_self_type(method)); const char *full_func_sym = CFCMethod_implementing_func_sym(method); const char *arg_names = CFCParamList_name_list(CFCMethod_get_param_list(method)); size_t meth_sym_size = CFCMethod_full_method_sym(method, klass, NULL, 0); char *full_meth_sym = (char*)MALLOCATE(meth_sym_size); CFCMethod_full_method_sym(method, klass, full_meth_sym, meth_sym_size); size_t offset_sym_size = CFCMethod_full_offset_sym(method, klass, NULL, 0); char *full_offset_sym = (char*)MALLOCATE(offset_sym_size); CFCMethod_full_offset_sym(method, klass, full_offset_sym, offset_sym_size); const char pattern[] = "extern size_t %s;\n#define %s(%s) \\\n %s((%s)%s)\n"; size_t size = sizeof(pattern) + strlen(full_offset_sym) + strlen(full_meth_sym) + strlen(arg_names) + strlen(full_func_sym) + strlen(self_type) + strlen(arg_names) + 20; char *method_def = (char*)MALLOCATE(size); sprintf(method_def, pattern, full_offset_sym, full_meth_sym, arg_names, full_func_sym, self_type, arg_names); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); return method_def; }
static char* S_invalid_callback_def(CFCMethod *method) { char *full_method_sym = CFCMethod_full_method_sym(method, NULL); const char *override_sym = CFCMethod_full_override_sym(method); CFCParamList *param_list = CFCMethod_get_param_list(method); const char *params = CFCParamList_to_c(param_list); CFCVariable **param_vars = CFCParamList_get_variables(param_list); // Thwart compiler warnings. CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); char *unused = S_build_unused_vars(param_vars); char *unreachable = S_maybe_unreachable(return_type); char pattern[] = "%s\n" "%s(%s) {%s\n" " CFISH_THROW(CFISH_ERR, \"Can't override %s via binding\");%s\n" "}\n"; char *callback_def = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params, unused, full_method_sym, unreachable); FREEMEM(full_method_sym); FREEMEM(unreachable); FREEMEM(unused); return callback_def; }
char* CFCPyMethod_callback_def(CFCMethod *method, CFCClass *invoker) { CFCParamList *param_list = CFCMethod_get_param_list(method); CFCVariable **vars = CFCParamList_get_variables(param_list); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *params = CFCParamList_to_c(param_list); char *override_sym = CFCMethod_full_override_sym(method, invoker); char *content; if (CFCMethod_can_be_bound(method)) { char *py_args = S_build_py_args(param_list); char *invocation = S_build_pymeth_invocation(method); char *refcount_mods = S_callback_refcount_mods(param_list); const char *maybe_return = CFCType_is_void(return_type) ? "" : " return cfcb_RESULT;\n"; const char pattern[] = "%s\n" "%s(%s) {\n" "%s\n" "%s\n" "%s" "%s" "}\n"; content = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params, py_args, invocation, refcount_mods, maybe_return); } else { char *unused = S_build_unused_vars(vars); char *unreachable = S_maybe_unreachable(return_type); char *meth_sym = CFCMethod_full_method_sym(method, invoker); const char pattern[] = "%s\n" "%s(%s) {%s\n" " CFISH_THROW(CFISH_ERR, \"Can't override %s via binding\");%s\n" "}\n"; content = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params, unused, meth_sym, unreachable); FREEMEM(meth_sym); FREEMEM(unused); FREEMEM(unreachable); } FREEMEM(override_sym); return content; }
static char* S_virtual_method_def(CFCMethod *method, CFCClass *klass) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *PREFIX = CFCClass_get_PREFIX(klass); const char *invoker_struct = CFCClass_full_struct_sym(klass); char *full_meth_sym = CFCMethod_full_method_sym(method, klass); char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); char *full_typedef = CFCMethod_full_typedef(method, klass); // Prepare parameter lists, minus invoker. The invoker gets forced to // "self" later. if (CFCParamList_variadic(param_list)) { CFCUtil_die("Variadic methods not supported"); } const char *arg_names_minus_invoker = CFCParamList_name_list(param_list); const char *params_minus_invoker = CFCParamList_to_c(param_list); while (*arg_names_minus_invoker && *arg_names_minus_invoker != ',') { arg_names_minus_invoker++; } while (*params_minus_invoker && *params_minus_invoker != ',') { params_minus_invoker++; } // Prepare a return statement... or not. CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *maybe_return = CFCType_is_void(return_type) ? "" : "return "; const char pattern[] = "extern %sVISIBLE size_t %s;\n" "static CFISH_INLINE %s\n" "%s(%s *self%s) {\n" " const %s method = (%s)cfish_obj_method(self, %s);\n" " %smethod(self%s);\n" "}\n"; char *method_def = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str, full_meth_sym, invoker_struct, params_minus_invoker, full_typedef, full_typedef, full_offset_sym, maybe_return, arg_names_minus_invoker); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); FREEMEM(full_typedef); return method_def; }
char* CFCPyMethod_wrapper(CFCMethod *method, CFCClass *invoker) { CFCParamList *param_list = CFCMethod_get_param_list(method); CFCType *return_type = CFCMethod_get_return_type(method); char *meth_sym = CFCMethod_full_method_sym(method, invoker); char *meth_top = S_meth_top(method); char *increfs = S_gen_arg_increfs(param_list, 1); char *decrefs = S_gen_decrefs(param_list, 1); char *invocation = S_gen_meth_invocation(method, invoker); char *ret; if (CFCType_is_void(return_type)) { ret = CFCUtil_strdup(" Py_RETURN_NONE;\n"); } else if (CFCType_incremented(return_type)) { ret = CFCUtil_strdup(" return CFBind_cfish_to_py_zeroref((cfish_Obj*)retvalCF);\n"); } else { char *conv = CFCPyTypeMap_c_to_py(return_type, "retvalCF"); ret = CFCUtil_sprintf(" return %s;\n", conv); FREEMEM(conv); } char pattern[] = "static PyObject*\n" "S_%s%s" "%s" // increfs "%s" // invocation "%s" // decrefs " if (CFBind_migrate_cferr()) {\n" " return NULL;\n" " }\n" "%s" // ret "}\n" ; char *wrapper = CFCUtil_sprintf(pattern, meth_sym, meth_top, increfs, invocation, decrefs, ret); FREEMEM(ret); FREEMEM(invocation); FREEMEM(decrefs); FREEMEM(increfs); FREEMEM(meth_sym); FREEMEM(meth_top); return wrapper; }
char* CFCPyMethod_pymethoddef(CFCMethod *method, CFCClass *invoker) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *flags = CFCParamList_num_vars(param_list) == 1 ? "METH_NOARGS" : "METH_KEYWORDS|METH_VARARGS"; char *meth_sym = CFCMethod_full_method_sym(method, invoker); char *micro_sym = CFCUtil_strdup(CFCSymbol_get_name((CFCSymbol*)method)); for (int i = 0; micro_sym[i] != 0; i++) { micro_sym[i] = tolower(micro_sym[i]); } char pattern[] = "{\"%s\", (PyCFunction)S_%s, %s, NULL},"; char *py_meth_def = CFCUtil_sprintf(pattern, micro_sym, meth_sym, flags); FREEMEM(meth_sym); FREEMEM(micro_sym); return py_meth_def; }
static char* S_gen_meth_invocation(CFCMethod *method, CFCClass *invoker) { CFCParamList *param_list = CFCMethod_get_param_list(method); char *full_meth = CFCMethod_full_method_sym(method, invoker); char *meth_type_c = CFCMethod_full_typedef(method, invoker); const char *class_var = CFCClass_full_class_var(invoker); char *first_arg = CFCUtil_sprintf("(%s*)self", CFCClass_full_struct_sym(invoker)); char *arg_list = S_gen_arg_list(param_list, first_arg); CFCType *return_type = CFCMethod_get_return_type(method); char *maybe_declare; const char *maybe_assign; if (CFCType_is_void(return_type)) { maybe_declare = CFCUtil_strdup(""); maybe_assign = ""; } else { maybe_declare = CFCUtil_sprintf(" %s retvalCF;\n", CFCType_to_c(return_type)); maybe_assign = "retvalCF = "; } const char pattern[] = "%s" " %s method = CFISH_METHOD_PTR(%s, %s);\n" " CFBIND_TRY(%smethod(%s));\n" ; char *content = CFCUtil_sprintf(pattern, maybe_declare, meth_type_c, class_var, full_meth, maybe_assign, arg_list); FREEMEM(arg_list); FREEMEM(first_arg); FREEMEM(maybe_declare); FREEMEM(full_meth); FREEMEM(meth_type_c); return content; }
/* Create a macro definition that aliases to a function name directly, since * this method may not be overridden. */ static char* S_final_method_def(CFCMethod *method, CFCClass *klass) { const char *self_type = CFCType_to_c(CFCMethod_self_type(method)); const char *full_func_sym = CFCMethod_imp_func(method); const char *arg_names = CFCParamList_name_list(CFCMethod_get_param_list(method)); char *full_meth_sym = CFCMethod_full_method_sym(method, klass); char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); const char pattern[] = "extern size_t %s;\n" "#define %s(%s) \\\n" " %s((%s)%s)\n"; char *method_def = CFCUtil_sprintf(pattern, full_offset_sym, full_meth_sym, arg_names, full_func_sym, self_type, arg_names); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); return method_def; }
static char* S_method_def(CFCMethod *method, CFCClass *klass, int optimized_final_meth) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *PREFIX = CFCClass_get_PREFIX(klass); const char *invoker_struct = CFCClass_full_struct_sym(klass); const char *self_name = CFCParamList_param_name(param_list, 0); char *full_meth_sym = CFCMethod_full_method_sym(method, klass); char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); char *full_typedef = CFCMethod_full_typedef(method, klass); char *full_imp_sym = CFCMethod_imp_func(method, klass); // Prepare parameter lists, minus the type of the invoker. if (CFCParamList_variadic(param_list)) { CFCUtil_die("Variadic methods not supported"); } const char *arg_names = CFCParamList_name_list(param_list); const char *params_end = CFCParamList_to_c(param_list); while (*params_end && *params_end != '*') { params_end++; } // Prepare a return statement... or not. CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *maybe_return = CFCType_is_void(return_type) ? "" : "return "; const char innards_pattern[] = " const %s method = (%s)cfish_obj_method(%s, %s);\n" " %smethod(%s);\n" ; char *innards = CFCUtil_sprintf(innards_pattern, full_typedef, full_typedef, self_name, full_offset_sym, maybe_return, arg_names); if (optimized_final_meth) { CFCParcel *parcel = CFCClass_get_parcel(klass); const char *privacy_sym = CFCParcel_get_privacy_sym(parcel); char *invoker_cast = CFCUtil_strdup(""); if (!CFCMethod_is_fresh(method, klass)) { CFCType *self_type = CFCMethod_self_type(method); invoker_cast = CFCUtil_cat(invoker_cast, "(", CFCType_to_c(self_type), ")", NULL); } const char pattern[] = "#ifdef %s\n" " %s%s(%s%s);\n" "#else\n" "%s" "#endif\n" ; char *temp = CFCUtil_sprintf(pattern, privacy_sym, maybe_return, full_imp_sym, invoker_cast, arg_names, innards); FREEMEM(innards); innards = temp; FREEMEM(invoker_cast); } const char pattern[] = "extern %sVISIBLE uint32_t %s;\n" "static CFISH_INLINE %s\n" "%s(%s%s) {\n" "%s" "}\n"; char *method_def = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str, full_meth_sym, invoker_struct, params_end, innards); FREEMEM(innards); FREEMEM(full_imp_sym); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); FREEMEM(full_typedef); return method_def; }
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 char* S_virtual_method_def(CFCMethod *method, CFCClass *klass) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *invoker_struct = CFCClass_full_struct_sym(klass); const char *common_struct = CFCType_get_specifier(CFCMethod_self_type(method)); const char *visibility = CFCClass_included(klass) ? "CHY_IMPORT" : "CHY_EXPORT"; size_t meth_sym_size = CFCMethod_full_method_sym(method, klass, NULL, 0); char *full_meth_sym = (char*)MALLOCATE(meth_sym_size); CFCMethod_full_method_sym(method, klass, full_meth_sym, meth_sym_size); size_t offset_sym_size = CFCMethod_full_offset_sym(method, klass, NULL, 0); char *full_offset_sym = (char*)MALLOCATE(offset_sym_size); CFCMethod_full_offset_sym(method, klass, full_offset_sym, offset_sym_size); size_t full_typedef_size = CFCMethod_full_typedef(method, klass, NULL, 0); char *full_typedef = (char*)MALLOCATE(full_typedef_size); CFCMethod_full_typedef(method, klass, full_typedef, full_typedef_size); // Prepare parameter lists, minus invoker. The invoker gets forced to // "self" later. const char *arg_names_minus_invoker = CFCParamList_name_list(param_list); const char *params_minus_invoker = CFCParamList_to_c(param_list); while (*arg_names_minus_invoker && *arg_names_minus_invoker != ',') { arg_names_minus_invoker++; } while (*params_minus_invoker && *params_minus_invoker != ',') { params_minus_invoker++; } // Prepare a return statement... or not. CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *maybe_return = CFCType_is_void(return_type) ? "" : "return "; const char pattern[] = "extern %s size_t %s;\n" "static CHY_INLINE %s\n" "%s(const %s *self%s) {\n" " char *const method_address = *(char**)self + %s;\n" " const %s method = *((%s*)method_address);\n" " %smethod((%s*)self%s);\n" "}\n"; size_t size = sizeof(pattern) + strlen(visibility) + strlen(full_offset_sym) + strlen(ret_type_str) + strlen(full_meth_sym) + strlen(invoker_struct) + strlen(params_minus_invoker) + strlen(full_offset_sym) + strlen(full_typedef) + strlen(full_typedef) + strlen(maybe_return) + strlen(common_struct) + strlen(arg_names_minus_invoker) + 40; char *method_def = (char*)MALLOCATE(size); sprintf(method_def, pattern, visibility, full_offset_sym, ret_type_str, full_meth_sym, invoker_struct, params_minus_invoker, full_offset_sym, full_typedef, full_typedef, maybe_return, common_struct, arg_names_minus_invoker); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); FREEMEM(full_typedef); return method_def; }