Beispiel #1
0
static CFCClass*
S_class_by_struct_sym_prereq(CFCParcel *self, const char *struct_sym,
                             size_t prefix_len) {
    CFCClass *klass = S_class_by_struct_sym(self, struct_sym, prefix_len);
    if (klass && prefix_len != 0) { return klass; }

    for (size_t i = 0; self->prereqs[i]; ++i) {
        const char *prereq_name   = CFCPrereq_get_name(self->prereqs[i]);
        CFCParcel  *prereq_parcel = CFCParcel_fetch(prereq_name);
        CFCClass *candidate
            = S_class_by_struct_sym(prereq_parcel, struct_sym, prefix_len);

        if (candidate) {
            if (prefix_len != 0) { return candidate; }
            if (klass) {
                CFCUtil_warn("Type '%s' is ambiguous. Do you mean %s or %s?",
                             struct_sym, CFCClass_full_struct_sym(klass),
                             CFCClass_full_struct_sym(candidate));
                return NULL;
            }
            klass = candidate;
        }
    }

    return klass;
}
Beispiel #2
0
static char*
S_ivars_size(CFCClass *klass) {
    CFCParcel *parcel = CFCClass_get_parcel(klass);
    char *ivars_size = NULL;

    if (CFCParcel_is_cfish(parcel)) {
        const char *struct_sym   = CFCClass_full_struct_sym(klass);
        ivars_size = CFCUtil_sprintf("sizeof(%s)", struct_sym);
    }
    else {
        size_t num_non_package_ivars = CFCClass_num_non_package_ivars(klass);
        size_t num_ivars             = CFCClass_num_member_vars(klass);

        if (num_non_package_ivars == num_ivars) {
            // No members in this package.
            ivars_size = CFCUtil_strdup("0");
        }
        else {
            const char *ivars_struct = CFCClass_full_ivars_struct(klass);
            ivars_size = CFCUtil_sprintf("sizeof(%s)", ivars_struct);
        }
    }

    return ivars_size;
}
Beispiel #3
0
static void
S_add_tree(CFCHierarchy *self, CFCClass *klass) {
    CFCUTIL_NULL_CHECK(klass);
    const char *full_struct_sym = CFCClass_full_struct_sym(klass);
    for (size_t i = 0; self->trees[i] != NULL; i++) {
        const char *existing = CFCClass_full_struct_sym(self->trees[i]);
        if (strcmp(full_struct_sym, existing) == 0) {
            CFCUtil_die("Tree '%s' alread added", full_struct_sym);
        }
    }
    self->num_trees++;
    size_t size = (self->num_trees + 1) * sizeof(CFCClass*);
    self->trees = (CFCClass**)REALLOCATE(self->trees, size);
    self->trees[self->num_trees - 1]
        = (CFCClass*)CFCBase_incref((CFCBase*)klass);
    self->trees[self->num_trees] = NULL;
}
Beispiel #4
0
void
CFCC_write_man_pages(CFCC *self) {
    CFCHierarchy  *hierarchy = self->hierarchy;
    CFCClass     **ordered   = CFCHierarchy_ordered_classes(hierarchy);

    size_t num_classes = 0;
    for (size_t i = 0; ordered[i] != NULL; i++) {
        CFCClass *klass = ordered[i];
        if (!CFCClass_included(klass)) { ++num_classes; }
    }
    char **man_pages = (char**)CALLOCATE(num_classes, sizeof(char*));

    // Generate man pages, but don't write.  That way, if there's an error
    // while generating the pages, we leak memory but don't clutter up the file 
    // system.
    for (size_t i = 0, j = 0; ordered[i] != NULL; i++) {
        CFCClass *klass = ordered[i];
        if (CFCClass_included(klass)) { continue; }

        char *man_page = CFCCMan_create_man_page(klass);
        man_pages[j++] = man_page;
    }

    const char *dest = CFCHierarchy_get_dest(hierarchy);
    char *man3_path
        = CFCUtil_sprintf("%s" CHY_DIR_SEP "man" CHY_DIR_SEP "man3", dest);
    if (!CFCUtil_is_dir(man3_path)) {
        CFCUtil_make_path(man3_path);
        if (!CFCUtil_is_dir(man3_path)) {
            CFCUtil_die("Can't make path %s", man3_path);
        }
    }

    // Write out any man pages that have changed.
    for (size_t i = 0, j = 0; ordered[i] != NULL; i++) {
        CFCClass *klass = ordered[i];
        if (CFCClass_included(klass)) { continue; }

        char *raw_man_page = man_pages[j++];
        if (!raw_man_page) { continue; }
        char *man_page = CFCUtil_sprintf("%s%s%s", self->man_header,
                                         raw_man_page, self->man_footer);

        const char *full_struct_sym = CFCClass_full_struct_sym(klass);
        char *filename = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.3", man3_path,
                                         full_struct_sym);
        CFCUtil_write_if_changed(filename, man_page, strlen(man_page));
        FREEMEM(filename);
        FREEMEM(man_page);
        FREEMEM(raw_man_page);
    }

    FREEMEM(man3_path);
    FREEMEM(man_pages);
    FREEMEM(ordered);
}
Beispiel #5
0
void
CFCType_resolve(CFCType *self, CFCClass **classes) {
    if (CFCType_is_composite(self)) {
        CFCType_resolve(self->child, classes);
        return;
    }
    if (!CFCType_is_object(self)) {
        return;
    }

    CFCClass *klass     = NULL;
    char     *specifier = self->specifier;

    if (isupper(self->specifier[0])) {
        // Try to find class from class list.
        for (size_t i = 0; classes[i]; ++i) {
            CFCClass   *maybe_class = classes[i];
            const char *struct_sym  = CFCClass_get_struct_sym(maybe_class);

            if (strcmp(specifier, struct_sym) == 0) {
                if (klass) {
                    CFCUtil_die("Type '%s' is ambigious", specifier);
                }
                klass = maybe_class;
            }
        }

        if (!klass) {
            CFCUtil_die("No class found for type '%s'", specifier);
        }

        // Create actual specifier with prefix.
        const char *prefix = CFCClass_get_prefix(klass);
        self->specifier = CFCUtil_sprintf("%s%s", prefix, specifier);
        FREEMEM(specifier);
    }
    else {
        // Try to find class from class list.
        for (size_t i = 0; classes[i]; ++i) {
            CFCClass *maybe_class = classes[i];
            const char *full_struct_sym
                = CFCClass_full_struct_sym(maybe_class);

            if (strcmp(specifier, full_struct_sym) == 0) {
                klass = maybe_class;
                break;
            }
        }
    }

    // Add parcel dependency.
    if (klass) {
        CFCParcel *class_parcel = CFCClass_get_parcel(klass);
        CFCParcel_add_dependent_parcel(self->parcel, class_parcel);
    }
}
Beispiel #6
0
char*
CFCPyMethod_constructor_wrapper(CFCFunction *init_func, CFCClass *invoker) {
    CFCParamList *param_list  = CFCFunction_get_param_list(init_func);
    const char *self_type
        = CFCType_to_c(CFCFunction_get_return_type(init_func));
    char *func_sym   = CFCFunction_full_func_sym(init_func, invoker);
    char *decs       = S_gen_decs(param_list, 1);
    char *increfs    = S_gen_arg_increfs(param_list, 1);
    char *decrefs    = S_gen_decrefs(param_list, 1);
    const char *class_var  = CFCClass_full_class_var(invoker);
    const char *struct_sym = CFCClass_full_struct_sym(invoker);
    char *error = NULL;
    char *arg_parsing = S_gen_arg_parsing(param_list, 1, &error);
    if (error) {
        CFCUtil_die("%s in constructor for %s", error,
                    CFCClass_get_name(invoker));
    }
    if (!arg_parsing) {
        CFCUtil_die("Unexpected arg parsing error for %s",
                    CFCClass_get_name(invoker));
    }
    char *first_arg = CFCUtil_sprintf("(%s)CFISH_Class_Make_Obj(%s)",
                                      self_type, class_var);
    char *arg_list = S_gen_arg_list(param_list, first_arg);

    char pattern[] =
        "static PyObject*\n"
        "S_%s_PY_NEW(PyTypeObject *type, PyObject *args, PyObject *kwargs) {\n"
        "%s" // decs
        "%s" // arg_parsing
        "%s" // increfs
        "    %s self = NULL;\n"
        "    CFBIND_TRY(self = %s(%s));\n"
        "%s" // decrefs
        "    if (CFBind_migrate_cferr()) {\n"
        "        return NULL;\n"
        "    }\n"
        "    return (PyObject*)self;\n"
        "}\n"
        ;
    char *wrapper = CFCUtil_sprintf(pattern, struct_sym, decs,
                                    arg_parsing, increfs, self_type,
                                    func_sym, arg_list, decrefs);

    FREEMEM(arg_list);
    FREEMEM(first_arg);
    FREEMEM(func_sym);
    FREEMEM(decrefs);
    FREEMEM(increfs);
    FREEMEM(decs);
    FREEMEM(arg_parsing);
    return wrapper;
}
char*
CFCBindMeth_typedef_dec(struct CFCMethod *method, CFCClass *klass) {
    const char *params_end
        = CFCParamList_to_c(CFCMethod_get_param_list(method));
    while (*params_end && *params_end != '*') {
        params_end++;
    }
    const char *self_struct = CFCClass_full_struct_sym(klass);
    const char *ret_type = CFCType_to_c(CFCMethod_get_return_type(method));
    char *full_typedef = CFCMethod_full_typedef(method, klass);
    char *buf = CFCUtil_sprintf("typedef %s\n(*%s)(%s%s);\n", ret_type,
                                full_typedef, self_struct,
                                params_end);
    FREEMEM(full_typedef);
    return buf;
}
Beispiel #8
0
static char*
S_virtual_method_def(CFCMethod *method, CFCClass *klass) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *PREFIX         = CFCClass_get_PREFIX(klass);
    const char *invoker_struct = CFCClass_full_struct_sym(klass);

    char *full_meth_sym   = CFCMethod_full_method_sym(method, klass);
    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
    char *full_typedef    = CFCMethod_full_typedef(method, klass);

    // Prepare parameter lists, minus invoker.  The invoker gets forced to
    // "self" later.
    if (CFCParamList_variadic(param_list)) {
        CFCUtil_die("Variadic methods not supported");
    }
    const char *arg_names_minus_invoker = CFCParamList_name_list(param_list);
    const char *params_minus_invoker    = CFCParamList_to_c(param_list);
    while (*arg_names_minus_invoker && *arg_names_minus_invoker != ',') {
        arg_names_minus_invoker++;
    }
    while (*params_minus_invoker && *params_minus_invoker != ',') {
        params_minus_invoker++;
    }

    // Prepare a return statement... or not.
    CFCType *return_type = CFCMethod_get_return_type(method);
    const char *ret_type_str = CFCType_to_c(return_type);
    const char *maybe_return = CFCType_is_void(return_type) ? "" : "return ";

    const char pattern[] =
        "extern %sVISIBLE size_t %s;\n"
        "static CFISH_INLINE %s\n"
        "%s(%s *self%s) {\n"
        "    const %s method = (%s)cfish_obj_method(self, %s);\n"
        "    %smethod(self%s);\n"
        "}\n";
    char *method_def
        = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str,
                          full_meth_sym, invoker_struct, params_minus_invoker,
                          full_typedef, full_typedef, full_offset_sym,
                          maybe_return, arg_names_minus_invoker);

    FREEMEM(full_offset_sym);
    FREEMEM(full_meth_sym);
    FREEMEM(full_typedef);
    return method_def;
}
Beispiel #9
0
static CFCMethod*
S_make_method_obj(CFCClass *klass, const char *method_name) {
    const char *klass_full_struct_sym = CFCClass_full_struct_sym(klass);
    const char *klass_name   = CFCClass_get_class_name(klass);
    const char *klass_cnick  = CFCClass_get_cnick(klass);
    CFCParcel  *klass_parcel = CFCClass_get_parcel(klass);

    CFCType *return_type = CFCType_new_object(CFCTYPE_INCREMENTED,
                                              klass_parcel, "cfish_Obj", 1);
    CFCType *self_type = CFCType_new_object(0, klass_parcel,
                                            klass_full_struct_sym, 1);
    CFCVariable *self_var = CFCVariable_new(NULL, NULL, NULL, NULL, "self",
                                            self_type, false);
    CFCParamList *param_list = NULL;

    if (strcmp(method_name, "Dump") == 0) {
        param_list = CFCParamList_new(false);
        CFCParamList_add_param(param_list, self_var, NULL);
    }
    else if (strcmp(method_name, "Load") == 0) {
        CFCType *dump_type = CFCType_new_object(0, klass_parcel, "cfish_Obj",
                                                1);
        CFCVariable *dump_var = CFCVariable_new(NULL, NULL, NULL, NULL, "dump",
                                                dump_type, false);
        param_list = CFCParamList_new(false);
        CFCParamList_add_param(param_list, self_var, NULL);
        CFCParamList_add_param(param_list, dump_var, NULL);
        CFCBase_decref((CFCBase*)dump_var);
        CFCBase_decref((CFCBase*)dump_type);
    }
    else {
        CFCUtil_die("Unexpected method_name: '%s'", method_name);
    }

    CFCMethod *method = CFCMethod_new(klass_parcel, "public", klass_name,
                                      klass_cnick, method_name, return_type,
                                      param_list, NULL, false, false);

    CFCBase_decref((CFCBase*)param_list);
    CFCBase_decref((CFCBase*)self_type);
    CFCBase_decref((CFCBase*)self_var);
    CFCBase_decref((CFCBase*)return_type);

    return method;
}
Beispiel #10
0
static char*
S_gen_meth_invocation(CFCMethod *method, CFCClass *invoker) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    char *full_meth = CFCMethod_full_method_sym(method, invoker);
    char *meth_type_c = CFCMethod_full_typedef(method, invoker);
    const char *class_var = CFCClass_full_class_var(invoker);
    char *first_arg
        = CFCUtil_sprintf("(%s*)self", CFCClass_full_struct_sym(invoker));
    char *arg_list = S_gen_arg_list(param_list, first_arg);

    CFCType *return_type = CFCMethod_get_return_type(method);
    char *maybe_declare;
    const char *maybe_assign;
    if (CFCType_is_void(return_type)) {
        maybe_declare = CFCUtil_strdup("");
        maybe_assign = "";
    }
    else {
        maybe_declare = CFCUtil_sprintf("    %s retvalCF;\n",
                                        CFCType_to_c(return_type));
        maybe_assign = "retvalCF = ";
    }

    const char pattern[] =
        "%s"
        "    %s method = CFISH_METHOD_PTR(%s, %s);\n"
        "    CFBIND_TRY(%smethod(%s));\n"
        ;
    char *content
        = CFCUtil_sprintf(pattern, maybe_declare, meth_type_c, class_var,
                          full_meth, maybe_assign, arg_list);

    FREEMEM(arg_list);
    FREEMEM(first_arg);
    FREEMEM(maybe_declare);
    FREEMEM(full_meth);
    FREEMEM(meth_type_c);
    return content;
}
Beispiel #11
0
void
CFCPerlTypeMap_write_xs_typemap(CFCHierarchy *hierarchy) {
    CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy);
    char *start  = CFCUtil_strdup("");
    char *input  = CFCUtil_strdup("");
    char *output = CFCUtil_strdup("");
    for (int i = 0; classes[i] != NULL; i++) {
        CFCClass *klass = classes[i];
        if (CFCClass_included(klass)) { continue; }

        const char *full_struct_sym = CFCClass_full_struct_sym(klass);
        const char *vtable_var      = CFCClass_full_vtable_var(klass);

        start = CFCUtil_cat(start, full_struct_sym, "*\t", vtable_var, "_\n",
                            NULL);
        input = CFCUtil_cat(input, vtable_var, "_\n"
                            "    $var = (", full_struct_sym,
                            "*)XSBind_sv_to_cfish_obj($arg, ", vtable_var,
                            ", NULL);\n\n", NULL);

        output = CFCUtil_cat(output, vtable_var, "_\n"
                             "    $arg = (SV*)Cfish_Obj_To_Host((cfish_Obj*)$var);\n"
                             "    CFISH_DECREF($var);\n"
                             "\n", NULL);
    }

    char *content = CFCUtil_strdup("");
    content = CFCUtil_cat(content, typemap_start, start, "\n\n",
                          typemap_input, input, "\n\n",
                          typemap_output, output, "\n\n", NULL);
    CFCUtil_write_if_changed("typemap", content, strlen(content));

    FREEMEM(content);
    FREEMEM(output);
    FREEMEM(input);
    FREEMEM(start);
    FREEMEM(classes);
}
static char*
S_method_def(CFCMethod *method, CFCClass *klass, int optimized_final_meth) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *PREFIX         = CFCClass_get_PREFIX(klass);
    const char *invoker_struct = CFCClass_full_struct_sym(klass);
    const char *self_name      = CFCParamList_param_name(param_list, 0);

    char *full_meth_sym   = CFCMethod_full_method_sym(method, klass);
    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
    char *full_typedef    = CFCMethod_full_typedef(method, klass);
    char *full_imp_sym    = CFCMethod_imp_func(method, klass);

    // Prepare parameter lists, minus the type of the invoker.
    if (CFCParamList_variadic(param_list)) {
        CFCUtil_die("Variadic methods not supported");
    }
    const char *arg_names  = CFCParamList_name_list(param_list);
    const char *params_end = CFCParamList_to_c(param_list);
    while (*params_end && *params_end != '*') {
        params_end++;
    }

    // Prepare a return statement... or not.
    CFCType *return_type = CFCMethod_get_return_type(method);
    const char *ret_type_str = CFCType_to_c(return_type);
    const char *maybe_return = CFCType_is_void(return_type) ? "" : "return ";

    const char innards_pattern[] =
        "    const %s method = (%s)cfish_obj_method(%s, %s);\n"
        "    %smethod(%s);\n"
        ;
    char *innards = CFCUtil_sprintf(innards_pattern, full_typedef,
                                    full_typedef, self_name, full_offset_sym,
                                    maybe_return, arg_names);
    if (optimized_final_meth) {
        CFCParcel  *parcel = CFCClass_get_parcel(klass);
        const char *privacy_sym = CFCParcel_get_privacy_sym(parcel);
        char *invoker_cast = CFCUtil_strdup("");
        if (!CFCMethod_is_fresh(method, klass)) {
            CFCType *self_type = CFCMethod_self_type(method);
            invoker_cast = CFCUtil_cat(invoker_cast, "(",
                                       CFCType_to_c(self_type), ")", NULL);
        }
        const char pattern[] =
            "#ifdef %s\n"
            "    %s%s(%s%s);\n"
            "#else\n"
            "%s"
            "#endif\n"
            ;
        char *temp = CFCUtil_sprintf(pattern, privacy_sym,
                                     maybe_return, full_imp_sym,
                                     invoker_cast, arg_names, innards);
        FREEMEM(innards);
        innards = temp;
        FREEMEM(invoker_cast);
    }

    const char pattern[] =
        "extern %sVISIBLE uint32_t %s;\n"
        "static CFISH_INLINE %s\n"
        "%s(%s%s) {\n"
        "%s"
        "}\n";
    char *method_def
        = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str,
                          full_meth_sym, invoker_struct, params_end, innards);

    FREEMEM(innards);
    FREEMEM(full_imp_sym);
    FREEMEM(full_offset_sym);
    FREEMEM(full_meth_sym);
    FREEMEM(full_typedef);
    return method_def;
}
Beispiel #13
0
char*
CFCC_link_text(CFCUri *uri_obj, CFCClass *klass) {
    char *link_text = NULL;
    int   type      = CFCUri_get_type(uri_obj);

    switch (type) {
        case CFC_URI_CLASS: {
            if (strcmp(CFCUri_get_prefix(uri_obj),
                       CFCClass_get_prefix(klass)) == 0
            ) {
                // Same parcel.
                const char *struct_sym = CFCUri_get_struct_sym(uri_obj);
                link_text = CFCUtil_strdup(struct_sym);
            }
            else {
                // Other parcel.
                const char *full_struct_sym = CFCUri_full_struct_sym(uri_obj);
                CFCClass *uri_class
                    = CFCClass_fetch_by_struct_sym(full_struct_sym);
                if (!uri_class) {
                    CFCUtil_warn("URI class not found: %s", full_struct_sym);
                }
                else {
                    const char *class_name
                        = CFCClass_get_class_name(uri_class);
                    link_text = CFCUtil_strdup(class_name);
                }
            }

            break;
        }

        case CFC_URI_FUNCTION:
        case CFC_URI_METHOD: {
#if 1
            const char *func_sym = CFCUri_get_func_sym(uri_obj);
            link_text = CFCUtil_sprintf("%s()", func_sym);
#else
            // Full function sym.
            const char *full_struct_sym = CFCUri_full_struct_sym(uri_obj);
            const char *func_sym        = CFCUri_get_func_sym(uri_obj);

            if (strcmp(full_struct_sym,
                       CFCClass_full_struct_sym(klass)) == 0
            ) {
                // Same class.
                link_text = CFCUtil_sprintf("%s()", func_sym);
            }
            else {
                CFCClass *uri_class
                    = CFCClass_fetch_by_struct_sym(full_struct_sym);

                if (!uri_class) {
                    CFCUtil_warn("URI class not found: %s", full_struct_sym);
                    link_text = CFCUtil_sprintf("%s()", func_sym);
                }
                else {
                    const char *prefix   = CFCUri_get_prefix(uri_obj);
                    const char *nickname = CFCClass_get_nickname(uri_class);

                    if (strcmp(prefix, CFCClass_get_prefix(klass)) == 0) {
                        // Same parcel.
                        link_text = CFCUtil_sprintf("%s_%s()", nickname,
                                                    func_sym);
                    }
                    else {
                        // Other parcel.
                        link_text = CFCUtil_sprintf("%s%s_%s()", prefix,
                                                    nickname, func_sym);
                    }
                }
            }
#endif
            break;
        }
    }

    return link_text;
}
Beispiel #14
0
static char*
S_virtual_method_def(CFCMethod *method, CFCClass *klass) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *invoker_struct = CFCClass_full_struct_sym(klass);
    const char *common_struct 
        = CFCType_get_specifier(CFCMethod_self_type(method));

    const char *visibility = CFCClass_included(klass)
                             ? "CHY_IMPORT" : "CHY_EXPORT";

    size_t meth_sym_size = CFCMethod_full_method_sym(method, klass, NULL, 0);
    char *full_meth_sym = (char*)MALLOCATE(meth_sym_size);
    CFCMethod_full_method_sym(method, klass, full_meth_sym, meth_sym_size);

    size_t offset_sym_size = CFCMethod_full_offset_sym(method, klass, NULL, 0);
    char *full_offset_sym = (char*)MALLOCATE(offset_sym_size);
    CFCMethod_full_offset_sym(method, klass, full_offset_sym, offset_sym_size);

    size_t full_typedef_size = CFCMethod_full_typedef(method, klass, NULL, 0);
    char *full_typedef = (char*)MALLOCATE(full_typedef_size);
    CFCMethod_full_typedef(method, klass, full_typedef, full_typedef_size);

    // Prepare parameter lists, minus invoker.  The invoker gets forced to
    // "self" later.
    const char *arg_names_minus_invoker = CFCParamList_name_list(param_list);
    const char *params_minus_invoker    = CFCParamList_to_c(param_list);
    while (*arg_names_minus_invoker && *arg_names_minus_invoker != ',') {
        arg_names_minus_invoker++;
    }
    while (*params_minus_invoker && *params_minus_invoker != ',') {
        params_minus_invoker++;
    }

    // Prepare a return statement... or not.
    CFCType *return_type = CFCMethod_get_return_type(method);
    const char *ret_type_str = CFCType_to_c(return_type);
    const char *maybe_return = CFCType_is_void(return_type) ? "" : "return ";

    const char pattern[] =
        "extern %s size_t %s;\n"
        "static CHY_INLINE %s\n"
        "%s(const %s *self%s) {\n"
        "    char *const method_address = *(char**)self + %s;\n"
        "    const %s method = *((%s*)method_address);\n"
        "    %smethod((%s*)self%s);\n"
        "}\n";

    size_t size = sizeof(pattern)
                  + strlen(visibility)
                  + strlen(full_offset_sym)
                  + strlen(ret_type_str)
                  + strlen(full_meth_sym)
                  + strlen(invoker_struct)
                  + strlen(params_minus_invoker)
                  + strlen(full_offset_sym)
                  + strlen(full_typedef)
                  + strlen(full_typedef)
                  + strlen(maybe_return)
                  + strlen(common_struct)
                  + strlen(arg_names_minus_invoker)
                  + 40;
    char *method_def = (char*)MALLOCATE(size);
    sprintf(method_def, pattern, visibility, full_offset_sym, ret_type_str,
            full_meth_sym, invoker_struct, params_minus_invoker,
            full_offset_sym, full_typedef, full_typedef, maybe_return,
            common_struct, arg_names_minus_invoker);

    FREEMEM(full_offset_sym);
    FREEMEM(full_meth_sym);
    FREEMEM(full_typedef);
    return method_def;
}
Beispiel #15
0
static void
S_add_load_method(CFCClass *klass) {
    CFCMethod *method = S_make_method_obj(klass, "Load");
    CFCClass_add_method(klass, method);
    CFCBase_decref((CFCBase*)method);
    const char *full_func_sym = CFCMethod_implementing_func_sym(method);
    const char *full_struct   = CFCClass_full_struct_sym(klass);
    const char *vtable_var    = CFCClass_full_vtable_var(klass);
    CFCClass   *parent        = CFCClass_get_parent(klass);
    const char *prefix        = CFCClass_get_prefix(klass);
    const char *class_cnick   = CFCClass_get_cnick(klass);
    char buf[BUF_SIZE];

    if (parent && CFCClass_has_attribute(parent, "dumpable")) {
        char *full_typedef = CFCMethod_full_typedef(method, klass);
        char *full_meth    = CFCMethod_full_method_sym(method, klass);

        const char pattern[] =
            "cfish_Obj*\n"
            "%s(%s *self, cfish_Obj *dump)\n"
            "{\n"
            "    cfish_Hash *source = (cfish_Hash*)CFISH_CERTIFY(dump, CFISH_HASH);\n"
            "    %s super_load = CFISH_SUPER_METHOD_PTR(%s, %s);\n"
            "    %s *loaded = (%s*)super_load(self, dump);\n"
            "    %sIVARS *ivars = %s%s_IVARS(loaded);\n";
        char *autocode
            = CFCUtil_sprintf(pattern, full_func_sym, full_struct,
                              full_typedef, vtable_var, full_meth, full_struct,
                              full_struct, full_struct, prefix, class_cnick);
        CFCClass_append_autocode(klass, autocode);
        FREEMEM(full_meth);
        FREEMEM(full_typedef);
        FREEMEM(autocode);

        CFCVariable **fresh = CFCClass_fresh_member_vars(klass);
        for (size_t i = 0; fresh[i] != NULL; i++) {
            S_process_load_member(klass, fresh[i], buf, BUF_SIZE);
        }
        FREEMEM(fresh);
    }
    else {
        const char pattern[] =
            "cfish_Obj*\n"
            "%s(%s *self, cfish_Obj *dump)\n"
            "{\n"
            "    cfish_Hash *source = (cfish_Hash*)CFISH_CERTIFY(dump, CFISH_HASH);\n"
            "    cfish_CharBuf *class_name = (cfish_CharBuf*)CFISH_CERTIFY(\n"
            "        Cfish_Hash_Fetch_Str(source, \"_class\", 6), CFISH_CHARBUF);\n"
            "    cfish_VTable *vtable = cfish_VTable_singleton(class_name, NULL);\n"
            "    %s *loaded = (%s*)Cfish_VTable_Make_Obj(vtable);\n"
            "    %sIVARS *ivars = %s%s_IVARS(loaded);\n"
            "    CHY_UNUSED_VAR(self);\n";
        char *autocode
            = CFCUtil_sprintf(pattern, full_func_sym, full_struct, full_struct,
                              full_struct,
                              full_struct, prefix, class_cnick);
        CFCClass_append_autocode(klass, autocode);
        FREEMEM(autocode);
        CFCVariable **members = CFCClass_member_vars(klass);
        for (size_t i = 0; members[i] != NULL; i++) {
            S_process_load_member(klass, members[i], buf, BUF_SIZE);
        }
    }

    CFCClass_append_autocode(klass, "    return (cfish_Obj*)loaded;\n}\n\n");
}
Beispiel #16
0
static void
S_add_dump_method(CFCClass *klass) {
    CFCMethod *method = S_make_method_obj(klass, "Dump");
    CFCClass_add_method(klass, method);
    CFCBase_decref((CFCBase*)method);
    const char *full_func_sym = CFCMethod_implementing_func_sym(method);
    const char *full_struct   = CFCClass_full_struct_sym(klass);
    const char *vtable_var    = CFCClass_full_vtable_var(klass);
    const char *prefix        = CFCClass_get_prefix(klass);
    const char *class_cnick   = CFCClass_get_cnick(klass);
    CFCClass   *parent        = CFCClass_get_parent(klass);
    char buf[BUF_SIZE];

    if (parent && CFCClass_has_attribute(parent, "dumpable")) {
        char *full_typedef = CFCMethod_full_typedef(method, klass);
        char *full_meth    = CFCMethod_full_method_sym(method, klass);

        const char pattern[] =
            "cfish_Obj*\n"
            "%s(%s *self)\n"
            "{\n"
            "    %sIVARS *ivars = %s%s_IVARS(self);\n"
            "    %s super_dump = CFISH_SUPER_METHOD_PTR(%s, %s);\n"
            "    cfish_Hash *dump = (cfish_Hash*)super_dump(self);\n";
        char *autocode
            = CFCUtil_sprintf(pattern, full_func_sym, full_struct,
                              full_struct, prefix, class_cnick,
                              full_typedef, vtable_var, full_meth);
        CFCClass_append_autocode(klass, autocode);
        FREEMEM(full_meth);
        FREEMEM(full_typedef);
        FREEMEM(autocode);

        CFCVariable **fresh = CFCClass_fresh_member_vars(klass);
        for (size_t i = 0; fresh[i] != NULL; i++) {
            S_process_dump_member(klass, fresh[i], buf, BUF_SIZE);
        }
        FREEMEM(fresh);
    }
    else {
        const char pattern[] =
            "cfish_Obj*\n"
            "%s(%s *self)\n"
            "{\n"
            "    %sIVARS *ivars = %s%s_IVARS(self);\n"
            "    cfish_Hash *dump = cfish_Hash_new(0);\n"
            "    Cfish_Hash_Store_Str(dump, \"_class\", 6,\n"
            "        (cfish_Obj*)Cfish_CB_Clone(Cfish_Obj_Get_Class_Name((cfish_Obj*)self)));\n";
        char *autocode
            = CFCUtil_sprintf(pattern, full_func_sym, full_struct,
                              full_struct, prefix, class_cnick);
        CFCClass_append_autocode(klass, autocode);
        FREEMEM(autocode);
        CFCVariable **members = CFCClass_member_vars(klass);
        for (size_t i = 0; members[i] != NULL; i++) {
            S_process_dump_member(klass, members[i], buf, BUF_SIZE);
        }
    }

    CFCClass_append_autocode(klass, "    return (cfish_Obj*)dump;\n}\n\n");
}
Beispiel #17
0
/* Write the "parcel.h" header file, which contains common symbols needed by
 * all classes, plus typedefs for all class structs.
 */
static void
S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
    CFCHierarchy *hierarchy   = self->hierarchy;
    const char   *prefix      = CFCParcel_get_prefix(parcel);
    const char   *PREFIX      = CFCParcel_get_PREFIX(parcel);
    const char   *privacy_sym = CFCParcel_get_privacy_sym(parcel);

    // Declare object structs and class singletons for all instantiable
    // classes.
    char *typedefs    = CFCUtil_strdup("");
    char *class_decls = CFCUtil_strdup("");
    CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy);
    for (int i = 0; ordered[i] != NULL; i++) {
        CFCClass *klass = ordered[i];
        const char *class_prefix = CFCClass_get_prefix(klass);
        if (strcmp(class_prefix, prefix) != 0) { continue; }

        if (!CFCClass_inert(klass)) {
            const char *full_struct = CFCClass_full_struct_sym(klass);
            typedefs = CFCUtil_cat(typedefs, "typedef struct ", full_struct,
                                   " ", full_struct, ";\n", NULL);
            const char *class_var = CFCClass_full_class_var(klass);
            class_decls = CFCUtil_cat(class_decls, "extern ", PREFIX,
                                      "VISIBLE cfish_Class *", class_var,
                                      ";\n", NULL);
        }
    }
    FREEMEM(ordered);

    // Special includes and macros for Clownfish parcel.
    const char *cfish_includes =
        "#include <stdarg.h>\n"
        "#include <stddef.h>\n"
        "\n"
        "#include \"cfish_platform.h\"\n"
        "#include \"cfish_hostdefs.h\"\n";

    // Special definitions for Clownfish parcel.
    const char *cfish_defs_1 =
        "#define CFISH_UNUSED_VAR(var) ((void)var)\n"
        "#define CFISH_UNREACHABLE_RETURN(type) return (type)0\n"
        "\n"
        "/* Generic method pointer.\n"
        " */\n"
        "typedef void\n"
        "(*cfish_method_t)(const void *vself);\n"
        "\n"
        "/* Access the function pointer for a given method from the class.\n"
        " */\n"
        "#define CFISH_METHOD_PTR(_class, _full_meth) \\\n"
        "     ((_full_meth ## _t)cfish_method(_class, _full_meth ## _OFFSET))\n"
        "\n"
        "static CFISH_INLINE cfish_method_t\n"
        "cfish_method(const void *klass, uint32_t offset) {\n"
        "    union { char *cptr; cfish_method_t *fptr; } ptr;\n"
        "    ptr.cptr = (char*)klass + offset;\n"
        "    return ptr.fptr[0];\n"
        "}\n"
        "\n"
        "typedef struct cfish_Dummy {\n"
        "   CFISH_OBJ_HEAD\n"
        "   void *klass;\n"
        "} cfish_Dummy;\n"
        "\n"
        "/* Access the function pointer for a given method from the object.\n"
        " */\n"
        "static CFISH_INLINE cfish_method_t\n"
        "cfish_obj_method(const void *object, uint32_t offset) {\n"
        "    cfish_Dummy *dummy = (cfish_Dummy*)object;\n"
        "    return cfish_method(dummy->klass, offset);\n"
        "}\n"
        "\n"
        "/* Access the function pointer for the given method in the\n"
        " * superclass. */\n"
        "#define CFISH_SUPER_METHOD_PTR(_class, _full_meth) \\\n"
        "     ((_full_meth ## _t)cfish_super_method(_class, \\\n"
        "                                           _full_meth ## _OFFSET))\n"
        "\n"
        "extern CFISH_VISIBLE uint32_t cfish_Class_offset_of_parent;\n"
        "static CFISH_INLINE cfish_method_t\n"
        "cfish_super_method(const void *klass, uint32_t offset) {\n"
        "    char *class_as_char = (char*)klass;\n"
        "    cfish_Class **parent_ptr\n"
        "        = (cfish_Class**)(class_as_char + cfish_Class_offset_of_parent);\n"
        "    return cfish_method(*parent_ptr, offset);\n"
        "}\n"
        "\n"
        "typedef void\n"
        "(*cfish_destroy_t)(void *vself);\n"
        "extern CFISH_VISIBLE uint32_t CFISH_Obj_Destroy_OFFSET;\n"
        "\n"
        "/** Invoke the [](.Destroy) method found in `klass` on\n"
        " * `self`.\n"
        " *\n"
        " * TODO: Eliminate this function if we can arrive at a proper SUPER syntax.\n"
        " */\n"
        "static CFISH_INLINE void\n"
        "cfish_super_destroy(void *vself, cfish_Class *klass) {\n"
        "    cfish_Obj *self = (cfish_Obj*)vself;\n"
        "    if (self != NULL) {\n"
        "        cfish_destroy_t super_destroy\n"
        "            = (cfish_destroy_t)cfish_super_method(klass, CFISH_Obj_Destroy_OFFSET);\n"
        "        super_destroy(self);\n"
        "    }\n"
        "}\n"
        "\n"
        "#define CFISH_SUPER_DESTROY(_self, _class) \\\n"
        "    cfish_super_destroy(_self, _class)\n"
        "\n"
        "extern CFISH_VISIBLE cfish_Obj*\n"
        "cfish_inc_refcount(void *vself);\n"
        "\n"
        "/** NULL-safe invocation invocation of `cfish_inc_refcount`.\n"
        " *\n"
        " * @return NULL if `self` is NULL, otherwise the return value\n"
        " * of `cfish_inc_refcount`.\n"
        " */\n"
        "static CFISH_INLINE cfish_Obj*\n"
        "cfish_incref(void *vself) {\n"
        "    if (vself != NULL) { return cfish_inc_refcount(vself); }\n"
        "    else { return NULL; }\n"
        "}\n"
        "\n"
        "#define CFISH_INCREF(_self) cfish_incref(_self)\n"
        "#define CFISH_INCREF_NN(_self) cfish_inc_refcount(_self)\n"
        "\n"
        "extern CFISH_VISIBLE uint32_t\n"
        "cfish_dec_refcount(void *vself);\n"
        "\n"
        "/** NULL-safe invocation of `cfish_dec_refcount`.\n"
        " *\n"
        " * @return NULL if `self` is NULL, otherwise the return value\n"
        " * of `cfish_dec_refcount`.\n"
        " */\n"
        "static CFISH_INLINE uint32_t\n"
        "cfish_decref(void *vself) {\n"
        "    if (vself != NULL) { return cfish_dec_refcount(vself); }\n"
        "    else { return 0; }\n"
        "}\n"
        "\n"
        "#define CFISH_DECREF(_self) cfish_decref(_self)\n"
        "#define CFISH_DECREF_NN(_self) cfish_dec_refcount(_self)\n"
        "\n"
        "extern CFISH_VISIBLE uint32_t\n"
        "cfish_get_refcount(void *vself);\n"
        "\n"
        "#define CFISH_REFCOUNT_NN(_self) \\\n"
        "    cfish_get_refcount(_self)\n"
        "\n"
        "/* Flags for internal use. */\n"
        "#define CFISH_fREFCOUNTSPECIAL 0x00000001\n"
        "#define CFISH_fFINAL           0x00000002\n"
        ;
    const char *cfish_defs_2 =
        "#ifdef CFISH_USE_SHORT_NAMES\n"
        "  #define UNUSED_VAR               CFISH_UNUSED_VAR\n"
        "  #define UNREACHABLE_RETURN       CFISH_UNREACHABLE_RETURN\n"
        "  #define METHOD_PTR               CFISH_METHOD_PTR\n"
        "  #define SUPER_METHOD_PTR         CFISH_SUPER_METHOD_PTR\n"
        "  #define SUPER_DESTROY(_self, _class) CFISH_SUPER_DESTROY(_self, _class)\n"
        "  #define INCREF(_self)                CFISH_INCREF(_self)\n"
        "  #define INCREF_NN(_self)             CFISH_INCREF_NN(_self)\n"
        "  #define DECREF(_self)                CFISH_DECREF(_self)\n"
        "  #define DECREF_NN(_self)             CFISH_DECREF_NN(_self)\n"
        "  #define REFCOUNT_NN(_self)           CFISH_REFCOUNT_NN(_self)\n"
        "#endif\n"
        "\n";

    char *extra_defs;
    char *extra_includes;
    if (CFCParcel_is_cfish(parcel)) {
        const char *spec_typedefs = CFCBindSpecs_get_typedefs();
        extra_defs = CFCUtil_sprintf("%s%s%s", cfish_defs_1, spec_typedefs,
                                     cfish_defs_2);
        extra_includes = CFCUtil_strdup(cfish_includes);
    }
    else {
        extra_defs = CFCUtil_strdup("");
        extra_includes = CFCUtil_strdup("");

        // Include parcel.h of prerequisite parcels.
        CFCParcel **prereq_parcels = CFCParcel_prereq_parcels(parcel);
        for (size_t i = 0; prereq_parcels[i]; ++i) {
            const char *prereq_prefix
                = CFCParcel_get_prefix(prereq_parcels[i]);
            extra_includes = CFCUtil_cat(extra_includes, "#include \"",
                                         prereq_prefix, "parcel.h\"\n", NULL);
        }
        FREEMEM(prereq_parcels);
    }

    const char pattern[] =
        "%s\n"
        "#ifndef CFISH_%sPARCEL_H\n"
        "#define CFISH_%sPARCEL_H 1\n"
        "\n"
        "#ifdef __cplusplus\n"
        "extern \"C\" {\n"
        "#endif\n"
        "\n"
        "%s" // Extra includes.
        "\n"
        "#ifdef %s\n"
        "  #define %sVISIBLE CFISH_EXPORT\n"
        "#else\n"
        "  #define %sVISIBLE CFISH_IMPORT\n"
        "#endif\n"
        "\n"
        "%s" // Typedefs.
        "\n"
        "%s" // Class singletons.
        "\n"
        "%s" // Extra definitions.
        "%sVISIBLE void\n"
        "%sbootstrap_inheritance();\n"
        "\n"
        "%sVISIBLE void\n"
        "%sbootstrap_parcel();\n"
        "\n"
        "void\n"
        "%sinit_parcel();\n"
        "\n"
        "#ifdef __cplusplus\n"
        "}\n"
        "#endif\n"
        "\n"
        "#endif /* CFISH_%sPARCEL_H */\n"
        "\n"
        "%s\n"
        "\n";
    char *file_content
        = CFCUtil_sprintf(pattern, self->c_header, PREFIX, PREFIX,
                          extra_includes, privacy_sym, PREFIX, PREFIX,
                          typedefs, class_decls, extra_defs, PREFIX, prefix,
                          PREFIX, prefix, prefix, PREFIX, self->c_footer);

    // Unlink then write file.
    const char *inc_dest = CFCHierarchy_get_include_dest(hierarchy);
    char *filepath = CFCUtil_sprintf("%s" CHY_DIR_SEP "%sparcel.h", inc_dest,
                                     prefix);
    remove(filepath);
    CFCUtil_write_file(filepath, file_content, strlen(file_content));
    FREEMEM(filepath);

    FREEMEM(typedefs);
    FREEMEM(class_decls);
    FREEMEM(extra_defs);
    FREEMEM(extra_includes);
    FREEMEM(file_content);
}
static char*
S_convert_link(cmark_node *link, CFCClass *doc_class, int header_level) {
    cmark_node *child = cmark_node_first_child(link);
    const char *uri   = cmark_node_get_url(link);
    char       *text  = S_nodes_to_pod(child, doc_class, header_level);
    char       *retval;

    if (!CFCUri_is_clownfish_uri(uri)) {
        retval = S_pod_link(text, uri);
        FREEMEM(text);
        return retval;
    }

    char       *new_uri  = NULL;
    char       *new_text = NULL;
    CFCUri     *uri_obj  = CFCUri_new(uri, doc_class);
    CFCUriType  type     = CFCUri_get_type(uri_obj);

    switch (type) {
        case CFC_URI_ERROR: {
            const char *error = CFCUri_get_error(uri_obj);
            new_text = CFCUtil_sprintf("[%s]", error);
            break;
        }

        case CFC_URI_NULL:
            // Change all instances of NULL to 'undef'
            new_text = CFCUtil_strdup("undef");
            break;

        case CFC_URI_CLASS: {
            CFCClass *klass = CFCUri_get_class(uri_obj);

            if (klass != doc_class) {
                const char *class_name = CFCClass_get_name(klass);
                new_uri = CFCUtil_strdup(class_name);
            }

            if (text[0] == '\0') {
                const char *src = CFCClass_included(klass)
                                  ? CFCClass_get_name(klass)
                                  : CFCClass_get_struct_sym(klass);
                new_text = CFCUtil_strdup(src);
            }

            break;
        }

        case CFC_URI_FUNCTION:
        case CFC_URI_METHOD: {
            CFCClass   *klass = CFCUri_get_class(uri_obj);
            const char *name  = CFCUri_get_callable_name(uri_obj);

            // Convert "Err_get_error" to "Clownfish->error".
            if (strcmp(CFCClass_full_struct_sym(klass), "cfish_Err") == 0
                && strcmp(name, "get_error") == 0
            ) {
                new_text = CFCUtil_strdup("Clownfish->error");
                break;
            }

            char *perl_name = CFCUtil_strdup(name);
            for (size_t i = 0; perl_name[i] != '\0'; ++i) {
                perl_name[i] = CFCUtil_tolower(perl_name[i]);
            }

            // The Perl POD only contains sections for novel methods. Link
            // to the class where the method is declared first.
            if (type == CFC_URI_METHOD) {
                CFCClass *parent = CFCClass_get_parent(klass);
                while (parent && CFCClass_method(parent, name)) {
                    klass = parent;
                    parent = CFCClass_get_parent(klass);
                }
            }

            if (klass == doc_class) {
                new_uri = CFCUtil_sprintf("/%s", perl_name);
            }
            else {
                const char *class_name = CFCClass_get_name(klass);
                new_uri = CFCUtil_sprintf("%s/%s", class_name, perl_name);
            }

            if (text[0] == '\0') {
                new_text = CFCUtil_sprintf("%s()", perl_name);
            }

            FREEMEM(perl_name);
            break;
        }

        case CFC_URI_DOCUMENT: {
            CFCDocument *doc = CFCUri_get_document(uri_obj);

            const char *path_part = CFCDocument_get_path_part(doc);
            new_uri = CFCUtil_global_replace(path_part, CHY_DIR_SEP, "::");

            if (text[0] == '\0') {
                const char *name = CFCDocument_get_name(doc);
                new_text = CFCUtil_strdup(name);
            }

            break;
        }
    }

    if (new_text) {
        FREEMEM(text);
        text = new_text;
    }

    if (new_uri) {
        retval = S_pod_link(text, new_uri);
        FREEMEM(new_uri);
        FREEMEM(text);
    }
    else {
        retval = text;
    }

    CFCBase_decref((CFCBase*)uri_obj);

    return retval;
}