Beispiel #1
0
int
CFCType_equals(CFCType *self, CFCType *other) {
    if ((CFCType_const(self)           ^ CFCType_const(other))
        || (CFCType_nullable(self)     ^ CFCType_nullable(other))
        || (CFCType_is_void(self)      ^ CFCType_is_void(other))
        || (CFCType_is_object(self)    ^ CFCType_is_object(other))
        || (CFCType_is_primitive(self) ^ CFCType_is_primitive(other))
        || (CFCType_is_integer(self)   ^ CFCType_is_integer(other))
        || (CFCType_is_floating(self)  ^ CFCType_is_floating(other))
        || (CFCType_is_va_list(self)   ^ CFCType_is_va_list(other))
        || (CFCType_is_arbitrary(self) ^ CFCType_is_arbitrary(other))
        || (CFCType_is_composite(self) ^ CFCType_is_composite(other))
        || (CFCType_incremented(self)  ^ CFCType_incremented(other))
        || (CFCType_decremented(self)  ^ CFCType_decremented(other))
        || !!self->child ^ !!other->child
        || !!self->array ^ !!other->array
       ) {
        return false;
    }
    if (self->indirection != other->indirection) { return false; }
    if (strcmp(self->specifier, other->specifier) != 0) { return false; }
    if (self->child) {
        if (!CFCType_equals(self->child, other->child)) { return false; }
    }
    if (self->array) {
        if (strcmp(self->array, other->array) != 0) { return false; }
    }
    return true;
}
Beispiel #2
0
void
CFCType_resolve(CFCType *self, CFCClass **classes) {
    if (CFCType_is_composite(self)) {
        CFCType_resolve(self->child, classes);
        return;
    }
    if (!CFCType_is_object(self)) {
        return;
    }

    CFCClass *klass     = NULL;
    char     *specifier = self->specifier;

    if (isupper(self->specifier[0])) {
        // Try to find class from class list.
        for (size_t i = 0; classes[i]; ++i) {
            CFCClass   *maybe_class = classes[i];
            const char *struct_sym  = CFCClass_get_struct_sym(maybe_class);

            if (strcmp(specifier, struct_sym) == 0) {
                if (klass) {
                    CFCUtil_die("Type '%s' is ambigious", specifier);
                }
                klass = maybe_class;
            }
        }

        if (!klass) {
            CFCUtil_die("No class found for type '%s'", specifier);
        }

        // Create actual specifier with prefix.
        const char *prefix = CFCClass_get_prefix(klass);
        self->specifier = CFCUtil_sprintf("%s%s", prefix, specifier);
        FREEMEM(specifier);
    }
    else {
        // Try to find class from class list.
        for (size_t i = 0; classes[i]; ++i) {
            CFCClass *maybe_class = classes[i];
            const char *full_struct_sym
                = CFCClass_full_struct_sym(maybe_class);

            if (strcmp(specifier, full_struct_sym) == 0) {
                klass = maybe_class;
                break;
            }
        }
    }

    // Add parcel dependency.
    if (klass) {
        CFCParcel *class_parcel = CFCClass_get_parcel(klass);
        CFCParcel_add_dependent_parcel(self->parcel, class_parcel);
    }
}
Beispiel #3
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);
}
Beispiel #4
0
char*
CFCVariable_global_c(CFCVariable *self, CFCClass *klass) {
    const char *type_str = CFCType_to_c(self->type);
    const char *postfix  = "";
    if (CFCType_is_composite(self->type)
        && CFCType_get_array(self->type) != NULL
       ) {
        postfix = CFCType_get_array(self->type);
    }

    char *full_sym = CFCVariable_full_sym(self, klass);
    char *global_c = CFCUtil_sprintf("%s %s%s", type_str, full_sym, postfix);

    FREEMEM(full_sym);
    return global_c;
}
Beispiel #5
0
const char*
CFCType_to_c(CFCType *self) {
    char *c_string = self->c_string;

    if (c_string) { return c_string; }

    if (CFCType_is_composite(self)) {
        // NOTE: Array postfixes are NOT included.
        const char *child_c_string = CFCType_to_c(self->child);
        size_t      child_c_len    = strlen(child_c_string);
        size_t      amount         = child_c_len + self->indirection;
        c_string = (char*)MALLOCATE(amount + 1);
        strcpy(c_string, child_c_string);
        for (int i = 0; i < self->indirection; i++) {
            strncat(c_string, "*", 1);
        }
    }
    else if (CFCType_is_object(self)) {
        if (CFCType_const(self)) {
            c_string = CFCUtil_sprintf("const %s*", self->specifier);
        }
        else {
            c_string = CFCUtil_sprintf("%s*", self->specifier);
        }
    }
    else {
        if (CFCType_const(self)) {
            c_string = CFCUtil_sprintf("const %s", self->specifier);
        }
        else {
            c_string = CFCUtil_strdup(self->specifier);
        }
    }

    self->c_string = c_string;

    return c_string;
}
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);
}
Beispiel #7
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;
}
Beispiel #8
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();
}