mirror of https://gitee.com/bigwinds/arangodb
1254 lines
43 KiB
C
1254 lines
43 KiB
C
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Ahuacatl, AST dump functions
|
|
///
|
|
/// @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 <BasicsC/logging.h>
|
|
|
|
#include "Ahuacatl/ast-codegen-js.h"
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup Ahuacatl
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief register a function name for easier later disposal
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool RegisterString (TRI_aql_codegen_t* const generator,
|
|
const char* const name) {
|
|
assert(generator);
|
|
|
|
TRI_PushBackVectorPointer(&generator->_strings, (char*) name);
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get a function name using the rule "f" + number
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static char* GetIndexedFunctionName (TRI_aql_codegen_t* const generator,
|
|
const size_t funcIndex) {
|
|
char* numberString;
|
|
char* functionName;
|
|
|
|
numberString = TRI_StringUInt64((uint64_t) funcIndex);
|
|
if (!numberString) {
|
|
return NULL;
|
|
}
|
|
|
|
functionName = TRI_Concatenate2String("f", numberString);
|
|
if (functionName) {
|
|
RegisterString(generator, functionName);
|
|
}
|
|
|
|
TRI_Free(numberString);
|
|
|
|
return functionName;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get the next function name (using the rule "f" + number, number will
|
|
/// be increased on each call)
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static char* GetNextFunctionName (TRI_aql_codegen_t* const generator) {
|
|
char* functionName;
|
|
|
|
assert(generator);
|
|
|
|
functionName = GetIndexedFunctionName(generator, ++generator->_funcIndex);
|
|
|
|
return functionName;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free a code scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void FreeScope (TRI_aql_codegen_scope_t* const scope) {
|
|
assert(scope);
|
|
|
|
// note: scope->_funcName is freed globally
|
|
|
|
if (scope->_buffer) {
|
|
TRI_FreeStringBuffer(scope->_buffer);
|
|
}
|
|
|
|
TRI_Free(scope);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a code scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_aql_codegen_scope_t* CreateScope (TRI_aql_codegen_t* const generator,
|
|
const char* const funcName,
|
|
const TRI_aql_scope_type_e type) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
|
|
scope = (TRI_aql_codegen_scope_t*) TRI_Allocate(sizeof(TRI_aql_codegen_scope_t));
|
|
|
|
if (!scope) {
|
|
return NULL;
|
|
}
|
|
|
|
scope->_funcName = TRI_DuplicateString(funcName);
|
|
if (!scope->_funcName) {
|
|
FreeScope(scope);
|
|
return NULL;
|
|
}
|
|
|
|
RegisterString(generator, scope->_funcName);
|
|
scope->_variablePrefix = NULL;
|
|
scope->_indent = 0;
|
|
scope->_forLoops = 0;
|
|
scope->_type = type;
|
|
|
|
scope->_buffer = TRI_CreateStringBuffer();
|
|
if (!scope->_buffer) {
|
|
FreeScope(scope);
|
|
return NULL;
|
|
}
|
|
|
|
return scope;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief start a new code scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool StartScope (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_scope_type_e type,
|
|
const char* const funcName) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
|
|
assert(generator);
|
|
assert(funcName);
|
|
|
|
scope = CreateScope(generator, funcName, type);
|
|
|
|
if (!scope) {
|
|
return false;
|
|
}
|
|
|
|
TRI_PushBackVectorPointer(&generator->_scopes, (void*) scope);
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief return the scope currently used
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_aql_codegen_scope_t* GetCurrentScope (TRI_aql_codegen_t* const generator) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
size_t length;
|
|
|
|
assert(generator);
|
|
|
|
length = generator->_scopes._length;
|
|
|
|
assert(length > 0);
|
|
|
|
scope = (TRI_aql_codegen_scope_t*) generator->_scopes._buffer[length -1];
|
|
|
|
return scope;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief increase the indent level in the current scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void Indent (TRI_aql_codegen_t* const generator) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
assert(generator);
|
|
|
|
scope = GetCurrentScope(generator);
|
|
assert(scope);
|
|
|
|
scope->_indent++;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief decrease the indent level in the current scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void Outdent (TRI_aql_codegen_t* const generator) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
assert(generator);
|
|
|
|
scope = GetCurrentScope(generator);
|
|
assert(scope);
|
|
assert(scope->_indent > 0);
|
|
|
|
--scope->_indent;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief add the current indentation to the output buffer in the current scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void AppendIndent (TRI_aql_codegen_t* const generator) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
size_t i;
|
|
|
|
assert(generator);
|
|
|
|
scope = GetCurrentScope(generator);
|
|
|
|
for (i = 0; i <= scope->_forLoops + scope->_indent; ++i) {
|
|
TRI_AppendStringStringBuffer(scope->_buffer, " ");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief remove the current scope from the stack
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void RemoveCurrentScope (TRI_aql_codegen_t* const generator) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
size_t length;
|
|
|
|
assert(generator);
|
|
|
|
length = generator->_scopes._length;
|
|
|
|
assert(length > 0);
|
|
|
|
scope = (TRI_aql_codegen_scope_t*) TRI_RemoveVectorPointer(&generator->_scopes, length - 1);
|
|
FreeScope(scope);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief close all for loops in current scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void CloseForLoops (TRI_aql_codegen_t* const generator) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
size_t i;
|
|
size_t n;
|
|
|
|
assert(generator);
|
|
|
|
scope = GetCurrentScope(generator);
|
|
|
|
assert(scope);
|
|
|
|
n = scope->_forLoops;
|
|
for (i = 0; i < n; ++i) {
|
|
scope->_forLoops--;
|
|
|
|
AppendIndent(generator);
|
|
TRI_AppendStringStringBuffer(scope->_buffer, "}\n");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief write a function definition to the output buffer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool AppendFunction (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_scope_type_e type,
|
|
const char* const name,
|
|
const char* const body) {
|
|
assert(generator);
|
|
assert(name);
|
|
assert(body);
|
|
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "\nfunction ");
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, name);
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "(");
|
|
if (type == AQL_SCOPE_COMPARE) {
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "l, r");
|
|
}
|
|
else {
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "previous");
|
|
}
|
|
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, ") {\n");
|
|
if (type != AQL_SCOPE_COMPARE) {
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, " var $ = AHUACATL_CLONE(previous);\n");
|
|
}
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, body);
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "\n");
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "}\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief end a scope. this will also write the scope's function to the
|
|
/// output buffer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static char* EndScope (TRI_aql_codegen_t* const generator) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
TRI_string_buffer_t* body;
|
|
char* funcName;
|
|
|
|
assert(generator);
|
|
|
|
scope = GetCurrentScope(generator);
|
|
|
|
assert(scope);
|
|
|
|
funcName = scope->_funcName;
|
|
|
|
body = TRI_CreateStringBuffer();
|
|
if (!body) {
|
|
// oom
|
|
generator->_error = true;
|
|
}
|
|
else {
|
|
if (scope->_type == AQL_SCOPE_RESULT) {
|
|
TRI_AppendStringStringBuffer(body, " var result = [];\n");
|
|
TRI_AppendStringStringBuffer(body, scope->_buffer->_buffer);
|
|
TRI_AppendStringStringBuffer(body, " return result;");
|
|
}
|
|
else {
|
|
TRI_AppendStringStringBuffer(body, scope->_buffer->_buffer);
|
|
}
|
|
|
|
AppendFunction(generator, scope->_type, funcName, body->_buffer);
|
|
TRI_FreeStringBuffer(body);
|
|
}
|
|
|
|
generator->_funcName = funcName;
|
|
|
|
RemoveCurrentScope(generator);
|
|
|
|
return funcName;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief increase the number of for loops in the current scope by one
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void IncreaseForCount (TRI_aql_codegen_t* const generator) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
size_t length;
|
|
|
|
assert(generator);
|
|
|
|
length = generator->_scopes._length;
|
|
|
|
assert(length > 0);
|
|
|
|
scope = (TRI_aql_codegen_scope_t*) generator->_scopes._buffer[length - 1];
|
|
assert(scope);
|
|
|
|
scope->_forLoops++;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief append code the current scope's output buffer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void AppendCode (TRI_aql_codegen_t* const generator, const char* const code) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
|
|
assert(generator);
|
|
|
|
scope = GetCurrentScope(generator);
|
|
|
|
assert(scope);
|
|
|
|
TRI_AppendStringStringBuffer(scope->_buffer, code);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief append the value of a value node to the current scope's output buffer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool AppendValue (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_node_value_t* const node) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
|
|
assert(generator);
|
|
|
|
scope = GetCurrentScope(generator);
|
|
|
|
assert(scope);
|
|
|
|
switch (node->_value._type) {
|
|
case AQL_TYPE_FAIL:
|
|
TRI_AppendStringStringBuffer(scope->_buffer, "fail");
|
|
break;
|
|
case AQL_TYPE_NULL:
|
|
TRI_AppendStringStringBuffer(scope->_buffer, "null");
|
|
break;
|
|
case AQL_TYPE_BOOL:
|
|
if (node->_value._value._bool) {
|
|
TRI_AppendStringStringBuffer(scope->_buffer, "true");
|
|
}
|
|
else {
|
|
TRI_AppendStringStringBuffer(scope->_buffer, "false");
|
|
}
|
|
break;
|
|
case AQL_TYPE_INT:
|
|
TRI_AppendInt64StringBuffer(scope->_buffer, node->_value._value._int);
|
|
break;
|
|
case AQL_TYPE_DOUBLE:
|
|
TRI_AppendDoubleStringBuffer(scope->_buffer, node->_value._value._double);
|
|
break;
|
|
case AQL_TYPE_STRING: {
|
|
char* escapedString;
|
|
size_t outLength;
|
|
|
|
TRI_AppendStringStringBuffer(scope->_buffer, "'");
|
|
escapedString = TRI_EscapeUtf8String(node->_value._value._string, strlen(node->_value._value._string), false, &outLength);
|
|
if (escapedString) {
|
|
TRI_AppendStringStringBuffer(scope->_buffer, escapedString);
|
|
TRI_Free(escapedString);
|
|
}
|
|
TRI_AppendStringStringBuffer(scope->_buffer, "'");
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief set a variable prefix for all variables to be printed
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void SetVariablePrefix (TRI_aql_codegen_t* const generator,
|
|
const char* const prefix) {
|
|
TRI_aql_codegen_scope_t* scope;
|
|
|
|
assert(generator);
|
|
|
|
scope = GetCurrentScope(generator);
|
|
|
|
assert(scope);
|
|
|
|
scope->_variablePrefix = (char*) prefix;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief print a variable name in the current scope, enclosed in $['...']
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool AppendVarname (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_node_t* const data) {
|
|
TRI_aql_node_variable_t* node = (TRI_aql_node_variable_t*) data;
|
|
|
|
AppendCode(generator, "$['");
|
|
AppendCode(generator, node->_name);
|
|
AppendCode(generator, "']");
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief print a variable name in the current scope, without modifications
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool AppendVarname0 (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_node_t* const data) {
|
|
TRI_aql_node_variable_t* node = (TRI_aql_node_variable_t*) data;
|
|
|
|
AppendCode(generator, node->_name);
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief print a variable name in the current scope, prepended by "_"
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool AppendVarname1 (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_node_t* const data) {
|
|
TRI_aql_node_variable_t* node = (TRI_aql_node_variable_t*) data;
|
|
|
|
AppendCode(generator, "_");
|
|
AppendCode(generator, node->_name);
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief print a variable name in the current scope, prepended by "__"
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool AppendVarname2 (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_node_t* const data) {
|
|
TRI_aql_node_variable_t* node = (TRI_aql_node_variable_t*) data;
|
|
|
|
AppendCode(generator, "__");
|
|
AppendCode(generator, node->_name);
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief print hasOwnProperty(...) if construct in current scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool AppendOwnPropertyName (TRI_aql_codegen_t* const generator,
|
|
const char* const name) {
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "if (!__");
|
|
AppendCode(generator, name);
|
|
AppendCode(generator, ".hasOwnProperty(_");
|
|
AppendCode(generator, name);
|
|
AppendCode(generator, ")) {\n");
|
|
Indent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "continue;\n");
|
|
Outdent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "}\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief print hasOwnProperty(...) if construct in current scope
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool AppendOwnPropertyVar (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_node_t* const data) {
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "if (!");
|
|
AppendVarname2(generator, data);
|
|
AppendCode(generator, ".hasOwnProperty(");
|
|
AppendVarname1(generator, data);
|
|
AppendCode(generator, ")) {\n");
|
|
Indent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "continue;\n");
|
|
Outdent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "}\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief generate the code for an individual node and all subnodes
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void GenerateCode (TRI_aql_codegen_t* const generator,
|
|
const TRI_aql_node_t* const data) {
|
|
TRI_aql_node_t* node;
|
|
|
|
if (!data) {
|
|
return;
|
|
}
|
|
|
|
node = (TRI_aql_node_t*) data;
|
|
|
|
while (node) {
|
|
switch (node->_type) {
|
|
case AQL_NODE_VALUE:
|
|
AppendValue(generator, (TRI_aql_node_value_t*) node);
|
|
break;
|
|
case AQL_NODE_LIST: {
|
|
TRI_vector_pointer_t* values = (TRI_vector_pointer_t*) &((TRI_aql_node_list_t*) node)->_values;
|
|
size_t i, n;
|
|
|
|
AppendCode(generator, "[ ");
|
|
|
|
n = values->_length;
|
|
for (i = 0; i < n; ++i) {
|
|
if (i > 0) {
|
|
AppendCode(generator, ", ");
|
|
}
|
|
GenerateCode(generator, (TRI_aql_node_t*) values->_buffer[i]);
|
|
}
|
|
AppendCode(generator, " ]");
|
|
break;
|
|
}
|
|
case AQL_NODE_ARRAY: {
|
|
TRI_associative_pointer_t* values = (TRI_associative_pointer_t*) &((TRI_aql_node_array_t*) node)->_values;
|
|
size_t i, n;
|
|
bool found = false;
|
|
|
|
AppendCode(generator, "{ ");
|
|
|
|
n = values->_nrAlloc;
|
|
for (i = 0; i < n; ++i) {
|
|
TRI_aql_node_array_element_t* element = (TRI_aql_node_array_element_t*) values->_table[i];
|
|
if (!element) {
|
|
continue;
|
|
}
|
|
|
|
if (found) {
|
|
AppendCode(generator, ", ");
|
|
}
|
|
found = true;
|
|
AppendCode(generator, "'");
|
|
AppendCode(generator, element->_name);
|
|
AppendCode(generator, "': ");
|
|
GenerateCode(generator, (TRI_aql_node_t*) element->_value);
|
|
}
|
|
AppendCode(generator, " }");
|
|
break;
|
|
}
|
|
case AQL_NODE_FOR:
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var ");
|
|
AppendVarname2(generator, ((TRI_aql_node_for_t*) node)->_variable);
|
|
AppendCode(generator, " = AHUACATL_LIST(");
|
|
GenerateCode(generator, ((TRI_aql_node_for_t*) node)->_expression);
|
|
AppendCode(generator, ");\n");
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "for (var ");
|
|
AppendVarname1(generator, ((TRI_aql_node_for_t*) node)->_variable);
|
|
AppendCode(generator, " in ");
|
|
AppendVarname2(generator, ((TRI_aql_node_for_t*) node)->_variable);
|
|
AppendCode(generator, ") {\n");
|
|
|
|
IncreaseForCount(generator);
|
|
AppendOwnPropertyVar(generator, ((TRI_aql_node_for_t*) node)->_variable);
|
|
|
|
AppendIndent(generator);
|
|
AppendVarname(generator, ((TRI_aql_node_for_t*) node)->_variable);
|
|
AppendCode(generator, " = ");
|
|
AppendVarname2(generator, ((TRI_aql_node_for_t*) node)->_variable);
|
|
AppendCode(generator, "[");
|
|
AppendVarname1(generator, ((TRI_aql_node_for_t*) node)->_variable);
|
|
AppendCode(generator, "];\n");
|
|
break;
|
|
case AQL_NODE_COLLECT: {
|
|
TRI_aql_node_list_t* list = (TRI_aql_node_list_t*) (((TRI_aql_node_collect_t*) node)->_list);
|
|
TRI_vector_pointer_t* values = (TRI_vector_pointer_t*) &list->_values;
|
|
char* previousFunction;
|
|
char* sortFuncName;
|
|
char* groupFuncName;
|
|
size_t i, n;
|
|
|
|
sortFuncName = GetNextFunctionName(generator);
|
|
|
|
StartScope(generator, AQL_SCOPE_COMPARE, sortFuncName);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var lhs, rhs;\n");
|
|
|
|
n = list->_values._length;
|
|
for (i = 0; i < n; ++i) {
|
|
TRI_aql_node_assign_t* element = (TRI_aql_node_assign_t*) values->_buffer[i];
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "lhs = ");
|
|
SetVariablePrefix(generator, "l");
|
|
GenerateCode(generator, element->_expression);
|
|
AppendCode(generator, ";\n");
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "rhs = ");
|
|
SetVariablePrefix(generator, "r");
|
|
GenerateCode(generator, element->_expression);
|
|
AppendCode(generator, ";\n");
|
|
SetVariablePrefix(generator, NULL);
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "if (AHUACATL_RELATIONAL_LESS(lhs, rhs)) {\n");
|
|
Indent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "return -1;\n");
|
|
Outdent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "}\n");
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "if (AHUACATL_RELATIONAL_GREATER(lhs, rhs)) {\n");
|
|
Indent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "return 1;\n");
|
|
Outdent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "}\n");
|
|
}
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "return 0;");
|
|
EndScope(generator);
|
|
|
|
|
|
groupFuncName = GetNextFunctionName(generator);
|
|
|
|
StartScope(generator, AQL_SCOPE_RESULT, groupFuncName);
|
|
AppendIndent(generator);
|
|
|
|
AppendCode(generator, "return { ");
|
|
|
|
n = values->_length;
|
|
for (i = 0; i < n; ++i) {
|
|
TRI_aql_node_assign_t* element = (TRI_aql_node_assign_t*) values->_buffer[i];
|
|
if (i > 0) {
|
|
AppendCode(generator, ", ");
|
|
}
|
|
AppendCode(generator, "'");
|
|
AppendCode(generator, ((TRI_aql_node_variable_t*) element->_variable)->_name);
|
|
AppendCode(generator, "' : ");
|
|
GenerateCode(generator, element->_expression);
|
|
}
|
|
AppendCode(generator, " };\n");
|
|
EndScope(generator);
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "result.push(AHUACATL_CLONE($));\n");
|
|
CloseForLoops(generator);
|
|
AppendCode(generator, " result = AHUACATL_GROUP(result, ");
|
|
AppendCode(generator, sortFuncName);
|
|
AppendCode(generator, ", ");
|
|
AppendCode(generator, groupFuncName);
|
|
|
|
if (((TRI_aql_node_collect_t*) node)->_into) {
|
|
AppendCode(generator, ", '");
|
|
AppendVarname0(generator, ((TRI_aql_node_collect_t*) node)->_into);
|
|
AppendCode(generator, "'");
|
|
}
|
|
AppendCode(generator, ");\n");
|
|
previousFunction = EndScope(generator);
|
|
|
|
StartScope(generator, AQL_SCOPE_RESULT, GetNextFunctionName(generator));
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var __group = ");
|
|
AppendCode(generator, previousFunction);
|
|
AppendCode(generator, "($);\n");
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "for (var _group in __group) {\n");
|
|
IncreaseForCount(generator);
|
|
AppendIndent(generator);
|
|
AppendOwnPropertyName(generator, "group");
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var $ = __group[_group];\n");
|
|
break;
|
|
}
|
|
case AQL_NODE_EXPAND: {
|
|
char* funcName = GetNextFunctionName(generator);
|
|
|
|
if (!funcName) {
|
|
assert(false);
|
|
// TODO: oom
|
|
}
|
|
|
|
StartScope(generator, AQL_SCOPE_RESULT, funcName);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var __e = AHUACATL_LIST($);\n");
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "for (var _e in __e) {\n");
|
|
Indent(generator);
|
|
AppendOwnPropertyName(generator, "e");
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "result.push(");
|
|
GenerateCode(generator, ((TRI_aql_node_expand_t*) node)->_expansion);
|
|
AppendCode(generator, ");\n");
|
|
Outdent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "}\n");
|
|
EndScope(generator);
|
|
|
|
AppendCode(generator, funcName);
|
|
AppendCode(generator, "(");
|
|
GenerateCode(generator, ((TRI_aql_node_expand_t*) node)->_expanded);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
}
|
|
case AQL_NODE_ASSIGN:
|
|
AppendIndent(generator);
|
|
AppendVarname(generator, ((TRI_aql_node_assign_t*) node)->_variable);
|
|
AppendCode(generator, " = ");
|
|
GenerateCode(generator, ((TRI_aql_node_assign_t*) node)->_expression);
|
|
AppendCode(generator, ";\n");
|
|
break;
|
|
case AQL_NODE_SUBQUERY: {
|
|
char* funcName = GetNextFunctionName(generator);
|
|
|
|
if (!funcName) {
|
|
assert(false);
|
|
// TODO: oom
|
|
}
|
|
|
|
StartScope(generator, AQL_SCOPE_RESULT, funcName);
|
|
GenerateCode(generator, ((TRI_aql_node_subquery_t*) node)->_query);
|
|
|
|
AppendCode(generator, funcName);
|
|
AppendCode(generator, "($)");
|
|
break;
|
|
}
|
|
case AQL_NODE_FILTER:
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "if (!(");
|
|
GenerateCode(generator, ((TRI_aql_node_filter_t*) node)->_expression);
|
|
AppendCode(generator, ")) {\n");
|
|
Indent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "continue;\n");
|
|
Outdent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "}\n");
|
|
break;
|
|
case AQL_NODE_RETURN:
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "result.push(");
|
|
GenerateCode(generator, ((TRI_aql_node_return_t*) node)->_expression);
|
|
AppendCode(generator, ");\n");
|
|
CloseForLoops(generator);
|
|
EndScope(generator);
|
|
break;
|
|
case AQL_NODE_LIMIT: {
|
|
char* previousFunction;
|
|
char* value;
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "result.push($);\n");
|
|
CloseForLoops(generator);
|
|
AppendCode(generator, " result = AHUACATL_LIMIT(result, ");
|
|
|
|
value = TRI_StringInt64(((TRI_aql_node_limit_t*) node)->_offset);
|
|
if (!value) {
|
|
return; // todo: OOM
|
|
}
|
|
RegisterString(generator, value);
|
|
AppendCode(generator, value);
|
|
AppendCode(generator, ", ");
|
|
|
|
value = TRI_StringInt64(((TRI_aql_node_limit_t*) node)->_count);
|
|
if (!value) {
|
|
return; // todo: OOM
|
|
}
|
|
RegisterString(generator, value);
|
|
AppendCode(generator, value);
|
|
AppendCode(generator, ");\n");
|
|
previousFunction = EndScope(generator);
|
|
|
|
StartScope(generator, AQL_SCOPE_RESULT, GetNextFunctionName(generator));
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var __limit = ");
|
|
AppendCode(generator, previousFunction);
|
|
AppendCode(generator, "($);\n");
|
|
AppendCode(generator, "for (var _limit in __limit) {\n");
|
|
IncreaseForCount(generator);
|
|
AppendIndent(generator);
|
|
AppendOwnPropertyName(generator, "limit");
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var $ = __limit[_limit];\n");
|
|
break;
|
|
}
|
|
case AQL_NODE_SORT: {
|
|
TRI_aql_codegen_scope_t* scope = GetCurrentScope(generator);
|
|
TRI_aql_node_list_t* list = (TRI_aql_node_list_t*) (((TRI_aql_node_sort_t*) node)->_list);
|
|
char* previousFunction;
|
|
char* sortFuncName;
|
|
size_t i;
|
|
size_t n;
|
|
|
|
previousFunction = scope->_funcName;
|
|
// todo: OOM
|
|
|
|
sortFuncName = GetNextFunctionName(generator);
|
|
|
|
StartScope(generator, AQL_SCOPE_COMPARE, sortFuncName);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var lhs, rhs;\n");
|
|
|
|
n = list->_values._length;
|
|
for (i = 0; i < n; ++i) {
|
|
TRI_aql_node_sort_element_t* element = (TRI_aql_node_sort_element_t*) list->_values._buffer[i];
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "lhs = ");
|
|
SetVariablePrefix(generator, "l");
|
|
GenerateCode(generator, element->_expression);
|
|
AppendCode(generator, ";\n");
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "rhs = ");
|
|
SetVariablePrefix(generator, "r");
|
|
GenerateCode(generator, element->_expression);
|
|
AppendCode(generator, ";\n");
|
|
SetVariablePrefix(generator, NULL);
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "if (AHUACATL_RELATIONAL_LESS(lhs, rhs)) {\n");
|
|
Indent(generator);
|
|
AppendIndent(generator);
|
|
if (element->_ascending) {
|
|
AppendCode(generator, "return -1;\n");
|
|
}
|
|
else {
|
|
AppendCode(generator, "return 1;\n");
|
|
}
|
|
Outdent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "}\n");
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "if (AHUACATL_RELATIONAL_GREATER(lhs, rhs)) {\n");
|
|
Indent(generator);
|
|
AppendIndent(generator);
|
|
if (element->_ascending) {
|
|
AppendCode(generator, "return 1;\n");
|
|
}
|
|
else {
|
|
AppendCode(generator, "return -1;\n");
|
|
}
|
|
Outdent(generator);
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "}\n");
|
|
}
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "return 0;");
|
|
EndScope(generator);
|
|
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "result.push(AHUACATL_CLONE($));\n");
|
|
CloseForLoops(generator);
|
|
AppendCode(generator, " AHUACATL_SORT(result, ");
|
|
AppendCode(generator, sortFuncName);
|
|
AppendCode(generator, ");\n");
|
|
EndScope(generator);
|
|
|
|
StartScope(generator, AQL_SCOPE_RESULT, GetNextFunctionName(generator));
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var __sort = ");
|
|
AppendCode(generator, previousFunction);
|
|
AppendCode(generator, "($);\n");
|
|
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "for (var _sort in __sort) {\n");
|
|
IncreaseForCount(generator);
|
|
AppendOwnPropertyName(generator, "sort");
|
|
AppendIndent(generator);
|
|
AppendCode(generator, "var $ = __sort[_sort];\n");
|
|
break;
|
|
}
|
|
case AQL_NODE_VARIABLE:
|
|
AppendVarname(generator, node);
|
|
break;
|
|
case AQL_NODE_REFERENCE:
|
|
if (((TRI_aql_node_reference_t*) node)->_isCollection) {
|
|
AppendCode(generator, "AHUACATL_GET_DOCUMENTS('");
|
|
AppendCode(generator, ((TRI_aql_node_reference_t*) node)->_name);
|
|
AppendCode(generator, "')");
|
|
}
|
|
else {
|
|
TRI_aql_codegen_scope_t* scope= GetCurrentScope(generator);
|
|
|
|
if (scope->_variablePrefix) {
|
|
AppendCode(generator, scope->_variablePrefix);
|
|
AppendCode(generator, "['");
|
|
AppendCode(generator, ((TRI_aql_node_reference_t*) node)->_name);
|
|
AppendCode(generator, "']");
|
|
}
|
|
else {
|
|
AppendCode(generator, "$['");
|
|
AppendCode(generator, ((TRI_aql_node_reference_t*) node)->_name);
|
|
AppendCode(generator, "']");
|
|
}
|
|
}
|
|
break;
|
|
case AQL_NODE_PARAMETER:
|
|
AppendCode(generator, "AHUACATL_GET_PARAMETER('");
|
|
AppendCode(generator, ((TRI_aql_node_parameter_t*) node)->_name);
|
|
AppendCode(generator, "')");
|
|
break;
|
|
case AQL_NODE_ATTRIBUTE_ACCESS:
|
|
AppendCode(generator, "AHUACATL_DOCUMENT_MEMBER(");
|
|
GenerateCode(generator, ((TRI_aql_node_attribute_access_t*) node)->_accessed);
|
|
AppendCode(generator, ", '");
|
|
AppendCode(generator, ((TRI_aql_node_attribute_access_t*) node)->_name);
|
|
AppendCode(generator, "')");
|
|
break;
|
|
case AQL_NODE_INDEXED:
|
|
AppendCode(generator, "AHUACATL_GET_INDEX(");
|
|
GenerateCode(generator, ((TRI_aql_node_indexed_t*) node)->_accessed);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_indexed_t*) node)->_index);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_ATTRIBUTE:
|
|
AppendCode(generator, "AHUACATL_DOCUMENT_MEMBER(__e[_e], '");
|
|
AppendCode(generator, ((TRI_aql_node_attribute_t*) node)->_name);
|
|
AppendCode(generator, "')");
|
|
break;
|
|
case AQL_NODE_OPERATOR_UNARY_NOT:
|
|
AppendCode(generator, "AHUACATL_LOGICAL_NOT(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_unary_t*) node)->_operand);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_UNARY_PLUS:
|
|
AppendCode(generator, "AHUACATL_UNARY_PLUS(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_unary_t*) node)->_operand);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_UNARY_MINUS:
|
|
AppendCode(generator, "AHUACATL_UNARY_MINUS(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_unary_t*) node)->_operand);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_AND:
|
|
AppendCode(generator, "AHUACATL_LOGICAL_AND(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_OR:
|
|
AppendCode(generator, "AHUACATL_LOGICAL_OR(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_PLUS:
|
|
AppendCode(generator, "AHUACATL_ARITHMETIC_PLUS(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_MINUS:
|
|
AppendCode(generator, "AHUACATL_ARITHMETIC_MINUS(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_TIMES:
|
|
AppendCode(generator, "AHUACATL_ARITHMETIC_TIMES(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_DIV:
|
|
AppendCode(generator, "AHUACATL_ARITHMETIC_DIVIDE(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_MOD:
|
|
AppendCode(generator, "AHUACATL_ARITHMETIC_MODULUS(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_EQ:
|
|
AppendCode(generator, "AHUACATL_RELATIONAL_EQUAL(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_NE:
|
|
AppendCode(generator, "AHUACATL_RELATIONAL_UNEQUAL(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_LT:
|
|
AppendCode(generator, "AHUACATL_RELATIONAL_LESS(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_LE:
|
|
AppendCode(generator, "AHUACATL_RELATIONAL_LESSEQUAL(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_GT:
|
|
AppendCode(generator, "AHUACATL_RELATIONAL_GREATER(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_GE:
|
|
AppendCode(generator, "AHUACATL_RELATIONAL_GREATEREQUAL(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_OPERATOR_BINARY_IN:
|
|
AppendCode(generator, "AHUACATL_RELATIONAL_IN(");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_lhs);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_operator_binary_t*) node)->_rhs);
|
|
AppendCode(generator, ")");
|
|
break;
|
|
case AQL_NODE_FCALL: {
|
|
AppendCode(generator, "AHUACATL_FCALL(");
|
|
AppendCode(generator, ((TRI_aql_node_fcall_t*) node)->_name);
|
|
AppendCode(generator, ", ");
|
|
GenerateCode(generator, ((TRI_aql_node_fcall_t*) node)->_parameters);
|
|
AppendCode(generator, ")");
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
node = node->_next;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup Ahuacatl
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a code generator
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_aql_codegen_t* TRI_CreateCodegenAql (void) {
|
|
TRI_aql_codegen_t* generator;
|
|
|
|
generator = (TRI_aql_codegen_t*) TRI_Allocate(sizeof(TRI_aql_codegen_t));
|
|
|
|
if (!generator) {
|
|
return NULL;
|
|
}
|
|
|
|
generator->_error = false;
|
|
generator->_funcIndex = 0;
|
|
generator->_funcName = NULL;
|
|
|
|
TRI_InitStringBuffer(&generator->_buffer);
|
|
|
|
TRI_InitVectorPointer(&generator->_strings);
|
|
|
|
TRI_InitVectorPointer(&generator->_scopes);
|
|
if (!StartScope(generator, AQL_SCOPE_RESULT, GetNextFunctionName(generator))) {
|
|
TRI_FreeCodegenAql(generator);
|
|
return NULL;
|
|
}
|
|
|
|
return generator;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free the code generator
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void TRI_FreeCodegenAql (TRI_aql_codegen_t* const generator) {
|
|
size_t i;
|
|
|
|
assert(generator);
|
|
|
|
TRI_DestroyStringBuffer(&generator->_buffer);
|
|
TRI_DestroyVectorPointer(&generator->_scopes);
|
|
|
|
// free strings
|
|
i = generator->_strings._length;
|
|
while (i--) {
|
|
void* string = generator->_strings._buffer[i];
|
|
if (string) {
|
|
TRI_Free(string);
|
|
}
|
|
}
|
|
TRI_DestroyVectorPointer(&generator->_strings);
|
|
|
|
TRI_Free(generator);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief generate Javascript code for the AST nodes recursively
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
char* TRI_GenerateCodeAql (const void* const data) {
|
|
TRI_aql_node_t* node = (TRI_aql_node_t*) data;
|
|
TRI_aql_codegen_t* generator;
|
|
char* code = NULL;
|
|
|
|
if (!node) {
|
|
// todo: handle errors
|
|
return code;
|
|
}
|
|
|
|
generator = TRI_CreateCodegenAql();
|
|
if (!generator) {
|
|
// todo: handle errors
|
|
return code;
|
|
}
|
|
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "(function() {\n");
|
|
|
|
GenerateCode(generator, node);
|
|
if (!generator->_funcName) {
|
|
generator->_error = true;
|
|
}
|
|
|
|
if (!generator->_error) {
|
|
char* funcName = generator->_funcName;
|
|
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "try {\n");
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, " return ");
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, funcName);
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "( { } );\n");
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "}\n");
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "catch (e) {\n");
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "print(e);\n");
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "}\n");
|
|
|
|
TRI_AppendStringStringBuffer(&generator->_buffer, "})();\n");
|
|
|
|
code = TRI_DuplicateString(generator->_buffer._buffer);
|
|
LOG_TRACE("generated code:\n%s\n",code);
|
|
//printf("generated code:\n%s\n",code);
|
|
}
|
|
|
|
TRI_FreeCodegenAql(generator);
|
|
|
|
return code;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
|
// End:
|