1
0
Fork 0

fixed tests

This commit is contained in:
Jan Steemann 2014-10-14 13:20:10 +02:00
parent e5de733eb3
commit 6895ba9e27
9 changed files with 172 additions and 56 deletions

View File

@ -76,6 +76,7 @@ namespace triagens {
template<typename T> template<typename T>
bool IsUnsafeDivision (T l, T r) { 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); return (l == (std::numeric_limits<T>::min)() && r == -1);
} }

View File

@ -1335,7 +1335,31 @@ AstNode* Ast::optimizeBinaryOperatorArithmetic (AstNode* node) {
if (lhs->isConstant() && rhs->isConstant()) { if (lhs->isConstant() && rhs->isConstant()) {
// now calculate the expression result // now calculate the expression result
if (node->type == NODE_TYPE_OPERATOR_BINARY_PLUS) { 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 left = lhs->castToNumber(this);
auto right = rhs->castToNumber(this); auto right = rhs->castToNumber(this);

View File

@ -655,8 +655,6 @@ AstNode* AstNode::castToNumber (Ast* ast) {
// conversion failed // conversion failed
} }
// fall-through intentional // fall-through intentional
default: {
}
} }
// fall-through intentional // fall-through intentional
} }
@ -680,6 +678,31 @@ AstNode* AstNode::castToNumber (Ast* ast) {
return ast->createNodeValueNull(); 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 /// @brief adds a JSON representation of the node to the JSON list specified
/// in the first argument /// in the first argument
@ -1067,38 +1090,46 @@ 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) { if (type == NODE_TYPE_VALUE) {
appendValue(buffer); appendValue(buffer);
return; return;
} }
if (type == NODE_TYPE_LIST) { if (type == NODE_TYPE_LIST) {
buffer->appendText("[ ");
size_t const n = numMembers(); size_t const n = numMembers();
if (verbose || n > 0) {
if (verbose || n > 1) {
buffer->appendChar('[');
}
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
if (i > 0) { if (i > 0) {
buffer->appendText(", "); buffer->appendChar(',');
} }
AstNode* member = getMember(i); AstNode* member = getMember(i);
if (member != nullptr) { if (member != nullptr) {
member->append(buffer); member->append(buffer, verbose);
}
}
if (verbose || n > 1) {
buffer->appendChar(']');
} }
} }
buffer->appendText(" ]");
return; return;
} }
if (type == NODE_TYPE_ARRAY) { if (type == NODE_TYPE_ARRAY) {
buffer->appendText("{ "); if (verbose) {
buffer->appendChar('{');
size_t const n = numMembers(); size_t const n = numMembers();
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
if (i > 0) { if (i > 0) {
buffer->appendText(", "); buffer->appendChar(',');
} }
AstNode* member = getMember(i); AstNode* member = getMember(i);
@ -1108,12 +1139,16 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
buffer->appendChar('"'); buffer->appendChar('"');
buffer->appendJsonEncoded(member->getStringValue()); buffer->appendJsonEncoded(member->getStringValue());
buffer->appendText("\" : "); buffer->appendText("\":", 2);
member->getMember(0)->append(buffer); member->getMember(0)->append(buffer, verbose);
} }
} }
buffer->appendText(" }"); buffer->appendChar('}');
}
else {
buffer->appendText("[object Object]");
}
return; return;
} }
@ -1132,9 +1167,9 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
// not used by V8 // not used by V8
auto member = getMember(0); auto member = getMember(0);
auto index = getMember(1); auto index = getMember(1);
member->append(buffer); member->append(buffer, verbose);
buffer->appendChar('['); buffer->appendChar('[');
index->append(buffer); index->append(buffer, verbose);
buffer->appendChar(']'); buffer->appendChar(']');
return; return;
} }
@ -1142,7 +1177,7 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
if (type == NODE_TYPE_ATTRIBUTE_ACCESS) { if (type == NODE_TYPE_ATTRIBUTE_ACCESS) {
// not used by V8 // not used by V8
auto member = getMember(0); auto member = getMember(0);
member->append(buffer); member->append(buffer, verbose);
buffer->appendChar('.'); buffer->appendChar('.');
buffer->appendText(getStringValue()); buffer->appendText(getStringValue());
return; return;
@ -1152,7 +1187,7 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
auto func = static_cast<Function*>(getData()); auto func = static_cast<Function*>(getData());
buffer->appendText(func->externalName); buffer->appendText(func->externalName);
buffer->appendChar('('); buffer->appendChar('(');
getMember(0)->append(buffer); getMember(0)->append(buffer, verbose);
buffer->appendChar(')'); buffer->appendChar(')');
return; return;
} }
@ -1166,7 +1201,7 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
buffer->appendChar(' '); buffer->appendChar(' ');
buffer->appendText((*it).second); buffer->appendText((*it).second);
getMember(0)->append(buffer); getMember(0)->append(buffer, verbose);
return; return;
} }
@ -1189,11 +1224,11 @@ void AstNode::append (triagens::basics::StringBuffer* buffer) const {
auto it = Operators.find(type); auto it = Operators.find(type);
TRI_ASSERT(it != Operators.end()); TRI_ASSERT(it != Operators.end());
getMember(0)->append(buffer); getMember(0)->append(buffer, verbose);
buffer->appendChar(' '); buffer->appendChar(' ');
buffer->appendText((*it).second); buffer->appendText((*it).second);
buffer->appendChar(' '); buffer->appendChar(' ');
getMember(1)->append(buffer); getMember(1)->append(buffer, verbose);
return; return;
} }

View File

@ -259,6 +259,14 @@ namespace triagens {
AstNode* castToNumber (Ast*); 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 /// @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); 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 /// @brief whether or not a node is simple enough to be used in a simple
/// expression /// expression
@ -535,7 +559,8 @@ namespace triagens {
/// @brief append a JavaScript representation of the node into a string buffer /// @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 // --SECTION-- private methods

View File

@ -784,7 +784,7 @@ void Executor::generateCodeNode (AstNode const* node) {
switch (node->type) { switch (node->type) {
case NODE_TYPE_VALUE: case NODE_TYPE_VALUE:
node->append(_buffer); node->append(_buffer, true);
break; break;
case NODE_TYPE_LIST: case NODE_TYPE_LIST:

View File

@ -622,7 +622,7 @@ std::pair<std::string, std::string> Expression::getMultipleAttributes() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Expression::stringify (triagens::basics::StringBuffer* buffer) const { void Expression::stringify (triagens::basics::StringBuffer* buffer) const {
_node->append(buffer); _node->append(buffer, true);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -678,6 +678,29 @@ Executor* Query::executor () {
return _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 /// @brief register a string
/// the string is freed when the query is destroyed /// the string is freed when the query is destroyed

View File

@ -299,6 +299,14 @@ namespace triagens {
Executor* executor (); 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 /// @brief register a string
/// the string is freed when the query is destroyed /// the string is freed when the query is destroyed

View File

@ -268,25 +268,25 @@ function ahuacatlArithmeticTestSuite () {
assertEqual([ 1 ], getQueryResults("RETURN 1 + null")); assertEqual([ 1 ], getQueryResults("RETURN 1 + null"));
assertEqual([ 1 ], getQueryResults("RETURN 1 + false")); assertEqual([ 1 ], getQueryResults("RETURN 1 + false"));
assertEqual([ 2 ], getQueryResults("RETURN 1 + true")); assertEqual([ 2 ], getQueryResults("RETURN 1 + true"));
assertEqual([ 1 ], getQueryResults("RETURN 1 + \"0\"")); assertEqual([ "10" ], getQueryResults("RETURN 1 + \"0\""));
assertEqual([ 43 ], getQueryResults("RETURN 1 + \"42\"")); assertEqual([ "142" ], getQueryResults("RETURN 1 + \"42\""));
assertEqual([ -16 ], getQueryResults("RETURN 1 + \"-17\"")); assertEqual([ "1-17" ], getQueryResults("RETURN 1 + \"-17\""));
assertEqual([ 1 ], getQueryResults("RETURN 1 + [ ]")); assertEqual([ 1 ], getQueryResults("RETURN 1 + [ ]"));
assertEqual([ 1 ], getQueryResults("RETURN 1 + [ 0 ]")); assertEqual([ "10" ], getQueryResults("RETURN 1 + [ 0 ]"));
assertEqual([ 5 ], getQueryResults("RETURN 1 + [ 4 ]")); assertEqual([ "14" ], getQueryResults("RETURN 1 + [ 4 ]"));
assertEqual([ -3 ], getQueryResults("RETURN 1 + [ -4 ]")); assertEqual([ "1-4" ], getQueryResults("RETURN 1 + [ -4 ]"));
assertEqual([ 1 ], getQueryResults("RETURN 1 + { }")); assertEqual([ "1[object Object]" ], getQueryResults("RETURN 1 + { }"));
assertEqual([ 1 ], getQueryResults("RETURN null + 1")); assertEqual([ 1 ], getQueryResults("RETURN null + 1"));
assertEqual([ 1 ], getQueryResults("RETURN false + 1")); assertEqual([ 1 ], getQueryResults("RETURN false + 1"));
assertEqual([ 2 ], getQueryResults("RETURN true + 1")); assertEqual([ 2 ], getQueryResults("RETURN true + 1"));
assertEqual([ 1 ], getQueryResults("RETURN \"0\" + 1")); assertEqual([ "01" ], getQueryResults("RETURN \"0\" + 1"));
assertEqual([ 24 ], getQueryResults("RETURN \"23\" + 1")); assertEqual([ "231" ], getQueryResults("RETURN \"23\" + 1"));
assertEqual([ -8 ], getQueryResults("RETURN \"-9\" + 1")); assertEqual([ "-91" ], getQueryResults("RETURN \"-9\" + 1"));
assertEqual([ 1 ], getQueryResults("RETURN [ ] + 1")); assertEqual([ "1" ], getQueryResults("RETURN [ ] + 1"));
assertEqual([ 1 ], getQueryResults("RETURN [ 0 ] + 1")); assertEqual([ "01" ], getQueryResults("RETURN [ 0 ] + 1"));
assertEqual([ 5 ], getQueryResults("RETURN [ 4 ] + 1")); assertEqual([ "41" ], getQueryResults("RETURN [ 4 ] + 1"));
assertEqual([ -3 ], getQueryResults("RETURN [ -4 ] + 1")); assertEqual([ "-41" ], getQueryResults("RETURN [ -4 ] + 1"));
assertEqual([ 1 ], getQueryResults("RETURN { } + 1")); assertEqual([ "[object Object]1" ], getQueryResults("RETURN { } + 1"));
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////