/* 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; }
char* CFCPerlConstructor_xsub_def(CFCPerlConstructor *self) { const char *c_name = self->sub.c_name; CFCParamList *param_list = self->sub.param_list; const char *name_list = CFCParamList_name_list(param_list); CFCVariable **arg_vars = CFCParamList_get_variables(param_list); const char *func_sym = CFCFunction_full_func_sym(self->init_func); char *allot_params = CFCPerlSub_build_allot_params((CFCPerlSub*)self); CFCVariable *self_var = arg_vars[0]; CFCType *self_type = CFCVariable_get_type(self_var); const char *self_type_str = CFCType_to_c(self_type); // Compensate for swallowed refcounts. char *refcount_mods = CFCUtil_strdup(""); for (size_t 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)) { const char *name = CFCVariable_micro_sym(var); refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_INCREF(", name, ");", NULL); } } const char pattern[] = "XS(%s);\n" "XS(%s) {\n" " dXSARGS;\n" " CFISH_UNUSED_VAR(cv);\n" " if (items < 1) { CFISH_THROW(CFISH_ERR, \"Usage: %%s(class_name, ...)\", GvNAME(CvGV(cv))); }\n" " SP -= items;\n" "\n" " %s\n" // Create "self" last, so that earlier exceptions while fetching // params don't trigger a bad invocation of DESTROY. " %s self = (%s)XSBind_new_blank_obj(ST(0));%s\n" "\n" " %s retval = %s(%s);\n" " if (retval) {\n" " ST(0) = (SV*)CFISH_Obj_To_Host((cfish_Obj*)retval);\n" " CFISH_Obj_Dec_RefCount((cfish_Obj*)retval);\n" " }\n" " else {\n" " ST(0) = newSV(0);\n" " }\n" " sv_2mortal(ST(0));\n" " XSRETURN(1);\n" "}\n\n"; char *xsub_def = CFCUtil_sprintf(pattern, c_name, c_name, allot_params, self_type_str, self_type_str, refcount_mods, self_type_str, func_sym, name_list); FREEMEM(refcount_mods); FREEMEM(allot_params); return xsub_def; }
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; }
/* 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; }
const char* CFCPerlSub_c_name_list(CFCPerlSub *self) { return CFCParamList_name_list(self->param_list); }
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; }
char* CFCPerlPod_gen_subroutine_pod(CFCPerlPod *self, CFCFunction *func, const char *alias, CFCClass *klass, const char *code_sample, const char *class_name, int is_constructor) { // Only allow "public" subs to be exposed as part of the public API. if (!CFCFunction_public(func)) { CFCUtil_die("%s#%s is not public", class_name, alias); } CFCParamList *param_list = CFCFunction_get_param_list(func); int num_vars = (int)CFCParamList_num_vars(param_list); char *pod = CFCUtil_sprintf("=head2 %s", alias); // Get documentation, which may be inherited. CFCDocuComment *docucomment = CFCFunction_get_docucomment(func); if (!docucomment) { const char *micro_sym = CFCFunction_micro_sym(func); CFCClass *parent = klass; while (NULL != (parent = CFCClass_get_parent(parent))) { CFCFunction *parent_func = (CFCFunction*)CFCClass_method(parent, micro_sym); if (!parent_func) { break; } docucomment = CFCFunction_get_docucomment(parent_func); if (docucomment) { break; } } } if (!docucomment) { CFCUtil_die("No DocuComment for '%s' in '%s'", alias, class_name); } // Build string summarizing arguments to use in header. if (num_vars > 2 || (is_constructor && num_vars > 1)) { pod = CFCUtil_cat(pod, "( I<[labeled params]> )\n\n", NULL); } else if (num_vars == 2) { // Kill self param. const char *name_list = CFCParamList_name_list(param_list); const char *after_comma = strchr(name_list, ',') + 1; while (isspace(*after_comma)) { after_comma++; } pod = CFCUtil_cat(pod, "(", after_comma, ")\n\n", NULL); } else { // num_args == 1, leave off 'self'. pod = CFCUtil_cat(pod, "()\n\n", NULL); } // Add code sample. if (code_sample && strlen(code_sample)) { pod = CFCUtil_cat(pod, code_sample, "\n", NULL); } // Incorporate "description" text from DocuComment. const char *long_doc = CFCDocuComment_get_description(docucomment); if (long_doc && strlen(long_doc)) { char *perlified = CFCPerlPod_md_to_pod(self, klass, long_doc); pod = CFCUtil_cat(pod, perlified, NULL); FREEMEM(perlified); } // Add params in a list. const char**param_names = CFCDocuComment_get_param_names(docucomment); const char**param_docs = CFCDocuComment_get_param_docs(docucomment); if (param_names[0]) { pod = CFCUtil_cat(pod, "=over\n\n", NULL); for (size_t i = 0; param_names[i] != NULL; i++) { char *perlified = CFCPerlPod_md_to_pod(self, klass, param_docs[i]); pod = CFCUtil_cat(pod, "=item *\n\nB<", param_names[i], "> - ", perlified, NULL); FREEMEM(perlified); } pod = CFCUtil_cat(pod, "=back\n\n", NULL); } // Add return value description, if any. const char *retval_doc = CFCDocuComment_get_retval(docucomment); if (retval_doc && strlen(retval_doc)) { char *perlified = CFCPerlPod_md_to_pod(self, klass, retval_doc); pod = CFCUtil_cat(pod, "Returns: ", perlified, NULL); FREEMEM(perlified); } return pod; }
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; }