aboutsummaryrefslogtreecommitdiff
path: root/test/cgen_test/cgen_test.c
blob: 6d58ed1a9e3fdb82c085dba1b1e7a1cc03bf9e6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 * Parse and verify schema complex nonsense schema, then generate common
 * and schema specific files for reader and builder, all outfileenated to
 * stdout, followed by the schema source in a comment.
 *
 * Notes:
 *
 * Later type declarations are visible in the same file regardles of
 * namespace. Earlier type declarations in included files are also
 * visible. Included files cannot see types in later included or
 * including files. (We do not test file inclusion here though). This
 * behaviour is chosen both because it seems sensible and because it
 * allows for independent file generation of each schema file.
 *
 * Googles flatc compiler does in some cases allow for later references
 * e.g. Monster reference itself, but require structs to be ordered.
 * We do not required that so structs are sorted topologically before
 * being given to the code generator. Tables use multiple layers of
 * forward declarations in the generated C code.
 *
 * Note: The google flatc compiler does support multiple namspaces
 * but apparently it not currently generate C++ correctly. As such is
 * not well-defined what exactly the meaning of a namespace is. We have
 * chosen it to mean everything from the definition until the next in
 * the same file. Anything before a namespace declaration is global.
 * Namespace declarations only affect the local file. Namespace
 * references allow spaces between dots when used as an operator, but
 * not when used as a string attribute - this matches flatc behavior.
 * When a namespace prefix is not specified, but the current scope is
 * searched first, then the global scope.
 *
 * There is no way to specify the global scope once a namespace has been
 * declared, other than starting a new file. It could be considered to
 * allow for "namespace ;".
 *
 * The flatc compiler does not allow a namespace prefixes in root_type,
 * but that is likely an oversight. We support it.
 *
 */
#include <stdio.h>
#include <string.h>
#include "flatcc/flatcc.h"

int main(void)
{
    const char *name = "../xyzzy.fbs";

    char input[] =
        "\t//buffers do not support include statements\n"
        "//\tinclude \"foobar.fbs\";\n"
        "// in flatc, only one field can have a key, but we have no issues\n"
        "// as long as the vector is sorted accordingly. The first key gets\n"
        "// gets a shorter find alias method.\n"
        "// (all scalar vectors can also be searched - they have find defined)\n"
        "/* block comments are also allowed.\n */\n"
        "//////////////////////////////////////////////////////////\n"
        "//////////////////////////////////////////////////////////\n"
        "table point { x : float (key); y: float; z: float (key); }\n"
        "namespace mystic;\n"
        "/************ ANOTHER DOC CASE *************/\n"
        "table island { lattitude : int; longitude : int; }\n"
        "     /// There are two different point tables\n"
        "// we test multi line doc comments here - this line should be ignored.\n"
        " /// - one in each name space.\n"
        "table point { interest: agent; blank: string; geo: mystic.island; }\n"
        "enum agent:int { lot, pirate, vessel, navy, parrot }\n"
        "\tnamespace the;\n"
        "//root_type point;\n"
        "attribute \"foo\";\n"
        "//attribute \"\"; // ensure empty strings are accepted.\n"
        "/// shade is for CG applications\n"
        "struct shade (force_align:2) { x: byte; y: byte; z: byte;\n"
        "/// alpha is unsigned!\n"
        "alpha: ubyte (key); }\n"
        "/// the.ui is a union\n"
        "///\n"
        "/// We got one blank comment line above.\n"
        "union u1 { /// Note that the.point is different from mystic.point in other namespace.\n"
        "point\n"
        "= /// meaningless doc comment that should be stripped\n"
        "2, foo = 4, mystic.island = 17, } enum e1:short { z = -2, one , two , three = 3, }\n"
        "// key on enum not supported by flatc\n"
        "table foo  { m: u1; e: e1 = z (key); x : int = mystic.agent.vessel; interest: mystic.agent = pirate; strange: mystic.agent = flags2.zulu; }\n"
        "// Unknown attributes can be repeated with varying types since behavior is unspecified.\n"
        "enum flags : short (bit_flags, \n"
        "/// foos are plentiful - here it is an enum of value 42\n"
        "foo: 42, foo, foo: \"hello\") { f1 = 1, f2 = 13, f3 }\n"
        "enum flags2 : uint (bit_flags) { zulu, alpha, bravo, charlie, delta, echo, foxtrot }\n"
        "/// A boolean enum - all enums must be type.\n"
        "enum confirm : bool { no, yes }\n"
        "// enums are not formally permitted in structs, but can be enabled.\n"
        "// This is advanced: boolean enum binary search on struct vector ...\n"
        "struct notify { primary_recipient: confirm (key); secondary_recipient: confirm; flags : flags; }\n"
        "// duplicates are disallowed by default, but can be enabled\n"
        "// enum dupes : byte { large = 2, great = 2, small = 0, other }\n"
        "table goo { hello: string (key, required); confirmations: [confirm];\n"
        "            never_mind: double = 3.1415 (deprecated);\n"
        "            embedded_t: [ubyte] (nested_flatbuffer: \"foo\");\n"
        "            embedded_s: [ubyte] (nested_flatbuffer: \"little.whale.c2\");\n"
        "            shady: shade;\n"
        "}\n"
        "struct s1 (force_align:4) { index: int (key); }\n"
        "struct c1 { a: ubyte; x1 : little.whale.c2; x2:uint; x3: short; light: shade (deprecated); }\n"
        "/// not all constructs support doc comments - this one doesn't\n"
        "namespace little.whale;\n"
        "struct c2 { y : c3; }\n"
        "//struct c3 { z : c1; }\n"
        "struct c3 { z : the.s1; }\n"
        "file_identifier \"fbuz\";\n"
        "file_extension \"cgen_test\";\n"
        "root_type little.whale.c2;\n"
        "//root_type c2;\n"
        "//root_type the.goo;\n"
        "table hop { einhorn: c3 (required); jupiter: c2; names: [string] (required); ehlist: [c3]; k2: the.goo; k2vec: [the.goo]; lunar: the.flags2 = bravo; }\n"
        "table TestOrder { x0 : byte; x1: bool = true; x2: short; x3: the.shade; x4: string; x5 : the.u1; x6 : [string]; x7: double; }\n"
        "table TestOrder2 (original_order) { x0 : byte; x1: bool = true; x1a : bool = 1; x2: short; x3: the.shade; x4: string; x5: the.u1; x6 : [string]; x7: double; }\n"
        "table StoreResponse {}\n"
        "rpc_service MonsterStorage {\n"
        "  Store(Monster):StoreResponse;\n"
        "  Retrieve(MonsterId):Monster;\n"
        "  RetrieveOne(MonsterId):Monster (deprecated);\n"
        "}\n"
        "/* \n"
        "*/table Monster {}\ntable MonsterId{ id: int; }\n"
        "/* \t/ */\n"; /* '\v' would give an error. */

    flatcc_options_t opts;
    flatcc_context_t ctx = 0;
    int ret = -1;

    flatcc_init_options(&opts);
    opts.cgen_common_reader = 1;
    opts.cgen_reader = 1;
    opts.cgen_common_builder = 1;
    opts.cgen_builder = 1;
    opts.gen_stdout = 1;

    /* The basename xyzzy is derived from path. */
    if (!(ctx = flatcc_create_context(&opts, name, 0, 0))) {
        fprintf(stderr, "unexpected: could not initialize context\n");
        return -1;
    }
    if ((ret = flatcc_parse_buffer(ctx, input, sizeof(input)))) {
        fprintf(stderr, "sorry, parse failed\n");
        goto done;
    } else {
        fprintf(stderr, "schema is valid!\n");
        fprintf(stderr, "now generating code for C ...\n\n");
        if (flatcc_generate_files(ctx)) {
            fprintf(stderr, "failed to generate output for C\n");
            goto done;
        };
        fprintf(stdout,
                "\n#if 0 /* FlatBuffers Schema Source */\n"
                "%s\n"
                "#endif /* FlatBuffers Schema Source */\n",
                input);
    }
    ret = 0;
done:
    flatcc_destroy_context(ctx);
    return ret;
}