static void
S_run_tests(CFCTest *test) {
    {
        CFCFileSpec *file_spec
            = CFCFileSpec_new("Clownfish/_include", "Stuff/Thing", ".cfh", 0);
        STR_EQ(test, CFCFileSpec_get_source_dir(file_spec),
               "Clownfish/_include", "get_source_dir");
        STR_EQ(test, CFCFileSpec_get_path_part(file_spec),
               "Stuff/Thing", "get_path_part");
        OK(test, !CFCFileSpec_included(file_spec), "not included");

        CFCBase_decref((CFCBase*)file_spec);
    }

    {
        CFCFileSpec *file_spec
            = CFCFileSpec_new("Clownfish/_include", "Stuff/Thing", ".cfh", 1);
        OK(test, CFCFileSpec_included(file_spec), "included");

        CFCBase_decref((CFCBase*)file_spec);
    }
}
Beispiel #2
0
int
CFCClass_included(CFCClass *self) {
    return self->file_spec ? CFCFileSpec_included(self->file_spec) : 0;
}
Beispiel #3
0
int
CFCParcel_included(CFCParcel *self) {
    return self->file_spec ? CFCFileSpec_included(self->file_spec) : false;
}
Beispiel #4
0
CFCClass*
CFCClass_do_create(CFCClass *self, struct CFCParcel *parcel,
                   const char *exposure, const char *class_name,
                   const char *cnick, const char *micro_sym,
                   CFCDocuComment *docucomment, CFCFileSpec *file_spec,
                   const char *parent_class_name, int is_final, int is_inert) {
    CFCUTIL_NULL_CHECK(class_name);
    exposure  = exposure  ? exposure  : "parcel";
    micro_sym = micro_sym ? micro_sym : "class";
    parcel    = parcel    ? parcel    : CFCParcel_default_parcel();
    CFCSymbol_init((CFCSymbol*)self, parcel, exposure, class_name, cnick,
                   micro_sym);
    if (!is_inert
        && !parent_class_name
        && strcmp(class_name, "Clownfish::Obj") != 0
       ) {
        parent_class_name = "Clownfish::Obj";
    }
    self->parent     = NULL;
    self->tree_grown = false;
    self->children        = (CFCClass**)CALLOCATE(1, sizeof(CFCClass*));
    self->num_kids        = 0;
    self->functions       = (CFCFunction**)CALLOCATE(1, sizeof(CFCFunction*));
    self->num_functions   = 0;
    self->methods         = (CFCMethod**)CALLOCATE(1, sizeof(CFCMethod*));
    self->num_methods     = 0;
    self->member_vars     = (CFCVariable**)CALLOCATE(1, sizeof(CFCVariable*));
    self->num_member_vars = 0;
    self->inert_vars      = (CFCVariable**)CALLOCATE(1, sizeof(CFCVariable*));
    self->num_inert_vars  = 0;
    self->parent_class_name = CFCUtil_strdup(parent_class_name);
    self->docucomment
        = (CFCDocuComment*)CFCBase_incref((CFCBase*)docucomment);
    self->file_spec = (CFCFileSpec*)CFCBase_incref((CFCBase*)file_spec);

    // Cache several derived symbols.
    const char *last_colon = strrchr(class_name, ':');
    self->struct_sym = last_colon
                       ? CFCUtil_strdup(last_colon + 1)
                       : CFCUtil_strdup(class_name);
    const char *prefix = CFCClass_get_prefix(self);
    size_t struct_sym_len = strlen(self->struct_sym);
    self->short_vtable_var = (char*)MALLOCATE(struct_sym_len + 1);
    size_t i;
    for (i = 0; i < struct_sym_len; i++) {
        self->short_vtable_var[i] = toupper(self->struct_sym[i]);
    }
    self->short_vtable_var[struct_sym_len] = '\0';
    self->full_struct_sym   = CFCUtil_sprintf("%s%s", prefix, self->struct_sym);
    self->ivars_struct      = CFCUtil_sprintf("%sIVARS", self->struct_sym);
    self->full_ivars_struct = CFCUtil_sprintf("%sIVARS", self->full_struct_sym);
    self->ivars_func        = CFCUtil_sprintf("%s_IVARS", CFCClass_get_cnick(self));
    self->full_ivars_func   = CFCUtil_sprintf("%s%s_IVARS", prefix,
                                              CFCClass_get_cnick(self));
    self->full_ivars_offset = CFCUtil_sprintf("%s_OFFSET", self->full_ivars_func);
    size_t full_struct_sym_len = strlen(self->full_struct_sym);
    self->full_vtable_var = (char*)MALLOCATE(full_struct_sym_len + 1);
    for (i = 0; self->full_struct_sym[i] != '\0'; i++) {
        self->full_vtable_var[i] = toupper(self->full_struct_sym[i]);
    }
    self->full_vtable_var[i] = '\0';
    self->privacy_symbol = CFCUtil_sprintf("C_%s", self->full_vtable_var);

    // Build the relative path to the autogenerated C header file.
    if (file_spec) {
        const char *path_part = CFCFileSpec_get_path_part(self->file_spec);
        self->include_h = CFCUtil_sprintf("%s.h", path_part);
    }
    else {
        self->include_h = CFCUtil_strdup("class.h");
    }

    self->is_final    = !!is_final;
    self->is_inert    = !!is_inert;

    if (file_spec && CFCFileSpec_included(file_spec)) {
        if (!CFCParcel_included(parcel)) {
            CFCUtil_die("Class %s from include dir found in parcel %s from"
                        " source dir",
                        class_name, CFCParcel_get_name(parcel));
        }
    }
    else {
        if (CFCParcel_included(parcel)) {
            CFCUtil_die("Class %s from source dir found in parcel %s from"
                        " include dir",
                        class_name, CFCParcel_get_name(parcel));
        }
    }

    // Store in registry.
    S_register(self);

    return self;
}
Beispiel #5
0
static CFCParcel*
S_new_from_json(const char *json, CFCFileSpec *file_spec) {
    const char *path = file_spec ? CFCFileSpec_get_path(file_spec) : "[NULL]";
    CFCJson *parsed = CFCJson_parse(json);
    if (!parsed) {
        CFCUtil_die("Invalid JSON parcel definition in '%s'", path);
    }
    if (CFCJson_get_type(parsed) != CFCJSON_HASH) {
        CFCUtil_die("Parcel definition must be a hash in '%s'", path);
    }
    const char  *name          = NULL;
    const char  *nickname      = NULL;
    int          installed     = true;
    CFCVersion  *version       = NULL;
    CFCVersion  *major_version = NULL;
    CFCJson     *prereqs       = NULL;
    CFCJson    **children      = CFCJson_get_children(parsed);
    for (size_t i = 0; children[i]; i += 2) {
        const char *key = CFCJson_get_string(children[i]);
        CFCJson *value = children[i + 1];
        int value_type = CFCJson_get_type(value);
        if (strcmp(key, "name") == 0) {
            if (value_type != CFCJSON_STRING) {
                CFCUtil_die("'name' must be a string (filepath %s)", path);
            }
            name = CFCJson_get_string(value);
        }
        else if (strcmp(key, "nickname") == 0) {
            if (value_type != CFCJSON_STRING) {
                CFCUtil_die("'nickname' must be a string (filepath %s)",
                            path);
            }
            nickname = CFCJson_get_string(value);
        }
        else if (strcmp(key, "installed") == 0) {
            if (value_type != CFCJSON_BOOL) {
                CFCUtil_die("'installed' must be a boolean (filepath %s)",
                            path);
            }
            installed = CFCJson_get_bool(value);
        }
        else if (strcmp(key, "version") == 0) {
            if (value_type != CFCJSON_STRING) {
                CFCUtil_die("'version' must be a string (filepath %s)",
                            path);
            }
            version = CFCVersion_new(CFCJson_get_string(value));
        }
        else if (strcmp(key, "major_version") == 0) {
            if (value_type != CFCJSON_STRING) {
                CFCUtil_die("'major_version' must be a string (filepath %s)",
                            path);
            }
            major_version = CFCVersion_new(CFCJson_get_string(value));
        }
        else if (strcmp(key, "prerequisites") == 0) {
            if (value_type != CFCJSON_HASH) {
                CFCUtil_die("'prerequisites' must be a hash (filepath %s)",
                            path);
            }
            prereqs = value;
        }
        else {
            CFCUtil_die("Unrecognized key: '%s' (filepath '%s')",
                        key, path);
        }
    }
    if (!name) {
        CFCUtil_die("Missing required key 'name' (filepath '%s')", path);
    }
    if (!version) {
        CFCUtil_die("Missing required key 'version' (filepath '%s')", path);
    }
    CFCParcel *self = CFCParcel_new(name, nickname, version, major_version,
                                    file_spec);
    if (!file_spec || !CFCFileSpec_included(file_spec)) {
        self->is_installed = installed;
    }
    if (prereqs) {
        S_set_prereqs(self, prereqs, path);
    }
    CFCBase_decref((CFCBase*)version);
    CFCBase_decref((CFCBase*)major_version);

    CFCJson_destroy(parsed);
    return self;
}