int CFCType_equals(CFCType *self, CFCType *other) { if ((CFCType_const(self) ^ CFCType_const(other)) || (CFCType_nullable(self) ^ CFCType_nullable(other)) || (CFCType_is_void(self) ^ CFCType_is_void(other)) || (CFCType_is_object(self) ^ CFCType_is_object(other)) || (CFCType_is_primitive(self) ^ CFCType_is_primitive(other)) || (CFCType_is_integer(self) ^ CFCType_is_integer(other)) || (CFCType_is_floating(self) ^ CFCType_is_floating(other)) || (CFCType_is_va_list(self) ^ CFCType_is_va_list(other)) || (CFCType_is_arbitrary(self) ^ CFCType_is_arbitrary(other)) || (CFCType_is_composite(self) ^ CFCType_is_composite(other)) || (CFCType_incremented(self) ^ CFCType_incremented(other)) || (CFCType_decremented(self) ^ CFCType_decremented(other)) || !!self->child ^ !!other->child || !!self->array ^ !!other->array ) { return false; } if (self->indirection != other->indirection) { return false; } if (strcmp(self->specifier, other->specifier) != 0) { return false; } if (self->child) { if (!CFCType_equals(self->child, other->child)) { return false; } } if (self->array) { if (strcmp(self->array, other->array) != 0) { return false; } } return true; }
static void S_run_primitive_tests(CFCTest *test) { CFCParcel *parcel = CFCParcel_new("Parcel", NULL, NULL, NULL); CFCType *type = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "hump_t", 0); OK(test, CFCType_is_primitive(type), "is_primitive"); { CFCType *twin = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "hump_t", 0); OK(test, CFCType_equals(type, twin), "equals"); CFCBase_decref((CFCBase*)twin); } { CFCType *other = CFCType_new(CFCTYPE_PRIMITIVE, parcel, "dump_t", 0); OK(test, !CFCType_equals(type, other), "equals spoiled by specifier"); CFCBase_decref((CFCBase*)other); } { CFCType *other = CFCType_new(CFCTYPE_PRIMITIVE|CFCTYPE_CONST, parcel, "hump_t", 0); OK(test, !CFCType_equals(type, other), "equals spoiled by const"); CFCBase_decref((CFCBase*)other); } CFCBase_decref((CFCBase*)type); CFCBase_decref((CFCBase*)parcel); }
int CFCCallable_can_be_bound(CFCCallable *self) { // Test whether parameters can be mapped automatically. CFCVariable **arg_vars = CFCParamList_get_variables(self->param_list); for (size_t i = 0; arg_vars[i] != NULL; i++) { CFCType *type = CFCVariable_get_type(arg_vars[i]); if (!CFCType_is_object(type) && !CFCType_is_primitive(type)) { return false; } } // Test whether return type can be mapped automatically. if (!CFCType_is_void(self->return_type) && !CFCType_is_object(self->return_type) && !CFCType_is_primitive(self->return_type) ) { return false; } return true; }
/* 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; }
static char* S_gen_target(CFCVariable *var, const char *value) { CFCType *type = CFCVariable_get_type(var); const char *specifier = CFCType_get_specifier(type); const char *micro_sym = CFCVariable_get_name(var); const char *maybe_maybe = ""; const char *dest_name; char *var_name = NULL; if (CFCType_is_primitive(type)) { dest_name = CFCType_get_specifier(type); if (value != NULL) { maybe_maybe = "maybe_"; } var_name = CFCUtil_sprintf("%s_ARG", CFCVariable_get_name(var)); } else if (CFCType_is_object(type)) { if (CFCType_nullable(type) || (value && strcmp(value, "NULL") == 0) ) { maybe_maybe = "maybe_"; } if (strcmp(specifier, "cfish_String") == 0) { dest_name = "string"; var_name = CFCUtil_sprintf("%s_ARG", CFCVariable_get_name(var)); } else if (strcmp(specifier, "cfish_Hash") == 0) { dest_name = "hash"; var_name = CFCUtil_sprintf("%s_ARG", CFCVariable_get_name(var)); } else if (strcmp(specifier, "cfish_Vector") == 0) { dest_name = "vec"; var_name = CFCUtil_sprintf("%s_ARG", CFCVariable_get_name(var)); } else { dest_name = "obj"; var_name = CFCUtil_sprintf("wrap_arg_%s", micro_sym); } } else { dest_name = "INVALID"; } char *content = CFCUtil_sprintf(", CFBind_%sconvert_%s, &%s", maybe_maybe, dest_name, var_name); FREEMEM(var_name); return content; }
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_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; }
char* CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) { if (CFCType_cfish_obj(type)) { return CFCUtil_strdup("interface{}"); } else if (CFCType_cfish_string(type)) { return CFCUtil_strdup("string"); } else if (CFCType_cfish_blob(type)) { return CFCUtil_strdup("[]byte"); } else if (CFCType_cfish_vector(type)) { return CFCUtil_strdup("[]interface{}"); } else if (CFCType_cfish_hash(type)) { return CFCUtil_strdup("map[string]interface{}"); } else if (CFCType_is_object(type)) { // Divide the specifier into prefix and struct name. const char *specifier = CFCType_get_specifier(type); size_t prefix_len = 0; for (size_t max = strlen(specifier); prefix_len < max; prefix_len++) { if (isupper(specifier[prefix_len])) { break; } } if (!prefix_len) { CFCUtil_die("Can't convert object type name '%s'", specifier); } const char *struct_sym = specifier + prefix_len; // Find the parcel that the type lives in. CFCParcel** all_parcels = CFCParcel_all_parcels(); CFCParcel *parcel = NULL; for (int i = 0; all_parcels[i] != NULL; i++) { const char *candidate = CFCParcel_get_prefix(all_parcels[i]); if (strncmp(candidate, specifier, prefix_len) == 0 && strlen(candidate) == prefix_len ) { parcel = all_parcels[i]; break; } } if (!parcel) { CFCUtil_die("Can't find parcel for type '%s'", specifier); } // If the type lives in this parcel, return only the struct sym // without a go package prefix. if (parcel == current_parcel) { return CFCUtil_strdup(struct_sym); } // The type lives in another parcel, so prefix its Go package name. // TODO: Stop downcasing once Clownfish parcel names are constrained // to lower case. const char *package_name = CFCParcel_get_name(parcel); if (strrchr(package_name, '.')) { package_name = strrchr(package_name, '.') + 1; } char *result = CFCUtil_sprintf("%s.%s", package_name, struct_sym); for (int i = 0; result[i] != '.'; i++) { result[i] = tolower(result[i]); } return result; } else if (CFCType_is_primitive(type)) { const char *specifier = CFCType_get_specifier(type); for (int i = 0; i < num_conversions; i++) { if (strcmp(specifier, conversions[i].c) == 0) { return CFCUtil_strdup(conversions[i].go); } } } return NULL; }
char* CFCPerlTypeMap_from_perl(CFCType *type, const char *xs_var) { char *result = NULL; if (CFCType_is_object(type)) { const char *struct_sym = CFCType_get_specifier(type); const char *vtable_var = CFCType_get_vtable_var(type); if (strcmp(struct_sym, "lucy_CharBuf") == 0 || strcmp(struct_sym, "cfish_CharBuf") == 0 || strcmp(struct_sym, "lucy_Obj") == 0 || strcmp(struct_sym, "cfish_Obj") == 0 ) { // Share buffers rather than copy between Perl scalars and // Clownfish string types. result = CFCUtil_cat(CFCUtil_strdup(""), "(", struct_sym, "*)XSBind_sv_to_cfish_obj(", xs_var, ", ", vtable_var, ", alloca(cfish_ZCB_size()))", NULL); } else { result = CFCUtil_cat(CFCUtil_strdup(""), "(", struct_sym, "*)XSBind_sv_to_cfish_obj(", xs_var, ", ", vtable_var, ", NULL)", NULL); } } else if (CFCType_is_primitive(type)) { const char *specifier = CFCType_get_specifier(type); size_t size = 80 + strlen(xs_var) * 2; result = (char*)MALLOCATE(size); if (strcmp(specifier, "double") == 0) { sprintf(result, "SvNV(%s)", xs_var); } else if (strcmp(specifier, "float") == 0) { sprintf(result, "(float)SvNV(%s)", xs_var); } else if (strcmp(specifier, "int") == 0) { sprintf(result, "(int)SvIV(%s)", xs_var); } else if (strcmp(specifier, "short") == 0) { sprintf(result, "(short)SvIV(%s)", xs_var); } else if (strcmp(specifier, "long") == 0) { const char pattern[] = "((sizeof(long) <= sizeof(IV)) ? (long)SvIV(%s) " ": (long)SvNV(%s))"; sprintf(result, pattern, xs_var, xs_var); } else if (strcmp(specifier, "size_t") == 0) { sprintf(result, "(size_t)SvIV(%s)", xs_var); } else if (strcmp(specifier, "uint64_t") == 0) { sprintf(result, "(uint64_t)SvNV(%s)", xs_var); } else if (strcmp(specifier, "uint32_t") == 0) { sprintf(result, "(uint32_t)SvUV(%s)", xs_var); } else if (strcmp(specifier, "uint16_t") == 0) { sprintf(result, "(uint16_t)SvUV(%s)", xs_var); } else if (strcmp(specifier, "uint8_t") == 0) { sprintf(result, "(uint8_t)SvUV(%s)", xs_var); } else if (strcmp(specifier, "int64_t") == 0) { sprintf(result, "(int64_t)SvNV(%s)", xs_var); } else if (strcmp(specifier, "int32_t") == 0) { sprintf(result, "(int32_t)SvIV(%s)", xs_var); } else if (strcmp(specifier, "int16_t") == 0) { sprintf(result, "(int16_t)SvIV(%s)", xs_var); } else if (strcmp(specifier, "int8_t") == 0) { sprintf(result, "(int8_t)SvIV(%s)", xs_var); } else if (strcmp(specifier, "chy_bool_t") == 0) { sprintf(result, "SvTRUE(%s) ? 1 : 0", xs_var); } else { FREEMEM(result); result = NULL; } } return result; }
char* CFCPerlTypeMap_to_perl(CFCType *type, const char *cf_var) { const char *type_str = CFCType_to_c(type); char *result = NULL; if (CFCType_is_object(type)) { result = CFCUtil_cat(CFCUtil_strdup(""), "(", cf_var, " == NULL ? newSV(0) : " "XSBind_cfish_to_perl((cfish_Obj*)", cf_var, "))", NULL); } else if (CFCType_is_primitive(type)) { // Convert from a primitive type to a Perl scalar. const char *specifier = CFCType_get_specifier(type); size_t size = 80 + strlen(cf_var) * 2; result = (char*)MALLOCATE(size); if (strcmp(specifier, "double") == 0) { sprintf(result, "newSVnv(%s)", cf_var); } else if (strcmp(specifier, "float") == 0) { sprintf(result, "newSVnv(%s)", cf_var); } else if (strcmp(specifier, "int") == 0) { sprintf(result, "newSViv(%s)", cf_var); } else if (strcmp(specifier, "short") == 0) { sprintf(result, "newSViv(%s)", cf_var); } else if (strcmp(specifier, "long") == 0) { char pattern[] = "((sizeof(long) <= sizeof(IV)) ? " "newSViv((IV)%s) : newSVnv((NV)%s))"; sprintf(result, pattern, cf_var, cf_var); } else if (strcmp(specifier, "size_t") == 0) { sprintf(result, "newSViv(%s)", cf_var); } else if (strcmp(specifier, "uint64_t") == 0) { char pattern[] = "sizeof(UV) == 8 ? newSVuv((UV)%s) : newSVnv((NV)%s)"; sprintf(result, pattern, cf_var, cf_var); } else if (strcmp(specifier, "uint32_t") == 0) { sprintf(result, "newSVuv(%s)", cf_var); } else if (strcmp(specifier, "uint16_t") == 0) { sprintf(result, "newSVuv(%s)", cf_var); } else if (strcmp(specifier, "uint8_t") == 0) { sprintf(result, "newSVuv(%s)", cf_var); } else if (strcmp(specifier, "int64_t") == 0) { char pattern[] = "sizeof(IV) == 8 ? newSViv((IV)%s) : newSVnv((NV)%s)"; sprintf(result, pattern, cf_var, cf_var); } else if (strcmp(specifier, "int32_t") == 0) { sprintf(result, "newSViv(%s)", cf_var); } else if (strcmp(specifier, "int16_t") == 0) { sprintf(result, "newSViv(%s)", cf_var); } else if (strcmp(specifier, "int8_t") == 0) { sprintf(result, "newSViv(%s)", cf_var); } else if (strcmp(specifier, "chy_bool_t") == 0) { sprintf(result, "newSViv(%s)", cf_var); } else { FREEMEM(result); result = NULL; } } else if (CFCType_is_composite(type)) { if (strcmp(type_str, "void*") == 0) { // Assume that void* is a reference SV -- either a hashref or an // arrayref. result = CFCUtil_cat(CFCUtil_strdup(""), "newRV_inc((SV*)", cf_var, ")", NULL); } } return result; }