int CFCMethod_compatible(CFCMethod *self, CFCMethod *other) { if (!other) { return false; } if (strcmp(self->macro_sym, other->macro_sym)) { return false; } int my_public = CFCMethod_public(self); int other_public = CFCMethod_public(other); if (!!my_public != !!other_public) { return false; } // Check arguments and initial values. CFCParamList *my_param_list = self->function.param_list; CFCParamList *other_param_list = other->function.param_list; CFCVariable **my_args = CFCParamList_get_variables(my_param_list); CFCVariable **other_args = CFCParamList_get_variables(other_param_list); const char **my_vals = CFCParamList_get_initial_values(my_param_list); const char **other_vals = CFCParamList_get_initial_values(other_param_list); for (size_t i = 1; ; i++) { // start at 1, skipping self if (!!my_args[i] != !!other_args[i]) { return false; } if (!!my_vals[i] != !!other_vals[i]) { return false; } if (my_vals[i]) { if (strcmp(my_vals[i], other_vals[i])) { return false; } } if (my_args[i]) { if (!CFCVariable_equals(my_args[i], other_args[i])) { return false; } } else { break; } } // Check return types. CFCType *type = CFCMethod_get_return_type(self); CFCType *other_type = CFCMethod_get_return_type(other); if (CFCType_is_object(type)) { // Weak validation to allow covariant object return types. if (!CFCType_is_object(other_type)) { return false; } if (!CFCType_similar(type, other_type)) { return false; } } else { if (!CFCType_equals(type, other_type)) { return false; } } return true; }
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; }
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; }
static void S_resolve(CFCUri *self, const char *parcel, const char *struct_sym, const char *callable) { // Try to find a CFCClass. CFCClass *doc_class = self->doc_class; CFCClass *klass = NULL; if (parcel) { char *full_struct_sym = CFCUtil_sprintf("%s_%s", parcel, struct_sym); klass = CFCClass_fetch_by_struct_sym(full_struct_sym); FREEMEM(full_struct_sym); } else if (struct_sym && doc_class) { const char *prefix = CFCClass_get_prefix(doc_class); char *full_struct_sym = CFCUtil_sprintf("%s%s", prefix, struct_sym); klass = CFCClass_fetch_by_struct_sym(full_struct_sym); FREEMEM(full_struct_sym); } else if (callable) { klass = doc_class; } if (klass) { if (!CFCClass_public(klass)) { CFCUtil_warn("Non-public class '%s' in Clownfish URI: %s", CFCClass_get_struct_sym(klass), self->string); } self->type = CFC_URI_CLASS; self->klass = klass; CFCBase_incref((CFCBase*)klass); if (callable) { if (islower(callable[0])) { CFCFunction *function = CFCClass_function(klass, callable); if (!function) { CFCUtil_warn("Unknown function '%s' in Clownfish URI: %s", callable, self->string); } else if (!CFCFunction_public(function)) { CFCUtil_warn("Non-public function '%s' in Clownfish URI:" " %s", callable, self->string); } self->type = CFC_URI_FUNCTION; self->callable = CFCUtil_strdup(callable); } else { CFCMethod *method = CFCClass_method(klass, callable); if (!method) { CFCUtil_warn("Unknown method '%s' in Clownfish URI: %s", callable, self->string); } else if (!CFCMethod_public(method)) { CFCUtil_warn("Non-public method '%s' in Clownfish URI:" " %s", callable, self->string); } self->type = CFC_URI_METHOD; self->callable = CFCUtil_strdup(callable); } } return; } // Try to find a CFCDocument. if (!parcel && struct_sym && !callable) { CFCDocument *doc = CFCDocument_fetch(struct_sym); if (doc) { self->type = CFC_URI_DOCUMENT; self->document = doc; CFCBase_incref((CFCBase*)doc); return; } } S_set_error(self, "Couldn't resolve Clownfish URI"); }