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>
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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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);
}
// -----------------------------------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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"));
},
////////////////////////////////////////////////////////////////////////////////