// Generate C code which initializes method metadata. char* CFCPerlClass_method_metadata_code(CFCPerlClass *self) { const char *class_var = CFCClass_full_class_var(self->client); CFCMethod **fresh_methods = CFCClass_fresh_methods(self->client); char *code = CFCUtil_strdup(""); for (int i = 0; fresh_methods[i] != NULL; i++) { CFCMethod *method = fresh_methods[i]; if (!CFCMethod_novel(method)) { continue; } const char *macro_sym = CFCMethod_get_macro_sym(method); const char *alias = CFCMethod_get_host_alias(method); if (alias) { code = CFCUtil_cat(code, " CFISH_Class_Add_Host_Method_Alias(", class_var, ", \"", alias, "\", \"", macro_sym, "\");\n", NULL); } if (CFCMethod_excluded_from_host(method)) { code = CFCUtil_cat(code, " CFISH_Class_Exclude_Host_Method(", class_var, ", \"", macro_sym, "\");\n", NULL); } } return code; }
char* CFCBindMeth_abstract_method_def(CFCMethod *method) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *params = CFCParamList_to_c(param_list); const char *full_func_sym = CFCMethod_imp_func(method); const char *vtable_var = CFCType_get_vtable_var(CFCMethod_self_type(method)); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *macro_sym = CFCMethod_get_macro_sym(method); // Thwart compiler warnings. CFCVariable **param_vars = CFCParamList_get_variables(param_list); char *unused = S_build_unused_vars(param_vars + 1); char *return_statement = S_maybe_unreachable(return_type); char pattern[] = "%s\n" "%s(%s) {\n" " cfish_String *klass = self ? CFISH_Obj_Get_Class_Name((cfish_Obj*)self) : %s->name;%s\n" " CFISH_THROW(CFISH_ERR, \"Abstract method '%s' not defined by %%o\", klass);%s\n" "}\n"; char *abstract_def = CFCUtil_sprintf(pattern, ret_type_str, full_func_sym, params, vtable_var, unused, macro_sym, return_statement); FREEMEM(unused); FREEMEM(return_statement); return abstract_def; }
char* CFCBindMeth_novel_spec_def(CFCMethod *method) { const char *macro_sym = CFCMethod_get_macro_sym(method); const char *imp_func = CFCMethod_imp_func(method); const char *full_override_sym = "NULL"; if (!CFCMethod_final(method)) { full_override_sym = CFCMethod_full_override_sym(method); } char *full_offset_sym = CFCMethod_full_offset_sym(method, NULL); char pattern[] = " {\n" " &%s, /* offset */\n" " \"%s\", /* name */\n" " (cfish_method_t)%s, /* func */\n" " (cfish_method_t)%s /* callback_func */\n" " }"; char *def = CFCUtil_sprintf(pattern, full_offset_sym, macro_sym, imp_func, full_override_sym); FREEMEM(full_offset_sym); return def; }
static char* S_obj_callback_def(CFCMethod *method, const char *callback_params, const char *refcount_mods) { const char *override_sym = CFCMethod_full_override_sym(method); const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *cb_func_name = CFCType_is_string_type(return_type) ? "cfish_Host_callback_str" : "cfish_Host_callback_obj"; char *nullable_check = CFCUtil_strdup(""); if (!CFCType_nullable(return_type)) { const char *macro_sym = CFCMethod_get_macro_sym(method); char pattern[] = "\n if (!retval) { CFISH_THROW(CFISH_ERR, " "\"%s() for class '%%o' cannot return NULL\", " "Cfish_Obj_Get_Class_Name((cfish_Obj*)self)); }"; size_t size = sizeof(pattern) + strlen(macro_sym) + 30; nullable_check = (char*)REALLOCATE(nullable_check, size); sprintf(nullable_check, pattern, macro_sym); } char pattern[] = "%s\n" "%s(%s) {\n" " %s retval = (%s)%s(%s);%s%s\n" " return retval;\n" "}\n"; size_t size = sizeof(pattern) + strlen(ret_type_str) + strlen(override_sym) + strlen(params) + strlen(ret_type_str) + strlen(ret_type_str) + strlen(cb_func_name) + strlen(callback_params) + strlen(nullable_check) + strlen(refcount_mods) + 30; char *callback_def = (char*)MALLOCATE(size); sprintf(callback_def, pattern, ret_type_str, override_sym, params, ret_type_str, ret_type_str, cb_func_name, callback_params, nullable_check, refcount_mods); FREEMEM(nullable_check); return callback_def; }
char* CFCBindMeth_spec_def(CFCMethod *method) { const char *macro_sym = CFCMethod_get_macro_sym(method); const char *impl_sym = CFCMethod_implementing_func_sym(method); int is_novel = CFCMethod_novel(method); const char *full_override_sym = "NULL"; if ((CFCMethod_public(method) || CFCMethod_abstract(method)) && is_novel) { full_override_sym = CFCMethod_full_override_sym(method); } size_t offset_sym_size = CFCMethod_full_offset_sym(method, NULL, NULL, 0); char *full_offset_sym = (char*)MALLOCATE(offset_sym_size); CFCMethod_full_offset_sym(method, NULL, full_offset_sym, offset_sym_size); char pattern[] = " {\n" " %d, /* is_novel */\n" " \"%s\", /* name */\n" " (cfish_method_t)%s, /* func */\n" " (cfish_method_t)%s, /* callback_func */\n" " &%s /* offset */\n" " }"; size_t size = sizeof(pattern) + 10 /* for is_novel */ + strlen(macro_sym) + strlen(impl_sym) + strlen(full_override_sym) + strlen(full_offset_sym) + 30; char *def = (char*)MALLOCATE(size); sprintf(def, pattern, is_novel, macro_sym, impl_sym, full_override_sym, full_offset_sym); FREEMEM(full_offset_sym); return def; }
static void S_bequeath_methods(CFCClass *self) { for (size_t child_num = 0; self->children[child_num] != NULL; child_num++) { CFCClass *child = self->children[child_num]; // Create array of methods, preserving exact order so vtables match up. size_t num_methods = 0; size_t max_methods = self->num_methods + child->num_methods; CFCMethod **methods = (CFCMethod**)MALLOCATE( (max_methods + 1) * sizeof(CFCMethod*)); // Gather methods which child inherits or overrides. for (size_t i = 0; i < self->num_methods; i++) { CFCMethod *method = self->methods[i]; const char *macro_sym = CFCMethod_get_macro_sym(method); CFCMethod *child_method = CFCClass_method(child, macro_sym); if (child_method) { CFCMethod_override(child_method, method); methods[num_methods++] = child_method; } else { methods[num_methods++] = method; } } // Append novel child methods to array. Child methods which were just // marked via CFCMethod_override() a moment ago are skipped. for (size_t i = 0; i < child->num_methods; i++) { CFCMethod *method = child->methods[i]; if (CFCMethod_novel(method)) { methods[num_methods++] = method; } } methods[num_methods] = NULL; // Manage refcounts and assign new array. Transform to final methods // if child class is a final class. if (child->is_final) { for (size_t i = 0; i < num_methods; i++) { if (CFCMethod_final(methods[i])) { CFCBase_incref((CFCBase*)methods[i]); } else { methods[i] = CFCMethod_finalize(methods[i]); } } } else { for (size_t i = 0; i < num_methods; i++) { CFCBase_incref((CFCBase*)methods[i]); } } for (size_t i = 0; i < child->num_methods; i++) { CFCBase_decref((CFCBase*)child->methods[i]); } FREEMEM(child->methods); child->methods = methods; child->num_methods = num_methods; // Pass it all down to the next generation. S_bequeath_methods(child); child->tree_grown = true; } }