blob: bf5408e3a8f434c2b69cbfe3f0e458f14c6b6836 [file] [log] [blame]
Gavin McDonald0b75e1a2010-10-28 02:12:01 +00001%{
2/*
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 */
20
21/**
22 * Thrift parser.
23 *
24 * This parser is used on a thrift definition file.
25 *
26 */
27
28#define __STDC_LIMIT_MACROS
29#define __STDC_FORMAT_MACROS
30#include <stdio.h>
31#include <inttypes.h>
32#include <limits.h>
33#include "main.h"
34#include "globals.h"
35#include "parse/t_program.h"
36#include "parse/t_scope.h"
37
38/**
39 * This global variable is used for automatic numbering of field indices etc.
40 * when parsing the members of a struct. Field values are automatically
41 * assigned starting from -1 and working their way down.
42 */
43int y_field_val = -1;
44int g_arglist = 0;
45
46%}
47
48/**
49 * This structure is used by the parser to hold the data types associated with
50 * various parse nodes.
51 */
52%union {
53 char* id;
54 int64_t iconst;
55 double dconst;
56 bool tbool;
57 t_doc* tdoc;
58 t_type* ttype;
59 t_base_type* tbase;
60 t_typedef* ttypedef;
61 t_enum* tenum;
62 t_enum_value* tenumv;
63 t_const* tconst;
64 t_const_value* tconstv;
65 t_struct* tstruct;
66 t_service* tservice;
67 t_function* tfunction;
68 t_field* tfield;
69 char* dtext;
70 t_field::e_req ereq;
71 t_annotation* tannot;
72}
73
74/**
75 * Strings identifier
76 */
77%token<id> tok_identifier
78%token<id> tok_literal
79%token<dtext> tok_doctext
80%token<id> tok_st_identifier
81
82/**
83 * Constant values
84 */
85%token<iconst> tok_int_constant
86%token<dconst> tok_dub_constant
87
88/**
89 * Header keywords
90 */
91%token tok_include
92%token tok_namespace
93%token tok_cpp_namespace
94%token tok_cpp_include
95%token tok_cpp_type
96%token tok_php_namespace
97%token tok_py_module
98%token tok_perl_package
99%token tok_java_package
100%token tok_xsd_all
101%token tok_xsd_optional
102%token tok_xsd_nillable
103%token tok_xsd_namespace
104%token tok_xsd_attrs
105%token tok_ruby_namespace
106%token tok_smalltalk_category
107%token tok_smalltalk_prefix
108%token tok_cocoa_prefix
109%token tok_csharp_namespace
110
111/**
112 * Base datatype keywords
113 */
114%token tok_void
115%token tok_bool
116%token tok_byte
117%token tok_string
118%token tok_binary
119%token tok_slist
120%token tok_senum
121%token tok_i16
122%token tok_i32
123%token tok_i64
124%token tok_double
125
126/**
127 * Complex type keywords
128 */
129%token tok_map
130%token tok_list
131%token tok_set
132
133/**
134 * Function modifiers
135 */
136%token tok_oneway
137
138/**
139 * Thrift language keywords
140 */
141%token tok_typedef
142%token tok_struct
143%token tok_xception
144%token tok_throws
145%token tok_extends
146%token tok_service
147%token tok_enum
148%token tok_const
149%token tok_required
150%token tok_optional
151
152/**
153 * Grammar nodes
154 */
155
156%type<ttype> BaseType
157%type<ttype> ContainerType
158%type<ttype> SimpleContainerType
159%type<ttype> MapType
160%type<ttype> SetType
161%type<ttype> ListType
162
163%type<tdoc> Definition
164%type<ttype> TypeDefinition
165
166%type<ttypedef> Typedef
167%type<ttype> DefinitionType
168
169%type<ttype> TypeAnnotations
170%type<ttype> TypeAnnotationList
171%type<tannot> TypeAnnotation
172
173%type<tfield> Field
174%type<iconst> FieldIdentifier
175%type<ereq> FieldRequiredness
176%type<ttype> FieldType
177%type<tconstv> FieldValue
178%type<tstruct> FieldList
179
180%type<tenum> Enum
181%type<tenum> EnumDefList
182%type<tenumv> EnumDef
183
184%type<ttypedef> Senum
185%type<tbase> SenumDefList
186%type<id> SenumDef
187
188%type<tconst> Const
189%type<tconstv> ConstValue
190%type<tconstv> ConstList
191%type<tconstv> ConstListContents
192%type<tconstv> ConstMap
193%type<tconstv> ConstMapContents
194
195%type<tstruct> Struct
196%type<tstruct> Xception
197%type<tservice> Service
198
199%type<tfunction> Function
200%type<ttype> FunctionType
201%type<tservice> FunctionList
202
203%type<tstruct> Throws
204%type<tservice> Extends
205%type<tbool> Oneway
206%type<tbool> XsdAll
207%type<tbool> XsdOptional
208%type<tbool> XsdNillable
209%type<tstruct> XsdAttributes
210%type<id> CppType
211
212%type<dtext> CaptureDocText
213
214%%
215
216/**
217 * Thrift Grammar Implementation.
218 *
219 * For the most part this source file works its way top down from what you
220 * might expect to find in a typical .thrift file, i.e. type definitions and
221 * namespaces up top followed by service definitions using those types.
222 */
223
224Program:
225 HeaderList DefinitionList
226 {
227 pdebug("Program -> Headers DefinitionList");
228 /*
229 TODO(dreiss): Decide whether full-program doctext is worth the trouble.
230 if ($1 != NULL) {
231 g_program->set_doc($1);
232 }
233 */
234 clear_doctext();
235 }
236
237CaptureDocText:
238 {
239 if (g_parse_mode == PROGRAM) {
240 $$ = g_doctext;
241 g_doctext = NULL;
242 } else {
243 $$ = NULL;
244 }
245 }
246
247/* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */
248DestroyDocText:
249 {
250 if (g_parse_mode == PROGRAM) {
251 clear_doctext();
252 }
253 }
254
255/* We have to DestroyDocText here, otherwise it catches the doctext
256 on the first real element. */
257HeaderList:
258 HeaderList DestroyDocText Header
259 {
260 pdebug("HeaderList -> HeaderList Header");
261 }
262|
263 {
264 pdebug("HeaderList -> ");
265 }
266
267Header:
268 Include
269 {
270 pdebug("Header -> Include");
271 }
272| tok_namespace tok_identifier tok_identifier
273 {
274 pdebug("Header -> tok_namespace tok_identifier tok_identifier");
275 if (g_parse_mode == PROGRAM) {
276 g_program->set_namespace($2, $3);
277 }
278 }
279/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
280| tok_cpp_namespace tok_identifier
281 {
282 pwarning(1, "'cpp_namespace' is deprecated. Use 'namespace cpp' instead");
283 pdebug("Header -> tok_cpp_namespace tok_identifier");
284 if (g_parse_mode == PROGRAM) {
285 g_program->set_namespace("cpp", $2);
286 }
287 }
288| tok_cpp_include tok_literal
289 {
290 pdebug("Header -> tok_cpp_include tok_literal");
291 if (g_parse_mode == PROGRAM) {
292 g_program->add_cpp_include($2);
293 }
294 }
295| tok_php_namespace tok_identifier
296 {
297 pwarning(1, "'php_namespace' is deprecated. Use 'namespace php' instead");
298 pdebug("Header -> tok_php_namespace tok_identifier");
299 if (g_parse_mode == PROGRAM) {
300 g_program->set_namespace("php", $2);
301 }
302 }
303/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
304| tok_py_module tok_identifier
305 {
306 pwarning(1, "'py_module' is deprecated. Use 'namespace py' instead");
307 pdebug("Header -> tok_py_module tok_identifier");
308 if (g_parse_mode == PROGRAM) {
309 g_program->set_namespace("py", $2);
310 }
311 }
312/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
313| tok_perl_package tok_identifier
314 {
315 pwarning(1, "'perl_package' is deprecated. Use 'namespace perl' instead");
316 pdebug("Header -> tok_perl_namespace tok_identifier");
317 if (g_parse_mode == PROGRAM) {
318 g_program->set_namespace("perl", $2);
319 }
320 }
321/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
322| tok_ruby_namespace tok_identifier
323 {
324 pwarning(1, "'ruby_namespace' is deprecated. Use 'namespace rb' instead");
325 pdebug("Header -> tok_ruby_namespace tok_identifier");
326 if (g_parse_mode == PROGRAM) {
327 g_program->set_namespace("rb", $2);
328 }
329 }
330/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
331| tok_smalltalk_category tok_st_identifier
332 {
333 pwarning(1, "'smalltalk_category' is deprecated. Use 'namespace smalltalk.category' instead");
334 pdebug("Header -> tok_smalltalk_category tok_st_identifier");
335 if (g_parse_mode == PROGRAM) {
336 g_program->set_namespace("smalltalk.category", $2);
337 }
338 }
339/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
340| tok_smalltalk_prefix tok_identifier
341 {
342 pwarning(1, "'smalltalk_prefix' is deprecated. Use 'namespace smalltalk.prefix' instead");
343 pdebug("Header -> tok_smalltalk_prefix tok_identifier");
344 if (g_parse_mode == PROGRAM) {
345 g_program->set_namespace("smalltalk.prefix", $2);
346 }
347 }
348/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
349| tok_java_package tok_identifier
350 {
351 pwarning(1, "'java_package' is deprecated. Use 'namespace java' instead");
352 pdebug("Header -> tok_java_package tok_identifier");
353 if (g_parse_mode == PROGRAM) {
354 g_program->set_namespace("java", $2);
355 }
356 }
357/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
358| tok_cocoa_prefix tok_identifier
359 {
360 pwarning(1, "'cocoa_prefix' is deprecated. Use 'namespace cocoa' instead");
361 pdebug("Header -> tok_cocoa_prefix tok_identifier");
362 if (g_parse_mode == PROGRAM) {
363 g_program->set_namespace("cocoa", $2);
364 }
365 }
366/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
367| tok_xsd_namespace tok_literal
368 {
369 pwarning(1, "'xsd_namespace' is deprecated. Use 'namespace xsd' instead");
370 pdebug("Header -> tok_xsd_namespace tok_literal");
371 if (g_parse_mode == PROGRAM) {
372 g_program->set_namespace("cocoa", $2);
373 }
374 }
375/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
376| tok_csharp_namespace tok_identifier
377 {
378 pwarning(1, "'csharp_namespace' is deprecated. Use 'namespace csharp' instead");
379 pdebug("Header -> tok_csharp_namespace tok_identifier");
380 if (g_parse_mode == PROGRAM) {
381 g_program->set_namespace("csharp", $2);
382 }
383 }
384
385Include:
386 tok_include tok_literal
387 {
388 pdebug("Include -> tok_include tok_literal");
389 if (g_parse_mode == INCLUDES) {
390 std::string path = include_file(std::string($2));
391 if (!path.empty()) {
392 g_program->add_include(path, std::string($2));
393 }
394 }
395 }
396
397DefinitionList:
398 DefinitionList CaptureDocText Definition
399 {
400 pdebug("DefinitionList -> DefinitionList Definition");
401 if ($2 != NULL && $3 != NULL) {
402 $3->set_doc($2);
403 }
404 }
405|
406 {
407 pdebug("DefinitionList -> ");
408 }
409
410Definition:
411 Const
412 {
413 pdebug("Definition -> Const");
414 if (g_parse_mode == PROGRAM) {
415 g_program->add_const($1);
416 }
417 $$ = $1;
418 }
419| TypeDefinition
420 {
421 pdebug("Definition -> TypeDefinition");
422 if (g_parse_mode == PROGRAM) {
423 g_scope->add_type($1->get_name(), $1);
424 if (g_parent_scope != NULL) {
425 g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1);
426 }
427 }
428 $$ = $1;
429 }
430| Service
431 {
432 pdebug("Definition -> Service");
433 if (g_parse_mode == PROGRAM) {
434 g_scope->add_service($1->get_name(), $1);
435 if (g_parent_scope != NULL) {
436 g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1);
437 }
438 g_program->add_service($1);
439 }
440 $$ = $1;
441 }
442
443TypeDefinition:
444 Typedef
445 {
446 pdebug("TypeDefinition -> Typedef");
447 if (g_parse_mode == PROGRAM) {
448 g_program->add_typedef($1);
449 }
450 }
451| Enum
452 {
453 pdebug("TypeDefinition -> Enum");
454 if (g_parse_mode == PROGRAM) {
455 g_program->add_enum($1);
456 }
457 }
458| Senum
459 {
460 pdebug("TypeDefinition -> Senum");
461 if (g_parse_mode == PROGRAM) {
462 g_program->add_typedef($1);
463 }
464 }
465| Struct
466 {
467 pdebug("TypeDefinition -> Struct");
468 if (g_parse_mode == PROGRAM) {
469 g_program->add_struct($1);
470 }
471 }
472| Xception
473 {
474 pdebug("TypeDefinition -> Xception");
475 if (g_parse_mode == PROGRAM) {
476 g_program->add_xception($1);
477 }
478 }
479
480Typedef:
481 tok_typedef DefinitionType tok_identifier
482 {
483 pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");
484 t_typedef *td = new t_typedef(g_program, $2, $3);
485 $$ = td;
486 }
487
488CommaOrSemicolonOptional:
489 ','
490 {}
491| ';'
492 {}
493|
494 {}
495
496Enum:
497 tok_enum tok_identifier '{' EnumDefList '}'
498 {
499 pdebug("Enum -> tok_enum tok_identifier { EnumDefList }");
500 $$ = $4;
501 $$->set_name($2);
502 }
503
504EnumDefList:
505 EnumDefList EnumDef
506 {
507 pdebug("EnumDefList -> EnumDefList EnumDef");
508 $$ = $1;
509 $$->append($2);
510 }
511|
512 {
513 pdebug("EnumDefList -> ");
514 $$ = new t_enum(g_program);
515 }
516
517EnumDef:
518 CaptureDocText tok_identifier '=' tok_int_constant CommaOrSemicolonOptional
519 {
520 pdebug("EnumDef -> tok_identifier = tok_int_constant");
521 if ($4 < 0) {
522 pwarning(1, "Negative value supplied for enum %s.\n", $2);
523 }
524 if ($4 > INT_MAX) {
525 pwarning(1, "64-bit value supplied for enum %s.\n", $2);
526 }
527 $$ = new t_enum_value($2, $4);
528 if ($1 != NULL) {
529 $$->set_doc($1);
530 }
531 if (g_parse_mode == PROGRAM) {
532 g_scope->add_constant($2, new t_const(g_type_i32, $2, new t_const_value($4)));
533 if (g_parent_scope != NULL) {
534 g_parent_scope->add_constant(g_parent_prefix + $2, new t_const(g_type_i32, $2, new t_const_value($4)));
535 }
536 }
537 }
538|
539 CaptureDocText tok_identifier CommaOrSemicolonOptional
540 {
541 pdebug("EnumDef -> tok_identifier");
542 $$ = new t_enum_value($2);
543 if ($1 != NULL) {
544 $$->set_doc($1);
545 }
546 }
547
548Senum:
549 tok_senum tok_identifier '{' SenumDefList '}'
550 {
551 pdebug("Senum -> tok_senum tok_identifier { SenumDefList }");
552 $$ = new t_typedef(g_program, $4, $2);
553 }
554
555SenumDefList:
556 SenumDefList SenumDef
557 {
558 pdebug("SenumDefList -> SenumDefList SenumDef");
559 $$ = $1;
560 $$->add_string_enum_val($2);
561 }
562|
563 {
564 pdebug("SenumDefList -> ");
565 $$ = new t_base_type("string", t_base_type::TYPE_STRING);
566 $$->set_string_enum(true);
567 }
568
569SenumDef:
570 tok_literal CommaOrSemicolonOptional
571 {
572 pdebug("SenumDef -> tok_literal");
573 $$ = $1;
574 }
575
576Const:
577 tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional
578 {
579 pdebug("Const -> tok_const FieldType tok_identifier = ConstValue");
580 if (g_parse_mode == PROGRAM) {
581 $$ = new t_const($2, $3, $5);
582 validate_const_type($$);
583
584 g_scope->add_constant($3, $$);
585 if (g_parent_scope != NULL) {
586 g_parent_scope->add_constant(g_parent_prefix + $3, $$);
587 }
588
589 } else {
590 $$ = NULL;
591 }
592 }
593
594ConstValue:
595 tok_int_constant
596 {
597 pdebug("ConstValue => tok_int_constant");
598 $$ = new t_const_value();
599 $$->set_integer($1);
600 if ($1 < INT32_MIN || $1 > INT32_MAX) {
601 pwarning(1, "64-bit constant \"%"PRIi64"\" may not work in all languages.\n", $1);
602 }
603 }
604| tok_dub_constant
605 {
606 pdebug("ConstValue => tok_dub_constant");
607 $$ = new t_const_value();
608 $$->set_double($1);
609 }
610| tok_literal
611 {
612 pdebug("ConstValue => tok_literal");
613 $$ = new t_const_value($1);
614 }
615| tok_identifier
616 {
617 pdebug("ConstValue => tok_identifier");
618 t_const* constant = g_scope->get_constant($1);
619 if (constant != NULL) {
620 $$ = constant->get_value();
621 } else {
622 if (g_parse_mode == PROGRAM) {
623 pwarning(1, "Constant strings should be quoted: %s\n", $1);
624 }
625 $$ = new t_const_value($1);
626 }
627 }
628| ConstList
629 {
630 pdebug("ConstValue => ConstList");
631 $$ = $1;
632 }
633| ConstMap
634 {
635 pdebug("ConstValue => ConstMap");
636 $$ = $1;
637 }
638
639ConstList:
640 '[' ConstListContents ']'
641 {
642 pdebug("ConstList => [ ConstListContents ]");
643 $$ = $2;
644 }
645
646ConstListContents:
647 ConstListContents ConstValue CommaOrSemicolonOptional
648 {
649 pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional");
650 $$ = $1;
651 $$->add_list($2);
652 }
653|
654 {
655 pdebug("ConstListContents =>");
656 $$ = new t_const_value();
657 $$->set_list();
658 }
659
660ConstMap:
661 '{' ConstMapContents '}'
662 {
663 pdebug("ConstMap => { ConstMapContents }");
664 $$ = $2;
665 }
666
667ConstMapContents:
668 ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional
669 {
670 pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional");
671 $$ = $1;
672 $$->add_map($2, $4);
673 }
674|
675 {
676 pdebug("ConstMapContents =>");
677 $$ = new t_const_value();
678 $$->set_map();
679 }
680
681Struct:
682 tok_struct tok_identifier XsdAll '{' FieldList '}' TypeAnnotations
683 {
684 pdebug("Struct -> tok_struct tok_identifier { FieldList }");
685 $5->set_xsd_all($3);
686 $$ = $5;
687 $$->set_name($2);
688 if ($7 != NULL) {
689 $$->annotations_ = $7->annotations_;
690 delete $7;
691 }
692 }
693
694XsdAll:
695 tok_xsd_all
696 {
697 $$ = true;
698 }
699|
700 {
701 $$ = false;
702 }
703
704XsdOptional:
705 tok_xsd_optional
706 {
707 $$ = true;
708 }
709|
710 {
711 $$ = false;
712 }
713
714XsdNillable:
715 tok_xsd_nillable
716 {
717 $$ = true;
718 }
719|
720 {
721 $$ = false;
722 }
723
724XsdAttributes:
725 tok_xsd_attrs '{' FieldList '}'
726 {
727 $$ = $3;
728 }
729|
730 {
731 $$ = NULL;
732 }
733
734Xception:
735 tok_xception tok_identifier '{' FieldList '}'
736 {
737 pdebug("Xception -> tok_xception tok_identifier { FieldList }");
738 $4->set_name($2);
739 $4->set_xception(true);
740 $$ = $4;
741 }
742
743Service:
744 tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}'
745 {
746 pdebug("Service -> tok_service tok_identifier { FunctionList }");
747 $$ = $6;
748 $$->set_name($2);
749 $$->set_extends($3);
750 }
751
752FlagArgs:
753 {
754 g_arglist = 1;
755 }
756
757UnflagArgs:
758 {
759 g_arglist = 0;
760 }
761
762Extends:
763 tok_extends tok_identifier
764 {
765 pdebug("Extends -> tok_extends tok_identifier");
766 $$ = NULL;
767 if (g_parse_mode == PROGRAM) {
768 $$ = g_scope->get_service($2);
769 if ($$ == NULL) {
770 yyerror("Service \"%s\" has not been defined.", $2);
771 exit(1);
772 }
773 }
774 }
775|
776 {
777 $$ = NULL;
778 }
779
780FunctionList:
781 FunctionList Function
782 {
783 pdebug("FunctionList -> FunctionList Function");
784 $$ = $1;
785 $1->add_function($2);
786 }
787|
788 {
789 pdebug("FunctionList -> ");
790 $$ = new t_service(g_program);
791 }
792
793Function:
794 CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws CommaOrSemicolonOptional
795 {
796 $6->set_name(std::string($4) + "_args");
797 $$ = new t_function($3, $4, $6, $8, $2);
798 if ($1 != NULL) {
799 $$->set_doc($1);
800 }
801 }
802
803Oneway:
804 tok_oneway
805 {
806 $$ = true;
807 }
808|
809 {
810 $$ = false;
811 }
812
813Throws:
814 tok_throws '(' FieldList ')'
815 {
816 pdebug("Throws -> tok_throws ( FieldList )");
817 $$ = $3;
818 if (g_parse_mode == PROGRAM && !validate_throws($$)) {
819 yyerror("Throws clause may not contain non-exception types");
820 exit(1);
821 }
822 }
823|
824 {
825 $$ = new t_struct(g_program);
826 }
827
828FieldList:
829 FieldList Field
830 {
831 pdebug("FieldList -> FieldList , Field");
832 $$ = $1;
833 if (!($$->append($2))) {
834 yyerror("Field identifier %d for \"%s\" has already been used", $2->get_key(), $2->get_name().c_str());
835 exit(1);
836 }
837 }
838|
839 {
840 pdebug("FieldList -> ");
841 y_field_val = -1;
842 $$ = new t_struct(g_program);
843 }
844
845Field:
846 CaptureDocText FieldIdentifier FieldRequiredness FieldType tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes CommaOrSemicolonOptional
847 {
848 pdebug("tok_int_constant : Field -> FieldType tok_identifier");
849 if ($2 < 0) {
850 pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $5);
851 if (g_strict >= 192) {
852 yyerror("Implicit field keys are deprecated and not allowed with -strict");
853 exit(1);
854 }
855 }
856 $$ = new t_field($4, $5, $2);
857 $$->set_req($3);
858 if ($6 != NULL) {
859 validate_field_value($$, $6);
860 $$->set_value($6);
861 }
862 $$->set_xsd_optional($7);
863 $$->set_xsd_nillable($8);
864 if ($1 != NULL) {
865 $$->set_doc($1);
866 }
867 if ($9 != NULL) {
868 $$->set_xsd_attrs($9);
869 }
870 }
871
872FieldIdentifier:
873 tok_int_constant ':'
874 {
875 if ($1 <= 0) {
876 pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", $1);
877 $1 = y_field_val--;
878 }
879 $$ = $1;
880 }
881|
882 {
883 $$ = y_field_val--;
884 }
885
886FieldRequiredness:
887 tok_required
888 {
889 if (g_arglist) {
890 if (g_parse_mode == PROGRAM) {
891 pwarning(1, "required keyword is ignored in argument lists.\n");
892 }
893 $$ = t_field::T_OPT_IN_REQ_OUT;
894 } else {
895 $$ = t_field::T_REQUIRED;
896 }
897 }
898| tok_optional
899 {
900 if (g_arglist) {
901 if (g_parse_mode == PROGRAM) {
902 pwarning(1, "optional keyword is ignored in argument lists.\n");
903 }
904 $$ = t_field::T_OPT_IN_REQ_OUT;
905 } else {
906 $$ = t_field::T_OPTIONAL;
907 }
908 }
909|
910 {
911 $$ = t_field::T_OPT_IN_REQ_OUT;
912 }
913
914FieldValue:
915 '=' ConstValue
916 {
917 if (g_parse_mode == PROGRAM) {
918 $$ = $2;
919 } else {
920 $$ = NULL;
921 }
922 }
923|
924 {
925 $$ = NULL;
926 }
927
928DefinitionType:
929 BaseType
930 {
931 pdebug("DefinitionType -> BaseType");
932 $$ = $1;
933 }
934| ContainerType
935 {
936 pdebug("DefinitionType -> ContainerType");
937 $$ = $1;
938 }
939
940FunctionType:
941 FieldType
942 {
943 pdebug("FunctionType -> FieldType");
944 $$ = $1;
945 }
946| tok_void
947 {
948 pdebug("FunctionType -> tok_void");
949 $$ = g_type_void;
950 }
951
952FieldType:
953 tok_identifier
954 {
955 pdebug("FieldType -> tok_identifier");
956 if (g_parse_mode == INCLUDES) {
957 // Ignore identifiers in include mode
958 $$ = NULL;
959 } else {
960 // Lookup the identifier in the current scope
961 $$ = g_scope->get_type($1);
962 if ($$ == NULL) {
963 yyerror("Type \"%s\" has not been defined.", $1);
964 exit(1);
965 }
966 }
967 }
968| BaseType
969 {
970 pdebug("FieldType -> BaseType");
971 $$ = $1;
972 }
973| ContainerType
974 {
975 pdebug("FieldType -> ContainerType");
976 $$ = $1;
977 }
978
979BaseType:
980 tok_string
981 {
982 pdebug("BaseType -> tok_string");
983 $$ = g_type_string;
984 }
985| tok_binary
986 {
987 pdebug("BaseType -> tok_binary");
988 $$ = g_type_binary;
989 }
990| tok_slist
991 {
992 pdebug("BaseType -> tok_slist");
993 $$ = g_type_slist;
994 }
995| tok_bool
996 {
997 pdebug("BaseType -> tok_bool");
998 $$ = g_type_bool;
999 }
1000| tok_byte
1001 {
1002 pdebug("BaseType -> tok_byte");
1003 $$ = g_type_byte;
1004 }
1005| tok_i16
1006 {
1007 pdebug("BaseType -> tok_i16");
1008 $$ = g_type_i16;
1009 }
1010| tok_i32
1011 {
1012 pdebug("BaseType -> tok_i32");
1013 $$ = g_type_i32;
1014 }
1015| tok_i64
1016 {
1017 pdebug("BaseType -> tok_i64");
1018 $$ = g_type_i64;
1019 }
1020| tok_double
1021 {
1022 pdebug("BaseType -> tok_double");
1023 $$ = g_type_double;
1024 }
1025
1026ContainerType: SimpleContainerType TypeAnnotations
1027 {
1028 pdebug("ContainerType -> SimpleContainerType TypeAnnotations");
1029 $$ = $1;
1030 if ($2 != NULL) {
1031 $$->annotations_ = $2->annotations_;
1032 delete $2;
1033 }
1034 }
1035
1036SimpleContainerType:
1037 MapType
1038 {
1039 pdebug("SimpleContainerType -> MapType");
1040 $$ = $1;
1041 }
1042| SetType
1043 {
1044 pdebug("SimpleContainerType -> SetType");
1045 $$ = $1;
1046 }
1047| ListType
1048 {
1049 pdebug("SimpleContainerType -> ListType");
1050 $$ = $1;
1051 }
1052
1053MapType:
1054 tok_map CppType '<' FieldType ',' FieldType '>'
1055 {
1056 pdebug("MapType -> tok_map <FieldType, FieldType>");
1057 $$ = new t_map($4, $6);
1058 if ($2 != NULL) {
1059 ((t_container*)$$)->set_cpp_name(std::string($2));
1060 }
1061 }
1062
1063SetType:
1064 tok_set CppType '<' FieldType '>'
1065 {
1066 pdebug("SetType -> tok_set<FieldType>");
1067 $$ = new t_set($4);
1068 if ($2 != NULL) {
1069 ((t_container*)$$)->set_cpp_name(std::string($2));
1070 }
1071 }
1072
1073ListType:
1074 tok_list '<' FieldType '>' CppType
1075 {
1076 pdebug("ListType -> tok_list<FieldType>");
1077 $$ = new t_list($3);
1078 if ($5 != NULL) {
1079 ((t_container*)$$)->set_cpp_name(std::string($5));
1080 }
1081 }
1082
1083CppType:
1084 tok_cpp_type tok_literal
1085 {
1086 $$ = $2;
1087 }
1088|
1089 {
1090 $$ = NULL;
1091 }
1092
1093TypeAnnotations:
1094 '(' TypeAnnotationList ')'
1095 {
1096 pdebug("TypeAnnotations -> ( TypeAnnotationList )");
1097 $$ = $2;
1098 }
1099|
1100 {
1101 $$ = NULL;
1102 }
1103
1104TypeAnnotationList:
1105 TypeAnnotationList TypeAnnotation
1106 {
1107 pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation");
1108 $$ = $1;
1109 $$->annotations_[$2->key] = $2->val;
1110 delete $2;
1111 }
1112|
1113 {
1114 /* Just use a dummy structure to hold the annotations. */
1115 $$ = new t_struct(g_program);
1116 }
1117
1118TypeAnnotation:
1119 tok_identifier '=' tok_literal CommaOrSemicolonOptional
1120 {
1121 pdebug("TypeAnnotation -> tok_identifier = tok_literal");
1122 $$ = new t_annotation;
1123 $$->key = $1;
1124 $$->val = $3;
1125 }
1126
1127%%