diff --git a/Ahuacatl/ahuacatl-ast-node.c b/Ahuacatl/ahuacatl-ast-node.c index 33dd78c451..f77540c429 100644 --- a/Ahuacatl/ahuacatl-ast-node.c +++ b/Ahuacatl/ahuacatl-ast-node.c @@ -946,7 +946,7 @@ TRI_aql_node_t* TRI_CreateNodeFcallAql (TRI_aql_context_t* const context, } ADD_MEMBER(parameters) - TRI_AQL_NODE_STRING(node) = function->_internalName; + TRI_AQL_NODE_DATA(node) = function; } return node; diff --git a/Ahuacatl/ahuacatl-bind-parameter.c b/Ahuacatl/ahuacatl-bind-parameter.c index dd3323f7bb..36a2f96bd4 100644 --- a/Ahuacatl/ahuacatl-bind-parameter.c +++ b/Ahuacatl/ahuacatl-bind-parameter.c @@ -36,109 +36,6 @@ /// @{ //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief create a value node from a bind parameter -//////////////////////////////////////////////////////////////////////////////// - -static TRI_aql_node_t* CreateNodeFromJson (TRI_aql_context_t* const context, - TRI_json_t* json) { - TRI_aql_node_t* node = NULL; - - switch (json->_type) { - case TRI_JSON_UNUSED: - break; - - case TRI_JSON_NULL: - node = TRI_CreateNodeValueNullAql(context); - break; - - case TRI_JSON_BOOLEAN: - node = TRI_CreateNodeValueBoolAql(context, json->_value._boolean); - break; - - case TRI_JSON_NUMBER: - node = TRI_CreateNodeValueDoubleAql(context, json->_value._number); - break; - - case TRI_JSON_STRING: - node = TRI_CreateNodeValueStringAql(context, json->_value._string.data); - break; - - case TRI_JSON_LIST: { - size_t i; - size_t n; - - node = TRI_CreateNodeListAql(context); - n = json->_value._objects._length; - - for (i = 0; i < n; ++i) { - TRI_json_t* subJson; - TRI_aql_node_t* member; - - subJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); - assert(subJson); - - member = CreateNodeFromJson(context, subJson); - if (member) { - TRI_PushBackVectorPointer(&node->_members, (void*) member); - } - else { - TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); - return NULL; - } - } - break; - } - case TRI_JSON_ARRAY: { - size_t i; - size_t n; - - node = TRI_CreateNodeArrayAql(context); - n = json->_value._objects._length; - - for (i = 0; i < n; i += 2) { - TRI_json_t* nameJson; - TRI_json_t* valueJson; - TRI_aql_node_t* member; - TRI_aql_node_t* valueNode; - char* name; - - // json_t containing the array element name - nameJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); - assert(nameJson); - - name = nameJson->_value._string.data; - assert(name); - - // json_t containing the array element value - valueJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i + 1); - assert(valueJson); - - valueNode = CreateNodeFromJson(context, valueJson); - if (!valueNode) { - TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); - return NULL; - } - - member = TRI_CreateNodeArrayElementAql(context, name, valueNode); - if (member) { - TRI_PushBackVectorPointer(&node->_members, (void*) member); - } - else { - TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); - return NULL; - } - } - break; - } - } - - if (!node) { - TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); - } - - return node; -} //////////////////////////////////////////////////////////////////////////////// /// @brief check if a node is a bind parameter and convert it into a value node @@ -167,7 +64,7 @@ static TRI_aql_node_t* ModifyNode (void* data, bind = (TRI_aql_bind_parameter_t*) TRI_LookupByKeyAssociativePointer(bindValues, name); if (bind) { - node = CreateNodeFromJson(context, bind->_value); + node = TRI_JsonNodeAql(context, bind->_value); } return node; diff --git a/Ahuacatl/ahuacatl-bind-parameter.h b/Ahuacatl/ahuacatl-bind-parameter.h index 6f5902766b..f78e12b2ab 100644 --- a/Ahuacatl/ahuacatl-bind-parameter.h +++ b/Ahuacatl/ahuacatl-bind-parameter.h @@ -37,6 +37,7 @@ #include "Ahuacatl/ahuacatl-ast-node.h" #include "Ahuacatl/ahuacatl-context.h" +#include "Ahuacatl/ahuacatl-conversions.h" #include "Ahuacatl/ahuacatl-tree-walker.h" #ifdef __cplusplus diff --git a/Ahuacatl/ahuacatl-codegen-js.c b/Ahuacatl/ahuacatl-codegen-js.c index 1ed608d14f..d2b5acec06 100644 --- a/Ahuacatl/ahuacatl-codegen-js.c +++ b/Ahuacatl/ahuacatl-codegen-js.c @@ -28,6 +28,7 @@ #include #include "Ahuacatl/ahuacatl-codegen-js.h" +#include "Ahuacatl/ahuacatl-functions.h" // ----------------------------------------------------------------------------- // --SECTION-- private functions @@ -108,11 +109,6 @@ static void AppendInt (TRI_aql_codegen_js_t* const generator, TRI_AppendInt64StringBuffer(GetBuffer(generator), value); } -static void AppendDouble (TRI_aql_codegen_js_t* const generator, - const double value) { - TRI_AppendDoubleStringBuffer(GetBuffer(generator), value); -} - static void AppendQuoted (TRI_aql_codegen_js_t* const generator, const char* name) { if (!name) { @@ -298,38 +294,8 @@ static size_t HandleSortNode (TRI_aql_codegen_js_t* const generator, static void HandleValue (TRI_aql_codegen_js_t* const generator, const TRI_aql_node_t* const node) { - switch (node->_value._type) { - case AQL_TYPE_FAIL: - AppendString(generator, "fail"); - break; - case AQL_TYPE_NULL: - AppendString(generator, "null"); - break; - case AQL_TYPE_BOOL: - AppendString(generator, node->_value._value._bool ? "true" : "false"); - break; - case AQL_TYPE_INT: - AppendInt(generator, node->_value._value._int); - break; - case AQL_TYPE_DOUBLE: - AppendDouble(generator, node->_value._value._double); - break; - case AQL_TYPE_STRING: { - char* escapedString; - size_t outLength; - - AppendString(generator, "'"); - escapedString = TRI_EscapeUtf8String(node->_value._value._string, strlen(node->_value._value._string), false, &outLength); - if (escapedString) { - AppendString(generator, escapedString); - TRI_Free(TRI_UNKNOWN_MEM_ZONE, escapedString); - } - else { - generator->_error = true; - } - AppendString(generator, "'"); - break; - } + if (!TRI_ValueJavascriptAql(GetBuffer(generator), &node->_value, node->_value._type)) { + generator->_error = true; } } @@ -360,12 +326,12 @@ static void HandleArray (TRI_aql_codegen_js_t* const generator, } DumpNode(generator, TRI_AQL_NODE_MEMBER(node, i)); } - AppendString(generator, " }"); -} + AppendString(generator, " }"); +} static void HandleArrayElement (TRI_aql_codegen_js_t* const generator, const TRI_aql_node_t* const node) { - AppendQuoted(generator, TRI_AQL_NODE_STRING(node)); + TRI_ValueJavascriptAql(GetBuffer(generator), &node->_value, AQL_TYPE_STRING); AppendString(generator, " : "); DumpNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); } @@ -601,7 +567,7 @@ static void HandleBinaryIn (TRI_aql_codegen_js_t* const generator, static void HandleFcall (TRI_aql_codegen_js_t* const generator, const TRI_aql_node_t* const node) { AppendString(generator, "AHUACATL_FCALL("); - AppendString(generator, TRI_AQL_NODE_STRING(node)); + AppendString(generator, TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node))); AppendString(generator, ", "); DumpNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); AppendString(generator, ")"); @@ -683,7 +649,7 @@ static void HandleLimit (TRI_aql_codegen_js_t* const generator, size_t r2 = NextRegister(generator); size_t funcIndex; - AppendString(generator, "result.push($);\n"); + AppendString(generator, "result.push(AHUACATL_CLONE($));\n"); CloseForLoops(generator); AppendString(generator, "result = AHUACATL_LIMIT(result, "); DumpNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); @@ -927,11 +893,11 @@ static void DumpNode (TRI_aql_codegen_js_t* generator, const TRI_aql_node_t* con } //////////////////////////////////////////////////////////////////////////////// -/// @} +/// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- -// --SECTION-- public functions +// --SECTION-- constructors / destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -939,12 +905,20 @@ static void DumpNode (TRI_aql_codegen_js_t* generator, const TRI_aql_node_t* con /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief free memory associated with a code generator +//////////////////////////////////////////////////////////////////////////////// + void TRI_FreeGeneratorAql (TRI_aql_codegen_js_t* const generator) { TRI_DestroyVectorPointer(&generator->_functions); TRI_DestroyStringBuffer(&generator->_buffer); TRI_Free(TRI_UNKNOWN_MEM_ZONE, generator); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief create a code generator +//////////////////////////////////////////////////////////////////////////////// + TRI_aql_codegen_js_t* TRI_CreateGeneratorAql (void) { TRI_aql_codegen_js_t* generator; @@ -962,6 +936,18 @@ TRI_aql_codegen_js_t* TRI_CreateGeneratorAql (void) { return generator; } +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief generate Javascript code for the AST nodes recursively @@ -986,7 +972,7 @@ TRI_aql_codegen_js_t* TRI_GenerateCodeAql (const void* const data) { TRI_AppendInt64StringBuffer(&generator->_buffer, (int64_t) funcIndex); TRI_AppendStringStringBuffer(&generator->_buffer, "({ });"); -//printf("GENERATED CODE:\n%s\n\n", generator->_buffer._buffer); + LOG_DEBUG("generated code: %s", generator->_buffer._buffer); return generator; } diff --git a/Ahuacatl/ahuacatl-codegen-js.h b/Ahuacatl/ahuacatl-codegen-js.h index 040b77eb28..311910ec70 100644 --- a/Ahuacatl/ahuacatl-codegen-js.h +++ b/Ahuacatl/ahuacatl-codegen-js.h @@ -33,9 +33,9 @@ #include #include #include -#include #include "Ahuacatl/ahuacatl-ast-node.h" +#include "Ahuacatl/ahuacatl-conversions.h" #ifdef __cplusplus extern "C" { @@ -50,12 +50,20 @@ extern "C" { /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief internal function types +//////////////////////////////////////////////////////////////////////////////// + typedef enum { AQL_FUNCTION_STANDALONE, AQL_FUNCTION_COMPARE } TRI_aql_codegen_function_type_e; +//////////////////////////////////////////////////////////////////////////////// +/// @brief code generator internal function struct +//////////////////////////////////////////////////////////////////////////////// + typedef struct TRI_aql_codegen_function_s { TRI_string_buffer_t _buffer; size_t _index; @@ -65,6 +73,10 @@ typedef struct TRI_aql_codegen_function_s { TRI_aql_codegen_function_t; +//////////////////////////////////////////////////////////////////////////////// +/// @brief code generator struct +//////////////////////////////////////////////////////////////////////////////// + typedef struct TRI_aql_codegen_js_s { TRI_string_buffer_t _buffer; TRI_vector_pointer_t _functions; @@ -79,7 +91,7 @@ TRI_aql_codegen_js_t; //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- -// --SECTION-- public functions +// --SECTION-- constructors / destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -87,10 +99,31 @@ TRI_aql_codegen_js_t; /// @{ //////////////////////////////////////////////////////////////////////////////// -TRI_aql_codegen_js_t* TRI_CreateGeneratorAql (void); +//////////////////////////////////////////////////////////////////////////////// +/// @brief free memory associated with a code generator +//////////////////////////////////////////////////////////////////////////////// void TRI_FreeGeneratorAql (TRI_aql_codegen_js_t* const); +//////////////////////////////////////////////////////////////////////////////// +/// @brief create a code generator +//////////////////////////////////////////////////////////////////////////////// + +TRI_aql_codegen_js_t* TRI_CreateGeneratorAql (void); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// /// @brief generate Javascript code for the AST nodes recursively //////////////////////////////////////////////////////////////////////////////// diff --git a/Ahuacatl/ahuacatl-constant-folder.c b/Ahuacatl/ahuacatl-constant-folder.c index 1f5c17fd8c..c46ce1c601 100644 --- a/Ahuacatl/ahuacatl-constant-folder.c +++ b/Ahuacatl/ahuacatl-constant-folder.c @@ -26,6 +26,10 @@ //////////////////////////////////////////////////////////////////////////////// #include "Ahuacatl/ahuacatl-constant-folder.h" +#include "Ahuacatl/ahuacatl-conversions.h" +#include "Ahuacatl/ahuacatl-functions.h" + +#include "V8/v8-execution.h" // ----------------------------------------------------------------------------- // --SECTION-- private functions @@ -36,6 +40,119 @@ /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief create code for a function call +//////////////////////////////////////////////////////////////////////////////// + +static TRI_string_buffer_t* FcallCode(const char* const name, + const TRI_aql_node_t* const args) { + TRI_string_buffer_t* buffer = TRI_CreateStringBuffer(TRI_UNKNOWN_MEM_ZONE); + size_t i; + size_t n; + + if (!buffer) { + return NULL; + } + + if (TRI_AppendStringStringBuffer(buffer, "(function(){return ") != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + if (TRI_AppendStringStringBuffer(buffer, name) != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + if (TRI_AppendCharStringBuffer(buffer, '(') != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + n = args->_members._length; + for (i = 0; i < n; ++i) { + TRI_aql_node_t* arg = (TRI_aql_node_t*) args->_members._buffer[i]; + if (i > 0) { + if (TRI_AppendCharStringBuffer(buffer, ',') != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + } + + if (!TRI_NodeJavascriptAql(buffer, arg)) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + } + + if (TRI_AppendStringStringBuffer(buffer, ");})") != TRI_ERROR_NO_ERROR) { + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); + return NULL; + } + + return buffer; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief optimise a function call +//////////////////////////////////////////////////////////////////////////////// + +static TRI_aql_node_t* OptimiseFcall (TRI_aql_context_t* const context, + TRI_aql_node_t* node) { + TRI_aql_node_t* args = (TRI_aql_node_t*) node->_members._buffer[0]; + TRI_aql_function_t* function; + TRI_js_exec_context_t* execContext; + TRI_string_buffer_t* code; + TRI_json_t* json; + size_t i; + size_t n; + + function = (TRI_aql_function_t*) TRI_AQL_NODE_DATA(node); + assert(function); + + // check if function is deterministic + if (!function->_isDeterministic) { + return node; + } + + // check if function call arguments are deterministic + n = args->_members._length; + for (i = 0; i < n; ++i) { + TRI_aql_node_t* arg = (TRI_aql_node_t*) args->_members._buffer[i]; + + if (!arg || !TRI_IsConstantValueNodeAql(arg)) { + return node; + } + } + + // all arguments are constants + code = FcallCode(function->_internalName, args); + if (!code) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return node; + } + + execContext = TRI_CreateExecutionContext(code->_buffer); + TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, code); + + if (!execContext) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return node; + } + + json = TRI_ExecuteResultContext(execContext); + if (!json) { + TRI_FreeExecutionContext(execContext); + return NULL; + } + + node = TRI_JsonNodeAql(context, json); + + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + + return node; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief optimise an arithmetic operation with one operand //////////////////////////////////////////////////////////////////////////////// @@ -54,7 +171,6 @@ static TRI_aql_node_t* OptimiseUnaryArithmeticOperation (TRI_aql_context_t* cons return node; } - assert(node->_type == AQL_NODE_OPERATOR_UNARY_PLUS || node->_type == AQL_NODE_OPERATOR_UNARY_MINUS); @@ -276,6 +392,8 @@ static TRI_aql_node_t* ModifyNode (void* data, TRI_aql_node_t* node) { case AQL_NODE_OPERATOR_BINARY_DIV: case AQL_NODE_OPERATOR_BINARY_MOD: return OptimiseBinaryArithmeticOperation(context, node); + case AQL_NODE_FCALL: + return OptimiseFcall(context, node); default: break; } diff --git a/Ahuacatl/ahuacatl-context.c b/Ahuacatl/ahuacatl-context.c index 35379cf414..abb9c53cb8 100644 --- a/Ahuacatl/ahuacatl-context.c +++ b/Ahuacatl/ahuacatl-context.c @@ -271,6 +271,7 @@ bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) { // constant folding failed return false; } +// TRI_DumpTreeAql((TRI_aql_node_t*) context->_first); return true; } @@ -295,8 +296,6 @@ bool TRI_LockQueryContextAql (TRI_aql_context_t* const context) { return false; } - // TRI_DumpTreeAql((TRI_aql_node_t*) context->_first); - return true; } @@ -514,15 +513,22 @@ bool TRI_AddVariableContextAql (TRI_aql_context_t* const context, const char* na char* TRI_RegisterStringAql (TRI_aql_context_t* const context, const char* const value, - const size_t length) { + const size_t length, + const bool deescape) { char* copy; - size_t outLength; if (!value) { ABORT_OOM } - copy = TRI_UnescapeUtf8String(value, length, &outLength); + if (deescape) { + size_t outLength; + copy = TRI_UnescapeUtf8String(value, length, &outLength); + } + else { + copy = TRI_DuplicateString(value); + } + if (!copy) { ABORT_OOM } diff --git a/Ahuacatl/ahuacatl-context.h b/Ahuacatl/ahuacatl-context.h index 82580634e2..b72a2b0732 100644 --- a/Ahuacatl/ahuacatl-context.h +++ b/Ahuacatl/ahuacatl-context.h @@ -62,7 +62,6 @@ extern "C" { typedef struct TRI_aql_scope_s { struct TRI_aql_scope_s* _parent; // parent scope TRI_associative_pointer_t _variables; // symbol table -// void* _node; // the start node of the scope void* _first; void* _last; } @@ -202,7 +201,8 @@ bool TRI_AddVariableContextAql (TRI_aql_context_t* const, const char*); char* TRI_RegisterStringAql (TRI_aql_context_t* const, const char* const, - const size_t); + const size_t, + const bool); //////////////////////////////////////////////////////////////////////////////// /// @brief checks if a variable is defined in the current scope or above diff --git a/Ahuacatl/ahuacatl-conversions.c b/Ahuacatl/ahuacatl-conversions.c new file mode 100644 index 0000000000..a4aef213a0 --- /dev/null +++ b/Ahuacatl/ahuacatl-conversions.c @@ -0,0 +1,273 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief Ahuacatl, conversions +/// +/// @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-conversions.h" + +//////////////////////////////////////////////////////////////////////////////// +/// @brief append list values to a string buffer +//////////////////////////////////////////////////////////////////////////////// + +static bool AppendListValues (TRI_string_buffer_t* const buffer, + const TRI_aql_node_t* const node) { + size_t i, n; + + n = node->_members._length; + for (i = 0; i < n; ++i) { + if (i > 0) { + if (TRI_AppendCharStringBuffer(buffer, ',') != TRI_ERROR_NO_ERROR) { + return false; + } + } + + if (!TRI_NodeJavascriptAql(buffer, TRI_AQL_NODE_MEMBER(node, i))) { + return false; + } + } + + return true; +} + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief create a value node from a json struct +//////////////////////////////////////////////////////////////////////////////// + +TRI_aql_node_t* TRI_JsonNodeAql (TRI_aql_context_t* const context, + const TRI_json_t* const json) { + TRI_aql_node_t* node = NULL; + char* value; + + switch (json->_type) { + case TRI_JSON_UNUSED: + break; + + case TRI_JSON_NULL: + node = TRI_CreateNodeValueNullAql(context); + break; + + case TRI_JSON_BOOLEAN: + node = TRI_CreateNodeValueBoolAql(context, json->_value._boolean); + break; + + case TRI_JSON_NUMBER: + node = TRI_CreateNodeValueDoubleAql(context, json->_value._number); + break; + + case TRI_JSON_STRING: + value = TRI_RegisterStringAql(context, json->_value._string.data, strlen(json->_value._string.data), false); + node = TRI_CreateNodeValueStringAql(context, value); + break; + + case TRI_JSON_LIST: { + size_t i; + size_t n; + + node = TRI_CreateNodeListAql(context); + n = json->_value._objects._length; + + for (i = 0; i < n; ++i) { + TRI_json_t* subJson; + TRI_aql_node_t* member; + + subJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); + assert(subJson); + + member = TRI_JsonNodeAql(context, subJson); + if (member) { + TRI_PushBackVectorPointer(&node->_members, (void*) member); + } + else { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return NULL; + } + } + break; + } + case TRI_JSON_ARRAY: { + size_t i; + size_t n; + + node = TRI_CreateNodeArrayAql(context); + n = json->_value._objects._length; + + for (i = 0; i < n; i += 2) { + TRI_json_t* nameJson; + TRI_json_t* valueJson; + TRI_aql_node_t* member; + TRI_aql_node_t* valueNode; + char* name; + + // json_t containing the array element name + nameJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); + assert(nameJson); + assert(nameJson->_value._string.data); + name = TRI_RegisterStringAql(context, nameJson->_value._string.data, strlen(nameJson->_value._string.data), false); + if (!name) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return NULL; + } + + // json_t containing the array element value + valueJson = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i + 1); + assert(valueJson); + + valueNode = TRI_JsonNodeAql(context, valueJson); + if (!valueNode) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return NULL; + } + + member = TRI_CreateNodeArrayElementAql(context, name, valueNode); + if (member) { + TRI_PushBackVectorPointer(&node->_members, (void*) member); + } + else { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return NULL; + } + } + break; + } + } + + if (!node) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + } + + return node; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a value node to its Javascript representation +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_ValueJavascriptAql (TRI_string_buffer_t* const buffer, + const TRI_aql_value_t* const value, + const TRI_aql_value_type_e type) { + switch (type) { + case AQL_TYPE_FAIL: + return (TRI_AppendStringStringBuffer(buffer, "fail") == TRI_ERROR_NO_ERROR); + + case AQL_TYPE_NULL: + return (TRI_AppendStringStringBuffer(buffer, "null") == TRI_ERROR_NO_ERROR); + + case AQL_TYPE_BOOL: + return (TRI_AppendStringStringBuffer(buffer, value->_value._bool ? "true" : "false") == TRI_ERROR_NO_ERROR); + + case AQL_TYPE_INT: + return (TRI_AppendInt64StringBuffer(buffer, value->_value._int) == TRI_ERROR_NO_ERROR); + + case AQL_TYPE_DOUBLE: + return (TRI_AppendDoubleStringBuffer(buffer, value->_value._double) == TRI_ERROR_NO_ERROR); + + case AQL_TYPE_STRING: { + char* escapedString; + size_t outLength; + + if (TRI_AppendCharStringBuffer(buffer, '"') != TRI_ERROR_NO_ERROR) { + return false; + } + + escapedString = TRI_EscapeUtf8String(value->_value._string, strlen(value->_value._string), false, &outLength); + if (!escapedString) { + return false; + } + + if (TRI_AppendStringStringBuffer(buffer, escapedString) != TRI_ERROR_NO_ERROR) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, escapedString); + return false; + } + + TRI_Free(TRI_UNKNOWN_MEM_ZONE, escapedString); + + return (TRI_AppendCharStringBuffer(buffer, '"') == TRI_ERROR_NO_ERROR); + } + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a node to its Javascript representation +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_NodeJavascriptAql (TRI_string_buffer_t* const buffer, + const TRI_aql_node_t* const node) { + switch (node->_type) { + case AQL_NODE_VALUE: + return TRI_ValueJavascriptAql(buffer, &node->_value, node->_value._type); + case AQL_NODE_ARRAY_ELEMENT: + if (!TRI_ValueJavascriptAql(buffer, &node->_value, AQL_TYPE_STRING)) { + return false; + } + + if (TRI_AppendCharStringBuffer(buffer, ':') != TRI_ERROR_NO_ERROR) { + return false; + } + + return TRI_NodeJavascriptAql(buffer, TRI_AQL_NODE_MEMBER(node, 0)); + case AQL_NODE_LIST: + if (TRI_AppendCharStringBuffer(buffer, '[') != TRI_ERROR_NO_ERROR) { + return false; + } + + if (!AppendListValues(buffer, node)) { + return false; + } + + return (TRI_AppendCharStringBuffer(buffer, ']') == TRI_ERROR_NO_ERROR); + case AQL_NODE_ARRAY: + if (TRI_AppendCharStringBuffer(buffer, '{') != TRI_ERROR_NO_ERROR) { + return false; + } + + if (!AppendListValues(buffer, node)) { + return false; + } + + return (TRI_AppendCharStringBuffer(buffer, '}') == TRI_ERROR_NO_ERROR); + default: + return false; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/Ahuacatl/ast-codegen-js.h b/Ahuacatl/ahuacatl-conversions.h similarity index 51% rename from Ahuacatl/ast-codegen-js.h rename to Ahuacatl/ahuacatl-conversions.h index 00d3d9fe04..47c3cd85a3 100644 --- a/Ahuacatl/ast-codegen-js.h +++ b/Ahuacatl/ahuacatl-conversions.h @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -/// @brief Ahuacatl, AST to JS code generator +/// @brief Ahuacatl, conversions /// /// @file /// @@ -25,15 +25,13 @@ /// @author Copyright 2012, triagens GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -#ifndef TRIAGENS_DURHAM_AHUACATL_AST_CODEGEN_JS_H -#define TRIAGENS_DURHAM_AHUACATL_AST_CODEGEN_JS_H 1 +#ifndef TRIAGENS_DURHAM_AHUACATL_CONVERSIONS_H +#define TRIAGENS_DURHAM_AHUACATL_CONVERSIONS_H 1 #include -#include -#include -#include #include -#include +#include +#include #include "Ahuacatl/ahuacatl-ast-node.h" @@ -41,58 +39,6 @@ extern "C" { #endif -// ----------------------------------------------------------------------------- -// --SECTION-- public types -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup Ahuacatl -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief enumeration of scope types -//////////////////////////////////////////////////////////////////////////////// - -typedef enum { - AQL_CODE_SCOPE_STANDALONE = 0, - AQL_CODE_SCOPE_RESULT = 1, - AQL_CODE_SCOPE_COMPARE = 2 -} -TRI_aql_code_scope_type_e; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief a function scope created by the code generator -//////////////////////////////////////////////////////////////////////////////// - -typedef struct TRI_aql_codegen_scope_s { - TRI_aql_code_scope_type_e _type; - TRI_string_buffer_t* _buffer; - char* _funcName; - char* _variablePrefix; - size_t _forLoops; - size_t _indent; -} -TRI_aql_codegen_scope_t; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief the code generator -//////////////////////////////////////////////////////////////////////////////// - -typedef struct TRI_aql_codegen_s { - TRI_string_buffer_t _buffer; - TRI_vector_pointer_t _scopes; - size_t _funcIndex; - bool _error; - char* _funcName; - TRI_vector_pointer_t _strings; -} -TRI_aql_codegen_t; - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- @@ -103,22 +49,26 @@ TRI_aql_codegen_t; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -/// @brief create a code generator +/// @brief create a value node from a json struct //////////////////////////////////////////////////////////////////////////////// -TRI_aql_codegen_t* TRI_CreateCodegenAql (void); +TRI_aql_node_t* TRI_JsonNodeAql (TRI_aql_context_t* const, + const TRI_json_t* const); //////////////////////////////////////////////////////////////////////////////// -/// @brief free the code generator +/// @brief convert a value node to its Javascript representation //////////////////////////////////////////////////////////////////////////////// -void TRI_FreeCodegenAql (TRI_aql_codegen_t* const); +bool TRI_ValueJavascriptAql (TRI_string_buffer_t* const, + const TRI_aql_value_t* const, + const TRI_aql_value_type_e); //////////////////////////////////////////////////////////////////////////////// -/// @brief generate Javascript code for the AST nodes recursively +/// @brief convert a node to its Javascript representation //////////////////////////////////////////////////////////////////////////////// -char* TRI_GenerateCodeAql (const void* const); +bool TRI_NodeJavascriptAql (TRI_string_buffer_t* const, + const TRI_aql_node_t* const); //////////////////////////////////////////////////////////////////////////////// /// @} diff --git a/Ahuacatl/ahuacatl-functions.c b/Ahuacatl/ahuacatl-functions.c index 91f83d80d0..d7858b3451 100644 --- a/Ahuacatl/ahuacatl-functions.c +++ b/Ahuacatl/ahuacatl-functions.c @@ -169,6 +169,20 @@ void TRI_FreeFunctionsAql (TRI_associative_pointer_t* functions) { TRI_Free(TRI_UNKNOWN_MEM_ZONE, functions); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a pointer to a function by name +//////////////////////////////////////////////////////////////////////////////// + +TRI_aql_function_t* TRI_GetFunctionAql (TRI_associative_pointer_t* functions, + const char* const internalName) { + TRI_aql_function_t* function; + + function = (TRI_aql_function_t*) TRI_LookupByKeyAssociativePointer(functions, (void*) internalName); + assert(function); + + return function; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief check if a function name is valid //////////////////////////////////////////////////////////////////////////////// @@ -186,16 +200,7 @@ bool TRI_IsValidFunctionAql (TRI_associative_pointer_t* functions, /// @brief get internal function name for an external one //////////////////////////////////////////////////////////////////////////////// -char* TRI_GetInternalNameFunctionAql (TRI_associative_pointer_t* functions, - const char* const externalName) { - TRI_aql_function_t* function; - - function = (TRI_aql_function_t*) TRI_LookupByKeyAssociativePointer(functions, externalName); - - if (!function) { - return NULL; - } - +const char* TRI_GetInternalNameFunctionAql (const TRI_aql_function_t* const function) { return function->_internalName; } @@ -233,6 +238,7 @@ bool TRI_RegisterFunctionAql (TRI_associative_pointer_t* functions, function->_minArgs = minArgs; function->_maxArgs = maxArgs; + function->_isDeterministic = isDeterministic; if (TRI_InsertKeyAssociativePointer(functions, externalName, function, false)) { // function already registered diff --git a/Ahuacatl/ahuacatl-functions.h b/Ahuacatl/ahuacatl-functions.h index 62314b4cae..c12cdf5c9a 100644 --- a/Ahuacatl/ahuacatl-functions.h +++ b/Ahuacatl/ahuacatl-functions.h @@ -67,6 +67,13 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void); void TRI_FreeFunctionsAql (TRI_associative_pointer_t*); +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a pointer to a function by name +//////////////////////////////////////////////////////////////////////////////// + +TRI_aql_function_t* TRI_GetFunctionAql (TRI_associative_pointer_t*, + const char*); + //////////////////////////////////////////////////////////////////////////////// /// @brief check if a function name is valid //////////////////////////////////////////////////////////////////////////////// @@ -77,7 +84,7 @@ bool TRI_IsValidFunctionAql (TRI_associative_pointer_t*, const char* const); /// @brief get internal function name for an external one //////////////////////////////////////////////////////////////////////////////// -char* TRI_GetInternalNameFunctionAql (TRI_associative_pointer_t*, const char* const); +const char* TRI_GetInternalNameFunctionAql (const TRI_aql_function_t* const); //////////////////////////////////////////////////////////////////////////////// /// @brief register a function name diff --git a/Ahuacatl/ahuacatl-tokens.c b/Ahuacatl/ahuacatl-tokens.c index 58d2ecdcbe..2a1eff34c8 100644 --- a/Ahuacatl/ahuacatl-tokens.c +++ b/Ahuacatl/ahuacatl-tokens.c @@ -1353,7 +1353,7 @@ YY_RULE_SETUP case 39: YY_RULE_SETUP { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext, strlen(yytext)); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext, strlen(yytext), false); return T_STRING; } YY_BREAK @@ -1361,7 +1361,7 @@ case 40: /* rule 40 can match eol */ YY_RULE_SETUP { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2, true); return T_STRING; } YY_BREAK @@ -1369,7 +1369,7 @@ case 41: /* rule 41 can match eol */ YY_RULE_SETUP { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2, true); return T_QUOTED_STRING; } YY_BREAK @@ -1377,14 +1377,14 @@ case 42: /* rule 42 can match eol */ YY_RULE_SETUP { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2, true); return T_QUOTED_STRING; } YY_BREAK case 43: YY_RULE_SETUP { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext, strlen(yytext)); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext, strlen(yytext), false); return T_NUMBER; } YY_BREAK @@ -1394,7 +1394,7 @@ YY_RULE_SETUP case 44: YY_RULE_SETUP { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 1); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 1, false); return T_PARAMETER; } YY_BREAK diff --git a/Ahuacatl/ahuacatl-tokens.l b/Ahuacatl/ahuacatl-tokens.l index efdcad9ea8..427f788ee6 100644 --- a/Ahuacatl/ahuacatl-tokens.l +++ b/Ahuacatl/ahuacatl-tokens.l @@ -215,27 +215,27 @@ * --------------------------------------------------------------------------- */ ([a-zA-Z][_a-zA-Z0-9]*|_+[a-zA-Z]+[_a-zA-Z0-9]*) { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext, strlen(yytext)); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext, strlen(yytext), false); return T_STRING; } `(\\.|[^\\`])*` { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2, true); return T_STRING; } \"(\\.|[^\\\"])*\" { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2, true); return T_QUOTED_STRING; } '(\\.|[^\\'])*' { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 2, true); return T_QUOTED_STRING; } (0|[1-9][0-9]*)(\.[0-9]+([eE]([\-\+])?[0-9]+)?)? { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext, strlen(yytext)); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext, strlen(yytext), false); return T_NUMBER; } @@ -244,7 +244,7 @@ * --------------------------------------------------------------------------- */ @[a-zA-Z][a-zA-Z0-9_]* { - yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 1); + yylval->strval = TRI_RegisterStringAql(yyextra, yytext + 1, strlen(yytext) - 1, false); return T_PARAMETER; } diff --git a/Ahuacatl/ahuacatl-tree-dump.c b/Ahuacatl/ahuacatl-tree-dump.c index 52612657a0..75b1f2179c 100644 --- a/Ahuacatl/ahuacatl-tree-dump.c +++ b/Ahuacatl/ahuacatl-tree-dump.c @@ -143,9 +143,11 @@ static void DumpNode (void* data, const TRI_aql_node_t* const node) { case AQL_NODE_PARAMETER: case AQL_NODE_ARRAY_ELEMENT: case AQL_NODE_ATTRIBUTE_ACCESS: - case AQL_NODE_FCALL: DumpString(state, node); break; + case AQL_NODE_FCALL: + printf("name: %s\n", TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node))); + break; case AQL_NODE_SORT_ELEMENT: PrintIndent(state); diff --git a/Ahuacatl/ahuacatl-tree-dump.h b/Ahuacatl/ahuacatl-tree-dump.h index 862d22cd9d..5da9c493c2 100644 --- a/Ahuacatl/ahuacatl-tree-dump.h +++ b/Ahuacatl/ahuacatl-tree-dump.h @@ -35,6 +35,7 @@ #include #include "Ahuacatl/ahuacatl-ast-node.h" +#include "Ahuacatl/ahuacatl-functions.h" #include "Ahuacatl/ahuacatl-tree-walker.h" #ifdef __cplusplus diff --git a/Ahuacatl/ast-codegen-js.c b/Ahuacatl/ast-codegen-js.c deleted file mode 100644 index 624e3ebca4..0000000000 --- a/Ahuacatl/ast-codegen-js.c +++ /dev/null @@ -1,1244 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// @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 - -#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(TRI_UNKNOWN_MEM_ZONE, 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(TRI_UNKNOWN_MEM_ZONE, scope->_buffer); - } - - TRI_Free(TRI_UNKNOWN_MEM_ZONE, 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_code_scope_type_e type) { - TRI_aql_codegen_scope_t* scope; - - scope = (TRI_aql_codegen_scope_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_codegen_scope_t), false); - - if (!scope) { - return NULL; - } - - scope->_funcName = TRI_DuplicateString(funcName); - if (!scope->_funcName) { - FreeScope(scope); - return NULL; - } - - printf("CREATING A SCOPE\n"); - - RegisterString(generator, scope->_funcName); - scope->_variablePrefix = NULL; - scope->_indent = 0; - scope->_forLoops = 0; - scope->_type = type; - - scope->_buffer = TRI_CreateStringBuffer(TRI_UNKNOWN_MEM_ZONE); - 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_code_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); - printf("REMOVING A SCOPE\n"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @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_code_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_CODE_SCOPE_COMPARE) { - TRI_AppendStringStringBuffer(&generator->_buffer, "l, r"); - } - else { - TRI_AppendStringStringBuffer(&generator->_buffer, "previous"); - } - - TRI_AppendStringStringBuffer(&generator->_buffer, ") {\n"); - if (type != AQL_CODE_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(TRI_UNKNOWN_MEM_ZONE); - if (!body) { - // oom - generator->_error = true; - } - else { - if (scope->_type == AQL_CODE_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(TRI_UNKNOWN_MEM_ZONE, 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_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(TRI_UNKNOWN_MEM_ZONE, 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 node) { - AppendCode(generator, "$['"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - 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 node) { - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - - 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 node) { - AppendCode(generator, "_"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - - 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 node) { - AppendCode(generator, "__"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - - 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; -} - -static void ProcessNode (TRI_aql_codegen_t* const, const TRI_aql_node_t* const); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief generate the code for an individual node and all members -//////////////////////////////////////////////////////////////////////////////// - -static void GenerateCode (TRI_aql_codegen_t* const generator, - const TRI_aql_node_t* const node) { - size_t i; - size_t n; - - if (!node) { - return; - } - - ProcessNode(generator, node); - n = node->_subNodes._length; - - for (i = 0; i < n; ++i) { - TRI_aql_node_t* subNode = (TRI_aql_node_t*) node->_subNodes._buffer[i]; - - ProcessNode(generator, subNode); - } -} - - -static void ProcessNode (TRI_aql_codegen_t* const generator, - const TRI_aql_node_t* const node) { - - printf("GENERATING CODE FOR NODE: %s\n", TRI_NodeNameAql(node->_type)); - - switch (node->_type) { - case AQL_NODE_VALUE: - AppendValue(generator, node); - break; - case AQL_NODE_LIST: { - size_t i, n; - - AppendCode(generator, "[ "); - n = node->_members._length; - for (i = 0; i < n; ++i) { - if (i > 0) { - AppendCode(generator, ", "); - } - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, i)); - } - AppendCode(generator, " ]"); - break; - } - case AQL_NODE_ARRAY: { - size_t i, n; - - AppendCode(generator, "{ "); - n = node->_members._length; - for (i = 0; i < n; ++i) { - if (i > 0) { - AppendCode(generator, ", "); - } - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, i)); - } - AppendCode(generator, " }"); - break; - } - case AQL_NODE_ARRAY_ELEMENT: { - AppendCode(generator, "'"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - AppendCode(generator, "' : "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - break; - } - case AQL_NODE_FOR: - AppendIndent(generator); - AppendCode(generator, "var "); - AppendVarname2(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, " = AHUACATL_LIST("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ");\n"); - - AppendIndent(generator); - AppendCode(generator, "for (var "); - AppendVarname1(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, " in "); - AppendVarname2(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ") {\n"); - - IncreaseForCount(generator); - AppendOwnPropertyVar(generator, TRI_AQL_NODE_MEMBER(node, 0)); - - AppendIndent(generator); - AppendVarname(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, " = "); - AppendVarname2(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, "["); - AppendVarname1(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, "];\n"); - break; - case AQL_NODE_COLLECT: { - char* previousFunction; - char* sortFuncName; - char* groupFuncName; - size_t i, n; - TRI_aql_node_t* list; - - sortFuncName = GetNextFunctionName(generator); - - StartScope(generator, AQL_CODE_SCOPE_COMPARE, sortFuncName); - AppendIndent(generator); - AppendCode(generator, "var lhs, rhs;\n"); - - list = TRI_AQL_NODE_MEMBER(node, 0); - n = list->_members._length; - for (i = 0; i < n; ++i) { - TRI_aql_node_t* element = TRI_AQL_NODE_MEMBER(list, i); - - AppendIndent(generator); - AppendCode(generator, "lhs = "); - SetVariablePrefix(generator, "l"); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(element, 1)); - AppendCode(generator, ";\n"); - - AppendIndent(generator); - AppendCode(generator, "rhs = "); - SetVariablePrefix(generator, "r"); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(element, 1)); - 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_CODE_SCOPE_RESULT, groupFuncName); - AppendIndent(generator); - - AppendCode(generator, "return { "); - - n = list->_members._length; - for (i = 0; i < n; ++i) { - TRI_aql_node_t* element = TRI_AQL_NODE_MEMBER(list, i); - TRI_aql_node_t* varNode = TRI_AQL_NODE_MEMBER(element, 0); - if (i > 0) { - AppendCode(generator, ", "); - } - AppendCode(generator, "'"); - AppendCode(generator, TRI_AQL_NODE_STRING(varNode)); - AppendCode(generator, "' : "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(element, 1)); - } - 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_MEMBER(node, 1)) { - AppendCode(generator, ", '"); - AppendVarname0(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, "'"); - } - AppendCode(generator, ");\n"); - previousFunction = EndScope(generator); - - StartScope(generator, AQL_CODE_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_CODE_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_MEMBER(node, 1)); - AppendCode(generator, ");\n"); - Outdent(generator); - AppendIndent(generator); - AppendCode(generator, "}\n"); - EndScope(generator); - - AppendCode(generator, funcName); - AppendCode(generator, "("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ")"); - break; - } - case AQL_NODE_ASSIGN: - AppendIndent(generator); - AppendVarname(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, " = "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ";\n"); - break; - case AQL_NODE_SUBQUERY: { - char* funcName = GetNextFunctionName(generator); - - if (!funcName) { - assert(false); - // TODO: oom - } - - StartScope(generator, AQL_CODE_SCOPE_RESULT, funcName); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - - AppendCode(generator, funcName); - AppendCode(generator, "($)"); - break; - } - case AQL_NODE_FILTER: - AppendIndent(generator); - AppendCode(generator, "if (!("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - 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_MEMBER(node, 0)); - AppendCode(generator, ");\n"); - CloseForLoops(generator); - EndScope(generator); - break; - case AQL_NODE_LIMIT: { - char* previousFunction; - - AppendIndent(generator); - AppendCode(generator, "result.push($);\n"); - CloseForLoops(generator); - AppendCode(generator, " result = AHUACATL_LIMIT(result, "); - - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ");\n"); - previousFunction = EndScope(generator); - - StartScope(generator, AQL_CODE_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_t* list; - char* previousFunction; - char* sortFuncName; - size_t i; - size_t n; - - previousFunction = scope->_funcName; - // todo: OOM - - sortFuncName = GetNextFunctionName(generator); - - StartScope(generator, AQL_CODE_SCOPE_COMPARE, sortFuncName); - AppendIndent(generator); - AppendCode(generator, "var lhs, rhs;\n"); - - list = TRI_AQL_NODE_MEMBER(node, 0); - n = list->_members._length; - for (i = 0; i < n; ++i) { - TRI_aql_node_t* element = TRI_AQL_NODE_MEMBER(list, i); - - AppendIndent(generator); - AppendCode(generator, "lhs = "); - SetVariablePrefix(generator, "l"); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(element, 0)); - AppendCode(generator, ";\n"); - - AppendIndent(generator); - AppendCode(generator, "rhs = "); - SetVariablePrefix(generator, "r"); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(element, 0)); - AppendCode(generator, ";\n"); - SetVariablePrefix(generator, NULL); - - AppendIndent(generator); - AppendCode(generator, "if (AHUACATL_RELATIONAL_LESS(lhs, rhs)) {\n"); - Indent(generator); - AppendIndent(generator); - if (TRI_AQL_NODE_BOOL(element)) { - 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 (TRI_AQL_NODE_BOOL(element)) { - 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_CODE_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_COLLECTION: - AppendCode(generator, "AHUACATL_GET_DOCUMENTS('"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - AppendCode(generator, "')"); - break; - case AQL_NODE_REFERENCE: { - TRI_aql_codegen_scope_t* scope= GetCurrentScope(generator); - - if (scope->_variablePrefix) { - AppendCode(generator, scope->_variablePrefix); - AppendCode(generator, "['"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - AppendCode(generator, "']"); - } - else { - AppendCode(generator, "$['"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - AppendCode(generator, "']"); - } - break; - } - case AQL_NODE_PARAMETER: - AppendCode(generator, "AHUACATL_GET_PARAMETER('"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - AppendCode(generator, "')"); - break; - case AQL_NODE_ATTRIBUTE_ACCESS: - AppendCode(generator, "AHUACATL_DOCUMENT_MEMBER("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", '"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - AppendCode(generator, "')"); - break; - case AQL_NODE_INDEXED: - AppendCode(generator, "AHUACATL_GET_INDEX("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_ATTRIBUTE: - AppendCode(generator, "AHUACATL_DOCUMENT_MEMBER(__e[_e], '"); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - AppendCode(generator, "')"); - break; - case AQL_NODE_OPERATOR_UNARY_NOT: - AppendCode(generator, "AHUACATL_LOGICAL_NOT("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_UNARY_PLUS: - AppendCode(generator, "AHUACATL_UNARY_PLUS("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_UNARY_MINUS: - AppendCode(generator, "AHUACATL_UNARY_MINUS("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_AND: - AppendCode(generator, "AHUACATL_LOGICAL_AND("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_OR: - AppendCode(generator, "AHUACATL_LOGICAL_OR("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_PLUS: - AppendCode(generator, "AHUACATL_ARITHMETIC_PLUS("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_MINUS: - AppendCode(generator, "AHUACATL_ARITHMETIC_MINUS("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_TIMES: - AppendCode(generator, "AHUACATL_ARITHMETIC_TIMES("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_DIV: - AppendCode(generator, "AHUACATL_ARITHMETIC_DIVIDE("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_MOD: - AppendCode(generator, "AHUACATL_ARITHMETIC_MODULUS("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_EQ: - AppendCode(generator, "AHUACATL_RELATIONAL_EQUAL("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_NE: - AppendCode(generator, "AHUACATL_RELATIONAL_UNEQUAL("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_LT: - AppendCode(generator, "AHUACATL_RELATIONAL_LESS("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_LE: - AppendCode(generator, "AHUACATL_RELATIONAL_LESSEQUAL("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_GT: - AppendCode(generator, "AHUACATL_RELATIONAL_GREATER("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_GE: - AppendCode(generator, "AHUACATL_RELATIONAL_GREATEREQUAL("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_OPERATOR_BINARY_IN: - AppendCode(generator, "AHUACATL_RELATIONAL_IN("); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 1)); - AppendCode(generator, ")"); - break; - case AQL_NODE_FCALL: { - AppendCode(generator, "AHUACATL_FCALL("); - AppendCode(generator, TRI_AQL_NODE_STRING(node)); - AppendCode(generator, ", "); - GenerateCode(generator, TRI_AQL_NODE_MEMBER(node, 0)); - AppendCode(generator, ")"); - } - default: - break; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --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(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_codegen_t), false); - - if (!generator) { - return NULL; - } - - generator->_error = false; - generator->_funcIndex = 0; - generator->_funcName = NULL; - - TRI_InitStringBuffer(&generator->_buffer, TRI_UNKNOWN_MEM_ZONE); - - TRI_InitVectorPointer(&generator->_strings, TRI_UNKNOWN_MEM_ZONE); - - TRI_InitVectorPointer(&generator->_scopes, TRI_UNKNOWN_MEM_ZONE); - - if (!StartScope(generator, AQL_CODE_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(TRI_UNKNOWN_MEM_ZONE, string); - } - } - TRI_DestroyVectorPointer(&generator->_strings); - - TRI_Free(TRI_UNKNOWN_MEM_ZONE, 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: diff --git a/Makefile.files b/Makefile.files index 595456bc30..d63bd1c59b 100644 --- a/Makefile.files +++ b/Makefile.files @@ -158,6 +158,7 @@ avocado_SOURCES = \ Ahuacatl/ahuacatl-collections.c \ Ahuacatl/ahuacatl-constant-folder.c \ Ahuacatl/ahuacatl-context.c \ + Ahuacatl/ahuacatl-conversions.c \ Ahuacatl/ahuacatl-error.c \ Ahuacatl/ahuacatl-functions.c \ Ahuacatl/ahuacatl-grammar.c \ diff --git a/Makefile.in b/Makefile.in index b0cc060c62..96571ddc50 100644 --- a/Makefile.in +++ b/Makefile.in @@ -339,6 +339,7 @@ am_avocado_OBJECTS = Admin/ApplicationAdminServer.$(OBJEXT) \ Ahuacatl/ahuacatl-collections.$(OBJEXT) \ Ahuacatl/ahuacatl-constant-folder.$(OBJEXT) \ Ahuacatl/ahuacatl-context.$(OBJEXT) \ + Ahuacatl/ahuacatl-conversions.$(OBJEXT) \ Ahuacatl/ahuacatl-error.$(OBJEXT) \ Ahuacatl/ahuacatl-functions.$(OBJEXT) \ Ahuacatl/ahuacatl-grammar.$(OBJEXT) \ @@ -773,6 +774,7 @@ avocado_SOURCES = \ Ahuacatl/ahuacatl-collections.c \ Ahuacatl/ahuacatl-constant-folder.c \ Ahuacatl/ahuacatl-context.c \ + Ahuacatl/ahuacatl-conversions.c \ Ahuacatl/ahuacatl-error.c \ Ahuacatl/ahuacatl-functions.c \ Ahuacatl/ahuacatl-grammar.c \ @@ -1687,6 +1689,8 @@ Ahuacatl/ahuacatl-constant-folder.$(OBJEXT): Ahuacatl/$(am__dirstamp) \ Ahuacatl/$(DEPDIR)/$(am__dirstamp) Ahuacatl/ahuacatl-context.$(OBJEXT): Ahuacatl/$(am__dirstamp) \ Ahuacatl/$(DEPDIR)/$(am__dirstamp) +Ahuacatl/ahuacatl-conversions.$(OBJEXT): Ahuacatl/$(am__dirstamp) \ + Ahuacatl/$(DEPDIR)/$(am__dirstamp) Ahuacatl/ahuacatl-error.$(OBJEXT): Ahuacatl/$(am__dirstamp) \ Ahuacatl/$(DEPDIR)/$(am__dirstamp) Ahuacatl/ahuacatl-functions.$(OBJEXT): Ahuacatl/$(am__dirstamp) \ @@ -1953,6 +1957,7 @@ mostlyclean-compile: -rm -f Ahuacatl/ahuacatl-collections.$(OBJEXT) -rm -f Ahuacatl/ahuacatl-constant-folder.$(OBJEXT) -rm -f Ahuacatl/ahuacatl-context.$(OBJEXT) + -rm -f Ahuacatl/ahuacatl-conversions.$(OBJEXT) -rm -f Ahuacatl/ahuacatl-error.$(OBJEXT) -rm -f Ahuacatl/ahuacatl-functions.$(OBJEXT) -rm -f Ahuacatl/ahuacatl-grammar.$(OBJEXT) @@ -2193,6 +2198,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@Ahuacatl/$(DEPDIR)/ahuacatl-collections.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@Ahuacatl/$(DEPDIR)/ahuacatl-constant-folder.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@Ahuacatl/$(DEPDIR)/ahuacatl-context.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Ahuacatl/$(DEPDIR)/ahuacatl-conversions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@Ahuacatl/$(DEPDIR)/ahuacatl-error.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@Ahuacatl/$(DEPDIR)/ahuacatl-functions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@Ahuacatl/$(DEPDIR)/ahuacatl-grammar.Po@am__quote@ diff --git a/V8/v8-conv.cpp b/V8/v8-conv.cpp index 82a47095d1..77d0375e0b 100644 --- a/V8/v8-conv.cpp +++ b/V8/v8-conv.cpp @@ -1553,6 +1553,68 @@ TRI_shaped_json_t* TRI_ShapedJsonV8Object (v8::Handle object, TRI_sha return shaped; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a V8 value to a json_t value +//////////////////////////////////////////////////////////////////////////////// + +TRI_json_t* TRI_ObjectToJson (v8::Handle parameter) { + if (parameter->IsBoolean()) { + v8::Handle booleanParameter = parameter->ToBoolean(); + return TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, booleanParameter->Value()); + } + + if (parameter->IsNull()) { + return TRI_CreateNullJson(TRI_UNKNOWN_MEM_ZONE); + } + + if (parameter->IsNumber()) { + v8::Handle numberParameter = parameter->ToNumber(); + return TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, numberParameter->Value()); + } + + if (parameter->IsString()) { + v8::Handle stringParameter= parameter->ToString(); + v8::String::Utf8Value str(stringParameter); + return TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, *str); + } + + if (parameter->IsArray()) { + v8::Handle arrayParameter = v8::Handle::Cast(parameter); + TRI_json_t* listJson = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE); + if (listJson) { + for (uint32_t j = 0; j < arrayParameter->Length(); ++j) { + v8::Handle item = arrayParameter->Get(j); + TRI_json_t* result = TRI_ObjectToJson(item); + if (result) { + TRI_PushBack2ListJson(listJson, result); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, result); + } + } + } + return listJson; + } + + if (parameter->IsObject()) { + v8::Handle arrayParameter = v8::Handle::Cast(parameter); + TRI_json_t* arrayJson = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE); + if (arrayJson) { + v8::Handle names = arrayParameter->GetOwnPropertyNames(); + for (uint32_t j = 0; j < names->Length(); ++j) { + v8::Handle key = names->Get(j); + v8::Handle item = arrayParameter->Get(key); + TRI_json_t* result = TRI_ObjectToJson(item); + if (result) { + TRI_Insert2ArrayJson(TRI_UNKNOWN_MEM_ZONE, arrayJson, TRI_ObjectToString(key).c_str(), result); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, result); + } + } + } + return arrayJson; + } + + return NULL; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief converts an V8 object to a string //////////////////////////////////////////////////////////////////////////////// diff --git a/V8/v8-conv.h b/V8/v8-conv.h index 352fc75f79..dac32fbeb7 100644 --- a/V8/v8-conv.h +++ b/V8/v8-conv.h @@ -92,6 +92,12 @@ v8::Handle TRI_JsonShapeData (TRI_shaper_t*, TRI_shaped_json_t* TRI_ShapedJsonV8Object (v8::Handle, TRI_shaper_t*); +//////////////////////////////////////////////////////////////////////////////// +/// @brief convert a V8 value to a json_t value +//////////////////////////////////////////////////////////////////////////////// + +TRI_json_t* TRI_ObjectToJson (v8::Handle); + //////////////////////////////////////////////////////////////////////////////// /// @brief converts an V8 object to a string //////////////////////////////////////////////////////////////////////////////// diff --git a/V8/v8-execution.cpp b/V8/v8-execution.cpp index b31a515393..e3cf018025 100644 --- a/V8/v8-execution.cpp +++ b/V8/v8-execution.cpp @@ -677,6 +677,28 @@ bool TRI_ExecuteOrderExecutionContext (TRI_js_exec_context_t context, int* r) { return true; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief executes a result context +//////////////////////////////////////////////////////////////////////////////// + +TRI_json_t* TRI_ExecuteResultContext (TRI_js_exec_context_t context) { + js_exec_context_t* ctx; + + ctx = (js_exec_context_t*) context; + // convert back into a handle + v8::Persistent func = ctx->_func; + + // and execute the function + v8::Handle args[] = { ctx->_arguments }; + v8::Handle result = func->Call(func, 1, args); + + if (result.IsEmpty()) { + return NULL; + } + + return TRI_ObjectToJson(result); +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/V8/v8-execution.h b/V8/v8-execution.h index 5eac0a70e9..39a25e4da1 100644 --- a/V8/v8-execution.h +++ b/V8/v8-execution.h @@ -142,6 +142,12 @@ bool TRI_ExecuteRefExecutionContext (TRI_memory_zone_t*, bool TRI_ExecuteOrderExecutionContext (TRI_js_exec_context_t, int* result); +//////////////////////////////////////////////////////////////////////////////// +/// @brief executes a result context +//////////////////////////////////////////////////////////////////////////////// + +TRI_json_t* TRI_ExecuteResultContext (TRI_js_exec_context_t context); + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/V8/v8-utils.h b/V8/v8-utils.h index b7968f7965..b9b941d690 100644 --- a/V8/v8-utils.h +++ b/V8/v8-utils.h @@ -86,7 +86,7 @@ static T* TRI_UnwrapClass (v8::Handle obj, int32_t type) { } return static_cast(v8::Handle::Cast(obj->GetInternalField(SLOT_CLASS))->Value()); -} +} //////////////////////////////////////////////////////////////////////////////// /// @brief adds attributes to array diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index 24f99cd1ab..980ccbdd1f 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -2831,6 +2831,7 @@ static v8::Handle JS_RunAhuacatl (v8::Arguments const& argv) { // bind parameters TRI_json_t* parameters = 0; + if (argv.Length() > 1) { parameters = TRI_JsonObject(argv[1]); } @@ -2874,10 +2875,13 @@ static v8::Handle JS_RunAhuacatl (v8::Arguments const& argv) { TRI_FreeGeneratorAql(generator); TRI_json_t* json = TRI_JsonObject(result); + if (json) { TRI_general_cursor_result_t* cursorResult = TRI_CreateResultAql(json); + if (cursorResult) { cursor = TRI_CreateGeneralCursor(cursorResult, doCount, batchSize); + if (!cursor) { TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult); TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); @@ -3079,6 +3083,7 @@ static v8::Handle JS_WhereHashConstAql (const v8::Arguments& argv) { for (int j = 1; j < argv.Length(); ++j) { v8::Handle parameter = argv[j]; TRI_json_t* jsonParameter = TRI_JsonObject(parameter); + if (jsonParameter == 0) { // NOT the null json value! return scope.Close(v8::ThrowException(v8::String::New("type value not currently supported for hash index"))); } @@ -3165,6 +3170,7 @@ static v8::Handle JS_WherePQConstAql (const v8::Arguments& argv) { for (int j = 1; j < argv.Length(); ++j) { v8::Handle parameter = argv[j]; TRI_json_t* jsonParameter = TRI_JsonObject(parameter); + if (jsonParameter == 0) { // NOT the null json value! return scope.Close(v8::ThrowException(v8::String::New("type value not currently supported for priority queue index"))); } @@ -3279,6 +3285,7 @@ static v8::Handle JS_WhereSkiplistConstAql (const v8::Arguments& argv for (int j = 1; j < argv.Length(); ++j) { v8::Handle parameter = argv[j]; TRI_json_t* jsonParameter = TRI_JsonObject(parameter); + if (jsonParameter == 0) { // NOT the null json value! return scope.Close(v8::ThrowException(v8::String::New("type value not currently supported for skiplist index"))); } @@ -3650,6 +3657,7 @@ static TRI_json_t* parametersToJson(v8::Arguments const& argv, int startPos, int for (int j = startPos; j < endPos; ++j) { v8::Handle parameter = argv[j]; TRI_json_t* jsonParameter = TRI_JsonObject(parameter); + if (jsonParameter == 0) { // NOT the null json value! v8::ThrowException(v8::String::New("type value not currently supported for skiplist index")); return 0; diff --git a/js/server/tests/ahuacatl-escaping.js b/js/server/tests/ahuacatl-escaping.js index 44c6e6a62b..32be967c06 100644 --- a/js/server/tests/ahuacatl-escaping.js +++ b/js/server/tests/ahuacatl-escaping.js @@ -144,7 +144,7 @@ function ahuacatlEscapingTestSuite () { /// @brief test punctuation names escaping //////////////////////////////////////////////////////////////////////////////// - testPunctuationName1 : function () { + testPunctuationBackticks1 : function () { var expected = [ 1, 2, 3 ]; var actual = getQueryResults("FOR `brown_fox` IN [ 1, 2, 3 ] RETURN `brown_fox`", true); assertEqual(expected, actual); @@ -154,12 +154,122 @@ function ahuacatlEscapingTestSuite () { /// @brief test punctuation names escaping //////////////////////////////////////////////////////////////////////////////// - testPunctuationName2 : function () { + testPunctuationBackticks2 : function () { var expected = [ 1, 2, 3 ]; var actual = getQueryResults("FOR `brown_fox__1234_` IN [ 1, 2, 3 ] RETURN `brown_fox__1234_`", true); assertEqual(expected, actual); }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationBackticks3 : function () { + var expected = [ 1, 2, 3 ]; + var actual = getQueryResults("FOR `brown fox 1234_` IN [ 1, 2, 3 ] RETURN `brown fox 1234_`", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationBackticks4 : function () { + var expected = [ 1, 3 ]; + var actual = getQueryResults("FOR r IN [ { \"a\" : 1, \"b\" : 1 }, { \"a\" : 2, \"b\" : 2 }, { \"a\" : 1, \"b\" : 3 } ] FILTER r.`a` == 1 RETURN r.`b`", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationBackticks5 : function () { + var expected = [ 1, 3 ]; + var actual = getQueryResults("FOR r IN [ { \"a fox\" : 1, \"b fox\" : 1 }, { \"a fox\" : 2, \"b fox\" : 2 }, { \"a fox\" : 1, \"b fox\" : 3 } ] FILTER r.`a fox` == 1 RETURN r.`b fox`", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationDoubleQuotes1 : function () { + var expected = [ { '"a"' : 1 }, { '"a"' : '"b"' } ]; + var actual = getQueryResults("FOR r IN [ { '\"a\"' : 1 }, { '\"a\"' : '\"b\"' } ] RETURN r", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationDoubleQuotes2 : function () { + var expected = [ { '"a fox"' : 1 }, { '"a fox "' : '"b fox"' } ]; + var actual = getQueryResults("FOR r IN [ { '\"a fox\"' : 1 }, { '\"a fox \"' : '\"b fox\"' } ] RETURN r", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationDoubleQuotes3 : function () { + var expected = [ { '"a" \\ " fox"' : 1 }, { '"a" \\ " fox "' : '"b fox"' } ]; + var actual = getQueryResults("FOR r IN [ { '\"a\" \\\\ \\\" fox\"' : 1 }, { '\"a\" \\\\ \\\" fox \"' : '\"b fox\"' } ] RETURN r", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationSingleQuotes1 : function () { + var expected = [ { "'a'" : 1 }, { "'a'" : "'b'" } ]; + var actual = getQueryResults("FOR r IN [ { \"'a'\" : 1 }, { \"'a'\" : \"'b'\" } ] RETURN r", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationSingleQuotes2 : function () { + var expected = [ { "'a fox'" : 1 }, { "'a fox'" : "'b fox'" } ]; + var actual = getQueryResults("FOR r IN [ { \"'a fox'\" : 1 }, { \"'a fox'\" : \"'b fox'\" } ] RETURN r", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test punctuation names escaping +//////////////////////////////////////////////////////////////////////////////// + + testPunctuationSingleQuotes3 : function () { + var expected = [ { "'a \\ ' fox'" : 1 }, { "'a \\ ' fox'" : "'b fox'" } ]; + var actual = getQueryResults("FOR r IN [ { \"'a \\\\ \\' fox'\" : 1 }, { \"'a \\\\ \\' fox'\" : \"'b fox'\" } ] RETURN r", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test UTF8 names escaping +//////////////////////////////////////////////////////////////////////////////// + + testUtf8Names1 : function () { + var expected = [ "wälder", "hänsel", "grätel", "fraß", "kloß" ]; + var actual = getQueryResults("FOR r IN [ { \"äöüÄÖÜß\" : \"wälder\" }, { \"äöüÄÖÜß\" : \"hänsel\" }, { \"äöüÄÖÜß\" : \"grätel\" }, { \"äöüÄÖÜß\" : \"fraß\" }, { \"äöüÄÖÜß\" : \"kloß\" } ] RETURN r.`äöüÄÖÜß`", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test UTF8 names escaping +//////////////////////////////////////////////////////////////////////////////// + + testUtf8Names2 : function () { + var expected = [ "中央アメリカ", "熱帯", "亜熱帯" ]; + var actual = getQueryResults("FOR r IN [ { \"アボカド\" : \"中央アメリカ\" }, { \"アボカド\" : \"熱帯\" }, { \"アボカド\" : \"亜熱帯\" } ] RETURN r.`アボカド`", true); + assertEqual(expected, actual); + }, + }; }