mirror of https://gitee.com/bigwinds/arangodb
1092 lines
36 KiB
C
1092 lines
36 KiB
C
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Ahuacatl, parser nodes
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2010-2012 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 triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// @author Jan Steemann
|
|
/// @author Copyright 2012, triagens GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Ahuacatl/ahuacatl-ast-node.h"
|
|
#include "Ahuacatl/ahuacatl-collections.h"
|
|
#include "Ahuacatl/ahuacatl-functions.h"
|
|
#include "Ahuacatl/ahuacatl-parser-functions.h"
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private macros
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup Ahuacatl
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief shortcut macro for signalling out of memory
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define ABORT_OOM \
|
|
TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); \
|
|
return NULL;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief shortcut macro to create a new node or fail in case of OOM
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define CREATE_NODE(type) \
|
|
TRI_aql_node_t* node = (TRI_aql_node_t*) \
|
|
TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_node_t), false); \
|
|
if (!node) { \
|
|
ABORT_OOM \
|
|
} \
|
|
\
|
|
assert(context); \
|
|
InitNode(context, node, type);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief add a sub node to a node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define ADD_MEMBER(member) \
|
|
if (!member) { \
|
|
ABORT_OOM \
|
|
} \
|
|
\
|
|
TRI_PushBackVectorPointer(&node->_members, (void*) member);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup Ahuacatl
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static inline void InitNode (TRI_aql_context_t* const context,
|
|
TRI_aql_node_t* const node,
|
|
const TRI_aql_node_type_e type) {
|
|
node->_type = type;
|
|
node->_next = NULL;
|
|
|
|
TRI_InitVectorPointer(&node->_members, TRI_UNKNOWN_MEM_ZONE);
|
|
TRI_RegisterNodeContextAql(context, node);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup Ahuacatl
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get the "nice" name of an AST node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const char* TRI_NodeNameAql (const TRI_aql_node_type_e type) {
|
|
switch (type) {
|
|
case AQL_NODE_UNDEFINED:
|
|
return "undefined";
|
|
case AQL_NODE_FOR:
|
|
return "for";
|
|
case AQL_NODE_LET:
|
|
return "let";
|
|
case AQL_NODE_FILTER:
|
|
return "filter";
|
|
case AQL_NODE_RETURN:
|
|
return "return";
|
|
case AQL_NODE_COLLECT:
|
|
return "collect";
|
|
case AQL_NODE_SORT:
|
|
return "sort";
|
|
case AQL_NODE_SORT_ELEMENT:
|
|
return "sort element";
|
|
case AQL_NODE_LIMIT:
|
|
return "limit";
|
|
case AQL_NODE_VARIABLE:
|
|
return "variable";
|
|
case AQL_NODE_COLLECTION:
|
|
return "collection";
|
|
case AQL_NODE_REFERENCE:
|
|
return "reference";
|
|
case AQL_NODE_ATTRIBUTE:
|
|
return "attribute";
|
|
case AQL_NODE_ASSIGN:
|
|
return "assign";
|
|
case AQL_NODE_OPERATOR_UNARY_PLUS:
|
|
return "uplus";
|
|
case AQL_NODE_OPERATOR_UNARY_MINUS:
|
|
return "uminus";
|
|
case AQL_NODE_OPERATOR_UNARY_NOT:
|
|
return "unot";
|
|
case AQL_NODE_OPERATOR_BINARY_AND:
|
|
return "and";
|
|
case AQL_NODE_OPERATOR_BINARY_OR:
|
|
return "or";
|
|
case AQL_NODE_OPERATOR_BINARY_PLUS:
|
|
return "plus";
|
|
case AQL_NODE_OPERATOR_BINARY_MINUS:
|
|
return "minus";
|
|
case AQL_NODE_OPERATOR_BINARY_TIMES:
|
|
return "times";
|
|
case AQL_NODE_OPERATOR_BINARY_DIV:
|
|
return "div";
|
|
case AQL_NODE_OPERATOR_BINARY_MOD:
|
|
return "mod";
|
|
case AQL_NODE_OPERATOR_BINARY_EQ:
|
|
return "eq";
|
|
case AQL_NODE_OPERATOR_BINARY_NE:
|
|
return "ne";
|
|
case AQL_NODE_OPERATOR_BINARY_LT:
|
|
return "lt";
|
|
case AQL_NODE_OPERATOR_BINARY_LE:
|
|
return "le";
|
|
case AQL_NODE_OPERATOR_BINARY_GT:
|
|
return "gt";
|
|
case AQL_NODE_OPERATOR_BINARY_GE:
|
|
return "ge";
|
|
case AQL_NODE_OPERATOR_BINARY_IN:
|
|
return "in";
|
|
case AQL_NODE_OPERATOR_TERNARY:
|
|
return "ternary";
|
|
case AQL_NODE_SUBQUERY:
|
|
return "subquery";
|
|
case AQL_NODE_ATTRIBUTE_ACCESS:
|
|
return "attribute access";
|
|
case AQL_NODE_INDEXED:
|
|
return "indexed";
|
|
case AQL_NODE_EXPAND:
|
|
return "expand";
|
|
case AQL_NODE_VALUE:
|
|
return "value";
|
|
case AQL_NODE_LIST:
|
|
return "list";
|
|
case AQL_NODE_ARRAY:
|
|
return "array";
|
|
case AQL_NODE_ARRAY_ELEMENT:
|
|
return "array element";
|
|
case AQL_NODE_PARAMETER:
|
|
return "parameter";
|
|
case AQL_NODE_FCALL:
|
|
return "function call";
|
|
}
|
|
|
|
assert(false);
|
|
return "undefined";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST for node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeForAql (TRI_aql_context_t* const context,
|
|
const char* const name,
|
|
const TRI_aql_node_t* const expression) {
|
|
CREATE_NODE(AQL_NODE_FOR)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
if (!TRI_IsValidVariableNameAql(name)) {
|
|
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_VARIABLE_NAME_INVALID, name);
|
|
return NULL;
|
|
}
|
|
|
|
{
|
|
TRI_aql_node_t* variable = TRI_CreateNodeVariableAql(context, name);
|
|
ADD_MEMBER(variable)
|
|
ADD_MEMBER(expression)
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST let node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeLetAql (TRI_aql_context_t* const context,
|
|
const char* const name,
|
|
const TRI_aql_node_t* const expression) {
|
|
TRI_aql_node_let_t* node;
|
|
TRI_aql_node_t* variableNode;
|
|
|
|
assert(context);
|
|
|
|
if (!name || !expression) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
node = (TRI_aql_node_let_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_node_let_t), false);
|
|
|
|
if (!node) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
InitNode(context, (TRI_aql_node_t*) node, AQL_NODE_LET);
|
|
|
|
variableNode = TRI_CreateNodeVariableAql(context, name);
|
|
if (!variableNode) {
|
|
return NULL;
|
|
}
|
|
|
|
node->_variable = variableNode;
|
|
node->_expression = (TRI_aql_node_t*) expression;
|
|
|
|
return (TRI_aql_node_t*) node;
|
|
}
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST filter node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeFilterAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const expression) {
|
|
CREATE_NODE(AQL_NODE_FILTER)
|
|
|
|
ADD_MEMBER(expression)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST return node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeReturnAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const expression) {
|
|
CREATE_NODE(AQL_NODE_RETURN)
|
|
|
|
ADD_MEMBER(expression)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST collect node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeCollectAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const list,
|
|
const char* const name) {
|
|
CREATE_NODE(AQL_NODE_COLLECT)
|
|
|
|
ADD_MEMBER(list)
|
|
if (name) {
|
|
TRI_aql_node_t* variable = TRI_CreateNodeVariableAql(context, name);
|
|
ADD_MEMBER(variable)
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST sort node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeSortAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const list) {
|
|
CREATE_NODE(AQL_NODE_SORT)
|
|
|
|
ADD_MEMBER(list)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST sort element node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeSortElementAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const expression,
|
|
const bool ascending) {
|
|
CREATE_NODE(AQL_NODE_SORT_ELEMENT)
|
|
|
|
ADD_MEMBER(expression)
|
|
TRI_AQL_NODE_BOOL(node) = ascending;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST limit node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeLimitAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const offset,
|
|
const TRI_aql_node_t* const count) {
|
|
CREATE_NODE(AQL_NODE_LIMIT)
|
|
|
|
ADD_MEMBER(offset)
|
|
ADD_MEMBER(count)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST assign node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeAssignAql (TRI_aql_context_t* const context,
|
|
const char* const name,
|
|
const TRI_aql_node_t* const expression) {
|
|
CREATE_NODE(AQL_NODE_ASSIGN)
|
|
|
|
{
|
|
TRI_aql_node_t* variable = TRI_CreateNodeVariableAql(context, name);
|
|
ADD_MEMBER(variable)
|
|
ADD_MEMBER(expression)
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST variable node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeVariableAql (TRI_aql_context_t* const context,
|
|
const char* const name) {
|
|
CREATE_NODE(AQL_NODE_VARIABLE)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
if (!TRI_AddVariableContextAql(context, name)) {
|
|
// duplicate variable name
|
|
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_VARIABLE_REDECLARED, name);
|
|
return NULL;
|
|
}
|
|
|
|
TRI_AQL_NODE_STRING(node) = (char*) name;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST collection node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeCollectionAql (TRI_aql_context_t* const context,
|
|
const char* const name) {
|
|
CREATE_NODE(AQL_NODE_COLLECTION)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
TRI_AQL_NODE_STRING(node) = (char*) name;
|
|
|
|
// duplicates are not a problem here, we simply ignore them
|
|
TRI_InsertKeyAssociativePointer(&context->_collectionNames, name, (void*) name, false);
|
|
|
|
if (context->_collectionNames._nrUsed > AQL_MAX_COLLECTIONS) {
|
|
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_TOO_MANY_COLLECTIONS, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST reference node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeReferenceAql (TRI_aql_context_t* const context,
|
|
const char* const name) {
|
|
CREATE_NODE(AQL_NODE_REFERENCE)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
TRI_AQL_NODE_STRING(node) = (char*) name;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST attribute node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeAttributeAql (TRI_aql_context_t* const context,
|
|
const char* const name) {
|
|
CREATE_NODE(AQL_NODE_ATTRIBUTE)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
TRI_AQL_NODE_STRING(node) = (char*) name;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST parameter node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeParameterAql (TRI_aql_context_t* const context,
|
|
const char* const name) {
|
|
CREATE_NODE(AQL_NODE_PARAMETER)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
// save name of bind parameter for later
|
|
TRI_InsertKeyAssociativePointer(&context->_parameterNames, name, (void*) name, true);
|
|
|
|
TRI_AQL_NODE_STRING(node) = (char*) name;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST unary plus node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorUnaryPlusAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const operand) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_UNARY_PLUS)
|
|
|
|
ADD_MEMBER(operand)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST unary minus node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorUnaryMinusAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const operand) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_UNARY_MINUS)
|
|
|
|
ADD_MEMBER(operand)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST unary not node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorUnaryNotAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const operand) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_UNARY_NOT)
|
|
|
|
ADD_MEMBER(operand)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary and node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryAndAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_AND)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary or node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryOrAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_OR)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary eq node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryEqAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_EQ)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary ne node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryNeAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_NE)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary lt node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryLtAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_LT)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary le node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryLeAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_LE)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary gt node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryGtAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_GT)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary ge node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryGeAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_GE)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary in node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryInAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_IN)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary plus node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryPlusAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_PLUS)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary minus node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryMinusAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_MINUS)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary times node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryTimesAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_TIMES)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary div node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryDivAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_DIV)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST binary mod node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorBinaryModAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const lhs,
|
|
const TRI_aql_node_t* const rhs) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_BINARY_MOD)
|
|
|
|
ADD_MEMBER(lhs)
|
|
ADD_MEMBER(rhs)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST ternary operator node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeOperatorTernaryAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const condition,
|
|
const TRI_aql_node_t* const truePart,
|
|
const TRI_aql_node_t* const falsePart) {
|
|
CREATE_NODE(AQL_NODE_OPERATOR_TERNARY)
|
|
|
|
ADD_MEMBER(condition)
|
|
ADD_MEMBER(truePart)
|
|
ADD_MEMBER(falsePart)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST subquery node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeSubqueryAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const query) {
|
|
CREATE_NODE(AQL_NODE_SUBQUERY)
|
|
|
|
ADD_MEMBER(query)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST attribute access node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeAttributeAccessAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const accessed,
|
|
const char* const name) {
|
|
CREATE_NODE(AQL_NODE_ATTRIBUTE_ACCESS)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
ADD_MEMBER(accessed)
|
|
TRI_AQL_NODE_STRING(node) = (char*) name;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST index access node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeIndexedAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const accessed,
|
|
const TRI_aql_node_t* const indexValue) {
|
|
CREATE_NODE(AQL_NODE_INDEXED)
|
|
|
|
ADD_MEMBER(accessed)
|
|
ADD_MEMBER(indexValue)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST expand node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeExpandAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const expanded,
|
|
const TRI_aql_node_t* const expansion) {
|
|
CREATE_NODE(AQL_NODE_EXPAND)
|
|
|
|
ADD_MEMBER(expanded)
|
|
ADD_MEMBER(expansion)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST null value node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeValueNullAql (TRI_aql_context_t* const context) {
|
|
CREATE_NODE(AQL_NODE_VALUE)
|
|
|
|
TRI_AQL_NODE_TYPE(node) = AQL_TYPE_NULL;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST int value node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeValueIntAql (TRI_aql_context_t* const context,
|
|
const int64_t value) {
|
|
CREATE_NODE(AQL_NODE_VALUE)
|
|
|
|
TRI_AQL_NODE_TYPE(node) = AQL_TYPE_INT;
|
|
TRI_AQL_NODE_INT(node) = value;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST double value node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeValueDoubleAql (TRI_aql_context_t* const context,
|
|
const double value) {
|
|
CREATE_NODE(AQL_NODE_VALUE)
|
|
|
|
TRI_AQL_NODE_TYPE(node) = AQL_TYPE_DOUBLE;
|
|
TRI_AQL_NODE_DOUBLE(node) = value;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST bool value node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeValueBoolAql (TRI_aql_context_t* const context,
|
|
const bool value) {
|
|
CREATE_NODE(AQL_NODE_VALUE)
|
|
|
|
TRI_AQL_NODE_TYPE(node) = AQL_TYPE_BOOL;
|
|
TRI_AQL_NODE_BOOL(node) = value;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST string value node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeValueStringAql (TRI_aql_context_t* const context,
|
|
const char* const value) {
|
|
CREATE_NODE(AQL_NODE_VALUE)
|
|
|
|
if (!value) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
TRI_AQL_NODE_TYPE(node) = AQL_TYPE_STRING;
|
|
TRI_AQL_NODE_STRING(node) = (char*) value;
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST list node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeListAql (TRI_aql_context_t* const context) {
|
|
CREATE_NODE(AQL_NODE_LIST)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST array node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeArrayAql (TRI_aql_context_t* const context) {
|
|
CREATE_NODE(AQL_NODE_ARRAY)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST array element node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeArrayElementAql (TRI_aql_context_t* const context,
|
|
const char* const name,
|
|
const TRI_aql_node_t* const value) {
|
|
CREATE_NODE(AQL_NODE_ARRAY_ELEMENT)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
TRI_AQL_NODE_STRING(node) = (char*) name;
|
|
ADD_MEMBER(value)
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create an AST function call node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_node_t* TRI_CreateNodeFcallAql (TRI_aql_context_t* const context,
|
|
const char* const name,
|
|
const TRI_aql_node_t* const parameters) {
|
|
CREATE_NODE(AQL_NODE_FCALL)
|
|
|
|
if (!name) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
{
|
|
TRI_aql_function_t* function;
|
|
TRI_associative_pointer_t* functions;
|
|
char* upperName;
|
|
|
|
assert(context->_vocbase);
|
|
functions = context->_vocbase->_functions;
|
|
assert(functions);
|
|
|
|
// normalize the name by upper-casing it
|
|
upperName = TRI_UpperAsciiString(name);
|
|
if (!upperName) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
function = (TRI_aql_function_t*) TRI_LookupByKeyAssociativePointer(functions, (void*) upperName);
|
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, upperName);
|
|
|
|
if (!function) {
|
|
// function name is unknown
|
|
TRI_SetErrorContextAql(context, TRI_ERROR_QUERY_FUNCTION_NAME_UNKNOWN, name);
|
|
return NULL;
|
|
}
|
|
|
|
ADD_MEMBER(parameters)
|
|
TRI_AQL_NODE_DATA(node) = function;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief add a value to the end of a list
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool TRI_PushListAql (TRI_aql_context_t* const context,
|
|
const TRI_aql_node_t* const value) {
|
|
TRI_aql_node_t* node = TRI_PeekStackParseAql(context);
|
|
|
|
assert(node);
|
|
|
|
ADD_MEMBER(value)
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief add a value to the end of an array
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool TRI_PushArrayAql (TRI_aql_context_t* const context,
|
|
const char* const name,
|
|
const TRI_aql_node_t* const value) {
|
|
TRI_aql_node_t* node = TRI_PeekStackParseAql(context);
|
|
TRI_aql_node_t* element;
|
|
|
|
assert(node);
|
|
|
|
element = TRI_CreateNodeArrayElementAql(context, name, value);
|
|
if (!element) {
|
|
ABORT_OOM
|
|
}
|
|
|
|
ADD_MEMBER(element)
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief check if a node is a constant
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool TRI_IsConstantValueNodeAql (const TRI_aql_node_t* const node) {
|
|
assert(node);
|
|
|
|
if (node->_type != AQL_NODE_VALUE &&
|
|
node->_type != AQL_NODE_LIST &&
|
|
node->_type != AQL_NODE_ARRAY) {
|
|
return false;
|
|
}
|
|
|
|
if (node->_type == AQL_NODE_LIST || node->_type == AQL_NODE_ARRAY) {
|
|
size_t i;
|
|
size_t n = node->_members._length;
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
TRI_aql_node_t* member = (TRI_aql_node_t*) node->_members._buffer[i];
|
|
|
|
if (!TRI_IsConstantValueNodeAql(member)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks if a node value is numeric
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool TRI_IsNumericValueNodeAql (const TRI_aql_node_t* const node) {
|
|
assert(node);
|
|
|
|
if (node->_type != AQL_NODE_VALUE) {
|
|
return false;
|
|
}
|
|
|
|
return (node->_value._type == AQL_TYPE_INT ||
|
|
node->_value._type == AQL_TYPE_DOUBLE);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks if a node value is boolean
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool TRI_IsBooleanValueNodeAql (const TRI_aql_node_t* const node) {
|
|
assert(node);
|
|
|
|
return (node->_type == AQL_NODE_VALUE && node->_value._type == AQL_TYPE_BOOL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get the boolean value of a node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool TRI_GetBooleanNodeValueAql (const TRI_aql_node_t* const node) {
|
|
assert(node);
|
|
assert(node->_type == AQL_NODE_VALUE);
|
|
|
|
return TRI_AQL_NODE_BOOL(node);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get the numeric value of a node
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
double TRI_GetNumericNodeValueAql (const TRI_aql_node_t* const node) {
|
|
assert(node);
|
|
assert(node->_type == AQL_NODE_VALUE);
|
|
|
|
if (node->_value._type == AQL_TYPE_INT) {
|
|
return (double) TRI_AQL_NODE_INT(node);
|
|
}
|
|
if (node->_value._type == AQL_TYPE_DOUBLE) {
|
|
return TRI_AQL_NODE_DOUBLE(node);
|
|
}
|
|
if (node->_value._type == AQL_TYPE_BOOL) {
|
|
return TRI_AQL_NODE_BOOL(node) ? 1.0 : 0.0;
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
|
// End:
|