diff --git a/Ahuacatl/ast-codegen-js.c b/Ahuacatl/ast-codegen-js.c index 3791735e88..9b7dd19ff9 100644 --- a/Ahuacatl/ast-codegen-js.c +++ b/Ahuacatl/ast-codegen-js.c @@ -39,7 +39,7 @@ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -/// @brief register a function name for later disposal +/// @brief register a function name for easier later disposal //////////////////////////////////////////////////////////////////////////////// static bool RegisterString (TRI_aql_codegen_t* const generator, @@ -51,6 +51,10 @@ static bool RegisterString (TRI_aql_codegen_t* const generator, 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; @@ -71,6 +75,11 @@ static char* GetIndexedFunctionName (TRI_aql_codegen_t* const generator, 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; @@ -81,6 +90,10 @@ static char* GetNextFunctionName (TRI_aql_codegen_t* const generator) { return functionName; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief free a code scope +//////////////////////////////////////////////////////////////////////////////// + static void FreeScope (TRI_aql_codegen_scope_t* const scope) { assert(scope); @@ -93,10 +106,16 @@ static void FreeScope (TRI_aql_codegen_scope_t* const scope) { TRI_Free(scope); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief create a code scope +//////////////////////////////////////////////////////////////////////////////// + static TRI_aql_codegen_scope_t* CreateScope (TRI_aql_codegen_t* const generator, const char* const funcName, const TRI_aql_scope_type_e type) { - TRI_aql_codegen_scope_t* scope = (TRI_aql_codegen_scope_t*) TRI_Allocate(sizeof(TRI_aql_codegen_scope_t)); + TRI_aql_codegen_scope_t* scope; + + scope = (TRI_aql_codegen_scope_t*) TRI_Allocate(sizeof(TRI_aql_codegen_scope_t)); if (!scope) { return NULL; @@ -123,7 +142,13 @@ static TRI_aql_codegen_scope_t* CreateScope (TRI_aql_codegen_t* const generator, return scope; } -static bool StartScope (TRI_aql_codegen_t* const generator, const TRI_aql_scope_type_e type, const char* const funcName) { +//////////////////////////////////////////////////////////////////////////////// +/// @brief start a new code scope +//////////////////////////////////////////////////////////////////////////////// + +static bool StartScope (TRI_aql_codegen_t* const generator, + const TRI_aql_scope_type_e type, + const char* const funcName) { TRI_aql_codegen_scope_t* scope; assert(generator); @@ -140,6 +165,10 @@ static bool StartScope (TRI_aql_codegen_t* const generator, const TRI_aql_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; @@ -155,6 +184,10 @@ static TRI_aql_codegen_scope_t* GetCurrentScope (TRI_aql_codegen_t* const genera 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); @@ -165,6 +198,10 @@ static void Indent (TRI_aql_codegen_t* const generator) { 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); @@ -176,6 +213,10 @@ static void Outdent (TRI_aql_codegen_t* const generator) { --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; @@ -189,6 +230,10 @@ static void AppendIndent (TRI_aql_codegen_t* const generator) { } } +//////////////////////////////////////////////////////////////////////////////// +/// @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; @@ -203,6 +248,10 @@ static void RemoveCurrentScope (TRI_aql_codegen_t* const generator) { FreeScope(scope); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief close all for loops in current scope +//////////////////////////////////////////////////////////////////////////////// + static void CloseForLoops (TRI_aql_codegen_t* const generator) { TRI_aql_codegen_scope_t* scope; size_t i; @@ -223,7 +272,14 @@ static void CloseForLoops (TRI_aql_codegen_t* const generator) { } } -static bool AppendFunction (TRI_aql_codegen_t* const generator, const TRI_aql_scope_type_e type, const char* const name, const char* const body) { +//////////////////////////////////////////////////////////////////////////////// +/// @brief write a function definition to the output buffer +//////////////////////////////////////////////////////////////////////////////// + +static bool AppendFunction (TRI_aql_codegen_t* const generator, + const TRI_aql_scope_type_e type, + const char* const name, + const char* const body) { assert(generator); assert(name); assert(body); @@ -249,6 +305,10 @@ static bool AppendFunction (TRI_aql_codegen_t* const generator, const TRI_aql_sc 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; @@ -288,6 +348,10 @@ static char* EndScope (TRI_aql_codegen_t* const 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; @@ -305,6 +369,10 @@ static void IncreaseForCount (TRI_aql_codegen_t* const generator) { 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; @@ -317,7 +385,12 @@ static void AppendCode (TRI_aql_codegen_t* const generator, const char* const co TRI_AppendStringStringBuffer(scope->_buffer, code); } -static bool AppendValue (TRI_aql_codegen_t* const generator, const TRI_aql_node_value_t* const node) { +//////////////////////////////////////////////////////////////////////////////// +/// @brief append the value of a value node to the current scope's output buffer +//////////////////////////////////////////////////////////////////////////////// + +static bool AppendValue (TRI_aql_codegen_t* const generator, + const TRI_aql_node_value_t* const node) { TRI_aql_codegen_scope_t* scope; assert(generator); @@ -364,7 +437,12 @@ static bool AppendValue (TRI_aql_codegen_t* const generator, const TRI_aql_node_ return true; } -static void SetVariablePrefix (TRI_aql_codegen_t* const generator, const char* const prefix) { +//////////////////////////////////////////////////////////////////////////////// +/// @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); @@ -376,7 +454,12 @@ static void SetVariablePrefix (TRI_aql_codegen_t* const generator, const char* c scope->_variablePrefix = (char*) prefix; } -static bool AppendVarname (TRI_aql_codegen_t* const generator, const TRI_aql_node_t* const data) { +//////////////////////////////////////////////////////////////////////////////// +/// @brief print a variable name in the current scope, enclosed in $['...'] +//////////////////////////////////////////////////////////////////////////////// + +static bool AppendVarname (TRI_aql_codegen_t* const generator, + const TRI_aql_node_t* const data) { TRI_aql_node_variable_t* node = (TRI_aql_node_variable_t*) data; AppendCode(generator, "$['"); @@ -386,7 +469,12 @@ static bool AppendVarname (TRI_aql_codegen_t* const generator, const TRI_aql_nod return true; } -static bool AppendVarname0 (TRI_aql_codegen_t* const generator, const TRI_aql_node_t* const data) { +//////////////////////////////////////////////////////////////////////////////// +/// @brief print a variable name in the current scope, without modifications +//////////////////////////////////////////////////////////////////////////////// + +static bool AppendVarname0 (TRI_aql_codegen_t* const generator, + const TRI_aql_node_t* const data) { TRI_aql_node_variable_t* node = (TRI_aql_node_variable_t*) data; AppendCode(generator, node->_name); @@ -394,7 +482,12 @@ static bool AppendVarname0 (TRI_aql_codegen_t* const generator, const TRI_aql_no return true; } -static bool AppendVarname1 (TRI_aql_codegen_t* const generator, const TRI_aql_node_t* const data) { +//////////////////////////////////////////////////////////////////////////////// +/// @brief print a variable name in the current scope, prepended by "_" +//////////////////////////////////////////////////////////////////////////////// + +static bool AppendVarname1 (TRI_aql_codegen_t* const generator, + const TRI_aql_node_t* const data) { TRI_aql_node_variable_t* node = (TRI_aql_node_variable_t*) data; AppendCode(generator, "_"); @@ -403,7 +496,12 @@ static bool AppendVarname1 (TRI_aql_codegen_t* const generator, const TRI_aql_no return true; } -static bool AppendVarname2 (TRI_aql_codegen_t* const generator, const TRI_aql_node_t* const data) { +//////////////////////////////////////////////////////////////////////////////// +/// @brief print a variable name in the current scope, prepended by "__" +//////////////////////////////////////////////////////////////////////////////// + +static bool AppendVarname2 (TRI_aql_codegen_t* const generator, + const TRI_aql_node_t* const data) { TRI_aql_node_variable_t* node = (TRI_aql_node_variable_t*) data; AppendCode(generator, "__"); @@ -412,7 +510,12 @@ static bool AppendVarname2 (TRI_aql_codegen_t* const generator, const TRI_aql_no return true; } -static bool AppendOwnPropertyName (TRI_aql_codegen_t* const generator, const char* const name) { +//////////////////////////////////////////////////////////////////////////////// +/// @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); @@ -429,7 +532,12 @@ static bool AppendOwnPropertyName (TRI_aql_codegen_t* const generator, const cha return true; } -static bool AppendOwnPropertyVar (TRI_aql_codegen_t* const generator, const TRI_aql_node_t* const data) { +//////////////////////////////////////////////////////////////////////////////// +/// @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); @@ -446,6 +554,10 @@ static bool AppendOwnPropertyVar (TRI_aql_codegen_t* const generator, const TRI_ return true; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief generate the code for an individual node and all subnodes +//////////////////////////////////////////////////////////////////////////////// + static void GenerateCode (TRI_aql_codegen_t* const generator, const TRI_aql_node_t* const data) { TRI_aql_node_t* node; @@ -1030,7 +1142,9 @@ static void GenerateCode (TRI_aql_codegen_t* const generator, //////////////////////////////////////////////////////////////////////////////// TRI_aql_codegen_t* TRI_CreateCodegenAql (void) { - TRI_aql_codegen_t* generator = (TRI_aql_codegen_t*) TRI_Allocate(sizeof(TRI_aql_codegen_t)); + TRI_aql_codegen_t* generator; + + generator = (TRI_aql_codegen_t*) TRI_Allocate(sizeof(TRI_aql_codegen_t)); if (!generator) { return NULL; diff --git a/Ahuacatl/ast-codegen-js.h b/Ahuacatl/ast-codegen-js.h index 9f2cb44f9b..c47b81e108 100644 --- a/Ahuacatl/ast-codegen-js.h +++ b/Ahuacatl/ast-codegen-js.h @@ -50,6 +50,10 @@ extern "C" { /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief enumeration of scope types +//////////////////////////////////////////////////////////////////////////////// + typedef enum { AQL_SCOPE_STANDALONE = 0, AQL_SCOPE_RESULT = 1, @@ -57,6 +61,10 @@ typedef enum { } TRI_aql_scope_type_e; +//////////////////////////////////////////////////////////////////////////////// +/// @brief a function scope created by the code generator +//////////////////////////////////////////////////////////////////////////////// + typedef struct TRI_aql_codegen_scope_s { TRI_aql_scope_type_e _type; TRI_string_buffer_t* _buffer; @@ -67,6 +75,10 @@ typedef struct TRI_aql_codegen_scope_s { } 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; diff --git a/Ahuacatl/ast-dump.c b/Ahuacatl/ast-dump.c index ff9c426c5f..b0333841d4 100644 --- a/Ahuacatl/ast-dump.c +++ b/Ahuacatl/ast-dump.c @@ -36,6 +36,10 @@ /// @addtogroup Ahuacatl /// @{ //////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the "nice" name of an AST node +//////////////////////////////////////////////////////////////////////////////// static char* GetTypeName (const TRI_aql_node_type_e type) { switch (type) { @@ -128,6 +132,10 @@ static char* GetTypeName (const TRI_aql_node_type_e type) { assert(false); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief print some indentation +//////////////////////////////////////////////////////////////////////////////// + static void Indent (TRI_aql_dump_t* const state) { size_t i; @@ -136,20 +144,36 @@ static void Indent (TRI_aql_dump_t* const state) { } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief print the type name of an AST node +//////////////////////////////////////////////////////////////////////////////// + static void PrintType (TRI_aql_dump_t* const state, const TRI_aql_node_type_e type) { Indent(state); printf("%s\n", GetTypeName(type)); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief increase the indent level by one +//////////////////////////////////////////////////////////////////////////////// + static inline void IndentState (TRI_aql_dump_t* const state) { ++state->_indent; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief decrease the indent level by one +//////////////////////////////////////////////////////////////////////////////// + static inline void OutdentState (TRI_aql_dump_t* const state) { assert(state->_indent > 0); --state->_indent; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief dump an AST value node's value +//////////////////////////////////////////////////////////////////////////////// + static void DumpValue (TRI_aql_dump_t* const state, TRI_aql_node_value_t* node) { switch (node->_value._type) { case AQL_TYPE_FAIL: @@ -173,6 +197,10 @@ static void DumpValue (TRI_aql_dump_t* const state, TRI_aql_node_value_t* node) } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief dump an AST node with all subnodes +//////////////////////////////////////////////////////////////////////////////// + static void DumpNode (TRI_aql_dump_t* const state, TRI_aql_node_t* const data) { TRI_aql_node_t* node; diff --git a/Ahuacatl/ast-dump.h b/Ahuacatl/ast-dump.h index be7fb23912..9836bf32d3 100644 --- a/Ahuacatl/ast-dump.h +++ b/Ahuacatl/ast-dump.h @@ -38,11 +38,28 @@ extern "C" { #endif +// ----------------------------------------------------------------------------- +// --SECTION-- public types +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief internal state of dump +//////////////////////////////////////////////////////////////////////////////// + typedef struct TRI_aql_dump_s { int64_t _indent; } TRI_aql_dump_t; +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- diff --git a/Makefile.in b/Makefile.in index e91ae6b31d..3856d29181 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1005,6 +1005,11 @@ SHELL_SERVER = @srcdir@/js/common/tests/shell-document.js \ UNITTESTS_SERVER = $(addprefix --unit-tests ,$(SHELL_SERVER)) +################################################################################ +################################################################################ +SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-queries.js +UNITTESTS_SERVER_AHUACATL = $(addprefix --unit-tests ,$(SHELL_SERVER_AHUACATL)) + ################################################################################ ################################################################################ SHELL_SERVER_INDEX = @srcdir@/js/server/tests/aql-index-primary.js \ @@ -2886,6 +2891,7 @@ unittests: unittests-verbose unittests-brief unittests-brief: \ unittests-boost \ unittests-shell-server \ + unittests-shell-server-ahuacatl \ unittests-http-server \ unittests-shell-client \ unittests-http-server \ @@ -2976,6 +2982,24 @@ unittests-shell-server: @echo +.PHONY: unittests-shell-server-ahuacatl + +unittests-shell-server-ahuacatl: + @echo + @echo "================================================================================" + @echo "|| SHELL SERVER TESTS (AHUACATL) ||" + @echo "================================================================================" + @echo + + @rm -rf "$(VOCDIR)" + @mkdir "$(VOCDIR)" + + $(VALGRIND) @builddir@/avocado "$(VOCDIR)" $(SERVER_OPT) $(UNITTESTS_SERVER_AHUACATL) || test "$(FORCE)" == "1" + + @rm -rf "$(VOCDIR)" + + @echo + .PHONY: unittests-shell-server-index unittests-shell-server-index: diff --git a/Makefile.unittests b/Makefile.unittests index 8466240ead..3514ec5a3d 100644 --- a/Makefile.unittests +++ b/Makefile.unittests @@ -14,6 +14,7 @@ unittests: unittests-verbose unittests-brief unittests-brief: \ unittests-boost \ unittests-shell-server \ + unittests-shell-server-ahuacatl \ unittests-http-server \ unittests-shell-client \ unittests-http-server \ @@ -148,6 +149,32 @@ unittests-shell-server: @echo +################################################################################ +## SHELL SERVER TESTS (AHUACATL) +################################################################################ + +SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-queries.js + +.PHONY: unittests-shell-server-ahuacatl + +UNITTESTS_SERVER_AHUACATL = $(addprefix --unit-tests ,$(SHELL_SERVER_AHUACATL)) + +unittests-shell-server-ahuacatl: + @echo + @echo "================================================================================" + @echo "|| SHELL SERVER TESTS (AHUACATL) ||" + @echo "================================================================================" + @echo + + @rm -rf "$(VOCDIR)" + @mkdir "$(VOCDIR)" + + $(VALGRIND) @builddir@/avocado "$(VOCDIR)" $(SERVER_OPT) $(UNITTESTS_SERVER_AHUACATL) || test "$(FORCE)" == "1" + + @rm -rf "$(VOCDIR)" + + @echo + ################################################################################ ## SHELL SERVER TESTS (INDEX) ################################################################################ diff --git a/js/server/tests/ahuacatl-queries.js b/js/server/tests/ahuacatl-queries.js index fe9b2bbff2..4890f346ae 100644 --- a/js/server/tests/ahuacatl-queries.js +++ b/js/server/tests/ahuacatl-queries.js @@ -551,9 +551,9 @@ function ahuacatlQueryTestSuite () { //////////////////////////////////////////////////////////////////////////////// testRelations1 : function () { - var expected = [ { "name" : "Abigail", "numFriends" : 3 }, { "name" : "Michael", "numFriends" : 2 }, { "name" : "Sophia", "numFriends" : 2 }, { "name" : "Mariah", "numFriends" : 2 } ]; + var expected = [ { "name" : "Abigail", "numFriends" : 3 }, { "name" : "Alexander", "numFriends" : 2 }, { "name" : "Isabella", "numFriends" : 2 }, { "name" : "John", "numFriends" : 2 } ]; - actual = getQueryResults("FOR u in " + users.name() + " FILTER u.active == true LET f = ((FOR r IN " + relations.name() + " FILTER r.from == u.id && r.type == \"friend\" RETURN r)) SORT AHUACATL_LENGTH(f) DESC LIMIT 0,4 FILTER AHUACATL_LENGTH(f) > 0 RETURN { \"name\" : u.name, \"numFriends\" : AHUACATL_LENGTH(f) }", false); + actual = getQueryResults("FOR u in " + users.name() + " FILTER u.active == true LET f = ((FOR r IN " + relations.name() + " FILTER r.from == u.id && r.type == \"friend\" RETURN r)) SORT AHUACATL_LENGTH(f) DESC, u.name LIMIT 0,4 FILTER AHUACATL_LENGTH(f) > 0 RETURN { \"name\" : u.name, \"numFriends\" : AHUACATL_LENGTH(f) }", false); assertEqual(expected, actual); },