blob: 7d48678c157ed4655e6af21b78a400d8ecc51c69 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
*/
#include "qmf/exceptions.h"
#include "qmf/Expression.h"
#include <iostream>
using namespace std;
using namespace qmf;
using namespace qpid::types;
Expression::Expression(const Variant::List& expr)
{
static int level(0);
level++;
Variant::List::const_iterator iter(expr.begin());
string op(iter->asString());
iter++;
if (op == "not") logicalOp = LOGICAL_NOT;
else if (op == "and") logicalOp = LOGICAL_AND;
else if (op == "or") logicalOp = LOGICAL_OR;
else {
logicalOp = LOGICAL_ID;
if (op == "eq") boolOp = BOOL_EQ;
else if (op == "ne") boolOp = BOOL_NE;
else if (op == "lt") boolOp = BOOL_LT;
else if (op == "le") boolOp = BOOL_LE;
else if (op == "gt") boolOp = BOOL_GT;
else if (op == "ge") boolOp = BOOL_GE;
else if (op == "re_match") boolOp = BOOL_RE_MATCH;
else if (op == "exists") boolOp = BOOL_EXISTS;
else if (op == "true") boolOp = BOOL_TRUE;
else if (op == "false") boolOp = BOOL_FALSE;
else
throw QmfException("Invalid operator in predicate expression");
}
if (logicalOp == LOGICAL_ID) {
switch (boolOp) {
case BOOL_EQ:
case BOOL_NE:
case BOOL_LT:
case BOOL_LE:
case BOOL_GT:
case BOOL_GE:
case BOOL_RE_MATCH:
//
// Binary operator: get two operands.
//
operandCount = 2;
break;
case BOOL_EXISTS:
//
// Unary operator: get one operand.
//
operandCount = 1;
break;
case BOOL_TRUE:
case BOOL_FALSE:
//
// Literal operator: no operands.
//
operandCount = 0;
break;
}
for (int idx = 0; idx < operandCount; idx++) {
if (iter == expr.end())
throw QmfException("Too few operands for operation: " + op);
if (iter->getType() == VAR_STRING) {
quoted[idx] = false;
operands[idx] = *iter;
} else if (iter->getType() == VAR_LIST) {
const Variant::List& sublist(iter->asList());
Variant::List::const_iterator subIter(sublist.begin());
if (subIter != sublist.end() && subIter->asString() == "quote") {
quoted[idx] = true;
subIter++;
if (subIter != sublist.end()) {
operands[idx] = *subIter;
subIter++;
if (subIter != sublist.end())
throw QmfException("Extra tokens at end of 'quote'");
}
} else
throw QmfException("Expected '[quote, <token>]'");
} else
throw QmfException("Expected string or list as operand for: " + op);
iter++;
}
if (iter != expr.end())
throw QmfException("Too many operands for operation: " + op);
} else {
//
// This is a logical expression, collect sub-expressions
//
while (iter != expr.end()) {
if (iter->getType() != VAR_LIST)
throw QmfException("Operands of " + op + " must be lists");
expressionList.push_back(boost::shared_ptr<Expression>(new Expression(iter->asList())));
iter++;
}
}
level--;
}
bool Expression::evaluate(const Variant::Map& data) const
{
list<boost::shared_ptr<Expression> >::const_iterator iter;
switch (logicalOp) {
case LOGICAL_ID:
return boolEval(data);
case LOGICAL_NOT:
for (iter = expressionList.begin(); iter != expressionList.end(); iter++)
if ((*iter)->evaluate(data))
return false;
return true;
case LOGICAL_AND:
for (iter = expressionList.begin(); iter != expressionList.end(); iter++)
if (!(*iter)->evaluate(data))
return false;
return true;
case LOGICAL_OR:
for (iter = expressionList.begin(); iter != expressionList.end(); iter++)
if ((*iter)->evaluate(data))
return true;
return false;
}
return false;
}
bool Expression::boolEval(const Variant::Map& data) const
{
Variant val[2];
bool exists[2];
for (int idx = 0; idx < operandCount; idx++) {
if (quoted[idx]) {
exists[idx] = true;
val[idx] = operands[idx];
} else {
Variant::Map::const_iterator mIter(data.find(operands[idx].asString()));
if (mIter == data.end()) {
exists[idx] = false;
} else {
exists[idx] = true;
val[idx] = mIter->second;
}
}
}
switch (boolOp) {
case BOOL_EQ: return (exists[0] && exists[1] && (val[0].asString() == val[1].asString()));
case BOOL_NE: return (exists[0] && exists[1] && (val[0].asString() != val[1].asString()));
case BOOL_LT: return (exists[0] && exists[1] && lessThan(val[0], val[1]));
case BOOL_LE: return (exists[0] && exists[1] && lessEqual(val[0], val[1]));
case BOOL_GT: return (exists[0] && exists[1] && greaterThan(val[0], val[1]));
case BOOL_GE: return (exists[0] && exists[1] && greaterEqual(val[0], val[1]));
case BOOL_RE_MATCH: return false; // TODO
case BOOL_EXISTS: return exists[0];
case BOOL_TRUE: return true;
case BOOL_FALSE: return false;
}
return false;
}
bool Expression::lessThan(const Variant& left, const Variant& right) const
{
switch (left.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
switch (right.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
return left.asInt64() < right.asInt64();
case VAR_STRING:
try {
return left.asInt64() < right.asInt64();
} catch (std::exception&) {}
break;
default:
break;
}
break;
case VAR_FLOAT: case VAR_DOUBLE:
switch (right.getType()) {
case VAR_FLOAT: case VAR_DOUBLE:
return left.asDouble() < right.asDouble();
case VAR_STRING:
try {
return left.asDouble() < right.asDouble();
} catch (std::exception&) {}
break;
default:
break;
}
break;
case VAR_STRING:
switch (right.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
try {
return left.asInt64() < right.asInt64();
} catch (std::exception&) {}
break;
case VAR_FLOAT: case VAR_DOUBLE:
try {
return left.asDouble() < right.asDouble();
} catch (std::exception&) {}
break;
case VAR_STRING:
return left.asString() < right.asString();
default:
break;
}
default:
break;
}
return false;
}
bool Expression::lessEqual(const Variant& left, const Variant& right) const
{
switch (left.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
switch (right.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
return left.asInt64() <= right.asInt64();
case VAR_STRING:
try {
return left.asInt64() <= right.asInt64();
} catch (std::exception&) {}
break;
default:
break;
}
break;
case VAR_FLOAT: case VAR_DOUBLE:
switch (right.getType()) {
case VAR_FLOAT: case VAR_DOUBLE:
return left.asDouble() <= right.asDouble();
case VAR_STRING:
try {
return left.asDouble() <= right.asDouble();
} catch (std::exception&) {}
break;
default:
break;
}
break;
case VAR_STRING:
switch (right.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
try {
return left.asInt64() <= right.asInt64();
} catch (std::exception&) {}
break;
case VAR_FLOAT: case VAR_DOUBLE:
try {
return left.asDouble() <= right.asDouble();
} catch (std::exception&) {}
break;
case VAR_STRING:
return left.asString() <= right.asString();
default:
break;
}
default:
break;
}
return false;
}
bool Expression::greaterThan(const Variant& left, const Variant& right) const
{
switch (left.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
switch (right.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
return left.asInt64() > right.asInt64();
case VAR_STRING:
try {
return left.asInt64() > right.asInt64();
} catch (std::exception&) {}
break;
default:
break;
}
break;
case VAR_FLOAT: case VAR_DOUBLE:
switch (right.getType()) {
case VAR_FLOAT: case VAR_DOUBLE:
return left.asDouble() > right.asDouble();
case VAR_STRING:
try {
return left.asDouble() > right.asDouble();
} catch (std::exception&) {}
break;
default:
break;
}
break;
case VAR_STRING:
switch (right.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
try {
return left.asInt64() > right.asInt64();
} catch (std::exception&) {}
break;
case VAR_FLOAT: case VAR_DOUBLE:
try {
return left.asDouble() > right.asDouble();
} catch (std::exception&) {}
break;
case VAR_STRING:
return left.asString() > right.asString();
default:
break;
}
default:
break;
}
return false;
}
bool Expression::greaterEqual(const Variant& left, const Variant& right) const
{
switch (left.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
switch (right.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
return left.asInt64() >= right.asInt64();
case VAR_STRING:
try {
return left.asInt64() >= right.asInt64();
} catch (std::exception&) {}
break;
default:
break;
}
break;
case VAR_FLOAT: case VAR_DOUBLE:
switch (right.getType()) {
case VAR_FLOAT: case VAR_DOUBLE:
return left.asDouble() >= right.asDouble();
case VAR_STRING:
try {
return left.asDouble() >= right.asDouble();
} catch (std::exception&) {}
break;
default:
break;
}
break;
case VAR_STRING:
switch (right.getType()) {
case VAR_UINT8: case VAR_UINT16: case VAR_UINT32: case VAR_UINT64:
case VAR_INT8: case VAR_INT16: case VAR_INT32: case VAR_INT64:
try {
return left.asInt64() >= right.asInt64();
} catch (std::exception&) {}
break;
case VAR_FLOAT: case VAR_DOUBLE:
try {
return left.asDouble() >= right.asDouble();
} catch (std::exception&) {}
break;
case VAR_STRING:
return left.asString() >= right.asString();
default:
break;
}
default:
break;
}
return false;
}