From 754216c24421337952e26b1469c8454360bd4bbe Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Thu, 3 May 2012 18:47:48 +0200 Subject: [PATCH] more code generation --- Ahuacatl/ahuacatl-codegen-js.c | 1003 +++++++++++++++++++++++++++++++- Ahuacatl/ahuacatl-codegen-js.h | 44 +- Ahuacatl/ahuacatl-context.c | 6 +- 3 files changed, 1032 insertions(+), 21 deletions(-) diff --git a/Ahuacatl/ahuacatl-codegen-js.c b/Ahuacatl/ahuacatl-codegen-js.c index ac07771972..b8ac23ae67 100644 --- a/Ahuacatl/ahuacatl-codegen-js.c +++ b/Ahuacatl/ahuacatl-codegen-js.c @@ -42,6 +42,975 @@ /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief hash variable +//////////////////////////////////////////////////////////////////////////////// + +static uint64_t HashVariable (TRI_associative_pointer_t* array, + void const* element) { + TRI_aql_codegen_variable_t* variable = (TRI_aql_codegen_variable_t*) element; + + return TRI_FnvHashString(variable->_name); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief comparison function used to determine variable equality +//////////////////////////////////////////////////////////////////////////////// + +static bool EqualVariable (TRI_associative_pointer_t* array, + void const* key, + void const* element) { + TRI_aql_codegen_variable_t* variable = (TRI_aql_codegen_variable_t*) element; + + return TRI_EqualString(key, variable->_name); +} + +static void ProcessNode (TRI_aql_codegen_js_t* const generator, const TRI_aql_node_t* const node); + +static inline TRI_aql_codegen_register_t IncRegister (TRI_aql_codegen_js_t* const generator) { + return ++generator->_registerIndex; +} + +static inline TRI_aql_codegen_register_t IncFunction (TRI_aql_codegen_js_t* const generator) { + return ++generator->_functionIndex; +} + +static inline bool OutputString (TRI_string_buffer_t* const buffer, const char* const value) { + if (!value) { + return false; + } + + return (TRI_AppendStringStringBuffer(buffer, value) == TRI_ERROR_NO_ERROR); +} + +static inline bool OutputChar (TRI_string_buffer_t* const buffer, const char value) { + return (TRI_AppendCharStringBuffer(buffer, value) == TRI_ERROR_NO_ERROR); +} + +static inline bool OutputInt (TRI_string_buffer_t* const buffer, const int64_t value) { + return (TRI_AppendInt64StringBuffer(buffer, value) == TRI_ERROR_NO_ERROR); +} + +static inline TRI_aql_codegen_scope_t* CurrentScope (TRI_aql_codegen_js_t* const generator) { + size_t n = generator->_scopes._length; + + assert(n > 0); + return (TRI_aql_codegen_scope_t*) TRI_AtVectorPointer(&generator->_scopes, n - 1); +} + +static inline void ScopeOutput (TRI_aql_codegen_js_t* const generator, const char* const value) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + + if (!OutputString(scope->_buffer, value)) { + generator->_error = true; + } +} + +static inline void ScopeOutputInt (TRI_aql_codegen_js_t* const generator, const int64_t value) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + + if (!OutputInt(scope->_buffer, value)) { + generator->_error = true; + } +} + +static inline void ScopeOutputQuoted (TRI_aql_codegen_js_t* const generator, const char* const value) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + + if (!OutputChar(scope->_buffer, '\'')) { + generator->_error = true; + } + if (!OutputString(scope->_buffer, value)) { + generator->_error = true; + } + if (!OutputChar(scope->_buffer, '\'')) { + generator->_error = true; + } +} + +static inline void ScopeOutputFunction (TRI_aql_codegen_js_t* const generator, const TRI_aql_codegen_register_t functionIndex) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + + if (!OutputString(scope->_buffer, FUNCTION_PREFIX)) { + generator->_error = true; + } + if (!OutputInt(scope->_buffer, (int64_t) functionIndex)) { + generator->_error = true; + } +} + +static inline void ScopeOutputRegister (TRI_aql_codegen_js_t* const generator, const TRI_aql_codegen_register_t registerIndex) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + + if (!OutputString(scope->_buffer, REGISTER_PREFIX)) { + generator->_error = true; + } + if (!OutputInt(scope->_buffer, (int64_t) registerIndex)) { + generator->_error = true; + } +} + +static void FreeVariable (TRI_aql_codegen_variable_t* const variable) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable->_name); + TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable); +} + +static TRI_aql_codegen_variable_t* CreateVariable (const char* const name, const TRI_aql_codegen_register_t registerIndex) { + TRI_aql_codegen_variable_t* variable; + + variable = (TRI_aql_codegen_variable_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_codegen_variable_t), false); + if (!variable) { + return NULL; + } + + variable->_register = registerIndex; + variable->_name = TRI_DuplicateString(name); + + if (!variable->_name) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, variable); + return NULL; + } + + return variable; +} + +static TRI_aql_codegen_scope_e NextScopeType (TRI_aql_codegen_js_t* const generator, const TRI_aql_codegen_scope_e type) { + TRI_aql_codegen_scope_t* scope; + + if (type == TRI_AQL_SCOPE_MAIN || type == TRI_AQL_SCOPE_LET) { + return type; + } + + scope = CurrentScope(generator); + + if (scope->_type == TRI_AQL_SCOPE_FOR || scope->_type == TRI_AQL_SCOPE_FOR_NESTED) { + return TRI_AQL_SCOPE_FOR_NESTED; + } + + return type; +} + +static void StartScope (TRI_aql_codegen_js_t* const generator, + TRI_string_buffer_t* const buffer, + const TRI_aql_codegen_scope_e const type, + const TRI_aql_codegen_register_t listRegister, + const TRI_aql_codegen_register_t keyRegister, + const TRI_aql_codegen_register_t ownRegister, + const TRI_aql_codegen_register_t resultRegister, + const char* const variableName, + const char* const name) { + 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) { + generator->_error = true; + return; + } + + scope->_buffer = buffer; + scope->_type = NextScopeType(generator, type); + scope->_listRegister = listRegister; + scope->_keyRegister = keyRegister; + scope->_ownRegister = ownRegister; + scope->_resultRegister = resultRegister; + scope->_variableName = variableName; + scope->_prefix = NULL; + scope->_name = name; + + TRI_InitAssociativePointer(&scope->_variables, + TRI_UNKNOWN_MEM_ZONE, + &TRI_HashStringKeyAssociativePointer, + &HashVariable, + &EqualVariable, + NULL); + + TRI_PushBackVectorPointer(&generator->_scopes, (void*) scope); + + ScopeOutput(generator, "\n/* scope start ("); + ScopeOutput(generator, scope->_name); + ScopeOutput(generator, ") */\n"); +} + +static void EndScope (TRI_aql_codegen_js_t* const generator) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + TRI_aql_codegen_register_t i, n; + + ScopeOutput(generator, "\n/* scope end ("); + ScopeOutput(generator, scope->_name); + ScopeOutput(generator, ") */\n"); + + n = generator->_scopes._length; + assert(n > 0); + scope = (TRI_aql_codegen_scope_t*) TRI_RemoveVectorPointer(&generator->_scopes, n - 1); + assert(scope); + + n = scope->_variables._nrAlloc; + for (i = 0; i < n; ++i) { + TRI_aql_codegen_variable_t* variable = (TRI_aql_codegen_variable_t*) scope->_variables._table[i]; + if (variable) { + FreeVariable(variable); + } + } + TRI_DestroyAssociativePointer(&scope->_variables); + + TRI_Free(TRI_UNKNOWN_MEM_ZONE, scope); +} + +static TRI_aql_codegen_register_t CreateSortFunction (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + TRI_aql_node_t* list; + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + TRI_aql_codegen_register_t functionIndex = IncFunction(generator); + size_t i; + size_t n; + + ScopeOutput(generator, "function "); + ScopeOutputFunction(generator, functionIndex); + ScopeOutput(generator, " (l, r) {\n"); + ScopeOutput(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); + + scope->_prefix = "l"; + ScopeOutput(generator, "lhs = "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(element, 0)); + ScopeOutput(generator, ";\n"); + + scope->_prefix = "r"; + ScopeOutput(generator, "rhs = "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(element, 0)); + ScopeOutput(generator, ";\n"); + + scope->_prefix = NULL; + ScopeOutput(generator, "if (AHUACATL_RELATIONAL_LESS(lhs, rhs)) {\n"); + ScopeOutput(generator, TRI_AQL_NODE_BOOL(element) ? "return -1;\n" : "return 1;\n"); + ScopeOutput(generator, "}\n"); + ScopeOutput(generator, "if (AHUACATL_RELATIONAL_GREATER(lhs, rhs)) {\n"); + ScopeOutput(generator, TRI_AQL_NODE_BOOL(element) ? "return 1;\n" : "return -1;\n"); + ScopeOutput(generator, "}\n"); + } + ScopeOutput(generator, "return 0;\n"); + ScopeOutput(generator, "}\n"); + + return functionIndex; +} + +static void InitList (TRI_aql_codegen_js_t* const generator, const TRI_aql_codegen_register_t resultRegister) { + ScopeOutput(generator, "var "); + ScopeOutputRegister(generator, resultRegister); + ScopeOutput(generator, " = [ ];\n"); +} + +static void InitArray (TRI_aql_codegen_js_t* const generator, const TRI_aql_codegen_register_t resultRegister) { + ScopeOutput(generator, "var "); + ScopeOutputRegister(generator, resultRegister); + ScopeOutput(generator, " = { };\n"); +} + +static void EnterSymbol (TRI_aql_codegen_js_t* const generator, const char* const name, const TRI_aql_codegen_register_t registerIndex) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + TRI_aql_codegen_variable_t* variable = CreateVariable(name, registerIndex); + + if (!variable) { + generator->_error = true; + return; + } + + if (TRI_InsertKeyAssociativePointer(&scope->_variables, name, (void*) variable, false)) { + generator->_error = true; + } +} + +static TRI_aql_codegen_register_t LookupSymbol (TRI_aql_codegen_js_t* const generator, const char* const name) { + size_t i = generator->_scopes._length; + + while (i-- > 0) { + TRI_aql_codegen_scope_t* scope = (TRI_aql_codegen_scope_t*) generator->_scopes._buffer[i]; + TRI_aql_codegen_variable_t* variable; + + variable = (TRI_aql_codegen_variable_t*) TRI_LookupByKeyAssociativePointer(&scope->_variables, name); + if (variable) { + return variable->_register; + } + } + + generator->_error = true; + return 0; +} + +static void ScopePropertyCheck (TRI_aql_codegen_js_t* const generator, + const TRI_aql_codegen_register_t listRegister, + const TRI_aql_codegen_register_t keyRegister) { + ScopeOutput(generator, "if (!"); + ScopeOutputRegister(generator, listRegister); + ScopeOutput(generator, ".hasOwnProperty("); + ScopeOutputRegister(generator, keyRegister); + ScopeOutput(generator, ")) {\n"); + ScopeOutput(generator, "continue;\n"); + ScopeOutput(generator, "}\n"); +} + +static void StartFor (TRI_aql_codegen_js_t* const generator, + const TRI_aql_codegen_register_t sourceRegister, + const char* const variableName) { + TRI_aql_codegen_register_t listRegister = IncRegister(generator); + TRI_aql_codegen_register_t keyRegister = IncRegister(generator); + TRI_aql_codegen_register_t ownRegister = IncRegister(generator); + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + + StartScope(generator, &generator->_buffer, TRI_AQL_SCOPE_FOR, listRegister, keyRegister, ownRegister, scope->_resultRegister, variableName, "for"); + if (variableName) { + EnterSymbol(generator, variableName, ownRegister); + } + + ScopeOutput(generator, "var "); + ScopeOutputRegister(generator, listRegister); + ScopeOutput(generator, " = AHUACATL_LIST("); + ScopeOutputRegister(generator, sourceRegister); + ScopeOutput(generator, ");\n"); + + ScopeOutput(generator, "for (var "); + ScopeOutputRegister(generator, keyRegister); + ScopeOutput(generator, " in "); + ScopeOutputRegister(generator, listRegister); + ScopeOutput(generator, ") {\n"); + + ScopePropertyCheck(generator, listRegister, keyRegister); + + // var rx = listx[keyx]; + scope = CurrentScope(generator); + ScopeOutput(generator, "var "); + ScopeOutputRegister(generator, scope->_ownRegister); + ScopeOutput(generator, " = "); + ScopeOutputRegister(generator, scope->_listRegister); + ScopeOutput(generator, "["); + ScopeOutputRegister(generator, scope->_keyRegister); + ScopeOutput(generator, "];\n"); +} + +static void CloseLoops (TRI_aql_codegen_js_t* const generator) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + + while (true) { + TRI_aql_codegen_scope_e type = scope->_type; + ScopeOutput(generator, "}\n"); + EndScope(generator); + + if (type != TRI_AQL_SCOPE_FOR_NESTED) { + break; + } + + scope = CurrentScope(generator); + } +} + +static TRI_vector_string_t StoreSymbols (TRI_aql_codegen_js_t* const generator, + const TRI_aql_codegen_register_t rowRegister) { + TRI_vector_string_t variableNames; + size_t i = generator->_scopes._length; + + TRI_InitVectorString(&variableNames, TRI_UNKNOWN_MEM_ZONE); + + while (i-- > 0) { + TRI_aql_codegen_scope_t* peek = (TRI_aql_codegen_scope_t*) generator->_scopes._buffer[i]; + size_t j, n; + + n = peek->_variables._nrAlloc; + for (j = 0; j < n; ++j) { + TRI_aql_codegen_variable_t* variable = (TRI_aql_codegen_variable_t*) peek->_variables._table[j]; + + if (!variable) { + continue; + } + + // row[name] = ...; + ScopeOutputRegister(generator, rowRegister); + ScopeOutput(generator, "["); + ScopeOutputQuoted(generator, variable->_name); + ScopeOutput(generator, "] = "); + ScopeOutputRegister(generator, variable->_register); + ScopeOutput(generator, ";\n"); + + TRI_PushBackVectorString(&variableNames, TRI_DuplicateString(variable->_name)); + } + + if (peek->_type != TRI_AQL_SCOPE_FOR_NESTED) { + break; + } + } + + return variableNames; +} + +static void RestoreSymbols (TRI_aql_codegen_js_t* const generator, TRI_vector_string_t* const variableNames) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + size_t i, n; + + n = variableNames->_length; + for (i = 0; i < n; ++i) { + TRI_aql_codegen_register_t registerIndex = IncRegister(generator); + char* variableName = (char*) variableNames->_buffer[i]; + + // re-enter symbols + if (variableName) { + EnterSymbol(generator, variableName, registerIndex); + } + + // unpack variables + ScopeOutput(generator, "var "); + ScopeOutputRegister(generator, registerIndex); + ScopeOutput(generator, " = "); + ScopeOutputRegister(generator, scope->_ownRegister); + ScopeOutput(generator, "["); + ScopeOutputQuoted(generator, variableName); + ScopeOutput(generator, "];\n"); + } + + TRI_DestroyVectorString(variableNames); +} + +static void ProcessReference (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + char* name = TRI_AQL_NODE_STRING(node); + + if (scope->_prefix) { + // sort function + ScopeOutput(generator, scope->_prefix); + ScopeOutput(generator, "["); + ScopeOutputQuoted(generator, name); + ScopeOutput(generator, "]"); + } + else { + // regular scope + TRI_aql_codegen_register_t registerIndex = LookupSymbol(generator, name); + ScopeOutputRegister(generator, registerIndex); + } +} + +static void ProcessValue (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + if (!TRI_ValueJavascriptAql(CurrentScope(generator)->_buffer, &node->_value, node->_value._type)) { + generator->_error = true; + } +} + +static void ProcessList (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + size_t i, n; + + ScopeOutput(generator, "[ "); + n = node->_members._length; + for (i = 0; i < n; ++i) { + if (i > 0) { + ScopeOutput(generator, ", "); + } + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, i)); + } + ScopeOutput(generator, " ]"); +} + +static void ProcessArray (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + size_t i, n; + + ScopeOutput(generator, "{ "); + n = node->_members._length; + for (i = 0; i < n; ++i) { + if (i > 0) { + ScopeOutput(generator, ", "); + } + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, i)); + } + ScopeOutput(generator, " }"); +} + +static void ProcessArrayElement (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + TRI_ValueJavascriptAql(CurrentScope(generator)->_buffer, &node->_value, AQL_TYPE_STRING); + ScopeOutput(generator, " : "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); +} + +static void ProcessAttributeAccess (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_DOCUMENT_MEMBER("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ScopeOutputQuoted(generator, TRI_AQL_NODE_STRING(node)); + ScopeOutput(generator, ")"); +} + +static void ProcessIndexed (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_GET_INDEX("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessCollection (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_GET_DOCUMENTS('"); + ScopeOutput(generator, TRI_AQL_NODE_STRING(node)); + ScopeOutput(generator, "')"); +} + +static void ProcessUnaryNot (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_LOGICAL_NOT("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ")"); +} + +static void ProcessUnaryMinus (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_UNARY_MINUS("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ")"); +} + +static void ProcessUnaryPlus (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_UNARY_PLUS("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryAnd (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_LOGICAL_AND("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryOr (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_LOGICAL_OR("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryPlus (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_ARITHMETIC_PLUS("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryMinus (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_ARITHMETIC_MINUS("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryTimes (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_ARITHMETIC_TIMES("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryDivide (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_ARITHMETIC_DIVIDE("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryModulus(TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_ARITHMETIC_MODULUS("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryEqual (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_RELATIONAL_EQUAL("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryUnequal (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_RELATIONAL_UNEQUAL("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryLessEqual (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_RELATIONAL_LESSEQUAL("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryLess (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_RELATIONAL_LESS("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryGreaterEqual (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_RELATIONAL_GREATEREQUAL("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryGreater (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_RELATIONAL_GREATER("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessBinaryIn (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_RELATIONAL_IN("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ")"); +} + +static void ProcessSubquery (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); +} + +static void ProcessFcall (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "AHUACATL_FCALL("); + ScopeOutput(generator, TRI_GetInternalNameFunctionAql((TRI_aql_function_t*) TRI_AQL_NODE_DATA(node))); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ")"); +} + +static void ProcessFor (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + TRI_aql_codegen_register_t sourceRegister = IncRegister(generator); + TRI_aql_node_t* nameNode; + + ScopeOutput(generator, "var "); + ScopeOutputRegister(generator, sourceRegister); + ScopeOutput(generator, " = "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ";\n"); + + nameNode = TRI_AQL_NODE_MEMBER(node, 0); + StartFor(generator, sourceRegister, nameNode->_value._value._string); +} + +static void ProcessSort (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + TRI_aql_codegen_register_t rowRegister = IncRegister(generator); + TRI_aql_codegen_register_t sourceRegister = scope->_resultRegister; + TRI_aql_codegen_register_t resultRegister; + TRI_aql_codegen_register_t functionIndex; + TRI_vector_string_t variableNames; + + // var row = { }; + InitArray(generator, rowRegister); + + variableNames = StoreSymbols(generator, rowRegister); + + // result.push(row) + ScopeOutputRegister(generator, scope->_resultRegister); + ScopeOutput(generator, ".push("); + ScopeOutputRegister(generator, rowRegister); + ScopeOutput(generator, ");\n"); + + // } + CloseLoops(generator); + + functionIndex = CreateSortFunction(generator, node); + + // now apply actual sorting + ScopeOutput(generator, "AHUACATL_SORT("); + ScopeOutputRegister(generator, sourceRegister); + ScopeOutput(generator, ", "); + ScopeOutputFunction(generator, functionIndex); + ScopeOutput(generator, ");\n"); + + // start new for loop + resultRegister = IncRegister(generator); + scope = CurrentScope(generator); + scope->_resultRegister = resultRegister; + InitList(generator, resultRegister); + StartFor(generator, sourceRegister, NULL); + + RestoreSymbols(generator, &variableNames); +} + +static void ProcessLimit (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + TRI_aql_codegen_register_t rowRegister = IncRegister(generator); + TRI_aql_codegen_register_t sourceRegister = scope->_resultRegister; + TRI_aql_codegen_register_t resultRegister; + TRI_aql_codegen_register_t limitRegister; + TRI_vector_string_t variableNames; + + // var row = { }; + InitArray(generator, rowRegister); + + variableNames = StoreSymbols(generator, rowRegister); + + // result.push(row) + ScopeOutputRegister(generator, scope->_resultRegister); + ScopeOutput(generator, ".push("); + ScopeOutputRegister(generator, rowRegister); + ScopeOutput(generator, ");\n"); + + // } + CloseLoops(generator); + + // now apply actual limit + limitRegister = IncRegister(generator); + ScopeOutput(generator, "var "); + ScopeOutputRegister(generator, limitRegister); + ScopeOutput(generator, " = AHUACATL_LIMIT("); + ScopeOutputRegister(generator, sourceRegister); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ", "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + ScopeOutput(generator, ");\n"); + + // start new for loop + resultRegister = IncRegister(generator); + scope = CurrentScope(generator); + scope->_resultRegister = resultRegister; + InitList(generator, resultRegister); + StartFor(generator, limitRegister, NULL); + + RestoreSymbols(generator, &variableNames); +} + +static void ProcessReturn (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + TRI_aql_codegen_scope_t* scope = CurrentScope(generator); + TRI_aql_codegen_register_t rowRegister = IncRegister(generator); + + // var row = ...; + ScopeOutput(generator, "var "); + ScopeOutputRegister(generator, rowRegister); + ScopeOutput(generator, " = "); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ";\n"); + + // result.push(row); + ScopeOutputRegister(generator, scope->_resultRegister); + ScopeOutput(generator, ".push("); + ScopeOutputRegister(generator, rowRegister); + ScopeOutput(generator, ");\n"); + + // } + CloseLoops(generator); +} + +static void ProcessAssign (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(node, 0); + TRI_aql_codegen_register_t resultRegister = IncRegister(generator); + + InitList(generator, resultRegister); + + StartScope(generator, &generator->_buffer, TRI_AQL_SCOPE_LET, 0, 0, 0, resultRegister, NULL, "let"); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); + EndScope(generator); + + EnterSymbol(generator, nameNode->_value._value._string, resultRegister); +} + +static void ProcessFilter (TRI_aql_codegen_js_t* const generator, + const TRI_aql_node_t* const node) { + ScopeOutput(generator, "if (!("); + ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); + ScopeOutput(generator, ")) {\n"); + ScopeOutput(generator, "continue;\n"); + ScopeOutput(generator, "}\n"); +} + +static void ProcessNode (TRI_aql_codegen_js_t* generator, const TRI_aql_node_t* const data) { + TRI_aql_node_t* node = (TRI_aql_node_t*) data; + + if (!node) { + return; + } + + while (node) { + switch (node->_type) { + case AQL_NODE_VALUE: + ProcessValue(generator, node); + break; + case AQL_NODE_LIST: + ProcessList(generator, node); + break; + case AQL_NODE_ARRAY: + ProcessArray(generator, node); + break; + case AQL_NODE_ARRAY_ELEMENT: + ProcessArrayElement(generator, node); + break; + case AQL_NODE_COLLECTION: + ProcessCollection(generator, node); + break; + case AQL_NODE_REFERENCE: + ProcessReference(generator, node); + break; + case AQL_NODE_ATTRIBUTE: +// ProcessAttribute(generator, node); + break; + case AQL_NODE_ATTRIBUTE_ACCESS: + ProcessAttributeAccess(generator, node); + break; + case AQL_NODE_INDEXED: + ProcessIndexed(generator, node); + break; + case AQL_NODE_EXPAND: +// ProcessExpand(generator, node); + break; + case AQL_NODE_OPERATOR_UNARY_NOT: + ProcessUnaryNot(generator, node); + break; + case AQL_NODE_OPERATOR_UNARY_PLUS: + ProcessUnaryPlus(generator, node); + break; + case AQL_NODE_OPERATOR_UNARY_MINUS: + ProcessUnaryMinus(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_AND: + ProcessBinaryAnd(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_OR: + ProcessBinaryOr(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_PLUS: + ProcessBinaryPlus(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_MINUS: + ProcessBinaryMinus(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_TIMES: + ProcessBinaryTimes(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_DIV: + ProcessBinaryDivide(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_MOD: + ProcessBinaryModulus(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_EQ: + ProcessBinaryEqual(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_NE: + ProcessBinaryUnequal(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_LT: + ProcessBinaryLess(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_LE: + ProcessBinaryLessEqual(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_GT: + ProcessBinaryGreater(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_GE: + ProcessBinaryGreaterEqual(generator, node); + break; + case AQL_NODE_OPERATOR_BINARY_IN: + ProcessBinaryIn(generator, node); + break; + case AQL_NODE_FCALL: + ProcessFcall(generator, node); + break; + case AQL_NODE_FOR: + ProcessFor(generator, node); + break; + case AQL_NODE_COLLECT: +// ProcessCollect(generator, node); + break; + case AQL_NODE_ASSIGN: + ProcessAssign(generator, node); + break; + case AQL_NODE_FILTER: + ProcessFilter(generator, node); + break; + case AQL_NODE_LIMIT: + ProcessLimit(generator, node); + break; + case AQL_NODE_SORT: + ProcessSort(generator, node); + break; + case AQL_NODE_RETURN: + ProcessReturn(generator, node); + break; + case AQL_NODE_SUBQUERY: + ProcessSubquery(generator, node); + break; + default: { + } + } + + node = node->_next; + } +} + + +void fux (TRI_aql_codegen_js_t* generator, const void* const data) { + TRI_aql_codegen_register_t resultRegister; + + resultRegister = IncRegister(generator); + StartScope(generator, &generator->_buffer, TRI_AQL_SCOPE_MAIN, 0, 0, 0, resultRegister, NULL, "main"); + InitList(generator, resultRegister); + + ProcessNode(generator, (TRI_aql_node_t*) data); + + EndScope(generator); +} + + + + + + //////////////////////////////////////////////////////////////////////////////// /// @brief append the value of a value node to the current scope's output buffer //////////////////////////////////////////////////////////////////////////////// @@ -49,13 +1018,13 @@ static void DumpNode (TRI_aql_codegen_js_t* const generator, const TRI_aql_node_t* const node); static TRI_string_buffer_t* GetBuffer (TRI_aql_codegen_js_t* const generator) { - TRI_aql_codegen_function_t* function; + TRI_aql_codegen_functionx_t* function; size_t n; n = generator->_functions._length; assert(n > 0); - function = (TRI_aql_codegen_function_t*) generator->_functions._buffer[n - 1]; + function = (TRI_aql_codegen_functionx_t*) generator->_functions._buffer[n - 1]; assert(function); return &function->_buffer; @@ -69,10 +1038,10 @@ static size_t NextFunction (TRI_aql_codegen_js_t* const generator) { return ++generator->_functionIndex; } -static TRI_aql_codegen_function_t* CreateFunction (TRI_aql_codegen_js_t* const generator) { - TRI_aql_codegen_function_t* function; +static TRI_aql_codegen_functionx_t* CreateFunction (TRI_aql_codegen_js_t* const generator) { + TRI_aql_codegen_functionx_t* function; - function = (TRI_aql_codegen_function_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_codegen_function_t), false); + function = (TRI_aql_codegen_functionx_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_codegen_functionx_t), false); if (!function) { generator->_error = true; return NULL; @@ -87,7 +1056,7 @@ static TRI_aql_codegen_function_t* CreateFunction (TRI_aql_codegen_js_t* const g return function; } -static void FreeFunction (TRI_aql_codegen_function_t* const function) { +static void FreeFunction (TRI_aql_codegen_functionx_t* const function) { assert(function); TRI_DestroyStringBuffer(&function->_buffer); @@ -159,7 +1128,7 @@ static void AppendOwnPropertyCheck (TRI_aql_codegen_js_t* const generator, static void StartFunction (TRI_aql_codegen_js_t* const generator, const TRI_aql_codegen_function_type_e type) { - TRI_aql_codegen_function_t* function = CreateFunction(generator); + TRI_aql_codegen_functionx_t* function = CreateFunction(generator); if (!function) { generator->_error = true; @@ -179,7 +1148,7 @@ static void StartFunction (TRI_aql_codegen_js_t* const generator, } static size_t EndFunction (TRI_aql_codegen_js_t* const generator) { - TRI_aql_codegen_function_t* function; + TRI_aql_codegen_functionx_t* function; size_t n; size_t funcIndex; @@ -198,21 +1167,21 @@ static size_t EndFunction (TRI_aql_codegen_js_t* const generator) { return funcIndex; } -static TRI_aql_codegen_function_t* CurrentFunction (TRI_aql_codegen_js_t* const generator) { - TRI_aql_codegen_function_t* function; +static TRI_aql_codegen_functionx_t* CurrentFunction (TRI_aql_codegen_js_t* const generator) { + TRI_aql_codegen_functionx_t* function; size_t n; n = generator->_functions._length; assert(n > 0); - function = (TRI_aql_codegen_function_t*) generator->_functions._buffer[n - 1]; + function = (TRI_aql_codegen_functionx_t*) generator->_functions._buffer[n - 1]; assert(function); return function; } static void IncreaseForCount (TRI_aql_codegen_js_t* const generator) { - TRI_aql_codegen_function_t* function = CurrentFunction(generator); + TRI_aql_codegen_functionx_t* function = CurrentFunction(generator); if (!function) { return; @@ -222,7 +1191,7 @@ static void IncreaseForCount (TRI_aql_codegen_js_t* const generator) { } static void CloseForLoops (TRI_aql_codegen_js_t* const generator) { - TRI_aql_codegen_function_t* function = CurrentFunction(generator); + TRI_aql_codegen_functionx_t* function = CurrentFunction(generator); size_t i; if (!function) { @@ -252,7 +1221,7 @@ static size_t HandleSortNode (TRI_aql_codegen_js_t* const generator, const TRI_aql_node_t* const node, const size_t idx) { TRI_aql_node_t* list; - TRI_aql_codegen_function_t* function; + TRI_aql_codegen_functionx_t* function; size_t funcIndex; size_t i; size_t n; @@ -345,7 +1314,7 @@ static void HandleCollection (TRI_aql_codegen_js_t* const generator, static void HandleReference (TRI_aql_codegen_js_t* const generator, const TRI_aql_node_t* const node) { - TRI_aql_codegen_function_t* function; + TRI_aql_codegen_functionx_t* function; function = CurrentFunction(generator); if (function && function->_prefix) { @@ -915,6 +1884,7 @@ static void DumpNode (TRI_aql_codegen_js_t* generator, const TRI_aql_node_t* con void TRI_FreeGeneratorAql (TRI_aql_codegen_js_t* const generator) { TRI_DestroyVectorPointer(&generator->_functions); + TRI_DestroyVectorPointer(&generator->_scopes); TRI_DestroyStringBuffer(&generator->_buffer); TRI_Free(TRI_UNKNOWN_MEM_ZONE, generator); } @@ -933,6 +1903,7 @@ TRI_aql_codegen_js_t* TRI_CreateGeneratorAql (void) { TRI_InitStringBuffer(&generator->_buffer, TRI_UNKNOWN_MEM_ZONE); TRI_InitVectorPointer(&generator->_functions, TRI_UNKNOWN_MEM_ZONE); + TRI_InitVectorPointer(&generator->_scopes, TRI_UNKNOWN_MEM_ZONE); generator->_error = false; generator->_registerIndex = 0; generator->_functionIndex = 0; @@ -966,6 +1937,8 @@ TRI_aql_codegen_js_t* TRI_GenerateCodeAql (const void* const data) { return NULL; } +// fux(generator, data); + StartFunction(generator, AQL_FUNCTION_STANDALONE); AppendString(generator, "var result = [];\n"); DumpNode(generator, (TRI_aql_node_t*) data); diff --git a/Ahuacatl/ahuacatl-codegen-js.h b/Ahuacatl/ahuacatl-codegen-js.h index f34a50e4b0..cc8a62a14f 100644 --- a/Ahuacatl/ahuacatl-codegen-js.h +++ b/Ahuacatl/ahuacatl-codegen-js.h @@ -29,10 +29,11 @@ #define TRIAGENS_DURHAM_AHUACATL_CODEGEN_JS_H 1 #include +#include +#include #include #include #include -#include #include "Ahuacatl/ahuacatl-ast-node.h" #include "Ahuacatl/ahuacatl-conversions.h" @@ -54,6 +55,8 @@ extern "C" { /// @brief internal function types //////////////////////////////////////////////////////////////////////////////// +typedef uint32_t TRI_aql_codegen_register_t; + typedef enum { AQL_FUNCTION_STANDALONE, AQL_FUNCTION_COMPARE @@ -64,14 +67,47 @@ TRI_aql_codegen_function_type_e; /// @brief code generator internal function struct //////////////////////////////////////////////////////////////////////////////// -typedef struct TRI_aql_codegen_function_s { +typedef struct TRI_aql_codegen_functionx_s { TRI_string_buffer_t _buffer; size_t _index; size_t _forCount; char* _prefix; } +TRI_aql_codegen_functionx_t; -TRI_aql_codegen_function_t; + +typedef enum { + TRI_AQL_SCOPE_MAIN, + TRI_AQL_SCOPE_LET, + TRI_AQL_SCOPE_FOR, + TRI_AQL_SCOPE_FOR_NESTED, + TRI_AQL_SCOPE_FUNCTION +} +TRI_aql_codegen_scope_e; + +typedef struct TRI_aql_codegen_variable_s { + char* _name; + TRI_aql_codegen_register_t _register; +} +TRI_aql_codegen_variable_t; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief code generator scope +//////////////////////////////////////////////////////////////////////////////// + +typedef struct TRI_aql_codegen_scope_s { + TRI_string_buffer_t* _buffer; + TRI_aql_codegen_scope_e _type; + TRI_aql_codegen_register_t _listRegister; + TRI_aql_codegen_register_t _keyRegister; + TRI_aql_codegen_register_t _ownRegister; + TRI_aql_codegen_register_t _resultRegister; + TRI_associative_pointer_t _variables; + const char* _variableName; + const char* _name; + char* _prefix; +} +TRI_aql_codegen_scope_t; //////////////////////////////////////////////////////////////////////////////// /// @brief code generator struct @@ -80,6 +116,8 @@ TRI_aql_codegen_function_t; typedef struct TRI_aql_codegen_js_s { TRI_string_buffer_t _buffer; TRI_vector_pointer_t _functions; + TRI_vector_pointer_t _scopes; + size_t _registerIndex; size_t _functionIndex; bool _error; diff --git a/Ahuacatl/ahuacatl-context.c b/Ahuacatl/ahuacatl-context.c index 75b46327fa..471685d90b 100644 --- a/Ahuacatl/ahuacatl-context.c +++ b/Ahuacatl/ahuacatl-context.c @@ -329,9 +329,9 @@ TRI_aql_scope_t* TRI_CreateScopeAql (void) { TRI_InitAssociativePointer(&scope->_variables, TRI_UNKNOWN_MEM_ZONE, - TRI_HashStringKeyAssociativePointer, - TRI_HashVariableAql, - TRI_EqualVariableAql, + &TRI_HashStringKeyAssociativePointer, + &TRI_HashVariableAql, + &TRI_EqualVariableAql, 0); scope->_first = NULL;