1#ifdef NDEBUG
2#undef NDEBUG
3#endif
4
5#include "llama.h"
6
7// TODO: shold not include libllama sources
8#include "../src/llama-grammar.h"
9
10#include <cassert>
11
12static const char * type_str(llama_gretype type) {
13 switch (type) {
14 case LLAMA_GRETYPE_CHAR: return "LLAMA_GRETYPE_CHAR";
15 case LLAMA_GRETYPE_CHAR_NOT: return "LLAMA_GRETYPE_CHAR_NOT";
16 case LLAMA_GRETYPE_CHAR_ALT: return "LLAMA_GRETYPE_CHAR_ALT";
17 case LLAMA_GRETYPE_CHAR_RNG_UPPER: return "LLAMA_GRETYPE_CHAR_RNG_UPPER";
18 case LLAMA_GRETYPE_RULE_REF: return "LLAMA_GRETYPE_RULE_REF";
19 case LLAMA_GRETYPE_ALT: return "LLAMA_GRETYPE_ALT";
20 case LLAMA_GRETYPE_END: return "LLAMA_GRETYPE_END";
21 default: return "?";
22 }
23}
24
25static void verify_parsing(const char *grammar_bytes, const std::vector<std::pair<std::string, uint32_t>> expected, const std::vector<llama_grammar_element> &expected_rules) {
26 uint32_t index = 0;
27 llama_grammar_parser parsed_grammar;
28 parsed_grammar.parse(src: grammar_bytes);
29
30 std::map<uint32_t, std::string> symbol_names;
31 for (auto it = parsed_grammar.symbol_ids.begin(); it != parsed_grammar.symbol_ids.end(); ++it) {
32 symbol_names[it->second] = it->first;
33 }
34
35 auto print_all = [&]() {
36 fprintf(stderr, format: " verify_parsing(R\"\"\"(%s)\"\"\", {\n", grammar_bytes);
37 for (auto it = parsed_grammar.symbol_ids.begin(); it != parsed_grammar.symbol_ids.end(); ++it) {
38 fprintf(stderr, format: " {\"%s\", %u},\n", it->first.c_str(), it->second);
39 }
40 fprintf(stderr, format: " }, {\n");
41 for (size_t i_rule = 0; i_rule < parsed_grammar.rules.size(); i_rule++) {
42 fprintf(stderr, format: " // %s (index %zu)\n", symbol_names[i_rule].c_str(), i_rule);
43 auto & rule = parsed_grammar.rules[i_rule];
44 for (uint32_t i = 0; i < rule.size(); i++) {
45 std::string rule_str;
46 fprintf(stderr, format: " {%s, ", type_str(type: rule[i].type));
47 if (rule[i].type == LLAMA_GRETYPE_CHAR || rule[i].type == LLAMA_GRETYPE_CHAR_ALT ||
48 rule[i].type == LLAMA_GRETYPE_CHAR_NOT || rule[i].type == LLAMA_GRETYPE_CHAR_RNG_UPPER) {
49 char c = rule[i].value;
50 if (c == '\n') {
51 fprintf(stderr, format: "'\\n'");
52 } else if (c == '\t') {
53 fprintf(stderr, format: "'\\t'");
54 } else if (c == '\r') {
55 fprintf(stderr, format: "'\\r'");
56 } else if (c == '\0') {
57 fprintf(stderr, format: "'\\0'");
58 } else {
59 fprintf(stderr, format: "'%c'", c);
60 }
61 } else if (rule[i].type == LLAMA_GRETYPE_RULE_REF) {
62 fprintf(stderr, format: "/* %s */ %u", symbol_names[rule[i].value].c_str(), rule[i].value);
63 } else {
64 fprintf(stderr, format: "%u", rule[i].value);
65 }
66 fprintf(stderr, format: "},\n");
67 }
68 }
69 fprintf(stderr, format: " });\n");
70 };
71
72 if (getenv(name: "TEST_GRAMMAR_PARSER_PRINT_ALL")) {
73 print_all();
74 fprintf(stderr, format: "\n");
75 return;
76 }
77
78 fprintf(stderr, format: "Testing grammar:%s\n", grammar_bytes);
79
80 if (parsed_grammar.symbol_ids.size() != expected.size()) {
81 fprintf(stderr, format: "Code to update expectation (set TEST_GRAMMAR_PARSER_PRINT_ALL=1 to print all):\n");
82 print_all();
83 assert(parsed_grammar.symbol_ids.size() == expected.size());
84 }
85
86 for (auto it = parsed_grammar.symbol_ids.begin(); it != parsed_grammar.symbol_ids.end(); ++it)
87 {
88 std::string key = it->first;
89 uint32_t value = it->second;
90 std::pair<std::string, uint32_t> expected_pair = expected[index];
91
92 // pretty print error message before asserting
93 if (expected_pair.first != key || expected_pair.second != value)
94 {
95 fprintf(stderr, format: "index: %u\n", index);
96 fprintf(stderr, format: "expected_pair: %s, %u\n", expected_pair.first.c_str(), expected_pair.second);
97 fprintf(stderr, format: "actual_pair: %s, %u\n", key.c_str(), value);
98 fprintf(stderr, format: "expected_pair != actual_pair\n");
99 fprintf(stderr, format: "Code to update expectation (set TEST_GRAMMAR_PARSER_PRINT_ALL=1 to print all):\n");
100 print_all();
101 }
102
103 assert(expected_pair.first == key && expected_pair.second == value);
104
105 index++;
106 }
107
108 index = 0;
109 for (auto rule : parsed_grammar.rules)
110 {
111 // compare rule to expected rule
112 for (uint32_t i = 0; i < rule.size(); i++)
113 {
114 llama_grammar_element element = rule[i];
115 llama_grammar_element expected_element = expected_rules[index];
116
117 // pretty print error message before asserting
118 if (expected_element.type != element.type || expected_element.value != element.value)
119 {
120 fprintf(stderr, format: "index: %u\n", index);
121 fprintf(stderr, format: "expected_element: %s, %u\n", type_str(type: expected_element.type), expected_element.value);
122 fprintf(stderr, format: "actual_element: %s, %u\n", type_str(type: element.type), element.value);
123 fprintf(stderr, format: "expected_element != actual_element\n");
124 fprintf(stderr, format: "all elements:\n");
125 fprintf(stderr, format: "Code to update expectation (set TEST_GRAMMAR_PARSER_PRINT_ALL=1 to print all):\n");
126 print_all();
127 }
128
129 assert(expected_element.type == element.type && expected_element.value == element.value);
130 index++;
131 }
132 }
133}
134
135static void verify_failure(const char * grammar_bytes) {
136 fprintf(stderr, format: "Testing expected failure:%s\n", grammar_bytes);
137 llama_grammar_parser result;
138 result.parse(src: grammar_bytes);
139 assert(result.rules.empty() && "should have failed");
140}
141
142int main()
143{
144 verify_failure(grammar_bytes: R"""(
145 root ::= "a"{,}"
146 )""");
147
148 verify_failure(grammar_bytes: R"""(
149 root ::= "a"{,10}"
150 )""");
151
152 verify_parsing(grammar_bytes: R"""(
153 root ::= "a"
154 )""", expected: {
155 {"root", 0},
156 }, expected_rules: {
157 // root (index 0)
158 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
159 {.type: LLAMA_GRETYPE_END, .value: 0},
160 });
161
162 verify_parsing(grammar_bytes: R"""(
163 root ::= "a" | [bdx-z] | [^1-3]
164 )""", expected: {
165 {"root", 0},
166 }, expected_rules: {
167 // root (index 0)
168 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
169 {.type: LLAMA_GRETYPE_ALT, .value: 0},
170 {.type: LLAMA_GRETYPE_CHAR, .value: 'b'},
171 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: 'd'},
172 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: 'x'},
173 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: 'z'},
174 {.type: LLAMA_GRETYPE_ALT, .value: 0},
175 {.type: LLAMA_GRETYPE_CHAR_NOT, .value: '1'},
176 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: '3'},
177 {.type: LLAMA_GRETYPE_END, .value: 0},
178 });
179
180 verify_parsing(grammar_bytes: R"""(
181 root ::= a+
182 a ::= "a"
183 )""", expected: {
184 {"a", 1},
185 {"root", 0},
186 {"root_2", 2},
187 }, expected_rules: {
188 // root (index 0)
189 {.type: LLAMA_GRETYPE_RULE_REF, /* a */ .value: 1},
190 {.type: LLAMA_GRETYPE_RULE_REF, /* root_2 */ .value: 2},
191 {.type: LLAMA_GRETYPE_END, .value: 0},
192 // a (index 1)
193 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
194 {.type: LLAMA_GRETYPE_END, .value: 0},
195 // root_2 (index 2)
196 {.type: LLAMA_GRETYPE_RULE_REF, /* a */ .value: 1},
197 {.type: LLAMA_GRETYPE_RULE_REF, /* root_2 */ .value: 2},
198 {.type: LLAMA_GRETYPE_ALT, .value: 0},
199 {.type: LLAMA_GRETYPE_END, .value: 0},
200 });
201
202 verify_parsing(grammar_bytes: R"""(
203 root ::= "a"+
204 )""", expected: {
205 {"root", 0},
206 {"root_1", 1},
207 }, expected_rules: {
208 // root (index 0)
209 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
210 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
211 {.type: LLAMA_GRETYPE_END, .value: 0},
212 // root_1 (index 1)
213 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
214 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
215 {.type: LLAMA_GRETYPE_ALT, .value: 0},
216 {.type: LLAMA_GRETYPE_END, .value: 0},
217 });
218
219 verify_parsing(grammar_bytes: R"""(
220 root ::= a?
221 a ::= "a"
222 )""", expected: {
223 {"a", 1},
224 {"root", 0},
225 {"root_2", 2},
226 }, expected_rules: {
227 // root (index 0)
228 {.type: LLAMA_GRETYPE_RULE_REF, /* root_2 */ .value: 2},
229 {.type: LLAMA_GRETYPE_END, .value: 0},
230 // a (index 1)
231 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
232 {.type: LLAMA_GRETYPE_END, .value: 0},
233 // root_2 (index 2)
234 {.type: LLAMA_GRETYPE_RULE_REF, /* a */ .value: 1},
235 {.type: LLAMA_GRETYPE_ALT, .value: 0},
236 {.type: LLAMA_GRETYPE_END, .value: 0},
237 });
238
239 verify_parsing(grammar_bytes: R"""(
240 root ::= "a"?
241 )""", expected: {
242 {"root", 0},
243 {"root_1", 1},
244 }, expected_rules: {
245 // root (index 0)
246 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
247 {.type: LLAMA_GRETYPE_END, .value: 0},
248 // root_1 (index 1)
249 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
250 {.type: LLAMA_GRETYPE_ALT, .value: 0},
251 {.type: LLAMA_GRETYPE_END, .value: 0},
252 });
253
254 verify_parsing(grammar_bytes: R"""(
255 root ::= a*
256 a ::= "a"
257 )""", expected: {
258 {"a", 1},
259 {"root", 0},
260 {"root_2", 2},
261 }, expected_rules: {
262 // root (index 0)
263 {.type: LLAMA_GRETYPE_RULE_REF, /* root_2 */ .value: 2},
264 {.type: LLAMA_GRETYPE_END, .value: 0},
265 // a (index 1)
266 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
267 {.type: LLAMA_GRETYPE_END, .value: 0},
268 // root_2 (index 2)
269 {.type: LLAMA_GRETYPE_RULE_REF, /* a */ .value: 1},
270 {.type: LLAMA_GRETYPE_RULE_REF, /* root_2 */ .value: 2},
271 {.type: LLAMA_GRETYPE_ALT, .value: 0},
272 {.type: LLAMA_GRETYPE_END, .value: 0},
273 });
274
275 verify_parsing(grammar_bytes: R"""(
276 root ::= "a"*
277 )""", expected: {
278 {"root", 0},
279 {"root_1", 1},
280 }, expected_rules: {
281 // root (index 0)
282 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
283 {.type: LLAMA_GRETYPE_END, .value: 0},
284 // root_1 (index 1)
285 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
286 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
287 {.type: LLAMA_GRETYPE_ALT, .value: 0},
288 {.type: LLAMA_GRETYPE_END, .value: 0},
289 });
290
291 verify_parsing(grammar_bytes: R"""(
292 root ::= "a"{2}
293 )""", expected: {
294 {"root", 0},
295 }, expected_rules: {
296 // root (index 0)
297 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
298 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
299 {.type: LLAMA_GRETYPE_END, .value: 0},
300 });
301
302 verify_parsing(grammar_bytes: R"""(
303 root ::= "a"{2,}
304 )""", expected: {
305 {"root", 0},
306 {"root_1", 1},
307 }, expected_rules: {
308 // root (index 0)
309 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
310 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
311 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
312 {.type: LLAMA_GRETYPE_END, .value: 0},
313 // root_1 (index 1)
314 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
315 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
316 {.type: LLAMA_GRETYPE_ALT, .value: 0},
317 {.type: LLAMA_GRETYPE_END, .value: 0},
318 });
319
320 verify_parsing(grammar_bytes: R"""(
321 root ::= "a"{ 4}
322 )""", expected: {
323 {"root", 0},
324 }, expected_rules: {
325 // root (index 0)
326 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
327 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
328 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
329 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
330 {.type: LLAMA_GRETYPE_END, .value: 0},
331 });
332
333 verify_parsing(grammar_bytes: R"""(
334 root ::= "a"{2,4}
335 )""", expected: {
336 {"root", 0},
337 {"root_1", 1},
338 {"root_2", 2},
339 }, expected_rules: {
340 // root (index 0)
341 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
342 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
343 {.type: LLAMA_GRETYPE_RULE_REF, /* root_2 */ .value: 2},
344 {.type: LLAMA_GRETYPE_END, .value: 0},
345 // root_1 (index 1)
346 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
347 {.type: LLAMA_GRETYPE_ALT, .value: 0},
348 {.type: LLAMA_GRETYPE_END, .value: 0},
349 // root_2 (index 2)
350 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
351 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
352 {.type: LLAMA_GRETYPE_ALT, .value: 0},
353 {.type: LLAMA_GRETYPE_END, .value: 0},
354 });
355
356 verify_parsing(grammar_bytes: R"""(
357 root ::= (expr "=" term "\n")+
358 expr ::= term ([-+*/] term)*
359 term ::= [0-9]+
360 )""", expected: {
361 {"expr", 2},
362 {"expr_5", 5},
363 {"expr_6", 6},
364 {"root", 0},
365 {"root_1", 1},
366 {"root_4", 4},
367 {"term", 3},
368 {"term_7", 7},
369 }, expected_rules: {
370 // root (index 0)
371 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
372 {.type: LLAMA_GRETYPE_RULE_REF, /* root_4 */ .value: 4},
373 {.type: LLAMA_GRETYPE_END, .value: 0},
374 // root_1 (index 1)
375 {.type: LLAMA_GRETYPE_RULE_REF, /* expr */ .value: 2},
376 {.type: LLAMA_GRETYPE_CHAR, .value: '='},
377 {.type: LLAMA_GRETYPE_RULE_REF, /* term */ .value: 3},
378 {.type: LLAMA_GRETYPE_CHAR, .value: '\n'},
379 {.type: LLAMA_GRETYPE_END, .value: 0},
380 // expr (index 2)
381 {.type: LLAMA_GRETYPE_RULE_REF, /* term */ .value: 3},
382 {.type: LLAMA_GRETYPE_RULE_REF, /* expr_6 */ .value: 6},
383 {.type: LLAMA_GRETYPE_END, .value: 0},
384 // term (index 3)
385 {.type: LLAMA_GRETYPE_CHAR, .value: '0'},
386 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: '9'},
387 {.type: LLAMA_GRETYPE_RULE_REF, /* term_7 */ .value: 7},
388 {.type: LLAMA_GRETYPE_END, .value: 0},
389 // root_4 (index 4)
390 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
391 {.type: LLAMA_GRETYPE_RULE_REF, /* root_4 */ .value: 4},
392 {.type: LLAMA_GRETYPE_ALT, .value: 0},
393 {.type: LLAMA_GRETYPE_END, .value: 0},
394 // expr_5 (index 5)
395 {.type: LLAMA_GRETYPE_CHAR, .value: '-'},
396 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '+'},
397 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '*'},
398 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '/'},
399 {.type: LLAMA_GRETYPE_RULE_REF, /* term */ .value: 3},
400 {.type: LLAMA_GRETYPE_END, .value: 0},
401 // expr_6 (index 6)
402 {.type: LLAMA_GRETYPE_RULE_REF, /* expr_5 */ .value: 5},
403 {.type: LLAMA_GRETYPE_RULE_REF, /* expr_6 */ .value: 6},
404 {.type: LLAMA_GRETYPE_ALT, .value: 0},
405 {.type: LLAMA_GRETYPE_END, .value: 0},
406 // term_7 (index 7)
407 {.type: LLAMA_GRETYPE_CHAR, .value: '0'},
408 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: '9'},
409 {.type: LLAMA_GRETYPE_RULE_REF, /* term_7 */ .value: 7},
410 {.type: LLAMA_GRETYPE_ALT, .value: 0},
411 {.type: LLAMA_GRETYPE_END, .value: 0},
412 });
413
414 verify_parsing(grammar_bytes: R"""(
415 root ::= (expr "=" ws term "\n")+
416 expr ::= term ([-+*/] term)*
417 term ::= ident | num | "(" ws expr ")" ws
418 ident ::= [a-z] [a-z0-9_]* ws
419 num ::= [0-9]+ ws
420 ws ::= [ \t\n]*
421 )""", expected: {
422 {"expr", 2},
423 {"expr_6", 6},
424 {"expr_7", 7},
425 {"ident", 8},
426 {"ident_10", 10},
427 {"num", 9},
428 {"num_11", 11},
429 {"root", 0},
430 {"root_1", 1},
431 {"root_5", 5},
432 {"term", 4},
433 {"ws", 3},
434 {"ws_12", 12},
435 }, expected_rules: {
436 // root (index 0)
437 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
438 {.type: LLAMA_GRETYPE_RULE_REF, /* root_5 */ .value: 5},
439 {.type: LLAMA_GRETYPE_END, .value: 0},
440 // root_1 (index 1)
441 {.type: LLAMA_GRETYPE_RULE_REF, /* expr */ .value: 2},
442 {.type: LLAMA_GRETYPE_CHAR, .value: '='},
443 {.type: LLAMA_GRETYPE_RULE_REF, /* ws */ .value: 3},
444 {.type: LLAMA_GRETYPE_RULE_REF, /* term */ .value: 4},
445 {.type: LLAMA_GRETYPE_CHAR, .value: '\n'},
446 {.type: LLAMA_GRETYPE_END, .value: 0},
447 // expr (index 2)
448 {.type: LLAMA_GRETYPE_RULE_REF, /* term */ .value: 4},
449 {.type: LLAMA_GRETYPE_RULE_REF, /* expr_7 */ .value: 7},
450 {.type: LLAMA_GRETYPE_END, .value: 0},
451 // ws (index 3)
452 {.type: LLAMA_GRETYPE_RULE_REF, /* ws_12 */ .value: 12},
453 {.type: LLAMA_GRETYPE_END, .value: 0},
454 // term (index 4)
455 {.type: LLAMA_GRETYPE_RULE_REF, /* ident */ .value: 8},
456 {.type: LLAMA_GRETYPE_ALT, .value: 0},
457 {.type: LLAMA_GRETYPE_RULE_REF, /* num */ .value: 9},
458 {.type: LLAMA_GRETYPE_ALT, .value: 0},
459 {.type: LLAMA_GRETYPE_CHAR, .value: '('},
460 {.type: LLAMA_GRETYPE_RULE_REF, /* ws */ .value: 3},
461 {.type: LLAMA_GRETYPE_RULE_REF, /* expr */ .value: 2},
462 {.type: LLAMA_GRETYPE_CHAR, .value: ')'},
463 {.type: LLAMA_GRETYPE_RULE_REF, /* ws */ .value: 3},
464 {.type: LLAMA_GRETYPE_END, .value: 0},
465 // root_5 (index 5)
466 {.type: LLAMA_GRETYPE_RULE_REF, /* root_1 */ .value: 1},
467 {.type: LLAMA_GRETYPE_RULE_REF, /* root_5 */ .value: 5},
468 {.type: LLAMA_GRETYPE_ALT, .value: 0},
469 {.type: LLAMA_GRETYPE_END, .value: 0},
470 // expr_6 (index 6)
471 {.type: LLAMA_GRETYPE_CHAR, .value: '-'},
472 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '+'},
473 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '*'},
474 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '/'},
475 {.type: LLAMA_GRETYPE_RULE_REF, /* term */ .value: 4},
476 {.type: LLAMA_GRETYPE_END, .value: 0},
477 // expr_7 (index 7)
478 {.type: LLAMA_GRETYPE_RULE_REF, /* expr_6 */ .value: 6},
479 {.type: LLAMA_GRETYPE_RULE_REF, /* expr_7 */ .value: 7},
480 {.type: LLAMA_GRETYPE_ALT, .value: 0},
481 {.type: LLAMA_GRETYPE_END, .value: 0},
482 // ident (index 8)
483 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
484 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: 'z'},
485 {.type: LLAMA_GRETYPE_RULE_REF, /* ident_10 */ .value: 10},
486 {.type: LLAMA_GRETYPE_RULE_REF, /* ws */ .value: 3},
487 {.type: LLAMA_GRETYPE_END, .value: 0},
488 // num (index 9)
489 {.type: LLAMA_GRETYPE_CHAR, .value: '0'},
490 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: '9'},
491 {.type: LLAMA_GRETYPE_RULE_REF, /* num_11 */ .value: 11},
492 {.type: LLAMA_GRETYPE_RULE_REF, /* ws */ .value: 3},
493 {.type: LLAMA_GRETYPE_END, .value: 0},
494 // ident_10 (index 10)
495 {.type: LLAMA_GRETYPE_CHAR, .value: 'a'},
496 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: 'z'},
497 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '0'},
498 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: '9'},
499 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '_'},
500 {.type: LLAMA_GRETYPE_RULE_REF, /* ident_10 */ .value: 10},
501 {.type: LLAMA_GRETYPE_ALT, .value: 0},
502 {.type: LLAMA_GRETYPE_END, .value: 0},
503 // num_11 (index 11)
504 {.type: LLAMA_GRETYPE_CHAR, .value: '0'},
505 {.type: LLAMA_GRETYPE_CHAR_RNG_UPPER, .value: '9'},
506 {.type: LLAMA_GRETYPE_RULE_REF, /* num_11 */ .value: 11},
507 {.type: LLAMA_GRETYPE_ALT, .value: 0},
508 {.type: LLAMA_GRETYPE_END, .value: 0},
509 // ws_12 (index 12)
510 {.type: LLAMA_GRETYPE_CHAR, .value: ' '},
511 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '\t'},
512 {.type: LLAMA_GRETYPE_CHAR_ALT, .value: '\n'},
513 {.type: LLAMA_GRETYPE_RULE_REF, /* ws_12 */ .value: 12},
514 {.type: LLAMA_GRETYPE_ALT, .value: 0},
515 {.type: LLAMA_GRETYPE_END, .value: 0},
516 });
517
518 return 0;
519}
520