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 void S_add_overridden_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass, int meth_index) { const char *sep = meth_index == 0 ? "" : ",\n"; char *imp_func = CFCMethod_imp_func(method, klass); char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); char *parent_offset = S_parent_offset(self, method, klass, "overridden", meth_index); char pattern[] = " {\n" " &%s, /* offset */\n" " %s, /* parent_offset */\n" " (cfish_method_t)%s /* func */\n" " }"; char *def = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset, imp_func); self->overridden_specs = CFCUtil_cat(self->overridden_specs, sep, def, NULL); FREEMEM(def); FREEMEM(parent_offset); FREEMEM(full_offset_sym); FREEMEM(imp_func); }
static void S_add_novel_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass, int meth_index) { const char *meth_name = CFCMethod_get_name(method); const char *sep = meth_index == 0 ? "" : ",\n"; char *full_override_sym; if (!CFCMethod_final(method) && !CFCMethod_excluded_from_host(method)) { full_override_sym = CFCMethod_full_override_sym(method, klass); } else { full_override_sym = CFCUtil_strdup("NULL"); } char *imp_func = CFCMethod_imp_func(method, klass); char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); 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, meth_name, imp_func, full_override_sym); self->novel_specs = CFCUtil_cat(self->novel_specs, sep, def, NULL); FREEMEM(def); FREEMEM(full_offset_sym); FREEMEM(imp_func); FREEMEM(full_override_sym); }
void CFCMethod_override(CFCMethod *self, CFCMethod *orig) { // Check that the override attempt is legal. if (CFCMethod_final(orig)) { const char *orig_class = CFCMethod_get_class_name(orig); const char *my_class = CFCMethod_get_class_name(self); CFCUtil_die("Attempt to override final method '%s' from '%s' by '%s'", orig->macro_sym, orig_class, my_class); } if (!CFCMethod_compatible(self, orig)) { const char *func = CFCMethod_imp_func(self); const char *orig_func = CFCMethod_imp_func(orig); CFCUtil_die("Non-matching signatures for %s and %s", func, orig_func); } // Mark the Method as no longer novel. self->is_novel = false; }
char* CFCBindMeth_imp_declaration(CFCMethod *method) { CFCType *return_type = CFCMethod_get_return_type(method); CFCParamList *param_list = CFCMethod_get_param_list(method); const char *ret_type_str = CFCType_to_c(return_type); const char *full_imp_sym = CFCMethod_imp_func(method); const char *param_list_str = CFCParamList_to_c(param_list); char *buf = CFCUtil_sprintf("%s\n%s(%s);", ret_type_str, full_imp_sym, param_list_str); return buf; }
char* CFCBindMeth_abstract_method_def(CFCMethod *method, CFCClass *klass) { CFCType *ret_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(ret_type); CFCType *type = CFCMethod_self_type(method); const char *class_var = CFCType_get_class_var(type); const char *meth_name = CFCMethod_get_name(method); CFCParamList *param_list = CFCMethod_get_param_list(method); const char *params = CFCParamList_to_c(param_list); CFCVariable **vars = CFCParamList_get_variables(param_list); const char *invocant = CFCVariable_get_name(vars[0]); // All variables other than the invocant are unused, and the return is // unreachable. char *unused = CFCUtil_strdup(""); for (int i = 1; vars[i] != NULL; i++) { const char *var_name = CFCVariable_get_name(vars[i]); size_t size = strlen(unused) + strlen(var_name) + 80; unused = (char*)REALLOCATE(unused, size); strcat(unused, "\n CFISH_UNUSED_VAR("); strcat(unused, var_name); strcat(unused, ");"); } char *unreachable; if (!CFCType_is_void(ret_type)) { unreachable = CFCUtil_sprintf(" CFISH_UNREACHABLE_RETURN(%s);\n", ret_type_str); } else { unreachable = CFCUtil_strdup(""); } char *full_func_sym = CFCMethod_imp_func(method, klass); char pattern[] = "%s\n" "%s(%s) {\n" "%s" " cfish_Err_abstract_method_call((cfish_Obj*)%s, %s, \"%s\");\n" "%s" "}\n"; char *abstract_def = CFCUtil_sprintf(pattern, ret_type_str, full_func_sym, params, unused, invocant, class_var, meth_name, unreachable); FREEMEM(unused); FREEMEM(unreachable); FREEMEM(full_func_sym); return abstract_def; }
/* 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; }
char* CFCBindMeth_overridden_spec_def(CFCMethod *method, CFCClass *klass) { const char *imp_func = CFCMethod_imp_func(method); char *full_offset_sym = CFCMethod_full_offset_sym(method, NULL); CFCClass *parent = CFCClass_get_parent(klass); char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent); char pattern[] = " {\n" " &%s, /* offset */\n" " &%s, /* parent_offset */\n" " (cfish_method_t)%s /* func */\n" " }"; char *def = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset_sym, imp_func); FREEMEM(full_offset_sym); FREEMEM(parent_offset_sym); return 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; }