KHtml

expression.cpp
1 /*
2  * expression.cc - Copyright 2005 Frerich Raabe <[email protected]>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "expression.h"
26 #include "xml/dom_nodeimpl.h"
27 #include "xml/dom_nodelistimpl.h"
28 #include "dom/dom_exception.h"
29 #include "dom/dom3_xpath.h"
30 //#include "xml/dom_stringimpl.h"
31 
32 #include <cmath>
33 
34 using namespace DOM;
35 using namespace khtml;
36 using namespace khtml::XPath;
37 using namespace std;
38 
39 // Use KJS's numeric FP stuff
40 #include "kjs/JSImmediate.h"
41 #include "kjs/operations.h"
42 
43 Value::Value():
44  m_type(Number),
45  m_number(KJS::NaN)
46 {
47  // ### remove eventually
48 }
49 
50 Value::Value(NodeImpl *value)
51  : m_type(Nodeset)
52 {
53  m_nodeset = new StaticNodeListImpl;
54  m_nodeset->append(value);
55 }
56 
57 Value::Value(const DomNodeList &value)
58  : m_type(Nodeset),
59  m_nodeset(value)
60 {
61 }
62 
63 Value::Value(bool value)
64  : m_type(Boolean),
65  m_bool(value)
66 {
67 }
68 
69 Value::Value(double value)
70  : m_type(Number),
71  m_number(value)
72 {
73 }
74 
75 Value::Value(const DOMString &value)
76  : m_type(String),
77  m_string(value)
78 {
79 }
80 
81 Value::Type Value::type() const
82 {
83  return m_type;
84 }
85 
86 bool Value::isNodeset() const
87 {
88  return m_type == Nodeset;
89 }
90 
91 bool Value::isBoolean() const
92 {
93  return m_type == Boolean;
94 }
95 
96 bool Value::isNumber() const
97 {
98  return m_type == Number;
99 }
100 
101 bool Value::isString() const
102 {
103  return m_type == String;
104 }
105 
106 DomNodeList &Value::toNodeset()
107 {
108  if (m_type != Nodeset) {
109  qCWarning(KHTML_LOG) << "Cannot convert anything to a nodeset.";
110  }
111  return m_nodeset;
112 }
113 
114 const DomNodeList &Value::toNodeset() const
115 {
116  if (m_type != Nodeset) {
117  qCWarning(KHTML_LOG) << "Cannot convert anything to a nodeset.";
118  }
119  return m_nodeset;
120 }
121 
122 bool Value::toBoolean() const
123 {
124  switch (m_type) {
125  case Nodeset:
126  return m_nodeset && m_nodeset->length() != 0;
127  case Boolean:
128  return m_bool;
129  case Number:
130  return m_number != 0;
131  case String:
132  return !m_string.isEmpty();
133  }
134  return bool();
135 }
136 
137 double Value::toNumber() const
138 {
139  switch (m_type) {
140  case Nodeset:
141  return Value(toString()).toNumber();
142  case Number:
143  return m_number;
144  case String: {
145  bool canConvert;
146  QString s = m_string.string().simplified();
147  double value = s.toDouble(&canConvert);
148  if (canConvert) {
149  return value;
150  } else {
151  return KJS::NaN;
152  }
153  }
154  case Boolean:
155  return m_bool ? 1 : 0;
156  }
157  return double();
158 }
159 
160 DOMString Value::toString() const
161 {
162  switch (m_type) {
163  case Nodeset:
164  if (m_nodeset && m_nodeset->length() == 0) {
165  return DOMString("");
166  }
167  m_nodeset->normalizeUpto(StaticNodeListImpl::AxisOrder);
168  return stringValue(m_nodeset->item(0));
169  case String:
170  return m_string;
171  case Number:
172  if (KJS::isNaN(m_number)) {
173  return DOMString("NaN");
174  } else if (m_number == 0) {
175  return DOMString("0");
176  } else if (KJS::isInf(m_number)) {
177  if (signbit(m_number) == 0) {
178  return DOMString("Infinity");
179  } else {
180  return DOMString("-Infinity");
181  }
182  }
183  return QString::number(m_number);
184  case Boolean:
185  return m_bool ? DOMString("true")
186  : DOMString("false");
187  }
188  return DOMString();
189 }
190 
191 QString Value::dump() const
192 {
193  QString s = "<value type=\"";
194  switch (m_type) {
195  case Nodeset:
196  s += "nodeset";
197  break;
198  case String:
199  s += "string";
200  break;
201  case Number:
202  s += "number";
203  break;
204  case Boolean:
205  s += "boolean";
206  break;
207  };
208  s += "\">" + toString().string() + "</value>";
209  return s;
210 }
211 
212 EvaluationContext &Expression::evaluationContext()
213 {
214  static EvaluationContext evaluationContext;
215  return evaluationContext;
216 }
217 
218 Expression::Expression()
219  : m_constantValue(nullptr)
220 {
221 }
222 
223 Expression::~Expression()
224 {
225  qDeleteAll(m_subExpressions);
226  delete m_constantValue;
227 }
228 
229 Value Expression::evaluate() const
230 {
231  if (m_constantValue) {
232  return *m_constantValue;
233  }
234  return doEvaluate();
235 }
236 
237 void Expression::addSubExpression(Expression *expr)
238 {
239  m_subExpressions.append(expr);
240 }
241 
242 void Expression::optimize()
243 {
244  bool allSubExpressionsConstant = true;
245  foreach (Expression *expr, m_subExpressions) {
246  if (expr->isConstant()) {
247  expr->optimize();
248  } else {
249  allSubExpressionsConstant = false;
250  }
251  }
252 
253  if (allSubExpressionsConstant) {
254  m_constantValue = new Value(doEvaluate());
255 
256  qDeleteAll(m_subExpressions);
257  m_subExpressions.clear();
258  }
259 }
260 
261 unsigned int Expression::subExprCount() const
262 {
263  return m_subExpressions.count();
264 }
265 
266 Expression *Expression::subExpr(unsigned int i)
267 {
268  Q_ASSERT(i < subExprCount());
269  return m_subExpressions.at(i);
270 }
271 
272 const Expression *Expression::subExpr(unsigned int i) const
273 {
274  Q_ASSERT(i < subExprCount());
275  return m_subExpressions.at(i);
276 }
277 
278 bool Expression::isConstant() const
279 {
280  foreach (Expression *expr, m_subExpressions) {
281  if (!expr->isConstant()) {
282  return false;
283  }
284  }
285  return true;
286 }
287 
288 void Expression::reportInvalidExpressionErr()
289 {
290  Expression::evaluationContext().reportException(XPathException::toCode(INVALID_EXPRESSION_ERR));
291 }
292 
293 void Expression::reportNamespaceErr()
294 {
295  Expression::evaluationContext().reportException(DOMException::NAMESPACE_ERR);
296 }
297 
This file is part of the HTML rendering engine for KDE.
QString simplified() const const
double toDouble(bool *ok) const const
bool canConvert(const QVariant &value)
QString number(int n, int base)
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
This library provides a full-featured HTML parser and widget.
char * toString(const T &value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Oct 25 2021 22:48:14 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.