Warning, file /frameworks/khtml/src/xpath/expression.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * expression.cc - Copyright 2005 Frerich Raabe <raabe@kde.org>
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  *
0008  * 1. Redistributions of source code must retain the above copyright
0009  *    notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *    notice, this list of conditions and the following disclaimer in the
0012  *    documentation and/or other materials provided with the distribution.
0013  *
0014  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0015  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0016  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0017  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0018  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0019  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0020  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0021  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0022  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0023  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0024  */
0025 #include "expression.h"
0026 #include "xml/dom_nodeimpl.h"
0027 #include "xml/dom_nodelistimpl.h"
0028 #include "dom/dom_exception.h"
0029 #include "dom/dom3_xpath.h"
0030 //#include "xml/dom_stringimpl.h"
0031 
0032 #include <cmath>
0033 
0034 using namespace DOM;
0035 using namespace khtml;
0036 using namespace khtml::XPath;
0037 using namespace std;
0038 
0039 // Use KJS's numeric FP stuff
0040 #include "kjs/JSImmediate.h"
0041 #include "kjs/operations.h"
0042 
0043 Value::Value():
0044     m_type(Number),
0045     m_number(KJS::NaN)
0046 {
0047     // ### remove eventually
0048 }
0049 
0050 Value::Value(NodeImpl *value)
0051     : m_type(Nodeset)
0052 {
0053     m_nodeset = new StaticNodeListImpl;
0054     m_nodeset->append(value);
0055 }
0056 
0057 Value::Value(const DomNodeList &value)
0058     : m_type(Nodeset),
0059       m_nodeset(value)
0060 {
0061 }
0062 
0063 Value::Value(bool value)
0064     : m_type(Boolean),
0065       m_bool(value)
0066 {
0067 }
0068 
0069 Value::Value(double value)
0070     : m_type(Number),
0071       m_number(value)
0072 {
0073 }
0074 
0075 Value::Value(const DOMString &value)
0076     : m_type(String),
0077       m_string(value)
0078 {
0079 }
0080 
0081 Value::Type Value::type() const
0082 {
0083     return m_type;
0084 }
0085 
0086 bool Value::isNodeset() const
0087 {
0088     return m_type == Nodeset;
0089 }
0090 
0091 bool Value::isBoolean() const
0092 {
0093     return m_type == Boolean;
0094 }
0095 
0096 bool Value::isNumber() const
0097 {
0098     return m_type == Number;
0099 }
0100 
0101 bool Value::isString() const
0102 {
0103     return m_type == String;
0104 }
0105 
0106 DomNodeList &Value::toNodeset()
0107 {
0108     if (m_type != Nodeset) {
0109         qCWarning(KHTML_LOG) << "Cannot convert anything to a nodeset.";
0110     }
0111     return m_nodeset;
0112 }
0113 
0114 const DomNodeList &Value::toNodeset() const
0115 {
0116     if (m_type != Nodeset) {
0117         qCWarning(KHTML_LOG) << "Cannot convert anything to a nodeset.";
0118     }
0119     return m_nodeset;
0120 }
0121 
0122 bool Value::toBoolean() const
0123 {
0124     switch (m_type) {
0125     case Nodeset:
0126         return m_nodeset && m_nodeset->length() != 0;
0127     case Boolean:
0128         return m_bool;
0129     case Number:
0130         return m_number != 0;
0131     case String:
0132         return !m_string.isEmpty();
0133     }
0134     return bool();
0135 }
0136 
0137 double Value::toNumber() const
0138 {
0139     switch (m_type) {
0140     case Nodeset:
0141         return Value(toString()).toNumber();
0142     case Number:
0143         return m_number;
0144     case String: {
0145         bool canConvert;
0146         QString s = m_string.string().simplified();
0147         double value = s.toDouble(&canConvert);
0148         if (canConvert) {
0149             return value;
0150         } else {
0151             return KJS::NaN;
0152         }
0153     }
0154     case Boolean:
0155         return m_bool ? 1 : 0;
0156     }
0157     return double();
0158 }
0159 
0160 DOMString Value::toString() const
0161 {
0162     switch (m_type) {
0163     case Nodeset:
0164         if (m_nodeset && m_nodeset->length() == 0) {
0165             return DOMString("");
0166         }
0167         m_nodeset->normalizeUpto(StaticNodeListImpl::AxisOrder);
0168         return stringValue(m_nodeset->item(0));
0169     case String:
0170         return m_string;
0171     case Number:
0172         if (KJS::isNaN(m_number)) {
0173             return DOMString("NaN");
0174         } else if (m_number == 0) {
0175             return DOMString("0");
0176         } else if (KJS::isInf(m_number)) {
0177             if (signbit(m_number) == 0) {
0178                 return DOMString("Infinity");
0179             } else {
0180                 return DOMString("-Infinity");
0181             }
0182         }
0183         return QString::number(m_number);
0184     case Boolean:
0185         return m_bool ? DOMString("true")
0186                : DOMString("false");
0187     }
0188     return DOMString();
0189 }
0190 
0191 QString Value::dump() const
0192 {
0193     QString s = "<value type=\"";
0194     switch (m_type) {
0195     case Nodeset:
0196         s += "nodeset";
0197         break;
0198     case String:
0199         s += "string";
0200         break;
0201     case Number:
0202         s += "number";
0203         break;
0204     case Boolean:
0205         s += "boolean";
0206         break;
0207     };
0208     s += "\">" + toString().string() + "</value>";
0209     return s;
0210 }
0211 
0212 EvaluationContext &Expression::evaluationContext()
0213 {
0214     static EvaluationContext evaluationContext;
0215     return evaluationContext;
0216 }
0217 
0218 Expression::Expression()
0219     : m_constantValue(nullptr)
0220 {
0221 }
0222 
0223 Expression::~Expression()
0224 {
0225     qDeleteAll(m_subExpressions);
0226     delete m_constantValue;
0227 }
0228 
0229 Value Expression::evaluate() const
0230 {
0231     if (m_constantValue) {
0232         return *m_constantValue;
0233     }
0234     return doEvaluate();
0235 }
0236 
0237 void Expression::addSubExpression(Expression *expr)
0238 {
0239     m_subExpressions.append(expr);
0240 }
0241 
0242 void Expression::optimize()
0243 {
0244     bool allSubExpressionsConstant = true;
0245     foreach (Expression *expr, m_subExpressions) {
0246         if (expr->isConstant()) {
0247             expr->optimize();
0248         } else {
0249             allSubExpressionsConstant = false;
0250         }
0251     }
0252 
0253     if (allSubExpressionsConstant) {
0254         m_constantValue = new Value(doEvaluate());
0255 
0256         qDeleteAll(m_subExpressions);
0257         m_subExpressions.clear();
0258     }
0259 }
0260 
0261 unsigned int Expression::subExprCount() const
0262 {
0263     return m_subExpressions.count();
0264 }
0265 
0266 Expression *Expression::subExpr(unsigned int i)
0267 {
0268     Q_ASSERT(i < subExprCount());
0269     return m_subExpressions.at(i);
0270 }
0271 
0272 const Expression *Expression::subExpr(unsigned int i) const
0273 {
0274     Q_ASSERT(i < subExprCount());
0275     return m_subExpressions.at(i);
0276 }
0277 
0278 bool Expression::isConstant() const
0279 {
0280     foreach (Expression *expr, m_subExpressions) {
0281         if (!expr->isConstant()) {
0282             return false;
0283         }
0284     }
0285     return true;
0286 }
0287 
0288 void Expression::reportInvalidExpressionErr()
0289 {
0290     Expression::evaluationContext().reportException(XPathException::toCode(INVALID_EXPRESSION_ERR));
0291 }
0292 
0293 void Expression::reportNamespaceErr()
0294 {
0295     Expression::evaluationContext().reportException(DOMException::NAMESPACE_ERR);
0296 }
0297