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; }
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; }
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; }
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); }
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; }
void CFCParcel_add_class(CFCParcel *self, CFCClass *klass) { // Ensure unique class name. const char *class_name = CFCClass_get_name(klass); CFCClass *other = S_fetch_class(self, class_name, 2); if (other) { CFCUtil_die("Two classes with name %s", class_name); } const char *struct_sym = CFCClass_get_struct_sym(klass); const char *nickname = CFCClass_get_nickname(klass); for (size_t i = 0; self->classes[i]; ++i) { CFCClass *other = self->classes[i]; // Ensure unique struct symbol and nickname in parcel. if (strcmp(struct_sym, CFCClass_get_struct_sym(other)) == 0) { CFCUtil_die("Class name conflict between %s and %s", CFCClass_get_name(klass), CFCClass_get_name(other)); } if (strcmp(nickname, CFCClass_get_nickname(other)) == 0) { CFCUtil_die("Class nickname conflict between %s and %s", CFCClass_get_name(klass), CFCClass_get_name(other)); } } size_t num_classes = self->num_classes; size_t size = (num_classes + 2) * sizeof(CFCClass*); CFCClass **classes = (CFCClass**)REALLOCATE(self->classes, size); classes[num_classes] = (CFCClass*)CFCBase_incref((CFCBase*)klass); classes[num_classes+1] = NULL; self->classes = classes; self->num_classes = num_classes + 1; }
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; }
CFCClass* CFCGoClass_get_client(CFCGoClass *self) { if (!self->client) { CFCClass *client = CFCClass_fetch_singleton(self->parcel, self->class_name); self->client = (CFCClass*)CFCBase_incref((CFCBase*)client); } return self->client; }
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; }
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; }
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; }
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; }
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; }
CFCParcel* CFCParcel_init(CFCParcel *self, const char *name, const char *cnick, CFCVersion *version) { // Validate name. if (!name || !S_validate_name_or_cnick(name)) { CFCUtil_die("Invalid name: '%s'", name ? name : "[NULL]"); } self->name = CFCUtil_strdup(name); // Validate or derive cnick. if (cnick) { if (!S_validate_name_or_cnick(cnick)) { CFCUtil_die("Invalid cnick: '%s'", cnick); } self->cnick = CFCUtil_strdup(cnick); } else { // Default cnick to name. self->cnick = CFCUtil_strdup(name); } // Default to version v0. if (version) { self->version = (CFCVersion*)CFCBase_incref((CFCBase*)version); } else { self->version = CFCVersion_new("v0"); } // Derive prefix, Prefix, PREFIX. size_t cnick_len = strlen(self->cnick); size_t prefix_len = cnick_len ? cnick_len + 1 : 0; size_t amount = prefix_len + 1; self->prefix = (char*)MALLOCATE(amount); self->Prefix = (char*)MALLOCATE(amount); self->PREFIX = (char*)MALLOCATE(amount); memcpy(self->Prefix, self->cnick, cnick_len); if (cnick_len) { self->Prefix[cnick_len] = '_'; self->Prefix[cnick_len + 1] = '\0'; } else { self->Prefix[cnick_len] = '\0'; } for (size_t i = 0; i < amount; i++) { self->prefix[i] = tolower(self->Prefix[i]); self->PREFIX[i] = toupper(self->Prefix[i]); } self->prefix[prefix_len] = '\0'; self->Prefix[prefix_len] = '\0'; self->PREFIX[prefix_len] = '\0'; return self; }
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; }
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; }
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; }
CFCType* CFCType_init(CFCType *self, int flags, struct CFCParcel *parcel, const char *specifier, int indirection) { self->flags = flags; self->parcel = (CFCParcel*)CFCBase_incref((CFCBase*)parcel); self->specifier = CFCUtil_strdup(specifier); self->indirection = indirection; self->c_string = NULL; self->width = 0; self->array = NULL; self->child = NULL; self->vtable_var = NULL; return self; }
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; }
static void S_register(CFCClass *self) { if (registry_size == registry_cap) { size_t new_cap = registry_cap + 10; registry = (CFCClassRegEntry*)REALLOCATE( registry, (new_cap + 1) * sizeof(CFCClassRegEntry)); for (size_t i = registry_cap; i <= new_cap; i++) { registry[i].key = NULL; registry[i].klass = NULL; } registry_cap = new_cap; } CFCParcel *parcel = CFCClass_get_parcel(self); const char *prefix = CFCParcel_get_prefix(parcel); const char *class_name = CFCClass_get_class_name(self); const char *cnick = CFCClass_get_cnick(self); const char *key = self->full_struct_sym; for (size_t i = 0; i < registry_size; i++) { CFCClass *other = registry[i].klass; CFCParcel *other_parcel = CFCClass_get_parcel(other); const char *other_prefix = CFCParcel_get_prefix(other_parcel); const char *other_class_name = CFCClass_get_class_name(other); const char *other_cnick = CFCClass_get_cnick(other); if (strcmp(class_name, other_class_name) == 0) { CFCUtil_die("Two classes with name %s", class_name); } if (strcmp(registry[i].key, key) == 0) { CFCUtil_die("Class name conflict between %s and %s", class_name, other_class_name); } if (strcmp(prefix, other_prefix) == 0 && strcmp(cnick, other_cnick) == 0 ) { CFCUtil_die("Class nickname conflict between %s and %s", class_name, other_class_name); } } registry[registry_size].key = CFCUtil_strdup(key); registry[registry_size].klass = (CFCClass*)CFCBase_incref((CFCBase*)self); registry_size++; }
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; }
static void S_register(CFCDocument *self) { if (CFCDocument_fetch(self->name) != NULL) { CFCUtil_die("Two documents with name %s", self->name); } if (registry_size == registry_cap) { size_t new_cap = registry_cap + 10; size_t bytes = (new_cap + 1) * sizeof(CFCDocument*); registry = (CFCDocument**)REALLOCATE(registry, bytes); registry_cap = new_cap; } registry[registry_size] = (CFCDocument*)CFCBase_incref((CFCBase*)self); registry[registry_size+1] = NULL; registry_size++; }
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; }
CFCPrereq* CFCPrereq_init(CFCPrereq *self, const char *name, CFCVersion *version) { // Validate name. if (!name || !S_validate_name_or_nickname(name)) { CFCUtil_die("Invalid name: '%s'", name ? name : "[NULL]"); } self->name = CFCUtil_strdup(name); // Default to version v0. if (version) { self->version = (CFCVersion*)CFCBase_incref((CFCBase*)version); } else { self->version = CFCVersion_new("v0"); } return self; }
void CFCGoClass_register(CFCGoClass *self) { if (registry_size == registry_cap) { size_t new_cap = registry_cap + 10; size_t amount = (new_cap + 1) * sizeof(CFCGoClass*); registry = (CFCGoClass**)REALLOCATE(registry, amount); for (size_t i = registry_cap; i <= new_cap; i++) { registry[i] = NULL; } registry_cap = new_cap; } CFCGoClass *existing = CFCGoClass_singleton(self->class_name); if (existing) { CFCUtil_die("Class '%s' already registered", self->class_name); } registry[registry_size] = (CFCGoClass*)CFCBase_incref((CFCBase*)self); registry_size++; qsort(registry, registry_size, sizeof(CFCGoClass*), S_compare_cfcgoclass); }
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); } } }
// Pass down member vars to from parent to children. static void S_bequeath_member_vars(CFCClass *self) { for (size_t i = 0; self->children[i] != NULL; i++) { CFCClass *child = self->children[i]; size_t num_vars = self->num_member_vars + child->num_member_vars; size_t size = (num_vars + 1) * sizeof(CFCVariable*); child->member_vars = (CFCVariable**)REALLOCATE(child->member_vars, size); memmove(child->member_vars + self->num_member_vars, child->member_vars, child->num_member_vars * sizeof(CFCVariable*)); memcpy(child->member_vars, self->member_vars, self->num_member_vars * sizeof(CFCVariable*)); for (size_t j = 0; self->member_vars[j] != NULL; j++) { CFCBase_incref((CFCBase*)child->member_vars[j]); } child->num_member_vars = num_vars; child->member_vars[num_vars] = NULL; S_bequeath_member_vars(child); } }
CFCType* CFCType_new_composite(int flags, CFCType *child, int indirection, const char *array) { if (!child) { CFCUtil_die("Missing required param 'child'"); } flags |= CFCTYPE_COMPOSITE; S_check_flags(flags, CFCTYPE_COMPOSITE | CFCTYPE_NULLABLE, "Composite"); CFCType *self = CFCType_new(flags, NULL, CFCType_get_specifier(child), indirection); self->child = (CFCType*)CFCBase_incref((CFCBase*)child); // Record array spec. const char *array_spec = array ? array : ""; size_t array_spec_size = strlen(array_spec) + 1; self->array = (char*)MALLOCATE(array_spec_size); strcpy(self->array, array_spec); return self; }
CFCType* CFCType_init(CFCType *self, int flags, struct CFCParcel *parcel, const char *specifier, int indirection, const char *c_string) { self->flags = flags; self->parcel = (CFCParcel*)CFCBase_incref((CFCBase*)parcel); self->specifier = CFCUtil_strdup(specifier); self->indirection = indirection; self->c_string = c_string ? CFCUtil_strdup(c_string) : CFCUtil_strdup(""); self->width = 0; self->array = NULL; self->child = NULL; if (flags & CFCTYPE_OBJECT) { self->vtable_var = CFCUtil_strdup(specifier); for (int i = 0; self->vtable_var[i] != 0; i++) { self->vtable_var[i] = toupper(self->vtable_var[i]); } } else { self->vtable_var = NULL; } return self; }
CFCPerlMethod* CFCPerlMethod_init(CFCPerlMethod *self, CFCMethod *method, const char *alias) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *class_name = CFCMethod_get_class_name(method); int use_labeled_params = CFCParamList_num_vars(param_list) > 2 ? 1 : 0; // The Clownfish destructor needs to be spelled DESTROY for Perl. if (!alias) { alias = CFCMethod_micro_sym(method); } static const char destroy_uppercase[] = "DESTROY"; if (strcmp(alias, "destroy") == 0) { alias = destroy_uppercase; } CFCPerlSub_init((CFCPerlSub*)self, param_list, class_name, alias, use_labeled_params); self->method = (CFCMethod*)CFCBase_incref((CFCBase*)method); return self; }