// 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* CFCPerlPod_constructors_pod(CFCPerlPod *self, CFCClass *klass) { if (!self->num_constructors) { return CFCUtil_strdup(""); } const char *class_name = CFCClass_get_name(klass); char *pod = CFCUtil_strdup("=head1 CONSTRUCTORS\n\n"); for (size_t i = 0; i < self->num_constructors; i++) { NamePod slot = self->constructors[i]; if (slot.pod) { pod = CFCUtil_cat(pod, slot.pod, "\n", NULL); } else { const char *func_name = slot.func ? slot.func : slot.alias; CFCFunction *pod_func = CFCClass_function(klass, func_name); if (!pod_func) { CFCUtil_die("Can't find constructor '%s' in class '%s'", func_name, CFCClass_get_name(klass)); } char *sub_pod = CFCPerlPod_gen_subroutine_pod((CFCCallable*)pod_func, slot.alias, klass, slot.sample, class_name, true); pod = CFCUtil_cat(pod, sub_pod, NULL); FREEMEM(sub_pod); } } return pod; }
static char* S_callback_refcount_mods(CFCParamList *param_list) { char *refcount_mods = CFCUtil_strdup(""); CFCVariable **arg_vars = CFCParamList_get_variables(param_list); // Adjust refcounts of arguments per method signature, so that Perl code // does not have to. for (int i = 0; arg_vars[i] != NULL; i++) { CFCVariable *var = arg_vars[i]; CFCType *type = CFCVariable_get_type(var); const char *name = CFCVariable_get_name(var); if (!CFCType_is_object(type)) { continue; } else if (CFCType_incremented(type)) { refcount_mods = CFCUtil_cat(refcount_mods, " CFISH_INCREF(", name, ");\n", NULL); } else if (CFCType_decremented(type)) { refcount_mods = CFCUtil_cat(refcount_mods, " CFISH_DECREF(", name, ");\n", NULL); } } return refcount_mods; }
static char* S_add_xs_init(char *xs_init, CFCPerlSub *xsub) { const char *c_name = CFCPerlSub_c_name(xsub); const char *perl_name = CFCPerlSub_perl_name(xsub); if (strlen(xs_init)) { xs_init = CFCUtil_cat(xs_init, "\n ", NULL); } xs_init = CFCUtil_cat(xs_init, "newXS(\"", perl_name, "\", ", c_name, ", file);", NULL); return xs_init; }
static char* S_gen_code_sample(CFCCallable *func, const char *alias, CFCClass *klass, int is_constructor) { char *prologue = CFCUtil_sprintf(""); char *class_var_name = S_camel_to_lower(CFCClass_get_struct_sym(klass)); CFCType *ret_type = CFCCallable_get_return_type(func); if (!CFCType_is_void(ret_type)) { char *ret_name = S_perl_var_name(ret_type, is_constructor); if (!is_constructor && strcmp(ret_name, class_var_name) == 0) { // Return type equals `klass`. Use a generic variable name // to avoid confusing code samples like // `my $string = $string->trim`. prologue = CFCUtil_cat(prologue, "my $result = ", NULL); } else { prologue = CFCUtil_cat(prologue, "my $", ret_name, " = ", NULL); } FREEMEM(ret_name); } if (is_constructor) { const char *invocant = CFCClass_get_name(klass); prologue = CFCUtil_cat(prologue, invocant, NULL); } else { prologue = CFCUtil_cat(prologue, "$", class_var_name, NULL); } prologue = CFCUtil_cat(prologue, "->", alias, NULL); CFCParamList *param_list = CFCCallable_get_param_list(func); int num_vars = CFCParamList_num_vars(param_list); int start = is_constructor ? 0 : 1; char *sample = NULL; if (start == num_vars) { sample = CFCUtil_sprintf(" %s();\n", prologue); } else if (is_constructor || num_vars - start >= 2) { sample = S_gen_labeled_sample(prologue, param_list, start); } else { sample = S_gen_positional_sample(prologue, param_list, start); } FREEMEM(class_var_name); FREEMEM(prologue); return sample; }
void CFCPerlClass_append_xs(CFCPerlClass *self, const char *xs) { if (!self->xs_code) { self->xs_code = CFCUtil_strdup(""); } self->xs_code = CFCUtil_cat(self->xs_code, xs, NULL); }
static char* S_gen_positional_sample(const char *prologue, CFCParamList *param_list, int start) { int num_vars = CFCParamList_num_vars(param_list); CFCVariable **vars = CFCParamList_get_variables(param_list); const char **inits = CFCParamList_get_initial_values(param_list); if (num_vars - start != 1) { CFCUtil_die("Code samples with multiple positional parameters" " are not supported yet."); } const char *name = CFCVariable_get_name(vars[start]); char *sample = CFCUtil_sprintf(" %s($%s);\n", prologue, name); const char *init = inits[start]; if (init) { if (strcmp(init, "NULL") == 0) { init = "undef"; } char *def_sample = CFCUtil_sprintf(" %s(); # default: %s\n", prologue, init); sample = CFCUtil_cat(sample, def_sample, NULL); FREEMEM(def_sample); } return sample; }
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 char* S_parent_offset(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass, const char *meth_type, int meth_index) { CFCClass *parent = CFCClass_get_parent(klass); if (!parent) { return CFCUtil_strdup("NULL"); } char *parent_offset = NULL; char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent); if (CFCClass_in_same_parcel(klass, parent)) { parent_offset = CFCUtil_sprintf("&%s", parent_offset_sym); } else { parent_offset = CFCUtil_strdup("NULL"); char pattern[] = " %s_specs[%d].parent_offset = &%s;\n"; char *code = CFCUtil_sprintf(pattern, meth_type, meth_index, parent_offset_sym); self->init_code = CFCUtil_cat(self->init_code, code, NULL); FREEMEM(code); } FREEMEM(parent_offset_sym); return parent_offset; }
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); }
char* CFCPerlPod_methods_pod(CFCPerlPod *self, CFCClass *klass) { const char *class_name = CFCClass_get_class_name(klass); char *abstract_pod = CFCUtil_strdup(""); char *methods_pod = CFCUtil_strdup(""); for (size_t i = 0; i < self->num_methods; i++) { NamePod meth_spec = self->methods[i]; CFCMethod *method = CFCClass_method(klass, meth_spec.func); if (!method) { method = CFCClass_method(klass, meth_spec.alias); } if (!method) { CFCUtil_die("Can't find method '%s' in class '%s'", meth_spec.alias, CFCClass_get_class_name(klass)); } char *meth_pod; if (meth_spec.pod) { meth_pod = CFCUtil_sprintf("%s\n", meth_spec.pod); } else { meth_pod = CFCPerlPod_gen_subroutine_pod(self, (CFCFunction*)method, meth_spec.alias, klass, meth_spec.sample, class_name, false); } if (CFCMethod_abstract(method)) { abstract_pod = CFCUtil_cat(abstract_pod, meth_pod, NULL); } else { methods_pod = CFCUtil_cat(methods_pod, meth_pod, NULL); } FREEMEM(meth_pod); } char *pod = CFCUtil_strdup(""); if (strlen(abstract_pod)) { pod = CFCUtil_cat(pod, "=head1 ABSTRACT METHODS\n\n", abstract_pod, NULL); } FREEMEM(abstract_pod); if (strlen(methods_pod)) { pod = CFCUtil_cat(pod, "=head1 METHODS\n\n", methods_pod, NULL); } FREEMEM(methods_pod); return pod; }
char* CFCPerlSub_build_allot_params(CFCPerlSub *self) { CFCParamList *param_list = self->param_list; CFCVariable **arg_vars = CFCParamList_get_variables(param_list); const char **arg_inits = CFCParamList_get_initial_values(param_list); size_t num_vars = CFCParamList_num_vars(param_list); char *allot_params = CFCUtil_strdup(""); // Declare variables and assign default values. for (size_t i = 1; i < num_vars; i++) { CFCVariable *arg_var = arg_vars[i]; const char *val = arg_inits[i]; const char *var_name = CFCVariable_micro_sym(arg_var); if (val == NULL) { CFCType *arg_type = CFCVariable_get_type(arg_var); val = CFCType_is_object(arg_type) ? "NULL" : "0"; } allot_params = CFCUtil_cat(allot_params, "arg_", var_name, " = ", val, ";\n ", NULL); } // Iterate over args in param list. allot_params = CFCUtil_cat(allot_params, "args_ok = XSBind_allot_params(\n" " &(ST(0)), 1, items,\n", NULL); for (size_t i = 1; i < num_vars; i++) { CFCVariable *var = arg_vars[i]; const char *val = arg_inits[i]; int required = val ? 0 : 1; const char *name = CFCVariable_micro_sym(var); CFCType *type = CFCVariable_get_type(var); char *arg = S_allot_params_arg(type, name, required); allot_params = CFCUtil_cat(allot_params, " ", arg, ",\n", NULL); FREEMEM(arg); } allot_params = CFCUtil_cat(allot_params, " NULL);\n", " if (!args_ok) {\n" " CFISH_RETHROW(CFISH_INCREF(cfish_Err_get_error()));\n" " }", NULL); return allot_params; }
static char* S_charmony_alloca_defines() { char *defines = CFCUtil_strdup(""); #if defined(CHY_HAS_ALLOCA_H) defines = CFCUtil_cat(defines, "#include <alloca.h>\n", NULL); #elif defined(CHY_HAS_MALLOC_H) defines = CFCUtil_cat(defines, "#include <malloc.h>\n", NULL); #elif defined(CHY_ALLOCA_IN_STDLIB_H) defines = CFCUtil_cat(defines, "#include <stdlib.h>\n", NULL); #endif defines = CFCUtil_cat(defines, "#define cfish_alloca ", XSTRING(chy_alloca), "\n", NULL); return defines; }
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_add_xsub_spec(char *xsub_specs, CFCPerlSub *xsub) { const char *c_name = CFCPerlSub_c_name(xsub); const char *alias = CFCPerlSub_get_alias(xsub); const char *sep = xsub_specs[0] == '\0' ? "" : ",\n"; xsub_specs = CFCUtil_cat(xsub_specs, sep, " { \"", alias, "\", ", c_name, " }", NULL); return xsub_specs; }
static char* S_build_py_args(CFCParamList *param_list) { int num_vars = CFCParamList_num_vars(param_list); CFCVariable **vars = CFCParamList_get_variables(param_list); char pattern[] = " PyObject *cfcb_ARGS = S_pack_tuple(%d"; char *py_args = CFCUtil_sprintf(pattern, num_vars - 1); for (int i = 1; vars[i] != NULL; i++) { const char *var_name = CFCVariable_get_name(vars[i]); CFCType *type = CFCVariable_get_type(vars[i]); char *conversion = CFCPyTypeMap_c_to_py(type, var_name); py_args = CFCUtil_cat(py_args, ",\n ", conversion, NULL); FREEMEM(conversion); } py_args = CFCUtil_cat(py_args, ");", NULL); return py_args; }
static char* S_gen_arg_list(CFCParamList *param_list, const char *first_arg) { CFCVariable **vars = CFCParamList_get_variables(param_list); int num_vars = CFCParamList_num_vars(param_list); char *arg_list = CFCUtil_strdup(""); for (int i = 0; i < num_vars; i++) { if (i > 0) { arg_list = CFCUtil_cat(arg_list, ", ", NULL); } if (i == 0 && first_arg != NULL) { arg_list = CFCUtil_cat(arg_list, first_arg, NULL); } else { arg_list = CFCUtil_cat(arg_list, CFCVariable_get_name(vars[i]), "_ARG", NULL); } } return arg_list; }
static char* S_charmony_feature_defines() { char *defines = CFCUtil_strdup(""); #ifdef CHY_LITTLE_END // Needed by NumberUtils.cfh. defines = CFCUtil_cat(defines, "#define CFISH_LITTLE_END\n", NULL); #endif #ifdef CHY_BIG_END // Needed by NumberUtils.cfh. defines = CFCUtil_cat(defines, "#define CFISH_BIG_END\n", NULL); #endif #ifdef CHY_HAS_FUNC_MACRO // Needed by Err.cfh. defines = CFCUtil_cat(defines, "#define CFISH_HAS_FUNC_MACRO\n", NULL); #endif #ifdef CHY_HAS_VARIADIC_MACROS // Needed by Err.cfh. defines = CFCUtil_cat(defines, "#define CFISH_HAS_VARIADIC_MACROS\n", NULL); #endif #ifdef CHY_HAS_ISO_VARIADIC_MACROS // Needed by Err.cfh. defines = CFCUtil_cat(defines, "#define CFISH_HAS_ISO_VARIADIC_MACROS\n", NULL); #endif #ifdef CHY_HAS_GNUC_VARIADIC_MACROS // Needed by Err.cfh. defines = CFCUtil_cat(defines, "#define CFISH_HAS_GNUC_VARIADIC_MACROS\n", NULL); #endif return defines; }
char* CFCGoClass_gen_meth_glue(CFCGoClass *self) { S_lazy_init_method_bindings(self); char *meth_defs = CFCUtil_strdup(""); for (size_t i = 0; self->method_bindings[i] != NULL; i++) { CFCGoMethod *meth_binding = self->method_bindings[i]; char *method_def = CFCGoMethod_func_def(meth_binding, self->client); meth_defs = CFCUtil_cat(meth_defs, method_def, "\n", NULL); FREEMEM(method_def); } return meth_defs; }
static char* S_gen_decs(CFCParamList *param_list, int first_tick) { char *decs = CFCUtil_strdup(""); int num_vars = CFCParamList_num_vars(param_list); CFCVariable **vars = CFCParamList_get_variables(param_list); for (int i = first_tick; i < num_vars; i++) { CFCType *type = CFCVariable_get_type(vars[i]); const char *name = CFCVariable_get_name(vars[i]); decs = CFCUtil_cat(decs, " ", CFCType_to_c(type), " ", name, "_ARG = 0;\n", NULL); } return decs; }
void CFCPerlTypeMap_write_xs_typemap(CFCHierarchy *hierarchy) { CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy); char *start = CFCUtil_strdup(""); char *input = CFCUtil_strdup(""); char *output = CFCUtil_strdup(""); for (int i = 0; classes[i] != NULL; i++) { CFCClass *klass = classes[i]; if (CFCClass_included(klass)) { continue; } const char *full_struct_sym = CFCClass_full_struct_sym(klass); const char *vtable_var = CFCClass_full_vtable_var(klass); start = CFCUtil_cat(start, full_struct_sym, "*\t", vtable_var, "_\n", NULL); input = CFCUtil_cat(input, vtable_var, "_\n" " $var = (", full_struct_sym, "*)XSBind_sv_to_cfish_obj($arg, ", vtable_var, ", NULL);\n\n", NULL); output = CFCUtil_cat(output, vtable_var, "_\n" " $arg = (SV*)Cfish_Obj_To_Host((cfish_Obj*)$var);\n" " CFISH_DECREF($var);\n" "\n", NULL); } char *content = CFCUtil_strdup(""); content = CFCUtil_cat(content, typemap_start, start, "\n\n", typemap_input, input, "\n\n", typemap_output, output, "\n\n", NULL); CFCUtil_write_if_changed("typemap", content, strlen(content)); FREEMEM(content); FREEMEM(output); FREEMEM(input); FREEMEM(start); FREEMEM(classes); }
char* CFCPerlPod_constructors_pod(CFCPerlPod *self, CFCClass *klass) { if (!self->num_constructors) { return CFCUtil_strdup(""); } const char *class_name = CFCClass_get_class_name(klass); char *pod = CFCUtil_strdup("=head1 CONSTRUCTORS\n\n"); for (size_t i = 0; i < self->num_constructors; i++) { NamePod slot = self->constructors[i]; if (slot.pod) { pod = CFCUtil_cat(pod, slot.pod, "\n", NULL); } else { CFCFunction *init_func = CFCClass_function(klass, slot.func); char *sub_pod = CFCPerlPod_gen_subroutine_pod(self, init_func, slot.alias, klass, slot.sample, class_name, true); pod = CFCUtil_cat(pod, sub_pod, NULL); FREEMEM(sub_pod); } } return pod; }
// Convert a node and its siblings. static char* S_nodes_to_pod(cmark_node *node, CFCClass *klass, int header_level) { char *result = CFCUtil_strdup(""); while (node != NULL) { char *pod = S_node_to_pod(node, klass, header_level); result = CFCUtil_cat(result, pod, NULL); FREEMEM(pod); node = cmark_node_next(node); } return result; }
char* CFCPerlSub_params_hash_def(CFCPerlSub *self) { if (!self->use_labeled_params) { return NULL; } char *def = CFCUtil_strdup(""); def = CFCUtil_cat(def, "%", self->perl_name, "_PARAMS = (", NULL); CFCVariable **arg_vars = CFCParamList_get_variables(self->param_list); const char **vals = CFCParamList_get_initial_values(self->param_list); // No labeled params means an empty params hash def. if (!arg_vars[1]) { def = CFCUtil_cat(def, ");\n", NULL); return def; } for (int i = 1; arg_vars[i] != NULL; i++) { CFCVariable *var = arg_vars[i]; const char *micro_sym = CFCVariable_micro_sym(var); const char *val = vals[i]; val = val == NULL ? "undef" : strcmp(val, "NULL") == 0 ? "undef" : strcmp(val, "true") == 0 ? "1" : strcmp(val, "false") == 0 ? "0" : val; def = CFCUtil_cat(def, "\n ", micro_sym, " => ", val, ",", NULL); } def = CFCUtil_cat(def, "\n);\n", NULL); return def; }
static char* S_gen_labeled_sample(const char *prologue, CFCParamList *param_list, int start) { int num_vars = CFCParamList_num_vars(param_list); CFCVariable **vars = CFCParamList_get_variables(param_list); const char **inits = CFCParamList_get_initial_values(param_list); size_t max_name_len = 0; // Find maximum length of parameter name. for (int i = start; i < num_vars; i++) { const char *name = CFCVariable_get_name(vars[i]); size_t name_len = strlen(name); if (name_len > max_name_len) { max_name_len = name_len; } } char *params = CFCUtil_strdup(""); for (int i = start; i < num_vars; i++) { const char *name = CFCVariable_get_name(vars[i]); const char *init = inits[i]; char *comment = NULL; if (init) { if (strcmp(init, "NULL") == 0) { init = "undef"; } comment = CFCUtil_sprintf("default: %s", init); } else { comment = CFCUtil_strdup("required"); } char *line = CFCUtil_sprintf(" %-*s => $%-*s # %s\n", (int)max_name_len, name, (int)max_name_len, name, comment); params = CFCUtil_cat(params, line, NULL); FREEMEM(line); FREEMEM(comment); } const char pattern[] = " %s(\n" "%s" " );\n"; char *sample = CFCUtil_sprintf(pattern, prologue, params); FREEMEM(params); return sample; }
static char* S_callback_refcount_mods(CFCMethod *method) { char *refcount_mods = CFCUtil_strdup(""); CFCType *return_type = CFCMethod_get_return_type(method); CFCParamList *param_list = CFCMethod_get_param_list(method); CFCVariable **arg_vars = CFCParamList_get_variables(param_list); // Host_callback_obj returns an incremented object. If this method does // not return an incremented object, we must cancel out that refcount. // (No function can return a decremented object.) if (CFCType_is_object(return_type) && !CFCType_incremented(return_type)) { refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_DECREF(retval);", NULL); } // The Host_callback_xxx functions have no effect on the refcounts of // arguments, so we need to adjust them after the fact. for (int i = 0; arg_vars[i] != NULL; i++) { CFCVariable *var = arg_vars[i]; CFCType *type = CFCVariable_get_type(var); const char *name = CFCVariable_micro_sym(var); if (!CFCType_is_object(type)) { continue; } else if (CFCType_incremented(type)) { refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_INCREF(", name, ");", NULL); } else if (CFCType_decremented(type)) { refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_DECREF(", name, ");", NULL); } } return refcount_mods; }
static char* S_callback_refcount_mods(CFCMethod *method) { char *refcount_mods = CFCUtil_strdup(""); CFCType *return_type = CFCMethod_get_return_type(method); CFCParamList *param_list = CFCMethod_get_param_list(method); CFCVariable **arg_vars = CFCParamList_get_variables(param_list); // `XSBind_perl_to_cfish()` returns an incremented object. If this method // does not return an incremented object, we must cancel out that // refcount. (No function can return a decremented object.) if (CFCType_is_object(return_type) && !CFCType_incremented(return_type)) { refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_DECREF(retval);", NULL); } // Adjust refcounts of arguments per method signature, so that Perl code // does not have to. for (int i = 0; arg_vars[i] != NULL; i++) { CFCVariable *var = arg_vars[i]; CFCType *type = CFCVariable_get_type(var); const char *name = CFCVariable_micro_sym(var); if (!CFCType_is_object(type)) { continue; } else if (CFCType_incremented(type)) { refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_INCREF(", name, ");", NULL); } else if (CFCType_decremented(type)) { refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_DECREF(", name, ");", NULL); } } return refcount_mods; }
char* CFCPerlSub_arg_name_list(CFCPerlSub *self) { CFCParamList *param_list = self->param_list; CFCVariable **arg_vars = CFCParamList_get_variables(param_list); size_t num_vars = CFCParamList_num_vars(param_list); char *name_list = CFCUtil_strdup("arg_self"); for (int i = 1; i < num_vars; i++) { CFCVariable *arg_var = arg_vars[i]; const char *var_name = CFCVariable_micro_sym(arg_vars[i]); name_list = CFCUtil_cat(name_list, ", arg_", var_name, NULL); } return name_list; }
static char* S_callback_decs(CFCClass *klass) { CFCMethod **fresh_methods = CFCClass_fresh_methods(klass); char *cb_decs = CFCUtil_strdup(""); for (int meth_num = 0; fresh_methods[meth_num] != NULL; meth_num++) { CFCMethod *method = fresh_methods[meth_num]; // Define callback to NULL. if (CFCMethod_novel(method) && !CFCMethod_final(method)) { const char *override_sym = CFCMethod_full_override_sym(method); cb_decs = CFCUtil_cat(cb_decs, "#define ", override_sym, " NULL\n", NULL); } } return cb_decs; }
static char* S_gen_arg_increfs(CFCParamList *param_list, int first_tick) { CFCVariable **vars = CFCParamList_get_variables(param_list); int num_vars = CFCParamList_num_vars(param_list); char *content = CFCUtil_strdup(""); for (int i = first_tick;i < num_vars; i++) { CFCType *type = CFCVariable_get_type(vars[i]); if (CFCType_decremented(type)) { const char *name = CFCVariable_get_name(vars[i]); const char *specifier = CFCType_get_specifier(type); char pattern[] = " %s_ARG = (%s*)CFISH_INCREF(%s_ARG);\n"; char *incref = CFCUtil_sprintf(pattern, name, specifier, name); content = CFCUtil_cat(content, incref, NULL); FREEMEM(incref); } } return content; }