Пример #1
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;
}
Пример #2
0
static char*
S_gen_labeled_sample(const char *prologue, CFCParamList *param_list,
                     int start) {
    int           num_vars = CFCParamList_num_vars(param_list);
    CFCVariable **vars     = CFCParamList_get_variables(param_list);
    const char  **inits    = CFCParamList_get_initial_values(param_list);

    size_t max_name_len = 0;

    // Find maximum length of parameter name.
    for (int i = start; i < num_vars; i++) {
        const char *name = CFCVariable_get_name(vars[i]);
        size_t name_len = strlen(name);
        if (name_len > max_name_len) { max_name_len = name_len; }
    }

    char *params = CFCUtil_strdup("");

    for (int i = start; i < num_vars; i++) {
        const char *name    = CFCVariable_get_name(vars[i]);
        const char *init    = inits[i];
        char       *comment = NULL;

        if (init) {
            if (strcmp(init, "NULL") == 0) { init = "undef"; }
            comment = CFCUtil_sprintf("default: %s", init);
        }
        else {
            comment = CFCUtil_strdup("required");
        }

        char *line = CFCUtil_sprintf("        %-*s => $%-*s  # %s\n",
                                     (int)max_name_len, name,
                                     (int)max_name_len, name,
                                     comment);
        params = CFCUtil_cat(params, line, NULL);
        FREEMEM(line);
        FREEMEM(comment);
    }

    const char pattern[] =
        "    %s(\n"
        "%s"
        "    );\n";
    char *sample = CFCUtil_sprintf(pattern, prologue, params);

    FREEMEM(params);
    return sample;
}
Пример #3
0
static char*
S_gen_positional_sample(const char *prologue, CFCParamList *param_list,
                        int start) {
    int           num_vars = CFCParamList_num_vars(param_list);
    CFCVariable **vars     = CFCParamList_get_variables(param_list);
    const char  **inits    = CFCParamList_get_initial_values(param_list);

    if (num_vars - start != 1) {
        CFCUtil_die("Code samples with multiple positional parameters"
                    " are not supported yet.");
    }

    const char *name = CFCVariable_get_name(vars[start]);
    char *sample = CFCUtil_sprintf("    %s($%s);\n", prologue, name);

    const char *init = inits[start];
    if (init) {
        if (strcmp(init, "NULL") == 0) { init = "undef"; }
        char *def_sample = CFCUtil_sprintf("    %s();  # default: %s\n",
                                           prologue, init);
        sample = CFCUtil_cat(sample, def_sample, NULL);
        FREEMEM(def_sample);
    }

    return sample;
}
Пример #4
0
static char*
S_callback_refcount_mods(CFCParamList *param_list) {
    char *refcount_mods = CFCUtil_strdup("");
    CFCVariable **arg_vars = CFCParamList_get_variables(param_list);

    // 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_get_name(var);
        if (!CFCType_is_object(type)) {
            continue;
        }
        else if (CFCType_incremented(type)) {
            refcount_mods = CFCUtil_cat(refcount_mods, "    CFISH_INCREF(",
                                        name, ");\n", NULL);
        }
        else if (CFCType_decremented(type)) {
            refcount_mods = CFCUtil_cat(refcount_mods, "    CFISH_DECREF(",
                                        name, ");\n", NULL);
        }
    }

    return refcount_mods;
}
Пример #5
0
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;
}
Пример #6
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);
}
Пример #7
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;
}
Пример #8
0
void
CFCGoTypeMap_go_meth_receiever(const char *struct_name,
                               CFCParamList *param_list,
                               char *buf, size_t buf_len) {
    size_t max_required = 2;
    if (param_list != NULL && CFCParamList_num_vars(param_list) > 0) {
        CFCVariable **vars = CFCParamList_get_variables(param_list);
        const char *orig = CFCVariable_get_name(vars[0]);
        max_required = strlen(orig) + 1;
    }
    if (buf_len < max_required) {
        CFCUtil_die("Buffer length too short: %d", buf_len);
    }

    // Find the first letter of the type and lowercase it.
    for (size_t i = 0, max = strlen(struct_name); i < max; i++) {
        if (isupper(struct_name[i])) {
            buf[0] = tolower(struct_name[i]);
            buf[1] = '\0';
            break;
        }
    }

    // Check for another argument with the same name.
    if (param_list != NULL) {
        CFCVariable **vars = CFCParamList_get_variables(param_list);
        size_t num_vars = CFCParamList_num_vars(param_list);
        for (size_t i = 1; i < num_vars; i++) {
            const char *name = CFCVariable_get_name(vars[i]);
            if (strcmp(name, buf) == 0) {
                // Bah, a clash.  Use the original name, even though it's
                // probably "self" which isn't good Go style.
                CFCGoTypeMap_go_arg_name(param_list, 0, buf, buf_len);
                break;
            }
        }
    }
}
Пример #9
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;
}
Пример #10
0
static char*
S_build_unused_vars(CFCVariable **vars) {
    char *unused = CFCUtil_strdup("");

    for (int i = 0; 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, ");");
    }

    return unused;
}
Пример #11
0
void
CFCGoTypeMap_go_arg_name(CFCParamList *param_list, size_t tick, char *buf,
                         size_t buf_len) {
    size_t num_vars = CFCParamList_num_vars(param_list);
    if (tick >= num_vars) {
        CFCUtil_die("Index out of range: %d >= %d", (int)tick, (int)num_vars);
    }
    CFCVariable **vars = CFCParamList_get_variables(param_list);
    const char *orig = CFCVariable_get_name(vars[tick]);
    size_t max_required = strlen(orig) + 2;
    if (buf_len < max_required || buf_len < 5) {
        CFCUtil_die("Buffer length too short: %d", buf_len);
    }

    // If the argument name is a Go keyword, append an underscore.  This is
    // ugly but bulletproof.
    for (int i = 0; i < num_go_keywords; i++) {
        if (strcmp(orig, go_keywords[i]) == 0) {
            sprintf(buf, "%s_", orig);
            return;
        }
    }

    // Transform into lowerCamelCase.
    size_t dest_tick = 0;
    int last_was_underscore = 0;
    for (size_t i = 0; i <= strlen(orig); i++) {
        if (i > buf_len) {
            CFCUtil_die("Name too long for buffer of size %d: '%s'", buf_len,
                        orig);
        }
        if (orig[i] == '_') {
            last_was_underscore = 1;
            continue;
        }
        else if (last_was_underscore) {
            buf[dest_tick] = toupper(orig[i]);
        }
        else {
            buf[dest_tick] = orig[i];
        }
        last_was_underscore = 0;
        dest_tick++;
    }
}
Пример #12
0
static char*
S_build_py_args(CFCParamList *param_list) {
    int num_vars = CFCParamList_num_vars(param_list);
    CFCVariable **vars = CFCParamList_get_variables(param_list);
    char pattern[] = "    PyObject *cfcb_ARGS = S_pack_tuple(%d";
    char *py_args = CFCUtil_sprintf(pattern, num_vars - 1);

    for (int i = 1; vars[i] != NULL; i++) {
        const char *var_name = CFCVariable_get_name(vars[i]);
        CFCType *type = CFCVariable_get_type(vars[i]);
        char *conversion = CFCPyTypeMap_c_to_py(type, var_name);
        py_args = CFCUtil_cat(py_args, ",\n        ", conversion, NULL);
        FREEMEM(conversion);
    }
    py_args = CFCUtil_cat(py_args, ");", NULL);

    return py_args;
}
Пример #13
0
static char*
S_gen_arg_list(CFCParamList *param_list, const char *first_arg) {
    CFCVariable **vars = CFCParamList_get_variables(param_list);
    int num_vars = CFCParamList_num_vars(param_list);
    char *arg_list = CFCUtil_strdup("");
    for (int i = 0; i < num_vars; i++) {
        if (i > 0) {
            arg_list = CFCUtil_cat(arg_list, ", ", NULL);
        }
        if (i == 0 && first_arg != NULL) {
            arg_list = CFCUtil_cat(arg_list, first_arg, NULL);
        }
        else {
            arg_list = CFCUtil_cat(arg_list, CFCVariable_get_name(vars[i]),
                                   "_ARG", NULL);
        }
    }
    return arg_list;
}
Пример #14
0
static char*
S_gen_arg_increfs(CFCParamList *param_list, int first_tick) {
    CFCVariable **vars = CFCParamList_get_variables(param_list);
    int num_vars = CFCParamList_num_vars(param_list);
    char *content = CFCUtil_strdup("");
    for (int i = first_tick;i < num_vars; i++) {
        CFCType *type = CFCVariable_get_type(vars[i]);
        if (CFCType_decremented(type)) {
            const char *name = CFCVariable_get_name(vars[i]);
            const char *specifier = CFCType_get_specifier(type);
            char pattern[] =
                "    %s_ARG = (%s*)CFISH_INCREF(%s_ARG);\n";
            char *incref = CFCUtil_sprintf(pattern, name, specifier, name);
            content = CFCUtil_cat(content, incref, NULL);
            FREEMEM(incref);
        }
    }
    return content;
}
Пример #15
0
// Prep refcount decrement calls to follow the Clownfish subroutine
// invocation.
static char*
S_gen_decrefs(CFCParamList *param_list, int first_tick) {
    CFCVariable **vars = CFCParamList_get_variables(param_list);
    int num_vars = CFCParamList_num_vars(param_list);
    char *decrefs = CFCUtil_strdup("");

    for (int i = first_tick; i < num_vars; i++) {
        CFCVariable *var = vars[i];
        CFCType *type = CFCVariable_get_type(var);
        const char *micro_sym = CFCVariable_get_name(var);
        const char *specifier = CFCType_get_specifier(type);

        if (strcmp(specifier, "cfish_Obj") == 0
             || strcmp(specifier, "cfish_String") == 0
             || strcmp(specifier, "cfish_Vector") == 0
             || strcmp(specifier, "cfish_Hash") == 0
            ) {
            decrefs = CFCUtil_cat(decrefs, "    CFISH_DECREF(", micro_sym,
                                  "_ARG);\n", NULL);
        }
    }

    return decrefs;
}
Пример #16
0
static char*
S_gen_labeled_sample(const char *invocant, const char *alias,
                     CFCParamList *param_list, size_t start) {
    size_t        num_vars = CFCParamList_num_vars(param_list);
    CFCVariable **vars     = CFCParamList_get_variables(param_list);
    const char  **inits    = CFCParamList_get_initial_values(param_list);

    size_t max_label_len = 0;
    size_t max_var_len   = 0;

    // Find maximum length of label and Perl variable.
    for (size_t i = start; i < num_vars; i++) {
        CFCVariable *var = vars[i];

        const char *label = CFCVariable_get_name(var);
        size_t label_len = strlen(label);
        if (label_len > max_label_len) { max_label_len = label_len; }

        char *perl_var = S_perl_var_name(var);
        size_t perl_var_len = strlen(perl_var);
        if (perl_var_len > max_var_len) { max_var_len = perl_var_len; }
        FREEMEM(perl_var);
    }

    char *params = CFCUtil_strdup("");

    for (size_t i = start; i < num_vars; i++) {
        CFCVariable *var      = vars[i];
        const char  *label    = CFCVariable_get_name(var);
        char        *perl_var = S_perl_var_name(var);
        perl_var = CFCUtil_cat(perl_var, ",", NULL);

        char       *comment = NULL;
        const char *init    = inits[i];

        if (init) {
            if (strcmp(init, "NULL") == 0) { init = "undef"; }
            comment = CFCUtil_sprintf("default: %s", init);
        }
        else {
            comment = CFCUtil_strdup("required");
        }

        char *line = CFCUtil_sprintf("        %-*s => $%-*s  # %s\n",
                                     max_label_len, label,
                                     max_var_len + 1, perl_var,
                                     comment);
        params = CFCUtil_cat(params, line, NULL);
        FREEMEM(line);
        FREEMEM(comment);
        FREEMEM(perl_var);
    }

    const char pattern[] =
        "    %s->%s(\n"
        "%s"
        "    );\n";
    char *sample = CFCUtil_sprintf(pattern, invocant, alias, params);

    FREEMEM(params);
    return sample;
}
Пример #17
0
/* Generate the code which parses arguments passed from Python and converts
 * them to Clownfish-flavored C values.
 */
static char*
S_gen_arg_parsing(CFCParamList *param_list, int first_tick, char **error) {
    char *content = NULL;

    CFCVariable **vars = CFCParamList_get_variables(param_list);
    const char **vals = CFCParamList_get_initial_values(param_list);
    int num_vars = CFCParamList_num_vars(param_list);

    char *declarations = CFCUtil_strdup("");
    char *keywords     = CFCUtil_strdup("");
    char *format_str   = CFCUtil_strdup("");
    char *targets      = CFCUtil_strdup("");
    int optional_started = 0;

    for (int i = first_tick; i < num_vars; i++) {
        CFCVariable *var  = vars[i];
        const char  *val  = vals[i];

        const char *var_name = CFCVariable_get_name(var);
        keywords = CFCUtil_cat(keywords, "\"", var_name, "\", ", NULL);

        // Build up ParseTuple format string.
        if (val == NULL) {
            if (optional_started) { // problem!
                *error = "Required after optional param";
                goto CLEAN_UP_AND_RETURN;
            }
        }
        else {
            if (!optional_started) {
                optional_started = 1;
                format_str = CFCUtil_cat(format_str, "|", NULL);
            }
        }
        format_str = CFCUtil_cat(format_str, "O&", NULL);

        char *declaration = S_gen_declaration(var, val);
        declarations = CFCUtil_cat(declarations, declaration, NULL);
        FREEMEM(declaration);

        char *target = S_gen_target(var, val);
        targets = CFCUtil_cat(targets, target, NULL);
        FREEMEM(target);
    }

    char parse_pattern[] =
        "%s"
        "    char *keywords[] = {%sNULL};\n"
        "    char *fmt = \"%s\";\n"
        "    int ok = PyArg_ParseTupleAndKeywords(args, kwargs, fmt,\n"
        "        keywords%s);\n"
        "    if (!ok) { return NULL; }\n"
        ;
    content = CFCUtil_sprintf(parse_pattern, declarations, keywords,
                              format_str, targets);

CLEAN_UP_AND_RETURN:
    FREEMEM(declarations);
    FREEMEM(keywords);
    FREEMEM(format_str);
    FREEMEM(targets);
    return content;
}