thrift/compiler/parse/thrifty.yy (1,119 lines of code) (raw):

%{ /* * 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 <cassert> #include <stdio.h> #include <inttypes.h> #include <limits.h> #include <stack> #include <utility> #include <boost/optional.hpp> #include <thrift/compiler/ast/t_scope.h> #include <thrift/compiler/ast/t_union.h> #include <thrift/compiler/parse/lexer.h> #include <thrift/compiler/parse/parsing_driver.h> #include <thrift/compiler/ast/t_container.h> /** * Note macro expansion because this is different between OSS and internal * build, sigh. */ #include THRIFTY_HH namespace apache { namespace thrift { namespace compiler { namespace { // Assume ownership of a pointer. template <typename T> std::unique_ptr<T> own(T* ptr) { return std::unique_ptr<T>(ptr); } yy::parser::symbol_type parse_lex(parsing_driver& driver, YYSTYPE*, YYLTYPE*) { auto token = driver.get_lexer().get_next_token(); if (token.token() == yy::parser::token::tok_error) { driver.end_parsing(); } return token; } #define yylex apache::thrift::compiler::parse_lex } // namespace } // namespace compiler } // namespace thrift } // namespace apache %} %code requires { #include <thrift/compiler/ast/t_enum_value.h> #include <thrift/compiler/ast/t_exception.h> #include <thrift/compiler/ast/t_function.h> #include <thrift/compiler/ast/t_program.h> #include <thrift/compiler/parse/t_ref.h> namespace apache { namespace thrift { namespace compiler { namespace yy { class location; }}}} /** * YYLTYPE evaluates to a class named 'location', which has: * position begin; * position end; * The class 'position', in turn, has: * std::string* filename; * unsigned line; * unsigned column; */ using YYLTYPE = apache::thrift::compiler::yy::location; using YYSTYPE = int; namespace apache { namespace thrift { namespace compiler { struct t_annotations; struct t_def_attrs; class t_base_type; class t_container; class t_container_type; class t_interaction; class t_service; class t_sink; class t_stream_response; class t_throws; class t_typedef; class t_union; class parsing_driver; using t_docstring = boost::optional<std::string>; using t_struct_annotations = node_list<t_const>; using t_typethrowspair = std::pair<t_type_ref, t_throws*>; } // namespace compiler } // namespace thrift } // namespace apache } %defines %locations %define api.token.constructor %define api.value.type variant %define api.namespace {apache::thrift::compiler::yy} %param {apache::thrift::compiler::parsing_driver& driver} {YYSTYPE * yylval_param} {YYLTYPE * yylloc_param} /** * Strings identifier */ %token<std::string> tok_identifier %token<std::string> tok_literal %token<t_docstring> tok_doctext %token<t_docstring> tok_inline_doc /** * Constant values */ %token<bool> tok_bool_constant %token<uint64_t> tok_int_constant %token<double> tok_dub_constant /** * Characters */ %token tok_char_comma "," %token tok_char_semicolon ";" %token tok_char_bracket_curly_l "{" %token tok_char_bracket_curly_r "}" %token tok_char_equal "=" %token tok_char_bracket_square_l "[" %token tok_char_bracket_square_r "]" %token tok_char_colon ":" %token tok_char_bracket_round_l "(" %token tok_char_bracket_round_r ")" %token tok_char_bracket_angle_l "<" %token tok_char_bracket_angle_r ">" %token tok_char_at_sign "@" %token tok_char_plus "+" %token tok_char_minus "-" /** * Header keywords */ %token tok_include %token tok_cpp_include %token tok_hs_include %token tok_package %token tok_namespace /** * Base datatype keywords */ %token tok_void %token tok_bool %token tok_byte %token tok_string %token tok_binary %token tok_i16 %token tok_i32 %token tok_i64 %token tok_double %token tok_float /** * Complex type keywords */ %token tok_map %token tok_list %token tok_set %token tok_stream %token tok_sink /** * Function qualifiers */ %token tok_oneway %token tok_idempotent %token tok_readonly /** * Exception qualifiers */ %token tok_safe %token tok_transient %token tok_stateful %token tok_permanent %token tok_server %token tok_client /** * Thrift language keywords */ %token tok_typedef %token tok_struct %token tok_exception %token tok_throws %token tok_extends %token tok_service %token tok_enum %token tok_const %token tok_required %token tok_optional %token tok_union %token tok_interaction %token tok_performs %token tok_eof 0 %token tok_error /** * Grammar nodes * * Memory management rules: * - mutable pointers in the process of being build, and * need to be owned when complete. * - t_refs are already owned. */ %type<t_ref<t_base_type>> BaseType %type<t_container*> ContainerType %type<t_container*> MapType %type<t_container*> SetType %type<t_container*> ListType %type<std::string> Identifier %type<std::string> FieldTypeIdentifier %type<t_def_attrs*> StatementAttrs %type<t_header_type> Header %type<t_named*> Definition %type<std::pair<t_statement_type, t_named*>> Statement %type<t_named*> StatementAnnotated %type<t_typedef*> Typedef %type<t_annotation*> Annotation %type<t_annotations*> Annotations %type<t_annotations*> AnnotationList %type<t_const*> StructuredAnnotation %type<t_struct_annotations*> StructuredAnnotations %type<t_struct_annotations*> NonEmptyStructuredAnnotationList %type<t_field*> Field %type<t_field*> FieldAnnotated %type<boost::optional<t_field_id>> FieldId %type<t_field_qualifier> FieldQualifier %type<t_type_ref> FieldType %type<t_stream_response*> StreamReturnType %type<t_sink*> SinkReturnType %type<t_typethrowspair> SinkFieldType %type<t_const_value*> FieldValue %type<t_field_list*> FieldList %type<int64_t> Integer %type<double> Double %type<t_enum*> Enum %type<t_enum_value_list*> EnumValueList %type<t_enum_value*> EnumValue %type<t_enum_value*> EnumValueAnnotated %type<t_const*> Const %type<t_const_value*> ConstValue %type<t_const_value*> ConstList %type<t_const_value*> ConstListContents %type<t_const_value*> ConstMap %type<t_const_value*> ConstMapContents %type<t_const_value*> ConstStruct %type<t_type_ref> ConstStructType %type<t_const_value*> ConstStructContents %type<t_struct*> Struct %type<t_union*> Union %type<t_error_kind> ErrorKind %type<t_error_blame> ErrorBlame %type<t_error_safety> ErrorSafety %type<t_exception*> Exception %type<t_service*> Service %type<t_interaction*> Interaction %type<t_function*> Function %type<t_function*> FunctionAnnotated %type<t_function*> Performs %type<std::pair<t_type_ref, boost::optional<t_type_ref>>> FunctionType %type<t_function_list*> FunctionList %type<t_throws*> MaybeThrows %type<t_ref<t_service>> Extends %type<t_function_qualifier> FunctionQualifier %type<t_docstring> CaptureDocText %type<t_docstring> InlineDocOptional %type<std::string> IntOrLiteral %type<bool> CommaOrSemicolonOptional %% /** * 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: StatementList { driver.debug("Program -> StatementList"); driver.clear_doctext(); } /** * This rule is to avoid keywords as exceptions in field type identifiers. * This allows to avoid shift-reduce conflicts due to a previous ambuguity * in the resolution of the FunctionQualifier FunctionType part of the * Function rule, when one of the tok_oneway, tok_idempotent or tok_readonly * is encountered. It could either resolve the token as FunctionQualifier or * resolve "" as FunctionQualifier and resolve the token as FunctionType. */ FieldTypeIdentifier: tok_identifier { $$ = std::move($1); } Identifier: FieldTypeIdentifier { $$ = std::move($1); } /* context sensitive keywords that should be allowed in identifiers. */ | tok_package { $$ = "package"; } | tok_sink { $$ = "sink"; } | tok_oneway { $$ = "oneway"; } | tok_readonly { $$ = "readonly"; } | tok_idempotent { $$ = "idempotent"; } | tok_safe { $$ = "safe"; } | tok_transient { $$ = "transient"; } | tok_stateful { $$ = "stateful"; } | tok_permanent { $$ = "permanent"; } | tok_server { $$ = "server"; } | tok_client { $$ = "client"; } CommaOrSemicolon: "," {} | ";" {} CommaOrSemicolonOptional: CommaOrSemicolon { $$ = true; } | { $$ = false; } CaptureDocText: { $$ = driver.pop_doctext(); } ProgramDocText: { /* when there is any doctext, assign it to the top level `program` */ driver.set_doctext(*driver.program, driver.pop_doctext()); } InlineDocOptional: tok_inline_doc { driver.debug("Inline doc"); $$ = driver.strip_doctext($1->c_str()); } | { $$ = boost::none; } Header: tok_include tok_literal { driver.debug("Header -> tok_include tok_literal"); driver.add_include(std::move($2)); $$ = t_header_type::standard; } | tok_package tok_literal { driver.debug("Header -> tok_package tok_literal"); driver.set_package(std::move($2)); $$ = t_header_type::program; } | tok_namespace Identifier Identifier { driver.debug("Header -> tok_namespace Identifier Identifier"); if (driver.mode == parsing_mode::PROGRAM) { driver.program->set_namespace(std::move($2), std::move($3)); } $$ = t_header_type::standard; } | tok_namespace Identifier tok_literal { driver.debug("Header -> tok_namespace Identifier tok_literal"); if (driver.mode == parsing_mode::PROGRAM) { driver.program->set_namespace(std::move($2), std::move($3)); } $$ = t_header_type::standard; } | tok_cpp_include tok_literal { driver.debug("Header -> tok_cpp_include tok_literal"); if (driver.mode == parsing_mode::PROGRAM) { driver.program->add_cpp_include($2); } $$ = t_header_type::standard; } | tok_hs_include tok_literal { driver.debug("Header -> tok_hs_include tok_literal"); // Do nothing. This syntax is handled by the hs compiler $$ = t_header_type::standard; } Definition: Typedef { $$ = $1; } | Enum { $$ = $1; } | Const { $$ = $1; } | Struct { $$ = $1; } | Union { $$ = $1; } | Exception { $$ = $1; } | Service { $$ = $1; } | Interaction { $$ = $1; } Statement: ProgramDocText Header { driver.debug("Statement -> ProgramDocText Header"); driver.validate_header_location(); $$ = std::make_pair(static_cast<t_statement_type>($2), nullptr); } | Definition { driver.debug("Statement -> Definition"); driver.set_parsed_definition(); $$ = std::make_pair(t_statement_type::definition, $1); } StatementAnnotated: StatementAttrs Statement Annotations { driver.debug("StatementAnnotated -> StatementAttrs Statement Annotations"); switch ($2.first) { case t_statement_type::standard_header: driver.validate_header_annotations(own($1), own($3)); $$ = nullptr; break; case t_statement_type::program_header: driver.set_program_annotations(own($1), own($3), @$); $$ = nullptr; break; case t_statement_type::definition: driver.avoid_tokens_loc(@$, {{$1 == nullptr, @2}}, {{$3 == nullptr, @2}}); $$ = $2.second; driver.set_attributes(*$$, own($1), own($3), @$); } } StatementAttrs: CaptureDocText StructuredAnnotations { driver.debug("StatementAttrs -> CaptureDocText StructuredAnnotations"); $$ = nullptr; if ($1 || $2 != nullptr) { driver.avoid_tokens_loc(@$, {{!$1, @2}}, {}); $$ = new t_def_attrs{std::move($1), own($2)}; } } StatementList: StatementList StatementAnnotated CommaOrSemicolonOptional { driver.debug("StatementList -> StatementList StatementAnnotated " "CommaOrSemicolonOptional"); if ($2 != nullptr) { driver.add_def(own($2)); } } | { driver.debug("StatementList -> "); } Integer: tok_int_constant { driver.debug("Integer -> tok_int_constant"); $$ = driver.to_int($1); } | tok_char_plus tok_int_constant { driver.debug("Integer -> + tok_int_constant"); $$ = driver.to_int($2); } | tok_char_minus tok_int_constant { driver.debug("Integer -> - tok_int_constant"); $$ = driver.to_int($2, true); } Double: tok_dub_constant { driver.debug("Double -> tok_dub_constant"); $$ = $1; } | tok_char_plus tok_dub_constant { driver.debug("Double -> + tok_dub_constant"); $$ = $2; } | tok_char_minus tok_dub_constant { driver.debug("Double -> - tok_dub_constant"); $$ = -$2; } Typedef: tok_typedef FieldType Identifier { driver.debug("TypeDef => tok_typedef FieldType Identifier"); $$ = new t_typedef(driver.program, std::move($3), std::move($2)); $$->set_lineno(@3.end.line); } Enum: tok_enum Identifier "{" EnumValueList "}" { driver.debug("Enum => tok_enum Identifier { EnumValueList }"); $$ = new t_enum(driver.program, std::move($2)); $$->set_values(std::move(*own($4))); $$->set_lineno(@2.end.line); } EnumValueList: EnumValueList EnumValueAnnotated CommaOrSemicolonOptional InlineDocOptional { driver.debug("EnumValueList EnumValueAnnotated CommaOrSemicolonOptional"); $$ = $1; if ($4 != boost::none) { driver.set_doctext(*$2, $4); } $$->emplace_back(own($2)); } | { driver.debug("EnumValueList -> "); $$ = new t_enum_value_list; } EnumValueAnnotated: StatementAttrs EnumValue Annotations { driver.debug("StatementAttrs EnumValue Annotations"); driver.avoid_tokens_loc(@$, {{$1 == nullptr, @2}}, {{$3 == nullptr, @2}}); $$ = $2; driver.set_attributes(*$$, own($1), own($3), @$); } EnumValue: Identifier "=" Integer { driver.debug("EnumValue -> Identifier = Integer"); $$ = new t_enum_value(std::move($1)); $$->set_value(driver.to_enum_value($3)); $$->set_lineno(@1.end.line); } | Identifier { driver.debug("EnumValue -> Identifier"); $$ = new t_enum_value(std::move($1)); $$->set_lineno(@1.end.line); } Const: tok_const FieldType Identifier "=" ConstValue { driver.debug("Const => tok_const FieldType Identifier = ConstValue"); $$ = new t_const(driver.program, std::move($2), std::move($3), own($5)); $$->set_lineno(@3.end.line); } ConstValue: tok_bool_constant { driver.debug("ConstValue => tok_bool_constant"); $$ = new t_const_value(); $$->set_bool($1); } | Integer { driver.debug("ConstValue => Integer"); $$ = driver.to_const_value($1).release(); } | Double { driver.debug("ConstValue => Double"); $$ = new t_const_value(); $$->set_double($1); } | tok_literal { driver.debug("ConstValue => tok_literal"); $$ = new t_const_value($1); } | Identifier { driver.debug("ConstValue => Identifier"); $$ = driver.copy_const_value($1).release(); } | ConstList { driver.debug("ConstValue => ConstList"); $$ = $1; } | ConstMap { driver.debug("ConstValue => ConstMap"); $$ = $1; } | ConstStruct { driver.debug("ConstValue => ConstStruct"); $$ = $1; } ConstList: "[" ConstListContents CommaOrSemicolonOptional "]" { driver.debug("ConstList => [ ConstListContents CommaOrSemicolonOptional ]"); $$ = $2; } | "[" "]" { driver.debug("ConstList => [ ]"); $$ = new t_const_value(); $$->set_list(); } ConstListContents: ConstListContents CommaOrSemicolon ConstValue { driver.debug("ConstListContents => ConstListContents CommaOrSemicolon ConstValue"); $$ = $1; $$->add_list(own($3)); } | ConstValue { driver.debug("ConstListContents => ConstValue"); $$ = new t_const_value(); $$->set_list(); $$->add_list(own($1)); } ConstMap: "{" ConstMapContents CommaOrSemicolonOptional "}" { driver.debug("ConstMap => { ConstMapContents CommaOrSemicolonOptional }"); $$ = $2; } | "{" "}" { driver.debug("ConstMap => { }"); $$ = new t_const_value(); $$->set_map(); } ConstMapContents: ConstMapContents CommaOrSemicolon ConstValue ":" ConstValue { driver.debug("ConstMapContents => ConstMapContents CommaOrSemicolon ConstValue : ConstValue"); $$ = $1; $$->add_map(own($3), own($5)); } | ConstValue ":" ConstValue { driver.debug("ConstMapContents => ConstValue : ConstValue"); $$ = new t_const_value(); $$->set_map(); $$->add_map(own($1), own($3)); } ConstStruct: ConstStructType "{" ConstStructContents CommaOrSemicolonOptional "}" { driver.debug("ConstStruct => ConstStructType { ConstStructContents CommaOrSemicolonOptional }"); $$ = $3; $$->set_ttype($1); } | ConstStructType "{" "}" { driver.debug("ConstStruct => ConstStructType { }"); $$ = new t_const_value(); $$->set_map(); $$->set_ttype($1); } ConstStructType: Identifier { driver.debug("ConstStructType -> Identifier"); $$ = driver.new_type_ref(std::move($1), nullptr, /*is_const=*/true); } ConstStructContents: ConstStructContents CommaOrSemicolon Identifier "=" ConstValue { driver.debug("ConstStructContents => ConstStructContents CommaOrSemicolon Identifier = ConstValue"); $$ = $1; $$->add_map(std::make_unique<t_const_value>($3), own($5)); } | Identifier "=" ConstValue { driver.debug("ConstStructContents => Identifier = ConstValue"); $$ = new t_const_value(); $$->set_map(); $$->add_map(std::make_unique<t_const_value>($1), own($3)); } Struct: tok_struct Identifier "{" FieldList "}" { driver.debug("Struct => tok_struct Identifier { FieldList }"); $$ = new t_struct(driver.program, std::move($2)); driver.set_fields(*$$, std::move(*own($4))); $$->set_lineno(@2.end.line); } Union: tok_union Identifier "{" FieldList "}" { driver.debug("Union => tok_union Identifier { FieldList }"); $$ = new t_union(driver.program, std::move($2)); driver.set_fields(*$$, std::move(*own($4))); $$->set_lineno(@2.end.line); } Exception: // TODO(afuller): Either make the qualifiers order agnostic or produce a better error message. ErrorSafety ErrorKind ErrorBlame tok_exception Identifier "{" FieldList "}" { driver.debug("Exception => ErrorSafety ErrorKind ErrorBlame tok_exception " "Identifier { FieldList }"); // TODO(afuller): Correct resulting source_loc.begin when safety qualifier is omitted. $$ = new t_exception(driver.program, std::move($5)); $$->set_safety($1); $$->set_kind($2); $$->set_blame($3); driver.set_fields(*$$, std::move(*own($7))); $$->set_lineno(@5.end.line); } ErrorSafety: tok_safe { $$ = t_error_safety::safe;} | { $$ = {}; } ErrorKind: tok_transient { $$ = t_error_kind::transient; } | tok_stateful { $$ = t_error_kind::stateful; } | tok_permanent { $$ = t_error_kind::permanent; } | { $$ = {}; } ErrorBlame: tok_client { $$ = t_error_blame::client; } | tok_server { $$ = t_error_blame::server; } | { $$ = {}; } Service: tok_service Identifier Extends "{" FunctionList "}" { driver.debug("Service => tok_service Identifier Extends { FunctionList }"); $$ = new t_service(driver.program, std::move($2), $3); driver.set_functions(*$$, own($5)); $$->set_lineno(@2.end.line); } Extends: tok_extends Identifier { driver.debug("Extends -> tok_extends Identifier"); $$ = driver.find_service($2); } | { $$ = nullptr; } Interaction: tok_interaction Identifier "{" FunctionList "}" { driver.debug("Interaction -> tok_interaction Identifier { FunctionList }"); $$ = new t_interaction(driver.program, std::move($2)); driver.set_functions(*$$, own($4)); $$->set_lineno(@2.end.line); } FunctionList: FunctionList FunctionAnnotated CommaOrSemicolonOptional { driver.debug("FunctionList -> FunctionList FunctionAnnotated CommaOrSemicolonOptional"); $1->emplace_back(own($2)); $$ = $1; } | FunctionList Performs CommaOrSemicolon { driver.debug("FunctionList -> FunctionList Performs CommaOrSemicolon"); $1->emplace_back(own($2)); $$ = $1; } | { driver.debug("FunctionList -> "); $$ = new t_function_list; } Function: FunctionQualifier FunctionType Identifier "(" FieldList ")" MaybeThrows { driver.debug("Function => FunctionQualifier FunctionType Identifier ( FieldList ) MaybeThrows"); driver.avoid_tokens_loc( @$, {{$1 == t_function_qualifier::unspecified, @2}}, {{$7 == nullptr, @6}}); $$ = new t_function(driver.program, std::move($2.first), std::move($3)); if ($2.second) { $$->set_returned_interaction(std::move(*$2.second)); } $$->set_qualifier($1); driver.set_fields($$->params(), std::move(*own($5))); $$->set_exceptions(own($7)); $$->set_lineno(@3.end.line); // TODO(afuller): Leave the param list unnamed. $$->params().set_name($$->name() + "_args"); } FunctionAnnotated: StatementAttrs Function Annotations { driver.debug("FunctionAnnotated => StatementAttrs Function Annotations"); driver.avoid_tokens_loc(@$, {{$1 == nullptr, @2}}, {{$3 == nullptr, @2}}); $$ = $2; driver.set_attributes(*$$, own($1), own($3), @$); } Performs: tok_performs FieldType { driver.debug("Performs => tok_performs FieldType"); auto& ret = $2; std::string name = ret.get_type() ? "create" + ret.get_type()->get_name() : "<interaction placeholder>"; $$ = new t_function( std::move(ret), std::move(name), std::make_unique<t_paramlist>(driver.program) ); $$->set_lineno(driver.get_lexer().lineno()); $$->set_is_interaction_constructor(); } FunctionQualifier: tok_oneway { $$ = t_function_qualifier::one_way; } | tok_idempotent { $$ = t_function_qualifier::idempotent; } | tok_readonly { $$ = t_function_qualifier::read_only; } | { $$ = {}; } MaybeThrows: tok_throws "(" FieldList ")" { driver.debug("MaybeThrows -> tok_throws ( FieldList )"); $$ = driver.new_throws(own($3)).release(); } | { $$ = nullptr; } FieldList: FieldList FieldAnnotated CommaOrSemicolonOptional InlineDocOptional { driver.debug("FieldList -> FieldAnnotated CommaOrSemicolonOptional"); $$ = $1; if ($4 != boost::none) { driver.set_doctext(*$2, $4); } $$->emplace_back($2); } | { driver.debug("FieldList -> "); $$ = new t_field_list; } Field: FieldId FieldQualifier FieldType Identifier FieldValue { driver.debug("Field => FieldId FieldQualifier FieldType Identifier FieldValue"); driver.avoid_tokens_loc(@$, {}, {{$5 == nullptr, @4}}); $$ = new t_field(std::move($3), std::move($4), $1.value_or(0), $1 != boost::none); $$->set_qualifier($2); $$->set_default_value(own($5)); $$->set_lineno(@4.end.line); } FieldAnnotated: StatementAttrs Field Annotations { driver.debug("FieldAnnotated => StatementAttrs Field Annotations"); driver.avoid_tokens_loc(@$, {{$1 == nullptr, @2}}, {{$3 == nullptr, @2}}); $$ = $2; driver.set_attributes(*$$, own($1), own($3), @$); } FieldId: Integer ":" { $$ = driver.to_field_id($1); } | { $$ = boost::none; } FieldQualifier: tok_required { $$ = t_field_qualifier::required; } | tok_optional { $$ = t_field_qualifier::optional; } | { $$ = {}; } FieldValue: "=" ConstValue { if (driver.mode == parsing_mode::PROGRAM) { $$ = $2; } else { delete $2; $$ = nullptr; } } | { $$ = nullptr; } FunctionType: StreamReturnType { driver.debug("FunctionType -> StreamReturnType"); $$ = {driver.new_type_ref(own($1), nullptr), boost::none}; } | FieldType "," StreamReturnType { driver.debug("FunctionType -> FieldType, StreamReturnType"); // This might actually be an interaction, corrected in standard mutator. $3->set_first_response_type(std::move($1)); $$ = {driver.new_type_ref(own($3), nullptr), boost::none}; } | FieldType "," FieldType "," StreamReturnType { driver.debug("FunctionType -> FieldType, FieldType, StreamReturnType"); $5->set_first_response_type(std::move($3)); $$ = {driver.new_type_ref(own($5), nullptr), $1}; } | SinkReturnType { driver.debug("FunctionType -> SinkReturnType"); $$ = {driver.new_type_ref(own($1), nullptr), boost::none}; } | FieldType "," SinkReturnType { driver.debug("FunctionType -> FieldType, SinkReturnType"); // This might actually be an interaction, corrected in standard mutator. $3->set_first_response_type(std::move($1)); $$ = {driver.new_type_ref(own($3), nullptr), boost::none}; } | FieldType "," FieldType "," SinkReturnType { driver.debug("FunctionType -> FieldType, FieldType, SinkReturnType"); $5->set_first_response_type(std::move($3)); $$ = {driver.new_type_ref(own($5), nullptr), $1}; } | FieldType { driver.debug("FunctionType -> FieldType"); // This might actually be an interaction, corrected in standard mutator. $$ = {$1, boost::none}; } | FieldType "," FieldType { driver.debug("FunctionType -> FieldType, FieldType"); $$ = {$3, $1}; } | tok_void { driver.debug("FunctionType -> tok_void"); $$ = {t_base_type::t_void(), boost::none}; } StreamReturnType: tok_stream "<" FieldType MaybeThrows ">" { driver.debug("StreamReturnType -> tok_stream < FieldType MaybeThrows >"); auto stream_res = std::make_unique<t_stream_response>(std::move($3)); stream_res->set_exceptions(own($4)); $$ = stream_res.release(); } SinkReturnType: tok_sink "<" SinkFieldType "," SinkFieldType ">" { driver.debug("SinkReturnType -> tok_sink<FieldType, FieldType>"); auto sink = std::make_unique<t_sink>(std::move($3.first), std::move($5.first)); sink->set_sink_exceptions(own($3.second)); sink->set_final_response_exceptions(own($5.second)); $$ = sink.release(); } SinkFieldType: FieldType MaybeThrows { driver.debug("SinkFieldType => FieldType MaybeThrows"); $$ = std::make_pair($1, $2); } FieldType: FieldTypeIdentifier Annotations { driver.debug("FieldType => Identifier Annotations"); $$ = driver.new_type_ref(std::move($1), own($2)); } | BaseType Annotations { driver.debug("FieldType -> BaseType"); $$ = driver.new_type_ref(*$1, own($2)); } | ContainerType Annotations { driver.debug("FieldType -> ContainerType"); $$ = driver.new_type_ref(own($1), own($2)); } BaseType: tok_string { driver.debug("BaseType -> tok_string"); $$ = &t_base_type::t_string(); } | tok_binary { driver.debug("BaseType -> tok_binary"); $$ = &t_base_type::t_binary(); } | tok_bool { driver.debug("BaseType -> tok_bool"); $$ = &t_base_type::t_bool(); } | tok_byte { driver.debug("BaseType -> tok_byte"); $$ = &t_base_type::t_byte(); } | tok_i16 { driver.debug("BaseType -> tok_i16"); $$ = &t_base_type::t_i16(); } | tok_i32 { driver.debug("BaseType -> tok_i32"); $$ = &t_base_type::t_i32(); } | tok_i64 { driver.debug("BaseType -> tok_i64"); $$ = &t_base_type::t_i64(); } | tok_double { driver.debug("BaseType -> tok_double"); $$ = &t_base_type::t_double(); } | tok_float { driver.debug("BaseType -> tok_float"); $$ = &t_base_type::t_float(); } ContainerType: MapType { $$ = $1; } | SetType { $$ = $1; } | ListType { $$ = $1; } MapType: tok_map "<" FieldType "," FieldType ">" { driver.debug("MapType -> tok_map<FieldType, FieldType>"); $$ = new t_map(std::move($3), std::move($5)); } SetType: tok_set "<" FieldType ">" { driver.debug("SetType -> tok_set<FieldType>"); $$ = new t_set(std::move($3)); } ListType: tok_list "<" FieldType ">" { driver.debug("ListType -> tok_list<FieldType>"); $$ = new t_list(std::move($3)); } Annotations: "(" AnnotationList CommaOrSemicolonOptional ")" { driver.debug("Annotations => ( AnnotationList CommaOrSemicolonOptional)"); $$ = $2; } | "(" ")" { driver.debug("Annotations => ( )"); $$ = nullptr; } | { $$ = nullptr; } AnnotationList: AnnotationList CommaOrSemicolon Annotation { driver.debug("NodeAnnotationList => NodeAnnotationList CommaOrSemicolon Annotation"); $$ = $1; $$->strings[$3->first] = std::move($3->second); delete $3; } | Annotation { driver.debug("AnnotationList => Annotation"); /* Just use a dummy structure to hold the annotations. */ $$ = new t_annotations(); $$->strings[$1->first] = std::move($1->second); delete $1; } Annotation: Identifier "=" IntOrLiteral { driver.debug("Annotation -> Identifier = IntOrLiteral"); $$ = new t_annotation{$1, {driver.get_source_range(@$), $3}}; } | Identifier { driver.debug("Annotation -> Identifier"); $$ = new t_annotation{$1, {driver.get_source_range(@$), "1"}}; } StructuredAnnotations: NonEmptyStructuredAnnotationList { driver.debug("StructuredAnnotations -> NonEmptyStructuredAnnotationList"); $$ = $1; } | { $$ = nullptr; } NonEmptyStructuredAnnotationList: NonEmptyStructuredAnnotationList StructuredAnnotation { driver.debug("NonEmptyStructuredAnnotationList -> NonEmptyStructuredAnnotationList StructuredAnnotation"); $$ = $1; $$->emplace_back($2); } | StructuredAnnotation { driver.debug("NonEmptyStructuredAnnotationList ->"); $$ = new t_struct_annotations; $$->emplace_back($1); } StructuredAnnotation: "@" ConstStruct { driver.debug("StructuredAnnotation => @ConstStruct"); $$ = driver.new_struct_annotation(own($2)).release(); } | "@" ConstStructType { driver.debug("StructuredAnnotation => @ConstStructType"); auto value = std::make_unique<t_const_value>(); value->set_map(); value->set_ttype(std::move($2)); $$ = driver.new_struct_annotation(std::move(value)).release(); } IntOrLiteral: tok_literal { driver.debug("IntOrLiteral -> tok_literal"); $$ = $1; } | tok_bool_constant { char buf[21]; // max len of int64_t as string + null terminator driver.debug("IntOrLiteral -> tok_bool_constant"); sprintf(buf, "%" PRIi32, $1 ? 1 : 0); $$ = buf; } | Integer { char buf[21]; // max len of int64_t as string + null terminator driver.debug("IntOrLiteral -> Integer"); sprintf(buf, "%" PRIi64, $1); $$ = buf; } %% /** * Method that will be called by the generated parser upon errors. */ void apache::thrift::compiler::yy::parser::error(const location_type&, std::string const& message) { /* * TODO(urielrivas): Pass the location as argument to yyerror. */ driver.yyerror(message); }