static char* S_meth_top(CFCMethod *method) { CFCParamList *param_list = CFCMethod_get_param_list(method); if (CFCParamList_num_vars(param_list) == 1) { char pattern[] = "(PyObject *self, PyObject *unused) {\n" " CFISH_UNUSED_VAR(unused);\n" ; return CFCUtil_sprintf(pattern); } else { char *error = NULL; char *arg_parsing = S_gen_arg_parsing(param_list, 1, &error); if (error) { CFCUtil_die("%s in %s", error, CFCMethod_get_name(method)); } if (!arg_parsing) { return NULL; } char *decs = S_gen_decs(param_list, 1); char pattern[] = "(PyObject *self, PyObject *args, PyObject *kwargs) {\n" "%s" // decs "%s" ; char *result = CFCUtil_sprintf(pattern, decs, arg_parsing); FREEMEM(arg_parsing); return result; } }
void CFCGoClass_spec_method(CFCGoClass *self, const char *name, const char *sig) { CFCUTIL_NULL_CHECK(sig); S_lazy_init_method_bindings(self); if (!name) { CFCGoMethod *meth_binding = CFCGoMethod_new(NULL); CFCGoMethod_customize(meth_binding, sig); size_t size = (self->num_bound + 2) * sizeof(CFCGoMethod*); self->method_bindings = (CFCGoMethod**)REALLOCATE(self->method_bindings, size); self->method_bindings[self->num_bound] = meth_binding; self->num_bound++; self->method_bindings[self->num_bound] = NULL; } else { CFCGoMethod *binding = NULL; for (int i = 0; self->method_bindings[i] != NULL; i++) { CFCGoMethod *candidate = self->method_bindings[i]; CFCMethod *meth = CFCGoMethod_get_client(candidate); if (meth && strcmp(name, CFCMethod_get_name(meth)) == 0) { binding = candidate; break; } } if (!binding) { CFCUtil_die("Can't find a method named '%s'", name); } CFCGoMethod_customize(binding, sig); } }
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* 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; }
static void S_lazy_init_method_bindings(CFCGoClass *self) { if (self->method_bindings) { return; } CFCUTIL_NULL_CHECK(self->client); size_t num_bound = 0; CFCMethod **fresh_methods = CFCClass_fresh_methods(self->client); CFCGoMethod **bound = (CFCGoMethod**)CALLOCATE(1, sizeof(CFCGoMethod*)); // Iterate over the class's fresh methods. for (size_t i = 0; fresh_methods[i] != NULL; i++) { CFCMethod *method = fresh_methods[i]; // Skip methods which have been explicitly excluded. if (CFCMethod_excluded_from_host(method)) { continue; } // Skip methods that shouldn't be bound. if (!CFCMethod_can_be_bound(method)) { continue; } // Only include novel methods. if (!CFCMethod_novel(method)) { continue; } const char *sym = CFCMethod_get_name(method); if (!CFCClass_fresh_method(self->client, sym)) { continue; } /* Create the binding, add it to the array. */ CFCGoMethod *meth_binding = CFCGoMethod_new(method); size_t size = (num_bound + 2) * sizeof(CFCGoMethod*); bound = (CFCGoMethod**)REALLOCATE(bound, size); bound[num_bound] = meth_binding; num_bound++; bound[num_bound] = NULL; } self->method_bindings = bound; self->num_bound = num_bound; }
char* CFCGoClass_go_typing(CFCGoClass *self) { char *content = NULL; if (!self->client) { CFCUtil_die("Can't find class for %s", self->class_name); } else if (CFCClass_inert(self->client)) { content = CFCUtil_strdup(""); } else { const char *short_struct = CFCClass_get_struct_sym(self->client); CFCClass *parent = CFCClass_get_parent(self->client); char *parent_type_str = NULL; if (parent) { const char *parent_struct = CFCClass_get_struct_sym(parent); CFCParcel *parent_parcel = CFCClass_get_parcel(parent); if (parent_parcel == self->parcel) { parent_type_str = CFCUtil_strdup(parent_struct); } else { char *parent_package = CFCGoTypeMap_go_short_package(parent_parcel); parent_type_str = CFCUtil_sprintf("%s.%s", parent_package, parent_struct); FREEMEM(parent_package); } } char *go_struct_def; if (parent && !self->suppress_struct) { go_struct_def = CFCUtil_sprintf("type %sIMP struct {\n\t%sIMP\n}\n", short_struct, parent_type_str); } else { go_struct_def = CFCUtil_strdup(""); } char *parent_iface; if (parent) { parent_iface = CFCUtil_sprintf("\t%s\n", parent_type_str); } else { parent_iface = CFCUtil_strdup(""); } char *novel_iface = CFCUtil_strdup(""); S_lazy_init_method_bindings(self); for (int i = 0; self->method_bindings[i] != NULL; i++) { CFCGoMethod *meth_binding = self->method_bindings[i]; CFCMethod *method = CFCGoMethod_get_client(meth_binding); if (method) { if (!CFCMethod_novel(method)) { continue; } const char *sym = CFCMethod_get_name(method); if (!CFCClass_fresh_method(self->client, sym)) { continue; } } const char *sig = CFCGoMethod_get_sig(meth_binding, self->client); novel_iface = CFCUtil_cat(novel_iface, "\t", sig, "\n", NULL); } char pattern[] = "type %s interface {\n" "%s" "%s" "}\n" "\n" "%s" ; content = CFCUtil_sprintf(pattern, short_struct, parent_iface, novel_iface, go_struct_def); FREEMEM(parent_type_str); FREEMEM(go_struct_def); FREEMEM(parent_iface); } return content; }
char* CFCPerlPod_methods_pod(CFCPerlPod *self, CFCClass *klass) { const char *class_name = CFCClass_get_name(klass); char *abstract_pod = CFCUtil_strdup(""); char *methods_pod = CFCUtil_strdup(""); // Start with methods that don't map to a Clownfish method. 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) { continue; } if (!meth_spec.pod) { CFCUtil_die("No POD specified for method '%s' in class '%s'", meth_spec.alias, CFCClass_get_name(klass)); } methods_pod = CFCUtil_cat(methods_pod, meth_spec.pod, "\n", NULL); } CFCMethod **fresh_methods = CFCClass_fresh_methods(klass); for (int meth_num = 0; fresh_methods[meth_num] != NULL; meth_num++) { CFCMethod *method = fresh_methods[meth_num]; const char *name = CFCMethod_get_name(method); char *meth_pod = NULL; // Try to find custom POD for method. NamePod *meth_spec = NULL; for (size_t j = 0; j < self->num_methods; j++) { NamePod *candidate = &self->methods[j]; const char *other_name = candidate->func; if (other_name && strcmp(other_name, name) == 0) { meth_spec = candidate; break; } } if (meth_spec) { // Found custom POD. if (meth_spec->pod) { meth_pod = CFCUtil_sprintf("%s\n", meth_spec->pod); } else { meth_pod = CFCPerlPod_gen_subroutine_pod((CFCCallable*)method, meth_spec->alias, klass, meth_spec->sample, class_name, false); } } else { // No custom POD found. Add POD for public methods with Perl // bindings. if (!CFCMethod_public(method) || CFCMethod_excluded_from_host(method) || !CFCMethod_can_be_bound(method) ) { continue; } // Only add POD for novel methods and the first implementation // of abstract methods. if (!CFCMethod_novel(method)) { if (CFCMethod_abstract(method)) { continue; } CFCClass *parent = CFCClass_get_parent(klass); CFCMethod *parent_method = CFCClass_method(parent, name); if (!CFCMethod_abstract(parent_method)) { continue; } } char *perl_name = CFCPerlMethod_perl_name(method); meth_pod = CFCPerlPod_gen_subroutine_pod((CFCCallable*)method, perl_name, klass, NULL, class_name, false); FREEMEM(perl_name); } 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; }