XPathPredicate.cpp [plain text]
#include "config.h"
#include "XPathPredicate.h"
#include "XPathFunctions.h"
#include "XPathUtil.h"
#include <math.h>
#include <wtf/MathExtras.h>
namespace WebCore {
namespace XPath {
Number::Number(double value)
: m_value(value)
{
}
Value Number::evaluate() const
{
return m_value;
}
StringExpression::StringExpression(String&& value)
: m_value(WTFMove(value))
{
}
Value StringExpression::evaluate() const
{
return m_value;
}
Negative::Negative(std::unique_ptr<Expression> expression)
{
addSubexpression(WTFMove(expression));
}
Value Negative::evaluate() const
{
return -subexpression(0).evaluate().toNumber();
}
NumericOp::NumericOp(Opcode opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs)
: m_opcode(opcode)
{
addSubexpression(WTFMove(lhs));
addSubexpression(WTFMove(rhs));
}
Value NumericOp::evaluate() const
{
double leftVal = subexpression(0).evaluate().toNumber();
double rightVal = subexpression(1).evaluate().toNumber();
switch (m_opcode) {
case OP_Add:
return leftVal + rightVal;
case OP_Sub:
return leftVal - rightVal;
case OP_Mul:
return leftVal * rightVal;
case OP_Div:
return leftVal / rightVal;
case OP_Mod:
return fmod(leftVal, rightVal);
}
ASSERT_NOT_REACHED();
return 0.0;
}
EqTestOp::EqTestOp(Opcode opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs)
: m_opcode(opcode)
{
addSubexpression(WTFMove(lhs));
addSubexpression(WTFMove(rhs));
}
bool EqTestOp::compare(const Value& lhs, const Value& rhs) const
{
if (lhs.isNodeSet()) {
const NodeSet& lhsSet = lhs.toNodeSet();
if (rhs.isNodeSet()) {
const NodeSet& rhsSet = rhs.toNodeSet();
for (auto& lhs : lhsSet) {
for (auto& rhs : rhsSet) {
if (compare(stringValue(lhs.get()), stringValue(rhs.get())))
return true;
}
}
return false;
}
if (rhs.isNumber()) {
for (auto& lhs : lhsSet) {
if (compare(Value(stringValue(lhs.get())).toNumber(), rhs))
return true;
}
return false;
}
if (rhs.isString()) {
for (auto& lhs : lhsSet) {
if (compare(stringValue(lhs.get()), rhs))
return true;
}
return false;
}
if (rhs.isBoolean()) {
return compare(lhs.toBoolean(), rhs);
}
ASSERT_NOT_REACHED();
}
if (rhs.isNodeSet()) {
const NodeSet& rhsSet = rhs.toNodeSet();
if (lhs.isNumber()) {
for (auto& rhs : rhsSet) {
if (compare(lhs, Value(stringValue(rhs.get())).toNumber()))
return true;
}
return false;
}
if (lhs.isString()) {
for (auto& rhs : rhsSet) {
if (compare(lhs, stringValue(rhs.get())))
return true;
}
return false;
}
if (lhs.isBoolean())
return compare(lhs, rhs.toBoolean());
ASSERT_NOT_REACHED();
}
switch (m_opcode) {
case OP_EQ:
case OP_NE:
bool equal;
if (lhs.isBoolean() || rhs.isBoolean())
equal = lhs.toBoolean() == rhs.toBoolean();
else if (lhs.isNumber() || rhs.isNumber())
equal = lhs.toNumber() == rhs.toNumber();
else
equal = lhs.toString() == rhs.toString();
if (m_opcode == OP_EQ)
return equal;
return !equal;
case OP_GT:
return lhs.toNumber() > rhs.toNumber();
case OP_GE:
return lhs.toNumber() >= rhs.toNumber();
case OP_LT:
return lhs.toNumber() < rhs.toNumber();
case OP_LE:
return lhs.toNumber() <= rhs.toNumber();
}
ASSERT_NOT_REACHED();
return false;
}
Value EqTestOp::evaluate() const
{
Value lhs(subexpression(0).evaluate());
Value rhs(subexpression(1).evaluate());
return compare(lhs, rhs);
}
LogicalOp::LogicalOp(Opcode opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs)
: m_opcode(opcode)
{
addSubexpression(WTFMove(lhs));
addSubexpression(WTFMove(rhs));
}
inline bool LogicalOp::shortCircuitOn() const
{
return m_opcode != OP_And;
}
Value LogicalOp::evaluate() const
{
bool lhsBool = subexpression(0).evaluate().toBoolean();
if (lhsBool == shortCircuitOn())
return lhsBool;
return subexpression(1).evaluate().toBoolean();
}
Union::Union(std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs)
{
addSubexpression(WTFMove(lhs));
addSubexpression(WTFMove(rhs));
}
Value Union::evaluate() const
{
Value lhsResult = subexpression(0).evaluate();
Value rhs = subexpression(1).evaluate();
NodeSet& resultSet = lhsResult.modifiableNodeSet();
const NodeSet& rhsNodes = rhs.toNodeSet();
HashSet<Node*> nodes;
for (auto& result : resultSet)
nodes.add(result.get());
for (auto& node : rhsNodes) {
if (nodes.add(node.get()).isNewEntry)
resultSet.append(node.get());
}
resultSet.markSorted(false);
return lhsResult;
}
bool evaluatePredicate(const Expression& expression)
{
Value result(expression.evaluate());
if (result.isNumber())
return EqTestOp(EqTestOp::OP_EQ, Function::create("position"_s), makeUnique<Number>(result.toNumber())).evaluate().toBoolean();
return result.toBoolean();
}
bool predicateIsContextPositionSensitive(const Expression& expression)
{
return expression.isContextPositionSensitive() || expression.resultType() == Value::NumberValue;
}
}
}