diff options
author | Nick Zolnierz <nicholas.zolnierz@mongodb.com> | 2020-07-07 16:58:11 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-07-08 15:27:48 +0000 |
commit | 4fc14ec5933feb9b5c1e9a4aa7203d76a685b28b (patch) | |
tree | 75107158f04f75b4ba2aad6dcae2d1b2f7b14922 /src/mongo/db/cst | |
parent | 8b4cd661c63d676e212f659096eaa4d5722cc49d (diff) | |
download | mongo-4fc14ec5933feb9b5c1e9a4aa7203d76a685b28b.tar.gz |
SERVER-48788 Add barebones bison grammar and BSON lexer for aggregation pipeline language
Diffstat (limited to 'src/mongo/db/cst')
-rw-r--r-- | src/mongo/db/cst/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/cst/bson_lexer.cpp | 153 | ||||
-rw-r--r-- | src/mongo/db/cst/bson_lexer.h | 74 | ||||
-rw-r--r-- | src/mongo/db/cst/c_node.h | 4 | ||||
-rw-r--r-- | src/mongo/db/cst/cst_test.cpp | 60 | ||||
-rw-r--r-- | src/mongo/db/cst/key_fieldname.h | 3 | ||||
-rw-r--r-- | src/mongo/db/cst/location_gen.h | 267 | ||||
-rw-r--r-- | src/mongo/db/cst/pipeline_grammar.yy | 144 | ||||
-rw-r--r-- | src/mongo/db/cst/pipeline_parser_gen.cpp | 888 | ||||
-rw-r--r-- | src/mongo/db/cst/pipeline_parser_gen.hpp | 1304 |
10 files changed, 2899 insertions, 1 deletions
diff --git a/src/mongo/db/cst/SConscript b/src/mongo/db/cst/SConscript index e872e618cab..64a446694b9 100644 --- a/src/mongo/db/cst/SConscript +++ b/src/mongo/db/cst/SConscript @@ -7,9 +7,12 @@ env = env.Clone() env.Library( target='cst', source=[ + 'bson_lexer.cpp', 'c_node.cpp', + 'pipeline_parser_gen.cpp', ], LIBDEPS=[ + "$BUILD_DIR/mongo/base", ] ) diff --git a/src/mongo/db/cst/bson_lexer.cpp b/src/mongo/db/cst/bson_lexer.cpp new file mode 100644 index 00000000000..1e2941bd701 --- /dev/null +++ b/src/mongo/db/cst/bson_lexer.cpp @@ -0,0 +1,153 @@ +/** + * Copyright (C) 2020-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/cst/bson_lexer.h" +#include "mongo/db/cst/pipeline_parser_gen.hpp" +#include "mongo/util/string_map.h" + +namespace mongo { + +namespace { + +// Structure to annotate reserved tokens, used to hint the lexer into behavior once the token is +// seen. There are no semantic values associated with these tokens. +struct KeywordToken { + boost::optional<PipelineParserGen::token_type> type; + bool traverseChild; + bool orderedArguments; +}; + +// Mapping of reserved keywords to BSON token. Any key which is not included in this map is treated +// as a terminal. +const StringMap<KeywordToken> reservedKeyLookup = { + {"$_internalInhibitOptimization", + { + PipelineParserGen::token::STAGE_INHIBIT_OPTIMIZATION, + false /* traverseChild */, + false /* orderedArguments */ + }}, +}; + +} // namespace + +void BSONLexer::tokenize(BSONElement elem, bool includeFieldName) { + // The rules for tokenizing element field names fall into two buckets: + // 1. It matches a reserved keyword or operator. In this case, the traversal rules and + // sensitivity to ordered nested arguments is dictated by the annotation in the lookup + // table. + // 2. It is not a reserved keyword and thus is treated as a STRING literal token. The + // traversal rules for such elements is always to traverse but ignore argument order if the + // value is an object. + KeywordToken fieldNameToken = [&] { + if (includeFieldName) { + if (auto it = reservedKeyLookup.find(elem.fieldNameStringData()); + it != reservedKeyLookup.end()) { + _tokens.emplace_back(*it->second.type, getNextLoc()); + return it->second; + } else { + _tokens.emplace_back( + PipelineParserGen::make_STRING(elem.fieldName(), getNextLoc())); + return KeywordToken{.type = PipelineParserGen::token::STRING, + .traverseChild = true, + .orderedArguments = false}; + } + } + return KeywordToken{.type = boost::none, .traverseChild = true, .orderedArguments = false}; + }(); + + switch (elem.type()) { + case BSONType::Object: + if (fieldNameToken.orderedArguments) { + _tokens.emplace_back(PipelineParserGen::token::START_ORDERED_OBJECT, getNextLoc()); + BSONObjIteratorSorted sortedIt(elem.embeddedObject()); + while (sortedIt.more()) { + tokenize(sortedIt.next(), true); + } + _tokens.emplace_back(PipelineParserGen::token::END_ORDERED_OBJECT, getNextLoc()); + } else { + _tokens.emplace_back(PipelineParserGen::token::START_OBJECT, getNextLoc()); + for (auto&& nestedElem : elem.embeddedObject()) { + tokenize(nestedElem, true); + } + _tokens.emplace_back(PipelineParserGen::token::END_OBJECT, getNextLoc()); + } + break; + case BSONType::Array: + _tokens.emplace_back(PipelineParserGen::token::START_ARRAY, getNextLoc()); + for (auto&& nestedElem : elem.Array()) { + // For arrays, do not tokenize the field names. + tokenize(nestedElem, false); + } + _tokens.emplace_back(PipelineParserGen::token::END_ARRAY, getNextLoc()); + break; + case BSONType::String: + _tokens.emplace_back(PipelineParserGen::make_STRING(elem.String(), getNextLoc())); + break; + case NumberLong: + _tokens.emplace_back( + PipelineParserGen::make_NUMBER_LONG(elem.numberLong(), getNextLoc())); + break; + case NumberInt: + _tokens.emplace_back( + PipelineParserGen::make_NUMBER_INT(elem.numberInt(), getNextLoc())); + break; + case NumberDouble: + _tokens.emplace_back( + PipelineParserGen::make_NUMBER_DOUBLE(elem.numberDouble(), getNextLoc())); + break; + case Bool: + _tokens.emplace_back(PipelineParserGen::make_BOOL(elem.boolean(), getNextLoc())); + break; + default: + MONGO_UNREACHABLE; + } +} + +BSONLexer::BSONLexer(std::vector<BSONElement> pipeline) { + _tokens.emplace_back(PipelineParserGen::token::START_ARRAY, getNextLoc()); + for (auto&& elem : pipeline) { + // Don't include field names for stages of the pipeline (aka indexes of the pipeline array). + tokenize(elem, false); + } + _tokens.emplace_back(PipelineParserGen::token::END_ARRAY, getNextLoc()); + + // Final token must indicate EOF. + _tokens.emplace_back(PipelineParserGen::make_END_OF_FILE(getNextLoc())); + + // Reset the position to use in yylex(). + _position = 0; +}; + +PipelineParserGen::symbol_type yylex(mongo::BSONLexer& lexer) { + return lexer.getNext(); +} + +} // namespace mongo diff --git a/src/mongo/db/cst/bson_lexer.h b/src/mongo/db/cst/bson_lexer.h new file mode 100644 index 00000000000..cbd735aae5b --- /dev/null +++ b/src/mongo/db/cst/bson_lexer.h @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2020-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include <sstream> +#include <string> +#include <vector> + +#include "mongo/bson/bsonobj.h" +#include "mongo/db/cst/pipeline_parser_gen.hpp" + +namespace mongo { + +class BSONLexer { +public: + explicit BSONLexer(std::vector<BSONElement> input); + + /** + * Retrieves the next token in the stream. + */ + PipelineParserGen::symbol_type getNext() { + return _tokens[_position++]; + } + +private: + // Tokenizes the given BSONElement, traversing its children if necessary. If the field name + // should not be considered, set 'includeFieldName' to false. + void tokenize(BSONElement elem, bool includeFieldName); + + PipelineParserGen::location_type getNextLoc() { + auto loc = PipelineParserGen::location_type{nullptr, _position, _position}; + _position++; + return loc; + } + + // Track the position of the input, both during construction of the list of tokens as well as + // during parse. + int _position = 0; + + std::vector<PipelineParserGen::symbol_type> _tokens; +}; + +// This is the entry point for retrieving the next token from the lexer, invoked from Bison's +// yyparse(). +PipelineParserGen::symbol_type yylex(mongo::BSONLexer& lexer); + +} // namespace mongo diff --git a/src/mongo/db/cst/c_node.h b/src/mongo/db/cst/c_node.h index d7c062cd9b1..0d0e717ab84 100644 --- a/src/mongo/db/cst/c_node.h +++ b/src/mongo/db/cst/c_node.h @@ -46,6 +46,10 @@ using UserDouble = double; using UserString = std::string; struct CNode { + static auto noopLeaf() { + return CNode{Children{}}; + } + auto toString() const { return toStringHelper(0); } diff --git a/src/mongo/db/cst/cst_test.cpp b/src/mongo/db/cst/cst_test.cpp index 80117ecc389..ce4a20f3f81 100644 --- a/src/mongo/db/cst/cst_test.cpp +++ b/src/mongo/db/cst/cst_test.cpp @@ -32,9 +32,12 @@ #include <iostream> #include <string> +#include "mongo/bson/json.h" +#include "mongo/db/cst/bson_lexer.h" #include "mongo/db/cst/c_node.h" #include "mongo/db/cst/key_fieldname.h" #include "mongo/db/cst/key_value.h" +#include "mongo/db/cst/pipeline_parser_gen.hpp" #include "mongo/db/query/util/make_data_structure.h" #include "mongo/unittest/unittest.h" @@ -62,5 +65,62 @@ TEST(CstTest, BuildsAndPrints) { } } +TEST(CstGrammarTest, EmptyPipeline) { + CNode output; + auto input = fromjson("{pipeline: []}"); + BSONLexer lexer(input["pipeline"].Array()); + auto parseTree = PipelineParserGen(lexer, &output); + ASSERT_EQ(0, parseTree.parse()); + ASSERT_TRUE(stdx::get_if<CNode::Children>(&output.payload)); + ASSERT_EQ(0, stdx::get_if<CNode::Children>(&output.payload)->size()); +} + +TEST(CstGrammarTest, InvalidPipelineSpec) { + { + CNode output; + auto input = fromjson("{pipeline: [{}]}"); + BSONLexer lexer(input["pipeline"].Array()); + auto parseTree = PipelineParserGen(lexer, &output); + ASSERT_EQ(1, parseTree.parse()); + } + { + CNode output; + auto input = fromjson("{pipeline: [{$unknownStage: {}}]}"); + BSONLexer lexer(input["pipeline"].Array()); + auto parseTree = PipelineParserGen(lexer, &output); + ASSERT_EQ(1, parseTree.parse()); + } + { + ASSERT_THROWS_CODE( + [] { + CNode output; + auto input = fromjson("{pipeline: 'not an array'}"); + BSONLexer lexer(input["pipeline"].Array()); + }(), + AssertionException, + 13111); + } +} + +TEST(CstGrammarTest, ParsesInternalInhibitOptimization) { + { + CNode output; + auto input = fromjson("{pipeline: [{$_internalInhibitOptimization: {}}]}"); + BSONLexer lexer(input["pipeline"].Array()); + auto parseTree = PipelineParserGen(lexer, &output); + ASSERT_EQ(0, parseTree.parse()); + auto stages = stdx::get<CNode::Children>(output.payload); + ASSERT_EQ(1, stages.size()); + ASSERT(KeyFieldname::inhibitOptimization == stdx::get<KeyFieldname>(stages[0].first)); + } + { + CNode output; + auto input = fromjson("{pipeline: [{$_internalInhibitOptimization: 'invalid'}]}"); + BSONLexer lexer(input["pipeline"].Array()); + auto parseTree = PipelineParserGen(lexer, &output); + ASSERT_EQ(1, parseTree.parse()); + } +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/cst/key_fieldname.h b/src/mongo/db/cst/key_fieldname.h index 9f852bf82fc..2ddb692b6b0 100644 --- a/src/mongo/db/cst/key_fieldname.h +++ b/src/mongo/db/cst/key_fieldname.h @@ -37,7 +37,8 @@ ENUMIFY(arrayMarker) \ ENUMIFY(atan2) \ ENUMIFY(id) \ - ENUMIFY(project) + ENUMIFY(project) \ + ENUMIFY(inhibitOptimization) MAKE_PRINTABLE_ENUM(KeyFieldname, KEYFIELDNAMES); MAKE_PRINTABLE_ENUM_STRING_ARRAY(key_fieldname, KeyFieldname, KEYFIELDNAMES); diff --git a/src/mongo/db/cst/location_gen.h b/src/mongo/db/cst/location_gen.h new file mode 100644 index 00000000000..7a3a880671c --- /dev/null +++ b/src/mongo/db/cst/location_gen.h @@ -0,0 +1,267 @@ +// A Bison parser, made by GNU Bison 3.5.4. + +// Locations for Bison parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +/** + ** \file src/mongo/db/cst/location_gen.h + ** Define the mongo::location class. + */ + +#ifndef YY_YY_SRC_MONGO_DB_CST_LOCATION_GEN_H_INCLUDED +#define YY_YY_SRC_MONGO_DB_CST_LOCATION_GEN_H_INCLUDED + +#include <iostream> +#include <string> + +#ifndef YY_NULLPTR +#if defined __cplusplus +#if 201103L <= __cplusplus +#define YY_NULLPTR nullptr +#else +#define YY_NULLPTR 0 +#endif +#else +#define YY_NULLPTR ((void*)0) +#endif +#endif + +#line 52 "src/mongo/db/cst/pipeline_grammar.yy" +namespace mongo { +#line 59 "src/mongo/db/cst/location_gen.h" + +/// A point in a source file. +class position { +public: + /// Type for line and column numbers. + typedef int counter_type; + + /// Construct a position. + explicit position(std::string* f = YY_NULLPTR, counter_type l = 1, counter_type c = 1) + : filename(f), line(l), column(c) {} + + + /// Initialization. + void initialize(std::string* fn = YY_NULLPTR, counter_type l = 1, counter_type c = 1) { + filename = fn; + line = l; + column = c; + } + + /** \name Line and Column related manipulators + ** \{ */ + /// (line related) Advance to the COUNT next lines. + void lines(counter_type count = 1) { + if (count) { + column = 1; + line = add_(line, count, 1); + } + } + + /// (column related) Advance to the COUNT next columns. + void columns(counter_type count = 1) { + column = add_(column, count, 1); + } + /** \} */ + + /// File name to which this position refers. + std::string* filename; + /// Current line number. + counter_type line; + /// Current column number. + counter_type column; + +private: + /// Compute max (min, lhs+rhs). + static counter_type add_(counter_type lhs, counter_type rhs, counter_type min) { + return lhs + rhs < min ? min : lhs + rhs; + } +}; + +/// Add \a width columns, in place. +inline position& operator+=(position& res, position::counter_type width) { + res.columns(width); + return res; +} + +/// Add \a width columns. +inline position operator+(position res, position::counter_type width) { + return res += width; +} + +/// Subtract \a width columns, in place. +inline position& operator-=(position& res, position::counter_type width) { + return res += -width; +} + +/// Subtract \a width columns. +inline position operator-(position res, position::counter_type width) { + return res -= width; +} + +/// Compare two position objects. +inline bool operator==(const position& pos1, const position& pos2) { + return (pos1.line == pos2.line && pos1.column == pos2.column && + (pos1.filename == pos2.filename || + (pos1.filename && pos2.filename && *pos1.filename == *pos2.filename))); +} + +/// Compare two position objects. +inline bool operator!=(const position& pos1, const position& pos2) { + return !(pos1 == pos2); +} + +/** \brief Intercept output stream redirection. + ** \param ostr the destination output stream + ** \param pos a reference to the position to redirect + */ +template <typename YYChar> +std::basic_ostream<YYChar>& operator<<(std::basic_ostream<YYChar>& ostr, const position& pos) { + if (pos.filename) + ostr << *pos.filename << ':'; + return ostr << pos.line << '.' << pos.column; +} + +/// Two points in a source file. +class location { +public: + /// Type for line and column numbers. + typedef position::counter_type counter_type; + + /// Construct a location from \a b to \a e. + location(const position& b, const position& e) : begin(b), end(e) {} + + /// Construct a 0-width location in \a p. + explicit location(const position& p = position()) : begin(p), end(p) {} + + /// Construct a 0-width location in \a f, \a l, \a c. + explicit location(std::string* f, counter_type l = 1, counter_type c = 1) + : begin(f, l, c), end(f, l, c) {} + + + /// Initialization. + void initialize(std::string* f = YY_NULLPTR, counter_type l = 1, counter_type c = 1) { + begin.initialize(f, l, c); + end = begin; + } + + /** \name Line and Column related manipulators + ** \{ */ +public: + /// Reset initial location to final location. + void step() { + begin = end; + } + + /// Extend the current location to the COUNT next columns. + void columns(counter_type count = 1) { + end += count; + } + + /// Extend the current location to the COUNT next lines. + void lines(counter_type count = 1) { + end.lines(count); + } + /** \} */ + + +public: + /// Beginning of the located region. + position begin; + /// End of the located region. + position end; +}; + +/// Join two locations, in place. +inline location& operator+=(location& res, const location& end) { + res.end = end.end; + return res; +} + +/// Join two locations. +inline location operator+(location res, const location& end) { + return res += end; +} + +/// Add \a width columns to the end position, in place. +inline location& operator+=(location& res, location::counter_type width) { + res.columns(width); + return res; +} + +/// Add \a width columns to the end position. +inline location operator+(location res, location::counter_type width) { + return res += width; +} + +/// Subtract \a width columns to the end position, in place. +inline location& operator-=(location& res, location::counter_type width) { + return res += -width; +} + +/// Subtract \a width columns to the end position. +inline location operator-(location res, location::counter_type width) { + return res -= width; +} + +/// Compare two location objects. +inline bool operator==(const location& loc1, const location& loc2) { + return loc1.begin == loc2.begin && loc1.end == loc2.end; +} + +/// Compare two location objects. +inline bool operator!=(const location& loc1, const location& loc2) { + return !(loc1 == loc2); +} + +/** \brief Intercept output stream redirection. + ** \param ostr the destination output stream + ** \param loc a reference to the location to redirect + ** + ** Avoid duplicate information. + */ +template <typename YYChar> +std::basic_ostream<YYChar>& operator<<(std::basic_ostream<YYChar>& ostr, const location& loc) { + location::counter_type end_col = 0 < loc.end.column ? loc.end.column - 1 : 0; + ostr << loc.begin; + if (loc.end.filename && (!loc.begin.filename || *loc.begin.filename != *loc.end.filename)) + ostr << '-' << loc.end.filename << ':' << loc.end.line << '.' << end_col; + else if (loc.begin.line < loc.end.line) + ostr << '-' << loc.end.line << '.' << end_col; + else if (loc.begin.column < end_col) + ostr << '-' << end_col; + return ostr; +} + +#line 52 "src/mongo/db/cst/pipeline_grammar.yy" +} // namespace mongo +#line 333 "src/mongo/db/cst/location_gen.h" + +#endif // !YY_YY_SRC_MONGO_DB_CST_LOCATION_GEN_H_INCLUDED diff --git a/src/mongo/db/cst/pipeline_grammar.yy b/src/mongo/db/cst/pipeline_grammar.yy new file mode 100644 index 00000000000..cd27bdb4d6d --- /dev/null +++ b/src/mongo/db/cst/pipeline_grammar.yy @@ -0,0 +1,144 @@ +/** + * Copyright (C) 2020-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +// +// This is a grammar file to describe the syntax of the aggregation pipeline language. It is +// ingested by GNU Bison (https://www.gnu.org/software/bison/) to generate native C++ parser code +// based on the rules provided here. +// +// To manually generate the parser files, run +// 'bison pipeline_grammar.yy -o pipeline_parser_gen.cpp'. +// +%require "3.5" +%language "c++" + +// Generate header for tokens to be included from lexer. +%defines +// Tell Bison to generate make_* methods for tokens. +%define api.token.constructor +// The mapping of scanner token ID to Bison's internal symbol enum is consistent. +%define api.token.raw +// Instead of specifying a %union directive of possible semantic types, allow Bison to build a sort +// of std::variant structure. This allows symbol declaration with '%type <C++ type> symbol'. +%define api.value.type variant + +%define parse.assert +%define api.namespace {mongo} +%define api.parser.class {PipelineParserGen} + +// Track locations of symbols. +%locations +%define api.location.file "location_gen.h" + +// Header only. +%code requires { + #include "mongo/db/cst/c_node.h" + #include "mongo/db/cst/key_fieldname.h" + #include "mongo/stdx/variant.h" + + // Forward declare any parameters needed for lexing/parsing. + namespace mongo { + class BSONLexer; + } +} + +// Cpp only. +%code { + #include "mongo/db/cst/bson_lexer.h" + + namespace mongo { + // Mandatory error function. + void PipelineParserGen::error (const PipelineParserGen::location_type& loc, + const std::string& msg) { + std::cerr << msg << " at loc " << loc << std::endl; + } + } // namespace mongo +} + +// Parsing parameters, funneled through yyparse() to yylex(). +%param {BSONLexer& driver} +// yyparse() parameter only. +%parse-param {CNode* cst} + +// +// Token definitions. +// + +%token + START_OBJECT + END_OBJECT + START_ORDERED_OBJECT + END_ORDERED_OBJECT + START_ARRAY + END_ARRAY + + // Reserve pipeline stage names. + STAGE_INHIBIT_OPTIMIZATION + + END_OF_FILE 0 "EOF" +; + +%token <std::string> STRING +%token <int> NUMBER_INT +%token <long long> NUMBER_LONG +%token <double> NUMBER_DOUBLE +%token <bool> BOOL + +// +// Semantic values (aka the C++ types produced by the actions). +// +%type <CNode> stageList +%type <std::pair<KeyFieldname, CNode>> stage + +// +// Grammar rules +// +%% + +// Entry point to pipeline parsing. +pipeline: START_ARRAY stageList END_ARRAY { + *cst = std::move($stageList); +}; + +stageList[result]: + %empty { } + | START_OBJECT stage END_OBJECT stageList[stagesArg] { + $result = std::move($stagesArg); + auto& children = stdx::get<CNode::Children>($result.payload); + children.emplace_back(std::move($stage)); + } +; + +stage: + STAGE_INHIBIT_OPTIMIZATION START_OBJECT END_OBJECT { + $stage = std::pair{KeyFieldname::inhibitOptimization, CNode::noopLeaf()}; + } +; + +%% diff --git a/src/mongo/db/cst/pipeline_parser_gen.cpp b/src/mongo/db/cst/pipeline_parser_gen.cpp new file mode 100644 index 00000000000..5f8b29b113d --- /dev/null +++ b/src/mongo/db/cst/pipeline_parser_gen.cpp @@ -0,0 +1,888 @@ +// A Bison parser, made by GNU Bison 3.5.4. + +// Skeleton implementation for Bison LALR(1) parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +// Undocumented macros, especially those whose name start with YY_, +// are private implementation details. Do not rely on them. + + +#include "pipeline_parser_gen.hpp" + + +// Unqualified %code blocks. +#line 72 "src/mongo/db/cst/pipeline_grammar.yy" + +#include "mongo/db/cst/bson_lexer.h" + +namespace mongo { +// Mandatory error function. +void PipelineParserGen::error(const PipelineParserGen::location_type& loc, const std::string& msg) { + std::cerr << msg << " at loc " << loc << std::endl; +} +} // namespace mongo + +#line 57 "src/mongo/db/cst/pipeline_parser_gen.cpp" + + +#ifndef YY_ +#if defined YYENABLE_NLS && YYENABLE_NLS +#if ENABLE_NLS +#include <libintl.h> // FIXME: INFRINGES ON USER NAME SPACE. +#define YY_(msgid) dgettext("bison-runtime", msgid) +#endif +#endif +#ifndef YY_ +#define YY_(msgid) msgid +#endif +#endif + +// Whether we are compiled with exception support. +#ifndef YY_EXCEPTIONS +#if defined __GNUC__ && !defined __EXCEPTIONS +#define YY_EXCEPTIONS 0 +#else +#define YY_EXCEPTIONS 1 +#endif +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K].location) +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#ifndef YYLLOC_DEFAULT +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) { \ + (Current).begin = YYRHSLOC(Rhs, 1).begin; \ + (Current).end = YYRHSLOC(Rhs, N).end; \ + } else { \ + (Current).begin = (Current).end = YYRHSLOC(Rhs, 0).end; \ + } \ + while (false) +#endif + + +// Enable debugging if requested. +#if YYDEBUG + +// A pseudo ostream that takes yydebug_ into account. +#define YYCDEBUG \ + if (yydebug_) \ + (*yycdebug_) + +#define YY_SYMBOL_PRINT(Title, Symbol) \ + do { \ + if (yydebug_) { \ + *yycdebug_ << Title << ' '; \ + yy_print_(*yycdebug_, Symbol); \ + *yycdebug_ << '\n'; \ + } \ + } while (false) + +#define YY_REDUCE_PRINT(Rule) \ + do { \ + if (yydebug_) \ + yy_reduce_print_(Rule); \ + } while (false) + +#define YY_STACK_PRINT() \ + do { \ + if (yydebug_) \ + yystack_print_(); \ + } while (false) + +#else // !YYDEBUG + +#define YYCDEBUG \ + if (false) \ + std::cerr +#define YY_SYMBOL_PRINT(Title, Symbol) YYUSE(Symbol) +#define YY_REDUCE_PRINT(Rule) static_cast<void>(0) +#define YY_STACK_PRINT() static_cast<void>(0) + +#endif // !YYDEBUG + +#define yyerrok (yyerrstatus_ = 0) +#define yyclearin (yyla.clear()) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYRECOVERING() (!!yyerrstatus_) + +#line 52 "src/mongo/db/cst/pipeline_grammar.yy" +namespace mongo { +#line 149 "src/mongo/db/cst/pipeline_parser_gen.cpp" + + +/// Build a parser object. +PipelineParserGen::PipelineParserGen(BSONLexer& driver_yyarg, CNode* cst_yyarg) +#if YYDEBUG + : yydebug_(false), + yycdebug_(&std::cerr), +#else + : +#endif + driver(driver_yyarg), + cst(cst_yyarg) { +} + +PipelineParserGen::~PipelineParserGen() {} + +PipelineParserGen::syntax_error::~syntax_error() YY_NOEXCEPT YY_NOTHROW {} + +/*---------------. +| Symbol types. | +`---------------*/ + + +// by_state. +PipelineParserGen::by_state::by_state() YY_NOEXCEPT : state(empty_state) {} + +PipelineParserGen::by_state::by_state(const by_state& that) YY_NOEXCEPT : state(that.state) {} + +void PipelineParserGen::by_state::clear() YY_NOEXCEPT { + state = empty_state; +} + +void PipelineParserGen::by_state::move(by_state& that) { + state = that.state; + that.clear(); +} + +PipelineParserGen::by_state::by_state(state_type s) YY_NOEXCEPT : state(s) {} + +PipelineParserGen::symbol_number_type PipelineParserGen::by_state::type_get() const YY_NOEXCEPT { + if (state == empty_state) + return empty_symbol; + else + return yystos_[+state]; +} + +PipelineParserGen::stack_symbol_type::stack_symbol_type() {} + +PipelineParserGen::stack_symbol_type::stack_symbol_type(YY_RVREF(stack_symbol_type) that) + : super_type(YY_MOVE(that.state), YY_MOVE(that.location)) { + switch (that.type_get()) { + case 17: // stageList + value.YY_MOVE_OR_COPY<CNode>(YY_MOVE(that.value)); + break; + + case 14: // BOOL + value.YY_MOVE_OR_COPY<bool>(YY_MOVE(that.value)); + break; + + case 13: // NUMBER_DOUBLE + value.YY_MOVE_OR_COPY<double>(YY_MOVE(that.value)); + break; + + case 11: // NUMBER_INT + value.YY_MOVE_OR_COPY<int>(YY_MOVE(that.value)); + break; + + case 12: // NUMBER_LONG + value.YY_MOVE_OR_COPY<long long>(YY_MOVE(that.value)); + break; + + case 18: // stage + value.YY_MOVE_OR_COPY<std::pair<KeyFieldname, CNode>>(YY_MOVE(that.value)); + break; + + case 10: // STRING + value.YY_MOVE_OR_COPY<std::string>(YY_MOVE(that.value)); + break; + + default: + break; + } + +#if 201103L <= YY_CPLUSPLUS + // that is emptied. + that.state = empty_state; +#endif +} + +PipelineParserGen::stack_symbol_type::stack_symbol_type(state_type s, YY_MOVE_REF(symbol_type) that) + : super_type(s, YY_MOVE(that.location)) { + switch (that.type_get()) { + case 17: // stageList + value.move<CNode>(YY_MOVE(that.value)); + break; + + case 14: // BOOL + value.move<bool>(YY_MOVE(that.value)); + break; + + case 13: // NUMBER_DOUBLE + value.move<double>(YY_MOVE(that.value)); + break; + + case 11: // NUMBER_INT + value.move<int>(YY_MOVE(that.value)); + break; + + case 12: // NUMBER_LONG + value.move<long long>(YY_MOVE(that.value)); + break; + + case 18: // stage + value.move<std::pair<KeyFieldname, CNode>>(YY_MOVE(that.value)); + break; + + case 10: // STRING + value.move<std::string>(YY_MOVE(that.value)); + break; + + default: + break; + } + + // that is emptied. + that.type = empty_symbol; +} + +#if YY_CPLUSPLUS < 201103L +PipelineParserGen::stack_symbol_type& PipelineParserGen::stack_symbol_type::operator=( + const stack_symbol_type& that) { + state = that.state; + switch (that.type_get()) { + case 17: // stageList + value.copy<CNode>(that.value); + break; + + case 14: // BOOL + value.copy<bool>(that.value); + break; + + case 13: // NUMBER_DOUBLE + value.copy<double>(that.value); + break; + + case 11: // NUMBER_INT + value.copy<int>(that.value); + break; + + case 12: // NUMBER_LONG + value.copy<long long>(that.value); + break; + + case 18: // stage + value.copy<std::pair<KeyFieldname, CNode>>(that.value); + break; + + case 10: // STRING + value.copy<std::string>(that.value); + break; + + default: + break; + } + + location = that.location; + return *this; +} + +PipelineParserGen::stack_symbol_type& PipelineParserGen::stack_symbol_type::operator=( + stack_symbol_type& that) { + state = that.state; + switch (that.type_get()) { + case 17: // stageList + value.move<CNode>(that.value); + break; + + case 14: // BOOL + value.move<bool>(that.value); + break; + + case 13: // NUMBER_DOUBLE + value.move<double>(that.value); + break; + + case 11: // NUMBER_INT + value.move<int>(that.value); + break; + + case 12: // NUMBER_LONG + value.move<long long>(that.value); + break; + + case 18: // stage + value.move<std::pair<KeyFieldname, CNode>>(that.value); + break; + + case 10: // STRING + value.move<std::string>(that.value); + break; + + default: + break; + } + + location = that.location; + // that is emptied. + that.state = empty_state; + return *this; +} +#endif + +template <typename Base> +void PipelineParserGen::yy_destroy_(const char* yymsg, basic_symbol<Base>& yysym) const { + if (yymsg) + YY_SYMBOL_PRINT(yymsg, yysym); +} + +#if YYDEBUG +template <typename Base> +void PipelineParserGen::yy_print_(std::ostream& yyo, const basic_symbol<Base>& yysym) const { + std::ostream& yyoutput = yyo; + YYUSE(yyoutput); + symbol_number_type yytype = yysym.type_get(); +#if defined __GNUC__ && !defined __clang__ && !defined __ICC && \ + __GNUC__ * 100 + __GNUC_MINOR__ <= 408 + // Avoid a (spurious) G++ 4.8 warning about "array subscript is + // below array bounds". + if (yysym.empty()) + std::abort(); +#endif + yyo << (yytype < yyntokens_ ? "token" : "nterm") << ' ' << yytname_[yytype] << " (" + << yysym.location << ": "; + YYUSE(yytype); + yyo << ')'; +} +#endif + +void PipelineParserGen::yypush_(const char* m, YY_MOVE_REF(stack_symbol_type) sym) { + if (m) + YY_SYMBOL_PRINT(m, sym); + yystack_.push(YY_MOVE(sym)); +} + +void PipelineParserGen::yypush_(const char* m, state_type s, YY_MOVE_REF(symbol_type) sym) { +#if 201103L <= YY_CPLUSPLUS + yypush_(m, stack_symbol_type(s, std::move(sym))); +#else + stack_symbol_type ss(s, sym); + yypush_(m, ss); +#endif +} + +void PipelineParserGen::yypop_(int n) { + yystack_.pop(n); +} + +#if YYDEBUG +std::ostream& PipelineParserGen::debug_stream() const { + return *yycdebug_; +} + +void PipelineParserGen::set_debug_stream(std::ostream& o) { + yycdebug_ = &o; +} + + +PipelineParserGen::debug_level_type PipelineParserGen::debug_level() const { + return yydebug_; +} + +void PipelineParserGen::set_debug_level(debug_level_type l) { + yydebug_ = l; +} +#endif // YYDEBUG + +PipelineParserGen::state_type PipelineParserGen::yy_lr_goto_state_(state_type yystate, int yysym) { + int yyr = yypgoto_[yysym - yyntokens_] + yystate; + if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate) + return yytable_[yyr]; + else + return yydefgoto_[yysym - yyntokens_]; +} + +bool PipelineParserGen::yy_pact_value_is_default_(int yyvalue) { + return yyvalue == yypact_ninf_; +} + +bool PipelineParserGen::yy_table_value_is_error_(int yyvalue) { + return yyvalue == yytable_ninf_; +} + +int PipelineParserGen::operator()() { + return parse(); +} + +int PipelineParserGen::parse() { + int yyn; + /// Length of the RHS of the rule being reduced. + int yylen = 0; + + // Error handling. + int yynerrs_ = 0; + int yyerrstatus_ = 0; + + /// The lookahead symbol. + symbol_type yyla; + + /// The locations where the error started and ended. + stack_symbol_type yyerror_range[3]; + + /// The return value of parse (). + int yyresult; + +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + YYCDEBUG << "Starting parse\n"; + + + /* Initialize the stack. The initial state will be set in + yynewstate, since the latter expects the semantical and the + location values to have been already stored, initialize these + stacks with a primary value. */ + yystack_.clear(); + yypush_(YY_NULLPTR, 0, YY_MOVE(yyla)); + + /*-----------------------------------------------. + | yynewstate -- push a new symbol on the stack. | + `-----------------------------------------------*/ + yynewstate: + YYCDEBUG << "Entering state " << int(yystack_[0].state) << '\n'; + + // Accept? + if (yystack_[0].state == yyfinal_) + YYACCEPT; + + goto yybackup; + + + /*-----------. + | yybackup. | + `-----------*/ + yybackup: + // Try to take a decision without lookahead. + yyn = yypact_[+yystack_[0].state]; + if (yy_pact_value_is_default_(yyn)) + goto yydefault; + + // Read a lookahead token. + if (yyla.empty()) { + YYCDEBUG << "Reading a token: "; +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + symbol_type yylookahead(yylex(driver)); + yyla.move(yylookahead); + } +#if YY_EXCEPTIONS + catch (const syntax_error& yyexc) { + YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; + error(yyexc); + goto yyerrlab1; + } +#endif // YY_EXCEPTIONS + } + YY_SYMBOL_PRINT("Next token is", yyla); + + /* If the proper action on seeing token YYLA.TYPE is to reduce or + to detect an error, take that action. */ + yyn += yyla.type_get(); + if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.type_get()) { + goto yydefault; + } + + // Reduce or error. + yyn = yytable_[yyn]; + if (yyn <= 0) { + if (yy_table_value_is_error_(yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + // Count tokens shifted since error; after three, turn off error status. + if (yyerrstatus_) + --yyerrstatus_; + + // Shift the lookahead token. + yypush_("Shifting", state_type(yyn), YY_MOVE(yyla)); + goto yynewstate; + + + /*-----------------------------------------------------------. + | yydefault -- do the default action for the current state. | + `-----------------------------------------------------------*/ + yydefault: + yyn = yydefact_[+yystack_[0].state]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + + /*-----------------------------. + | yyreduce -- do a reduction. | + `-----------------------------*/ + yyreduce: + yylen = yyr2_[yyn]; + { + stack_symbol_type yylhs; + yylhs.state = yy_lr_goto_state_(yystack_[yylen].state, yyr1_[yyn]); + /* Variants are always initialized to an empty instance of the + correct type. The default '$$ = $1' action is NOT applied + when using variants. */ + switch (yyr1_[yyn]) { + case 17: // stageList + yylhs.value.emplace<CNode>(); + break; + + case 14: // BOOL + yylhs.value.emplace<bool>(); + break; + + case 13: // NUMBER_DOUBLE + yylhs.value.emplace<double>(); + break; + + case 11: // NUMBER_INT + yylhs.value.emplace<int>(); + break; + + case 12: // NUMBER_LONG + yylhs.value.emplace<long long>(); + break; + + case 18: // stage + yylhs.value.emplace<std::pair<KeyFieldname, CNode>>(); + break; + + case 10: // STRING + yylhs.value.emplace<std::string>(); + break; + + default: + break; + } + + + // Default location. + { + stack_type::slice range(yystack_, yylen); + YYLLOC_DEFAULT(yylhs.location, range, yylen); + yyerror_range[1].location = yylhs.location; + } + + // Perform the reduction. + YY_REDUCE_PRINT(yyn); +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + switch (yyn) { + case 2: +#line 125 "src/mongo/db/cst/pipeline_grammar.yy" + { + *cst = std::move(yystack_[1].value.as<CNode>()); + } +#line 678 "src/mongo/db/cst/pipeline_parser_gen.cpp" + break; + + case 3: +#line 130 "src/mongo/db/cst/pipeline_grammar.yy" + { + } +#line 684 "src/mongo/db/cst/pipeline_parser_gen.cpp" + break; + + case 4: +#line 131 "src/mongo/db/cst/pipeline_grammar.yy" + { + yylhs.value.as<CNode>() = std::move(yystack_[0].value.as<CNode>()); + auto& children = + stdx::get<CNode::Children>(yylhs.value.as<CNode>().payload); + children.emplace_back( + std::move(yystack_[2].value.as<std::pair<KeyFieldname, CNode>>())); + } +#line 694 "src/mongo/db/cst/pipeline_parser_gen.cpp" + break; + + case 5: +#line 139 "src/mongo/db/cst/pipeline_grammar.yy" + { + yylhs.value.as<std::pair<KeyFieldname, CNode>>() = + std::pair{KeyFieldname::inhibitOptimization, CNode::noopLeaf()}; + } +#line 702 "src/mongo/db/cst/pipeline_parser_gen.cpp" + break; + + +#line 706 "src/mongo/db/cst/pipeline_parser_gen.cpp" + + default: + break; + } + } +#if YY_EXCEPTIONS + catch (const syntax_error& yyexc) { + YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; + error(yyexc); + YYERROR; + } +#endif // YY_EXCEPTIONS + YY_SYMBOL_PRINT("-> $$ =", yylhs); + yypop_(yylen); + yylen = 0; + YY_STACK_PRINT(); + + // Shift the result of the reduction. + yypush_(YY_NULLPTR, YY_MOVE(yylhs)); + } + goto yynewstate; + + + /*--------------------------------------. + | yyerrlab -- here on detecting error. | + `--------------------------------------*/ + yyerrlab: + // If not already recovering from an error, report this error. + if (!yyerrstatus_) { + ++yynerrs_; + error(yyla.location, yysyntax_error_(yystack_[0].state, yyla)); + } + + + yyerror_range[1].location = yyla.location; + if (yyerrstatus_ == 3) { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + // Return failure if at end of input. + if (yyla.type_get() == yyeof_) + YYABORT; + else if (!yyla.empty()) { + yy_destroy_("Error: discarding", yyla); + yyla.clear(); + } + } + + // Else will try to reuse lookahead token after shifting the error token. + goto yyerrlab1; + + + /*---------------------------------------------------. + | yyerrorlab -- error raised explicitly by YYERROR. | + `---------------------------------------------------*/ + yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and + the label yyerrorlab therefore never appears in user code. */ + if (false) + YYERROR; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + yypop_(yylen); + yylen = 0; + goto yyerrlab1; + + + /*-------------------------------------------------------------. + | yyerrlab1 -- common code for both syntax error and YYERROR. | + `-------------------------------------------------------------*/ + yyerrlab1: + yyerrstatus_ = 3; // Each real token shifted decrements this. + { + stack_symbol_type error_token; + for (;;) { + yyn = yypact_[+yystack_[0].state]; + if (!yy_pact_value_is_default_(yyn)) { + yyn += yy_error_token_; + if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == yy_error_token_) { + yyn = yytable_[yyn]; + if (0 < yyn) + break; + } + } + + // Pop the current state because it cannot handle the error token. + if (yystack_.size() == 1) + YYABORT; + + yyerror_range[1].location = yystack_[0].location; + yy_destroy_("Error: popping", yystack_[0]); + yypop_(); + YY_STACK_PRINT(); + } + + yyerror_range[2].location = yyla.location; + YYLLOC_DEFAULT(error_token.location, yyerror_range, 2); + + // Shift the error token. + error_token.state = state_type(yyn); + yypush_("Shifting", YY_MOVE(error_token)); + } + goto yynewstate; + + + /*-------------------------------------. + | yyacceptlab -- YYACCEPT comes here. | + `-------------------------------------*/ + yyacceptlab: + yyresult = 0; + goto yyreturn; + + + /*-----------------------------------. + | yyabortlab -- YYABORT comes here. | + `-----------------------------------*/ + yyabortlab: + yyresult = 1; + goto yyreturn; + + + /*-----------------------------------------------------. + | yyreturn -- parsing is finished, return the result. | + `-----------------------------------------------------*/ + yyreturn: + if (!yyla.empty()) + yy_destroy_("Cleanup: discarding lookahead", yyla); + + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + yypop_(yylen); + while (1 < yystack_.size()) { + yy_destroy_("Cleanup: popping", yystack_[0]); + yypop_(); + } + + return yyresult; + } +#if YY_EXCEPTIONS + catch (...) { + YYCDEBUG << "Exception caught: cleaning lookahead and stack\n"; + // Do not try to display the values of the reclaimed symbols, + // as their printers might throw an exception. + if (!yyla.empty()) + yy_destroy_(YY_NULLPTR, yyla); + + while (1 < yystack_.size()) { + yy_destroy_(YY_NULLPTR, yystack_[0]); + yypop_(); + } + throw; + } +#endif // YY_EXCEPTIONS +} + +void PipelineParserGen::error(const syntax_error& yyexc) { + error(yyexc.location, yyexc.what()); +} + +// Generate an error message. +std::string PipelineParserGen::yysyntax_error_(state_type, const symbol_type&) const { + return YY_("syntax error"); +} + + +const signed char PipelineParserGen::yypact_ninf_ = -8; + +const signed char PipelineParserGen::yytable_ninf_ = -1; + +const signed char PipelineParserGen::yypact_[] = {-7, -2, 2, -6, -4, -8, 3, 1, -8, 4, -2, -8, -8}; + +const signed char PipelineParserGen::yydefact_[] = {0, 3, 0, 0, 0, 1, 0, 0, 2, 0, 3, 5, 4}; + +const signed char PipelineParserGen::yypgoto_[] = {-8, -8, -3, -8}; + +const signed char PipelineParserGen::yydefgoto_[] = {-1, 2, 4, 7}; + +const signed char PipelineParserGen::yytable_[] = {1, 3, 5, 6, 8, 10, 9, 12, 11}; + +const signed char PipelineParserGen::yycheck_[] = {7, 3, 0, 9, 8, 4, 3, 10, 4}; + +const signed char PipelineParserGen::yystos_[] = {0, 7, 16, 3, 17, 0, 9, 18, 8, 3, 4, 4, 17}; + +const signed char PipelineParserGen::yyr1_[] = {0, 15, 16, 17, 17, 18}; + +const signed char PipelineParserGen::yyr2_[] = {0, 2, 3, 0, 4, 3}; + + +#if YYDEBUG +// YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. +// First, the terminals, then, starting at \a yyntokens_, nonterminals. +const char* const PipelineParserGen::yytname_[] = {"\"EOF\"", + "error", + "$undefined", + "START_OBJECT", + "END_OBJECT", + "START_ORDERED_OBJECT", + "END_ORDERED_OBJECT", + "START_ARRAY", + "END_ARRAY", + "STAGE_INHIBIT_OPTIMIZATION", + "STRING", + "NUMBER_INT", + "NUMBER_LONG", + "NUMBER_DOUBLE", + "BOOL", + "$accept", + "pipeline", + "stageList", + "stage", + YY_NULLPTR}; + + +const unsigned char PipelineParserGen::yyrline_[] = {0, 125, 125, 130, 131, 139}; + +// Print the state stack on the debug stream. +void PipelineParserGen::yystack_print_() { + *yycdebug_ << "Stack now"; + for (stack_type::const_iterator i = yystack_.begin(), i_end = yystack_.end(); i != i_end; ++i) + *yycdebug_ << ' ' << int(i->state); + *yycdebug_ << '\n'; +} + +// Report on the debug stream that the rule \a yyrule is going to be reduced. +void PipelineParserGen::yy_reduce_print_(int yyrule) { + int yylno = yyrline_[yyrule]; + int yynrhs = yyr2_[yyrule]; + // Print the symbols being reduced, and their result. + *yycdebug_ << "Reducing stack by rule " << yyrule - 1 << " (line " << yylno << "):\n"; + // The symbols being reduced. + for (int yyi = 0; yyi < yynrhs; yyi++) + YY_SYMBOL_PRINT(" $" << yyi + 1 << " =", yystack_[(yynrhs) - (yyi + 1)]); +} +#endif // YYDEBUG + + +#line 52 "src/mongo/db/cst/pipeline_grammar.yy" +} // namespace mongo +#line 1000 "src/mongo/db/cst/pipeline_parser_gen.cpp" + +#line 144 "src/mongo/db/cst/pipeline_grammar.yy" diff --git a/src/mongo/db/cst/pipeline_parser_gen.hpp b/src/mongo/db/cst/pipeline_parser_gen.hpp new file mode 100644 index 00000000000..eb5258d7cfa --- /dev/null +++ b/src/mongo/db/cst/pipeline_parser_gen.hpp @@ -0,0 +1,1304 @@ +// A Bison parser, made by GNU Bison 3.5.4. + +// Skeleton interface for Bison LALR(1) parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + + +/** + ** \file src/mongo/db/cst/pipeline_parser_gen.hpp + ** Define the mongo::parser class. + */ + +// C++ LALR(1) parser skeleton written by Akim Demaille. + +// Undocumented macros, especially those whose name start with YY_, +// are private implementation details. Do not rely on them. + +#ifndef YY_YY_SRC_MONGO_DB_CST_PIPELINE_PARSER_GEN_HPP_INCLUDED +#define YY_YY_SRC_MONGO_DB_CST_PIPELINE_PARSER_GEN_HPP_INCLUDED +// "%code requires" blocks. +#line 60 "src/mongo/db/cst/pipeline_grammar.yy" + +#include "mongo/db/cst/c_node.h" +#include "mongo/db/cst/key_fieldname.h" +#include "mongo/stdx/variant.h" + +// Forward declare any parameters needed for lexing/parsing. +namespace mongo { +class BSONLexer; +} + +#line 59 "src/mongo/db/cst/pipeline_parser_gen.hpp" + +#include <cassert> +#include <cstdlib> // std::abort +#include <iostream> +#include <stdexcept> +#include <string> +#include <vector> + +#if defined __cplusplus +#define YY_CPLUSPLUS __cplusplus +#else +#define YY_CPLUSPLUS 199711L +#endif + +// Support move semantics when possible. +#if 201103L <= YY_CPLUSPLUS +#define YY_MOVE std::move +#define YY_MOVE_OR_COPY move +#define YY_MOVE_REF(Type) Type&& +#define YY_RVREF(Type) Type&& +#define YY_COPY(Type) Type +#else +#define YY_MOVE +#define YY_MOVE_OR_COPY copy +#define YY_MOVE_REF(Type) Type& +#define YY_RVREF(Type) const Type& +#define YY_COPY(Type) const Type& +#endif + +// Support noexcept when possible. +#if 201103L <= YY_CPLUSPLUS +#define YY_NOEXCEPT noexcept +#define YY_NOTHROW +#else +#define YY_NOEXCEPT +#define YY_NOTHROW throw() +#endif + +// Support constexpr when possible. +#if 201703 <= YY_CPLUSPLUS +#define YY_CONSTEXPR constexpr +#else +#define YY_CONSTEXPR +#endif +#include "location_gen.h" +#include <typeinfo> +#ifndef YY_ASSERT +#include <cassert> +#define YY_ASSERT assert +#endif + + +#ifndef YY_ATTRIBUTE_PURE +#if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +#define YY_ATTRIBUTE_PURE __attribute__((__pure__)) +#else +#define YY_ATTRIBUTE_PURE +#endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +#if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +#define YY_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#else +#define YY_ATTRIBUTE_UNUSED +#endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if !defined lint || defined __GNUC__ +#define YYUSE(E) ((void)(E)) +#else +#define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && !defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +#define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +#define YY_IGNORE_MAYBE_UNINITIALIZED_END _Pragma("GCC diagnostic pop") +#else +#define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +#define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +#define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +#define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && !defined __ICC && 6 <= __GNUC__ +#define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wuseless-cast\"") +#define YY_IGNORE_USELESS_CAST_END _Pragma("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +#define YY_IGNORE_USELESS_CAST_BEGIN +#define YY_IGNORE_USELESS_CAST_END +#endif + +#ifndef YY_CAST +#ifdef __cplusplus +#define YY_CAST(Type, Val) static_cast<Type>(Val) +#define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type>(Val) +#else +#define YY_CAST(Type, Val) ((Type)(Val)) +#define YY_REINTERPRET_CAST(Type, Val) ((Type)(Val)) +#endif +#endif +#ifndef YY_NULLPTR +#if defined __cplusplus +#if 201103L <= __cplusplus +#define YY_NULLPTR nullptr +#else +#define YY_NULLPTR 0 +#endif +#else +#define YY_NULLPTR ((void*)0) +#endif +#endif + +/* Debug traces. */ +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif + +#line 52 "src/mongo/db/cst/pipeline_grammar.yy" +namespace mongo { +#line 194 "src/mongo/db/cst/pipeline_parser_gen.hpp" + + +/// A Bison parser. +class PipelineParserGen { +public: +#ifndef YYSTYPE + /// A buffer to store and retrieve objects. + /// + /// Sort of a variant, but does not keep track of the nature + /// of the stored data, since that knowledge is available + /// via the current parser state. + class semantic_type { + public: + /// Type of *this. + typedef semantic_type self_type; + + /// Empty construction. + semantic_type() YY_NOEXCEPT : yybuffer_(), yytypeid_(YY_NULLPTR) {} + + /// Construct and fill. + template <typename T> + semantic_type(YY_RVREF(T) t) : yytypeid_(&typeid(T)) { + YY_ASSERT(sizeof(T) <= size); + new (yyas_<T>()) T(YY_MOVE(t)); + } + + /// Destruction, allowed only if empty. + ~semantic_type() YY_NOEXCEPT { + YY_ASSERT(!yytypeid_); + } + +#if 201103L <= YY_CPLUSPLUS + /// Instantiate a \a T in here from \a t. + template <typename T, typename... U> + T& emplace(U&&... u) { + YY_ASSERT(!yytypeid_); + YY_ASSERT(sizeof(T) <= size); + yytypeid_ = &typeid(T); + return *new (yyas_<T>()) T(std::forward<U>(u)...); + } +#else + /// Instantiate an empty \a T in here. + template <typename T> + T& emplace() { + YY_ASSERT(!yytypeid_); + YY_ASSERT(sizeof(T) <= size); + yytypeid_ = &typeid(T); + return *new (yyas_<T>()) T(); + } + + /// Instantiate a \a T in here from \a t. + template <typename T> + T& emplace(const T& t) { + YY_ASSERT(!yytypeid_); + YY_ASSERT(sizeof(T) <= size); + yytypeid_ = &typeid(T); + return *new (yyas_<T>()) T(t); + } +#endif + + /// Instantiate an empty \a T in here. + /// Obsolete, use emplace. + template <typename T> + T& build() { + return emplace<T>(); + } + + /// Instantiate a \a T in here from \a t. + /// Obsolete, use emplace. + template <typename T> + T& build(const T& t) { + return emplace<T>(t); + } + + /// Accessor to a built \a T. + template <typename T> + T& as() YY_NOEXCEPT { + YY_ASSERT(yytypeid_); + YY_ASSERT(*yytypeid_ == typeid(T)); + YY_ASSERT(sizeof(T) <= size); + return *yyas_<T>(); + } + + /// Const accessor to a built \a T (for %printer). + template <typename T> + const T& as() const YY_NOEXCEPT { + YY_ASSERT(yytypeid_); + YY_ASSERT(*yytypeid_ == typeid(T)); + YY_ASSERT(sizeof(T) <= size); + return *yyas_<T>(); + } + + /// Swap the content with \a that, of same type. + /// + /// Both variants must be built beforehand, because swapping the actual + /// data requires reading it (with as()), and this is not possible on + /// unconstructed variants: it would require some dynamic testing, which + /// should not be the variant's responsibility. + /// Swapping between built and (possibly) non-built is done with + /// self_type::move (). + template <typename T> + void swap(self_type& that) YY_NOEXCEPT { + YY_ASSERT(yytypeid_); + YY_ASSERT(*yytypeid_ == *that.yytypeid_); + std::swap(as<T>(), that.as<T>()); + } + + /// Move the content of \a that to this. + /// + /// Destroys \a that. + template <typename T> + void move(self_type& that) { +#if 201103L <= YY_CPLUSPLUS + emplace<T>(std::move(that.as<T>())); +#else + emplace<T>(); + swap<T>(that); +#endif + that.destroy<T>(); + } + +#if 201103L <= YY_CPLUSPLUS + /// Move the content of \a that to this. + template <typename T> + void move(self_type&& that) { + emplace<T>(std::move(that.as<T>())); + that.destroy<T>(); + } +#endif + + /// Copy the content of \a that to this. + template <typename T> + void copy(const self_type& that) { + emplace<T>(that.as<T>()); + } + + /// Destroy the stored \a T. + template <typename T> + void destroy() { + as<T>().~T(); + yytypeid_ = YY_NULLPTR; + } + + private: + /// Prohibit blind copies. + self_type& operator=(const self_type&); + semantic_type(const self_type&); + + /// Accessor to raw memory as \a T. + template <typename T> + T* yyas_() YY_NOEXCEPT { + void* yyp = yybuffer_.yyraw; + return static_cast<T*>(yyp); + } + + /// Const accessor to raw memory as \a T. + template <typename T> + const T* yyas_() const YY_NOEXCEPT { + const void* yyp = yybuffer_.yyraw; + return static_cast<const T*>(yyp); + } + + /// An auxiliary type to compute the largest semantic type. + union union_type { + // stageList + char dummy1[sizeof(CNode)]; + + // BOOL + char dummy2[sizeof(bool)]; + + // NUMBER_DOUBLE + char dummy3[sizeof(double)]; + + // NUMBER_INT + char dummy4[sizeof(int)]; + + // NUMBER_LONG + char dummy5[sizeof(long long)]; + + // stage + char dummy6[sizeof(std::pair<KeyFieldname, CNode>)]; + + // STRING + char dummy7[sizeof(std::string)]; + }; + + /// The size of the largest semantic type. + enum { size = sizeof(union_type) }; + + /// A buffer to store semantic values. + union { + /// Strongest alignment constraints. + long double yyalign_me; + /// A buffer large enough to store any of the semantic values. + char yyraw[size]; + } yybuffer_; + + /// Whether the content is built: if defined, the name of the stored type. + const std::type_info* yytypeid_; + }; + +#else + typedef YYSTYPE semantic_type; +#endif + /// Symbol locations. + typedef location location_type; + + /// Syntax errors thrown from user actions. + struct syntax_error : std::runtime_error { + syntax_error(const location_type& l, const std::string& m) + : std::runtime_error(m), location(l) {} + + syntax_error(const syntax_error& s) : std::runtime_error(s.what()), location(s.location) {} + + ~syntax_error() YY_NOEXCEPT YY_NOTHROW; + + location_type location; + }; + + /// Tokens. + struct token { + enum yytokentype { + END_OF_FILE = 0, + START_OBJECT = 3, + END_OBJECT = 4, + START_ORDERED_OBJECT = 5, + END_ORDERED_OBJECT = 6, + START_ARRAY = 7, + END_ARRAY = 8, + STAGE_INHIBIT_OPTIMIZATION = 9, + STRING = 10, + NUMBER_INT = 11, + NUMBER_LONG = 12, + NUMBER_DOUBLE = 13, + BOOL = 14 + }; + }; + + /// (External) token type, as returned by yylex. + typedef token::yytokentype token_type; + + /// Symbol type: an internal symbol number. + typedef int symbol_number_type; + + /// The symbol type number to denote an empty symbol. + enum { empty_symbol = -2 }; + + /// Internal symbol number for tokens (subsumed by symbol_number_type). + typedef signed char token_number_type; + + /// A complete symbol. + /// + /// Expects its Base type to provide access to the symbol type + /// via type_get (). + /// + /// Provide access to semantic value and location. + template <typename Base> + struct basic_symbol : Base { + /// Alias to Base. + typedef Base super_type; + + /// Default constructor. + basic_symbol() : value(), location() {} + +#if 201103L <= YY_CPLUSPLUS + /// Move constructor. + basic_symbol(basic_symbol&& that); +#endif + + /// Copy constructor. + basic_symbol(const basic_symbol& that); + + /// Constructor for valueless symbols, and symbols from each type. +#if 201103L <= YY_CPLUSPLUS + basic_symbol(typename Base::kind_type t, location_type&& l) + : Base(t), location(std::move(l)) {} +#else + basic_symbol(typename Base::kind_type t, const location_type& l) : Base(t), location(l) {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol(typename Base::kind_type t, CNode&& v, location_type&& l) + : Base(t), value(std::move(v)), location(std::move(l)) {} +#else + basic_symbol(typename Base::kind_type t, const CNode& v, const location_type& l) + : Base(t), value(v), location(l) {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol(typename Base::kind_type t, bool&& v, location_type&& l) + : Base(t), value(std::move(v)), location(std::move(l)) {} +#else + basic_symbol(typename Base::kind_type t, const bool& v, const location_type& l) + : Base(t), value(v), location(l) {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol(typename Base::kind_type t, double&& v, location_type&& l) + : Base(t), value(std::move(v)), location(std::move(l)) {} +#else + basic_symbol(typename Base::kind_type t, const double& v, const location_type& l) + : Base(t), value(v), location(l) {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol(typename Base::kind_type t, int&& v, location_type&& l) + : Base(t), value(std::move(v)), location(std::move(l)) {} +#else + basic_symbol(typename Base::kind_type t, const int& v, const location_type& l) + : Base(t), value(v), location(l) {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol(typename Base::kind_type t, long long&& v, location_type&& l) + : Base(t), value(std::move(v)), location(std::move(l)) {} +#else + basic_symbol(typename Base::kind_type t, const long long& v, const location_type& l) + : Base(t), value(v), location(l) {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol(typename Base::kind_type t, + std::pair<KeyFieldname, CNode>&& v, + location_type&& l) + : Base(t), value(std::move(v)), location(std::move(l)) {} +#else + basic_symbol(typename Base::kind_type t, + const std::pair<KeyFieldname, CNode>& v, + const location_type& l) + : Base(t), value(v), location(l) {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol(typename Base::kind_type t, std::string&& v, location_type&& l) + : Base(t), value(std::move(v)), location(std::move(l)) {} +#else + basic_symbol(typename Base::kind_type t, const std::string& v, const location_type& l) + : Base(t), value(v), location(l) {} +#endif + + /// Destroy the symbol. + ~basic_symbol() { + clear(); + } + + /// Destroy contents, and record that is empty. + void clear() { + // User destructor. + symbol_number_type yytype = this->type_get(); + basic_symbol<Base>& yysym = *this; + (void)yysym; + switch (yytype) { + default: + break; + } + + // Type destructor. + switch (yytype) { + case 17: // stageList + value.template destroy<CNode>(); + break; + + case 14: // BOOL + value.template destroy<bool>(); + break; + + case 13: // NUMBER_DOUBLE + value.template destroy<double>(); + break; + + case 11: // NUMBER_INT + value.template destroy<int>(); + break; + + case 12: // NUMBER_LONG + value.template destroy<long long>(); + break; + + case 18: // stage + value.template destroy<std::pair<KeyFieldname, CNode>>(); + break; + + case 10: // STRING + value.template destroy<std::string>(); + break; + + default: + break; + } + + Base::clear(); + } + + /// Whether empty. + bool empty() const YY_NOEXCEPT; + + /// Destructive move, \a s is emptied into this. + void move(basic_symbol& s); + + /// The semantic value. + semantic_type value; + + /// The location. + location_type location; + + private: +#if YY_CPLUSPLUS < 201103L + /// Assignment operator. + basic_symbol& operator=(const basic_symbol& that); +#endif + }; + + /// Type access provider for token (enum) based symbols. + struct by_type { + /// Default constructor. + by_type(); + +#if 201103L <= YY_CPLUSPLUS + /// Move constructor. + by_type(by_type&& that); +#endif + + /// Copy constructor. + by_type(const by_type& that); + + /// The symbol type as needed by the constructor. + typedef token_type kind_type; + + /// Constructor from (external) token numbers. + by_type(kind_type t); + + /// Record that this symbol is empty. + void clear(); + + /// Steal the symbol type from \a that. + void move(by_type& that); + + /// The (internal) type number (corresponding to \a type). + /// \a empty when empty. + symbol_number_type type_get() const YY_NOEXCEPT; + + /// The symbol type. + /// \a empty_symbol when empty. + /// An int, not token_number_type, to be able to store empty_symbol. + int type; + }; + + /// "External" symbols: returned by the scanner. + struct symbol_type : basic_symbol<by_type> { + /// Superclass. + typedef basic_symbol<by_type> super_type; + + /// Empty symbol. + symbol_type() {} + + /// Constructor for valueless symbols, and symbols from each type. +#if 201103L <= YY_CPLUSPLUS + symbol_type(int tok, location_type l) : super_type(token_type(tok), std::move(l)) { + YY_ASSERT(tok == token::END_OF_FILE || tok == token::START_OBJECT || + tok == token::END_OBJECT || tok == token::START_ORDERED_OBJECT || + tok == token::END_ORDERED_OBJECT || tok == token::START_ARRAY || + tok == token::END_ARRAY || tok == token::STAGE_INHIBIT_OPTIMIZATION); + } +#else + symbol_type(int tok, const location_type& l) : super_type(token_type(tok), l) { + YY_ASSERT(tok == token::END_OF_FILE || tok == token::START_OBJECT || + tok == token::END_OBJECT || tok == token::START_ORDERED_OBJECT || + tok == token::END_ORDERED_OBJECT || tok == token::START_ARRAY || + tok == token::END_ARRAY || tok == token::STAGE_INHIBIT_OPTIMIZATION); + } +#endif +#if 201103L <= YY_CPLUSPLUS + symbol_type(int tok, bool v, location_type l) + : super_type(token_type(tok), std::move(v), std::move(l)) { + YY_ASSERT(tok == token::BOOL); + } +#else + symbol_type(int tok, const bool& v, const location_type& l) + : super_type(token_type(tok), v, l) { + YY_ASSERT(tok == token::BOOL); + } +#endif +#if 201103L <= YY_CPLUSPLUS + symbol_type(int tok, double v, location_type l) + : super_type(token_type(tok), std::move(v), std::move(l)) { + YY_ASSERT(tok == token::NUMBER_DOUBLE); + } +#else + symbol_type(int tok, const double& v, const location_type& l) + : super_type(token_type(tok), v, l) { + YY_ASSERT(tok == token::NUMBER_DOUBLE); + } +#endif +#if 201103L <= YY_CPLUSPLUS + symbol_type(int tok, int v, location_type l) + : super_type(token_type(tok), std::move(v), std::move(l)) { + YY_ASSERT(tok == token::NUMBER_INT); + } +#else + symbol_type(int tok, const int& v, const location_type& l) + : super_type(token_type(tok), v, l) { + YY_ASSERT(tok == token::NUMBER_INT); + } +#endif +#if 201103L <= YY_CPLUSPLUS + symbol_type(int tok, long long v, location_type l) + : super_type(token_type(tok), std::move(v), std::move(l)) { + YY_ASSERT(tok == token::NUMBER_LONG); + } +#else + symbol_type(int tok, const long long& v, const location_type& l) + : super_type(token_type(tok), v, l) { + YY_ASSERT(tok == token::NUMBER_LONG); + } +#endif +#if 201103L <= YY_CPLUSPLUS + symbol_type(int tok, std::string v, location_type l) + : super_type(token_type(tok), std::move(v), std::move(l)) { + YY_ASSERT(tok == token::STRING); + } +#else + symbol_type(int tok, const std::string& v, const location_type& l) + : super_type(token_type(tok), v, l) { + YY_ASSERT(tok == token::STRING); + } +#endif + }; + + /// Build a parser object. + PipelineParserGen(BSONLexer& driver_yyarg, CNode* cst_yyarg); + virtual ~PipelineParserGen(); + + /// Parse. An alias for parse (). + /// \returns 0 iff parsing succeeded. + int operator()(); + + /// Parse. + /// \returns 0 iff parsing succeeded. + virtual int parse(); + +#if YYDEBUG + /// The current debugging stream. + std::ostream& debug_stream() const YY_ATTRIBUTE_PURE; + /// Set the current debugging stream. + void set_debug_stream(std::ostream&); + + /// Type for debugging levels. + typedef int debug_level_type; + /// The current debugging level. + debug_level_type debug_level() const YY_ATTRIBUTE_PURE; + /// Set the current debugging level. + void set_debug_level(debug_level_type l); +#endif + + /// Report a syntax error. + /// \param loc where the syntax error is found. + /// \param msg a description of the syntax error. + virtual void error(const location_type& loc, const std::string& msg); + + /// Report a syntax error. + void error(const syntax_error& err); + + // Implementation of make_symbol for each symbol type. +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_END_OF_FILE(location_type l) { + return symbol_type(token::END_OF_FILE, std::move(l)); + } +#else + static symbol_type make_END_OF_FILE(const location_type& l) { + return symbol_type(token::END_OF_FILE, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_START_OBJECT(location_type l) { + return symbol_type(token::START_OBJECT, std::move(l)); + } +#else + static symbol_type make_START_OBJECT(const location_type& l) { + return symbol_type(token::START_OBJECT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_END_OBJECT(location_type l) { + return symbol_type(token::END_OBJECT, std::move(l)); + } +#else + static symbol_type make_END_OBJECT(const location_type& l) { + return symbol_type(token::END_OBJECT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_START_ORDERED_OBJECT(location_type l) { + return symbol_type(token::START_ORDERED_OBJECT, std::move(l)); + } +#else + static symbol_type make_START_ORDERED_OBJECT(const location_type& l) { + return symbol_type(token::START_ORDERED_OBJECT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_END_ORDERED_OBJECT(location_type l) { + return symbol_type(token::END_ORDERED_OBJECT, std::move(l)); + } +#else + static symbol_type make_END_ORDERED_OBJECT(const location_type& l) { + return symbol_type(token::END_ORDERED_OBJECT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_START_ARRAY(location_type l) { + return symbol_type(token::START_ARRAY, std::move(l)); + } +#else + static symbol_type make_START_ARRAY(const location_type& l) { + return symbol_type(token::START_ARRAY, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_END_ARRAY(location_type l) { + return symbol_type(token::END_ARRAY, std::move(l)); + } +#else + static symbol_type make_END_ARRAY(const location_type& l) { + return symbol_type(token::END_ARRAY, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_STAGE_INHIBIT_OPTIMIZATION(location_type l) { + return symbol_type(token::STAGE_INHIBIT_OPTIMIZATION, std::move(l)); + } +#else + static symbol_type make_STAGE_INHIBIT_OPTIMIZATION(const location_type& l) { + return symbol_type(token::STAGE_INHIBIT_OPTIMIZATION, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_STRING(std::string v, location_type l) { + return symbol_type(token::STRING, std::move(v), std::move(l)); + } +#else + static symbol_type make_STRING(const std::string& v, const location_type& l) { + return symbol_type(token::STRING, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_NUMBER_INT(int v, location_type l) { + return symbol_type(token::NUMBER_INT, std::move(v), std::move(l)); + } +#else + static symbol_type make_NUMBER_INT(const int& v, const location_type& l) { + return symbol_type(token::NUMBER_INT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_NUMBER_LONG(long long v, location_type l) { + return symbol_type(token::NUMBER_LONG, std::move(v), std::move(l)); + } +#else + static symbol_type make_NUMBER_LONG(const long long& v, const location_type& l) { + return symbol_type(token::NUMBER_LONG, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_NUMBER_DOUBLE(double v, location_type l) { + return symbol_type(token::NUMBER_DOUBLE, std::move(v), std::move(l)); + } +#else + static symbol_type make_NUMBER_DOUBLE(const double& v, const location_type& l) { + return symbol_type(token::NUMBER_DOUBLE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static symbol_type make_BOOL(bool v, location_type l) { + return symbol_type(token::BOOL, std::move(v), std::move(l)); + } +#else + static symbol_type make_BOOL(const bool& v, const location_type& l) { + return symbol_type(token::BOOL, v, l); + } +#endif + + +private: + /// This class is not copyable. + PipelineParserGen(const PipelineParserGen&); + PipelineParserGen& operator=(const PipelineParserGen&); + + /// Stored state numbers (used for stacks). + typedef signed char state_type; + + /// Generate an error message. + /// \param yystate the state where the error occurred. + /// \param yyla the lookahead token. + virtual std::string yysyntax_error_(state_type yystate, const symbol_type& yyla) const; + + /// Compute post-reduction state. + /// \param yystate the current state + /// \param yysym the nonterminal to push on the stack + static state_type yy_lr_goto_state_(state_type yystate, int yysym); + + /// Whether the given \c yypact_ value indicates a defaulted state. + /// \param yyvalue the value to check + static bool yy_pact_value_is_default_(int yyvalue); + + /// Whether the given \c yytable_ value indicates a syntax error. + /// \param yyvalue the value to check + static bool yy_table_value_is_error_(int yyvalue); + + static const signed char yypact_ninf_; + static const signed char yytable_ninf_; + + /// Convert a scanner token number \a t to a symbol number. + /// In theory \a t should be a token_type, but character literals + /// are valid, yet not members of the token_type enum. + static token_number_type yytranslate_(int t); + + // Tables. + // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + // STATE-NUM. + static const signed char yypact_[]; + + // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + // Performed when YYTABLE does not specify something else to do. Zero + // means the default is an error. + static const signed char yydefact_[]; + + // YYPGOTO[NTERM-NUM]. + static const signed char yypgoto_[]; + + // YYDEFGOTO[NTERM-NUM]. + static const signed char yydefgoto_[]; + + // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + // positive, shift that token. If negative, reduce the rule whose + // number is the opposite. If YYTABLE_NINF, syntax error. + static const signed char yytable_[]; + + static const signed char yycheck_[]; + + // YYSTOS[STATE-NUM] -- The (internal number of the) accessing + // symbol of state STATE-NUM. + static const signed char yystos_[]; + + // YYR1[YYN] -- Symbol number of symbol that rule YYN derives. + static const signed char yyr1_[]; + + // YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. + static const signed char yyr2_[]; + + +#if YYDEBUG + /// For a symbol, its name in clear. + static const char* const yytname_[]; + + // YYRLINE[YYN] -- Source line where rule number YYN was defined. + static const unsigned char yyrline_[]; + /// Report on the debug stream that the rule \a r is going to be reduced. + virtual void yy_reduce_print_(int r); + /// Print the state stack on the debug stream. + virtual void yystack_print_(); + + /// Debugging level. + int yydebug_; + /// Debug stream. + std::ostream* yycdebug_; + + /// \brief Display a symbol type, value and location. + /// \param yyo The output stream. + /// \param yysym The symbol. + template <typename Base> + void yy_print_(std::ostream& yyo, const basic_symbol<Base>& yysym) const; +#endif + + /// \brief Reclaim the memory associated to a symbol. + /// \param yymsg Why this token is reclaimed. + /// If null, print nothing. + /// \param yysym The symbol. + template <typename Base> + void yy_destroy_(const char* yymsg, basic_symbol<Base>& yysym) const; + +private: + /// Type access provider for state based symbols. + struct by_state { + /// Default constructor. + by_state() YY_NOEXCEPT; + + /// The symbol type as needed by the constructor. + typedef state_type kind_type; + + /// Constructor. + by_state(kind_type s) YY_NOEXCEPT; + + /// Copy constructor. + by_state(const by_state& that) YY_NOEXCEPT; + + /// Record that this symbol is empty. + void clear() YY_NOEXCEPT; + + /// Steal the symbol type from \a that. + void move(by_state& that); + + /// The (internal) type number (corresponding to \a state). + /// \a empty_symbol when empty. + symbol_number_type type_get() const YY_NOEXCEPT; + + /// The state number used to denote an empty symbol. + /// We use the initial state, as it does not have a value. + enum { empty_state = 0 }; + + /// The state. + /// \a empty when empty. + state_type state; + }; + + /// "Internal" symbol: element of the stack. + struct stack_symbol_type : basic_symbol<by_state> { + /// Superclass. + typedef basic_symbol<by_state> super_type; + /// Construct an empty symbol. + stack_symbol_type(); + /// Move or copy construction. + stack_symbol_type(YY_RVREF(stack_symbol_type) that); + /// Steal the contents from \a sym to build this. + stack_symbol_type(state_type s, YY_MOVE_REF(symbol_type) sym); +#if YY_CPLUSPLUS < 201103L + /// Assignment, needed by push_back by some old implementations. + /// Moves the contents of that. + stack_symbol_type& operator=(stack_symbol_type& that); + + /// Assignment, needed by push_back by other implementations. + /// Needed by some other old implementations. + stack_symbol_type& operator=(const stack_symbol_type& that); +#endif + }; + + /// A stack with random access from its top. + template <typename T, typename S = std::vector<T>> + class stack { + public: + // Hide our reversed order. + typedef typename S::reverse_iterator iterator; + typedef typename S::const_reverse_iterator const_iterator; + typedef typename S::size_type size_type; + typedef typename std::ptrdiff_t index_type; + + stack(size_type n = 200) : seq_(n) {} + + /// Random access. + /// + /// Index 0 returns the topmost element. + const T& operator[](index_type i) const { + return seq_[size_type(size() - 1 - i)]; + } + + /// Random access. + /// + /// Index 0 returns the topmost element. + T& operator[](index_type i) { + return seq_[size_type(size() - 1 - i)]; + } + + /// Steal the contents of \a t. + /// + /// Close to move-semantics. + void push(YY_MOVE_REF(T) t) { + seq_.push_back(T()); + operator[](0).move(t); + } + + /// Pop elements from the stack. + void pop(std::ptrdiff_t n = 1) YY_NOEXCEPT { + for (; 0 < n; --n) + seq_.pop_back(); + } + + /// Pop all elements from the stack. + void clear() YY_NOEXCEPT { + seq_.clear(); + } + + /// Number of elements on the stack. + index_type size() const YY_NOEXCEPT { + return index_type(seq_.size()); + } + + std::ptrdiff_t ssize() const YY_NOEXCEPT { + return std::ptrdiff_t(size()); + } + + /// Iterator on top of the stack (going downwards). + const_iterator begin() const YY_NOEXCEPT { + return seq_.rbegin(); + } + + /// Bottom of the stack. + const_iterator end() const YY_NOEXCEPT { + return seq_.rend(); + } + + /// Present a slice of the top of a stack. + class slice { + public: + slice(const stack& stack, index_type range) : stack_(stack), range_(range) {} + + const T& operator[](index_type i) const { + return stack_[range_ - i]; + } + + private: + const stack& stack_; + index_type range_; + }; + + private: + stack(const stack&); + stack& operator=(const stack&); + /// The wrapped container. + S seq_; + }; + + + /// Stack type. + typedef stack<stack_symbol_type> stack_type; + + /// The stack. + stack_type yystack_; + + /// Push a new state on the stack. + /// \param m a debug message to display + /// if null, no trace is output. + /// \param sym the symbol + /// \warning the contents of \a s.value is stolen. + void yypush_(const char* m, YY_MOVE_REF(stack_symbol_type) sym); + + /// Push a new look ahead token on the state on the stack. + /// \param m a debug message to display + /// if null, no trace is output. + /// \param s the state + /// \param sym the symbol (for its value and location). + /// \warning the contents of \a sym.value is stolen. + void yypush_(const char* m, state_type s, YY_MOVE_REF(symbol_type) sym); + + /// Pop \a n symbols from the stack. + void yypop_(int n = 1); + + /// Some specific tokens. + static const token_number_type yy_error_token_ = 1; + static const token_number_type yy_undef_token_ = 2; + + /// Constants. + enum { + yyeof_ = 0, + yylast_ = 8, ///< Last index in yytable_. + yynnts_ = 4, ///< Number of nonterminal symbols. + yyfinal_ = 5, ///< Termination state number. + yyntokens_ = 15 ///< Number of tokens. + }; + + + // User arguments. + BSONLexer& driver; + CNode* cst; +}; + +inline PipelineParserGen::token_number_type PipelineParserGen::yytranslate_(int t) { + return static_cast<token_number_type>(t); +} + +// basic_symbol. +#if 201103L <= YY_CPLUSPLUS +template <typename Base> +PipelineParserGen::basic_symbol<Base>::basic_symbol(basic_symbol&& that) + : Base(std::move(that)), value(), location(std::move(that.location)) { + switch (this->type_get()) { + case 17: // stageList + value.move<CNode>(std::move(that.value)); + break; + + case 14: // BOOL + value.move<bool>(std::move(that.value)); + break; + + case 13: // NUMBER_DOUBLE + value.move<double>(std::move(that.value)); + break; + + case 11: // NUMBER_INT + value.move<int>(std::move(that.value)); + break; + + case 12: // NUMBER_LONG + value.move<long long>(std::move(that.value)); + break; + + case 18: // stage + value.move<std::pair<KeyFieldname, CNode>>(std::move(that.value)); + break; + + case 10: // STRING + value.move<std::string>(std::move(that.value)); + break; + + default: + break; + } +} +#endif + +template <typename Base> +PipelineParserGen::basic_symbol<Base>::basic_symbol(const basic_symbol& that) + : Base(that), value(), location(that.location) { + switch (this->type_get()) { + case 17: // stageList + value.copy<CNode>(YY_MOVE(that.value)); + break; + + case 14: // BOOL + value.copy<bool>(YY_MOVE(that.value)); + break; + + case 13: // NUMBER_DOUBLE + value.copy<double>(YY_MOVE(that.value)); + break; + + case 11: // NUMBER_INT + value.copy<int>(YY_MOVE(that.value)); + break; + + case 12: // NUMBER_LONG + value.copy<long long>(YY_MOVE(that.value)); + break; + + case 18: // stage + value.copy<std::pair<KeyFieldname, CNode>>(YY_MOVE(that.value)); + break; + + case 10: // STRING + value.copy<std::string>(YY_MOVE(that.value)); + break; + + default: + break; + } +} + + +template <typename Base> +bool PipelineParserGen::basic_symbol<Base>::empty() const YY_NOEXCEPT { + return Base::type_get() == empty_symbol; +} + +template <typename Base> +void PipelineParserGen::basic_symbol<Base>::move(basic_symbol& s) { + super_type::move(s); + switch (this->type_get()) { + case 17: // stageList + value.move<CNode>(YY_MOVE(s.value)); + break; + + case 14: // BOOL + value.move<bool>(YY_MOVE(s.value)); + break; + + case 13: // NUMBER_DOUBLE + value.move<double>(YY_MOVE(s.value)); + break; + + case 11: // NUMBER_INT + value.move<int>(YY_MOVE(s.value)); + break; + + case 12: // NUMBER_LONG + value.move<long long>(YY_MOVE(s.value)); + break; + + case 18: // stage + value.move<std::pair<KeyFieldname, CNode>>(YY_MOVE(s.value)); + break; + + case 10: // STRING + value.move<std::string>(YY_MOVE(s.value)); + break; + + default: + break; + } + + location = YY_MOVE(s.location); +} + +// by_type. +inline PipelineParserGen::by_type::by_type() : type(empty_symbol) {} + +#if 201103L <= YY_CPLUSPLUS +inline PipelineParserGen::by_type::by_type(by_type&& that) : type(that.type) { + that.clear(); +} +#endif + +inline PipelineParserGen::by_type::by_type(const by_type& that) : type(that.type) {} + +inline PipelineParserGen::by_type::by_type(token_type t) : type(yytranslate_(t)) {} + +inline void PipelineParserGen::by_type::clear() { + type = empty_symbol; +} + +inline void PipelineParserGen::by_type::move(by_type& that) { + type = that.type; + that.clear(); +} + +inline int PipelineParserGen::by_type::type_get() const YY_NOEXCEPT { + return type; +} + +#line 52 "src/mongo/db/cst/pipeline_grammar.yy" +} // namespace mongo +#line 1564 "src/mongo/db/cst/pipeline_parser_gen.hpp" + + +#endif // !YY_YY_SRC_MONGO_DB_CST_PIPELINE_PARSER_GEN_HPP_INCLUDED |