static char* S_full_method_sym(CFCMethod *self, CFCClass *invoker, const char *postfix) { const char *PREFIX; const char *cnick; if (invoker) { PREFIX = CFCClass_get_PREFIX(invoker); cnick = CFCClass_get_cnick(invoker); } else { PREFIX = CFCMethod_get_PREFIX(self); cnick = CFCMethod_get_class_cnick(self); } return CFCUtil_sprintf("%s%s_%s%s", PREFIX, cnick, self->macro_sym, postfix); }
static char* S_virtual_method_def(CFCMethod *method, CFCClass *klass) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *PREFIX = CFCClass_get_PREFIX(klass); const char *invoker_struct = CFCClass_full_struct_sym(klass); 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); // Prepare parameter lists, minus invoker. The invoker gets forced to // "self" later. if (CFCParamList_variadic(param_list)) { CFCUtil_die("Variadic methods not supported"); } const char *arg_names_minus_invoker = CFCParamList_name_list(param_list); const char *params_minus_invoker = CFCParamList_to_c(param_list); while (*arg_names_minus_invoker && *arg_names_minus_invoker != ',') { arg_names_minus_invoker++; } while (*params_minus_invoker && *params_minus_invoker != ',') { params_minus_invoker++; } // 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 pattern[] = "extern %sVISIBLE size_t %s;\n" "static CFISH_INLINE %s\n" "%s(%s *self%s) {\n" " const %s method = (%s)cfish_obj_method(self, %s);\n" " %smethod(self%s);\n" "}\n"; char *method_def = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str, full_meth_sym, invoker_struct, params_minus_invoker, full_typedef, full_typedef, full_offset_sym, maybe_return, arg_names_minus_invoker); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); FREEMEM(full_typedef); return method_def; }
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; }
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); }