diff options
Diffstat (limited to 'compiler/cpp/src/thrifty.yy')
-rw-r--r-- | compiler/cpp/src/thrifty.yy | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy new file mode 100644 index 000000000..bf5408e3a --- /dev/null +++ b/compiler/cpp/src/thrifty.yy @@ -0,0 +1,1127 @@ +%{ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Thrift parser. + * + * This parser is used on a thrift definition file. + * + */ + +#define __STDC_LIMIT_MACROS +#define __STDC_FORMAT_MACROS +#include <stdio.h> +#include <inttypes.h> +#include <limits.h> +#include "main.h" +#include "globals.h" +#include "parse/t_program.h" +#include "parse/t_scope.h" + +/** + * This global variable is used for automatic numbering of field indices etc. + * when parsing the members of a struct. Field values are automatically + * assigned starting from -1 and working their way down. + */ +int y_field_val = -1; +int g_arglist = 0; + +%} + +/** + * This structure is used by the parser to hold the data types associated with + * various parse nodes. + */ +%union { + char* id; + int64_t iconst; + double dconst; + bool tbool; + t_doc* tdoc; + t_type* ttype; + t_base_type* tbase; + t_typedef* ttypedef; + t_enum* tenum; + t_enum_value* tenumv; + t_const* tconst; + t_const_value* tconstv; + t_struct* tstruct; + t_service* tservice; + t_function* tfunction; + t_field* tfield; + char* dtext; + t_field::e_req ereq; + t_annotation* tannot; +} + +/** + * Strings identifier + */ +%token<id> tok_identifier +%token<id> tok_literal +%token<dtext> tok_doctext +%token<id> tok_st_identifier + +/** + * Constant values + */ +%token<iconst> tok_int_constant +%token<dconst> tok_dub_constant + +/** + * Header keywords + */ +%token tok_include +%token tok_namespace +%token tok_cpp_namespace +%token tok_cpp_include +%token tok_cpp_type +%token tok_php_namespace +%token tok_py_module +%token tok_perl_package +%token tok_java_package +%token tok_xsd_all +%token tok_xsd_optional +%token tok_xsd_nillable +%token tok_xsd_namespace +%token tok_xsd_attrs +%token tok_ruby_namespace +%token tok_smalltalk_category +%token tok_smalltalk_prefix +%token tok_cocoa_prefix +%token tok_csharp_namespace + +/** + * Base datatype keywords + */ +%token tok_void +%token tok_bool +%token tok_byte +%token tok_string +%token tok_binary +%token tok_slist +%token tok_senum +%token tok_i16 +%token tok_i32 +%token tok_i64 +%token tok_double + +/** + * Complex type keywords + */ +%token tok_map +%token tok_list +%token tok_set + +/** + * Function modifiers + */ +%token tok_oneway + +/** + * Thrift language keywords + */ +%token tok_typedef +%token tok_struct +%token tok_xception +%token tok_throws +%token tok_extends +%token tok_service +%token tok_enum +%token tok_const +%token tok_required +%token tok_optional + +/** + * Grammar nodes + */ + +%type<ttype> BaseType +%type<ttype> ContainerType +%type<ttype> SimpleContainerType +%type<ttype> MapType +%type<ttype> SetType +%type<ttype> ListType + +%type<tdoc> Definition +%type<ttype> TypeDefinition + +%type<ttypedef> Typedef +%type<ttype> DefinitionType + +%type<ttype> TypeAnnotations +%type<ttype> TypeAnnotationList +%type<tannot> TypeAnnotation + +%type<tfield> Field +%type<iconst> FieldIdentifier +%type<ereq> FieldRequiredness +%type<ttype> FieldType +%type<tconstv> FieldValue +%type<tstruct> FieldList + +%type<tenum> Enum +%type<tenum> EnumDefList +%type<tenumv> EnumDef + +%type<ttypedef> Senum +%type<tbase> SenumDefList +%type<id> SenumDef + +%type<tconst> Const +%type<tconstv> ConstValue +%type<tconstv> ConstList +%type<tconstv> ConstListContents +%type<tconstv> ConstMap +%type<tconstv> ConstMapContents + +%type<tstruct> Struct +%type<tstruct> Xception +%type<tservice> Service + +%type<tfunction> Function +%type<ttype> FunctionType +%type<tservice> FunctionList + +%type<tstruct> Throws +%type<tservice> Extends +%type<tbool> Oneway +%type<tbool> XsdAll +%type<tbool> XsdOptional +%type<tbool> XsdNillable +%type<tstruct> XsdAttributes +%type<id> CppType + +%type<dtext> CaptureDocText + +%% + +/** + * Thrift Grammar Implementation. + * + * For the most part this source file works its way top down from what you + * might expect to find in a typical .thrift file, i.e. type definitions and + * namespaces up top followed by service definitions using those types. + */ + +Program: + HeaderList DefinitionList + { + pdebug("Program -> Headers DefinitionList"); + /* + TODO(dreiss): Decide whether full-program doctext is worth the trouble. + if ($1 != NULL) { + g_program->set_doc($1); + } + */ + clear_doctext(); + } + +CaptureDocText: + { + if (g_parse_mode == PROGRAM) { + $$ = g_doctext; + g_doctext = NULL; + } else { + $$ = NULL; + } + } + +/* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */ +DestroyDocText: + { + if (g_parse_mode == PROGRAM) { + clear_doctext(); + } + } + +/* We have to DestroyDocText here, otherwise it catches the doctext + on the first real element. */ +HeaderList: + HeaderList DestroyDocText Header + { + pdebug("HeaderList -> HeaderList Header"); + } +| + { + pdebug("HeaderList -> "); + } + +Header: + Include + { + pdebug("Header -> Include"); + } +| tok_namespace tok_identifier tok_identifier + { + pdebug("Header -> tok_namespace tok_identifier tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace($2, $3); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_cpp_namespace tok_identifier + { + pwarning(1, "'cpp_namespace' is deprecated. Use 'namespace cpp' instead"); + pdebug("Header -> tok_cpp_namespace tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("cpp", $2); + } + } +| tok_cpp_include tok_literal + { + pdebug("Header -> tok_cpp_include tok_literal"); + if (g_parse_mode == PROGRAM) { + g_program->add_cpp_include($2); + } + } +| tok_php_namespace tok_identifier + { + pwarning(1, "'php_namespace' is deprecated. Use 'namespace php' instead"); + pdebug("Header -> tok_php_namespace tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("php", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_py_module tok_identifier + { + pwarning(1, "'py_module' is deprecated. Use 'namespace py' instead"); + pdebug("Header -> tok_py_module tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("py", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_perl_package tok_identifier + { + pwarning(1, "'perl_package' is deprecated. Use 'namespace perl' instead"); + pdebug("Header -> tok_perl_namespace tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("perl", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_ruby_namespace tok_identifier + { + pwarning(1, "'ruby_namespace' is deprecated. Use 'namespace rb' instead"); + pdebug("Header -> tok_ruby_namespace tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("rb", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_smalltalk_category tok_st_identifier + { + pwarning(1, "'smalltalk_category' is deprecated. Use 'namespace smalltalk.category' instead"); + pdebug("Header -> tok_smalltalk_category tok_st_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("smalltalk.category", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_smalltalk_prefix tok_identifier + { + pwarning(1, "'smalltalk_prefix' is deprecated. Use 'namespace smalltalk.prefix' instead"); + pdebug("Header -> tok_smalltalk_prefix tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("smalltalk.prefix", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_java_package tok_identifier + { + pwarning(1, "'java_package' is deprecated. Use 'namespace java' instead"); + pdebug("Header -> tok_java_package tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("java", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_cocoa_prefix tok_identifier + { + pwarning(1, "'cocoa_prefix' is deprecated. Use 'namespace cocoa' instead"); + pdebug("Header -> tok_cocoa_prefix tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("cocoa", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_xsd_namespace tok_literal + { + pwarning(1, "'xsd_namespace' is deprecated. Use 'namespace xsd' instead"); + pdebug("Header -> tok_xsd_namespace tok_literal"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("cocoa", $2); + } + } +/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ +| tok_csharp_namespace tok_identifier + { + pwarning(1, "'csharp_namespace' is deprecated. Use 'namespace csharp' instead"); + pdebug("Header -> tok_csharp_namespace tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_namespace("csharp", $2); + } + } + +Include: + tok_include tok_literal + { + pdebug("Include -> tok_include tok_literal"); + if (g_parse_mode == INCLUDES) { + std::string path = include_file(std::string($2)); + if (!path.empty()) { + g_program->add_include(path, std::string($2)); + } + } + } + +DefinitionList: + DefinitionList CaptureDocText Definition + { + pdebug("DefinitionList -> DefinitionList Definition"); + if ($2 != NULL && $3 != NULL) { + $3->set_doc($2); + } + } +| + { + pdebug("DefinitionList -> "); + } + +Definition: + Const + { + pdebug("Definition -> Const"); + if (g_parse_mode == PROGRAM) { + g_program->add_const($1); + } + $$ = $1; + } +| TypeDefinition + { + pdebug("Definition -> TypeDefinition"); + if (g_parse_mode == PROGRAM) { + g_scope->add_type($1->get_name(), $1); + if (g_parent_scope != NULL) { + g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1); + } + } + $$ = $1; + } +| Service + { + pdebug("Definition -> Service"); + if (g_parse_mode == PROGRAM) { + g_scope->add_service($1->get_name(), $1); + if (g_parent_scope != NULL) { + g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1); + } + g_program->add_service($1); + } + $$ = $1; + } + +TypeDefinition: + Typedef + { + pdebug("TypeDefinition -> Typedef"); + if (g_parse_mode == PROGRAM) { + g_program->add_typedef($1); + } + } +| Enum + { + pdebug("TypeDefinition -> Enum"); + if (g_parse_mode == PROGRAM) { + g_program->add_enum($1); + } + } +| Senum + { + pdebug("TypeDefinition -> Senum"); + if (g_parse_mode == PROGRAM) { + g_program->add_typedef($1); + } + } +| Struct + { + pdebug("TypeDefinition -> Struct"); + if (g_parse_mode == PROGRAM) { + g_program->add_struct($1); + } + } +| Xception + { + pdebug("TypeDefinition -> Xception"); + if (g_parse_mode == PROGRAM) { + g_program->add_xception($1); + } + } + +Typedef: + tok_typedef DefinitionType tok_identifier + { + pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier"); + t_typedef *td = new t_typedef(g_program, $2, $3); + $$ = td; + } + +CommaOrSemicolonOptional: + ',' + {} +| ';' + {} +| + {} + +Enum: + tok_enum tok_identifier '{' EnumDefList '}' + { + pdebug("Enum -> tok_enum tok_identifier { EnumDefList }"); + $$ = $4; + $$->set_name($2); + } + +EnumDefList: + EnumDefList EnumDef + { + pdebug("EnumDefList -> EnumDefList EnumDef"); + $$ = $1; + $$->append($2); + } +| + { + pdebug("EnumDefList -> "); + $$ = new t_enum(g_program); + } + +EnumDef: + CaptureDocText tok_identifier '=' tok_int_constant CommaOrSemicolonOptional + { + pdebug("EnumDef -> tok_identifier = tok_int_constant"); + if ($4 < 0) { + pwarning(1, "Negative value supplied for enum %s.\n", $2); + } + if ($4 > INT_MAX) { + pwarning(1, "64-bit value supplied for enum %s.\n", $2); + } + $$ = new t_enum_value($2, $4); + if ($1 != NULL) { + $$->set_doc($1); + } + if (g_parse_mode == PROGRAM) { + g_scope->add_constant($2, new t_const(g_type_i32, $2, new t_const_value($4))); + if (g_parent_scope != NULL) { + g_parent_scope->add_constant(g_parent_prefix + $2, new t_const(g_type_i32, $2, new t_const_value($4))); + } + } + } +| + CaptureDocText tok_identifier CommaOrSemicolonOptional + { + pdebug("EnumDef -> tok_identifier"); + $$ = new t_enum_value($2); + if ($1 != NULL) { + $$->set_doc($1); + } + } + +Senum: + tok_senum tok_identifier '{' SenumDefList '}' + { + pdebug("Senum -> tok_senum tok_identifier { SenumDefList }"); + $$ = new t_typedef(g_program, $4, $2); + } + +SenumDefList: + SenumDefList SenumDef + { + pdebug("SenumDefList -> SenumDefList SenumDef"); + $$ = $1; + $$->add_string_enum_val($2); + } +| + { + pdebug("SenumDefList -> "); + $$ = new t_base_type("string", t_base_type::TYPE_STRING); + $$->set_string_enum(true); + } + +SenumDef: + tok_literal CommaOrSemicolonOptional + { + pdebug("SenumDef -> tok_literal"); + $$ = $1; + } + +Const: + tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional + { + pdebug("Const -> tok_const FieldType tok_identifier = ConstValue"); + if (g_parse_mode == PROGRAM) { + $$ = new t_const($2, $3, $5); + validate_const_type($$); + + g_scope->add_constant($3, $$); + if (g_parent_scope != NULL) { + g_parent_scope->add_constant(g_parent_prefix + $3, $$); + } + + } else { + $$ = NULL; + } + } + +ConstValue: + tok_int_constant + { + pdebug("ConstValue => tok_int_constant"); + $$ = new t_const_value(); + $$->set_integer($1); + if ($1 < INT32_MIN || $1 > INT32_MAX) { + pwarning(1, "64-bit constant \"%"PRIi64"\" may not work in all languages.\n", $1); + } + } +| tok_dub_constant + { + pdebug("ConstValue => tok_dub_constant"); + $$ = new t_const_value(); + $$->set_double($1); + } +| tok_literal + { + pdebug("ConstValue => tok_literal"); + $$ = new t_const_value($1); + } +| tok_identifier + { + pdebug("ConstValue => tok_identifier"); + t_const* constant = g_scope->get_constant($1); + if (constant != NULL) { + $$ = constant->get_value(); + } else { + if (g_parse_mode == PROGRAM) { + pwarning(1, "Constant strings should be quoted: %s\n", $1); + } + $$ = new t_const_value($1); + } + } +| ConstList + { + pdebug("ConstValue => ConstList"); + $$ = $1; + } +| ConstMap + { + pdebug("ConstValue => ConstMap"); + $$ = $1; + } + +ConstList: + '[' ConstListContents ']' + { + pdebug("ConstList => [ ConstListContents ]"); + $$ = $2; + } + +ConstListContents: + ConstListContents ConstValue CommaOrSemicolonOptional + { + pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional"); + $$ = $1; + $$->add_list($2); + } +| + { + pdebug("ConstListContents =>"); + $$ = new t_const_value(); + $$->set_list(); + } + +ConstMap: + '{' ConstMapContents '}' + { + pdebug("ConstMap => { ConstMapContents }"); + $$ = $2; + } + +ConstMapContents: + ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional + { + pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional"); + $$ = $1; + $$->add_map($2, $4); + } +| + { + pdebug("ConstMapContents =>"); + $$ = new t_const_value(); + $$->set_map(); + } + +Struct: + tok_struct tok_identifier XsdAll '{' FieldList '}' TypeAnnotations + { + pdebug("Struct -> tok_struct tok_identifier { FieldList }"); + $5->set_xsd_all($3); + $$ = $5; + $$->set_name($2); + if ($7 != NULL) { + $$->annotations_ = $7->annotations_; + delete $7; + } + } + +XsdAll: + tok_xsd_all + { + $$ = true; + } +| + { + $$ = false; + } + +XsdOptional: + tok_xsd_optional + { + $$ = true; + } +| + { + $$ = false; + } + +XsdNillable: + tok_xsd_nillable + { + $$ = true; + } +| + { + $$ = false; + } + +XsdAttributes: + tok_xsd_attrs '{' FieldList '}' + { + $$ = $3; + } +| + { + $$ = NULL; + } + +Xception: + tok_xception tok_identifier '{' FieldList '}' + { + pdebug("Xception -> tok_xception tok_identifier { FieldList }"); + $4->set_name($2); + $4->set_xception(true); + $$ = $4; + } + +Service: + tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' + { + pdebug("Service -> tok_service tok_identifier { FunctionList }"); + $$ = $6; + $$->set_name($2); + $$->set_extends($3); + } + +FlagArgs: + { + g_arglist = 1; + } + +UnflagArgs: + { + g_arglist = 0; + } + +Extends: + tok_extends tok_identifier + { + pdebug("Extends -> tok_extends tok_identifier"); + $$ = NULL; + if (g_parse_mode == PROGRAM) { + $$ = g_scope->get_service($2); + if ($$ == NULL) { + yyerror("Service \"%s\" has not been defined.", $2); + exit(1); + } + } + } +| + { + $$ = NULL; + } + +FunctionList: + FunctionList Function + { + pdebug("FunctionList -> FunctionList Function"); + $$ = $1; + $1->add_function($2); + } +| + { + pdebug("FunctionList -> "); + $$ = new t_service(g_program); + } + +Function: + CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws CommaOrSemicolonOptional + { + $6->set_name(std::string($4) + "_args"); + $$ = new t_function($3, $4, $6, $8, $2); + if ($1 != NULL) { + $$->set_doc($1); + } + } + +Oneway: + tok_oneway + { + $$ = true; + } +| + { + $$ = false; + } + +Throws: + tok_throws '(' FieldList ')' + { + pdebug("Throws -> tok_throws ( FieldList )"); + $$ = $3; + if (g_parse_mode == PROGRAM && !validate_throws($$)) { + yyerror("Throws clause may not contain non-exception types"); + exit(1); + } + } +| + { + $$ = new t_struct(g_program); + } + +FieldList: + FieldList Field + { + pdebug("FieldList -> FieldList , Field"); + $$ = $1; + if (!($$->append($2))) { + yyerror("Field identifier %d for \"%s\" has already been used", $2->get_key(), $2->get_name().c_str()); + exit(1); + } + } +| + { + pdebug("FieldList -> "); + y_field_val = -1; + $$ = new t_struct(g_program); + } + +Field: + CaptureDocText FieldIdentifier FieldRequiredness FieldType tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes CommaOrSemicolonOptional + { + pdebug("tok_int_constant : Field -> FieldType tok_identifier"); + if ($2 < 0) { + pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $5); + if (g_strict >= 192) { + yyerror("Implicit field keys are deprecated and not allowed with -strict"); + exit(1); + } + } + $$ = new t_field($4, $5, $2); + $$->set_req($3); + if ($6 != NULL) { + validate_field_value($$, $6); + $$->set_value($6); + } + $$->set_xsd_optional($7); + $$->set_xsd_nillable($8); + if ($1 != NULL) { + $$->set_doc($1); + } + if ($9 != NULL) { + $$->set_xsd_attrs($9); + } + } + +FieldIdentifier: + tok_int_constant ':' + { + if ($1 <= 0) { + pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", $1); + $1 = y_field_val--; + } + $$ = $1; + } +| + { + $$ = y_field_val--; + } + +FieldRequiredness: + tok_required + { + if (g_arglist) { + if (g_parse_mode == PROGRAM) { + pwarning(1, "required keyword is ignored in argument lists.\n"); + } + $$ = t_field::T_OPT_IN_REQ_OUT; + } else { + $$ = t_field::T_REQUIRED; + } + } +| tok_optional + { + if (g_arglist) { + if (g_parse_mode == PROGRAM) { + pwarning(1, "optional keyword is ignored in argument lists.\n"); + } + $$ = t_field::T_OPT_IN_REQ_OUT; + } else { + $$ = t_field::T_OPTIONAL; + } + } +| + { + $$ = t_field::T_OPT_IN_REQ_OUT; + } + +FieldValue: + '=' ConstValue + { + if (g_parse_mode == PROGRAM) { + $$ = $2; + } else { + $$ = NULL; + } + } +| + { + $$ = NULL; + } + +DefinitionType: + BaseType + { + pdebug("DefinitionType -> BaseType"); + $$ = $1; + } +| ContainerType + { + pdebug("DefinitionType -> ContainerType"); + $$ = $1; + } + +FunctionType: + FieldType + { + pdebug("FunctionType -> FieldType"); + $$ = $1; + } +| tok_void + { + pdebug("FunctionType -> tok_void"); + $$ = g_type_void; + } + +FieldType: + tok_identifier + { + pdebug("FieldType -> tok_identifier"); + if (g_parse_mode == INCLUDES) { + // Ignore identifiers in include mode + $$ = NULL; + } else { + // Lookup the identifier in the current scope + $$ = g_scope->get_type($1); + if ($$ == NULL) { + yyerror("Type \"%s\" has not been defined.", $1); + exit(1); + } + } + } +| BaseType + { + pdebug("FieldType -> BaseType"); + $$ = $1; + } +| ContainerType + { + pdebug("FieldType -> ContainerType"); + $$ = $1; + } + +BaseType: + tok_string + { + pdebug("BaseType -> tok_string"); + $$ = g_type_string; + } +| tok_binary + { + pdebug("BaseType -> tok_binary"); + $$ = g_type_binary; + } +| tok_slist + { + pdebug("BaseType -> tok_slist"); + $$ = g_type_slist; + } +| tok_bool + { + pdebug("BaseType -> tok_bool"); + $$ = g_type_bool; + } +| tok_byte + { + pdebug("BaseType -> tok_byte"); + $$ = g_type_byte; + } +| tok_i16 + { + pdebug("BaseType -> tok_i16"); + $$ = g_type_i16; + } +| tok_i32 + { + pdebug("BaseType -> tok_i32"); + $$ = g_type_i32; + } +| tok_i64 + { + pdebug("BaseType -> tok_i64"); + $$ = g_type_i64; + } +| tok_double + { + pdebug("BaseType -> tok_double"); + $$ = g_type_double; + } + +ContainerType: SimpleContainerType TypeAnnotations + { + pdebug("ContainerType -> SimpleContainerType TypeAnnotations"); + $$ = $1; + if ($2 != NULL) { + $$->annotations_ = $2->annotations_; + delete $2; + } + } + +SimpleContainerType: + MapType + { + pdebug("SimpleContainerType -> MapType"); + $$ = $1; + } +| SetType + { + pdebug("SimpleContainerType -> SetType"); + $$ = $1; + } +| ListType + { + pdebug("SimpleContainerType -> ListType"); + $$ = $1; + } + +MapType: + tok_map CppType '<' FieldType ',' FieldType '>' + { + pdebug("MapType -> tok_map <FieldType, FieldType>"); + $$ = new t_map($4, $6); + if ($2 != NULL) { + ((t_container*)$$)->set_cpp_name(std::string($2)); + } + } + +SetType: + tok_set CppType '<' FieldType '>' + { + pdebug("SetType -> tok_set<FieldType>"); + $$ = new t_set($4); + if ($2 != NULL) { + ((t_container*)$$)->set_cpp_name(std::string($2)); + } + } + +ListType: + tok_list '<' FieldType '>' CppType + { + pdebug("ListType -> tok_list<FieldType>"); + $$ = new t_list($3); + if ($5 != NULL) { + ((t_container*)$$)->set_cpp_name(std::string($5)); + } + } + +CppType: + tok_cpp_type tok_literal + { + $$ = $2; + } +| + { + $$ = NULL; + } + +TypeAnnotations: + '(' TypeAnnotationList ')' + { + pdebug("TypeAnnotations -> ( TypeAnnotationList )"); + $$ = $2; + } +| + { + $$ = NULL; + } + +TypeAnnotationList: + TypeAnnotationList TypeAnnotation + { + pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation"); + $$ = $1; + $$->annotations_[$2->key] = $2->val; + delete $2; + } +| + { + /* Just use a dummy structure to hold the annotations. */ + $$ = new t_struct(g_program); + } + +TypeAnnotation: + tok_identifier '=' tok_literal CommaOrSemicolonOptional + { + pdebug("TypeAnnotation -> tok_identifier = tok_literal"); + $$ = new t_annotation; + $$->key = $1; + $$->val = $3; + } + +%% |