1
0
Fork 0

defer evaluation of logical operators

This commit is contained in:
Jan Steemann 2014-01-10 10:58:30 +01:00
parent 56054d3e66
commit 8277e7582c
3 changed files with 112 additions and 16 deletions

View File

@ -1939,28 +1939,30 @@ static void ProcessUnaryPlus (TRI_aql_codegen_js_t* const generator,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for binary and (a && b) /// @brief generate code for binary and (a && b)
/// this passes two functions to the operator for lazy evaluation
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void ProcessBinaryAnd (TRI_aql_codegen_js_t* const generator, static void ProcessBinaryAnd (TRI_aql_codegen_js_t* const generator,
const TRI_aql_node_t* const node) { const TRI_aql_node_t* const node) {
ScopeOutput(generator, "aql.LOGICAL_AND("); ScopeOutput(generator, "aql.LOGICAL_AND_FN(function () {\nreturn ");
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0));
ScopeOutput(generator, ", "); ScopeOutput(generator, "}, function () {\nreturn ");
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1));
ScopeOutput(generator, ")"); ScopeOutput(generator, "})");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for binary or (a || b) /// @brief generate code for binary or (a || b)
/// this passes two functions to the operator for lazy evaluation
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void ProcessBinaryOr (TRI_aql_codegen_js_t* const generator, static void ProcessBinaryOr (TRI_aql_codegen_js_t* const generator,
const TRI_aql_node_t* const node) { const TRI_aql_node_t* const node) {
ScopeOutput(generator, "aql.LOGICAL_OR("); ScopeOutput(generator, "aql.LOGICAL_OR_FN(function () {\nreturn ");
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0));
ScopeOutput(generator, ", "); ScopeOutput(generator, "}, function () {\nreturn ");
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1));
ScopeOutput(generator, ")"); ScopeOutput(generator, "})");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -2125,13 +2127,13 @@ static void ProcessBinaryIn (TRI_aql_codegen_js_t* const generator,
static void ProcessTernary (TRI_aql_codegen_js_t* const generator, static void ProcessTernary (TRI_aql_codegen_js_t* const generator,
const TRI_aql_node_t* const node) { const TRI_aql_node_t* const node) {
ScopeOutput(generator, "aql.TERNARY_OPERATOR("); ScopeOutput(generator, "aql.TERNARY_OPERATOR_FN(");
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0)); ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0));
ScopeOutput(generator, ", "); ScopeOutput(generator, ", function () { \nreturn ");
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1)); ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 1));
ScopeOutput(generator, ", "); ScopeOutput(generator, "}, function () {\nreturn ");
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 2)); ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 2));
ScopeOutput(generator, ")"); ScopeOutput(generator, "})");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -1064,6 +1064,26 @@ function TERNARY_OPERATOR (condition, truePart, falsePart) {
return falsePart; return falsePart;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief execute ternary operator
///
/// the condition operand must be a boolean value, returns either the truepart
/// or the falsepart
////////////////////////////////////////////////////////////////////////////////
function TERNARY_OPERATOR_FN (condition, truePart, falsePart) {
"use strict";
if (TYPEWEIGHT(condition) !== TYPEWEIGHT_BOOL) {
THROW(INTERNAL.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);
}
if (condition) {
return truePart();
}
return falsePart();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief perform logical and /// @brief perform logical and
/// ///
@ -1108,6 +1128,60 @@ function LOGICAL_OR (lhs, rhs) {
return rhs; return rhs;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief perform logical and
///
/// both operands must be boolean values, returns a boolean, uses short-circuit
/// evaluation
////////////////////////////////////////////////////////////////////////////////
function LOGICAL_AND_FN (lhs, rhs) {
"use strict";
var l = lhs();
if (TYPEWEIGHT(l) !== TYPEWEIGHT_BOOL) {
THROW(INTERNAL.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);
}
if (! l) {
return false;
}
var r = rhs();
if (TYPEWEIGHT(r) !== TYPEWEIGHT_BOOL) {
THROW(INTERNAL.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);
}
return r;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief perform logical or
///
/// both operands must be boolean values, returns a boolean, uses short-circuit
/// evaluation
////////////////////////////////////////////////////////////////////////////////
function LOGICAL_OR_FN (lhs, rhs) {
"use strict";
var l = lhs();
if (TYPEWEIGHT(l) !== TYPEWEIGHT_BOOL) {
THROW(INTERNAL.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);
}
if (l) {
return true;
}
var r = rhs();
if (TYPEWEIGHT(r) !== TYPEWEIGHT_BOOL) {
THROW(INTERNAL.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);
}
return r;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief perform logical negation /// @brief perform logical negation
/// ///
@ -4002,8 +4076,11 @@ exports.GET_DOCUMENTS_SKIPLIST = GET_DOCUMENTS_SKIPLIST;
exports.GET_DOCUMENTS_SKIPLIST_LIST = GET_DOCUMENTS_SKIPLIST_LIST; exports.GET_DOCUMENTS_SKIPLIST_LIST = GET_DOCUMENTS_SKIPLIST_LIST;
exports.COLLECTIONS = COLLECTIONS; exports.COLLECTIONS = COLLECTIONS;
exports.TERNARY_OPERATOR = TERNARY_OPERATOR; exports.TERNARY_OPERATOR = TERNARY_OPERATOR;
exports.TERNARY_OPERATOR_FN = TERNARY_OPERATOR_FN;
exports.LOGICAL_AND = LOGICAL_AND; exports.LOGICAL_AND = LOGICAL_AND;
exports.LOGICAL_OR = LOGICAL_OR; exports.LOGICAL_OR = LOGICAL_OR;
exports.LOGICAL_AND_FN = LOGICAL_AND_FN;
exports.LOGICAL_OR_FN = LOGICAL_OR_FN;
exports.LOGICAL_NOT = LOGICAL_NOT; exports.LOGICAL_NOT = LOGICAL_NOT;
exports.RELATIONAL_EQUAL = RELATIONAL_EQUAL; exports.RELATIONAL_EQUAL = RELATIONAL_EQUAL;
exports.RELATIONAL_UNEQUAL = RELATIONAL_UNEQUAL; exports.RELATIONAL_UNEQUAL = RELATIONAL_UNEQUAL;

View File

@ -238,18 +238,35 @@ function ahuacatlLogicalTestSuite () {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testBinaryAndShortCircuit1 : function () { testBinaryAndShortCircuit1 : function () {
// TODO: FIXME var expected = [ false ];
// var expected = [ false ]; var actual = getQueryResults("RETURN false && FAIL('this will fail')");
// var actual = getQueryResults("RETURN false && FAIL('this will fail')"); assertEqual(expected, actual);
//assertEqual(expected, actual);
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief test binary and, short circuit evaluation /// @brief test binary or, short circuit evaluation
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
testBinaryAndShortCircuit2 : function () { testBinaryAndShortCircuit2 : function () {
assertException(function() { getQueryResults("RETURN false && FAIL('this will fail')"); }); assertException(function() { getQueryResults("RETURN true && FAIL('this will fail')"); });
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test binary or, short circuit evaluation
////////////////////////////////////////////////////////////////////////////////
testBinaryOrShortCircuit1 : function () {
var expected = [ true ];
var actual = getQueryResults("RETURN true || FAIL('this will fail')");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test binary or, short circuit evaluation
////////////////////////////////////////////////////////////////////////////////
testBinaryOrShortCircuit2 : function () {
assertException(function() { getQueryResults("RETURN false || FAIL('this will fail')"); });
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////