mirror of https://gitee.com/bigwinds/arangodb
fixed tests
This commit is contained in:
parent
e5de733eb3
commit
6895ba9e27
|
@ -76,6 +76,7 @@ namespace triagens {
|
|||
|
||||
template<typename T>
|
||||
bool IsUnsafeDivision (T l, T r) {
|
||||
// note: the caller still has to check whether r is zero (division by zero)
|
||||
return (l == (std::numeric_limits<T>::min)() && r == -1);
|
||||
}
|
||||
|
||||
|
|
|
@ -1335,7 +1335,31 @@ AstNode* Ast::optimizeBinaryOperatorArithmetic (AstNode* node) {
|
|||
if (lhs->isConstant() && rhs->isConstant()) {
|
||||
// now calculate the expression result
|
||||
if (node->type == NODE_TYPE_OPERATOR_BINARY_PLUS) {
|
||||
// TODO: add string concatenation
|
||||
if (lhs->isStringValue() || lhs->isList() || lhs->isArray() ||
|
||||
rhs->isStringValue() || rhs->isList() || rhs->isArray()) {
|
||||
// + means string concatenation if one of the operands is a string, a list or an array
|
||||
auto left = lhs->castToString(this);
|
||||
auto right = rhs->castToString(this);
|
||||
|
||||
TRI_ASSERT(left->type == NODE_TYPE_VALUE && left->value.type == VALUE_TYPE_STRING);
|
||||
TRI_ASSERT(right->type == NODE_TYPE_VALUE && right->value.type == VALUE_TYPE_STRING);
|
||||
|
||||
if (*left->value.value._string == '\0') {
|
||||
// left side is empty
|
||||
return right;
|
||||
}
|
||||
else if (*right->value.value._string == '\0') {
|
||||
// right side is empty
|
||||
return left;
|
||||
}
|
||||
|
||||
// must concat
|
||||
char* concatenated = _query->registerStringConcat(left->value.value._string, right->value.value._string);
|
||||
TRI_ASSERT(concatenated != nullptr);
|
||||
return createNodeValueString(concatenated);
|
||||
}
|
||||
|
||||
// arithmetic +
|
||||
auto left = lhs->castToNumber(this);
|
||||
auto right = rhs->castToNumber(this);
|
||||
|
||||
|
|
|
@ -655,8 +655,6 @@ AstNode* AstNode::castToNumber (Ast* ast) {
|
|||
// conversion failed
|
||||
}
|
||||
// fall-through intentional
|
||||
default: {
|
||||
}
|
||||
}
|
||||
// fall-through intentional
|
||||
}
|
||||
|
@ -680,6 +678,31 @@ AstNode* AstNode::castToNumber (Ast* ast) {
|
|||
return ast->createNodeValueNull();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief convert the node's value to a string value
|
||||
/// this may create a new node or return the node itself if it is already a
|
||||
/// string value node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* AstNode::castToString (Ast* ast) {
|
||||
TRI_ASSERT(type == NODE_TYPE_VALUE ||
|
||||
type == NODE_TYPE_LIST ||
|
||||
type == NODE_TYPE_ARRAY);
|
||||
|
||||
if (type == NODE_TYPE_VALUE && value.type == VALUE_TYPE_STRING) {
|
||||
// already a string
|
||||
return this;
|
||||
}
|
||||
|
||||
// stringify node
|
||||
triagens::basics::StringBuffer buffer(TRI_UNKNOWN_MEM_ZONE);
|
||||
append(&buffer, false);
|
||||
|
||||
char const* value = ast->query()->registerString(buffer.c_str(), buffer.length(), false);
|
||||
TRI_ASSERT(value != nullptr);
|
||||
return ast->createNodeValueString(value);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a JSON representation of the node to the JSON list specified
|
||||
/// in the first argument
|
||||
|
@ -1067,53 +1090,65 @@ AstNode* AstNode::clone (Ast* ast) const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief append a string representation of the node into a string buffer
|
||||
/// @brief append a string representation of the node to a string buffer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AstNode::append (triagens::basics::StringBuffer* buffer) const {
|
||||
void AstNode::append (triagens::basics::StringBuffer* buffer,
|
||||
bool verbose) const {
|
||||
if (type == NODE_TYPE_VALUE) {
|
||||
appendValue(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == NODE_TYPE_LIST) {
|
||||
buffer->appendText("[ ");
|
||||
size_t const n = numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
buffer->appendText(", ");
|
||||
if (verbose || n > 0) {
|
||||
if (verbose || n > 1) {
|
||||
buffer->appendChar('[');
|
||||
}
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
buffer->appendChar(',');
|
||||
}
|
||||
|
||||
AstNode* member = getMember(i);
|
||||
if (member != nullptr) {
|
||||
member->append(buffer);
|
||||
AstNode* member = getMember(i);
|
||||
if (member != nullptr) {
|
||||
member->append(buffer, verbose);
|
||||
}
|
||||
}
|
||||
if (verbose || n > 1) {
|
||||
buffer->appendChar(']');
|
||||
}
|
||||
}
|
||||
buffer->appendText(" ]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == NODE_TYPE_ARRAY) {
|
||||
buffer->appendText("{ ");
|
||||
size_t const n = numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
buffer->appendText(", ");
|
||||
}
|
||||
|
||||
AstNode* member = getMember(i);
|
||||
if (member != nullptr) {
|
||||
TRI_ASSERT(member->type == NODE_TYPE_ARRAY_ELEMENT);
|
||||
TRI_ASSERT(member->numMembers() == 1);
|
||||
|
||||
buffer->appendChar('"');
|
||||
buffer->appendJsonEncoded(member->getStringValue());
|
||||
buffer->appendText("\" : ");
|
||||
|
||||
member->getMember(0)->append(buffer);
|
||||
if (verbose) {
|
||||
buffer->appendChar('{');
|
||||
size_t const n = numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (i > 0) {
|
||||
buffer->appendChar(',');
|
||||
}
|
||||
|
||||
AstNode* member = getMember(i);
|
||||
if (member != nullptr) {
|
||||
TRI_ASSERT(member->type == NODE_TYPE_ARRAY_ELEMENT);
|
||||
TRI_ASSERT(member->numMembers() == 1);
|
||||
|
||||
buffer->appendChar('"');
|
||||
buffer->appendJsonEncoded(member->getStringValue());
|
||||
buffer->appendText("\":", 2);
|
||||
|
||||
member->getMember(0)->append(buffer, verbose);
|
||||
}
|
||||
}
|
||||
buffer->appendChar('}');
|
||||
}
|
||||
else {
|
||||
buffer->appendText("[object Object]");
|
||||
}
|
||||
buffer->appendText(" }");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1132,9 +1167,9 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
|
|||
// not used by V8
|
||||
auto member = getMember(0);
|
||||
auto index = getMember(1);
|
||||
member->append(buffer);
|
||||
member->append(buffer, verbose);
|
||||
buffer->appendChar('[');
|
||||
index->append(buffer);
|
||||
index->append(buffer, verbose);
|
||||
buffer->appendChar(']');
|
||||
return;
|
||||
}
|
||||
|
@ -1142,7 +1177,7 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
|
|||
if (type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
// not used by V8
|
||||
auto member = getMember(0);
|
||||
member->append(buffer);
|
||||
member->append(buffer, verbose);
|
||||
buffer->appendChar('.');
|
||||
buffer->appendText(getStringValue());
|
||||
return;
|
||||
|
@ -1152,7 +1187,7 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
|
|||
auto func = static_cast<Function*>(getData());
|
||||
buffer->appendText(func->externalName);
|
||||
buffer->appendChar('(');
|
||||
getMember(0)->append(buffer);
|
||||
getMember(0)->append(buffer, verbose);
|
||||
buffer->appendChar(')');
|
||||
return;
|
||||
}
|
||||
|
@ -1166,7 +1201,7 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
|
|||
buffer->appendChar(' ');
|
||||
buffer->appendText((*it).second);
|
||||
|
||||
getMember(0)->append(buffer);
|
||||
getMember(0)->append(buffer, verbose);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1189,11 +1224,11 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
|
|||
auto it = Operators.find(type);
|
||||
TRI_ASSERT(it != Operators.end());
|
||||
|
||||
getMember(0)->append(buffer);
|
||||
getMember(0)->append(buffer, verbose);
|
||||
buffer->appendChar(' ');
|
||||
buffer->appendText((*it).second);
|
||||
buffer->appendChar(' ');
|
||||
getMember(1)->append(buffer);
|
||||
getMember(1)->append(buffer, verbose);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -259,6 +259,14 @@ namespace triagens {
|
|||
|
||||
AstNode* castToNumber (Ast*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief convert the node's value to a string value
|
||||
/// this may create a new node or return the node itself if it is already a
|
||||
/// string value node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNode* castToString (Ast*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the node value is trueish
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -320,6 +328,22 @@ namespace triagens {
|
|||
return (type == NODE_TYPE_VALUE && value.type == VALUE_TYPE_STRING);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a value node is of list type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool isList () const {
|
||||
return (type == NODE_TYPE_LIST);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a value node is of array type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool isArray () const {
|
||||
return (type == NODE_TYPE_ARRAY);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a node is simple enough to be used in a simple
|
||||
/// expression
|
||||
|
@ -535,7 +559,8 @@ namespace triagens {
|
|||
/// @brief append a JavaScript representation of the node into a string buffer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void append (triagens::basics::StringBuffer*) const;
|
||||
void append (triagens::basics::StringBuffer*,
|
||||
bool) const;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
|
|
|
@ -784,7 +784,7 @@ void Executor::generateCodeNode (AstNode const* node) {
|
|||
|
||||
switch (node->type) {
|
||||
case NODE_TYPE_VALUE:
|
||||
node->append(_buffer);
|
||||
node->append(_buffer, true);
|
||||
break;
|
||||
|
||||
case NODE_TYPE_LIST:
|
||||
|
|
|
@ -622,7 +622,7 @@ std::pair<std::string, std::string> Expression::getMultipleAttributes() {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Expression::stringify (triagens::basics::StringBuffer* buffer) const {
|
||||
_node->append(buffer);
|
||||
_node->append(buffer, true);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -678,6 +678,29 @@ Executor* Query::executor () {
|
|||
return _executor;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register the concatenation of two strings
|
||||
/// the string is freed when the query is destroyed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* Query::registerStringConcat (char const* a,
|
||||
char const* b) {
|
||||
char* concatenated = TRI_Concatenate2StringZ(TRI_UNKNOWN_MEM_ZONE, a, b);
|
||||
|
||||
if (concatenated == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
try {
|
||||
_strings.push_back(concatenated);
|
||||
}
|
||||
catch (...) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
return concatenated;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a string
|
||||
/// the string is freed when the query is destroyed
|
||||
|
|
|
@ -299,6 +299,14 @@ namespace triagens {
|
|||
|
||||
Executor* executor ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register the concatenation of two strings
|
||||
/// the string is freed when the query is destroyed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* registerStringConcat (char const*,
|
||||
char const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a string
|
||||
/// the string is freed when the query is destroyed
|
||||
|
|
|
@ -268,25 +268,25 @@ function ahuacatlArithmeticTestSuite () {
|
|||
assertEqual([ 1 ], getQueryResults("RETURN 1 + null"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN 1 + false"));
|
||||
assertEqual([ 2 ], getQueryResults("RETURN 1 + true"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN 1 + \"0\""));
|
||||
assertEqual([ 43 ], getQueryResults("RETURN 1 + \"42\""));
|
||||
assertEqual([ -16 ], getQueryResults("RETURN 1 + \"-17\""));
|
||||
assertEqual([ "10" ], getQueryResults("RETURN 1 + \"0\""));
|
||||
assertEqual([ "142" ], getQueryResults("RETURN 1 + \"42\""));
|
||||
assertEqual([ "1-17" ], getQueryResults("RETURN 1 + \"-17\""));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN 1 + [ ]"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN 1 + [ 0 ]"));
|
||||
assertEqual([ 5 ], getQueryResults("RETURN 1 + [ 4 ]"));
|
||||
assertEqual([ -3 ], getQueryResults("RETURN 1 + [ -4 ]"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN 1 + { }"));
|
||||
assertEqual([ "10" ], getQueryResults("RETURN 1 + [ 0 ]"));
|
||||
assertEqual([ "14" ], getQueryResults("RETURN 1 + [ 4 ]"));
|
||||
assertEqual([ "1-4" ], getQueryResults("RETURN 1 + [ -4 ]"));
|
||||
assertEqual([ "1[object Object]" ], getQueryResults("RETURN 1 + { }"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN null + 1"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN false + 1"));
|
||||
assertEqual([ 2 ], getQueryResults("RETURN true + 1"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN \"0\" + 1"));
|
||||
assertEqual([ 24 ], getQueryResults("RETURN \"23\" + 1"));
|
||||
assertEqual([ -8 ], getQueryResults("RETURN \"-9\" + 1"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN [ ] + 1"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN [ 0 ] + 1"));
|
||||
assertEqual([ 5 ], getQueryResults("RETURN [ 4 ] + 1"));
|
||||
assertEqual([ -3 ], getQueryResults("RETURN [ -4 ] + 1"));
|
||||
assertEqual([ 1 ], getQueryResults("RETURN { } + 1"));
|
||||
assertEqual([ "01" ], getQueryResults("RETURN \"0\" + 1"));
|
||||
assertEqual([ "231" ], getQueryResults("RETURN \"23\" + 1"));
|
||||
assertEqual([ "-91" ], getQueryResults("RETURN \"-9\" + 1"));
|
||||
assertEqual([ "1" ], getQueryResults("RETURN [ ] + 1"));
|
||||
assertEqual([ "01" ], getQueryResults("RETURN [ 0 ] + 1"));
|
||||
assertEqual([ "41" ], getQueryResults("RETURN [ 4 ] + 1"));
|
||||
assertEqual([ "-41" ], getQueryResults("RETURN [ -4 ] + 1"));
|
||||
assertEqual([ "[object Object]1" ], getQueryResults("RETURN { } + 1"));
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue