static void S_run_void_tests(CFCTest *test) { CFCParser *parser = CFCParser_new(); { CFCType *type = CFCType_new_void(false); STR_EQ(test, CFCType_get_specifier(type), "void", "get_specifier"); STR_EQ(test, CFCType_to_c(type), "void", "to_c"); OK(test, CFCType_is_void(type), "is_void"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCType_new_void(true); STR_EQ(test, CFCType_to_c(type), "const void", "'const' in C representation"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCTest_parse_type(test, parser, "void"); OK(test, CFCType_is_void(type), "void is_void"); CFCBase_decref((CFCBase*)type); } { CFCType *type = CFCTest_parse_type(test, parser, "const void"); OK(test, CFCType_is_void(type), "const void is_void"); OK(test, CFCType_const(type), "const void is const"); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); }
static void S_run_basic_tests(CFCTest *test) { CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL); CFCParcel_register(neato_parcel); CFCType *type = CFCType_new(0, neato_parcel, "mytype_t", 0); OK(test, CFCType_get_parcel(type) == neato_parcel, "get_parcel"); STR_EQ(test, CFCType_to_c(type), "mytype_t", "to_c"); STR_EQ(test, CFCType_get_specifier(type), "mytype_t", "get_specifier"); #define TEST_BOOL_ACCESSOR(type, name) \ OK(test, !CFCType_ ## name(type), #name " false by default"); TEST_BOOL_ACCESSOR(type, const); TEST_BOOL_ACCESSOR(type, nullable); TEST_BOOL_ACCESSOR(type, incremented); TEST_BOOL_ACCESSOR(type, decremented); TEST_BOOL_ACCESSOR(type, is_void); TEST_BOOL_ACCESSOR(type, is_object); TEST_BOOL_ACCESSOR(type, is_primitive); TEST_BOOL_ACCESSOR(type, is_integer); TEST_BOOL_ACCESSOR(type, is_floating); TEST_BOOL_ACCESSOR(type, is_string_type); TEST_BOOL_ACCESSOR(type, is_va_list); TEST_BOOL_ACCESSOR(type, is_arbitrary); TEST_BOOL_ACCESSOR(type, is_composite); CFCBase_decref((CFCBase*)neato_parcel); CFCBase_decref((CFCBase*)type); CFCParcel_reap_singletons(); }
static char* S_primitive_callback_def(CFCMethod *method, const char *callback_start, const char *refcount_mods) { const char *override_sym = CFCMethod_full_override_sym(method); const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *micro_sym = CFCMethod_micro_sym(method); char callback_func[50]; if (CFCType_is_integer(return_type)) { strcpy(callback_func, "S_finish_callback_i64"); } else if (CFCType_is_floating(return_type)) { strcpy(callback_func, "S_finish_callback_f64"); } else { CFCUtil_die("Unexpected type: %s", ret_type_str); } char pattern[] = "%s\n" "%s(%s) {\n" "%s" " %s retval = (%s)%s(\"%s\");%s\n" " return retval;\n" "}\n"; char *callback_def = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params, callback_start, ret_type_str, ret_type_str, callback_func, micro_sym, refcount_mods); return callback_def; }
char* CFCBindMeth_abstract_method_def(CFCMethod *method) { CFCParamList *param_list = CFCMethod_get_param_list(method); const char *params = CFCParamList_to_c(param_list); const char *full_func_sym = CFCMethod_imp_func(method); const char *vtable_var = CFCType_get_vtable_var(CFCMethod_self_type(method)); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *macro_sym = CFCMethod_get_macro_sym(method); // Thwart compiler warnings. CFCVariable **param_vars = CFCParamList_get_variables(param_list); char *unused = S_build_unused_vars(param_vars + 1); char *return_statement = S_maybe_unreachable(return_type); char pattern[] = "%s\n" "%s(%s) {\n" " cfish_String *klass = self ? CFISH_Obj_Get_Class_Name((cfish_Obj*)self) : %s->name;%s\n" " CFISH_THROW(CFISH_ERR, \"Abstract method '%s' not defined by %%o\", klass);%s\n" "}\n"; char *abstract_def = CFCUtil_sprintf(pattern, ret_type_str, full_func_sym, params, vtable_var, unused, macro_sym, return_statement); FREEMEM(unused); FREEMEM(return_statement); return abstract_def; }
static char* S_invalid_callback_def(CFCMethod *method) { char *full_method_sym = CFCMethod_full_method_sym(method, NULL); const char *override_sym = CFCMethod_full_override_sym(method); CFCParamList *param_list = CFCMethod_get_param_list(method); const char *params = CFCParamList_to_c(param_list); CFCVariable **param_vars = CFCParamList_get_variables(param_list); // Thwart compiler warnings. CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); char *unused = S_build_unused_vars(param_vars); char *unreachable = S_maybe_unreachable(return_type); char pattern[] = "%s\n" "%s(%s) {%s\n" " CFISH_THROW(CFISH_ERR, \"Can't override %s via binding\");%s\n" "}\n"; char *callback_def = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params, unused, full_method_sym, unreachable); FREEMEM(full_method_sym); FREEMEM(unreachable); FREEMEM(unused); return callback_def; }
/* Create a macro definition that aliases to a function name directly, since * this method may not be overridden. */ static char* S_final_method_def(CFCMethod *method, CFCClass *klass) { const char *self_type = CFCType_to_c(CFCMethod_self_type(method)); const char *full_func_sym = CFCMethod_implementing_func_sym(method); const char *arg_names = CFCParamList_name_list(CFCMethod_get_param_list(method)); size_t meth_sym_size = CFCMethod_full_method_sym(method, klass, NULL, 0); char *full_meth_sym = (char*)MALLOCATE(meth_sym_size); CFCMethod_full_method_sym(method, klass, full_meth_sym, meth_sym_size); size_t offset_sym_size = CFCMethod_full_offset_sym(method, klass, NULL, 0); char *full_offset_sym = (char*)MALLOCATE(offset_sym_size); CFCMethod_full_offset_sym(method, klass, full_offset_sym, offset_sym_size); const char pattern[] = "extern size_t %s;\n#define %s(%s) \\\n %s((%s)%s)\n"; size_t size = sizeof(pattern) + strlen(full_offset_sym) + strlen(full_meth_sym) + strlen(arg_names) + strlen(full_func_sym) + strlen(self_type) + strlen(arg_names) + 20; char *method_def = (char*)MALLOCATE(size); sprintf(method_def, pattern, full_offset_sym, full_meth_sym, arg_names, full_func_sym, self_type, arg_names); FREEMEM(full_offset_sym); FREEMEM(full_meth_sym); return method_def; }
char* CFCPerlConstructor_xsub_def(CFCPerlConstructor *self) { const char *c_name = self->sub.c_name; CFCParamList *param_list = self->sub.param_list; const char *name_list = CFCParamList_name_list(param_list); CFCVariable **arg_vars = CFCParamList_get_variables(param_list); const char *func_sym = CFCFunction_full_func_sym(self->init_func); char *allot_params = CFCPerlSub_build_allot_params((CFCPerlSub*)self); CFCVariable *self_var = arg_vars[0]; CFCType *self_type = CFCVariable_get_type(self_var); const char *self_type_str = CFCType_to_c(self_type); // Compensate for swallowed refcounts. char *refcount_mods = CFCUtil_strdup(""); for (size_t i = 0; arg_vars[i] != NULL; i++) { CFCVariable *var = arg_vars[i]; CFCType *type = CFCVariable_get_type(var); if (CFCType_is_object(type) && CFCType_decremented(type)) { const char *name = CFCVariable_micro_sym(var); refcount_mods = CFCUtil_cat(refcount_mods, "\n CFISH_INCREF(", name, ");", NULL); } } const char pattern[] = "XS(%s);\n" "XS(%s) {\n" " dXSARGS;\n" " CFISH_UNUSED_VAR(cv);\n" " if (items < 1) { CFISH_THROW(CFISH_ERR, \"Usage: %%s(class_name, ...)\", GvNAME(CvGV(cv))); }\n" " SP -= items;\n" "\n" " %s\n" // Create "self" last, so that earlier exceptions while fetching // params don't trigger a bad invocation of DESTROY. " %s self = (%s)XSBind_new_blank_obj(ST(0));%s\n" "\n" " %s retval = %s(%s);\n" " if (retval) {\n" " ST(0) = (SV*)CFISH_Obj_To_Host((cfish_Obj*)retval);\n" " CFISH_Obj_Dec_RefCount((cfish_Obj*)retval);\n" " }\n" " else {\n" " ST(0) = newSV(0);\n" " }\n" " sv_2mortal(ST(0));\n" " XSRETURN(1);\n" "}\n\n"; char *xsub_def = CFCUtil_sprintf(pattern, c_name, c_name, allot_params, self_type_str, self_type_str, refcount_mods, self_type_str, func_sym, name_list); FREEMEM(refcount_mods); FREEMEM(allot_params); return xsub_def; }
static void S_process_load_member(CFCClass *klass, CFCVariable *member, char *buf, size_t buf_size) { CFCUTIL_NULL_CHECK(member); CFCType *type = CFCVariable_get_type(member); const char *type_str = CFCType_to_c(type); const char *name = CFCVariable_micro_sym(member); unsigned name_len = (unsigned)strlen(name); char extraction[200]; const char *specifier = CFCType_get_specifier(type); // Skip the VTable. if (strcmp(specifier, "cfish_VTable") == 0) { return; } if (2 * strlen(type_str) + 100 > sizeof(extraction)) { // play it safe CFCUtil_die("type_str too long: '%s'", type_str); } if (CFCType_is_integer(type)) { if (strcmp(specifier, "bool") == 0) { sprintf(extraction, "Cfish_Obj_To_Bool(var)"); } else { sprintf(extraction, "(%s)Cfish_Obj_To_I64(var)", type_str); } } else if (CFCType_is_floating(type)) { sprintf(extraction, "(%s)Cfish_Obj_To_F64(var)", type_str); } else if (CFCType_is_object(type)) { const char *vtable_var = CFCType_get_vtable_var(type); sprintf(extraction, "(%s*)CFISH_CERTIFY(Cfish_Obj_Load(var, var), %s)", specifier, vtable_var); } else { CFCUtil_die("Don't know how to load %s", specifier); } const char *pattern = " {\n" " cfish_Obj *var = Cfish_Hash_Fetch_Str(source, \"%s\", %u);\n" " if (var) { ivars->%s = %s; }\n" " }\n"; size_t needed = sizeof(pattern) + (name_len * 2) + strlen(extraction) + 20; if (buf_size < needed) { CFCUtil_die("Buffer not big enough (%lu < %lu)", (unsigned long)buf_size, (unsigned long)needed); } sprintf(buf, pattern, name, name_len, name, extraction); CFCClass_append_autocode(klass, buf); }
char* CFCBindMeth_imp_declaration(CFCMethod *method) { CFCType *return_type = CFCMethod_get_return_type(method); CFCParamList *param_list = CFCMethod_get_param_list(method); const char *ret_type_str = CFCType_to_c(return_type); const char *full_imp_sym = CFCMethod_imp_func(method); const char *param_list_str = CFCParamList_to_c(param_list); char *buf = CFCUtil_sprintf("%s\n%s(%s);", ret_type_str, full_imp_sym, param_list_str); return buf; }
char* CFCPyMethod_constructor_wrapper(CFCFunction *init_func, CFCClass *invoker) { CFCParamList *param_list = CFCFunction_get_param_list(init_func); const char *self_type = CFCType_to_c(CFCFunction_get_return_type(init_func)); char *func_sym = CFCFunction_full_func_sym(init_func, invoker); char *decs = S_gen_decs(param_list, 1); char *increfs = S_gen_arg_increfs(param_list, 1); char *decrefs = S_gen_decrefs(param_list, 1); const char *class_var = CFCClass_full_class_var(invoker); const char *struct_sym = CFCClass_full_struct_sym(invoker); char *error = NULL; char *arg_parsing = S_gen_arg_parsing(param_list, 1, &error); if (error) { CFCUtil_die("%s in constructor for %s", error, CFCClass_get_name(invoker)); } if (!arg_parsing) { CFCUtil_die("Unexpected arg parsing error for %s", CFCClass_get_name(invoker)); } char *first_arg = CFCUtil_sprintf("(%s)CFISH_Class_Make_Obj(%s)", self_type, class_var); char *arg_list = S_gen_arg_list(param_list, first_arg); char pattern[] = "static PyObject*\n" "S_%s_PY_NEW(PyTypeObject *type, PyObject *args, PyObject *kwargs) {\n" "%s" // decs "%s" // arg_parsing "%s" // increfs " %s self = NULL;\n" " CFBIND_TRY(self = %s(%s));\n" "%s" // decrefs " if (CFBind_migrate_cferr()) {\n" " return NULL;\n" " }\n" " return (PyObject*)self;\n" "}\n" ; char *wrapper = CFCUtil_sprintf(pattern, struct_sym, decs, arg_parsing, increfs, self_type, func_sym, arg_list, decrefs); FREEMEM(arg_list); FREEMEM(first_arg); FREEMEM(func_sym); FREEMEM(decrefs); FREEMEM(increfs); FREEMEM(decs); FREEMEM(arg_parsing); return wrapper; }
static char* S_build_pymeth_invocation(CFCMethod *method) { CFCType *return_type = CFCMethod_get_return_type(method); const char *micro_sym = CFCSymbol_get_name((CFCSymbol*)method); char *invocation = NULL; const char *ret_type_str = CFCType_to_c(return_type); if (CFCType_is_void(return_type)) { const char pattern[] = " CALL_PYMETH_VOID((PyObject*)self, \"%s\", cfcb_ARGS);"; invocation = CFCUtil_sprintf(pattern, micro_sym); } else if (CFCType_is_object(return_type)) { const char *nullable = CFCType_nullable(return_type) ? "true" : "false"; const char *ret_class = CFCType_get_class_var(return_type); const char pattern[] = " %s cfcb_RESULT = (%s)CALL_PYMETH_OBJ((PyObject*)self, \"%s\", cfcb_ARGS, %s, %s);"; invocation = CFCUtil_sprintf(pattern, ret_type_str, ret_type_str, micro_sym, ret_class, nullable); } else if (CFCType_is_primitive(return_type)) { char type_upcase[64]; if (strlen(ret_type_str) > 63) { CFCUtil_die("Unexpectedly long type name: %s", ret_type_str); } for (int i = 0, max = strlen(ret_type_str) + 1; i < max; i++) { type_upcase[i] = toupper(ret_type_str[i]); } const char pattern[] = " %s cfcb_RESULT = CALL_PYMETH_%s((PyObject*)self, \"%s\", cfcb_ARGS);"; invocation = CFCUtil_sprintf(pattern, ret_type_str, type_upcase, micro_sym); } else { CFCUtil_die("Unexpected return type: %s", CFCType_to_c(return_type)); } return invocation; }
// Cache various C string representations. static void S_generate_c_strings(CFCVariable *self) { const char *type_str = CFCType_to_c(self->type); const char *postfix = ""; if (CFCType_is_composite(self->type) && CFCType_get_array(self->type) != NULL ) { postfix = CFCType_get_array(self->type); } const char *name = CFCVariable_get_name(self); self->local_c = CFCUtil_sprintf("%s %s%s", type_str, name, postfix); self->local_dec = CFCUtil_sprintf("%s;", self->local_c); }
static char* S_maybe_unreachable(CFCType *return_type) { char *return_statement; if (CFCType_is_void(return_type)) { return_statement = CFCUtil_strdup(""); } else { const char *ret_type_str = CFCType_to_c(return_type); char pattern[] = "\n CFISH_UNREACHABLE_RETURN(%s);"; return_statement = CFCUtil_sprintf(pattern, ret_type_str); } return return_statement; }
static char* S_gen_decs(CFCParamList *param_list, int first_tick) { char *decs = CFCUtil_strdup(""); int num_vars = CFCParamList_num_vars(param_list); CFCVariable **vars = CFCParamList_get_variables(param_list); for (int i = first_tick; i < num_vars; i++) { CFCType *type = CFCVariable_get_type(vars[i]); const char *name = CFCVariable_get_name(vars[i]); decs = CFCUtil_cat(decs, " ", CFCType_to_c(type), " ", name, "_ARG = 0;\n", NULL); } return decs; }
char* CFCBindMeth_abstract_method_def(CFCMethod *method, CFCClass *klass) { CFCType *ret_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(ret_type); CFCType *type = CFCMethod_self_type(method); const char *class_var = CFCType_get_class_var(type); const char *meth_name = CFCMethod_get_name(method); CFCParamList *param_list = CFCMethod_get_param_list(method); const char *params = CFCParamList_to_c(param_list); CFCVariable **vars = CFCParamList_get_variables(param_list); const char *invocant = CFCVariable_get_name(vars[0]); // All variables other than the invocant are unused, and the return is // unreachable. char *unused = CFCUtil_strdup(""); for (int i = 1; vars[i] != NULL; i++) { const char *var_name = CFCVariable_get_name(vars[i]); size_t size = strlen(unused) + strlen(var_name) + 80; unused = (char*)REALLOCATE(unused, size); strcat(unused, "\n CFISH_UNUSED_VAR("); strcat(unused, var_name); strcat(unused, ");"); } char *unreachable; if (!CFCType_is_void(ret_type)) { unreachable = CFCUtil_sprintf(" CFISH_UNREACHABLE_RETURN(%s);\n", ret_type_str); } else { unreachable = CFCUtil_strdup(""); } char *full_func_sym = CFCMethod_imp_func(method, klass); char pattern[] = "%s\n" "%s(%s) {\n" "%s" " cfish_Err_abstract_method_call((cfish_Obj*)%s, %s, \"%s\");\n" "%s" "}\n"; char *abstract_def = CFCUtil_sprintf(pattern, ret_type_str, full_func_sym, params, unused, invocant, class_var, meth_name, unreachable); FREEMEM(unused); FREEMEM(unreachable); FREEMEM(full_func_sym); return abstract_def; }
static char* S_maybe_unreachable(CFCType *return_type) { char *return_statement; if (CFCType_is_void(return_type)) { return_statement = CFCUtil_strdup(""); } else { const char *ret_type_str = CFCType_to_c(return_type); return_statement = (char*)MALLOCATE(strlen(ret_type_str) + 60); sprintf(return_statement, "\n CHY_UNREACHABLE_RETURN(%s);", ret_type_str); } return return_statement; }
// Create an assignment statement for extracting $self from the Perl stack. static char* S_self_assign_statement(CFCPerlMethod *self, CFCType *type, const char *method_name) { (void)self; // unused const char *type_c = CFCType_to_c(type); if (!CFCType_is_object(type)) { CFCUtil_die("Not an object type: %s", type_c); } const char *vtable_var = CFCType_get_vtable_var(type); char pattern[] = "%s self = (%s)XSBind_sv_to_cfish_obj(ST(0), %s, NULL);"; char *statement = CFCUtil_sprintf(pattern, type_c, type_c, vtable_var); return statement; }
/* Some of the ParseTuple conversion routines provided by the Python-flavored * CFBind module accept a CFBindArg instead of just a pointer to the value * itself. This routine generates the declarations for those CFBindArg * variables, as well as handling some default values. */ static char* S_gen_declaration(CFCVariable *var, const char *val) { CFCType *type = CFCVariable_get_type(var); const char *var_name = CFCVariable_get_name(var); const char *type_str = CFCType_to_c(type); char *result = NULL; if (CFCType_is_object(type)) { const char *specifier = CFCType_get_specifier(type); if (strcmp(specifier, "cfish_String") == 0) { if (val && strcmp(val, "NULL") != 0) { const char pattern[] = " const char arg_%s_DEFAULT[] = %s;\n" " %s_ARG = CFISH_SSTR_WRAP_UTF8(\n" " arg_%s_DEFAULT, sizeof(arg_%s_DEFAULT) - 1);\n" ; result = CFCUtil_sprintf(pattern, var_name, val, var_name, var_name, var_name); } } else { if (val && strcmp(val, "NULL") != 0) { CFCUtil_die("Can't assign a default of '%s' to a %s", val, type_str); } if (strcmp(specifier, "cfish_Hash") != 0 && strcmp(specifier, "cfish_Vector") != 0 ) { const char *class_var = CFCType_get_class_var(type); char pattern[] = " CFBindArg wrap_arg_%s = {%s, &%s_ARG};\n" ; result = CFCUtil_sprintf(pattern, var_name, class_var, var_name); } } } else if (CFCType_is_primitive(type)) { if (val) { char pattern[] = " %s_ARG = %s;\n"; result = CFCUtil_sprintf(pattern, var_name, val); } } else { CFCUtil_die("Unexpected type, can't gen declaration: %s", type_str); } return result; }
char* CFCPyMethod_callback_def(CFCMethod *method, CFCClass *invoker) { CFCParamList *param_list = CFCMethod_get_param_list(method); CFCVariable **vars = CFCParamList_get_variables(param_list); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *params = CFCParamList_to_c(param_list); char *override_sym = CFCMethod_full_override_sym(method, invoker); char *content; if (CFCMethod_can_be_bound(method)) { char *py_args = S_build_py_args(param_list); char *invocation = S_build_pymeth_invocation(method); char *refcount_mods = S_callback_refcount_mods(param_list); const char *maybe_return = CFCType_is_void(return_type) ? "" : " return cfcb_RESULT;\n"; const char pattern[] = "%s\n" "%s(%s) {\n" "%s\n" "%s\n" "%s" "%s" "}\n"; content = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params, py_args, invocation, refcount_mods, maybe_return); } else { char *unused = S_build_unused_vars(vars); char *unreachable = S_maybe_unreachable(return_type); char *meth_sym = CFCMethod_full_method_sym(method, invoker); const char pattern[] = "%s\n" "%s(%s) {%s\n" " CFISH_THROW(CFISH_ERR, \"Can't override %s via binding\");%s\n" "}\n"; content = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params, unused, meth_sym, unreachable); FREEMEM(meth_sym); FREEMEM(unused); FREEMEM(unreachable); } FREEMEM(override_sym); return content; }
char* CFCBindMeth_callback_dec(CFCMethod *method) { CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *override_sym = CFCMethod_full_override_sym(method); const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); char pattern[] = "%s\n" "%s(%s);\n"; char *callback_dec = CFCUtil_sprintf(pattern, ret_type_str, override_sym, params); return callback_dec; }
static char* S_obj_callback_def(CFCMethod *method, const char *callback_params, const char *refcount_mods) { const char *override_sym = CFCMethod_full_override_sym(method); const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *cb_func_name = CFCType_is_string_type(return_type) ? "cfish_Host_callback_str" : "cfish_Host_callback_obj"; char *nullable_check = CFCUtil_strdup(""); if (!CFCType_nullable(return_type)) { const char *macro_sym = CFCMethod_get_macro_sym(method); char pattern[] = "\n if (!retval) { CFISH_THROW(CFISH_ERR, " "\"%s() for class '%%o' cannot return NULL\", " "Cfish_Obj_Get_Class_Name((cfish_Obj*)self)); }"; size_t size = sizeof(pattern) + strlen(macro_sym) + 30; nullable_check = (char*)REALLOCATE(nullable_check, size); sprintf(nullable_check, pattern, macro_sym); } char pattern[] = "%s\n" "%s(%s) {\n" " %s retval = (%s)%s(%s);%s%s\n" " return retval;\n" "}\n"; size_t size = sizeof(pattern) + strlen(ret_type_str) + strlen(override_sym) + strlen(params) + strlen(ret_type_str) + strlen(ret_type_str) + strlen(cb_func_name) + strlen(callback_params) + strlen(nullable_check) + strlen(refcount_mods) + 30; char *callback_def = (char*)MALLOCATE(size); sprintf(callback_def, pattern, ret_type_str, override_sym, params, ret_type_str, ret_type_str, cb_func_name, callback_params, nullable_check, refcount_mods); FREEMEM(nullable_check); return callback_def; }
static void S_run_integer_tests(CFCTest *test) { { CFCType *type = CFCType_new_integer(CFCTYPE_CONST, "int32_t"); OK(test, CFCType_const(type), "const"); STR_EQ(test, CFCType_get_specifier(type), "int32_t", "get_specifier"); STR_EQ(test, CFCType_to_c(type), "const int32_t", "'const' in C representation"); CFCBase_decref((CFCBase*)type); } { CFCParser *parser = CFCParser_new(); static const char *specifiers[14] = { "bool", "char", "short", "int", "long", "size_t", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t" }; for (int i = 0; i < 14; ++i) { const char *specifier = specifiers[i]; CFCType *type; type = CFCTest_parse_type(test, parser, specifier); OK(test, CFCType_is_integer(type), "%s is_integer", specifier); CFCBase_decref((CFCBase*)type); char *const_specifier = CFCUtil_sprintf("const %s", specifier); type = CFCTest_parse_type(test, parser, const_specifier); OK(test, CFCType_is_integer(type), "%s is_integer", const_specifier); OK(test, CFCType_const(type), "%s is const", const_specifier); FREEMEM(const_specifier); CFCBase_decref((CFCBase*)type); } CFCBase_decref((CFCBase*)parser); } }
char* CFCBindMeth_typedef_dec(struct CFCMethod *method, CFCClass *klass) { const char *params_end = CFCParamList_to_c(CFCMethod_get_param_list(method)); while (*params_end && *params_end != '*') { params_end++; } const char *self_struct = CFCClass_full_struct_sym(klass); const char *ret_type = CFCType_to_c(CFCMethod_get_return_type(method)); char *full_typedef = CFCMethod_full_typedef(method, klass); char *buf = CFCUtil_sprintf("typedef %s\n(*%s)(%s%s);\n", ret_type, full_typedef, self_struct, params_end); FREEMEM(full_typedef); return buf; }
char* CFCVariable_global_c(CFCVariable *self, CFCClass *klass) { const char *type_str = CFCType_to_c(self->type); const char *postfix = ""; if (CFCType_is_composite(self->type) && CFCType_get_array(self->type) != NULL ) { postfix = CFCType_get_array(self->type); } char *full_sym = CFCVariable_full_sym(self, klass); char *global_c = CFCUtil_sprintf("%s %s%s", type_str, full_sym, postfix); FREEMEM(full_sym); return global_c; }
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 void S_run_va_list_tests(CFCTest *test) { { CFCType *type = CFCType_new_va_list(); STR_EQ(test, CFCType_get_specifier(type), "va_list", "specifier defaults to 'va_list'"); STR_EQ(test, CFCType_to_c(type), "va_list", "to_c"); CFCBase_decref((CFCBase*)type); } { CFCParser *parser = CFCParser_new(); CFCType *type = CFCTest_parse_type(test, parser, "va_list"); OK(test, CFCType_is_va_list(type), "is_va_list"); CFCBase_decref((CFCBase*)type); CFCBase_decref((CFCBase*)parser); } }
char* CFCPerlSub_arg_declarations(CFCPerlSub *self) { CFCParamList *param_list = self->param_list; CFCVariable **arg_vars = CFCParamList_get_variables(param_list); size_t num_vars = CFCParamList_num_vars(param_list); char *decls = CFCUtil_strdup(""); // Declare variables. for (size_t i = 1; i < num_vars; i++) { CFCVariable *arg_var = arg_vars[i]; CFCType *type = CFCVariable_get_type(arg_var); const char *type_str = CFCType_to_c(type); const char *var_name = CFCVariable_micro_sym(arg_var); decls = CFCUtil_cat(decls, " ", type_str, " arg_", var_name, ";\n", NULL); } return decls; }
char* CFCBindMeth_typedef_dec(struct CFCMethod *method, CFCClass *klass) { const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); const char *ret_type = CFCType_to_c(CFCMethod_get_return_type(method)); size_t full_typedef_size = CFCMethod_full_typedef(method, klass, NULL, 0); char *full_typedef = (char*)MALLOCATE(full_typedef_size); CFCMethod_full_typedef(method, klass, full_typedef, full_typedef_size); size_t size = strlen(params) + strlen(ret_type) + strlen(full_typedef) + 20 + sizeof("\0"); char *buf = (char*)MALLOCATE(size); sprintf(buf, "typedef %s\n(*%s)(%s);\n", ret_type, full_typedef, params); FREEMEM(full_typedef); return buf; }
static char* S_allot_params_arg(CFCType *type, const char *label, int required) { const char *type_c_string = CFCType_to_c(type); unsigned label_len = (unsigned)strlen(label); const char *req_string = required ? "true" : "false"; if (CFCType_is_object(type)) { const char *struct_sym = CFCType_get_specifier(type); const char *class_var = CFCType_get_class_var(type); // Share buffers rather than copy between Perl scalars and Clownfish // string types. int use_sv_buffer = false; if (strcmp(struct_sym, "cfish_String") == 0 || strcmp(struct_sym, "cfish_Obj") == 0 ) { use_sv_buffer = true; } const char *allocation = use_sv_buffer ? "alloca(cfish_SStr_size())" : "NULL"; const char pattern[] = "ALLOT_OBJ(&arg_%s, \"%s\", %u, %s, %s, %s)"; char *arg = CFCUtil_sprintf(pattern, label, label, label_len, req_string, class_var, allocation); return arg; } else if (CFCType_is_primitive(type)) { for (int i = 0; prim_type_to_allot_macro[i].prim_type != NULL; i++) { const char *prim_type = prim_type_to_allot_macro[i].prim_type; if (strcmp(prim_type, type_c_string) == 0) { const char *allot = prim_type_to_allot_macro[i].allot_macro; char pattern[] = "%s(&arg_%s, \"%s\", %u, %s)"; char *arg = CFCUtil_sprintf(pattern, allot, label, label, label_len, req_string); return arg; } } } CFCUtil_die("Missing typemap for %s", type_c_string); return NULL; // unreachable }
static char* S_primitive_callback_def(CFCMethod *method, const char *callback_params, const char *refcount_mods) { const char *override_sym = CFCMethod_full_override_sym(method); const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); char cb_func_name[40]; if (CFCType_is_floating(return_type)) { strcpy(cb_func_name, "cfish_Host_callback_f64"); } else if (CFCType_is_integer(return_type)) { strcpy(cb_func_name, "cfish_Host_callback_i64"); } else if (strcmp(ret_type_str, "void*") == 0) { strcpy(cb_func_name, "cfish_Host_callback_host"); } else { CFCUtil_die("unrecognized type: %s", ret_type_str); } char pattern[] = "%s\n" "%s(%s) {\n" " return (%s)%s(%s);%s\n" "}\n"; size_t size = sizeof(pattern) + strlen(ret_type_str) + strlen(override_sym) + strlen(params) + strlen(ret_type_str) + strlen(cb_func_name) + strlen(callback_params) + strlen(refcount_mods) + 20; char *callback_def = (char*)MALLOCATE(size); sprintf(callback_def, pattern, ret_type_str, override_sym, params, ret_type_str, cb_func_name, callback_params, refcount_mods); return callback_def; }