summaryrefslogtreecommitdiff
path: root/src/mongo/db/cst
diff options
context:
space:
mode:
authorNick Zolnierz <nicholas.zolnierz@mongodb.com>2020-07-07 16:58:11 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-08 15:27:48 +0000
commit4fc14ec5933feb9b5c1e9a4aa7203d76a685b28b (patch)
tree75107158f04f75b4ba2aad6dcae2d1b2f7b14922 /src/mongo/db/cst
parent8b4cd661c63d676e212f659096eaa4d5722cc49d (diff)
downloadmongo-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/SConscript3
-rw-r--r--src/mongo/db/cst/bson_lexer.cpp153
-rw-r--r--src/mongo/db/cst/bson_lexer.h74
-rw-r--r--src/mongo/db/cst/c_node.h4
-rw-r--r--src/mongo/db/cst/cst_test.cpp60
-rw-r--r--src/mongo/db/cst/key_fieldname.h3
-rw-r--r--src/mongo/db/cst/location_gen.h267
-rw-r--r--src/mongo/db/cst/pipeline_grammar.yy144
-rw-r--r--src/mongo/db/cst/pipeline_parser_gen.cpp888
-rw-r--r--src/mongo/db/cst/pipeline_parser_gen.hpp1304
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