Пример #1
0
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);
}
Пример #2
0
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();
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
/* 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;
}
Пример #7
0
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;
}
Пример #8
0
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);
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
// 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);
}
Пример #13
0
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;
}
Пример #14
0
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;
}
Пример #15
0
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;
}
Пример #16
0
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;
}
Пример #17
0
// 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;
}
Пример #18
0
/* 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;
}
Пример #19
0
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;
}
Пример #20
0
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;
}
Пример #21
0
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;
}
Пример #22
0
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);
    }
}
Пример #23
0
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;
}
Пример #24
0
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;
}
Пример #25
0
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;
}
Пример #26
0
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);
    }
}
Пример #27
0
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;
}
Пример #28
0
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;
}
Пример #29
0
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
}
Пример #30
0
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;
}