2 #include "thrift/parse/t_program.h"
6 * Licensed to the Apache Software Foundation (ASF) under one
7 * or more contributor license agreements. See the NOTICE file
8 * distributed with this work for additional information
9 * regarding copyright ownership. The ASF licenses this file
10 * to you under the Apache License, Version 2.0 (the
11 * "License"); you may not use this file except in compliance
12 * with the License. You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing,
17 * software distributed under the License is distributed on an
18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 * KIND, either express or implied. See the License for the
20 * specific language governing permissions and limitations
27 * This parser is used on a thrift definition file.
31 #ifndef __STDC_LIMIT_MACROS
32 #define __STDC_LIMIT_MACROS
34 #ifndef __STDC_FORMAT_MACROS
35 #define __STDC_FORMAT_MACROS
46 #include "thrift/windows/config.h"
48 #include "thrift/main.h"
49 #include "thrift/common.h"
50 #include "thrift/globals.h"
51 #include "thrift/parse/t_program.h"
52 #include "thrift/parse/t_scope.h"
55 //warning C4065: switch statement contains 'default' but no 'case' labels
56 #pragma warning(disable:4065)
60 * This global variable is used for automatic numbering of field indices etc.
61 * when parsing the members of a struct. Field values are automatically
62 * assigned starting from -1 and working their way down.
66 * This global variable is used for automatic numbering of enum values.
67 * y_enum_val is the last value assigned; the next auto-assigned value will be
68 * y_enum_val+1, and then it continues working upwards. Explicitly specified
69 * enum values reset y_enum_val to that value.
71 int32_t y_enum_val = -1;
73 const int struct_is_struct = 0;
74 const int struct_is_union = 1;
79 * This structure is used by the parser to hold the data types associated with
80 * various parse nodes.
94 t_const_value* tconstv;
97 t_function* tfunction;
101 t_annotation* tannot;
108 %token<id> tok_identifier
109 %token<id> tok_literal
110 %token<dtext> tok_doctext
115 %token<iconst> tok_int_constant
116 %token<dconst> tok_dub_constant
123 %token tok_cpp_include
126 %token tok_xsd_optional
127 %token tok_xsd_nillable
131 * Base datatype keywords
146 * Complex type keywords
158 * Thrift language keywords
177 %type<ttype> BaseType
178 %type<ttype> SimpleBaseType
179 %type<ttype> ContainerType
180 %type<ttype> SimpleContainerType
183 %type<ttype> ListType
185 %type<tdoc> Definition
186 %type<ttype> TypeDefinition
188 %type<ttypedef> Typedef
190 %type<ttype> TypeAnnotations
191 %type<ttype> TypeAnnotationList
192 %type<tannot> TypeAnnotation
193 %type<id> TypeAnnotationValue
196 %type<tfieldid> FieldIdentifier
197 %type<ereq> FieldRequiredness
198 %type<ttype> FieldType
199 %type<tconstv> FieldValue
200 %type<tstruct> FieldList
201 %type<tbool> FieldReference
204 %type<tenum> EnumDefList
205 %type<tenumv> EnumDef
206 %type<tenumv> EnumValue
208 %type<ttypedef> Senum
209 %type<tbase> SenumDefList
213 %type<tconstv> ConstValue
214 %type<tconstv> ConstList
215 %type<tconstv> ConstListContents
216 %type<tconstv> ConstMap
217 %type<tconstv> ConstMapContents
219 %type<iconst> StructHead
220 %type<tstruct> Struct
221 %type<tstruct> Xception
222 %type<tservice> Service
224 %type<tfunction> Function
225 %type<ttype> FunctionType
226 %type<tservice> FunctionList
228 %type<tstruct> Throws
229 %type<tservice> Extends
232 %type<tbool> XsdOptional
233 %type<tbool> XsdNillable
234 %type<tstruct> XsdAttributes
237 %type<dtext> CaptureDocText
242 * Thrift Grammar Implementation.
244 * For the most part this source file works its way top down from what you
245 * might expect to find in a typical .thrift file, i.e. type definitions and
246 * namespaces up top followed by service definitions using those types.
250 HeaderList DefinitionList
252 pdebug("Program -> Headers DefinitionList");
253 if((g_program_doctext_candidate != NULL) && (g_program_doctext_status != ALREADY_PROCESSED))
255 g_program->set_doc(g_program_doctext_candidate);
256 g_program_doctext_status = ALREADY_PROCESSED;
263 if (g_parse_mode == PROGRAM) {
271 /* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */
274 if (g_parse_mode == PROGRAM) {
279 /* We have to DestroyDocText here, otherwise it catches the doctext
280 on the first real element. */
282 HeaderList DestroyDocText Header
284 pdebug("HeaderList -> HeaderList Header");
288 pdebug("HeaderList -> ");
294 pdebug("Header -> Include");
296 | tok_namespace tok_identifier tok_identifier TypeAnnotations
298 pdebug("Header -> tok_namespace tok_identifier tok_identifier");
299 declare_valid_program_doctext();
300 if (g_parse_mode == PROGRAM) {
301 g_program->set_namespace($2, $3);
304 g_program->set_namespace_annotations($2, $4->annotations_);
308 | tok_namespace '*' tok_identifier
310 pdebug("Header -> tok_namespace * tok_identifier");
311 declare_valid_program_doctext();
312 if (g_parse_mode == PROGRAM) {
313 g_program->set_namespace("*", $3);
316 | tok_cpp_include tok_literal
318 pdebug("Header -> tok_cpp_include tok_literal");
319 declare_valid_program_doctext();
320 if (g_parse_mode == PROGRAM) {
321 g_program->add_cpp_include($2);
326 tok_include tok_literal
328 pdebug("Include -> tok_include tok_literal");
329 declare_valid_program_doctext();
330 if (g_parse_mode == INCLUDES) {
331 std::string path = include_file(std::string($2));
333 g_program->add_include(path, std::string($2));
339 DefinitionList CaptureDocText Definition
341 pdebug("DefinitionList -> DefinitionList Definition");
342 if ($2 != NULL && $3 != NULL) {
348 pdebug("DefinitionList -> ");
354 pdebug("Definition -> Const");
355 if (g_parse_mode == PROGRAM) {
356 g_program->add_const($1);
362 pdebug("Definition -> TypeDefinition");
363 if (g_parse_mode == PROGRAM) {
364 g_scope->add_type($1->get_name(), $1);
365 if (g_parent_scope != NULL) {
366 g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1);
368 if (! g_program->is_unique_typename($1)) {
369 yyerror("Type \"%s\" is already defined.", $1->get_name().c_str());
377 pdebug("Definition -> Service");
378 if (g_parse_mode == PROGRAM) {
379 g_scope->add_service($1->get_name(), $1);
380 if (g_parent_scope != NULL) {
381 g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1);
383 g_program->add_service($1);
384 if (! g_program->is_unique_typename($1)) {
385 yyerror("Type \"%s\" is already defined.", $1->get_name().c_str());
395 pdebug("TypeDefinition -> Typedef");
396 if (g_parse_mode == PROGRAM) {
397 g_program->add_typedef($1);
402 pdebug("TypeDefinition -> Enum");
403 if (g_parse_mode == PROGRAM) {
404 g_program->add_enum($1);
409 pdebug("TypeDefinition -> Senum");
410 if (g_parse_mode == PROGRAM) {
411 g_program->add_typedef($1);
416 pdebug("TypeDefinition -> Struct");
417 if (g_parse_mode == PROGRAM) {
418 g_program->add_struct($1);
423 pdebug("TypeDefinition -> Xception");
424 if (g_parse_mode == PROGRAM) {
425 g_program->add_xception($1);
429 CommaOrSemicolonOptional:
438 tok_typedef FieldType tok_identifier TypeAnnotations CommaOrSemicolonOptional
440 pdebug("TypeDef -> tok_typedef FieldType tok_identifier");
441 validate_simple_identifier( $3);
442 t_typedef *td = new t_typedef(g_program, $2, $3);
445 $$->annotations_ = $4->annotations_;
451 tok_enum tok_identifier '{' EnumDefList '}' TypeAnnotations
453 pdebug("Enum -> tok_enum tok_identifier { EnumDefList }");
455 validate_simple_identifier( $2);
458 $$->annotations_ = $6->annotations_;
462 // make constants for all the enum values
463 if (g_parse_mode == PROGRAM) {
464 const std::vector<t_enum_value*>& enum_values = $$->get_constants();
465 std::vector<t_enum_value*>::const_iterator c_iter;
466 for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
467 std::string const_name = $$->get_name() + "." + (*c_iter)->get_name();
468 t_const_value* const_val = new t_const_value((*c_iter)->get_value());
469 const_val->set_enum($$);
470 g_scope->add_constant(const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val));
471 if (g_parent_scope != NULL) {
472 g_parent_scope->add_constant(g_parent_prefix + const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val));
481 pdebug("EnumDefList -> EnumDefList EnumDef");
487 pdebug("EnumDefList -> ");
488 $$ = new t_enum(g_program);
493 CaptureDocText EnumValue TypeAnnotations CommaOrSemicolonOptional
495 pdebug("EnumDef -> EnumValue");
501 $$->annotations_ = $3->annotations_;
507 tok_identifier '=' tok_int_constant
509 pdebug("EnumValue -> tok_identifier = tok_int_constant");
510 if ($3 < INT32_MIN || $3 > INT32_MAX) {
511 // Note: this used to be just a warning. However, since thrift always
512 // treats enums as i32 values, I'm changing it to a fatal error.
513 // I doubt this will affect many people, but users who run into this
514 // will have to update their thrift files to manually specify the
515 // truncated i32 value that thrift has always been using anyway.
516 failure("64-bit value supplied for enum %s will be truncated.", $1);
518 y_enum_val = static_cast<int32_t>($3);
519 $$ = new t_enum_value($1, y_enum_val);
524 pdebug("EnumValue -> tok_identifier");
525 validate_simple_identifier( $1);
526 if (y_enum_val == INT32_MAX) {
527 failure("enum value overflow at enum %s", $1);
530 $$ = new t_enum_value($1, y_enum_val);
534 tok_senum tok_identifier '{' SenumDefList '}' TypeAnnotations
536 pdebug("Senum -> tok_senum tok_identifier { SenumDefList }");
537 validate_simple_identifier( $2);
538 $$ = new t_typedef(g_program, $4, $2);
540 $$->annotations_ = $6->annotations_;
546 SenumDefList SenumDef
548 pdebug("SenumDefList -> SenumDefList SenumDef");
550 $$->add_string_enum_val($2);
554 pdebug("SenumDefList -> ");
555 $$ = new t_base_type("string", t_base_type::TYPE_STRING);
556 $$->set_string_enum(true);
560 tok_literal CommaOrSemicolonOptional
562 pdebug("SenumDef -> tok_literal");
567 tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional
569 pdebug("Const -> tok_const FieldType tok_identifier = ConstValue");
570 if (g_parse_mode == PROGRAM) {
571 validate_simple_identifier( $3);
572 g_scope->resolve_const_value($5, $2);
573 $$ = new t_const($2, $3, $5);
574 validate_const_type($$);
576 g_scope->add_constant($3, $$);
577 if (g_parent_scope != NULL) {
578 g_parent_scope->add_constant(g_parent_prefix + $3, $$);
588 pdebug("ConstValue => tok_int_constant");
589 $$ = new t_const_value();
591 if (!g_allow_64bit_consts && ($1 < INT32_MIN || $1 > INT32_MAX)) {
592 pwarning(1, "64-bit constant \"%" PRIi64"\" may not work in all languages.\n", $1);
597 pdebug("ConstValue => tok_dub_constant");
598 $$ = new t_const_value();
603 pdebug("ConstValue => tok_literal");
604 $$ = new t_const_value($1);
608 pdebug("ConstValue => tok_identifier");
609 $$ = new t_const_value();
610 $$->set_identifier($1);
614 pdebug("ConstValue => ConstList");
619 pdebug("ConstValue => ConstMap");
624 '[' ConstListContents ']'
626 pdebug("ConstList => [ ConstListContents ]");
631 ConstListContents ConstValue CommaOrSemicolonOptional
633 pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional");
639 pdebug("ConstListContents =>");
640 $$ = new t_const_value();
645 '{' ConstMapContents '}'
647 pdebug("ConstMap => { ConstMapContents }");
652 ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional
654 pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional");
660 pdebug("ConstMapContents =>");
661 $$ = new t_const_value();
668 $$ = struct_is_struct;
672 $$ = struct_is_union;
676 StructHead tok_identifier XsdAll '{' FieldList '}' TypeAnnotations
678 pdebug("Struct -> tok_struct tok_identifier { FieldList }");
679 validate_simple_identifier( $2);
681 $5->set_union($1 == struct_is_union);
685 $$->annotations_ = $7->annotations_;
721 tok_xsd_attrs '{' FieldList '}'
731 tok_xception tok_identifier '{' FieldList '}' TypeAnnotations
733 pdebug("Xception -> tok_xception tok_identifier { FieldList }");
734 validate_simple_identifier( $2);
736 $4->set_xception(true);
739 $$->annotations_ = $6->annotations_;
745 tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' TypeAnnotations
747 pdebug("Service -> tok_service tok_identifier { FunctionList }");
748 validate_simple_identifier( $2);
753 $$->annotations_ = $9->annotations_;
769 tok_extends tok_identifier
771 pdebug("Extends -> tok_extends tok_identifier");
773 if (g_parse_mode == PROGRAM) {
774 $$ = g_scope->get_service($2);
776 yyerror("Service \"%s\" has not been defined.", $2);
787 FunctionList Function
789 pdebug("FunctionList -> FunctionList Function");
791 $1->add_function($2);
795 pdebug("FunctionList -> ");
796 $$ = new t_service(g_program);
800 CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws TypeAnnotations CommaOrSemicolonOptional
802 validate_simple_identifier( $4);
803 $6->set_name(std::string($4) + "_args");
804 $$ = new t_function($3, $4, $6, $8, $2);
809 $$->annotations_ = $9->annotations_;
825 tok_throws '(' FieldList ')'
827 pdebug("Throws -> tok_throws ( FieldList )");
829 if (g_parse_mode == PROGRAM && !validate_throws($$)) {
830 yyerror("Throws clause may not contain non-exception types");
836 $$ = new t_struct(g_program);
842 pdebug("FieldList -> FieldList , Field");
844 if (!($$->append($2))) {
845 yyerror("\"%d: %s\" - field identifier/name has already been used", $2->get_key(), $2->get_name().c_str());
851 pdebug("FieldList -> ");
853 $$ = new t_struct(g_program);
857 CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional
859 pdebug("tok_int_constant : Field -> FieldType tok_identifier");
860 if ($2.auto_assigned) {
861 pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6);
862 if (g_strict >= 192) {
863 yyerror("Implicit field keys are deprecated and not allowed with -strict");
867 validate_simple_identifier($6);
868 $$ = new t_field($4, $6, $2.value);
869 $$->set_reference($5);
872 g_scope->resolve_const_value($7, $4);
873 validate_field_value($$, $7);
876 $$->set_xsd_optional($8);
877 $$->set_xsd_nillable($9);
882 $$->set_xsd_attrs($10);
885 $$->annotations_ = $11->annotations_;
894 if (g_allow_neg_field_keys) {
896 * g_allow_neg_field_keys exists to allow users to add explicitly
897 * specified key values to old .thrift files without breaking
898 * protocol compatibility.
900 if ($1 != y_field_val) {
902 * warn if the user-specified negative value isn't what
903 * thrift would have auto-assigned.
905 pwarning(1, "Nonpositive field key (%" PRIi64") differs from what would be "
906 "auto-assigned by thrift (%d).\n", $1, y_field_val);
909 * Leave $1 as-is, and update y_field_val to be one less than $1.
910 * The FieldList parsing will catch any duplicate key values.
912 y_field_val = static_cast<int32_t>($1 - 1);
913 $$.value = static_cast<int32_t>($1);
914 $$.auto_assigned = false;
916 pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n",
918 $$.value = y_field_val--;
919 $$.auto_assigned = true;
922 $$.value = static_cast<int32_t>($1);
923 $$.auto_assigned = false;
925 if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) {
926 pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n",
927 $$.value, SHRT_MIN, SHRT_MAX);
932 $$.value = y_field_val--;
933 $$.auto_assigned = true;
934 if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) {
935 pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n",
936 $$.value, SHRT_MIN, SHRT_MAX);
953 $$ = t_field::T_REQUIRED;
958 if (g_parse_mode == PROGRAM) {
959 pwarning(1, "optional keyword is ignored in argument lists.\n");
961 $$ = t_field::T_OPT_IN_REQ_OUT;
963 $$ = t_field::T_OPTIONAL;
968 $$ = t_field::T_OPT_IN_REQ_OUT;
974 if (g_parse_mode == PROGRAM) {
988 pdebug("FunctionType -> FieldType");
993 pdebug("FunctionType -> tok_void");
1000 pdebug("FieldType -> tok_identifier");
1001 if (g_parse_mode == INCLUDES) {
1002 // Ignore identifiers in include mode
1005 // Lookup the identifier in the current scope
1006 $$ = g_scope->get_type($1);
1009 * Either this type isn't yet declared, or it's never
1010 declared. Either way allow it and we'll figure it out
1013 $$ = new t_typedef(g_program, $1, true);
1019 pdebug("FieldType -> BaseType");
1024 pdebug("FieldType -> ContainerType");
1028 BaseType: SimpleBaseType TypeAnnotations
1030 pdebug("BaseType -> SimpleBaseType TypeAnnotations");
1032 $$ = new t_base_type(*static_cast<t_base_type*>($1));
1033 $$->annotations_ = $2->annotations_;
1043 pdebug("BaseType -> tok_string");
1048 pdebug("BaseType -> tok_binary");
1053 pdebug("BaseType -> tok_slist");
1058 pdebug("BaseType -> tok_bool");
1063 pdebug("BaseType -> tok_i8");
1068 pdebug("BaseType -> tok_i16");
1073 pdebug("BaseType -> tok_i32");
1078 pdebug("BaseType -> tok_i64");
1083 pdebug("BaseType -> tok_double");
1087 ContainerType: SimpleContainerType TypeAnnotations
1089 pdebug("ContainerType -> SimpleContainerType TypeAnnotations");
1092 $$->annotations_ = $2->annotations_;
1097 SimpleContainerType:
1100 pdebug("SimpleContainerType -> MapType");
1105 pdebug("SimpleContainerType -> SetType");
1110 pdebug("SimpleContainerType -> ListType");
1115 tok_map CppType '<' FieldType ',' FieldType '>'
1117 pdebug("MapType -> tok_map <FieldType, FieldType>");
1118 $$ = new t_map($4, $6);
1120 ((t_container*)$$)->set_cpp_name(std::string($2));
1125 tok_set CppType '<' FieldType '>'
1127 pdebug("SetType -> tok_set<FieldType>");
1130 ((t_container*)$$)->set_cpp_name(std::string($2));
1135 tok_list '<' FieldType '>' CppType
1137 pdebug("ListType -> tok_list<FieldType>");
1138 check_for_list_of_bytes($3);
1139 $$ = new t_list($3);
1141 ((t_container*)$$)->set_cpp_name(std::string($5));
1146 tok_cpp_type tok_literal
1156 '(' TypeAnnotationList ')'
1158 pdebug("TypeAnnotations -> ( TypeAnnotationList )");
1167 TypeAnnotationList TypeAnnotation
1169 pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation");
1171 $$->annotations_[$2->key] = $2->val;
1176 /* Just use a dummy structure to hold the annotations. */
1177 $$ = new t_struct(g_program);
1181 tok_identifier TypeAnnotationValue CommaOrSemicolonOptional
1183 pdebug("TypeAnnotation -> TypeAnnotationValue");
1184 $$ = new t_annotation;
1189 TypeAnnotationValue:
1192 pdebug("TypeAnnotationValue -> = tok_literal");
1197 pdebug("TypeAnnotationValue ->");