예제 #1
0
파일: CFCDumpable.c 프로젝트: theory/lucy
static void
S_process_dump_member(CFCClass *klass, CFCVariable *member, char *buf,
                      size_t buf_size) {
    CFCUTIL_NULL_CHECK(member);
    CFCType *type = CFCVariable_get_type(member);
    const char *name = CFCVariable_micro_sym(member);
    unsigned name_len = (unsigned)strlen(name);
    const char *specifier = CFCType_get_specifier(type);

    // Skip the VTable.
    if (strcmp(specifier, "cfish_VTable") == 0) {
        return;
    }

    if (CFCType_is_integer(type) || CFCType_is_floating(type)) {
        char int_pattern[] =
            "    Cfish_Hash_Store_Str(dump, \"%s\", %u, (cfish_Obj*)cfish_CB_newf(\"%%i64\", (int64_t)ivars->%s));\n";
        char float_pattern[] =
            "    Cfish_Hash_Store_Str(dump, \"%s\", %u, (cfish_Obj*)cfish_CB_newf(\"%%f64\", (double)ivars->%s));\n";
        char bool_pattern[] =
            "    Cfish_Hash_Store_Str(dump, \"%s\", %u, (cfish_Obj*)cfish_Bool_singleton(ivars->%s));\n";
        const char *pattern;
        if (strcmp(specifier, "bool") == 0) {
            pattern = bool_pattern;
        }
        else if (CFCType_is_integer(type)) {
            pattern = int_pattern;
        }
        else {
            pattern = float_pattern;
        }
        size_t needed = strlen(pattern) + name_len * 2 + 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);
    }
    else if (CFCType_is_object(type)) {
        char pattern[] =
            "    if (ivars->%s) {\n"
            "        Cfish_Hash_Store_Str(dump, \"%s\", %u, Cfish_Obj_Dump((cfish_Obj*)ivars->%s));\n"
            "    }\n";

        size_t needed = strlen(pattern) + name_len * 3 + 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, name_len, name);
    }
    else {
        CFCUtil_die("Don't know how to dump a %s",
                    CFCType_get_specifier(type));
    }

    CFCClass_append_autocode(klass, buf);
}
예제 #2
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);
}
예제 #3
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();
}
예제 #4
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;
}
예제 #5
0
파일: CFCDumpable.c 프로젝트: theory/lucy
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);
}
예제 #6
0
파일: CFCMethod.c 프로젝트: theory/lucy
CFCMethod*
CFCMethod_init(CFCMethod *self, CFCParcel *parcel, const char *exposure,
               const char *class_name, const char *class_cnick,
               const char *macro_sym, CFCType *return_type,
               CFCParamList *param_list, CFCDocuComment *docucomment,
               int is_final, int is_abstract) {
    // Validate macro_sym, derive micro_sym.
    if (!S_validate_macro_sym(macro_sym)) {
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Invalid macro_sym: '%s'",
                    macro_sym ? macro_sym : "[NULL]");
    }
    char *micro_sym = CFCUtil_strdup(macro_sym);
    for (size_t i = 0; micro_sym[i] != '\0'; i++) {
        micro_sym[i] = tolower(micro_sym[i]);
    }

    // Super-init and clean up derived micro_sym.
    CFCFunction_init((CFCFunction*)self, parcel, exposure, class_name,
                     class_cnick, micro_sym, return_type, param_list,
                     docucomment, false);
    FREEMEM(micro_sym);

    // Verify that the first element in the arg list is a self.
    CFCVariable **args = CFCParamList_get_variables(param_list);
    if (!args[0]) { CFCUtil_die("Missing 'self' argument"); }
    CFCType *type = CFCVariable_get_type(args[0]);
    const char *specifier = CFCType_get_specifier(type);
    const char *prefix    = CFCMethod_get_prefix(self);
    const char *last_colon = strrchr(class_name, ':');
    const char *struct_sym = last_colon ? last_colon + 1 : class_name;
    if (strcmp(specifier, struct_sym) != 0) {
        char *wanted = CFCUtil_sprintf("%s%s", prefix, struct_sym);
        int mismatch = strcmp(wanted, specifier);
        FREEMEM(wanted);
        if (mismatch) {
            CFCUtil_die("First arg type doesn't match class: '%s' '%s'",
                        class_name, specifier);
        }
    }

    self->macro_sym         = CFCUtil_strdup(macro_sym);
    self->full_override_sym = NULL;
    self->host_alias        = NULL;
    self->is_final          = is_final;
    self->is_abstract       = is_abstract;
    self->is_excluded       = false;

    // Assume that this method is novel until we discover when applying
    // inheritance that it overrides another.
    self->is_novel = true;

    return self;
}
예제 #7
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;
}
예제 #8
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);
    }
}
예제 #9
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);
    }
}
예제 #10
0
static char*
S_perl_var_name(CFCType *type, int is_ctor_retval) {
    const char *specifier = CFCType_get_specifier(type);
    char       *perl_name = NULL;

    if (CFCType_is_object(type)) {
        if (!is_ctor_retval && strcmp(specifier, "cfish_Vector") == 0) {
            perl_name = CFCUtil_strdup("arrayref");
        }
        else if (!is_ctor_retval && strcmp(specifier, "cfish_Hash") == 0) {
            perl_name = CFCUtil_strdup("hashref");
        }
        else {
            // Skip parcel prefix.
            if (CFCUtil_islower(*specifier)) {
                for (specifier++; *specifier; specifier++) {
                    if (*specifier == '_') {
                        specifier++;
                        break;
                    }
                }
            }

            perl_name = S_camel_to_lower(specifier);
        }
    }
    else if (CFCType_is_integer(type)) {
        if (strcmp(specifier, "bool") == 0) {
            perl_name = CFCUtil_strdup("bool");
        }
        else {
            perl_name = CFCUtil_strdup("int");
        }
    }
    else if (CFCType_is_floating(type)) {
        perl_name = CFCUtil_strdup("float");
    }
    else {
        CFCUtil_die("Don't know how to create code sample for type '%s'",
                    specifier);
    }

    return perl_name;
}
예제 #11
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;
}
예제 #12
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
}
예제 #13
0
파일: CFCType.c 프로젝트: hernan604/lucy
CFCType*
CFCType_new_composite(int flags, CFCType *child, int indirection,
                      const char *array) {
    if (!child) {
        CFCUtil_die("Missing required param 'child'");
    }
    flags |= CFCTYPE_COMPOSITE;
    S_check_flags(flags, CFCTYPE_COMPOSITE | CFCTYPE_NULLABLE, "Composite");

    CFCType *self = CFCType_new(flags, NULL, CFCType_get_specifier(child),
                                indirection);
    self->child = (CFCType*)CFCBase_incref((CFCBase*)child);

    // Record array spec.
    const char *array_spec = array ? array : "";
    size_t array_spec_size = strlen(array_spec) + 1;
    self->array = (char*)MALLOCATE(array_spec_size);
    strcpy(self->array, array_spec);

    return self;
}
예제 #14
0
static void
S_run_arbitrary_tests(CFCTest *test) {
    {
        CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL);
        CFCParcel_register(neato_parcel);

        CFCType *foo = CFCType_new_arbitrary(neato_parcel, "foo_t");
        STR_EQ(test, CFCType_get_specifier(foo), "foo_t", "get_specifier");
        STR_EQ(test, CFCType_to_c(foo), "foo_t", "to_c");

        CFCType *twin = CFCType_new_arbitrary(neato_parcel, "foo_t");
        OK(test, CFCType_equals(foo, twin), "equals");

        CFCType *compare_t
            = CFCType_new_arbitrary(neato_parcel, "Sort_compare_t");
        OK(test, !CFCType_equals(foo, compare_t),
           "equals spoiled by different specifier");

        CFCBase_decref((CFCBase*)neato_parcel);
        CFCBase_decref((CFCBase*)foo);
        CFCBase_decref((CFCBase*)compare_t);
        CFCBase_decref((CFCBase*)twin);
    }

    {
        CFCParser *parser = CFCParser_new();
        static const char *specifiers[2] = { "foo_t", "Sort_compare_t" };
        for (int i = 0; i < 2; ++i) {
            const char *specifier = specifiers[i];
            CFCType *type = CFCTest_parse_type(test, parser, specifier);
            OK(test, CFCType_is_arbitrary(type), "arbitrary type %s",
               specifier);
            CFCBase_decref((CFCBase*)type);
        }
        CFCBase_decref((CFCBase*)parser);
    }

    CFCParcel_reap_singletons();
}
예제 #15
0
static char*
S_perl_var_name(CFCVariable *var) {
    CFCType    *type      = CFCVariable_get_type(var);
    const char *specifier = CFCType_get_specifier(type);
    char       *perl_name = NULL;

    if (CFCType_is_object(type)) {
        // Skip parcel prefix.
        if (islower(*specifier)) {
            for (specifier++; *specifier; specifier++) {
                if (*specifier == '_') {
                    specifier++;
                    break;
                }
            }
        }

        perl_name = S_camel_to_lower(specifier);
    }
    else if (CFCType_is_integer(type)) {
        if (strcmp(specifier, "bool") == 0) {
            perl_name = CFCUtil_strdup("bool");
        }
        else {
            perl_name = CFCUtil_strdup("int");
        }
    }
    else if (CFCType_is_floating(type)) {
        perl_name = CFCUtil_strdup("float");
    }
    else {
        CFCUtil_die("Don't know how to create code sample for type '%s'",
                    specifier);
    }

    return perl_name;
}
예제 #16
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;
}
예제 #17
0
파일: CFCType.c 프로젝트: pavansondur/lucy
CFCType*
CFCType_new_composite(int flags, CFCType *child, int indirection,
                      const char *array) {
    if (!child) {
        CFCUtil_die("Missing required param 'child'");
    }
    flags |= CFCTYPE_COMPOSITE;
    S_check_flags(flags, CFCTYPE_COMPOSITE | CFCTYPE_NULLABLE, "Composite");

    // Cache C representation.
    // NOTE: Array postfixes are NOT included.
    const size_t  MAX_LEN        = 256;
    const char   *child_c_string = CFCType_to_c(child);
    size_t        child_c_len    = strlen(child_c_string);
    size_t        amount         = child_c_len + indirection;
    if (amount > MAX_LEN) {
        CFCUtil_die("C representation too long");
    }
    char c_string[MAX_LEN + 1];
    strcpy(c_string, child_c_string);
    for (int i = 0; i < indirection; i++) {
        strncat(c_string, "*", 1);
    }

    CFCType *self = CFCType_new(flags, NULL, CFCType_get_specifier(child),
                                indirection, c_string);
    self->child = (CFCType*)CFCBase_incref((CFCBase*)child);

    // Record array spec.
    const char *array_spec = array ? array : "";
    size_t array_spec_size = strlen(array_spec) + 1;
    self->array = (char*)MALLOCATE(array_spec_size);
    strcpy(self->array, array_spec);

    return self;
}
예제 #18
0
static void
S_run_float_tests(CFCTest *test) {
    {
        CFCType *type = CFCType_new_float(CFCTYPE_CONST, "float");
        OK(test, CFCType_const(type), "const");
        STR_EQ(test, CFCType_get_specifier(type), "float", "get_specifier");
        STR_EQ(test, CFCType_to_c(type), "const float",
               "'const' in C representation");
        CFCBase_decref((CFCBase*)type);
    }

    {
        CFCParser *parser = CFCParser_new();
        static const char *specifiers[2] = {
            "float",
            "double"
        };
        for (int i = 0; i < 2; ++i) {
            const char *specifier = specifiers[i];
            CFCType *type;

            type = CFCTest_parse_type(test, parser, specifier);
            OK(test, CFCType_is_floating(type), "%s is_floating", 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_floating(type), "%s is_floating",
               const_specifier);
            OK(test, CFCType_const(type), "%s is const", const_specifier);
            FREEMEM(const_specifier);
            CFCBase_decref((CFCBase*)type);
        }
        CFCBase_decref((CFCBase*)parser);
    }
}
예제 #19
0
char*
CFCPerlTypeMap_from_perl(CFCType *type, const char *xs_var) {
    char *result = NULL;

    if (CFCType_is_object(type)) {
        const char *struct_sym = CFCType_get_specifier(type);
        const char *vtable_var = CFCType_get_vtable_var(type);
        if (strcmp(struct_sym, "lucy_CharBuf") == 0
            || strcmp(struct_sym, "cfish_CharBuf") == 0
            || strcmp(struct_sym, "lucy_Obj") == 0
            || strcmp(struct_sym, "cfish_Obj") == 0
           ) {
            // Share buffers rather than copy between Perl scalars and
            // Clownfish string types.
            result = CFCUtil_cat(CFCUtil_strdup(""), "(", struct_sym,
                                 "*)XSBind_sv_to_cfish_obj(", xs_var,
                                 ", ", vtable_var,
                                 ", alloca(cfish_ZCB_size()))", NULL);
        }
        else {
            result = CFCUtil_cat(CFCUtil_strdup(""), "(", struct_sym,
                                 "*)XSBind_sv_to_cfish_obj(", xs_var,
                                 ", ", vtable_var, ", NULL)", NULL);
        }
    }
    else if (CFCType_is_primitive(type)) {
        const char *specifier = CFCType_get_specifier(type);
        size_t size = 80 + strlen(xs_var) * 2;
        result = (char*)MALLOCATE(size);

        if (strcmp(specifier, "double") == 0) {
            sprintf(result, "SvNV(%s)", xs_var);
        }
        else if (strcmp(specifier, "float") == 0) {
            sprintf(result, "(float)SvNV(%s)", xs_var);
        }
        else if (strcmp(specifier, "int") == 0) {
            sprintf(result, "(int)SvIV(%s)", xs_var);
        }
        else if (strcmp(specifier, "short") == 0) {
            sprintf(result, "(short)SvIV(%s)", xs_var);
        }
        else if (strcmp(specifier, "long") == 0) {
            const char pattern[] =
                "((sizeof(long) <= sizeof(IV)) ? (long)SvIV(%s) "
                ": (long)SvNV(%s))";
            sprintf(result, pattern, xs_var, xs_var);
        }
        else if (strcmp(specifier, "size_t") == 0) {
            sprintf(result, "(size_t)SvIV(%s)", xs_var);
        }
        else if (strcmp(specifier, "uint64_t") == 0) {
            sprintf(result, "(uint64_t)SvNV(%s)", xs_var);
        }
        else if (strcmp(specifier, "uint32_t") == 0) {
            sprintf(result, "(uint32_t)SvUV(%s)", xs_var);
        }
        else if (strcmp(specifier, "uint16_t") == 0) {
            sprintf(result, "(uint16_t)SvUV(%s)", xs_var);
        }
        else if (strcmp(specifier, "uint8_t") == 0) {
            sprintf(result, "(uint8_t)SvUV(%s)", xs_var);
        }
        else if (strcmp(specifier, "int64_t") == 0) {
            sprintf(result, "(int64_t)SvNV(%s)", xs_var);
        }
        else if (strcmp(specifier, "int32_t") == 0) {
            sprintf(result, "(int32_t)SvIV(%s)", xs_var);
        }
        else if (strcmp(specifier, "int16_t") == 0) {
            sprintf(result, "(int16_t)SvIV(%s)", xs_var);
        }
        else if (strcmp(specifier, "int8_t") == 0) {
            sprintf(result, "(int8_t)SvIV(%s)", xs_var);
        }
        else if (strcmp(specifier, "chy_bool_t") == 0) {
            sprintf(result, "SvTRUE(%s) ? 1 : 0", xs_var);
        }
        else {
            FREEMEM(result);
            result = NULL;
        }
    }

    return result;
}
예제 #20
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;
}
예제 #21
0
char*
CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) {
    if (CFCType_cfish_obj(type)) {
        return CFCUtil_strdup("interface{}");
    }
    else if (CFCType_cfish_string(type)) {
        return CFCUtil_strdup("string");
    }
    else if (CFCType_cfish_blob(type)) {
        return CFCUtil_strdup("[]byte");
    }
    else if (CFCType_cfish_vector(type)) {
        return CFCUtil_strdup("[]interface{}");
    }
    else if (CFCType_cfish_hash(type)) {
        return CFCUtil_strdup("map[string]interface{}");
    }
    else if (CFCType_is_object(type)) {
        // Divide the specifier into prefix and struct name.
        const char *specifier  = CFCType_get_specifier(type);
        size_t      prefix_len = 0;
        for (size_t max = strlen(specifier); prefix_len < max; prefix_len++) {
            if (isupper(specifier[prefix_len])) {
                break;
            }
        }
        if (!prefix_len) {
            CFCUtil_die("Can't convert object type name '%s'", specifier);
        }
        const char *struct_sym = specifier + prefix_len;

        // Find the parcel that the type lives in.
        CFCParcel** all_parcels = CFCParcel_all_parcels();
        CFCParcel *parcel = NULL;
        for (int i = 0; all_parcels[i] != NULL; i++) {
            const char *candidate = CFCParcel_get_prefix(all_parcels[i]);
            if (strncmp(candidate, specifier, prefix_len) == 0
                && strlen(candidate) == prefix_len
               ) {
                parcel = all_parcels[i];
                break;
            }
        }
        if (!parcel) {
            CFCUtil_die("Can't find parcel for type '%s'", specifier);
        }

        // If the type lives in this parcel, return only the struct sym
        // without a go package prefix.
        if (parcel == current_parcel) {
            return CFCUtil_strdup(struct_sym);
        }

        // The type lives in another parcel, so prefix its Go package name.
        // TODO: Stop downcasing once Clownfish parcel names are constrained
        // to lower case.
        const char *package_name = CFCParcel_get_name(parcel);
        if (strrchr(package_name, '.')) {
            package_name = strrchr(package_name, '.') + 1;
        }
        char *result = CFCUtil_sprintf("%s.%s", package_name, struct_sym);
        for (int i = 0; result[i] != '.'; i++) {
            result[i] = tolower(result[i]);
        }
        return result;
    }
    else if (CFCType_is_primitive(type)) {
        const char *specifier = CFCType_get_specifier(type);
        for (int i = 0; i < num_conversions; i++) {
            if (strcmp(specifier, conversions[i].c) == 0) {
                return CFCUtil_strdup(conversions[i].go);
            }
        }
    }

    return NULL;
}
예제 #22
0
static void
S_run_object_tests(CFCTest *test) {
    static const char *modifiers[4] = {
        "const", "incremented", "decremented", "nullable"
    };
    static int flags[4] = {
        CFCTYPE_CONST,
        CFCTYPE_INCREMENTED,
        CFCTYPE_DECREMENTED,
        CFCTYPE_NULLABLE
    };
    static int (*accessors[4])(CFCType *type) = {
        CFCType_const,
        CFCType_incremented,
        CFCType_decremented,
        CFCType_nullable
    };

    {
        CFCParser *parser = CFCParser_new();
        CFCParcel *neato_parcel
            = CFCTest_parse_parcel(test, parser, "parcel Neato;");

        static const char *specifiers[4] = {
            "Foo", "FooJr", "FooIII", "Foo4th"
        };
        for (int i = 0; i < 4; ++i) {
            const char *specifier = specifiers[i];

            char *class_code = CFCUtil_sprintf("class %s {}", specifier);
            CFCClass *klass = CFCTest_parse_class(test, parser, class_code);
            FREEMEM(class_code);

            static const char *prefixes[2] = { "", "neato_" };
            char *expect = CFCUtil_sprintf("neato_%s", specifier);
            for (int j = 0; j < 2; ++j) {
                char *src = CFCUtil_sprintf("%s%s*", prefixes[j], specifier);
                CFCType *type = CFCTest_parse_type(test, parser, src);
                CFCType_resolve(type);
                STR_EQ(test, CFCType_get_specifier(type), expect,
                       "object_type_specifier: %s", src);
                OK(test, CFCType_is_object(type), "%s is_object", src);
                INT_EQ(test, CFCType_get_indirection(type), 1,
                       "%s indirection", src);

                FREEMEM(src);
                CFCBase_decref((CFCBase*)type);
            }
            FREEMEM(expect);

            for (int j = 0; j < 4; ++j) {
                char *src = CFCUtil_sprintf("%s %s*", modifiers[j], specifier);
                CFCType *type = CFCTest_parse_type(test, parser, src);
                OK(test, CFCType_is_object(type), "%s is_object", src);
                OK(test, accessors[j](type), "%s accessor", src);

                FREEMEM(src);
                CFCBase_decref((CFCBase*)type);
            }

            CFCBase_decref((CFCBase*)klass);
            CFCClass_clear_registry();
        }

        CFCBase_decref((CFCBase*)neato_parcel);
        CFCBase_decref((CFCBase*)parser);
    }

    CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL);
    CFCClass *foo_class
        = CFCClass_create(neato_parcel, NULL, "Foo", NULL, NULL, NULL, NULL,
                          NULL, false, false, false);
    CFCType *foo = CFCType_new_object(0, neato_parcel, "Foo", 1);
    CFCType_resolve(foo);

    {
        CFCType *another_foo = CFCType_new_object(0, neato_parcel, "Foo", 1);
        CFCType_resolve(another_foo);
        OK(test, CFCType_equals(foo, another_foo), "equals");
        CFCBase_decref((CFCBase*)another_foo);
    }

    {
        CFCClass *bar_class
            = CFCClass_create(neato_parcel, NULL, "Bar", NULL, NULL, NULL,
                              NULL, NULL, false, false, false);
        CFCType *bar = CFCType_new_object(0, neato_parcel, "Bar", 1);
        CFCType_resolve(bar);
        OK(test, !CFCType_equals(foo, bar),
           "different specifier spoils equals");
        CFCBase_decref((CFCBase*)bar);
        CFCBase_decref((CFCBase*)bar_class);
    }

    {
        CFCParcel *foreign_parcel
            = CFCParcel_new("Foreign", NULL, NULL, NULL);
        CFCClass *foreign_foo_class
            = CFCClass_create(foreign_parcel, NULL, "Foreign::Foo", NULL, NULL,
                              NULL, NULL, NULL, false, false, false);
        CFCType *foreign_foo = CFCType_new_object(0, foreign_parcel, "Foo", 1);
        CFCType_resolve(foreign_foo);
        OK(test, !CFCType_equals(foo, foreign_foo),
           "different parcel spoils equals");
        STR_EQ(test, CFCType_get_specifier(foreign_foo), "foreign_Foo",
               "prepend parcel prefix to specifier");
        CFCBase_decref((CFCBase*)foreign_parcel);
        CFCBase_decref((CFCBase*)foreign_foo_class);
        CFCBase_decref((CFCBase*)foreign_foo);
    }

    {
        for (int i = 0; i < 4; ++i) {
            CFCType *modified_foo
                = CFCType_new_object(flags[i], neato_parcel, "Foo", 1);
            CFCType_resolve(modified_foo);
            OK(test, accessors[i](modified_foo), "%s", modifiers[i]);
            OK(test, !accessors[i](foo), "not %s", modifiers[i]);
            OK(test, !CFCType_equals(foo, modified_foo),
               "different %s spoils equals", modifiers[i]);
            OK(test, !CFCType_similar(foo, modified_foo),
               "different %s spoils similar", modifiers[i]);
            CFCBase_decref((CFCBase*)modified_foo);
        }
    }

    {
        CFCType *string_type
            = CFCType_new_object(0, neato_parcel, "String", 1);
        OK(test, CFCType_is_string_type(string_type), "%s", "is_string_type");
        OK(test, !CFCType_is_string_type(foo), "not %s", "not is_string_type");
        CFCBase_decref((CFCBase*)string_type);
    }

    CFCBase_decref((CFCBase*)neato_parcel);
    CFCBase_decref((CFCBase*)foo_class);
    CFCBase_decref((CFCBase*)foo);

    CFCClass_clear_registry();
    CFCParcel_reap_singletons();
}
예제 #23
0
char*
CFCPerlTypeMap_to_perl(CFCType *type, const char *cf_var) {
    const char *type_str = CFCType_to_c(type);
    char *result = NULL;

    if (CFCType_is_object(type)) {
        result = CFCUtil_cat(CFCUtil_strdup(""), "(", cf_var,
                             " == NULL ? newSV(0) : "
                             "XSBind_cfish_to_perl((cfish_Obj*)",
                             cf_var, "))", NULL);
    }
    else if (CFCType_is_primitive(type)) {
        // Convert from a primitive type to a Perl scalar.
        const char *specifier = CFCType_get_specifier(type);
        size_t size = 80 + strlen(cf_var) * 2;
        result = (char*)MALLOCATE(size);

        if (strcmp(specifier, "double") == 0) {
            sprintf(result, "newSVnv(%s)", cf_var);
        }
        else if (strcmp(specifier, "float") == 0) {
            sprintf(result, "newSVnv(%s)", cf_var);
        }
        else if (strcmp(specifier, "int") == 0) {
            sprintf(result, "newSViv(%s)", cf_var);
        }
        else if (strcmp(specifier, "short") == 0) {
            sprintf(result, "newSViv(%s)", cf_var);
        }
        else if (strcmp(specifier, "long") == 0) {
            char pattern[] =
                "((sizeof(long) <= sizeof(IV)) ? "
                "newSViv((IV)%s) : newSVnv((NV)%s))";
            sprintf(result, pattern, cf_var, cf_var);
        }
        else if (strcmp(specifier, "size_t") == 0) {
            sprintf(result, "newSViv(%s)", cf_var);
        }
        else if (strcmp(specifier, "uint64_t") == 0) {
            char pattern[] = "sizeof(UV) == 8 ? newSVuv((UV)%s) : newSVnv((NV)%s)";
            sprintf(result, pattern, cf_var, cf_var);
        }
        else if (strcmp(specifier, "uint32_t") == 0) {
            sprintf(result, "newSVuv(%s)", cf_var);
        }
        else if (strcmp(specifier, "uint16_t") == 0) {
            sprintf(result, "newSVuv(%s)", cf_var);
        }
        else if (strcmp(specifier, "uint8_t") == 0) {
            sprintf(result, "newSVuv(%s)", cf_var);
        }
        else if (strcmp(specifier, "int64_t") == 0) {
            char pattern[] = "sizeof(IV) == 8 ? newSViv((IV)%s) : newSVnv((NV)%s)";
            sprintf(result, pattern, cf_var, cf_var);
        }
        else if (strcmp(specifier, "int32_t") == 0) {
            sprintf(result, "newSViv(%s)", cf_var);
        }
        else if (strcmp(specifier, "int16_t") == 0) {
            sprintf(result, "newSViv(%s)", cf_var);
        }
        else if (strcmp(specifier, "int8_t") == 0) {
            sprintf(result, "newSViv(%s)", cf_var);
        }
        else if (strcmp(specifier, "chy_bool_t") == 0) {
            sprintf(result, "newSViv(%s)", cf_var);
        }
        else {
            FREEMEM(result);
            result = NULL;
        }
    }
    else if (CFCType_is_composite(type)) {
        if (strcmp(type_str, "void*") == 0) {
            // Assume that void* is a reference SV -- either a hashref or an
            // arrayref.
            result = CFCUtil_cat(CFCUtil_strdup(""), "newRV_inc((SV*)",
                                 cf_var, ")", NULL);
        }
    }

    return result;
}
예제 #24
0
static void
S_run_composite_tests(CFCTest *test) {
    CFCParser *parser = CFCParser_new();
    CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL, NULL);
    CFCParser_set_parcel(parser, neato_parcel);

    {
        static const char *type_strings[14] = {
            "char*",
            "char**",
            "char***",
            "int32_t*",
            "Obj**",
            "int8_t[]",
            "int8_t[1]",
            "neato_method_t[]",
            "neato_method_t[1]",
            "multi_dimensional_t[1][10]",
            "char * * ",
            "const Obj**",
            "const void*",
            "int8_t[ 3 ]"
        };
        for (int i = 0; i < 14; ++i) {
            const char *type_string = type_strings[i];
            CFCType *type = CFCTest_parse_type(test, parser, type_string);
            OK(test, CFCType_is_composite(type), "composite type %s",
               type_string);
            CFCBase_decref((CFCBase*)type);
        }
    }

    {
        CFCType *foo = CFCType_new_object(0, neato_parcel, "Foo", 1);
        CFCType *const_foo
            = CFCType_new_object(CFCTYPE_CONST, neato_parcel, "Foo", 1);

        CFCType *composite = CFCType_new_composite(0, foo, 1, NULL);
        OK(test, CFCType_is_composite(composite), "is_composite");
        STR_EQ(test, CFCType_get_specifier(composite), "Foo",
               "get_specifier delegates to child" );

        CFCType *twin = CFCType_new_composite(0, foo, 1, NULL);
        OK(test, CFCType_equals(composite, twin), "equals");
        CFCBase_decref((CFCBase*)twin);

        CFCType *const_composite
            = CFCType_new_composite(0, const_foo, 1, NULL);
        OK(test, !CFCType_equals(composite, const_composite),
           "equals spoiled by different child");
        CFCBase_decref((CFCBase*)const_composite);

        CFCBase_decref((CFCBase*)composite);
        CFCBase_decref((CFCBase*)foo);
        CFCBase_decref((CFCBase*)const_foo);
    }

    {
        CFCType *foo_array = CFCTest_parse_type(test, parser, "foo_t[]");
        CFCType_resolve(foo_array);
        STR_EQ(test, CFCType_get_array(foo_array), "[]", "get_array");
        STR_EQ(test, CFCType_to_c(foo_array), "foo_t",
               "array subscripts not included by to_c");
        CFCType *foo_array_array
            = CFCTest_parse_type(test, parser, "foo_t[][]");
        OK(test, !CFCType_equals(foo_array, foo_array_array),
           "equals spoiled by different array postfixes");

        CFCBase_decref((CFCBase*)foo_array);
        CFCBase_decref((CFCBase*)foo_array_array);
    }

    {
        CFCType *foo_star = CFCTest_parse_type(test, parser, "foo_t*");
        CFCType *foo_star_star = CFCTest_parse_type(test, parser, "foo_t**");
        OK(test, !CFCType_equals(foo_star, foo_star_star),
           "equals spoiled by different levels of indirection");
        INT_EQ(test, CFCType_get_indirection(foo_star), 1,
               "foo_t* indirection");
        INT_EQ(test, CFCType_get_indirection(foo_star_star), 2,
               "foo_t** indirection");

        CFCBase_decref((CFCBase*)foo_star);
        CFCBase_decref((CFCBase*)foo_star_star);
    }

    CFCBase_decref((CFCBase*)neato_parcel);
    CFCBase_decref((CFCBase*)parser);
}
예제 #25
0
static void
S_run_tests(CFCTest *test) {
#define STUFF_THING "Stuff" CHY_DIR_SEP "Thing"

    CFCParser *parser = CFCParser_new();
    CFCFileSpec *file_spec = CFCFileSpec_new(".", STUFF_THING, 0);

    {
        const char *string =
            "parcel Stuff;\n"
            "class Stuff::Thing {\n"
            "    Foo *foo;\n"
            "    Bar *bar;\n"
            "}\n"
            "class Foo {}\n"
            "class Bar {}\n"
            "__C__\n"
            "int foo;\n"
            "__END_C__\n";
        CFCFile *file = CFCParser_parse_file(parser, string, file_spec);

        STR_EQ(test, CFCFile_get_source_dir(file), ".", "get_source_dir");
        STR_EQ(test, CFCFile_get_path_part(file), STUFF_THING,
               "get_path_part");
        OK(test, !CFCFile_included(file), "included");

        STR_EQ(test, CFCFile_guard_name(file), "H_STUFF_THING", "guard_name");
        STR_EQ(test, CFCFile_guard_start(file),
               "#ifndef H_STUFF_THING\n#define H_STUFF_THING 1\n",
               "guard_start");
        STR_EQ(test, CFCFile_guard_close(file), "#endif /* H_STUFF_THING */\n",
               "guard_close");

        OK(test, !CFCFile_get_modified(file), "modified false at start");
        CFCFile_set_modified(file, 1);
        OK(test, CFCFile_get_modified(file), "set_modified, get_modified");

#define PATH_TO_STUFF_THING \
    "path" CHY_DIR_SEP \
    "to" CHY_DIR_SEP \
    "Stuff" CHY_DIR_SEP \
    "Thing"

        char *cfh_path = CFCFile_cfh_path(file, "path/to");
        STR_EQ(test, cfh_path, PATH_TO_STUFF_THING ".cfh", "cfh_path");
        FREEMEM(cfh_path);
        char *c_path = CFCFile_c_path(file, "path/to");
        STR_EQ(test, c_path, PATH_TO_STUFF_THING ".c", "c_path");
        FREEMEM(c_path);
        char *h_path = CFCFile_h_path(file, "path/to");
        STR_EQ(test, h_path, PATH_TO_STUFF_THING ".h", "h_path");
        FREEMEM(h_path);

        CFCClass **classes = CFCFile_classes(file);
        OK(test,
           classes[0] != NULL && classes[1] != NULL && classes[2] != NULL
           && classes[3] == NULL,
           "classes() filters blocks");
        CFCVariable **member_vars = CFCClass_fresh_member_vars(classes[0]);
        CFCType *foo_type = CFCVariable_get_type(member_vars[0]);
        CFCType_resolve(foo_type);
        STR_EQ(test, CFCType_get_specifier(foo_type), "stuff_Foo",
               "file production picked up parcel def");
        CFCType *bar_type = CFCVariable_get_type(member_vars[1]);
        CFCType_resolve(bar_type);
        STR_EQ(test, CFCType_get_specifier(bar_type), "stuff_Bar",
               "parcel def is sticky");

        CFCParcel *parcel = CFCFile_get_parcel(file);
        STR_EQ(test, CFCParcel_get_name(parcel), "Stuff", "get_parcel");

        CFCBase **blocks = CFCFile_blocks(file);
        STR_EQ(test, CFCBase_get_cfc_class(blocks[0]),
               "Clownfish::CFC::Model::Class", "blocks[0]");
        STR_EQ(test, CFCBase_get_cfc_class(blocks[1]),
               "Clownfish::CFC::Model::Class", "blocks[1]");
        STR_EQ(test, CFCBase_get_cfc_class(blocks[2]),
               "Clownfish::CFC::Model::Class", "blocks[2]");
        STR_EQ(test, CFCBase_get_cfc_class(blocks[3]),
               "Clownfish::CFC::Model::CBlock", "blocks[3]");
        OK(test, blocks[4] == NULL, "blocks[4]");

        CFCBase_decref((CFCBase*)file);

        CFCClass_clear_registry();
    }

    CFCBase_decref((CFCBase*)file_spec);
    CFCBase_decref((CFCBase*)parser);

    CFCParcel_reap_singletons();
}
예제 #26
0
static void
S_run_tests(CFCTest *test) {
    CFCParser *parser = CFCParser_new();
    OK(test, parser != NULL, "new");

    {
        CFCParcel *fish = CFCTest_parse_parcel(test, parser, "parcel Fish;");

        CFCParcel *registered
            = CFCParcel_new("Crustacean", "Crust", NULL, false);
        CFCParcel_register(registered);
        CFCParcel *parcel
            = CFCTest_parse_parcel(test, parser, "parcel Crustacean;");
        OK(test, parcel == registered, "Fetch registered parcel");
        OK(test, CFCParser_get_parcel(parser) == parcel,
           "parcel_definition sets internal var");

        CFCBase_decref((CFCBase*)fish);
        CFCBase_decref((CFCBase*)registered);
        CFCBase_decref((CFCBase*)parcel);
    }

    {
        static const char *const specifiers[8] = {
            "foo", "_foo", "foo_yoo", "FOO", "Foo", "fOO", "f00", "foo_foo_foo"
        };
        for (int i = 0; i < 8; ++i) {
            const char *specifier = specifiers[i];
            char *src = CFCUtil_sprintf("int32_t %s;", specifier);
            CFCVariable *var = CFCTest_parse_variable(test, parser, src);
            STR_EQ(test, CFCVariable_micro_sym(var), specifier,
                   "identifier/declarator: %s", specifier);
            FREEMEM(src);
            CFCBase_decref((CFCBase*)var);
        }
    }

    {
        static const char *const specifiers[6] = {
            "void", "float", "uint32_t", "int64_t", "uint8_t", "bool"
        };
        for (int i = 0; i < 6; ++i) {
            const char *specifier = specifiers[i];
            char *src = CFCUtil_sprintf("int32_t %s;", specifier);
            CFCBase *result = CFCParser_parse(parser, src);
            OK(test, result == NULL,
               "reserved word not parsed as identifier: %s", specifier);
            FREEMEM(src);
            CFCBase_decref(result);
        }
    }

    {
        static const char *const type_strings[7] = {
            "bool", "const char *", "Obj*", "i32_t", "char[]", "long[1]",
            "i64_t[30]"
        };
        for (int i = 0; i < 7; ++i) {
            const char *type_string = type_strings[i];
            CFCType *type = CFCTest_parse_type(test, parser, type_string);
            CFCBase_decref((CFCBase*)type);
        }
    }

    {
        static const char *const class_names[7] = {
            "ByteBuf", "Obj", "ANDMatcher", "Foo", "FooJr", "FooIII", "Foo4th"
        };
        CFCClass *class_list[8];
        for (int i = 0; i < 7; ++i) {
            char *class_code = CFCUtil_sprintf("class %s {}", class_names[i]);
            CFCClass *klass = CFCTest_parse_class(test, parser, class_code);
            class_list[i] = klass;
            FREEMEM(class_code);
        }
        class_list[7] = NULL;
        for (int i = 0; i < 7; ++i) {
            const char *class_name = class_names[i];
            char *src      = CFCUtil_sprintf("%s*", class_name);
            char *expected = CFCUtil_sprintf("crust_%s", class_name);
            CFCType *type = CFCTest_parse_type(test, parser, src);
            CFCType_resolve(type, class_list);
            STR_EQ(test, CFCType_get_specifier(type), expected,
                   "object_type_specifier: %s", class_name);
            FREEMEM(src);
            FREEMEM(expected);
            CFCBase_decref((CFCBase*)type);
        }
        for (int i = 0; i < 7; ++i) {
            CFCBase_decref((CFCBase*)class_list[i]);
        }
        CFCClass_clear_registry();
    }

    {
        CFCType *type = CFCTest_parse_type(test, parser, "const char");
        OK(test, CFCType_const(type), "type_qualifier const");
        CFCBase_decref((CFCBase*)type);
    }

    {
        static const char *const exposures[2] = {
            "public", ""
        };
        static int (*const accessors[2])(CFCSymbol *sym) = {
            CFCSymbol_public, CFCSymbol_parcel
        };
        for (int i = 0; i < 2; ++i) {
            const char *exposure = exposures[i];
            char *src = CFCUtil_sprintf("%s inert int32_t foo;", exposure);
            CFCVariable *var = CFCTest_parse_variable(test, parser, src);
            OK(test, accessors[i]((CFCSymbol*)var), "exposure_specifier %s",
               exposure);
            FREEMEM(src);
            CFCBase_decref((CFCBase*)var);
        }
    }

    {
        static const char *const hex_constants[] = {
            "0x1", "0x0a", "0xFFFFFFFF", "-0xFC", NULL
        };
        S_test_initial_value(test, parser, hex_constants, "int32_t",
                             "hex_constant:");
    }

    {
        static const char *const integer_constants[] = {
            "1", "-9999", "0", "10000", NULL
        };
        S_test_initial_value(test, parser, integer_constants, "int32_t",
                             "integer_constant:");
    }

    {
        static const char *const float_constants[] = {
            "1.0", "-9999.999", "0.1", "0.0", NULL
        };
        S_test_initial_value(test, parser, float_constants, "double",
                             "float_constant:");
    }

    {
        static const char *const string_literals[] = {
            "\"blah\"", "\"blah blah\"", "\"\\\"blah\\\" \\\"blah\\\"\"", NULL
        };
        S_test_initial_value(test, parser, string_literals, "String*",
                             "string_literal:");
    }

    {
        static const char *const composites[5] = {
            "int[]", "i32_t **", "Foo **", "Foo ***", "const void *"
        };
        for (int i = 0; i < 5; ++i) {
            const char *composite = composites[i];
            CFCType *type = CFCTest_parse_type(test, parser, composite);
            OK(test, CFCType_is_composite(type), "composite_type: %s",
               composite);
            CFCBase_decref((CFCBase*)type);
        }
    }

    {
        static const char *const object_types[5] = {
            "Obj *", "incremented Foo*", "decremented String *"
        };
        for (int i = 0; i < 3; ++i) {
            const char *object_type = object_types[i];
            CFCType *type = CFCTest_parse_type(test, parser, object_type);
            OK(test, CFCType_is_object(type), "object_type: %s",
               object_type);
            CFCBase_decref((CFCBase*)type);
        }
    }

    {
        static const char *const param_list_strings[3] = {
            "()",
            "(int foo)",
            "(Obj *foo, Foo **foo_ptr)"
        };
        for (int i = 0; i < 3; ++i) {
            const char *param_list_string = param_list_strings[i];
            CFCParamList *param_list
                = CFCTest_parse_param_list(test, parser, param_list_string);
            INT_EQ(test, CFCParamList_num_vars(param_list), i,
                   "param list num_vars: %d", i);
            CFCBase_decref((CFCBase*)param_list);
        }
    }

    {
        CFCParamList *param_list
            = CFCTest_parse_param_list(test, parser, "(int foo, ...)");
        OK(test, CFCParamList_variadic(param_list), "variadic param list");
        CFCBase_decref((CFCBase*)param_list);
    }

    {
        const char *param_list_string =
            "(int foo = 0xFF, char *bar =\"blah\")";
        CFCParamList *param_list
            = CFCTest_parse_param_list(test, parser, param_list_string);
        const char **initial_values
            = CFCParamList_get_initial_values(param_list);
        STR_EQ(test, initial_values[0], "0xFF",
               "param list initial_values[0]");
        STR_EQ(test, initial_values[1], "\"blah\"",
               "param list initial_values[1]");
        OK(test, initial_values[2] == NULL, "param list initial_values[2]");
        CFCBase_decref((CFCBase*)param_list);
    }

    {
        CFCParser_set_class_name(parser, "Stuff::Obj");
        CFCParser_set_class_cnick(parser, "Obj");

        const char *method_string =
            "public Foo* Spew_Foo(Obj *self, uint32_t *how_many);";
        CFCMethod *method = CFCTest_parse_method(test, parser, method_string);
        CFCBase_decref((CFCBase*)method);

        const char *var_string =
            "public inert Hash *hash;";
        CFCVariable *var = CFCTest_parse_variable(test, parser, var_string);
        CFCBase_decref((CFCBase*)var);
    }

    {
        static const char *const class_names[4] = {
            "Foo", "Foo::FooJr", "Foo::FooJr::FooIII",
            "Foo::FooJr::FooIII::Foo4th"
        };
        for (int i = 0; i < 4; ++i) {
            const char *class_name = class_names[i];
            char *class_string = CFCUtil_sprintf("class %s { }", class_name);
            CFCClass *klass
                = CFCTest_parse_class(test, parser, class_string);
            STR_EQ(test, CFCClass_get_class_name(klass), class_name,
                   "class_name: %s", class_name);
            FREEMEM(class_string);
            CFCBase_decref((CFCBase*)klass);
        }
    }

    {
        static const char *const cnicks[2] =  { "Food", "FF" };
        for (int i = 0; i < 2; ++i) {
            const char *cnick = cnicks[i];
            char *class_string
                = CFCUtil_sprintf("class Foodie%s cnick %s { }", cnick, cnick);
            CFCClass *klass
                = CFCTest_parse_class(test, parser, class_string);
            STR_EQ(test, CFCClass_get_cnick(klass), cnick, "cnick: %s", cnick);
            FREEMEM(class_string);
            CFCBase_decref((CFCBase*)klass);
        }
    }

    CFCBase_decref((CFCBase*)parser);

    CFCClass_clear_registry();
    CFCParcel_reap_singletons();
}