summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp')
-rw-r--r--src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp b/src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp
new file mode 100644
index 0000000..7b3e4d8
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/xml/XPathPredicate.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(XPATH)
+
+#include "XPathPredicate.h"
+
+#include "Node.h"
+#include "XPathFunctions.h"
+#include "XPathUtil.h"
+#include "XPathValue.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(const String& value)
+ : m_value(value)
+{
+}
+
+Value StringExpression::evaluate() const
+{
+ return m_value;
+}
+
+Value Negative::evaluate() const
+{
+ Value p(subExpr(0)->evaluate());
+ return -p.toNumber();
+}
+
+NumericOp::NumericOp(Opcode opcode, Expression* lhs, Expression* rhs)
+ : m_opcode(opcode)
+{
+ addSubExpression(lhs);
+ addSubExpression(rhs);
+}
+
+Value NumericOp::evaluate() const
+{
+ Value lhs(subExpr(0)->evaluate());
+ Value rhs(subExpr(1)->evaluate());
+
+ double leftVal = lhs.toNumber();
+ double rightVal = rhs.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, Expression* lhs, Expression* rhs)
+ : m_opcode(opcode)
+{
+ addSubExpression(lhs);
+ addSubExpression(rhs);
+}
+
+bool EqTestOp::compare(const Value& lhs, const Value& rhs) const
+{
+ if (lhs.isNodeSet()) {
+ const NodeSet& lhsSet = lhs.toNodeSet();
+ if (rhs.isNodeSet()) {
+ // If both objects to be compared are node-sets, then the comparison will be true if and only if
+ // there is a node in the first node-set and a node in the second node-set such that the result of
+ // performing the comparison on the string-values of the two nodes is true.
+ const NodeSet& rhsSet = rhs.toNodeSet();
+ for (unsigned lindex = 0; lindex < lhsSet.size(); ++lindex)
+ for (unsigned rindex = 0; rindex < rhsSet.size(); ++rindex)
+ if (compare(stringValue(lhsSet[lindex]), stringValue(rhsSet[rindex])))
+ return true;
+ return false;
+ }
+ if (rhs.isNumber()) {
+ // If one object to be compared is a node-set and the other is a number, then the comparison will be true
+ // if and only if there is a node in the node-set such that the result of performing the comparison on the number
+ // to be compared and on the result of converting the string-value of that node to a number using the number function is true.
+ for (unsigned lindex = 0; lindex < lhsSet.size(); ++lindex)
+ if (compare(Value(stringValue(lhsSet[lindex])).toNumber(), rhs))
+ return true;
+ return false;
+ }
+ if (rhs.isString()) {
+ // If one object to be compared is a node-set and the other is a string, then the comparison will be true
+ // if and only if there is a node in the node-set such that the result of performing the comparison on
+ // the string-value of the node and the other string is true.
+ for (unsigned lindex = 0; lindex < lhsSet.size(); ++lindex)
+ if (compare(stringValue(lhsSet[lindex]), rhs))
+ return true;
+ return false;
+ }
+ if (rhs.isBoolean()) {
+ // If one object to be compared is a node-set and the other is a boolean, then the comparison will be true
+ // if and only if the result of performing the comparison on the boolean and on the result of converting
+ // the node-set to a boolean using the boolean function is true.
+ return compare(lhs.toBoolean(), rhs);
+ }
+ ASSERT(0);
+ }
+ if (rhs.isNodeSet()) {
+ const NodeSet& rhsSet = rhs.toNodeSet();
+ if (lhs.isNumber()) {
+ for (unsigned rindex = 0; rindex < rhsSet.size(); ++rindex)
+ if (compare(lhs, Value(stringValue(rhsSet[rindex])).toNumber()))
+ return true;
+ return false;
+ }
+ if (lhs.isString()) {
+ for (unsigned rindex = 0; rindex < rhsSet.size(); ++rindex)
+ if (compare(lhs, stringValue(rhsSet[rindex])))
+ return true;
+ return false;
+ }
+ if (lhs.isBoolean())
+ return compare(lhs, rhs.toBoolean());
+ ASSERT(0);
+ }
+
+ // Neither side is a NodeSet.
+ 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(0);
+ return false;
+}
+
+Value EqTestOp::evaluate() const
+{
+ Value lhs(subExpr(0)->evaluate());
+ Value rhs(subExpr(1)->evaluate());
+
+ return compare(lhs, rhs);
+}
+
+LogicalOp::LogicalOp(Opcode opcode, Expression* lhs, Expression* rhs)
+ : m_opcode(opcode)
+{
+ addSubExpression(lhs);
+ addSubExpression(rhs);
+}
+
+bool LogicalOp::shortCircuitOn() const
+{
+ if (m_opcode == OP_And)
+ return false; //false and foo
+
+ return true; //true or bar
+}
+
+Value LogicalOp::evaluate() const
+{
+ Value lhs(subExpr(0)->evaluate());
+
+ // This is not only an optimization, http://www.w3.org/TR/xpath
+ // dictates that we must do short-circuit evaluation
+ bool lhsBool = lhs.toBoolean();
+ if (lhsBool == shortCircuitOn())
+ return lhsBool;
+
+ return subExpr(1)->evaluate().toBoolean();
+}
+
+Value Union::evaluate() const
+{
+ Value lhsResult = subExpr(0)->evaluate();
+ Value rhs = subExpr(1)->evaluate();
+ if (!lhsResult.isNodeSet() || !rhs.isNodeSet())
+ return NodeSet();
+
+ NodeSet& resultSet = lhsResult.modifiableNodeSet();
+ const NodeSet& rhsNodes = rhs.toNodeSet();
+
+ HashSet<Node*> nodes;
+ for (size_t i = 0; i < resultSet.size(); ++i)
+ nodes.add(resultSet[i]);
+
+ for (size_t i = 0; i < rhsNodes.size(); ++i) {
+ Node* node = rhsNodes[i];
+ if (nodes.add(node).second)
+ resultSet.append(node);
+ }
+
+ // It is also possible to use merge sort to avoid making the result unsorted;
+ // but this would waste the time in cases when order is not important.
+ resultSet.markSorted(false);
+ return lhsResult;
+}
+
+Predicate::Predicate(Expression* expr)
+ : m_expr(expr)
+{
+}
+
+Predicate::~Predicate()
+{
+ delete m_expr;
+}
+
+bool Predicate::evaluate() const
+{
+ ASSERT(m_expr != 0);
+
+ Value result(m_expr->evaluate());
+
+ // foo[3] means foo[position()=3]
+ if (result.isNumber())
+ return EqTestOp(EqTestOp::OP_EQ, createFunction("position"), new Number(result.toNumber())).evaluate().toBoolean();
+
+ return result.toBoolean();
+}
+
+}
+}
+
+#endif // ENABLE(XPATH)