• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KHTML

  • sources
  • kde-4.14
  • kdelibs
  • khtml
  • xpath
predicate.cpp
Go to the documentation of this file.
1 /*
2  * predicate.cc - Copyright 2005 Frerich Raabe <raabe@kde.org>
3  * Copyright 2010 Maksim Orlovich <maksim@kde.org>
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 #include "predicate.h"
27 #include "functions.h"
28 
29 #include <QString>
30 
31 #include "xml/dom_nodeimpl.h"
32 #include "xml/dom_nodelistimpl.h"
33 #include "kjs/operations.h"
34 #include "kjs/value.h"
35 
36 #include <math.h>
37 
38 using namespace DOM;
39 using namespace khtml;
40 using namespace khtml::XPath;
41 
42 Number::Number( double value )
43  : m_value( value )
44 {
45 }
46 
47 bool Number::isConstant() const
48 {
49  return true;
50 }
51 
52 QString Number::dump() const
53 {
54  return "<number>" + QString::number( m_value ) + "</number>";
55 }
56 
57 Value Number::doEvaluate() const
58 {
59  return Value( m_value );
60 }
61 
62 String::String( const DOMString &value )
63  : m_value( value )
64 {
65 }
66 
67 bool String::isConstant() const
68 {
69  return true;
70 }
71 
72 QString String::dump() const
73 {
74  return "<string>" + m_value.string() + "</string>";
75 }
76 
77 Value String::doEvaluate() const
78 {
79  return Value( m_value );
80 }
81 
82 Value Negative::doEvaluate() const
83 {
84  Value p( subExpr( 0 )->evaluate() );
85  return Value( -p.toNumber() );
86 }
87 
88 QString Negative::dump() const
89 {
90  return "<negative>" + subExpr( 0 )->dump() + "</number>";
91 }
92 
93 QString BinaryExprBase::dump() const
94 {
95  QString s = "<" + opName() + ">";
96  s += "<operand>" + subExpr( 0 )->dump() + "</operand>";
97  s += "<operand>" + subExpr( 1 )->dump() + "</operand>";
98  s += "</" + opName() + ">";
99  return s;
100 }
101 
102 NumericOp::NumericOp( int _opCode, Expression* lhs, Expression* rhs ) :
103  opCode( _opCode )
104 {
105  addSubExpression( lhs );
106  addSubExpression( rhs );
107 }
108 
109 Value NumericOp::doEvaluate() const
110 {
111  Value lhs( subExpr( 0 )->evaluate() );
112  Value rhs( subExpr( 1 )->evaluate() );
113  double leftVal = lhs.toNumber(), rightVal = rhs.toNumber();
114 
115  switch (opCode) {
116  case OP_Add:
117  return Value( leftVal + rightVal );
118  case OP_Sub:
119  return Value( leftVal - rightVal );
120  case OP_Mul:
121  return Value( leftVal * rightVal );
122  case OP_Div:
123  if ( rightVal == 0.0 || rightVal == -0.0 ) {
124  if ( leftVal == 0.0 || leftVal == -0.0) {
125  return Value(); // 0/0 = NaN
126  } else {
127  // +/- Infinity.
128  if (signbit(leftVal) == signbit(rightVal))
129  return Value( KJS::Inf );
130  else
131  return Value( -KJS::Inf );
132  }
133  } else {
134  return Value( leftVal / rightVal );
135  }
136  case OP_Mod:
137  if ( rightVal == 0.0 || rightVal == -0.0 )
138  return Value(); //Divide by 0;
139  else
140  return Value( remainder( leftVal, rightVal ) );
141  default:
142  assert(0);
143  return Value();
144  }
145 }
146 
147 QString NumericOp::opName() const
148 {
149  switch (opCode) {
150  case OP_Add:
151  return QLatin1String( "addition" );
152  case OP_Sub:
153  return QLatin1String( "subtraction" );
154  case OP_Mul:
155  return QLatin1String( "multiplication" );
156  case OP_Div:
157  return QLatin1String( "division" );
158  case OP_Mod:
159  return QLatin1String( "modulo" );
160  default:
161  assert(0);
162  return QString();
163  }
164 }
165 
166 RelationOp::RelationOp( int _opCode, Expression* lhs, Expression* rhs ) :
167  opCode( _opCode )
168 {
169  addSubExpression( lhs );
170  addSubExpression( rhs );
171 }
172 
173 static void stringify(const Value& val, WTF::Vector<DOMString>* out)
174 {
175  if (val.isString()) {
176  out->append(val.toString());
177  } else {
178  assert(val.isNodeset());
179 
180  const DomNodeList& set = val.toNodeset();
181  for (unsigned long i = 0; i < set->length(); ++i) {
182  DOM::DOMString stringVal = stringValue(set->item(i));
183  out->append(stringVal);
184  }
185  }
186 }
187 
188 static void numify(const Value& val, WTF::Vector<double>* out)
189 {
190  if (val.isNumber()) {
191  out->append(val.toNumber());
192  } else {
193  assert(val.isNodeset());
194 
195  const DomNodeList& set = val.toNodeset();
196  for (unsigned long i = 0; i < set->length(); ++i) {
197  DOM::DOMString stringVal = stringValue(set->item(i));
198  out->append(Value(stringVal).toNumber());
199  }
200  }
201 }
202 
203 Value RelationOp::doEvaluate() const
204 {
205  Value lhs( subExpr( 0 )->evaluate() );
206  Value rhs( subExpr( 1 )->evaluate() );
207 
208  if (lhs.isNodeset() || rhs.isNodeset())
209  {
210  // If both are nodesets, or one is a string our
211  // comparisons are based on strings.
212  if ((lhs.isNodeset() && rhs.isNodeset()) ||
213  (lhs.isString() || rhs.isString())) {
214 
215  WTF::Vector<DOM::DOMString> leftStrings;
216  WTF::Vector<DOM::DOMString> rightStrings;
217 
218  stringify(lhs, &leftStrings);
219  stringify(rhs, &rightStrings);
220 
221  for (unsigned pl = 0; pl < leftStrings.size(); ++pl) {
222  for (unsigned pr = 0; pr < rightStrings.size(); ++pr) {
223  if (compareStrings(leftStrings[pl], rightStrings[pr]))
224  return Value(true);
225  } // pr
226  } // pl
227  return Value(false);
228  }
229 
230  // If one is a number, we do a number-based comparison
231  if (lhs.isNumber() || rhs.isNumber()) {
232  WTF::Vector<double> leftNums;
233  WTF::Vector<double> rightNums;
234 
235  numify(lhs, &leftNums);
236  numify(rhs, &rightNums);
237 
238  for (unsigned pl = 0; pl < leftNums.size(); ++pl) {
239  for (unsigned pr = 0; pr < rightNums.size(); ++pr) {
240  if (compareNumbers(leftNums[pl], rightNums[pr]))
241  return Value(true);
242  } // pr
243  } // pl
244  return Value(false);
245  }
246 
247  // Has to be a boolean-based comparison.
248  // These ones are simpler, since we just convert the nodeset to a bool
249  assert(lhs.isBoolean() || rhs.isBoolean());
250 
251  if (lhs.isNodeset())
252  lhs = Value(lhs.toBoolean());
253  else
254  rhs = Value(rhs.toBoolean());
255  } // nodeset comparisons
256 
257 
258  if (opCode == OP_EQ || opCode == OP_NE) {
259  bool equal;
260  if ( lhs.isBoolean() || rhs.isBoolean() ) {
261  equal = ( lhs.toBoolean() == rhs.toBoolean() );
262  } else if ( lhs.isNumber() || rhs.isNumber() ) {
263  equal = ( lhs.toNumber() == rhs.toNumber() );
264  } else {
265  equal = ( lhs.toString() == rhs.toString() );
266  }
267 
268  if ( opCode == OP_EQ )
269  return Value( equal );
270  else
271  return Value( !equal );
272 
273  }
274 
275  // For other ops, we always convert to numbers
276  double leftVal = lhs.toNumber(), rightVal = rhs.toNumber();
277  return Value(compareNumbers(leftVal, rightVal));
278 }
279 
280 
281 bool RelationOp::compareNumbers(double leftVal, double rightVal) const
282 {
283  switch (opCode) {
284  case OP_GT:
285  return leftVal > rightVal;
286  case OP_GE:
287  return leftVal >= rightVal;
288  case OP_LT:
289  return leftVal < rightVal;
290  case OP_LE:
291  return leftVal <= rightVal;
292  case OP_EQ:
293  return leftVal == rightVal;
294  case OP_NE:
295  return leftVal != rightVal;
296  default:
297  assert(0);
298  return false;
299  }
300 }
301 
302 bool RelationOp::compareStrings(const DOM::DOMString& l, const DOM::DOMString& r) const
303 {
304  // String comparisons, as invoked within the nodeset case, are string-based
305  // only for == and !=. Everything else still goes to numbers.
306  if (opCode == OP_EQ)
307  return (l == r);
308  if (opCode == OP_NE)
309  return (l != r);
310 
311  return compareNumbers(Value(l).toNumber(), Value(r).toNumber());
312 }
313 
314 QString RelationOp::opName() const
315 {
316  switch (opCode) {
317  case OP_GT:
318  return QLatin1String( "relationGT" );
319  case OP_GE:
320  return QLatin1String( "relationGE" );
321  case OP_LT:
322  return QLatin1String( "relationLT" );
323  case OP_LE:
324  return QLatin1String( "relationLE" );
325  case OP_EQ:
326  return QLatin1String( "relationEQ" );
327  case OP_NE:
328  return QLatin1String( "relationNE" );
329  default:
330  assert(0);
331  return QString();
332  }
333 }
334 
335 LogicalOp::LogicalOp( int _opCode, Expression* lhs, Expression* rhs ) :
336  opCode( _opCode )
337 {
338  addSubExpression( lhs );
339  addSubExpression( rhs );
340 }
341 
342 bool LogicalOp::shortCircuitOn() const
343 {
344  if (opCode == OP_And)
345  return false; //false and foo
346  else
347  return true; //true or bar
348 }
349 
350 bool LogicalOp::isConstant() const
351 {
352  return subExpr( 0 )->isConstant() &&
353  subExpr( 0 )->evaluate().toBoolean() == shortCircuitOn();
354 }
355 
356 QString LogicalOp::opName() const
357 {
358  if ( opCode == OP_And )
359  return QLatin1String( "conjunction" );
360  else
361  return QLatin1String( "disjunction" );
362 }
363 
364 Value LogicalOp::doEvaluate() const
365 {
366  Value lhs( subExpr( 0 )->evaluate() );
367 
368  // This is not only an optimization, http://www.w3.org/TR/xpath
369  // dictates that we must do short-circuit evaluation
370  bool lhsBool = lhs.toBoolean();
371  if ( lhsBool == shortCircuitOn() ) {
372  return Value( lhsBool );
373  }
374 
375  return Value( subExpr( 1 )->evaluate().toBoolean() );
376 }
377 
378 QString Union::opName() const
379 {
380  return QLatin1String("union");
381 }
382 
383 Value Union::doEvaluate() const
384 {
385  Value lhs = subExpr( 0 )->evaluate();
386  Value rhs = subExpr( 1 )->evaluate();
387  if ( !lhs.isNodeset() || !rhs.isNodeset() ) {
388  kWarning(6011) << "Union operator '|' works only with nodesets.";
389  Expression::reportInvalidExpressionErr();
390  return Value( new StaticNodeListImpl );
391  }
392 
393  DomNodeList lhsNodes = lhs.toNodeset();
394  DomNodeList rhsNodes = rhs.toNodeset();
395  DomNodeList result = new StaticNodeListImpl;
396 
397  for ( unsigned long n = 0; n < lhsNodes->length(); ++n )
398  result->append( lhsNodes->item( n ) );
399 
400  for ( unsigned long n = 0; n < rhsNodes->length(); ++n )
401  result->append( rhsNodes->item( n ) );
402 
403  return Value( result );
404 }
405 
406 Predicate::Predicate( Expression *expr )
407  : m_expr( expr )
408 {
409 }
410 
411 Predicate::~Predicate()
412 {
413  delete m_expr;
414 }
415 
416 bool Predicate::evaluate() const
417 {
418  Q_ASSERT( m_expr != 0 );
419 
420  Value result( m_expr->evaluate() );
421 
422  // foo[3] really means foo[position()=3]
423  if ( result.isNumber() ) {
424  return double( Expression::evaluationContext().position ) == result.toNumber();
425  }
426 
427  return result.toBoolean();
428 }
429 
430 void Predicate::optimize()
431 {
432  m_expr->optimize();
433 }
434 
435 QString Predicate::dump() const
436 {
437  return QString() + "<predicate>" + m_expr->dump() + "</predicate>";
438 }
439 
440 // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
khtml::XPath::Value::toString
DOM::DOMString toString() const
Definition: expression.cpp:160
khtml::XPath::Value::isNodeset
bool isNodeset() const
Definition: expression.cpp:86
khtml::XPath::NumericOp::OP_Sub
Definition: predicate.h:84
khtml::XPath::RelationOp::OP_EQ
Definition: predicate.h:106
khtml::XPath::Value::isNumber
bool isNumber() const
Definition: expression.cpp:96
assert
#define assert(x)
Definition: editor.cpp:43
khtml::XPath::Expression::addSubExpression
void addSubExpression(Expression *expr)
Definition: expression.cpp:237
khtml::XPath::Predicate::optimize
void optimize()
Definition: predicate.cpp:430
khtml::XPath::String::String
String(const DOM::DOMString &value)
Definition: predicate.cpp:62
khtml::XPath::Expression::isConstant
virtual bool isConstant() const
Definition: expression.cpp:278
khtml::XPath::RelationOp::OP_LT
Definition: predicate.h:103
DOM::DOMString::string
QString string() const
Definition: dom_string.cpp:236
double
khtml::XPath::DomNodeList
SharedPtr< DOM::StaticNodeListImpl > DomNodeList
Definition: util.h:41
khtml::XPath::Predicate::dump
QString dump() const
Definition: predicate.cpp:435
khtml::XPath::BinaryExprBase::dump
virtual QString dump() const
Definition: predicate.cpp:93
khtml::XPath::RelationOp::OP_LE
Definition: predicate.h:105
khtml::XPath::LogicalOp::OP_And
Definition: predicate.h:126
khtml::XPath::Value
Definition: expression.h:75
khtml::XPath::Expression::dump
virtual QString dump() const =0
QString::number
QString number(int n, int base)
khtml::XPath::Number::isConstant
bool isConstant() const
Definition: predicate.cpp:47
numify
static void numify(const Value &val, WTF::Vector< double > *out)
Definition: predicate.cpp:188
khtml::XPath::BinaryExprBase::opName
virtual QString opName() const =0
khtml::XPath::Expression::evaluationContext
static EvaluationContext & evaluationContext()
Definition: expression.cpp:212
khtml::XPath::NumericOp::OP_Div
Definition: predicate.h:86
khtml::XPath::Predicate::evaluate
bool evaluate() const
Definition: predicate.cpp:416
khtml::XPath::RelationOp::RelationOp
RelationOp(int opCode, Expression *lhs, Expression *rhs)
Definition: predicate.cpp:166
khtml::XPath::Expression::reportInvalidExpressionErr
static void reportInvalidExpressionErr()
Definition: expression.cpp:288
khtml::XPath::stringValue
DOMString stringValue(NodeImpl *node)
Definition: util.cpp:68
DOM::DOMString
This class implements the basic string we use in the DOM.
Definition: dom_string.h:43
khtml::XPath::String::isConstant
bool isConstant() const
Definition: predicate.cpp:67
khtml::XPath::NumericOp::OP_Mul
Definition: predicate.h:85
QString
khtml::XPath::Value::toBoolean
bool toBoolean() const
Definition: expression.cpp:122
khtml::XPath::LogicalOp::LogicalOp
LogicalOp(int opCode, Expression *lhs, Expression *rhs)
Definition: predicate.cpp:335
khtml::XPath::Expression::evaluate
virtual Value evaluate() const
Definition: expression.cpp:229
khtml::XPath::String::dump
virtual QString dump() const
Definition: predicate.cpp:72
khtml::XPath::Predicate::Predicate
Predicate(Expression *expr)
Definition: predicate.cpp:406
khtml::XPath::LogicalOp::isConstant
virtual bool isConstant() const
Definition: predicate.cpp:350
QLatin1String
khtml::XPath::NumericOp::NumericOp
NumericOp(int opCode, Expression *lhs, Expression *rhs)
Definition: predicate.cpp:102
functions.h
predicate.h
khtml::XPath::NumericOp::OP_Mod
Definition: predicate.h:87
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
khtml::XPath::RelationOp::OP_NE
Definition: predicate.h:107
khtml::XPath::Expression::subExpr
Expression * subExpr(unsigned int i)
Definition: expression.cpp:266
stringify
static void stringify(const Value &val, WTF::Vector< DOMString > *out)
Definition: predicate.cpp:173
khtml::XPath::Expression
Definition: expression.h:114
khtml::XPath::Negative::dump
virtual QString dump() const
Definition: predicate.cpp:88
khtml::XPath::Number::dump
virtual QString dump() const
Definition: predicate.cpp:52
khtml::XPath::Value::isString
bool isString() const
Definition: expression.cpp:101
khtml::XPath::NumericOp::OP_Add
Definition: predicate.h:83
khtml::XPath::Predicate::~Predicate
~Predicate()
Definition: predicate.cpp:411
khtml::XPath::Value::toNodeset
DomNodeList & toNodeset()
Definition: expression.cpp:106
khtml::XPath::Expression::optimize
void optimize()
Definition: expression.cpp:242
khtml::XPath::RelationOp::OP_GT
Definition: predicate.h:102
khtml::XPath::Value::toNumber
double toNumber() const
Definition: expression.cpp:137
khtml::XPath::RelationOp::OP_GE
Definition: predicate.h:104
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:26:19 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal