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