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); } }
int CFCClass_included(CFCClass *self) { return self->file_spec ? CFCFileSpec_included(self->file_spec) : 0; }
int CFCParcel_included(CFCParcel *self) { return self->file_spec ? CFCFileSpec_included(self->file_spec) : false; }
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; }
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; }