CFCType* CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier, int indirection) { // Validate params. if (indirection != 1) { CFCUtil_die("Parameter 'indirection' can only be 1"); } if (!specifier || !strlen(specifier)) { CFCUtil_die("Missing required param 'specifier'"); } if ((flags & CFCTYPE_INCREMENTED) && (flags & CFCTYPE_DECREMENTED)) { CFCUtil_die("Can't be both incremented and decremented"); } // Use default parcel if none supplied. if (!parcel) { parcel = CFCParcel_default_parcel(); } // Add flags. flags |= CFCTYPE_OBJECT; if (strstr(specifier, "String")) { // Determine whether this type is a string type. flags |= CFCTYPE_STRING_TYPE; } // Validate specifier. if (!isalpha(*specifier)) { CFCUtil_die("Invalid specifier: '%s'", specifier); } const char *small_specifier = specifier; while (!isupper(*small_specifier)) { if (!isalnum(*small_specifier) && *small_specifier != '_') { CFCUtil_die("Invalid specifier: '%s'", specifier); } small_specifier++; } if (!CFCSymbol_validate_class_name_component(small_specifier)) { CFCUtil_die("Invalid specifier: '%s'", specifier); } int acceptable_flags = CFCTYPE_OBJECT | CFCTYPE_STRING_TYPE | CFCTYPE_CONST | CFCTYPE_NULLABLE | CFCTYPE_INCREMENTED | CFCTYPE_DECREMENTED; S_check_flags(flags, acceptable_flags, "Object"); return CFCType_new(flags, parcel, specifier, 1); }
CFCParcel* CFCParcel_fetch(const char *name) { // Return the default parcel for either a blank name or a NULL name. if (!name || !strlen(name)) { return CFCParcel_default_parcel(); } for (size_t i = 0; i < num_registered ; i++) { CFCParcel *existing = registry[i]; if (strcmp(existing->name, name) == 0) { return existing; } } return NULL; }
void CFCParcel_register(CFCParcel *self) { CFCParcel *existing = CFCParcel_fetch(self->name); if (existing) { CFCUtil_die("Parcel '%s' already registered", self->name); } if (!num_registered) { // Init default parcel as first. registry = (CFCParcel**)CALLOCATE(3, sizeof(CFCParcel*)); CFCParcel *def = CFCParcel_default_parcel(); registry[0] = (CFCParcel*)CFCBase_incref((CFCBase*)def); num_registered++; } size_t size = (num_registered + 2) * sizeof(CFCParcel*); registry = (CFCParcel**)REALLOCATE(registry, size); registry[num_registered++] = (CFCParcel*)CFCBase_incref((CFCBase*)self); registry[num_registered] = NULL; }
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; }
CFCType* CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier, int indirection) { // Validate params. if (indirection != 1) { CFCUtil_die("Parameter 'indirection' can only be 1"); } if (!specifier || !strlen(specifier)) { CFCUtil_die("Missing required param 'specifier'"); } if ((flags & CFCTYPE_INCREMENTED) && (flags & CFCTYPE_DECREMENTED)) { CFCUtil_die("Can't be both incremented and decremented"); } // Use default parcel if none supplied. if (!parcel) { parcel = CFCParcel_default_parcel(); } // Add flags. flags |= CFCTYPE_OBJECT; if (strstr(specifier, "CharBuf")) { // Determine whether this type is a string type. flags |= CFCTYPE_STRING_TYPE; } const size_t MAX_SPECIFIER_LEN = 256; char full_specifier[MAX_SPECIFIER_LEN + 1]; char small_specifier[MAX_SPECIFIER_LEN + 1]; if (isupper(*specifier)) { const char *prefix = CFCParcel_get_prefix(parcel); if (strlen(prefix) + strlen(specifier) > MAX_SPECIFIER_LEN) { CFCUtil_die("Specifier and/or parcel prefix too long"); } sprintf(full_specifier, "%s%s", prefix, specifier); strcpy(small_specifier, specifier); } else if (!isalpha(*specifier)) { CFCUtil_die("Invalid specifier: '%s'", specifier); } else { if (strlen(specifier) > MAX_SPECIFIER_LEN) { CFCUtil_die("Specifier too long"); } const char *probe = specifier; while (*probe) { if (isupper(*probe)) { break; } else if (!isalnum(*probe) && *probe != '_') { CFCUtil_die("Invalid specifier: '%s'", specifier); } probe++; } strcpy(full_specifier, specifier); strcpy(small_specifier, probe); } if (!CFCSymbol_validate_class_name_component(small_specifier)) { CFCUtil_die("Invalid specifier: '%s'", specifier); } // Cache C representation. char c_string[MAX_SPECIFIER_LEN + 10]; if (flags & CFCTYPE_CONST) { sprintf(c_string, "const %s*", full_specifier); } else { sprintf(c_string, "%s*", full_specifier); } int acceptable_flags = CFCTYPE_OBJECT | CFCTYPE_STRING_TYPE | CFCTYPE_CONST | CFCTYPE_NULLABLE | CFCTYPE_INCREMENTED | CFCTYPE_DECREMENTED; S_check_flags(flags, acceptable_flags, "Object"); return CFCType_new(flags, parcel, full_specifier, 1, c_string); }
static void S_run_tests(CFCTest *test) { CFCParcel *parcel = CFCParcel_default_parcel(); { static const char *exposures[4] = { "public", "private", "parcel", "local" }; static int (*accessors[4])(CFCSymbol *sym) = { CFCSymbol_public, CFCSymbol_private, CFCSymbol_parcel, CFCSymbol_local }; for (int i = 0; i < 4; ++i) { CFCSymbol *symbol = CFCSymbol_new(parcel, exposures[i], NULL, NULL, "sym"); for (int j = 0; j < 4; ++j) { int has_exposure = accessors[j](symbol); if (i == j) { OK(test, has_exposure, "exposure %s", exposures[i]); } else { OK(test, !has_exposure, "%s means not %s", exposures[i], exposures[j]); } } CFCBase_decref((CFCBase*)symbol); } } { CFCSymbol *foo = CFCSymbol_new(parcel, "parcel", "Foo", NULL, "sym"); CFCSymbol *foo_jr = CFCSymbol_new(parcel, "parcel", "Foo::FooJr", NULL, "sym"); int equal = CFCSymbol_equals(foo, foo_jr); OK(test, !equal, "different class_name spoils equals"); const char *foo_jr_name = CFCSymbol_get_class_name(foo_jr); STR_EQ(test, foo_jr_name, "Foo::FooJr", "get_class_name"); const char *foo_jr_cnick = CFCSymbol_get_class_cnick(foo_jr); STR_EQ(test, foo_jr_cnick, "FooJr", "derive class_cnick from class_name"); CFCBase_decref((CFCBase*)foo); CFCBase_decref((CFCBase*)foo_jr); } { CFCSymbol *public_exposure = CFCSymbol_new(parcel, "public", NULL, NULL, "sym"); CFCSymbol *parcel_exposure = CFCSymbol_new(parcel, "parcel", NULL, NULL, "sym"); int equal = CFCSymbol_equals(public_exposure, parcel_exposure); OK(test, !equal, "different exposure spoils equals"); CFCBase_decref((CFCBase*)public_exposure); CFCBase_decref((CFCBase*)parcel_exposure); } { CFCParcel *lucifer_parcel = CFCParcel_new("Lucifer", NULL, NULL, false); CFCParcel_register(lucifer_parcel); CFCSymbol *lucifer = CFCSymbol_new(lucifer_parcel, "parcel", NULL, NULL, "sym"); CFCParcel *symbol_parcel = CFCSymbol_get_parcel(lucifer); OK(test, symbol_parcel == lucifer_parcel, "derive parcel"); const char *prefix = CFCSymbol_get_prefix(lucifer); STR_EQ(test, prefix, "lucifer_", "get_prefix"); const char *Prefix = CFCSymbol_get_Prefix(lucifer); STR_EQ(test, Prefix, "Lucifer_", "get_Prefix"); const char *PREFIX = CFCSymbol_get_PREFIX(lucifer); STR_EQ(test, PREFIX, "LUCIFER_", "get_PREFIX"); CFCParcel *luser_parcel = CFCParcel_new("Luser", NULL, NULL, false); CFCParcel_register(luser_parcel); CFCSymbol *luser = CFCSymbol_new(luser_parcel, "parcel", NULL, NULL, "sym"); int equal = CFCSymbol_equals(lucifer, luser); OK(test, !equal, "different exposure spoils equals"); CFCBase_decref((CFCBase*)lucifer_parcel); CFCBase_decref((CFCBase*)lucifer); CFCBase_decref((CFCBase*)luser_parcel); CFCBase_decref((CFCBase*)luser); } { CFCSymbol *ooga = CFCSymbol_new(parcel, "parcel", NULL, NULL, "ooga"); CFCSymbol *booga = CFCSymbol_new(parcel, "parcel", NULL, NULL, "booga"); int equal = CFCSymbol_equals(ooga, booga); OK(test, !equal, "different micro_sym spoils equals"); CFCBase_decref((CFCBase*)ooga); CFCBase_decref((CFCBase*)booga); } { CFCParcel *eep_parcel = CFCParcel_new("Eep", NULL, NULL, false); CFCParcel_register(eep_parcel); CFCSymbol *eep = CFCSymbol_new(eep_parcel, "parcel", "Op::Ork", NULL, "ah_ah"); const char *short_sym = CFCSymbol_short_sym(eep); STR_EQ(test, short_sym, "Ork_ah_ah", "short_sym"); const char *full_sym = CFCSymbol_full_sym(eep); STR_EQ(test, full_sym, "eep_Ork_ah_ah", "full_sym"); CFCBase_decref((CFCBase*)eep_parcel); CFCBase_decref((CFCBase*)eep); } CFCParcel_reap_singletons(); }