Esempio n. 1
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;
}
Esempio n. 2
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;
}
Esempio n. 3
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;
}
Esempio n. 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;
}
Esempio n. 5
0
static char*
S_meth_top(CFCMethod *method) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);

    if (CFCParamList_num_vars(param_list) == 1) {
        char pattern[] =
            "(PyObject *self, PyObject *unused) {\n"
            "    CFISH_UNUSED_VAR(unused);\n"
            ;
        return CFCUtil_sprintf(pattern);
    }
    else {
        char *error = NULL;
        char *arg_parsing = S_gen_arg_parsing(param_list, 1, &error);
        if (error) {
            CFCUtil_die("%s in %s", error, CFCMethod_get_name(method));
        }
        if (!arg_parsing) {
            return NULL;
        }
        char *decs = S_gen_decs(param_list, 1);
        char pattern[] =
            "(PyObject *self, PyObject *args, PyObject *kwargs) {\n"
            "%s" // decs
            "%s"
            ;
        char *result = CFCUtil_sprintf(pattern, decs, arg_parsing);
        FREEMEM(arg_parsing);
        return result;
    }
}
Esempio n. 6
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;
}
Esempio n. 7
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;
}
Esempio n. 8
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;
}
Esempio n. 9
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;
}
Esempio n. 10
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;
}
Esempio n. 11
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;
}
Esempio n. 12
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;
}
Esempio n. 13
0
char*
CFCPyMethod_wrapper(CFCMethod *method, CFCClass *invoker) {
    CFCParamList *param_list  = CFCMethod_get_param_list(method);
    CFCType      *return_type = CFCMethod_get_return_type(method);
    char *meth_sym   = CFCMethod_full_method_sym(method, invoker);
    char *meth_top   = S_meth_top(method);
    char *increfs    = S_gen_arg_increfs(param_list, 1);
    char *decrefs    = S_gen_decrefs(param_list, 1);
    char *invocation = S_gen_meth_invocation(method, invoker);
    char *ret;
    if (CFCType_is_void(return_type)) {
        ret = CFCUtil_strdup("    Py_RETURN_NONE;\n");
    }
    else if (CFCType_incremented(return_type)) {
        ret = CFCUtil_strdup("    return CFBind_cfish_to_py_zeroref((cfish_Obj*)retvalCF);\n");
    }
    else {
        char *conv = CFCPyTypeMap_c_to_py(return_type, "retvalCF");
        ret = CFCUtil_sprintf("    return %s;\n", conv);
        FREEMEM(conv);
    }

    char pattern[] =
        "static PyObject*\n"
        "S_%s%s"
        "%s" // increfs
        "%s" // invocation
        "%s" // decrefs
        "    if (CFBind_migrate_cferr()) {\n"
        "        return NULL;\n"
        "    }\n"
        "%s" // ret
        "}\n"
        ;
    char *wrapper = CFCUtil_sprintf(pattern, meth_sym, meth_top,
                                    increfs, invocation, decrefs, ret);
    FREEMEM(ret);
    FREEMEM(invocation);
    FREEMEM(decrefs);
    FREEMEM(increfs);
    FREEMEM(meth_sym);
    FREEMEM(meth_top);

    return wrapper;
}
Esempio n. 14
0
static char*
S_void_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));
    const char *micro_sym = CFCMethod_micro_sym(method);
    const char pattern[] =
        "void\n"
        "%s(%s) {\n"
        "%s"
        "    S_finish_callback_void(\"%s\");%s\n"
        "}\n";
    char *callback_def
        = CFCUtil_sprintf(pattern, override_sym, params, callback_start,
                          micro_sym, refcount_mods);

    return callback_def;
}
Esempio n. 15
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;
}
Esempio n. 16
0
char*
CFCPyMethod_pymethoddef(CFCMethod *method, CFCClass *invoker) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *flags = CFCParamList_num_vars(param_list) == 1
                        ? "METH_NOARGS"
                        : "METH_KEYWORDS|METH_VARARGS";
    char *meth_sym = CFCMethod_full_method_sym(method, invoker);
    char *micro_sym = CFCUtil_strdup(CFCSymbol_get_name((CFCSymbol*)method));
    for (int i = 0; micro_sym[i] != 0; i++) {
        micro_sym[i] = tolower(micro_sym[i]);
    }

    char pattern[] =
        "{\"%s\", (PyCFunction)S_%s, %s, NULL},";
    char *py_meth_def = CFCUtil_sprintf(pattern, micro_sym, meth_sym, flags);

    FREEMEM(meth_sym);
    FREEMEM(micro_sym);
    return py_meth_def;
}
Esempio n. 17
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;
}
Esempio n. 18
0
static char*
S_void_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));
    const char pattern[] =
        "void\n"
        "%s(%s) {\n"
        "    cfish_Host_callback(%s);%s\n"
        "}\n";
    size_t size = sizeof(pattern)
                  + strlen(override_sym)
                  + strlen(params)
                  + strlen(callback_params)
                  + strlen(refcount_mods)
                  + 200;
    char *callback_def = (char*)MALLOCATE(size);
    sprintf(callback_def, pattern, override_sym, params, callback_params,
            refcount_mods);
    return callback_def;
}
Esempio n. 19
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_imp_func(method);
    const char *arg_names 
        = CFCParamList_name_list(CFCMethod_get_param_list(method));

    char *full_meth_sym   = CFCMethod_full_method_sym(method, klass);
    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);

    const char pattern[] =
        "extern size_t %s;\n"
        "#define %s(%s) \\\n"
        "    %s((%s)%s)\n";
    char *method_def
        = CFCUtil_sprintf(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;
}
Esempio n. 20
0
CFCPerlMethod*
CFCPerlMethod_init(CFCPerlMethod *self, CFCMethod *method,
                   const char *alias) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *class_name = CFCMethod_get_class_name(method);
    int use_labeled_params = CFCParamList_num_vars(param_list) > 2
                             ? 1 : 0;

    // The Clownfish destructor needs to be spelled DESTROY for Perl.
    if (!alias) {
        alias = CFCMethod_micro_sym(method);
    }
    static const char destroy_uppercase[] = "DESTROY";
    if (strcmp(alias, "destroy") == 0) {
        alias = destroy_uppercase;
    }

    CFCPerlSub_init((CFCPerlSub*)self, param_list, class_name, alias,
                    use_labeled_params);
    self->method = (CFCMethod*)CFCBase_incref((CFCBase*)method);
    return self;
}
Esempio n. 21
0
static char*
S_gen_meth_invocation(CFCMethod *method, CFCClass *invoker) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    char *full_meth = CFCMethod_full_method_sym(method, invoker);
    char *meth_type_c = CFCMethod_full_typedef(method, invoker);
    const char *class_var = CFCClass_full_class_var(invoker);
    char *first_arg
        = CFCUtil_sprintf("(%s*)self", CFCClass_full_struct_sym(invoker));
    char *arg_list = S_gen_arg_list(param_list, first_arg);

    CFCType *return_type = CFCMethod_get_return_type(method);
    char *maybe_declare;
    const char *maybe_assign;
    if (CFCType_is_void(return_type)) {
        maybe_declare = CFCUtil_strdup("");
        maybe_assign = "";
    }
    else {
        maybe_declare = CFCUtil_sprintf("    %s retvalCF;\n",
                                        CFCType_to_c(return_type));
        maybe_assign = "retvalCF = ";
    }

    const char pattern[] =
        "%s"
        "    %s method = CFISH_METHOD_PTR(%s, %s);\n"
        "    CFBIND_TRY(%smethod(%s));\n"
        ;
    char *content
        = CFCUtil_sprintf(pattern, maybe_declare, meth_type_c, class_var,
                          full_meth, maybe_assign, arg_list);

    FREEMEM(arg_list);
    FREEMEM(first_arg);
    FREEMEM(maybe_declare);
    FREEMEM(full_meth);
    FREEMEM(meth_type_c);
    return content;
}
Esempio n. 22
0
static char*
S_callback_refcount_mods(CFCMethod *method) {
    char *refcount_mods = CFCUtil_strdup("");
    CFCType *return_type = CFCMethod_get_return_type(method);
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    CFCVariable **arg_vars = CFCParamList_get_variables(param_list);

    // `XSBind_perl_to_cfish()` returns an incremented object.  If this method
    // does not return an incremented object, we must cancel out that
    // refcount.  (No function can return a decremented object.)
    if (CFCType_is_object(return_type) && !CFCType_incremented(return_type)) {
        refcount_mods = CFCUtil_cat(refcount_mods,
                                    "\n    CFISH_DECREF(retval);", NULL);
    }

    // Adjust refcounts of arguments per method signature, so that Perl code
    // does not have to.
    for (int i = 0; arg_vars[i] != NULL; i++) {
        CFCVariable *var  = arg_vars[i];
        CFCType     *type = CFCVariable_get_type(var);
        const char  *name = CFCVariable_micro_sym(var);
        if (!CFCType_is_object(type)) {
            continue;
        }
        else if (CFCType_incremented(type)) {
            refcount_mods = CFCUtil_cat(refcount_mods, "\n    CFISH_INCREF(",
                                        name, ");", NULL);
        }
        else if (CFCType_decremented(type)) {
            refcount_mods = CFCUtil_cat(refcount_mods, "\n    CFISH_DECREF(",
                                        name, ");", NULL);
        }
    }

    return refcount_mods;
}
Esempio n. 23
0
static char*
S_callback_refcount_mods(CFCMethod *method) {
    char *refcount_mods = CFCUtil_strdup("");
    CFCType *return_type = CFCMethod_get_return_type(method);
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    CFCVariable **arg_vars = CFCParamList_get_variables(param_list);

    // Host_callback_obj returns an incremented object.  If this method does
    // not return an incremented object, we must cancel out that refcount.
    // (No function can return a decremented object.)
    if (CFCType_is_object(return_type) && !CFCType_incremented(return_type)) {
        refcount_mods = CFCUtil_cat(refcount_mods,
                                    "\n    CFISH_DECREF(retval);", NULL);
    }

    // The Host_callback_xxx functions have no effect on the refcounts of
    // arguments, so we need to adjust them after the fact.
    for (int i = 0; arg_vars[i] != NULL; i++) {
        CFCVariable *var  = arg_vars[i];
        CFCType     *type = CFCVariable_get_type(var);
        const char  *name = CFCVariable_micro_sym(var);
        if (!CFCType_is_object(type)) {
            continue;
        }
        else if (CFCType_incremented(type)) {
            refcount_mods = CFCUtil_cat(refcount_mods, "\n    CFISH_INCREF(",
                                        name, ");", NULL);
        }
        else if (CFCType_decremented(type)) {
            refcount_mods = CFCUtil_cat(refcount_mods, "\n    CFISH_DECREF(",
                                        name, ");", NULL);
        }
    }
    
    return refcount_mods;
}
Esempio n. 24
0
static char*
S_obj_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);
    const char *nullable  = CFCType_nullable(return_type) ? "true" : "false";

    char pattern[] =
        "%s\n"
        "%s(%s) {\n"
        "%s"
        "    %s retval = (%s)S_finish_callback_obj(self, \"%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,
                          micro_sym, nullable, refcount_mods);

    return callback_def;
}
Esempio n. 25
0
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;
}
Esempio n. 26
0
static char*
S_xsub_body(CFCPerlMethod *self) {
    CFCMethod    *method        = self->method;
    CFCParamList *param_list    = CFCMethod_get_param_list(method);
    CFCVariable **arg_vars      = CFCParamList_get_variables(param_list);
    const char   *name_list     = CFCParamList_name_list(param_list);
    char *body = CFCUtil_strdup("");

    CFCParcel *parcel = CFCMethod_get_parcel(method);
    const char *class_name = CFCMethod_get_class_name(method);
    CFCClass *klass = CFCClass_fetch_singleton(parcel, class_name);
    if (!klass) {
        CFCUtil_die("Can't find a CFCClass for '%s'", class_name);
    }

    // Extract the method function pointer.
    char *full_typedef = CFCMethod_full_typedef(method, klass);
    char *full_meth    = CFCMethod_full_method_sym(method, klass);
    char *method_ptr
        = CFCUtil_sprintf("%s method = CFISH_METHOD_PTR(%s, %s);\n    ",
                          full_typedef, CFCClass_full_vtable_var(klass),
                          full_meth);
    body = CFCUtil_cat(body, method_ptr, NULL);
    FREEMEM(full_typedef);
    FREEMEM(full_meth);
    FREEMEM(method_ptr);

    // Compensate for functions which eat refcounts.
    for (int 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)) {
            body = CFCUtil_cat(body, "CFISH_INCREF(",
                               CFCVariable_micro_sym(var), ");\n    ", NULL);
        }
    }

    if (CFCType_is_void(CFCMethod_get_return_type(method))) {
        // Invoke method in void context.
        body = CFCUtil_cat(body, "method(", name_list,
                           ");\n    XSRETURN(0);", NULL);
    }
    else {
        // Return a value for method invoked in a scalar context.
        CFCType *return_type = CFCMethod_get_return_type(method);
        const char *type_str = CFCType_to_c(return_type);
        char *assignment = CFCPerlTypeMap_to_perl(return_type, "retval");
        if (!assignment) {
            CFCUtil_die("Can't find typemap for '%s'", type_str);
        }
        body = CFCUtil_cat(body, type_str, " retval = method(",
                           name_list, ");\n    ST(0) = ", assignment, ";",
                           NULL);
        if (CFCType_is_object(return_type)
            && CFCType_incremented(return_type)
           ) {
            body = CFCUtil_cat(body, "\n    CFISH_DECREF(retval);", NULL);
        }
        body = CFCUtil_cat(body, "\n    sv_2mortal( ST(0) );\n    XSRETURN(1);",
                           NULL);
        FREEMEM(assignment);
    }

    return body;
}
Esempio n. 27
0
static char*
S_xsub_def_positional_args(CFCPerlMethod *self) {
    CFCMethod *method = self->method;
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
    const char **arg_inits = CFCParamList_get_initial_values(param_list);
    unsigned num_vars = (unsigned)CFCParamList_num_vars(param_list);
    char *body = S_xsub_body(self);

    // Determine how many args are truly required and build an error check.
    unsigned min_required = 0;
    for (unsigned i = 0; i < num_vars; i++) {
        if (arg_inits[i] == NULL) {
            min_required = i + 1;
        }
    }
    char *xs_name_list = num_vars > 0
                         ? CFCUtil_strdup(CFCVariable_micro_sym(arg_vars[0]))
                         : CFCUtil_strdup("");
    for (unsigned i = 1; i < num_vars; i++) {
        const char *var_name = CFCVariable_micro_sym(arg_vars[i]);
        if (i < min_required) {
            xs_name_list = CFCUtil_cat(xs_name_list, ", ", var_name, NULL);
        }
        else {
            xs_name_list = CFCUtil_cat(xs_name_list, ", [", var_name, "]",
                                       NULL);
        }
    }
    const char num_args_pattern[] =
        "if (items %s %u) { CFISH_THROW(CFISH_ERR, \"Usage: %%s(%s)\", GvNAME(CvGV(cv))); }";
    char *num_args_check;
    if (min_required < num_vars) {
        num_args_check = CFCUtil_sprintf(num_args_pattern, "<", min_required,
                                         xs_name_list);
    }
    else {
        num_args_check = CFCUtil_sprintf(num_args_pattern, "!=", num_vars,
                                         xs_name_list);
    }

    // Var assignments.
    char *var_assignments = CFCUtil_strdup("");
    for (unsigned i = 0; i < num_vars; i++) {
        CFCVariable *var = arg_vars[i];
        const char  *val = arg_inits[i];
        const char  *var_name = CFCVariable_micro_sym(var);
        CFCType     *var_type = CFCVariable_get_type(var);
        const char  *type_c   = CFCType_to_c(var_type);

        if (i == 0) {    // self
            const char *meth_micro_sym = CFCMethod_micro_sym(self->method);
            char *statement
                = S_self_assign_statement(self, var_type, meth_micro_sym);
            var_assignments = CFCUtil_cat(var_assignments, statement, NULL);
            FREEMEM(statement);
        }
        else {
            char perl_stack_var[30];
            sprintf(perl_stack_var, "ST(%u)", i);
            char *conversion
                = CFCPerlTypeMap_from_perl(var_type, perl_stack_var);
            if (!conversion) {
                CFCUtil_die("Can't map type '%s'", type_c);
            }
            if (val) {
                char pattern[] =
                    "\n    %s %s = ( items >= %u && XSBind_sv_defined(ST(%u)) )"
                    " ? %s : %s;";
                char *statement = CFCUtil_sprintf(pattern, type_c, var_name, i,
                                                  i, conversion, val);
                var_assignments
                    = CFCUtil_cat(var_assignments, statement, NULL);
                FREEMEM(statement);
            }
            else {
                var_assignments
                    = CFCUtil_cat(var_assignments, "\n    ", type_c, " ",
                                  var_name, " = ", conversion, ";", NULL);
            }
            FREEMEM(conversion);
        }
    }

    char pattern[] =
        "XS(%s);\n"
        "XS(%s) {\n"
        "    dXSARGS;\n"
        "    CHY_UNUSED_VAR(cv);\n"
        "    SP -= items;\n"
        "    %s;\n"
        "\n"
        "    /* Extract vars from Perl stack. */\n"
        "    %s\n"
        "\n"
        "    /* Execute */\n"
        "    %s\n"
        "}\n";
    char *xsub
        = CFCUtil_sprintf(pattern, self->sub.c_name, self->sub.c_name,
                          num_args_check, var_assignments, body);

    FREEMEM(num_args_check);
    FREEMEM(var_assignments);
    FREEMEM(body);
    return xsub;
}
Esempio n. 28
0
static char*
S_callback_start(CFCMethod *method) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    static const char pattern[] =
        "    dSP;\n"
        "    EXTEND(SP, %d);\n"
        "    ENTER;\n"
        "    SAVETMPS;\n"
        "    PUSHMARK(SP);\n"
        "    mPUSHs((SV*)Cfish_Obj_To_Host((cfish_Obj*)self));\n";
    int num_args = (int)CFCParamList_num_vars(param_list) - 1;
    int num_to_extend = num_args == 0 ? 1
                      : num_args == 1 ? 2
                      : 1 + (num_args * 2);
    char *params = CFCUtil_sprintf(pattern, num_to_extend);

    // Iterate over arguments, mapping them to Perl scalars.
    CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
    for (int i = 1; arg_vars[i] != NULL; i++) {
        CFCVariable *var      = arg_vars[i];
        const char  *name     = CFCVariable_micro_sym(var);
        CFCType     *type     = CFCVariable_get_type(var);
        const char  *c_type   = CFCType_to_c(type);

        // Add labels when there are two or more parameters.
        if (num_args > 1) {
            char num_buf[20];
            sprintf(num_buf, "%d", (int)strlen(name));
            params = CFCUtil_cat(params, "   mPUSHp(\"", name, "\", ",
                                 num_buf, ");\n", NULL);
        }

        if (CFCType_is_string_type(type)) {
            // Convert Clownfish string type to UTF-8 Perl string scalars.
            params = CFCUtil_cat(params, "    mPUSHs(XSBind_cb_to_sv(",
                                 "(cfish_CharBuf*)", name, "));\n", NULL);
        }
        else if (CFCType_is_object(type)) {
            // Wrap other Clownfish object types in Perl objects.
            params = CFCUtil_cat(params, "    mPUSHs(XSBind_cfish_to_perl(",
                                 "(cfish_Obj*)", name, "));\n", NULL);
        }
        else if (CFCType_is_integer(type)) {
            // Convert primitive integer types to IV Perl scalars.
            int width = (int)CFCType_get_width(type);
            if (width != 0 && width <= 4) {
                params = CFCUtil_cat(params, "   mPUSHi(",
                                     name, ");\n", NULL);
            }
            else {
                // If the Perl IV integer type is not wide enough, use
                // doubles.  This may be lossy if the value is above 2**52,
                // but practically speaking, it's important to handle numbers
                // between 2**32 and 2**52 cleanly.
                params = CFCUtil_cat(params,
                                     "    if (sizeof(IV) >= sizeof(", c_type,
                                     ")) { mPUSHi(", name, "); }\n",
                                     "    else { mPUSHn((double)", name,
                                     "); } // lossy \n", NULL);
            }
        }
        else if (CFCType_is_floating(type)) {
            // Convert primitive floating point types to NV Perl scalars.
            params = CFCUtil_cat(params, "   mPUSHn(",
                                 name, ");\n", NULL);
        }
        else {
            // Can't map variable type.  Signal to caller.
            FREEMEM(params);
            return NULL;
        }
    }

    // Restore the Perl stack pointer.
    params = CFCUtil_cat(params, "    PUTBACK;\n", NULL);

    return params;
}
Esempio n. 29
0
static char*
S_virtual_method_def(CFCMethod *method, CFCClass *klass) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *invoker_struct = CFCClass_full_struct_sym(klass);
    const char *common_struct 
        = CFCType_get_specifier(CFCMethod_self_type(method));

    const char *visibility = CFCClass_included(klass)
                             ? "CHY_IMPORT" : "CHY_EXPORT";

    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);

    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);

    // Prepare parameter lists, minus invoker.  The invoker gets forced to
    // "self" later.
    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 %s size_t %s;\n"
        "static CHY_INLINE %s\n"
        "%s(const %s *self%s) {\n"
        "    char *const method_address = *(char**)self + %s;\n"
        "    const %s method = *((%s*)method_address);\n"
        "    %smethod((%s*)self%s);\n"
        "}\n";

    size_t size = sizeof(pattern)
                  + strlen(visibility)
                  + strlen(full_offset_sym)
                  + strlen(ret_type_str)
                  + strlen(full_meth_sym)
                  + strlen(invoker_struct)
                  + strlen(params_minus_invoker)
                  + strlen(full_offset_sym)
                  + strlen(full_typedef)
                  + strlen(full_typedef)
                  + strlen(maybe_return)
                  + strlen(common_struct)
                  + strlen(arg_names_minus_invoker)
                  + 40;
    char *method_def = (char*)MALLOCATE(size);
    sprintf(method_def, pattern, visibility, full_offset_sym, ret_type_str,
            full_meth_sym, invoker_struct, params_minus_invoker,
            full_offset_sym, full_typedef, full_typedef, maybe_return,
            common_struct, arg_names_minus_invoker);

    FREEMEM(full_offset_sym);
    FREEMEM(full_meth_sym);
    FREEMEM(full_typedef);
    return method_def;
}
Esempio n. 30
0
static char*
S_callback_params(CFCMethod *method) {
    const char *micro_sym = CFCSymbol_micro_sym((CFCSymbol*)method);
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    unsigned num_params = CFCParamList_num_vars(param_list) - 1;
    size_t needed = strlen(micro_sym) + 30;
    char *params = (char*)MALLOCATE(needed);

    // TODO: use something other than micro_sym here.
    sprintf(params, "self, \"%s\", %u", micro_sym, num_params);

    // Iterate over arguments, mapping them to various arg wrappers which
    // conform to Host's callback interface.
    CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
    for (int i = 1; arg_vars[i] != NULL; i++) {
        CFCVariable *var      = arg_vars[i];
        const char  *name     = CFCVariable_micro_sym(var);
        size_t       name_len = strlen(name);
        CFCType     *type     = CFCVariable_get_type(var);
        const char  *c_type   = CFCType_to_c(type);
        size_t       size     = strlen(params)
                                + strlen(c_type)
                                + name_len * 2
                                + 30;
        char        *new_buf  = (char*)MALLOCATE(size);

        if (CFCType_is_string_type(type)) {
            sprintf(new_buf, "%s, CFISH_ARG_STR(\"%s\", %s)", params, name, name);
        }
        else if (CFCType_is_object(type)) {
            sprintf(new_buf, "%s, CFISH_ARG_OBJ(\"%s\", %s)", params, name, name);
        }
        else if (CFCType_is_integer(type)) {
            int width = CFCType_get_width(type);
            if (width) {
                if (width <= 4) {
                    sprintf(new_buf, "%s, CFISH_ARG_I32(\"%s\", %s)", params,
                            name, name);
                }
                else {
                    sprintf(new_buf, "%s, CFISH_ARG_I64(\"%s\", %s)", params,
                            name, name);
                }
            }
            else {
                sprintf(new_buf, "%s, CFISH_ARG_I(%s, \"%s\", %s)", params,
                        c_type, name, name);
            }
        }
        else if (CFCType_is_floating(type)) {
            sprintf(new_buf, "%s, CFISH_ARG_F64(\"%s\", %s)", params, name, name);
        }
        else {
            // Can't map variable type.  Signal to caller.
            FREEMEM(params);
            FREEMEM(new_buf);
            return NULL;
        }

        FREEMEM(params);
        params = new_buf;
    }

    return params;
}