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; }
CFCClass* CFCClass_do_create(CFCClass *self, struct CFCParcel *parcel, const char *exposure, const char *name, const char *nickname, CFCDocuComment *docucomment, CFCFileSpec *file_spec, const char *parent_class_name, int is_final, int is_inert, int is_abstract) { CFCUTIL_NULL_CHECK(parcel); CFCUTIL_NULL_CHECK(name); exposure = exposure ? exposure : "parcel"; // Validate. if (!S_validate_exposure(exposure)) { CFCBase_decref((CFCBase*)self); CFCUtil_die("Invalid exposure: '%s'", exposure); } if (!CFCClass_validate_class_name(name)) { CFCBase_decref((CFCBase*)self); CFCUtil_die("Invalid name: '%s'", name); } const char *last_colon = strrchr(name, ':'); const char *struct_sym = last_colon ? last_colon + 1 : name; // Derive nickname if necessary, then validate. const char *real_nickname = NULL; if (nickname) { real_nickname = nickname; } else { real_nickname = struct_sym; } if (!S_validate_nickname(real_nickname)) { CFCBase_decref((CFCBase*)self); CFCUtil_die("Invalid nickname: '%s'", real_nickname); } // Default parent class name is "Clownfish::Obj". if (!is_inert && !parent_class_name && strcmp(name, "Clownfish::Obj") != 0 ) { parent_class_name = "Clownfish::Obj"; } // Assign. self->parcel = (CFCParcel*)CFCBase_incref((CFCBase*)parcel); self->exposure = CFCUtil_strdup(exposure); self->name = CFCUtil_strdup(name); self->nickname = CFCUtil_strdup(real_nickname); self->tree_grown = false; self->parent = NULL; self->children = (CFCClass**)CALLOCATE(1, sizeof(CFCClass*)); self->num_kids = 0; self->functions = (CFCFunction**)CALLOCATE(1, sizeof(CFCFunction*)); self->num_functions = 0; self->fresh_methods = (CFCMethod**)CALLOCATE(1, sizeof(CFCMethod*)); self->num_fresh_meths = 0; self->methods = NULL; self->num_methods = 0; self->fresh_vars = (CFCVariable**)CALLOCATE(1, sizeof(CFCVariable*)); self->num_fresh_vars = 0; self->member_vars = NULL; 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 *prefix = CFCClass_get_prefix(self); self->struct_sym = CFCUtil_strdup(struct_sym); self->full_struct_sym = CFCUtil_sprintf("%s%s", prefix, struct_sym); self->ivars_struct = CFCUtil_sprintf("%sIVARS", struct_sym); self->full_ivars_struct = CFCUtil_sprintf("%s%s", prefix, self->ivars_struct); self->ivars_func = CFCUtil_sprintf("%s_IVARS", self->nickname); self->full_ivars_func = CFCUtil_sprintf("%s%s", prefix, self->ivars_func); self->full_ivars_offset = CFCUtil_sprintf("%s_OFFSET", self->full_ivars_func); const char *PREFIX = CFCClass_get_PREFIX(self); size_t struct_sym_len = strlen(struct_sym); char *short_class_var = (char*)MALLOCATE(struct_sym_len + 1); size_t i; for (i = 0; i < struct_sym_len; i++) { short_class_var[i] = toupper(struct_sym[i]); } short_class_var[struct_sym_len] = '\0'; self->short_class_var = short_class_var; self->full_class_var = CFCUtil_sprintf("%s%s", PREFIX, short_class_var); self->privacy_symbol = CFCUtil_sprintf("C_%s", self->full_class_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; self->is_abstract = !!is_abstract; // Check for include flag mismatch. if (!CFCClass_included(self) && CFCParcel_included(parcel)) { CFCUtil_die("Class %s from source dir found in parcel %s from" " include dir", name, CFCParcel_get_name(parcel)); } // Skip class if it's from an include dir and the parcel was already // processed in another source or include dir. const char *class_source_dir = CFCClass_get_source_dir(self); const char *parcel_source_dir = CFCParcel_get_source_dir(parcel); if (!CFCClass_included(self) || !class_source_dir || !parcel_source_dir || strcmp(class_source_dir, parcel_source_dir) == 0 ) { char *error; CFCUTIL_TRY { // Store in registry. S_register(self); } CFCUTIL_CATCH(error); if (error) { CFCBase_decref((CFCBase*)self); CFCUtil_rethrow(error); } CFCParcel_add_struct_sym(parcel, self->struct_sym); }