// 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;
}
Beispiel #2
0
char*
CFCBindMeth_abstract_method_def(CFCMethod *method) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *params = CFCParamList_to_c(param_list);
    const char *full_func_sym = CFCMethod_imp_func(method);
    const char *vtable_var
        = CFCType_get_vtable_var(CFCMethod_self_type(method));
    CFCType    *return_type  = CFCMethod_get_return_type(method);
    const char *ret_type_str = CFCType_to_c(return_type);
    const char *macro_sym    = CFCMethod_get_macro_sym(method);

    // Thwart compiler warnings.
    CFCVariable **param_vars = CFCParamList_get_variables(param_list);
    char *unused = S_build_unused_vars(param_vars + 1);
    char *return_statement = S_maybe_unreachable(return_type);

    char pattern[] =
        "%s\n"
        "%s(%s) {\n"
        "    cfish_String *klass = self ? CFISH_Obj_Get_Class_Name((cfish_Obj*)self) : %s->name;%s\n"
        "    CFISH_THROW(CFISH_ERR, \"Abstract method '%s' not defined by %%o\", klass);%s\n"
        "}\n";
    char *abstract_def
        = CFCUtil_sprintf(pattern, ret_type_str, full_func_sym, params,
                          vtable_var, unused, macro_sym, return_statement);

    FREEMEM(unused);
    FREEMEM(return_statement);
    return abstract_def;
}
Beispiel #3
0
char*
CFCBindMeth_novel_spec_def(CFCMethod *method) {
    const char *macro_sym = CFCMethod_get_macro_sym(method);
    const char *imp_func  = CFCMethod_imp_func(method);

    const char *full_override_sym = "NULL";
    if (!CFCMethod_final(method)) {
        full_override_sym = CFCMethod_full_override_sym(method);
    }

    char *full_offset_sym = CFCMethod_full_offset_sym(method, NULL);

    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, macro_sym, imp_func,
                          full_override_sym);

    FREEMEM(full_offset_sym);
    return def;
}
Beispiel #4
0
static char*
S_obj_callback_def(CFCMethod *method, const char *callback_params,
                   const char *refcount_mods) {
    const char *override_sym = CFCMethod_full_override_sym(method);
    const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method));
    CFCType *return_type = CFCMethod_get_return_type(method);
    const char *ret_type_str = CFCType_to_c(return_type);
    const char *cb_func_name = CFCType_is_string_type(return_type)
                               ? "cfish_Host_callback_str"
                               : "cfish_Host_callback_obj";

    char *nullable_check = CFCUtil_strdup("");
    if (!CFCType_nullable(return_type)) {
        const char *macro_sym = CFCMethod_get_macro_sym(method);
        char pattern[] =
            "\n    if (!retval) { CFISH_THROW(CFISH_ERR, "
            "\"%s() for class '%%o' cannot return NULL\", "
            "Cfish_Obj_Get_Class_Name((cfish_Obj*)self)); }";
        size_t size = sizeof(pattern) + strlen(macro_sym) + 30;
        nullable_check = (char*)REALLOCATE(nullable_check, size);
        sprintf(nullable_check, pattern, macro_sym);
    }

    char pattern[] =
        "%s\n"
        "%s(%s) {\n"
        "    %s retval = (%s)%s(%s);%s%s\n"
        "    return retval;\n"
        "}\n";
    size_t size = sizeof(pattern)
                  + strlen(ret_type_str)
                  + strlen(override_sym)
                  + strlen(params)
                  + strlen(ret_type_str)
                  + strlen(ret_type_str)
                  + strlen(cb_func_name)
                  + strlen(callback_params)
                  + strlen(nullable_check)
                  + strlen(refcount_mods)
                  + 30;
    char *callback_def = (char*)MALLOCATE(size);
    sprintf(callback_def, pattern, ret_type_str, override_sym, params,
            ret_type_str, ret_type_str, cb_func_name, callback_params,
            nullable_check, refcount_mods);

    FREEMEM(nullable_check);
    return callback_def;
}
Beispiel #5
0
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;
}
Beispiel #6
0
static void
S_bequeath_methods(CFCClass *self) {
    for (size_t child_num = 0; self->children[child_num] != NULL; child_num++) {
        CFCClass *child = self->children[child_num];

        // Create array of methods, preserving exact order so vtables match up.
        size_t num_methods = 0;
        size_t max_methods = self->num_methods + child->num_methods;
        CFCMethod **methods = (CFCMethod**)MALLOCATE(
                                  (max_methods + 1) * sizeof(CFCMethod*));

        // Gather methods which child inherits or overrides.
        for (size_t i = 0; i < self->num_methods; i++) {
            CFCMethod *method = self->methods[i];
            const char *macro_sym = CFCMethod_get_macro_sym(method);
            CFCMethod *child_method = CFCClass_method(child, macro_sym);
            if (child_method) {
                CFCMethod_override(child_method, method);
                methods[num_methods++] = child_method;
            }
            else {
                methods[num_methods++] = method;
            }
        }

        // Append novel child methods to array.  Child methods which were just
        // marked via CFCMethod_override() a moment ago are skipped.
        for (size_t i = 0; i < child->num_methods; i++) {
            CFCMethod *method = child->methods[i];
            if (CFCMethod_novel(method)) {
                methods[num_methods++] = method;
            }
        }
        methods[num_methods] = NULL;

        // Manage refcounts and assign new array.  Transform to final methods
        // if child class is a final class.
        if (child->is_final) {
            for (size_t i = 0; i < num_methods; i++) {
                if (CFCMethod_final(methods[i])) {
                    CFCBase_incref((CFCBase*)methods[i]);
                }
                else {
                    methods[i] = CFCMethod_finalize(methods[i]);
                }
            }
        }
        else {
            for (size_t i = 0; i < num_methods; i++) {
                CFCBase_incref((CFCBase*)methods[i]);
            }
        }
        for (size_t i = 0; i < child->num_methods; i++) {
            CFCBase_decref((CFCBase*)child->methods[i]);
        }
        FREEMEM(child->methods);
        child->methods     = methods;
        child->num_methods = num_methods;

        // Pass it all down to the next generation.
        S_bequeath_methods(child);
        child->tree_grown = true;
    }
}