Beispiel #1
0
CFCPerlSub*
CFCPerlSub_init(CFCPerlSub *self, CFCParamList *param_list,
                const char *class_name, const char *alias,
                int use_labeled_params) {
    CFCUTIL_NULL_CHECK(param_list);
    CFCUTIL_NULL_CHECK(class_name);
    CFCUTIL_NULL_CHECK(alias);
    self->param_list  = (CFCParamList*)CFCBase_incref((CFCBase*)param_list);
    self->class_name  = CFCUtil_strdup(class_name);
    self->alias       = CFCUtil_strdup(alias);
    self->use_labeled_params = use_labeled_params;
    self->perl_name = CFCUtil_sprintf("%s::%s", class_name, alias);

    size_t c_name_len = strlen(self->perl_name) + sizeof("XS_") + 1;
    self->c_name = (char*)MALLOCATE(c_name_len);
    int j = 3;
    memcpy(self->c_name, "XS_", j);
    for (int i = 0, max = (int)strlen(self->perl_name); i < max; i++) {
        char c = self->perl_name[i];
        if (c == ':') {
            while (self->perl_name[i + 1] == ':') { i++; }
            self->c_name[j++] = '_';
        }
        else {
            self->c_name[j++] = c;
        }
    }
    self->c_name[j] = 0; // NULL-terminate.

    return self;
}
Beispiel #2
0
CFCPerl*
CFCPerl_init(CFCPerl *self, CFCHierarchy *hierarchy, const char *lib_dir,
             const char *boot_class, const char *header, const char *footer) {
    CFCUTIL_NULL_CHECK(hierarchy);
    CFCUTIL_NULL_CHECK(lib_dir);
    CFCUTIL_NULL_CHECK(boot_class);
    CFCUTIL_NULL_CHECK(header);
    CFCUTIL_NULL_CHECK(footer);
    self->hierarchy  = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy);
    self->lib_dir    = CFCUtil_strdup(lib_dir);
    self->boot_class = CFCUtil_strdup(boot_class);
    self->header     = CFCUtil_strdup(header);
    self->footer     = CFCUtil_strdup(footer);

    // Derive path to generated .xs file.
    self->xs_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.xs", lib_dir,
                                    boot_class);
    S_replace_double_colons(self->xs_path, CHY_DIR_SEP_CHAR);

    // Derive the name of the bootstrap function.
    self->boot_func = CFCUtil_sprintf("cfish_%s_bootstrap", boot_class);
    for (int i = 0; self->boot_func[i] != 0; i++) {
        if (!isalnum(self->boot_func[i])) {
            self->boot_func[i] = '_';
        }
    }

    return self;
}
Beispiel #3
0
CFCPerlConstructor*
CFCPerlConstructor_init(CFCPerlConstructor *self, CFCClass *klass,
                        const char *alias, const char *initializer) {
    CFCUTIL_NULL_CHECK(alias);
    CFCUTIL_NULL_CHECK(klass);
    const char *class_name = CFCClass_get_class_name(klass);
    initializer = initializer ? initializer : "init";

    // Find the implementing function.
    self->init_func = NULL;
    CFCFunction **funcs = CFCClass_functions(klass);
    for (size_t i = 0; funcs[i] != NULL; i++) {
        CFCFunction *func = funcs[i];
        const char *func_name = CFCFunction_micro_sym(func);
        if (strcmp(initializer, func_name) == 0) {
            self->init_func = (CFCFunction*)CFCBase_incref((CFCBase*)func);
            break;
        }
    }
    if (!self->init_func) {
        CFCUtil_die("Missing or invalid '%s' function for '%s'",
                    initializer, class_name);
    }
    CFCParamList *param_list = CFCFunction_get_param_list(self->init_func);
    CFCPerlSub_init((CFCPerlSub*)self, param_list, class_name, alias,
                    true);
    return self;
}
Beispiel #4
0
int
S_do_propagate_modified(CFCHierarchy *self, CFCClass *klass, int modified) {
    const char *path_part = CFCClass_get_path_part(klass);
    CFCUTIL_NULL_CHECK(path_part);
    CFCFile *file = S_fetch_file(self, path_part);
    CFCUTIL_NULL_CHECK(file);
    const char *source_path = CFCFile_get_path(file);
    char *h_path = CFCFile_h_path(file, self->inc_dest);

    if (!CFCUtil_current(source_path, h_path)) {
        modified = true;
    }
    FREEMEM(h_path);
    if (modified) {
        CFCFile_set_modified(file, modified);
    }

    // Proceed to the next generation.
    int somebody_is_modified = modified;
    CFCClass **children = CFCClass_children(klass);
    for (size_t i = 0; children[i] != NULL; i++) {
        CFCClass *kid = children[i];
        if (CFCClass_final(klass)) {
            CFCUtil_die("Attempt to inherit from final class '%s' by '%s'",
                        CFCClass_get_name(klass),
                        CFCClass_get_name(kid));
        }
        if (S_do_propagate_modified(self, kid, modified)) {
            somebody_is_modified = 1;
        }
    }

    return somebody_is_modified;
}
Beispiel #5
0
CFCBindCore*
CFCBindCore_init(CFCBindCore *self, CFCHierarchy *hierarchy,
                 const char *header, const char *footer) {
    CFCUTIL_NULL_CHECK(hierarchy);
    CFCUTIL_NULL_CHECK(header);
    CFCUTIL_NULL_CHECK(footer);
    self->hierarchy = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy);
    self->c_header  = CFCUtil_make_c_comment(header);
    self->c_footer  = CFCUtil_make_c_comment(footer);
    return self;
}
Beispiel #6
0
CFCGoClass*
CFCGoClass_new(CFCParcel *parcel, const char *class_name) {
    CFCUTIL_NULL_CHECK(parcel);
    CFCUTIL_NULL_CHECK(class_name);
    CFCGoClass *self = (CFCGoClass*)CFCBase_allocate(&CFCGOCLASS_META);
    self->parcel = (CFCParcel*)CFCBase_incref((CFCBase*)parcel);
    self->class_name = CFCUtil_strdup(class_name);
    // Client may be NULL, since fetch_singleton() does not always succeed.
    CFCClass *client = CFCClass_fetch_singleton(parcel, class_name);
    self->client = (CFCClass*)CFCBase_incref((CFCBase*)client);
    return self;
}
Beispiel #7
0
CFCC*
CFCC_init(CFCC *self, CFCHierarchy *hierarchy, const char *header,
          const char *footer) {
    CFCUTIL_NULL_CHECK(hierarchy);
    CFCUTIL_NULL_CHECK(header);
    CFCUTIL_NULL_CHECK(footer);
    self->hierarchy  = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy);
    self->html_gen   = CFCCHtml_new(hierarchy, header, footer);
    self->c_header   = CFCUtil_make_c_comment(header);
    self->c_footer   = CFCUtil_make_c_comment(footer);
    self->man_header = CFCUtil_make_troff_comment(header);
    self->man_footer = CFCUtil_make_troff_comment(footer);
    return self;
}
Beispiel #8
0
CFCCallable*
CFCCallable_init(CFCCallable *self, const char *exposure, const char *name,
                 CFCType *return_type, CFCParamList *param_list,
                 CFCDocuComment *docucomment) {

    exposure = exposure ? exposure : "parcel";
    CFCUTIL_NULL_CHECK(return_type);
    CFCUTIL_NULL_CHECK(param_list);
    CFCSymbol_init((CFCSymbol*)self, exposure, name);
    self->return_type = (CFCType*)CFCBase_incref((CFCBase*)return_type);
    self->param_list  = (CFCParamList*)CFCBase_incref((CFCBase*)param_list);
    self->docucomment = (CFCDocuComment*)CFCBase_incref((CFCBase*)docucomment);
    return self;
}
Beispiel #9
0
void
CFCClass_add_child(CFCClass *self, CFCClass *child) {
    CFCUTIL_NULL_CHECK(child);
    if (self->tree_grown) {
        CFCUtil_die("Can't call add_child after grow_tree");
    }
    if (self->is_inert) {
        CFCUtil_die("Can't inherit from inert class %s",
                    CFCClass_get_class_name(self));
    }
    if (child->is_inert) {
        CFCUtil_die("Inert class %s can't inherit",
                    CFCClass_get_class_name(child));
    }
    self->num_kids++;
    size_t size = (self->num_kids + 1) * sizeof(CFCClass*);
    self->children = (CFCClass**)REALLOCATE(self->children, size);
    self->children[self->num_kids - 1]
        = (CFCClass*)CFCBase_incref((CFCBase*)child);
    self->children[self->num_kids] = NULL;

    // Add parcel dependency.
    CFCParcel *parcel       = CFCClass_get_parcel(self);
    CFCParcel *child_parcel = CFCClass_get_parcel(child);
    CFCParcel_add_inherited_parcel(child_parcel, parcel);
}
Beispiel #10
0
void
CFCGoClass_spec_method(CFCGoClass *self, const char *name, const char *sig) {
    CFCUTIL_NULL_CHECK(sig);
    S_lazy_init_method_bindings(self);
    if (!name) {
        CFCGoMethod *meth_binding = CFCGoMethod_new(NULL);
        CFCGoMethod_customize(meth_binding, sig);

        size_t size = (self->num_bound + 2) * sizeof(CFCGoMethod*);
        self->method_bindings
            = (CFCGoMethod**)REALLOCATE(self->method_bindings, size);
        self->method_bindings[self->num_bound] = meth_binding;
        self->num_bound++;
        self->method_bindings[self->num_bound] = NULL;
    }
    else {
        CFCGoMethod *binding = NULL;
        for (int i = 0; self->method_bindings[i] != NULL; i++) {
            CFCGoMethod *candidate = self->method_bindings[i];
            CFCMethod *meth = CFCGoMethod_get_client(candidate);
            if (meth && strcmp(name, CFCMethod_get_name(meth)) == 0) {
                binding = candidate;
                break;
            }
        }
        if (!binding) {
            CFCUtil_die("Can't find a method named '%s'", name);
        }
        CFCGoMethod_customize(binding, sig);
    }
}
Beispiel #11
0
static void
S_process_dump_member(CFCClass *klass, CFCVariable *member, char *buf,
                      size_t buf_size) {
    CFCUTIL_NULL_CHECK(member);
    CFCType *type = CFCVariable_get_type(member);
    const char *name = CFCVariable_micro_sym(member);
    unsigned name_len = (unsigned)strlen(name);
    const char *specifier = CFCType_get_specifier(type);

    // Skip the VTable.
    if (strcmp(specifier, "cfish_VTable") == 0) {
        return;
    }

    if (CFCType_is_integer(type) || CFCType_is_floating(type)) {
        char int_pattern[] =
            "    Cfish_Hash_Store_Str(dump, \"%s\", %u, (cfish_Obj*)cfish_CB_newf(\"%%i64\", (int64_t)ivars->%s));\n";
        char float_pattern[] =
            "    Cfish_Hash_Store_Str(dump, \"%s\", %u, (cfish_Obj*)cfish_CB_newf(\"%%f64\", (double)ivars->%s));\n";
        char bool_pattern[] =
            "    Cfish_Hash_Store_Str(dump, \"%s\", %u, (cfish_Obj*)cfish_Bool_singleton(ivars->%s));\n";
        const char *pattern;
        if (strcmp(specifier, "bool") == 0) {
            pattern = bool_pattern;
        }
        else if (CFCType_is_integer(type)) {
            pattern = int_pattern;
        }
        else {
            pattern = float_pattern;
        }
        size_t needed = strlen(pattern) + name_len * 2 + 20;
        if (buf_size < needed) {
            CFCUtil_die("Buffer not big enough (%lu < %lu)",
                        (unsigned long)buf_size, (unsigned long)needed);
        }
        sprintf(buf, pattern, name, name_len, name);
    }
    else if (CFCType_is_object(type)) {
        char pattern[] =
            "    if (ivars->%s) {\n"
            "        Cfish_Hash_Store_Str(dump, \"%s\", %u, Cfish_Obj_Dump((cfish_Obj*)ivars->%s));\n"
            "    }\n";

        size_t needed = strlen(pattern) + name_len * 3 + 20;
        if (buf_size < needed) {
            CFCUtil_die("Buffer not big enough (%lu < %lu)",
                        (unsigned long)buf_size, (unsigned long)needed);
        }
        sprintf(buf, pattern, name, name, name_len, name);
    }
    else {
        CFCUtil_die("Don't know how to dump a %s",
                    CFCType_get_specifier(type));
    }

    CFCClass_append_autocode(klass, buf);
}
Beispiel #12
0
CFCUri*
CFCUri_init(CFCUri *self, const char *uri, CFCClass *doc_class) {
    CFCUTIL_NULL_CHECK(uri);

    self->string    = CFCUtil_strdup(uri);
    self->doc_class = (CFCClass*)CFCBase_incref((CFCBase*)doc_class);

    return self;
}
Beispiel #13
0
CFCPython*
CFCPython_new(CFCHierarchy *hierarchy) {
    CFCUTIL_NULL_CHECK(hierarchy);
    CFCPython *self = (CFCPython*)CFCBase_allocate(&CFCPYTHON_META);
    self->hierarchy  = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy);
    self->header     = CFCUtil_strdup("");
    self->footer     = CFCUtil_strdup("");
    return self;
}
Beispiel #14
0
CFCPerl*
CFCPerl_init(CFCPerl *self, CFCHierarchy *hierarchy, const char *lib_dir,
             const char *header, const char *footer) {
    CFCUTIL_NULL_CHECK(hierarchy);
    CFCUTIL_NULL_CHECK(lib_dir);
    CFCUTIL_NULL_CHECK(header);
    CFCUTIL_NULL_CHECK(footer);
    self->hierarchy  = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy);
    self->lib_dir    = CFCUtil_strdup(lib_dir);
    self->header     = CFCUtil_strdup(header);
    self->footer     = CFCUtil_strdup(footer);
    self->c_header   = CFCUtil_make_c_comment(header);
    self->c_footer   = CFCUtil_make_c_comment(footer);
    self->pod_header = CFCUtil_make_perl_comment(header);
    self->pod_footer = CFCUtil_make_perl_comment(footer);

    return self;
}
Beispiel #15
0
static void
S_process_load_member(CFCClass *klass, CFCVariable *member, char *buf,
                      size_t buf_size) {
    CFCUTIL_NULL_CHECK(member);
    CFCType *type = CFCVariable_get_type(member);
    const char *type_str = CFCType_to_c(type);
    const char *name = CFCVariable_micro_sym(member);
    unsigned name_len = (unsigned)strlen(name);
    char extraction[200];
    const char *specifier = CFCType_get_specifier(type);

    // Skip the VTable.
    if (strcmp(specifier, "cfish_VTable") == 0) {
        return;
    }

    if (2 * strlen(type_str) + 100 > sizeof(extraction)) { // play it safe
        CFCUtil_die("type_str too long: '%s'", type_str);
    }
    if (CFCType_is_integer(type)) {
        if (strcmp(specifier, "bool") == 0) {
            sprintf(extraction, "Cfish_Obj_To_Bool(var)");
        }
        else {
            sprintf(extraction, "(%s)Cfish_Obj_To_I64(var)", type_str);
        }
    }
    else if (CFCType_is_floating(type)) {
        sprintf(extraction, "(%s)Cfish_Obj_To_F64(var)", type_str);
    }
    else if (CFCType_is_object(type)) {
        const char *vtable_var = CFCType_get_vtable_var(type);
        sprintf(extraction,
                "(%s*)CFISH_CERTIFY(Cfish_Obj_Load(var, var), %s)",
                specifier, vtable_var);
    }
    else {
        CFCUtil_die("Don't know how to load %s", specifier);
    }

    const char *pattern =
        "    {\n"
        "        cfish_Obj *var = Cfish_Hash_Fetch_Str(source, \"%s\", %u);\n"
        "        if (var) { ivars->%s = %s; }\n"
        "    }\n";
    size_t needed = sizeof(pattern)
                    + (name_len * 2)
                    + strlen(extraction)
                    + 20;
    if (buf_size < needed) {
        CFCUtil_die("Buffer not big enough (%lu < %lu)",
                    (unsigned long)buf_size, (unsigned long)needed);
    }
    sprintf(buf, pattern, name, name_len, name, extraction);

    CFCClass_append_autocode(klass, buf);
}
Beispiel #16
0
CFCGoClass*
CFCGoClass_singleton(const char *class_name) {
    CFCUTIL_NULL_CHECK(class_name);
    for (size_t i = 0; i < registry_size; i++) {
        CFCGoClass *existing = registry[i];
        if (strcmp(class_name, existing->class_name) == 0) {
            return existing;
        }
    }
    return NULL;
}
CFCPerlClass*
CFCPerlClass_init(CFCPerlClass *self, CFCParcel *parcel,
                  const char *class_name) {
    CFCUTIL_NULL_CHECK(parcel);
    CFCUTIL_NULL_CHECK(class_name);
    self->parcel = (CFCParcel*)CFCBase_incref((CFCBase*)parcel);
    self->class_name = CFCUtil_strdup(class_name);
    // Client may be NULL, since fetch_singleton() does not always succeed.
    CFCClass *client = CFCClass_fetch_singleton(parcel, class_name);
    self->client = (CFCClass*)CFCBase_incref((CFCBase*)client);
    self->pod_spec          = NULL;
    self->xs_code           = NULL;
    self->cons_aliases      = NULL;
    self->cons_inits        = NULL;
    self->num_cons          = 0;
    self->exclude_cons      = 0;
    self->class_aliases     = (char**)CALLOCATE(1, sizeof(char*));
    self->num_class_aliases = 0;
    return self;
}
void
CFCPerlPod_add_method(CFCPerlPod *self, const char *alias, const char *method,
                      const char *sample, const char *pod) {
    CFCUTIL_NULL_CHECK(alias);
    self->num_methods++;
    size_t size = self->num_methods * sizeof(NamePod);
    self->methods = (NamePod*)REALLOCATE(self->methods, size);
    NamePod *slot = &self->methods[self->num_methods - 1];
    slot->alias  = CFCUtil_strdup(alias);
    slot->func   = method ? CFCUtil_strdup(method) : NULL;
    slot->sample = sample ? CFCUtil_strdup(sample) : NULL;
    slot->pod    = pod ? CFCUtil_strdup(pod) : NULL;
}
Beispiel #19
0
void
CFCClass_add_inert_var(CFCClass *self, CFCVariable *var) {
    CFCUTIL_NULL_CHECK(var);
    if (self->tree_grown) {
        CFCUtil_die("Can't call add_inert_var after grow_tree");
    }
    self->num_inert_vars++;
    size_t size = (self->num_inert_vars + 1) * sizeof(CFCVariable*);
    self->inert_vars = (CFCVariable**)REALLOCATE(self->inert_vars, size);
    self->inert_vars[self->num_inert_vars - 1]
        = (CFCVariable*)CFCBase_incref((CFCBase*)var);
    self->inert_vars[self->num_inert_vars] = NULL;
}
Beispiel #20
0
void
CFCClass_add_function(CFCClass *self, CFCFunction *func) {
    CFCUTIL_NULL_CHECK(func);
    if (self->tree_grown) {
        CFCUtil_die("Can't call add_function after grow_tree");
    }
    self->num_functions++;
    size_t size = (self->num_functions + 1) * sizeof(CFCFunction*);
    self->functions = (CFCFunction**)REALLOCATE(self->functions, size);
    self->functions[self->num_functions - 1]
        = (CFCFunction*)CFCBase_incref((CFCBase*)func);
    self->functions[self->num_functions] = NULL;
}
Beispiel #21
0
void
CFCClass_add_method(CFCClass *self, CFCMethod *method) {
    CFCUTIL_NULL_CHECK(method);
    if (self->tree_grown) {
        CFCUtil_die("Can't call add_method after grow_tree");
    }
    if (self->is_inert) {
        CFCUtil_die("Can't add_method to an inert class");
    }
    self->num_methods++;
    size_t size = (self->num_methods + 1) * sizeof(CFCMethod*);
    self->methods = (CFCMethod**)REALLOCATE(self->methods, size);
    self->methods[self->num_methods - 1]
        = (CFCMethod*)CFCBase_incref((CFCBase*)method);
    self->methods[self->num_methods] = NULL;
}
Beispiel #22
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;
}
Beispiel #23
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 #24
0
static void
S_add_file(CFCHierarchy *self, CFCFile *file) {
    CFCUTIL_NULL_CHECK(file);
    CFCClass **classes = CFCFile_classes(file);

    self->num_files++;
    size_t size = (self->num_files + 1) * sizeof(CFCFile*);
    self->files = (CFCFile**)REALLOCATE(self->files, size);
    self->files[self->num_files - 1]
        = (CFCFile*)CFCBase_incref((CFCBase*)file);
    self->files[self->num_files] = NULL;

    for (size_t i = 0; classes[i] != NULL; i++) {
        CFCClass *klass = classes[i];
        const char *parent_name = CFCClass_get_parent_class_name(klass);
        if (!parent_name) {
            S_add_tree(self, klass);
        }
    }
}
Beispiel #25
0
CFCClass*
CFCClass_fetch_singleton(CFCParcel *parcel, const char *class_name) {
    CFCUTIL_NULL_CHECK(class_name);

    // Build up the key.
    const char *last_colon = strrchr(class_name, ':');
    const char *struct_sym = last_colon
                             ? last_colon + 1
                             : class_name;
    const char *prefix = parcel ? CFCParcel_get_prefix(parcel) : "";
    size_t prefix_len = strlen(prefix);
    size_t struct_sym_len = strlen(struct_sym);
    if (prefix_len + struct_sym_len > MAX_SINGLETON_LEN) {
        CFCUtil_die("names too long: '%s', '%s'", prefix, struct_sym);
    }
    char key[MAX_SINGLETON_LEN + 1];
    sprintf(key, "%s%s", prefix, struct_sym);
    for (size_t i = 0; i < registry_size; i++) {
        if (strcmp(registry[i].key, key) == 0) {
            return registry[i].klass;
        }
    }
    return NULL;
}
Beispiel #26
0
void
CFCPython_set_footer(CFCPython *self, const char *footer) {
    CFCUTIL_NULL_CHECK(footer);
    free(self->footer);
    self->footer = CFCUtil_make_c_comment(footer);
}
Beispiel #27
0
void
CFCPython_set_header(CFCPython *self, const char *header) {
    CFCUTIL_NULL_CHECK(header);
    free(self->header);
    self->header = CFCUtil_make_c_comment(header);
}
Beispiel #28
0
CFCSymbol*
CFCSymbol_init(CFCSymbol *self, struct CFCParcel *parcel,
               const char *exposure, const char *class_name,
               const char *class_cnick, const char *micro_sym) {
    // Validate.
    CFCUTIL_NULL_CHECK(parcel);
    if (!S_validate_exposure(exposure)) {
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Invalid exposure: '%s'", exposure ? exposure : "[NULL]");
    }
    if (class_name && !S_validate_class_name(class_name)) {
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Invalid class_name: '%s'", class_name);
    }
    if (!micro_sym || !S_validate_identifier(micro_sym)) {
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Invalid micro_sym: '%s'",  micro_sym ? micro_sym : "[NULL]");
    }

    // Derive class_cnick if necessary, then validate.
    const char *real_cnick = NULL;
    if (class_name) {
        if (class_cnick) {
            real_cnick = class_cnick;
        }
        else {
            const char *last_colon = strrchr(class_name, ':');
            real_cnick = last_colon ? last_colon + 1 : class_name;
        }
    }
    else if (class_cnick) {
        // Sanity check class_cnick without class_name.
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Can't supply class_cnick without class_name");
    }
    else {
        real_cnick = NULL;
    }
    if (real_cnick && !S_validate_class_cnick(real_cnick)) {
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Invalid class_cnick: '%s'", real_cnick);
    }

    // Assign.
    self->parcel      = (CFCParcel*)CFCBase_incref((CFCBase*)parcel);
    self->exposure    = CFCUtil_strdup(exposure);
    self->class_name  = CFCUtil_strdup(class_name);
    self->class_cnick = CFCUtil_strdup(real_cnick);
    self->micro_sym   = CFCUtil_strdup(micro_sym);

    // Derive short_sym.
    size_t class_cnick_len = self->class_cnick
                             ? strlen(self->class_cnick)
                             : 0;
    size_t short_sym_len = class_cnick_len
                           + strlen("_")
                           + strlen(self->micro_sym);
    self->short_sym = (char*)MALLOCATE(short_sym_len + 1);
    if (self->class_cnick) {
        memcpy((void*)self->short_sym, self->class_cnick, class_cnick_len);
    }
    self->short_sym[class_cnick_len] = '_';
    memcpy(&self->short_sym[class_cnick_len + 1],
           self->micro_sym, strlen(micro_sym));
    self->short_sym[short_sym_len] = '\0';

    // Derive full_sym;
    const char *prefix       = CFCParcel_get_prefix(self->parcel);
    size_t      prefix_len   = strlen(prefix);
    size_t      full_sym_len = prefix_len + short_sym_len;
    self->full_sym = (char*)MALLOCATE(full_sym_len + 1);
    memcpy(self->full_sym, prefix, prefix_len);
    memcpy(&self->full_sym[prefix_len], self->short_sym, short_sym_len);
    self->full_sym[full_sym_len] = '\0';

    return self;
}
Beispiel #29
0
void
CFCPerl_write_bindings(CFCPerl *self, const char *boot_class,
                       CFCParcel **parcels) {
    CFCUTIL_NULL_CHECK(boot_class);
    CFCUTIL_NULL_CHECK(parcels);

    CFCClass     **ordered  = CFCHierarchy_ordered_classes(self->hierarchy);
    CFCPerlClass **registry = CFCPerlClass_registry();
    char *privacy_syms    = CFCUtil_strdup("");
    char *includes        = CFCUtil_strdup("");
    char *generated_xs    = CFCUtil_strdup("");
    char *class_specs     = CFCUtil_strdup("");
    char *xsub_specs      = CFCUtil_strdup("");
    char *bootstrap_calls = CFCUtil_strdup("");
    char *hand_rolled_xs  = CFCUtil_strdup("");

    for (size_t i = 0; parcels[i]; ++i) {
        CFCParcel *parcel = parcels[i];

        // Set host_module_name for parcel.
        if (!CFCParcel_included(parcel) && CFCParcel_is_installed(parcel)) {
            CFCParcel_set_host_module_name(parcel, boot_class);
        }

        // Bake the parcel privacy defines into the XS, so it can be compiled
        // without any extra compiler flags.
        const char *privacy_sym = CFCParcel_get_privacy_sym(parcel);
        privacy_syms = CFCUtil_cat(privacy_syms, "#define ", privacy_sym,
                                   "\n", NULL);

        // Bootstrap calls.
        const char *prefix = CFCParcel_get_prefix(parcel);
        includes = CFCUtil_cat(includes, "#include \"", prefix, "perl.h\"\n",
                               NULL);
        bootstrap_calls = CFCUtil_cat(bootstrap_calls, "    ", prefix,
                                      "bootstrap_perl();\n", NULL);
    }

    for (size_t i = 0; ordered[i] != NULL; i++) {
        CFCClass *klass = ordered[i];

        CFCParcel *parcel = CFCClass_get_parcel(klass);
        int found = false;
        for (size_t j = 0; parcels[j]; j++) {
            if (parcel == parcels[j]) {
                found = true;
                break;
            }
        }
        if (!found) { continue; }

        // Pound-includes for generated headers.
        const char *include_h = CFCClass_include_h(klass);
        includes = CFCUtil_cat(includes, "#include \"", include_h, "\"\n",
                               NULL);

        if (CFCClass_inert(klass)) { continue; }
        int num_xsubs = 0;

        // Constructors.
        CFCPerlConstructor **constructors
            = CFCPerlClass_constructor_bindings(klass);
        for (size_t j = 0; constructors[j] != NULL; j++) {
            CFCPerlSub *xsub = (CFCPerlSub*)constructors[j];

            // Add the XSUB function definition.
            char *xsub_def
                = CFCPerlConstructor_xsub_def(constructors[j], klass);
            generated_xs = CFCUtil_cat(generated_xs, xsub_def, "\n",
                                       NULL);
            FREEMEM(xsub_def);

            // Add XSUB initialization at boot.
            xsub_specs = S_add_xsub_spec(xsub_specs, xsub);
            num_xsubs += 1;

            CFCBase_decref((CFCBase*)constructors[j]);
        }
        FREEMEM(constructors);

        // Methods.
        CFCPerlMethod **methods = CFCPerlClass_method_bindings(klass);
        for (size_t j = 0; methods[j] != NULL; j++) {
            CFCPerlSub *xsub = (CFCPerlSub*)methods[j];

            // Add the XSUB function definition.
            char *xsub_def = CFCPerlMethod_xsub_def(methods[j], klass);
            generated_xs = CFCUtil_cat(generated_xs, xsub_def, "\n",
                                       NULL);
            FREEMEM(xsub_def);

            // Add XSUB initialization at boot.
            xsub_specs = S_add_xsub_spec(xsub_specs, xsub);
            num_xsubs += 1;

            CFCBase_decref((CFCBase*)methods[j]);
        }
        FREEMEM(methods);

        // Append XSBind_ClassSpec entry.
        const char *class_name = CFCClass_get_name(klass);
        CFCClass *parent = CFCClass_get_parent(klass);
        char *parent_name;
        if (parent) {
            parent_name = CFCUtil_sprintf("\"%s\"", CFCClass_get_name(parent));
        }
        else {
            parent_name = CFCUtil_strdup("NULL");
        }
        char *class_spec = CFCUtil_sprintf("{ \"%s\", %s, %d }", class_name,
                                           parent_name, num_xsubs);
        const char *sep = class_specs[0] == '\0' ? "" : ",\n";
        class_specs = CFCUtil_cat(class_specs, sep, "        ", class_spec,
                                  NULL);
        FREEMEM(class_spec);
        FREEMEM(parent_name);
    }

    // Hand-rolled XS.
    for (size_t i = 0; registry[i] != NULL; i++) {
        CFCPerlClass *perl_class = registry[i];

        CFCParcel *parcel = CFCPerlClass_get_parcel(perl_class);
        int found = false;
        for (size_t j = 0; parcels[j]; j++) {
            if (parcel == parcels[j]) {
                found = true;
                break;
            }
        }
        if (!found) { continue; }

        const char *xs = CFCPerlClass_get_xs_code(perl_class);
        hand_rolled_xs = CFCUtil_cat(hand_rolled_xs, xs, "\n", NULL);
    }

    const char pattern[] =
        "%s" // Header.
        "\n"
        "%s" // Privacy syms.
        "\n"
        "#include \"XSBind.h\"\n"
        "%s" // Includes.
        "\n"
        "#ifndef XS_INTERNAL\n"
        "  #define XS_INTERNAL XS\n"
        "#endif\n"
        "\n"
        "%s" // Generated XS.
        "\n"
        "MODULE = %s   PACKAGE = %s\n" // Boot class.
        "\n"
        "BOOT:\n"
        "{\n"
        "    static const cfish_XSBind_ClassSpec class_specs[] = {\n"
        "%s\n" // Class specs.
        "    };\n"
        "    static const cfish_XSBind_XSubSpec xsub_specs[] = {\n"
        "%s\n" // XSUB specs.
        "    };\n"
        "    size_t num_classes\n"
        "        = sizeof(class_specs) / sizeof(class_specs[0]);\n"
        "    const char* file = __FILE__;\n"
        "\n"
        "%s" // Bootstrap calls.
        "\n"
        "    cfish_XSBind_bootstrap(aTHX_ num_classes, class_specs,\n"
        "                           xsub_specs, file);\n"
        "}\n"
        "\n"
        "%s" // Hand-rolled XS.
        "\n"
        "%s"; // Footer
    char *contents
        = CFCUtil_sprintf(pattern, self->c_header, privacy_syms, includes,
                          generated_xs, boot_class, boot_class, class_specs,
                          xsub_specs, bootstrap_calls, hand_rolled_xs,
                          self->c_footer);

    // Derive path to generated .xs file.
    char *xs_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.xs", self->lib_dir,
                                    boot_class);
    S_replace_double_colons(xs_path, CHY_DIR_SEP_CHAR);

    // Write out if there have been any changes.
    CFCUtil_write_if_changed(xs_path, contents, strlen(contents));

    FREEMEM(xs_path);
    FREEMEM(contents);
    FREEMEM(hand_rolled_xs);
    FREEMEM(bootstrap_calls);
    FREEMEM(xsub_specs);
    FREEMEM(class_specs);
    FREEMEM(generated_xs);
    FREEMEM(includes);
    FREEMEM(privacy_syms);
    FREEMEM(ordered);
}
Beispiel #30
0
void
CFCBindFile_write_h(CFCFile *file, const char *dest, const char *header,
                    const char *footer) {
    CFCUTIL_NULL_CHECK(file);
    CFCUTIL_NULL_CHECK(dest);
    CFCUTIL_NULL_CHECK(header);
    CFCUTIL_NULL_CHECK(footer);

    // Make directories.
    char *h_path = CFCFile_h_path(file, dest);
    char *h_dir  = CFCUtil_strdup(h_path);
    for (size_t len = strlen(h_dir); len--;) {
        if (h_dir[len] == CHY_DIR_SEP_CHAR) {
            h_dir[len] = 0;
            break;
        }
    }
    if (!CFCUtil_is_dir(h_dir)) {
        CFCUtil_make_path(h_dir);
        if (!CFCUtil_is_dir(h_dir)) {
            CFCUtil_die("Can't make path %s", h_dir);
        }
    }
    FREEMEM(h_dir);

    // Create the include-guard strings.
    const char *include_guard_start = CFCFile_guard_start(file);
    const char *include_guard_close = CFCFile_guard_close(file);

    // Aggregate block content.
    char *content = CFCUtil_strdup("");
    CFCBase **blocks = CFCFile_blocks(file);
    for (int i = 0; blocks[i] != NULL; i++) {
        const char *cfc_class = CFCBase_get_cfc_class(blocks[i]);

        if (strcmp(cfc_class, "Clownfish::CFC::Model::Parcel") == 0) {
            CFCParcel *parcel = (CFCParcel*)blocks[i];
            const char *prefix = CFCParcel_get_prefix(parcel);
            content = CFCUtil_cat(content, "#include \"", prefix,
                                  "parcel.h\"\n\n", NULL);
        }
        else if (strcmp(cfc_class, "Clownfish::CFC::Model::Class") == 0) {
            CFCBindClass *class_binding
                = CFCBindClass_new((CFCClass*)blocks[i]);
            char *c_header = CFCBindClass_to_c_header(class_binding);
            content = CFCUtil_cat(content, c_header, "\n", NULL);
            FREEMEM(c_header);
            CFCBase_decref((CFCBase*)class_binding);
        }
        else if (strcmp(cfc_class, "Clownfish::CFC::Model::CBlock") == 0) {
            const char *block_contents 
                = CFCCBlock_get_contents((CFCCBlock*)blocks[i]);
            content = CFCUtil_cat(content, block_contents, "\n", NULL);
        }
        else {
            CFCUtil_die("Unexpected class: %s", cfc_class);
        }
    }

    char pattern[] =
        "%s\n"
        "\n"
        "%s\n"
        "\n"
        "#ifdef __cplusplus\n"
        "extern \"C\" {\n"
        "#endif\n"
        "\n"
        "%s\n"
        "\n"
        "#ifdef __cplusplus\n"
        "}\n"
        "#endif\n"
        "\n"
        "%s\n"
        "\n"
        "%s\n"
        "\n";
    char *file_content
        = CFCUtil_sprintf(pattern, header, include_guard_start, content,
                          include_guard_close, footer);

    // Unlink then write file.
    remove(h_path);
    CFCUtil_write_file(h_path, file_content, strlen(file_content));

    FREEMEM(content);
    FREEMEM(file_content);
    FREEMEM(h_path);
}