1
0
Fork 0
arangodb/QL/javascripter.c

302 lines
10 KiB
C

////////////////////////////////////////////////////////////////////////////////
/// @brief AST to javascript-string conversion 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 "QL/javascripter.h"
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup QL
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief initialize the to-Javascript conversion context
////////////////////////////////////////////////////////////////////////////////
QL_javascript_conversion_t *QLJavascripterInit (void) {
TRI_string_buffer_t *buffer;
QL_javascript_conversion_t *converter;
converter = (QL_javascript_conversion_t *) TRI_Allocate(sizeof(QL_javascript_conversion_t));
if (converter == 0) {
return 0;
}
// init
converter->_buffer = 0;
converter->_prefix = 0;
buffer = (TRI_string_buffer_t *) TRI_Allocate(sizeof(TRI_string_buffer_t));
if (buffer == 0) {
TRI_Free(converter);
return 0;
}
TRI_InitStringBuffer(buffer);
converter->_buffer = buffer;
return converter;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free the to-Javascript conversion text
////////////////////////////////////////////////////////////////////////////////
void QLJavascripterFree (QL_javascript_conversion_t *converter) {
if (converter == 0) {
return;
}
TRI_FreeStringBuffer(converter->_buffer);
TRI_Free(converter->_buffer);
TRI_Free(converter);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Walk a horizontal list of elements and print them
////////////////////////////////////////////////////////////////////////////////
void QLJavascripterWalkList (QL_javascript_conversion_t *converter, QL_ast_node_t *node,
const char separator, size_t counter) {
QL_ast_node_t *next;
if (node == 0) {
return;
}
next = node->_next;
while (next != 0) {
if (counter++ > 0) {
TRI_AppendCharStringBuffer(converter->_buffer, separator);
}
QLJavascripterConvert(converter, next);
next = next->_next;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a javascript string by recursively walking an expression AST
////////////////////////////////////////////////////////////////////////////////
void QLJavascripterConvert (QL_javascript_conversion_t *converter, QL_ast_node_t *node) {
QL_ast_node_t *lhs, *rhs;
size_t outLength;
if (node == 0) {
return;
}
lhs = node->_lhs;
rhs = node->_rhs;
switch (node->_type) {
case QLNodeValueUndefined:
TRI_AppendStringStringBuffer(converter->_buffer, "undefined");
return;
case QLNodeValueNull:
TRI_AppendStringStringBuffer(converter->_buffer, "null");
return;
case QLNodeValueBool:
TRI_AppendStringStringBuffer(converter->_buffer, node->_value._boolValue ? "true" : "false");
return;
case QLNodeValueString:
TRI_AppendCharStringBuffer(converter->_buffer, '\'');
TRI_AppendStringStringBuffer(converter->_buffer,
TRI_EscapeUtf8String(node->_value._stringValue, strlen(node->_value._stringValue), false, &outLength));
TRI_AppendCharStringBuffer(converter->_buffer, '\'');
return;
case QLNodeValueNumberInt:
TRI_AppendInt64StringBuffer(converter->_buffer, node->_value._intValue);
return;
case QLNodeValueNumberDouble:
TRI_AppendDoubleStringBuffer(converter->_buffer, node->_value._doubleValue);
return;
case QLNodeValueNumberDoubleString:
TRI_AppendStringStringBuffer(converter->_buffer, node->_value._stringValue);
return;
case QLNodeValueArray:
TRI_AppendCharStringBuffer(converter->_buffer, '[');
QLJavascripterWalkList(converter, rhs, ',', 0);
TRI_AppendCharStringBuffer(converter->_buffer, ']');
return;
case QLNodeValueDocument:
TRI_AppendCharStringBuffer(converter->_buffer, '{');
QLJavascripterWalkList(converter, rhs, ',', 0);
TRI_AppendCharStringBuffer(converter->_buffer, '}');
return;
case QLNodeValueParameterNumeric:
case QLNodeValueParameterNamed:
// TODO:
return;
case QLNodeValueIdentifier:
TRI_AppendStringStringBuffer(converter->_buffer, node->_value._stringValue);
return;
case QLNodeValueNamedValue:
QLJavascripterConvert(converter, lhs);
TRI_AppendCharStringBuffer(converter->_buffer, ':');
QLJavascripterConvert(converter, rhs);
return;
case QLNodeReferenceCollectionAlias:
if (converter->_prefix == 0) {
TRI_AppendStringStringBuffer(converter->_buffer, "$['");
TRI_AppendStringStringBuffer(converter->_buffer, node->_value._stringValue);
TRI_AppendStringStringBuffer(converter->_buffer, "']");
}
else {
TRI_AppendStringStringBuffer(converter->_buffer, "$['");
TRI_AppendStringStringBuffer(converter->_buffer, converter->_prefix);
TRI_AppendStringStringBuffer(converter->_buffer, "']");
}
return;
case QLNodeUnaryOperatorPlus:
case QLNodeUnaryOperatorMinus:
case QLNodeUnaryOperatorNot:
TRI_AppendStringStringBuffer(converter->_buffer, QLAstNodeGetUnaryOperatorString(node->_type));
QLJavascripterConvert(converter, lhs);
return;
case QLNodeBinaryOperatorAnd:
case QLNodeBinaryOperatorOr:
case QLNodeBinaryOperatorIdentical:
case QLNodeBinaryOperatorUnidentical:
case QLNodeBinaryOperatorEqual:
case QLNodeBinaryOperatorUnequal:
case QLNodeBinaryOperatorLess:
case QLNodeBinaryOperatorGreater:
case QLNodeBinaryOperatorLessEqual:
case QLNodeBinaryOperatorGreaterEqual:
case QLNodeBinaryOperatorAdd:
case QLNodeBinaryOperatorSubtract:
case QLNodeBinaryOperatorMultiply:
case QLNodeBinaryOperatorDivide:
case QLNodeBinaryOperatorModulus:
case QLNodeBinaryOperatorIn:
TRI_AppendCharStringBuffer(converter->_buffer, '(');
QLJavascripterConvert(converter, lhs);
TRI_AppendStringStringBuffer(converter->_buffer, QLAstNodeGetBinaryOperatorString(node->_type));
QLJavascripterConvert(converter, rhs);
TRI_AppendCharStringBuffer(converter->_buffer, ')');
return;
case QLNodeContainerMemberAccess:
QLJavascripterConvert(converter, lhs);
QLJavascripterWalkList(converter, rhs, '.', 1);
return;
case QLNodeContainerTernarySwitch:
QLJavascripterConvert(converter, lhs);
TRI_AppendCharStringBuffer(converter->_buffer, ':');
QLJavascripterConvert(converter, rhs);
return;
case QLNodeControlFunctionCall:
QLJavascripterConvert(converter, lhs);
TRI_AppendCharStringBuffer(converter->_buffer, '(');
QLJavascripterWalkList(converter, rhs, ',', 0);
TRI_AppendCharStringBuffer(converter->_buffer, ')');
return;
case QLNodeControlTernary:
TRI_AppendCharStringBuffer(converter->_buffer, '(');
QLJavascripterConvert(converter, lhs);
TRI_AppendCharStringBuffer(converter->_buffer, '?');
QLJavascripterConvert(converter, rhs);
TRI_AppendCharStringBuffer(converter->_buffer, ')');
return;
default:
return;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a javascript string by recursively walking an order by AST
////////////////////////////////////////////////////////////////////////////////
void QLJavascripterConvertOrder (QL_javascript_conversion_t *converter, QL_ast_node_t *node) {
QL_ast_node_t *lhs, *rhs;
if (node == 0) {
return;
}
lhs = node->_lhs;
TRI_AppendCharStringBuffer(converter->_buffer, '(');
converter->_prefix = "l";
QLJavascripterConvert(converter, lhs);
TRI_AppendCharStringBuffer(converter->_buffer, '>');
converter->_prefix = "r";
QLJavascripterConvert(converter, lhs);
TRI_AppendCharStringBuffer(converter->_buffer, '?');
rhs = node->_rhs;
if (rhs->_value._boolValue) {
TRI_AppendStringStringBuffer(converter->_buffer, "1");
}
else {
TRI_AppendStringStringBuffer(converter->_buffer, "-1");
}
TRI_AppendCharStringBuffer(converter->_buffer, ':');
converter->_prefix = "l";
QLJavascripterConvert(converter, lhs);
TRI_AppendCharStringBuffer(converter->_buffer, '<');
converter->_prefix = "r";
QLJavascripterConvert(converter, lhs);
TRI_AppendCharStringBuffer(converter->_buffer, '?');
if (rhs->_value._boolValue) {
TRI_AppendStringStringBuffer(converter->_buffer, "-1");
}
else {
TRI_AppendStringStringBuffer(converter->_buffer, "1");
}
TRI_AppendCharStringBuffer(converter->_buffer, ':');
if (node->_next) {
QLJavascripterConvertOrder(converter, node->_next);
}
else {
TRI_AppendCharStringBuffer(converter->_buffer, '0');
}
TRI_AppendCharStringBuffer(converter->_buffer, ')');
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End: