diff --git a/Ahuacatl/ahuacatl-constant-folder.c b/Ahuacatl/ahuacatl-constant-folder.c index 36e600c526..074e89205f 100644 --- a/Ahuacatl/ahuacatl-constant-folder.c +++ b/Ahuacatl/ahuacatl-constant-folder.c @@ -35,11 +35,553 @@ // --SECTION-- private functions // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief hash a variable +//////////////////////////////////////////////////////////////////////////////// + +static uint64_t HashFieldAccess (TRI_associative_pointer_t* array, + void const* element) { + TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) element; + + return TRI_FnvHashString(fieldAccess->_fieldName); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief comparison function used to determine variable equality +//////////////////////////////////////////////////////////////////////////////// + +static bool EqualFieldAccess (TRI_associative_pointer_t* array, + void const* key, + void const* element) { + TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) element; + + return TRI_EqualString(key, fieldAccess->_fieldName); +} + +static int TypeWeight (const TRI_json_t* const value) { + switch (value->_type) { + case TRI_JSON_BOOLEAN: + return 1; + case TRI_JSON_NUMBER: + return 2; + case TRI_JSON_STRING: + return 3; + case TRI_JSON_LIST: + return 4; + case TRI_JSON_ARRAY: + return 5; + case TRI_JSON_NULL: + default: + return 0; + } +} + +static int Compare (const TRI_json_t* const lhs, const TRI_json_t* const rhs) { + int lWeight = TypeWeight(lhs); + int rWeight = TypeWeight(rhs); + + if (lWeight < rWeight) { + return -1; + } + if (lWeight > rWeight) { + return 1; + } + + // equal weight + switch (lhs->_type) { + case TRI_JSON_NULL: + return 0; // null == null; + case TRI_JSON_BOOLEAN: + if (lhs->_value._boolean == rhs->_value._boolean) { + return 0; + } + if (!lhs->_value._boolean && rhs->_value._boolean) { + return -1; + } + return 1; + case TRI_JSON_NUMBER: + if (lhs->_value._number == rhs->_value._number) { + return 0; + } + if (lhs->_value._number < rhs->_value._number) { + return -1; + } + return 1; + case TRI_JSON_STRING: + return strcmp(lhs->_value._string.data, rhs->_value._string.data); + case TRI_JSON_LIST: { + size_t nl = lhs->_value._objects._length; + size_t nr = rhs->_value._objects._length; + size_t i; + + for (i = 0; i < nl; ++i) { + int result; + + if (i >= nr) { + // left list is longer + return 1; + } + + result = Compare(TRI_AtVector(&lhs->_value._objects, i), TRI_AtVector(&rhs->_value._objects, i)); + if (result != 0) { + return result; + } + } + + // right list is longer + if (nr > nl) { + return -1; + } + + return 0; + } + case TRI_JSON_ARRAY: { + size_t nl = lhs->_value._objects._length; + size_t nr = rhs->_value._objects._length; + size_t i; + + for (i = 0; i < nl; i += 2) { + int result; + + if (i > nr) { + // left list is longer + return 1; + } + + // compare key + result = Compare(TRI_AtVector(&lhs->_value._objects, i), TRI_AtVector(&rhs->_value._objects, i)); + if (result != 0) { + return result; + } + + // compare value + result = Compare(TRI_AtVector(&lhs->_value._objects, i + 1), TRI_AtVector(&rhs->_value._objects, i + 1)); + if (result != 0) { + return result; + } + } + + // right list is longer + if (nr > nl) { + return -1; + } + + return 0; + } + default: + return 0; + } +} + +static bool IsSameValue (const TRI_json_t* const lhs, const TRI_json_t* const rhs) { + if (!lhs || !rhs) { + return false; + } + + if (lhs->_type != rhs->_type) { + return false; + } + + switch (lhs->_type) { + case TRI_JSON_NULL: + return true; + case TRI_JSON_BOOLEAN: + return (lhs->_value._boolean == rhs->_value._boolean); + case TRI_JSON_NUMBER: + return (lhs->_value._number == rhs->_value._number); // TODO: handle epsilon + case TRI_JSON_STRING: + return TRI_EqualString(lhs->_value._string.data, rhs->_value._string.data); + case TRI_JSON_LIST: + case TRI_JSON_ARRAY: { + // lists and arrays can be treated the same here + size_t n = lhs->_value._objects._length; + size_t i; + + if (n != rhs->_value._objects._length) { + return false; + } + + for (i = 0; i < n; ++i) { + if (!IsSameValue(TRI_AtVector(&lhs->_value._objects, i), TRI_AtVector(&rhs->_value._objects, i))) { + return false; + } + } + return true; + } + default: + return false; + } +} + +static bool IsInList (const TRI_json_t* const lhs, const TRI_json_t* const rhs) { + size_t n; + size_t i; + + if (!lhs || !rhs || !rhs->_type == TRI_JSON_LIST) { + return false; + } + + n = rhs->_value._objects._length; + for (i = 0; i < n; ++i) { + TRI_json_t* r = (TRI_json_t*) TRI_AtVector(&rhs->_value._objects, i); + + if (IsSameValue(lhs, r)) { + return true; + } + } + + return false; +} + +static char* AccessName (const TRI_aql_access_e type) { + switch (type) { + case TRI_AQL_ACCESS_ALL: + return "all"; + case TRI_AQL_ACCESS_IMPOSSIBLE: + return "impossible"; + case TRI_AQL_ACCESS_EXACT: + return "exact"; + case TRI_AQL_ACCESS_LIST: + return "list"; + case TRI_AQL_ACCESS_SINGLE_RANGE: + return "single range"; + case TRI_AQL_ACCESS_DOUBLE_RANGE: + return "double range"; + default: + return "unknown"; + } +} + +static TRI_aql_field_access_t* MergeAccess (TRI_aql_context_t* const context, + TRI_aql_field_access_t* lhs, + TRI_aql_field_access_t* rhs) { + assert(lhs); + assert(rhs); + + assert(lhs->_fieldName != NULL); + assert(rhs->_fieldName != NULL); + + if (lhs->_type > rhs->_type) { + // swap operands so they are always sorted + TRI_aql_field_access_t* tmp = lhs; + lhs = rhs; + rhs = tmp; + } + + if (lhs->_type == TRI_AQL_ACCESS_ALL) { + // TODO: free lhs + return rhs; + } + + if (lhs->_type == TRI_AQL_ACCESS_IMPOSSIBLE) { + // TODO: free rhs + return lhs; + } + + if (lhs->_type == TRI_AQL_ACCESS_EXACT) { + if (rhs->_type == TRI_AQL_ACCESS_EXACT) { + if (!IsSameValue(lhs->_value._exactValue, rhs->_value._exactValue)) { + // lhs and rhs values are non-identical + lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, lhs->_value._exactValue); + // TODO: free rhs + return lhs; + } + + // lhs and rhs values are identical + // TODO: free rhs + return lhs; + } + else if (rhs->_type == TRI_AQL_ACCESS_LIST) { + if (!IsInList(lhs->_value._exactValue, rhs->_value._list)) { + // lhs value is not in rhs list + lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, lhs->_value._exactValue); + // TODO: free rhs + return lhs; + } + + // lhs value is contained in rhs + // TODO: free rhs + return lhs; + } + else if (rhs->_type == TRI_AQL_ACCESS_SINGLE_RANGE) { + // check if value is in range + int result = Compare(lhs->_value._exactValue, rhs->_value._singleRange._value); + + bool contained = ((rhs->_value._singleRange._type == TRI_AQL_RANGE_LOWER_EXCLUDED && result > 0) || + (rhs->_value._singleRange._type == TRI_AQL_RANGE_LOWER_INCLUDED && result >= 0) || + (rhs->_value._singleRange._type == TRI_AQL_RANGE_UPPER_EXCLUDED && result < 0) || + (rhs->_value._singleRange._type == TRI_AQL_RANGE_UPPER_INCLUDED && result <= 0)); + + if (!contained) { + // lhs value is not contained in rhs range + lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, lhs->_value._exactValue); + // TODO: free rhs + return lhs; + } + + // lhs value is contained in rhs range + // TODO: free lhs + return rhs; + } + else if (rhs->_type == TRI_AQL_ACCESS_DOUBLE_RANGE) { + // check if value is in range + int result; + bool contained; + + result = Compare(lhs->_value._exactValue, rhs->_value._between._lower._value); + + contained = ((rhs->_value._between._lower._type == TRI_AQL_RANGE_LOWER_EXCLUDED && result > 0) || + (rhs->_value._between._lower._type == TRI_AQL_RANGE_LOWER_INCLUDED && result >= 0)); + + if (!contained) { + // lhs value is not contained in rhs range + lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, lhs->_value._exactValue); + // TODO: free rhs + return lhs; + } + + result = Compare(lhs->_value._exactValue, rhs->_value._between._upper._value); + + contained = ((rhs->_value._between._upper._type == TRI_AQL_RANGE_UPPER_EXCLUDED && result < 0) || + (rhs->_value._between._upper._type == TRI_AQL_RANGE_UPPER_INCLUDED && result <= 0)); + + if (!contained) { + // lhs value is not contained in rhs range + lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE; + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, lhs->_value._exactValue); + // TODO: free rhs + return lhs; + } + + // lhs value is contained in rhs range + // TODO: free lhs + return rhs; + } + } + + if (lhs->_type == TRI_AQL_ACCESS_LIST) { + if (rhs->_type == TRI_AQL_ACCESS_LIST) { + // make a list of both + } + else if (rhs->_type == TRI_AQL_ACCESS_SINGLE_RANGE) { + // check if value in range + } + else if (rhs->_type == TRI_AQL_ACCESS_DOUBLE_RANGE) { + // check if value in range + } + } + + if (lhs->_type == TRI_AQL_ACCESS_SINGLE_RANGE) { + if (rhs->_type == TRI_AQL_ACCESS_SINGLE_RANGE) { + // check if value in range + } + else if (rhs->_type == TRI_AQL_ACCESS_DOUBLE_RANGE) { + // check if value in range + } + } + + if (lhs->_type == TRI_AQL_ACCESS_DOUBLE_RANGE) { + } + + return NULL; +} + + +static TRI_aql_field_access_t* CreateAccess (TRI_aql_context_t* const context, + const TRI_aql_field_name_t* const field, + const TRI_aql_node_type_e operator, + const TRI_aql_node_t* const node) { + TRI_aql_field_access_t* fieldAccess; + TRI_json_t* value; + + value = TRI_NodeJsonAql(context, node); + if (!value) { + return NULL; + } + + fieldAccess = (TRI_aql_field_access_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_field_access_t), false); + if (fieldAccess == NULL) { + return NULL; + } + + fieldAccess->_fieldName = TRI_DuplicateString(field->_name._buffer); + if (fieldAccess->_fieldName == NULL) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, fieldAccess); + return NULL; + } + + if (operator == AQL_NODE_OPERATOR_BINARY_EQ) { + fieldAccess->_type = TRI_AQL_ACCESS_EXACT; + fieldAccess->_value._exactValue = value; + } + else if (operator == AQL_NODE_OPERATOR_BINARY_LT) { + fieldAccess->_type = TRI_AQL_ACCESS_SINGLE_RANGE; + fieldAccess->_value._singleRange._type = TRI_AQL_RANGE_UPPER_EXCLUDED; + fieldAccess->_value._singleRange._value = value; + } + else if (operator == AQL_NODE_OPERATOR_BINARY_LE) { + fieldAccess->_type = TRI_AQL_ACCESS_SINGLE_RANGE; + fieldAccess->_value._singleRange._type = TRI_AQL_RANGE_UPPER_INCLUDED; + fieldAccess->_value._singleRange._value = value; + } + else if (operator == AQL_NODE_OPERATOR_BINARY_GT) { + fieldAccess->_type = TRI_AQL_ACCESS_SINGLE_RANGE; + fieldAccess->_value._singleRange._type = TRI_AQL_RANGE_LOWER_EXCLUDED; + fieldAccess->_value._singleRange._value = value; + } + else if (operator == AQL_NODE_OPERATOR_BINARY_GE) { + fieldAccess->_type = TRI_AQL_ACCESS_SINGLE_RANGE; + fieldAccess->_value._singleRange._type = TRI_AQL_RANGE_LOWER_INCLUDED; + fieldAccess->_value._singleRange._value = value; + } + else { + assert(false); + } + + return fieldAccess; +} + + +static void CreateFieldAccess (TRI_aql_context_t* const context, + const TRI_aql_field_name_t* const field, + const TRI_aql_node_type_e operator, + const TRI_aql_node_t* const node) { + TRI_aql_field_access_t* previous; + TRI_aql_field_access_t* fieldAccess; + + if (!field || !field->_name._buffer) { + return; + } + + fieldAccess = CreateAccess(context, field, operator, node); + if (!fieldAccess) { + // TODO: mark failure + return; + } + + previous = (TRI_aql_field_access_t*) TRI_LookupByKeyAssociativePointer(&context->_ranges, field->_name._buffer); + if (previous) { + printf("ENTER MERGE\n"); + TRI_aql_field_access_t* merged = MergeAccess(context, fieldAccess, previous); + printf("LEAVE MERGE\n"); + + // TODO: + // free previous + // free fieldAccess + if (merged) { + TRI_InsertKeyAssociativePointer(&context->_ranges, fieldAccess->_fieldName, merged, true); + printf("MERGE1\n"); + } + + // previous access exists, must merge + // merge(previous, new) + // TRI_InsertKeyAssociativePointer(&context + } + else { + // no previous access exists, no need to merge + TRI_InsertKeyAssociativePointer(&context->_ranges, fieldAccess->_fieldName, fieldAccess, false); + printf("INSERT1\n"); + } +} + //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Ahuacatl /// @{ //////////////////////////////////////////////////////////////////////////////// +static TRI_aql_field_name_t* GetFieldName (TRI_aql_context_t* const context, + const TRI_aql_node_t* const node) { + if (node->_type == AQL_NODE_ATTRIBUTE_ACCESS) { + TRI_aql_field_name_t* field = GetFieldName(context, TRI_AQL_NODE_MEMBER(node, 0)); + + if (!field) { + return NULL; + } + + TRI_AppendCharStringBuffer(&field->_name, '.'); + TRI_AppendStringStringBuffer(&field->_name, TRI_AQL_NODE_STRING(node)); + return field; + } + else if (node->_type == AQL_NODE_REFERENCE) { + TRI_aql_field_name_t* field; + + field = (TRI_aql_field_name_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_field_name_t), false); + + if (!field) { + TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); + return NULL; + } + + field->_variable = TRI_AQL_NODE_STRING(node); + TRI_InitStringBuffer(&field->_name, TRI_UNKNOWN_MEM_ZONE); + TRI_AppendStringStringBuffer(&field->_name, TRI_AQL_NODE_STRING(node)); + + return field; + } + + return NULL; +} +//////////////////////////////////////////////////////////////////////////////// +/// @brief inspect a filter expression +//////////////////////////////////////////////////////////////////////////////// + +static void InspectFilter (TRI_aql_context_t* const context, + TRI_aql_node_t* node) { + printf("ITERATION SOMETHING %s\n", TRI_NodeNameAql(node->_type)); + if (node->_type == AQL_NODE_OPERATOR_UNARY_NOT) { + return; + } + + if (node->_type == AQL_NODE_OPERATOR_BINARY_OR) { + TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1); + + InspectFilter(context, lhs); + InspectFilter(context, rhs); + } + + if (node->_type == AQL_NODE_OPERATOR_BINARY_AND) { + TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1); + + InspectFilter(context, lhs); + InspectFilter(context, rhs); + } + + if (node->_type == AQL_NODE_OPERATOR_BINARY_EQ || +// node->_type == AQL_NODE_OPERATOR_BINARY_NE || + node->_type == AQL_NODE_OPERATOR_BINARY_LT || + node->_type == AQL_NODE_OPERATOR_BINARY_LE || + node->_type == AQL_NODE_OPERATOR_BINARY_GT || + node->_type == AQL_NODE_OPERATOR_BINARY_GE) { + TRI_aql_node_t* lhs = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* rhs = TRI_AQL_NODE_MEMBER(node, 1); + + if (lhs->_type == AQL_NODE_ATTRIBUTE_ACCESS) { + TRI_aql_field_name_t* field = GetFieldName(context, lhs); + + if (field) { + CreateFieldAccess(context, field, node->_type, rhs); + TRI_DestroyStringBuffer(&field->_name); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, field); + } + } + else if (lhs->_type == AQL_NODE_ATTRIBUTE_ACCESS) { + TRI_aql_field_name_t* field = GetFieldName(context, rhs); + + if (field) { + CreateFieldAccess(context, field, node->_type, lhs); + TRI_DestroyStringBuffer(&field->_name); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, field); + } + } + } +} + //////////////////////////////////////////////////////////////////////////////// /// @brief create javascript function code for a relational operation //////////////////////////////////////////////////////////////////////////////// @@ -265,7 +807,12 @@ static TRI_aql_node_t* OptimiseFilter (TRI_aql_context_t* const context, TRI_aql_node_t* expression = TRI_AQL_NODE_MEMBER(node, 0); bool result; - if (!expression || !TRI_IsConstantValueNodeAql(expression)) { + if (!expression) { + return node; + } + + if (!TRI_IsConstantValueNodeAql(expression)) { + //InspectFilter(context, expression); return node; } @@ -558,6 +1105,32 @@ static TRI_aql_node_t* OptimiseBinaryArithmeticOperation (TRI_aql_context_t* con return node; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief mark a for node +//////////////////////////////////////////////////////////////////////////////// + +static TRI_aql_node_t* MarkFor (TRI_aql_context_t* const context, + TRI_aql_node_t* node) { + TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_node_t* expressionNode = TRI_AQL_NODE_MEMBER(node, 1); + + if (!nameNode || !expressionNode) { + return node; + } + + if (expressionNode->_type == AQL_NODE_COLLECTION) { + char* varName = TRI_AQL_NODE_STRING(nameNode); + char* collectionName = TRI_AQL_NODE_STRING(expressionNode); + + if (!varName || !collectionName) { + return node; + } + } + + return node; +} + + //////////////////////////////////////////////////////////////////////////////// /// @brief fold constants in a node //////////////////////////////////////////////////////////////////////////////// @@ -598,6 +1171,8 @@ static TRI_aql_node_t* ModifyNode (void* data, TRI_aql_node_t* node) { return OptimiseFilter(context, node); case AQL_NODE_FCALL: return OptimiseFcall(context, node); + case AQL_NODE_FOR: +// return MarkFor(context, node); default: break; } @@ -625,6 +1200,14 @@ static TRI_aql_node_t* ModifyNode (void* data, TRI_aql_node_t* node) { TRI_aql_node_t* TRI_FoldConstantsAql (TRI_aql_context_t* const context, TRI_aql_node_t* node) { TRI_aql_modify_tree_walker_t* walker; + + // todo: must free + TRI_InitAssociativePointer(&context->_ranges, + TRI_UNKNOWN_MEM_ZONE, + &TRI_HashStringKeyAssociativePointer, + &HashFieldAccess, + &EqualFieldAccess, + NULL); walker = TRI_CreateModifyTreeWalkerAql((void*) context, &ModifyNode); if (!walker) { @@ -635,7 +1218,33 @@ TRI_aql_node_t* TRI_FoldConstantsAql (TRI_aql_context_t* const context, node = TRI_ModifyWalkTreeAql(walker, node); TRI_FreeModifyTreeWalkerAql(walker); +/* + size_t i; + for (i = 0; i < context->_ranges._nrAlloc; ++i) { + TRI_aql_field_access_t* fieldAccess = context->_ranges._table[i]; + if (!fieldAccess) { + continue; + } + + printf("\nFIELD ACCESS\n- FIELD: %s\n",fieldAccess->_fieldName); + printf("- TYPE: %s\n", AccessName(fieldAccess->_type)); + if (fieldAccess->_type == TRI_AQL_ACCESS_EXACT) { + TRI_string_buffer_t b; + TRI_InitStringBuffer(&b, TRI_UNKNOWN_MEM_ZONE); + TRI_StringifyJson(&b, fieldAccess->_value._exactValue); + + printf("- VALUE: %s\n", b._buffer); + } + else if (fieldAccess->_type == TRI_AQL_ACCESS_SINGLE_RANGE) { + TRI_string_buffer_t b; + TRI_InitStringBuffer(&b, TRI_UNKNOWN_MEM_ZONE); + TRI_StringifyJson(&b, fieldAccess->_value._singleRange._value); + + printf("- VALUE: %s\n", b._buffer); + } + } +*/ return node; } diff --git a/Ahuacatl/ahuacatl-constant-folder.h b/Ahuacatl/ahuacatl-constant-folder.h index 4788df1d1b..93ac6c0cbd 100644 --- a/Ahuacatl/ahuacatl-constant-folder.h +++ b/Ahuacatl/ahuacatl-constant-folder.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -51,6 +52,66 @@ extern "C" { /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief access type +//////////////////////////////////////////////////////////////////////////////// + +typedef enum { + TRI_AQL_RANGE_LOWER_EXCLUDED, + TRI_AQL_RANGE_LOWER_INCLUDED, + TRI_AQL_RANGE_UPPER_EXCLUDED, + TRI_AQL_RANGE_UPPER_INCLUDED +} +TRI_aql_range_e; + +typedef enum { + TRI_AQL_ACCESS_ALL = 0, + TRI_AQL_ACCESS_IMPOSSIBLE, + TRI_AQL_ACCESS_EXACT, + TRI_AQL_ACCESS_LIST, + TRI_AQL_ACCESS_SINGLE_RANGE, + TRI_AQL_ACCESS_DOUBLE_RANGE, +} +TRI_aql_access_e; + +typedef struct TRI_aql_range_s { + TRI_json_t* _value; + TRI_aql_range_e _type; +} +TRI_aql_range_t; + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief attribute access container used during optimisation +//////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_aql_field_access_s { + char* _fieldName; + TRI_aql_access_e _type; + union { + TRI_json_t* _exactValue; + TRI_json_t* _list; + TRI_aql_range_t _singleRange; + struct { + TRI_aql_range_t _lower; + TRI_aql_range_t _upper; + } + _between; + } + _value; +} +TRI_aql_field_access_t; + + + +typedef struct TRI_aql_field_name_s { + const char* _variable; + TRI_string_buffer_t _name; +} +TRI_aql_field_name_t; + + + //////////////////////////////////////////////////////////////////////////////// /// @brief fold constants recursively //////////////////////////////////////////////////////////////////////////////// diff --git a/Ahuacatl/ahuacatl-context.h b/Ahuacatl/ahuacatl-context.h index b72a2b0732..a069040839 100644 --- a/Ahuacatl/ahuacatl-context.h +++ b/Ahuacatl/ahuacatl-context.h @@ -82,6 +82,7 @@ typedef struct TRI_aql_context_s { TRI_associative_pointer_t _parameterValues; TRI_associative_pointer_t _parameterNames; TRI_associative_pointer_t _collectionNames; + TRI_associative_pointer_t _ranges; size_t _variableIndex; void* _first; char* _query; diff --git a/Ahuacatl/ahuacatl-conversions.c b/Ahuacatl/ahuacatl-conversions.c index a4aef213a0..cb3c8a39b6 100644 --- a/Ahuacatl/ahuacatl-conversions.c +++ b/Ahuacatl/ahuacatl-conversions.c @@ -60,6 +60,59 @@ static bool AppendListValues (TRI_string_buffer_t* const buffer, /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief create a json struct from a value node +//////////////////////////////////////////////////////////////////////////////// + +TRI_json_t* TRI_NodeJsonAql (TRI_aql_context_t* const context, + const TRI_aql_node_t* const node) { + switch (node->_type) { + case AQL_NODE_VALUE: { + switch (node->_value._type) { + case AQL_TYPE_FAIL: + case AQL_TYPE_NULL: + return TRI_CreateNullJson(TRI_UNKNOWN_MEM_ZONE); + case AQL_TYPE_BOOL: + return TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, node->_value._value._bool); + case AQL_TYPE_INT: + return TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, (double) node->_value._value._int); + case AQL_TYPE_DOUBLE: + return TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, node->_value._value._double); + case AQL_TYPE_STRING: + return TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, node->_value._value._string); + } + } + case AQL_NODE_LIST: { + TRI_json_t* result = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE); + size_t i, n; + + if (result) { + n = node->_members._length; + for (i = 0; i < n; ++i) { + TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, TRI_NodeJsonAql(context, TRI_AQL_NODE_MEMBER(node, i))); + } + } + return result; + } + case AQL_NODE_ARRAY: { + TRI_json_t* result = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE); + size_t i, n; + + if (result) { + n = node->_members._length; + for (i = 0; i < n; ++i) { + TRI_aql_node_t* element = TRI_AQL_NODE_MEMBER(node, i); + TRI_InsertArrayJson(TRI_UNKNOWN_MEM_ZONE, result, TRI_AQL_NODE_STRING(element), TRI_NodeJsonAql(context, TRI_AQL_NODE_MEMBER(element, 0))); + } + } + return result; + } + default: { + return NULL; + } + } +} + //////////////////////////////////////////////////////////////////////////////// /// @brief create a value node from a json struct //////////////////////////////////////////////////////////////////////////////// diff --git a/Ahuacatl/ahuacatl-conversions.h b/Ahuacatl/ahuacatl-conversions.h index 47c3cd85a3..1d16ce8734 100644 --- a/Ahuacatl/ahuacatl-conversions.h +++ b/Ahuacatl/ahuacatl-conversions.h @@ -48,6 +48,13 @@ extern "C" { /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief create a json struct from a value node +//////////////////////////////////////////////////////////////////////////////// + +TRI_json_t* TRI_NodeJsonAql (TRI_aql_context_t* const, + const TRI_aql_node_t* const); + //////////////////////////////////////////////////////////////////////////////// /// @brief create a value node from a json struct ////////////////////////////////////////////////////////////////////////////////