cc54b1cb406be4453a5deec289695daae8de23d2
[WebKit-https.git] / WebCore / xml / XPathPredicate.cpp
1 /*
2  * Copyright 2005 Frerich Raabe <raabe@kde.org>
3  * Copyright (C) 2006 Apple Computer, Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #if ENABLE(XPATH)
30
31 #include "XPathPredicate.h"
32
33 #include "Node.h"
34 #include "XPathFunctions.h"
35 #include "XPathValue.h"
36 #include <math.h>
37
38 #ifdef _MSC_VER // math functions missing from Microsoft Visual Studio standard C library
39 #define remainder(x, y) fmod((x), (y))
40 #endif
41
42 namespace WebCore {
43 namespace XPath {
44         
45 Number::Number(double value)
46     : m_value(value)
47 {
48 }
49
50 bool Number::isConstant() const
51 {
52     return true;
53 }
54
55 Value Number::doEvaluate() const
56 {
57     return m_value;
58 }
59
60 StringExpression::StringExpression(const String& value)
61     : m_value(value)
62 {
63 }
64
65 bool StringExpression::isConstant() const
66 {
67     return true;
68 }
69
70 Value StringExpression::doEvaluate() const
71 {
72     return m_value;
73 }
74
75 Value Negative::doEvaluate() const
76 {
77     Value p(subExpr(0)->evaluate());
78     if (!p.isNumber())
79         return Value();
80     return -p.toNumber();
81 }
82
83 NumericOp::NumericOp(Opcode opcode, Expression* lhs, Expression* rhs)
84     : m_opcode(opcode)
85 {
86     addSubExpression(lhs);
87     addSubExpression(rhs);
88 }
89
90 Value NumericOp::doEvaluate() const
91 {
92     Value lhs(subExpr(0)->evaluate());
93     Value rhs(subExpr(1)->evaluate());
94     
95     if (!lhs.isNumber() || !rhs.isNumber())
96         return Value();
97
98     double leftVal = lhs.toNumber(), rightVal = rhs.toNumber();
99
100     switch (m_opcode) {
101         case OP_Add:
102             return leftVal + rightVal;
103         case OP_Sub:
104             return leftVal - rightVal;
105         case OP_Mul:
106             return leftVal * rightVal;
107         case OP_Div:
108             return leftVal / rightVal;
109         case OP_Mod:
110             return remainder(leftVal, rightVal);
111         case OP_GT:
112             return leftVal > rightVal;
113         case OP_GE:
114             return leftVal >= rightVal;
115         case OP_LT:
116             return leftVal < rightVal;
117         case OP_LE:
118             return leftVal <= rightVal;
119     }
120     
121     return Value();
122 }
123
124 EqTestOp::EqTestOp(Opcode opcode, Expression* lhs, Expression* rhs)
125     : m_opcode(opcode)
126 {
127     addSubExpression(lhs);
128     addSubExpression(rhs);
129 }
130
131 Value EqTestOp::doEvaluate() const
132 {
133     Value lhs(subExpr(0)->evaluate());
134     Value rhs(subExpr(1)->evaluate());
135
136     bool equal;
137     if (lhs.isBoolean() || rhs.isBoolean())
138         equal = lhs.toBoolean() == rhs.toBoolean();
139     else if (lhs.isNumber() || rhs.isNumber())
140         equal = lhs.toNumber() == rhs.toNumber();
141     else
142         equal = lhs.toString() == rhs.toString();
143
144     if (m_opcode == OP_EQ)
145         return equal;
146
147     return !equal;
148 }
149
150 LogicalOp::LogicalOp(Opcode opcode, Expression* lhs, Expression* rhs)
151     : m_opcode(opcode)
152 {
153     addSubExpression(lhs);
154     addSubExpression(rhs);
155 }
156
157 bool LogicalOp::shortCircuitOn() const
158 {
159     if (m_opcode == OP_And)
160         return false; //false and foo
161
162     return true;  //true or bar
163 }
164
165 bool LogicalOp::isConstant() const
166 {
167     return subExpr(0)->isConstant() &&
168            subExpr(0)->evaluate().toBoolean() == shortCircuitOn();
169 }
170
171 Value LogicalOp::doEvaluate() const
172 {
173     Value lhs(subExpr(0)->evaluate());
174
175     // This is not only an optimization, http://www.w3.org/TR/xpath
176     // dictates that we must do short-circuit evaluation
177     bool lhsBool = lhs.toBoolean();
178     if (lhsBool == shortCircuitOn())
179         return lhsBool;
180
181     return subExpr(1)->evaluate().toBoolean();
182 }
183
184 Value Union::doEvaluate() const
185 {
186     // FIXME: This algorithm doesn't return nodes in document order, as it should.
187     Value lhs = subExpr(0)->evaluate();
188     Value rhs = subExpr(1)->evaluate();
189     if (!lhs.isNodeVector() || !rhs.isNodeVector())
190         return NodeVector();
191     
192     NodeVector lhsNodes = lhs.toNodeVector();
193     NodeVector rhsNodes = rhs.toNodeVector();
194     NodeVector result = lhsNodes;
195     
196     HashSet<Node*> nodes;
197     for (size_t i = 0; i < result.size(); ++i)
198         nodes.add(result[i].get());
199     
200     for (size_t i = 0; i < rhsNodes.size(); ++i) {
201         Node* node = rhsNodes[i].get();
202         if (nodes.add(node).second)
203             result.append(node);
204     }
205     
206     return result;
207 }
208
209 Predicate::Predicate(Expression* expr)
210     : m_expr(expr)
211 {
212 }
213
214 Predicate::~Predicate()
215 {
216     delete m_expr;
217 }
218
219 bool Predicate::evaluate() const
220 {
221     ASSERT(m_expr != 0);
222
223     Value result(m_expr->evaluate());
224
225     // foo[3] means foo[position()=3]
226     if (result.isNumber())
227         return EqTestOp(EqTestOp::OP_EQ, createFunction("position"), new Number(result.toNumber())).evaluate().toBoolean();
228
229     return result.toBoolean();
230 }
231
232 void Predicate::optimize()
233 {
234     m_expr->optimize();
235 }
236
237 }
238 }
239
240 #endif // ENABLE(XPATH)