char* CFCBindMeth_typedef_dec(struct CFCMethod *method, CFCClass *klass) { const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); const char *ret_type = CFCType_to_c(CFCMethod_get_return_type(method)); 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); size_t size = strlen(params) + strlen(ret_type) + strlen(full_typedef) + 20 + sizeof("\0"); char *buf = (char*)MALLOCATE(size); sprintf(buf, "typedef %s\n(*%s)(%s);\n", ret_type, full_typedef, params); FREEMEM(full_typedef); return buf; }
char* CFCBindMeth_typedef_dec(struct CFCMethod *method, CFCClass *klass) { const char *params_end = CFCParamList_to_c(CFCMethod_get_param_list(method)); while (*params_end && *params_end != '*') { params_end++; } const char *self_struct = CFCClass_full_struct_sym(klass); const char *ret_type = CFCType_to_c(CFCMethod_get_return_type(method)); char *full_typedef = CFCMethod_full_typedef(method, klass); char *buf = CFCUtil_sprintf("typedef %s\n(*%s)(%s%s);\n", ret_type, full_typedef, self_struct, params_end); FREEMEM(full_typedef); return buf; }
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; }
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; }
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; }