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); }
static char* S_ivars_size(CFCClass *klass) { CFCParcel *parcel = CFCClass_get_parcel(klass); char *ivars_size = NULL; if (CFCParcel_is_cfish(parcel)) { const char *struct_sym = CFCClass_full_struct_sym(klass); ivars_size = CFCUtil_sprintf("sizeof(%s)", struct_sym); } else { size_t num_non_package_ivars = CFCClass_num_non_package_ivars(klass); size_t num_ivars = CFCClass_num_member_vars(klass); if (num_non_package_ivars == num_ivars) { // No members in this package. ivars_size = CFCUtil_strdup("0"); } else { const char *ivars_struct = CFCClass_full_ivars_struct(klass); ivars_size = CFCUtil_sprintf("sizeof(%s)", ivars_struct); } } return ivars_size; }
char* CFCBindMeth_method_def(CFCMethod *method, CFCClass *klass) { // If the method is final and the class where it is declared final is in // the same parcel as the invocant, we can optimize the call by resolving // to the implementing function directly. if (CFCMethod_final(method)) { CFCClass *ancestor = klass; while (ancestor && !CFCMethod_is_fresh(method, ancestor)) { ancestor = CFCClass_get_parent(ancestor); } if (CFCClass_get_parcel(ancestor) == CFCClass_get_parcel(klass)) { return S_optimized_final_method_def(method, klass); } } return S_virtual_method_def(method, klass); }
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++; }
void CFCType_resolve(CFCType *self, CFCClass **classes) { if (CFCType_is_composite(self)) { CFCType_resolve(self->child, classes); return; } if (!CFCType_is_object(self)) { return; } CFCClass *klass = NULL; char *specifier = self->specifier; if (isupper(self->specifier[0])) { // Try to find class from class list. for (size_t i = 0; classes[i]; ++i) { CFCClass *maybe_class = classes[i]; const char *struct_sym = CFCClass_get_struct_sym(maybe_class); if (strcmp(specifier, struct_sym) == 0) { if (klass) { CFCUtil_die("Type '%s' is ambigious", specifier); } klass = maybe_class; } } if (!klass) { CFCUtil_die("No class found for type '%s'", specifier); } // Create actual specifier with prefix. const char *prefix = CFCClass_get_prefix(klass); self->specifier = CFCUtil_sprintf("%s%s", prefix, specifier); FREEMEM(specifier); } else { // Try to find class from class list. for (size_t i = 0; classes[i]; ++i) { CFCClass *maybe_class = classes[i]; const char *full_struct_sym = CFCClass_full_struct_sym(maybe_class); if (strcmp(specifier, full_struct_sym) == 0) { klass = maybe_class; break; } } } // Add parcel dependency. if (klass) { CFCParcel *class_parcel = CFCClass_get_parcel(klass); CFCParcel_add_dependent_parcel(self->parcel, class_parcel); } }
static CFCMethod* S_make_method_obj(CFCClass *klass, const char *method_name) { const char *klass_full_struct_sym = CFCClass_full_struct_sym(klass); const char *klass_name = CFCClass_get_class_name(klass); const char *klass_cnick = CFCClass_get_cnick(klass); CFCParcel *klass_parcel = CFCClass_get_parcel(klass); CFCType *return_type = CFCType_new_object(CFCTYPE_INCREMENTED, klass_parcel, "cfish_Obj", 1); CFCType *self_type = CFCType_new_object(0, klass_parcel, klass_full_struct_sym, 1); CFCVariable *self_var = CFCVariable_new(NULL, NULL, NULL, NULL, "self", self_type, false); CFCParamList *param_list = NULL; if (strcmp(method_name, "Dump") == 0) { param_list = CFCParamList_new(false); CFCParamList_add_param(param_list, self_var, NULL); } else if (strcmp(method_name, "Load") == 0) { CFCType *dump_type = CFCType_new_object(0, klass_parcel, "cfish_Obj", 1); CFCVariable *dump_var = CFCVariable_new(NULL, NULL, NULL, NULL, "dump", dump_type, false); param_list = CFCParamList_new(false); CFCParamList_add_param(param_list, self_var, NULL); CFCParamList_add_param(param_list, dump_var, NULL); CFCBase_decref((CFCBase*)dump_var); CFCBase_decref((CFCBase*)dump_type); } else { CFCUtil_die("Unexpected method_name: '%s'", method_name); } CFCMethod *method = CFCMethod_new(klass_parcel, "public", klass_name, klass_cnick, method_name, return_type, param_list, NULL, false, false); CFCBase_decref((CFCBase*)param_list); CFCBase_decref((CFCBase*)self_type); CFCBase_decref((CFCBase*)self_var); CFCBase_decref((CFCBase*)return_type); return method; }
char* CFCGoClass_gen_ctors(CFCGoClass *self) { CFCFunction *ctor_func = CFCClass_function(self->client, "new"); if (self->suppress_ctor || !ctor_func || !CFCFunction_can_be_bound(ctor_func) ) { return CFCUtil_strdup(""); } CFCParcel *parcel = CFCClass_get_parcel(self->client); CFCParamList *param_list = CFCFunction_get_param_list(ctor_func); CFCType *ret_type = CFCFunction_get_return_type(ctor_func); const char *struct_sym = CFCClass_get_struct_sym(self->client); char *name = CFCUtil_sprintf("New%s", struct_sym); char *cfunc = CFCFunction_full_func_sym(ctor_func, self->client); char *cfargs = CFCGoFunc_ctor_cfargs(parcel, param_list); char *first_line = CFCGoFunc_ctor_start(parcel, name, param_list, ret_type); char *ret_statement = CFCGoFunc_return_statement(parcel, ret_type, "retvalCF"); char pattern[] = "%s" "\tretvalCF := C.%s(%s)\n" "%s" "}\n" ; char *content = CFCUtil_sprintf(pattern, first_line, cfunc, cfargs, ret_statement); FREEMEM(ret_statement); FREEMEM(cfargs); FREEMEM(cfunc); FREEMEM(first_line); FREEMEM(name); return content; }
char* CFCGoClass_go_typing(CFCGoClass *self) { char *content = NULL; if (!self->client) { CFCUtil_die("Can't find class for %s", self->class_name); } else if (CFCClass_inert(self->client)) { content = CFCUtil_strdup(""); } else { const char *short_struct = CFCClass_get_struct_sym(self->client); CFCClass *parent = CFCClass_get_parent(self->client); char *parent_type_str = NULL; if (parent) { const char *parent_struct = CFCClass_get_struct_sym(parent); CFCParcel *parent_parcel = CFCClass_get_parcel(parent); if (parent_parcel == self->parcel) { parent_type_str = CFCUtil_strdup(parent_struct); } else { char *parent_package = CFCGoTypeMap_go_short_package(parent_parcel); parent_type_str = CFCUtil_sprintf("%s.%s", parent_package, parent_struct); FREEMEM(parent_package); } } char *go_struct_def; if (parent && !self->suppress_struct) { go_struct_def = CFCUtil_sprintf("type %sIMP struct {\n\t%sIMP\n}\n", short_struct, parent_type_str); } else { go_struct_def = CFCUtil_strdup(""); } char *parent_iface; if (parent) { parent_iface = CFCUtil_sprintf("\t%s\n", parent_type_str); } else { parent_iface = CFCUtil_strdup(""); } char *novel_iface = CFCUtil_strdup(""); S_lazy_init_method_bindings(self); for (int i = 0; self->method_bindings[i] != NULL; i++) { CFCGoMethod *meth_binding = self->method_bindings[i]; CFCMethod *method = CFCGoMethod_get_client(meth_binding); if (method) { if (!CFCMethod_novel(method)) { continue; } const char *sym = CFCMethod_get_name(method); if (!CFCClass_fresh_method(self->client, sym)) { continue; } } const char *sig = CFCGoMethod_get_sig(meth_binding, self->client); novel_iface = CFCUtil_cat(novel_iface, "\t", sig, "\n", NULL); } char pattern[] = "type %s interface {\n" "%s" "%s" "}\n" "\n" "%s" ; content = CFCUtil_sprintf(pattern, short_struct, parent_iface, novel_iface, go_struct_def); FREEMEM(parent_type_str); FREEMEM(go_struct_def); FREEMEM(parent_iface); } return content; }
static char* S_method_def(CFCMethod *method, CFCClass *klass, int optimized_final_meth) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *PREFIX = CFCClass_get_PREFIX(klass); const char *invoker_struct = CFCClass_full_struct_sym(klass); const char *self_name = CFCParamList_param_name(param_list, 0); char *full_meth_sym = CFCMethod_full_method_sym(method, klass); char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); char *full_typedef = CFCMethod_full_typedef(method, klass); char *full_imp_sym = CFCMethod_imp_func(method, klass); // Prepare parameter lists, minus the type of the invoker. if (CFCParamList_variadic(param_list)) { CFCUtil_die("Variadic methods not supported"); } const char *arg_names = CFCParamList_name_list(param_list); const char *params_end = CFCParamList_to_c(param_list); while (*params_end && *params_end != '*') { params_end++; } // Prepare a return statement... or not. CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *maybe_return = CFCType_is_void(return_type) ? "" : "return "; const char innards_pattern[] = " const %s method = (%s)cfish_obj_method(%s, %s);\n" " %smethod(%s);\n" ; char *innards = CFCUtil_sprintf(innards_pattern, full_typedef, full_typedef, self_name, full_offset_sym, maybe_return, arg_names); if (optimized_final_meth) { CFCParcel *parcel = CFCClass_get_parcel(klass); const char *privacy_sym = CFCParcel_get_privacy_sym(parcel); char *invoker_cast = CFCUtil_strdup(""); if (!CFCMethod_is_fresh(method, klass)) { CFCType *self_type = CFCMethod_self_type(method); invoker_cast = CFCUtil_cat(invoker_cast, "(", CFCType_to_c(self_type), ")", NULL); } const char pattern[] = "#ifdef %s\n" " %s%s(%s%s);\n" "#else\n" "%s" "#endif\n" ; char *temp = CFCUtil_sprintf(pattern, privacy_sym, maybe_return, full_imp_sym, invoker_cast, arg_names, innards); FREEMEM(innards); innards = temp; FREEMEM(invoker_cast); } const char pattern[] = "extern %sVISIBLE uint32_t %s;\n" "static CFISH_INLINE %s\n" "%s(%s%s) {\n" "%s" "}\n"; char *method_def = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str, full_meth_sym, invoker_struct, params_end, innards); FREEMEM(innards); FREEMEM(full_imp_sym); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); FREEMEM(full_typedef); return method_def; }
void CFCPerl_write_bindings(CFCPerl *self, const char *boot_class, CFCParcel **parcels) { CFCUTIL_NULL_CHECK(boot_class); CFCUTIL_NULL_CHECK(parcels); CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); CFCPerlClass **registry = CFCPerlClass_registry(); char *privacy_syms = CFCUtil_strdup(""); char *includes = CFCUtil_strdup(""); char *generated_xs = CFCUtil_strdup(""); char *class_specs = CFCUtil_strdup(""); char *xsub_specs = CFCUtil_strdup(""); char *bootstrap_calls = CFCUtil_strdup(""); char *hand_rolled_xs = CFCUtil_strdup(""); for (size_t i = 0; parcels[i]; ++i) { CFCParcel *parcel = parcels[i]; // Set host_module_name for parcel. if (!CFCParcel_included(parcel) && CFCParcel_is_installed(parcel)) { CFCParcel_set_host_module_name(parcel, boot_class); } // Bake the parcel privacy defines into the XS, so it can be compiled // without any extra compiler flags. const char *privacy_sym = CFCParcel_get_privacy_sym(parcel); privacy_syms = CFCUtil_cat(privacy_syms, "#define ", privacy_sym, "\n", NULL); // Bootstrap calls. const char *prefix = CFCParcel_get_prefix(parcel); includes = CFCUtil_cat(includes, "#include \"", prefix, "perl.h\"\n", NULL); bootstrap_calls = CFCUtil_cat(bootstrap_calls, " ", prefix, "bootstrap_perl();\n", NULL); } for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; CFCParcel *parcel = CFCClass_get_parcel(klass); int found = false; for (size_t j = 0; parcels[j]; j++) { if (parcel == parcels[j]) { found = true; break; } } if (!found) { continue; } // Pound-includes for generated headers. const char *include_h = CFCClass_include_h(klass); includes = CFCUtil_cat(includes, "#include \"", include_h, "\"\n", NULL); if (CFCClass_inert(klass)) { continue; } int num_xsubs = 0; // Constructors. CFCPerlConstructor **constructors = CFCPerlClass_constructor_bindings(klass); for (size_t j = 0; constructors[j] != NULL; j++) { CFCPerlSub *xsub = (CFCPerlSub*)constructors[j]; // Add the XSUB function definition. char *xsub_def = CFCPerlConstructor_xsub_def(constructors[j], klass); generated_xs = CFCUtil_cat(generated_xs, xsub_def, "\n", NULL); FREEMEM(xsub_def); // Add XSUB initialization at boot. xsub_specs = S_add_xsub_spec(xsub_specs, xsub); num_xsubs += 1; CFCBase_decref((CFCBase*)constructors[j]); } FREEMEM(constructors); // Methods. CFCPerlMethod **methods = CFCPerlClass_method_bindings(klass); for (size_t j = 0; methods[j] != NULL; j++) { CFCPerlSub *xsub = (CFCPerlSub*)methods[j]; // Add the XSUB function definition. char *xsub_def = CFCPerlMethod_xsub_def(methods[j], klass); generated_xs = CFCUtil_cat(generated_xs, xsub_def, "\n", NULL); FREEMEM(xsub_def); // Add XSUB initialization at boot. xsub_specs = S_add_xsub_spec(xsub_specs, xsub); num_xsubs += 1; CFCBase_decref((CFCBase*)methods[j]); } FREEMEM(methods); // Append XSBind_ClassSpec entry. const char *class_name = CFCClass_get_name(klass); CFCClass *parent = CFCClass_get_parent(klass); char *parent_name; if (parent) { parent_name = CFCUtil_sprintf("\"%s\"", CFCClass_get_name(parent)); } else { parent_name = CFCUtil_strdup("NULL"); } char *class_spec = CFCUtil_sprintf("{ \"%s\", %s, %d }", class_name, parent_name, num_xsubs); const char *sep = class_specs[0] == '\0' ? "" : ",\n"; class_specs = CFCUtil_cat(class_specs, sep, " ", class_spec, NULL); FREEMEM(class_spec); FREEMEM(parent_name); } // Hand-rolled XS. for (size_t i = 0; registry[i] != NULL; i++) { CFCPerlClass *perl_class = registry[i]; CFCParcel *parcel = CFCPerlClass_get_parcel(perl_class); int found = false; for (size_t j = 0; parcels[j]; j++) { if (parcel == parcels[j]) { found = true; break; } } if (!found) { continue; } const char *xs = CFCPerlClass_get_xs_code(perl_class); hand_rolled_xs = CFCUtil_cat(hand_rolled_xs, xs, "\n", NULL); } const char pattern[] = "%s" // Header. "\n" "%s" // Privacy syms. "\n" "#include \"XSBind.h\"\n" "%s" // Includes. "\n" "#ifndef XS_INTERNAL\n" " #define XS_INTERNAL XS\n" "#endif\n" "\n" "%s" // Generated XS. "\n" "MODULE = %s PACKAGE = %s\n" // Boot class. "\n" "BOOT:\n" "{\n" " static const cfish_XSBind_ClassSpec class_specs[] = {\n" "%s\n" // Class specs. " };\n" " static const cfish_XSBind_XSubSpec xsub_specs[] = {\n" "%s\n" // XSUB specs. " };\n" " size_t num_classes\n" " = sizeof(class_specs) / sizeof(class_specs[0]);\n" " const char* file = __FILE__;\n" "\n" "%s" // Bootstrap calls. "\n" " cfish_XSBind_bootstrap(aTHX_ num_classes, class_specs,\n" " xsub_specs, file);\n" "}\n" "\n" "%s" // Hand-rolled XS. "\n" "%s"; // Footer char *contents = CFCUtil_sprintf(pattern, self->c_header, privacy_syms, includes, generated_xs, boot_class, boot_class, class_specs, xsub_specs, bootstrap_calls, hand_rolled_xs, self->c_footer); // Derive path to generated .xs file. char *xs_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.xs", self->lib_dir, boot_class); S_replace_double_colons(xs_path, CHY_DIR_SEP_CHAR); // Write out if there have been any changes. CFCUtil_write_if_changed(xs_path, contents, strlen(contents)); FREEMEM(xs_path); FREEMEM(contents); FREEMEM(hand_rolled_xs); FREEMEM(bootstrap_calls); FREEMEM(xsub_specs); FREEMEM(class_specs); FREEMEM(generated_xs); FREEMEM(includes); FREEMEM(privacy_syms); FREEMEM(ordered); }