1
0
Fork 0
arangodb/arangod/Ahuacatl/ahuacatl-statementlist.cpp

373 lines
11 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// @brief Ahuacatl, statement list
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 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
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "Ahuacatl/ahuacatl-statementlist.h"
#include "Basics/logging.h"
#include "Ahuacatl/ahuacatl-ast-node.h"
#include "Ahuacatl/ahuacatl-scope.h"
// -----------------------------------------------------------------------------
// --SECTION-- private members
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief dummy no-operations node (re-used for ALL non-operations)}
////////////////////////////////////////////////////////////////////////////////
static TRI_aql_node_t* DummyNopNode;
////////////////////////////////////////////////////////////////////////////////
/// @brief dummy empty return node (re-used for multiple operations)
////////////////////////////////////////////////////////////////////////////////
static TRI_aql_node_t* DummyReturnEmptyNode;
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief get the statement at a certain position
////////////////////////////////////////////////////////////////////////////////
static inline TRI_aql_node_t* StatementAt (const TRI_aql_statement_list_t* const list,
const size_t position) {
return list->_statements[position];
}
////////////////////////////////////////////////////////////////////////////////
/// @brief invalidates all statements in a scope marked as "empty"
////////////////////////////////////////////////////////////////////////////////
static size_t InvalidateEmptyScope (TRI_aql_statement_list_t* const list,
const size_t position) {
size_t i, n;
size_t scopes;
TRI_ASSERT(list);
n = list->_statements.size();
i = position;
scopes = 0;
while (i < n) {
TRI_aql_node_t* node = StatementAt(list, i);
TRI_aql_node_type_e type = node->_type;
if (i == position) {
TRI_ASSERT(type == TRI_AQL_NODE_SCOPE_START);
list->_statements[i] = DummyReturnEmptyNode;
}
else {
list->_statements[i] = TRI_GetDummyNopNodeAql();
}
++i;
if (type == TRI_AQL_NODE_SCOPE_START) {
++scopes;
}
else if (type == TRI_AQL_NODE_SCOPE_END) {
TRI_ASSERT(scopes > 0);
--scopes;
if (scopes == 0) {
break;
}
}
}
return i;
}
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief create and initialize a statement list
////////////////////////////////////////////////////////////////////////////////
TRI_aql_statement_list_t* TRI_CreateStatementListAql (void) {
TRI_aql_statement_list_t* list;
try {
list = new TRI_aql_statement_list_t();
}
catch (std::exception&) {
list = nullptr;
}
if (list == NULL) {
return NULL;
}
list->_currentLevel = 0;
return list;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free a statement list
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeStatementListAql (TRI_aql_statement_list_t* const list) {
if (list == NULL) {
return;
}
delete list;
}
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief init the global nodes at program start
////////////////////////////////////////////////////////////////////////////////
void TRI_GlobalInitStatementListAql (void) {
DummyNopNode = TRI_CreateNodeNopAql();
DummyReturnEmptyNode = TRI_CreateNodeReturnEmptyAql();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free the global nodes at program end
////////////////////////////////////////////////////////////////////////////////
void TRI_GlobalFreeStatementListAql (void) {
if (DummyNopNode != NULL) {
TRI_DestroyVectorPointer(&DummyNopNode->_members);
delete DummyNopNode;
}
if (DummyReturnEmptyNode != NULL) {
TRI_aql_node_t* list = TRI_AQL_NODE_MEMBER(DummyReturnEmptyNode, 0);
TRI_DestroyVectorPointer(&list->_members);
delete list;
TRI_DestroyVectorPointer(&DummyReturnEmptyNode->_members);
delete DummyReturnEmptyNode;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the address of the dummy non-op node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_GetDummyNopNodeAql (void) {
return DummyNopNode;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief pull out uncorrelated subqueries from the middle of the statement
/// list to the beginning
////////////////////////////////////////////////////////////////////////////////
void TRI_PulloutStatementListAql (TRI_aql_statement_list_t* const list) {
size_t i, n;
size_t scopes = 0;
size_t targetScope = 0;
size_t moveStart = 0;
bool watch = false;
TRI_ASSERT(list);
i = 0;
n = list->_statements.size();
while (i < n) {
TRI_aql_node_t* node = StatementAt(list, i);
TRI_aql_node_type_e type = node->_type;
if (type == TRI_AQL_NODE_SCOPE_START) {
// node is a scope start
TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);
if (scope->_type == TRI_AQL_SCOPE_SUBQUERY && scope->_selfContained) {
if (! watch && scopes > 0) {
watch = true;
targetScope = scopes;
moveStart = i;
}
}
++scopes;
}
else if (type == TRI_AQL_NODE_SCOPE_END) {
// node is a scope end
--scopes;
if (watch && scopes == targetScope) {
watch = false;
node = StatementAt(list, i + 1);
// check if next statement is a subquery statement
if (i + 1 < n && node->_type == TRI_AQL_NODE_SUBQUERY) {
size_t j = moveStart;
size_t inserted = 0;
node->_type = TRI_AQL_NODE_SUBQUERY_CACHED;
// moving statements from the middle to the beginning of the list will also
// modify the positions we're moving from
while (j < i + 2) {
node = StatementAt(list, j + inserted);
if (! TRI_InsertStatementListAql(list, node, inserted + 0)) {
return;
}
// insert a dummy node in place of the moved node
list->_statements[j + inserted + 1] = TRI_GetDummyNopNodeAql();
// next
++j;
++inserted;
}
// moving statements from the middle to the beginning of the list will also
// change the list length and the position we'll be continuing from
n += inserted;
i = j + inserted;
}
}
}
++i;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add a statement to the front of the statement list
////////////////////////////////////////////////////////////////////////////////
bool TRI_InsertStatementListAql (TRI_aql_statement_list_t* const list,
TRI_aql_node_t* const node,
const size_t position) {
TRI_ASSERT(list != NULL);
TRI_ASSERT(node != NULL);
try {
list->_statements.insert(list->_statements.begin() + position, node);
}
catch (std::exception&) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add a statement to the end of the statement list
////////////////////////////////////////////////////////////////////////////////
bool TRI_AppendStatementListAql (TRI_aql_statement_list_t* const list,
TRI_aql_node_t* const node) {
TRI_aql_node_type_e type;
TRI_ASSERT(list != NULL);
TRI_ASSERT(node != NULL);
type = node->_type;
TRI_ASSERT(TRI_IsTopLevelTypeAql(type));
if (type == TRI_AQL_NODE_SCOPE_START) {
++list->_currentLevel;
}
else if (type == TRI_AQL_NODE_SCOPE_END) {
TRI_ASSERT(list->_currentLevel > 0);
--list->_currentLevel;
}
try {
list->_statements.push_back(node);
}
catch (std::exception&) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief remove all non-ops from the statement list
////////////////////////////////////////////////////////////////////////////////
void TRI_CompactStatementListAql (TRI_aql_statement_list_t* const list) {
size_t i, j, n;
TRI_ASSERT(list);
i = 0;
j = 0;
n = list->_statements.size();
while (i < n) {
TRI_aql_node_t* node = StatementAt(list, i);
if (node->_type == TRI_AQL_NODE_NOP) {
++i;
continue;
}
if (node->_type == TRI_AQL_NODE_SCOPE_START) {
TRI_aql_scope_t* scope = (TRI_aql_scope_t*) TRI_AQL_NODE_DATA(node);
if (scope->_empty) {
i = InvalidateEmptyScope(list, i);
j = i;
continue;
}
}
/* should not happen anymore
if (node->_type == TRI_AQL_NODE_RETURN_EMPTY) {
TRI_ASSERT(false);
}
*/
list->_statements[j++] = node;
++i;
}
list->_statements.resize(j);
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End: