//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Jan Steemann //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGOD_AQL_AST_H #define ARANGOD_AQL_AST_H 1 #include "Basics/Common.h" #include "Aql/AstNode.h" #include "Aql/BindParameters.h" #include "Aql/Scopes.h" #include "Aql/Variable.h" #include "Aql/VariableGenerator.h" #include "Basics/json.h" #include "VocBase/transaction.h" #include namespace arangodb { namespace aql { class Query; typedef std::unordered_map> TopLevelAttributes; //////////////////////////////////////////////////////////////////////////////// /// @brief the AST //////////////////////////////////////////////////////////////////////////////// class Ast { friend class Condition; public: ////////////////////////////////////////////////////////////////////////////// /// @brief create the AST ////////////////////////////////////////////////////////////////////////////// Ast(Query*); ////////////////////////////////////////////////////////////////////////////// /// @brief destroy the AST ////////////////////////////////////////////////////////////////////////////// ~Ast(); public: ////////////////////////////////////////////////////////////////////////////// /// @brief return the query ////////////////////////////////////////////////////////////////////////////// inline Query* query() const { return _query; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the variable generator ////////////////////////////////////////////////////////////////////////////// inline VariableGenerator* variables() { return &_variables; } ////////////////////////////////////////////////////////////////////////////// /// @brief return the variable generator ////////////////////////////////////////////////////////////////////////////// inline VariableGenerator* variables() const { return const_cast(&_variables); } ////////////////////////////////////////////////////////////////////////////// /// @brief return the root of the AST ////////////////////////////////////////////////////////////////////////////// inline AstNode const* root() const { return _root; } ////////////////////////////////////////////////////////////////////////////// /// @brief begin a subquery ////////////////////////////////////////////////////////////////////////////// void startSubQuery() { // insert a new root node AstNodeType type; if (_queries.empty()) { // root node of query type = NODE_TYPE_ROOT; } else { // sub query node type = NODE_TYPE_SUBQUERY; } auto root = createNode(type); // save the root node _queries.emplace_back(root); // set the current root node if everything went well _root = root; } ////////////////////////////////////////////////////////////////////////////// /// @brief end a subquery ////////////////////////////////////////////////////////////////////////////// AstNode* endSubQuery() { // get the current root node AstNode* root = _queries.back(); // remove it from the stack _queries.pop_back(); // set root node to previous root node _root = _queries.back(); // return the root node we just popped from the stack return root; } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not we currently are in a subquery ////////////////////////////////////////////////////////////////////////////// bool isInSubQuery() const { return (_queries.size() > 1); } ////////////////////////////////////////////////////////////////////////////// /// @brief return a copy of our own bind parameters ////////////////////////////////////////////////////////////////////////////// std::unordered_set bindParameters() const { return std::unordered_set(_bindParameters); } ////////////////////////////////////////////////////////////////////////////// /// @brief get the query scopes ////////////////////////////////////////////////////////////////////////////// inline Scopes* scopes() { return &_scopes; } ////////////////////////////////////////////////////////////////////////////// /// @brief track the write collection ////////////////////////////////////////////////////////////////////////////// inline void addWriteCollection(AstNode const* node) { TRI_ASSERT(node->type == NODE_TYPE_COLLECTION || node->type == NODE_TYPE_PARAMETER); _writeCollections.emplace_back(node); } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not function calls may access collection documents ////////////////////////////////////////////////////////////////////////////// bool functionsMayAccessDocuments() const { return _functionsMayAccessDocuments; } ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the query contains a traversal ////////////////////////////////////////////////////////////////////////////// bool containsTraversal() const { return _containsTraversal; } ////////////////////////////////////////////////////////////////////////////// /// @brief convert the AST into JSON /// the caller is responsible for freeing the JSON later ////////////////////////////////////////////////////////////////////////////// TRI_json_t* toJson(TRI_memory_zone_t*, bool) const; ////////////////////////////////////////////////////////////////////////////// /// @brief add an operation to the root node ////////////////////////////////////////////////////////////////////////////// void addOperation(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief find the bottom-most expansion subnodes (if any) ////////////////////////////////////////////////////////////////////////////// AstNode const* findExpansionSubNode(AstNode const*) const; ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST passthru node /// note: this type of node is only used during parsing and optimized away /// later ////////////////////////////////////////////////////////////////////////////// AstNode* createNodePassthru(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST example node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeExample(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST for node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeFor(char const*, size_t, AstNode const*, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST let node, without an IF condition ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeLet(char const*, size_t, AstNode const*, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST let node, without creating a variable ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeLet(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST let node, with an IF condition ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeLet(char const*, size_t, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST filter node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeFilter(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST filter node for an UPSERT query ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeUpsertFilter(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST return node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeReturn(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST remove node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeRemove(AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST insert node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeInsert(AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST update node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeUpdate(AstNode const*, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST replace node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeReplace(AstNode const*, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST upsert node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeUpsert(AstNodeType, AstNode const*, AstNode const*, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST distinct node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeDistinct(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST collect node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeCollect(AstNode const*, AstNode const*, AstNode const*, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST collect node, COUNT INTO ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeCollectCount(AstNode const*, char const*, size_t length, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST sort node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeSort(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST sort element node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeSortElement(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST limit node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeLimit(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST assign node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeAssign(char const*, size_t, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST variable node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeVariable(char const*, size_t, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST collection node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeCollection(char const*, TRI_transaction_type_e); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST reference node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeReference(char const*, size_t); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST reference node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeReference(std::string const&); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST reference node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeReference(Variable const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST parameter node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeParameter(char const*, size_t); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST quantifier node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeQuantifier(int64_t); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST unary operator ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeUnaryOperator(AstNodeType, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST binary operator ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeBinaryOperator(AstNodeType, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST binary array operator ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeBinaryArrayOperator(AstNodeType, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST ternary operator ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeTernaryOperator(AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST attribute access node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeAttributeAccess(AstNode const*, char const*, size_t); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST attribute access node w/ bind parameter ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeBoundAttributeAccess(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST index access node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeIndexedAccess(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST array limit node (offset, count) ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeArrayLimit(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST expansion node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeExpansion(int64_t, AstNode const*, AstNode const*, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST iterator node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeIterator(char const*, size_t, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST null value node ////////////////////////////////////////////////////////////////////////////// static AstNode* createNodeValueNull(); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST bool value node ////////////////////////////////////////////////////////////////////////////// static AstNode* createNodeValueBool(bool); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST int value node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeValueInt(int64_t); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST double value node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeValueDouble(double); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST string value node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeValueString(char const*, size_t); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST array node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeArray(); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST unique array node, AND-merged from two other arrays ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeIntersectedArray(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST unique array node, OR-merged from two other arrays ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeUnionizedArray(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST object node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeObject(); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST object element node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeObjectElement(char const*, size_t, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST calculated object element node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeCalculatedObjectElement(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST collection pair node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeCollectionPair(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST collection list node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeCollectionList(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST direction node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeDirection(uint64_t, uint64_t); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST direction node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeDirection(uint64_t, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST direction node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeCollectionDirection(uint64_t, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST traversal node with only vertex variable ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeTraversal(char const*, size_t, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST traversal node with vertex and edge variable ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeTraversal(char const*, size_t, char const*, size_t, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST traversal node with vertex, edge and path variable ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeTraversal(char const*, size_t, char const*, size_t, char const*, size_t, AstNode const*, AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST function call node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeFunctionCall(char const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST range node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeRange(AstNode const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST nop node ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeNop(); ////////////////////////////////////////////////////////////////////////////// /// @brief get the AST nop node ////////////////////////////////////////////////////////////////////////////// static AstNode* getNodeNop(); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST n-ary operator ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeNaryOperator(AstNodeType); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST n-ary operator ////////////////////////////////////////////////////////////////////////////// AstNode* createNodeNaryOperator(AstNodeType, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief injects bind parameters into the AST ////////////////////////////////////////////////////////////////////////////// void injectBindParameters(BindParameters&); ////////////////////////////////////////////////////////////////////////////// /// @brief replace variables ////////////////////////////////////////////////////////////////////////////// AstNode* replaceVariables( AstNode*, std::unordered_map const&); ////////////////////////////////////////////////////////////////////////////// /// @brief replace a variable reference in the expression with another /// expression (e.g. inserting c = `a + b` into expression `c + 1` so the /// latter /// becomes `a + b + 1` ////////////////////////////////////////////////////////////////////////////// AstNode* replaceVariableReference(AstNode*, Variable const*, AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the AST ////////////////////////////////////////////////////////////////////////////// void validateAndOptimize(); ////////////////////////////////////////////////////////////////////////////// /// @brief determines the variables referenced in an expression ////////////////////////////////////////////////////////////////////////////// static void getReferencedVariables(AstNode const*, std::unordered_set&); ////////////////////////////////////////////////////////////////////////////// /// @brief determines the top-level attributes in an expression, grouped by /// variable ////////////////////////////////////////////////////////////////////////////// static TopLevelAttributes getReferencedAttributes(AstNode const*, bool&); ////////////////////////////////////////////////////////////////////////////// /// @brief recursively clone a node ////////////////////////////////////////////////////////////////////////////// AstNode* clone(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief deduplicate an array /// will return the original node if no modifications were made, and a new /// node if the array contained modifications ////////////////////////////////////////////////////////////////////////////// AstNode const* deduplicateArray(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief check if an operator is reversible ////////////////////////////////////////////////////////////////////////////// static bool IsReversibleOperator(AstNodeType); ////////////////////////////////////////////////////////////////////////////// /// @brief get the reversed operator for a comparison operator ////////////////////////////////////////////////////////////////////////////// static AstNodeType ReverseOperator(AstNodeType); ////////////////////////////////////////////////////////////////////////////// /// @brief get the n-ary operator type equivalent for a binary operator type ////////////////////////////////////////////////////////////////////////////// static AstNodeType NaryOperatorType(AstNodeType); ////////////////////////////////////////////////////////////////////////////// /// @brief create an AST node from JSON ////////////////////////////////////////////////////////////////////////////// AstNode* nodeFromJson(TRI_json_t const*, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief traverse the AST using a depth-first visitor ////////////////////////////////////////////////////////////////////////////// static AstNode* traverseAndModify(AstNode*, std::function, void*); private: ////////////////////////////////////////////////////////////////////////////// /// @brief make condition from example ////////////////////////////////////////////////////////////////////////////// AstNode* makeConditionFromExample(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create a number node for an arithmetic result, integer ////////////////////////////////////////////////////////////////////////////// AstNode* createArithmeticResultNode(int64_t); ////////////////////////////////////////////////////////////////////////////// /// @brief create a number node for an arithmetic result, double ////////////////////////////////////////////////////////////////////////////// AstNode* createArithmeticResultNode(double); ////////////////////////////////////////////////////////////////////////////// /// @brief executes an expression with constant parameters ////////////////////////////////////////////////////////////////////////////// AstNode* executeConstExpression(AstNode const*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the unary operators + and - /// the unary plus will be converted into a simple value node if the operand /// of /// the operation is a constant number ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeUnaryOperatorArithmetic(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the unary operator NOT with a non-constant expression ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeNotExpression(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the unary operator NOT ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeUnaryOperatorLogical(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the binary logical operators && and || ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeBinaryOperatorLogical(AstNode*, bool); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the binary relational operators <, <=, >, >=, ==, != and /// IN ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeBinaryOperatorRelational(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the binary arithmetic operators +, -, *, / and % ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeBinaryOperatorArithmetic(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the ternary operator ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeTernaryOperator(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes an attribute access ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeAttributeAccess(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes a call to a built-in function ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeFunctionCall(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes a reference to a variable ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeReference(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes indexed access, e.g. a[0] or a['foo'] ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeIndexedAccess(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the LET statement ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeLet(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the FILTER statement ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeFilter(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief optimizes the FOR statement /// no real optimizations are done here, but we do an early check if the /// FOR loop operand is actually a list ////////////////////////////////////////////////////////////////////////////// AstNode* optimizeFor(AstNode*); ////////////////////////////////////////////////////////////////////////////// /// @brief traverse the AST, using pre- and post-order visitors ////////////////////////////////////////////////////////////////////////////// static AstNode* traverseAndModify(AstNode*, std::function, std::function, std::function, void*); ////////////////////////////////////////////////////////////////////////////// /// @brief traverse the AST, using pre- and post-order visitors ////////////////////////////////////////////////////////////////////////////// static void traverseReadOnly(AstNode const*, std::function, std::function, std::function, void*); ////////////////////////////////////////////////////////////////////////////// /// @brief traverse the AST using a depth-first visitor, with const nodes ////////////////////////////////////////////////////////////////////////////// static void traverseReadOnly(AstNode const*, std::function, void*); ////////////////////////////////////////////////////////////////////////////// /// @brief normalize a function name ////////////////////////////////////////////////////////////////////////////// std::pair normalizeFunctionName(char const*); ////////////////////////////////////////////////////////////////////////////// /// @brief create a node of the specified type ////////////////////////////////////////////////////////////////////////////// AstNode* createNode(AstNodeType); public: ////////////////////////////////////////////////////////////////////////////// /// @brief negated comparison operators ////////////////////////////////////////////////////////////////////////////// static std::unordered_map const NegatedOperators; ////////////////////////////////////////////////////////////////////////////// /// @brief reverse comparison operators ////////////////////////////////////////////////////////////////////////////// static std::unordered_map const ReversedOperators; private: ////////////////////////////////////////////////////////////////////////////// /// @brief the query ////////////////////////////////////////////////////////////////////////////// Query* _query; ////////////////////////////////////////////////////////////////////////////// /// @brief all scopes used in the query ////////////////////////////////////////////////////////////////////////////// Scopes _scopes; ////////////////////////////////////////////////////////////////////////////// /// @brief generator for variables ////////////////////////////////////////////////////////////////////////////// VariableGenerator _variables; ////////////////////////////////////////////////////////////////////////////// /// @brief the bind parameters we found in the query ////////////////////////////////////////////////////////////////////////////// std::unordered_set _bindParameters; ////////////////////////////////////////////////////////////////////////////// /// @brief root node of the AST ////////////////////////////////////////////////////////////////////////////// AstNode* _root; ////////////////////////////////////////////////////////////////////////////// /// @brief root nodes of queries and subqueries ////////////////////////////////////////////////////////////////////////////// std::vector _queries; ////////////////////////////////////////////////////////////////////////////// /// @brief which collection is going to be modified in the query ////////////////////////////////////////////////////////////////////////////// std::vector _writeCollections; ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not function calls may access collection data ////////////////////////////////////////////////////////////////////////////// bool _functionsMayAccessDocuments; ////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the query contains a traversal ////////////////////////////////////////////////////////////////////////////// bool _containsTraversal; ////////////////////////////////////////////////////////////////////////////// /// @brief a singleton no-op node instance ////////////////////////////////////////////////////////////////////////////// static AstNode const NopNode; ////////////////////////////////////////////////////////////////////////////// /// @brief a singleton null node instance ////////////////////////////////////////////////////////////////////////////// static AstNode const NullNode; ////////////////////////////////////////////////////////////////////////////// /// @brief a singleton false node instance ////////////////////////////////////////////////////////////////////////////// static AstNode const FalseNode; ////////////////////////////////////////////////////////////////////////////// /// @brief a singleton true node instance ////////////////////////////////////////////////////////////////////////////// static AstNode const TrueNode; ////////////////////////////////////////////////////////////////////////////// /// @brief a singleton zero node instance ////////////////////////////////////////////////////////////////////////////// static AstNode const ZeroNode; ////////////////////////////////////////////////////////////////////////////// /// @brief a singleton empty string node instance ////////////////////////////////////////////////////////////////////////////// static AstNode const EmptyStringNode; }; } } #endif