Exemple #1
0
char*
CFCPyMethod_callback_def(CFCMethod *method, CFCClass *invoker) {
    CFCParamList *param_list   = CFCMethod_get_param_list(method);
    CFCVariable **vars         = CFCParamList_get_variables(param_list);
    CFCType      *return_type  = CFCMethod_get_return_type(method);
    const char   *ret_type_str = CFCType_to_c(return_type);
    const char   *params       = CFCParamList_to_c(param_list);
    char         *override_sym = CFCMethod_full_override_sym(method, invoker);
    char *content;

    if (CFCMethod_can_be_bound(method)) {
        char *py_args = S_build_py_args(param_list);
        char *invocation = S_build_pymeth_invocation(method);
        char *refcount_mods = S_callback_refcount_mods(param_list);
        const char *maybe_return = CFCType_is_void(return_type)
                                   ? ""
                                   : "    return cfcb_RESULT;\n";

        const char pattern[] =
            "%s\n"
            "%s(%s) {\n"
            "%s\n"
            "%s\n"
            "%s"
            "%s"
            "}\n";
        content = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params,
                                  py_args, invocation, refcount_mods,
                                  maybe_return);
    }
    else {
        char *unused = S_build_unused_vars(vars);
        char *unreachable = S_maybe_unreachable(return_type);
        char *meth_sym = CFCMethod_full_method_sym(method, invoker);
        const char pattern[] =
            "%s\n"
            "%s(%s) {%s\n"
            "    CFISH_THROW(CFISH_ERR, \"Can't override %s via binding\");%s\n"
            "}\n";
        content = CFCUtil_sprintf(pattern, ret_type_str, override_sym,
                                  params, unused, meth_sym, unreachable);
        FREEMEM(meth_sym);
        FREEMEM(unused);
        FREEMEM(unreachable);
    }

    FREEMEM(override_sym);
    return content;
}
Exemple #2
0
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*
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;
}