void CFCMethod_set_host_alias(CFCMethod *self, const char *alias) { if (!alias || !alias[0]) { CFCUtil_die("Missing required param 'alias'"); } if (!self->is_novel) { CFCUtil_die("Can't set_host_alias %s -- method %s not novel in %s", alias, self->macro_sym, CFCMethod_get_class_name(self)); } if (self->host_alias) { if (strcmp(self->host_alias, alias) == 0) { return; } CFCUtil_die("Can't set_host_alias %s -- already set to %s for method" " %s in %s", alias, self->host_alias, self->macro_sym, CFCMethod_get_class_name(self)); } self->host_alias = CFCUtil_strdup(alias); }
void CFCMethod_exclude_from_host(CFCMethod *self) { if (!self->is_novel) { CFCUtil_die("Can't exclude_from_host -- method %s not novel in %s", self->macro_sym, CFCMethod_get_class_name(self)); } self->is_excluded = true; }
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; }
CFCMethod* CFCClass_fresh_method(CFCClass *self, const char *sym) { CFCMethod *method = CFCClass_method(self, sym); if (method) { const char *class_name = CFCClass_get_class_name(self); const char *meth_class_name = CFCMethod_get_class_name(method); if (strcmp(class_name, meth_class_name) == 0) { return method; } } return NULL; }
CFCMethod* CFCMethod_finalize(CFCMethod *self) { CFCParcel *parcel = CFCMethod_get_parcel(self); const char *exposure = CFCMethod_get_exposure(self); const char *class_name = CFCMethod_get_class_name(self); const char *class_cnick = CFCMethod_get_class_cnick(self); CFCMethod *finalized = CFCMethod_new(parcel, exposure, class_name, class_cnick, self->macro_sym, self->function.return_type, self->function.param_list, self->function.docucomment, true, self->is_abstract); finalized->is_novel = self->is_novel; return finalized; }
void CFCPerlClass_exclude_method(CFCPerlClass *self, const char *meth_name) { if (!self->client) { CFCUtil_die("Can't exclude_method %s -- can't find client for %s", meth_name, self->class_name); } CFCMethod *method = CFCClass_method(self->client, meth_name); if (!method) { CFCUtil_die("Can't exclude_method %s -- method not found in %s", meth_name, self->class_name); } if (strcmp(CFCMethod_get_class_name(method), self->class_name) != 0) { CFCUtil_die("Can't exclude_method %s -- method not fresh in %s", meth_name, self->class_name); } CFCMethod_exclude_from_host(method); }
void CFCPerlClass_bind_method(CFCPerlClass *self, const char *alias, const char *meth_name) { if (!self->client) { CFCUtil_die("Can't bind_method %s -- can't find client for %s", alias, self->class_name); } CFCMethod *method = CFCClass_method(self->client, meth_name); if (!method) { CFCUtil_die("Can't bind_method %s -- can't find method %s in %s", alias, meth_name, self->class_name); } if (strcmp(CFCMethod_get_class_name(method), self->class_name) != 0) { CFCUtil_die("Can't bind_method %s -- method %s not fresh in %s", alias, meth_name, self->class_name); } CFCMethod_set_host_alias(method, alias); }
CFCPerlMethod* CFCPerlMethod_init(CFCPerlMethod *self, CFCMethod *method, const char *alias) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *class_name = CFCMethod_get_class_name(method); int use_labeled_params = CFCParamList_num_vars(param_list) > 2 ? 1 : 0; // The Clownfish destructor needs to be spelled DESTROY for Perl. if (!alias) { alias = CFCMethod_micro_sym(method); } static const char destroy_uppercase[] = "DESTROY"; if (strcmp(alias, "destroy") == 0) { alias = destroy_uppercase; } CFCPerlSub_init((CFCPerlSub*)self, param_list, class_name, alias, use_labeled_params); self->method = (CFCMethod*)CFCBase_incref((CFCBase*)method); return self; }
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; }