KHTML
expression.cpp
Go to the documentation of this file.
00001 /* 00002 * expression.cc - Copyright 2005 Frerich Raabe <raabe@kde.org> 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 00014 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00017 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00024 */ 00025 #include "expression.h" 00026 #include "xml/dom_nodeimpl.h" 00027 #include "xml/dom_nodelistimpl.h" 00028 #include "dom/dom_exception.h" 00029 #include "dom/dom3_xpath.h" 00030 //#include "xml/dom_stringimpl.h" 00031 00032 #include <cmath> 00033 00034 using namespace DOM; 00035 using namespace khtml; 00036 using namespace khtml::XPath; 00037 using namespace std; 00038 00039 // Use KJS's numeric FP stuff 00040 #include "kjs/JSImmediate.h" 00041 #include "kjs/operations.h" 00042 00043 Value::Value(): 00044 m_type ( Number ), 00045 m_number( KJS::NaN ) 00046 { 00047 // ### remove eventually 00048 } 00049 00050 Value::Value( NodeImpl *value ) 00051 : m_type( Nodeset ) 00052 { 00053 m_nodeset = new StaticNodeListImpl; 00054 m_nodeset->append( value ); 00055 } 00056 00057 Value::Value( const DomNodeList &value ) 00058 : m_type( Nodeset ), 00059 m_nodeset( value ) 00060 { 00061 } 00062 00063 Value::Value( bool value ) 00064 : m_type( Boolean ), 00065 m_bool( value ) 00066 { 00067 } 00068 00069 Value::Value( double value ) 00070 : m_type( Number ), 00071 m_number( value ) 00072 { 00073 } 00074 00075 Value::Value( const DOMString &value ) 00076 : m_type( String ), 00077 m_string( value ) 00078 { 00079 } 00080 00081 Value::Type Value::type() const 00082 { 00083 return m_type; 00084 } 00085 00086 bool Value::isNodeset() const 00087 { 00088 return m_type == Nodeset; 00089 } 00090 00091 bool Value::isBoolean() const 00092 { 00093 return m_type == Boolean; 00094 } 00095 00096 bool Value::isNumber() const 00097 { 00098 return m_type == Number; 00099 } 00100 00101 bool Value::isString() const 00102 { 00103 return m_type == String; 00104 } 00105 00106 DomNodeList &Value::toNodeset() 00107 { 00108 if ( m_type != Nodeset ) { 00109 kWarning(6011) << "Cannot convert anything to a nodeset."; 00110 } 00111 return m_nodeset; 00112 } 00113 00114 const DomNodeList &Value::toNodeset() const 00115 { 00116 if ( m_type != Nodeset ) { 00117 kWarning(6011) << "Cannot convert anything to a nodeset."; 00118 } 00119 return m_nodeset; 00120 } 00121 00122 bool Value::toBoolean() const 00123 { 00124 switch ( m_type ) { 00125 case Nodeset: 00126 return m_nodeset && m_nodeset->length() != 0; 00127 case Boolean: 00128 return m_bool; 00129 case Number: 00130 return m_number != 0; 00131 case String: 00132 return !m_string.isEmpty(); 00133 } 00134 return bool(); 00135 } 00136 00137 double Value::toNumber() const 00138 { 00139 switch ( m_type ) { 00140 case Nodeset: 00141 return Value( toString() ).toNumber(); 00142 case Number: 00143 return m_number; 00144 case String: { 00145 bool canConvert; 00146 QString s = m_string.string().simplified(); 00147 double value = s.toDouble( &canConvert ); 00148 if ( canConvert ) { 00149 return value; 00150 } else { 00151 return KJS::NaN; 00152 } 00153 } 00154 case Boolean: 00155 return m_bool ? 1 : 0; 00156 } 00157 return double(); 00158 } 00159 00160 DOMString Value::toString() const 00161 { 00162 switch ( m_type ) { 00163 case Nodeset: 00164 if ( m_nodeset && m_nodeset->length() == 0 ) { 00165 return DOMString( "" ); 00166 } 00167 m_nodeset->normalizeUpto( StaticNodeListImpl::AxisOrder ); 00168 return stringValue( m_nodeset->item(0) ); 00169 case String: 00170 return m_string; 00171 case Number: 00172 if ( KJS::isNaN( m_number ) ) { 00173 return DOMString( "NaN" ); 00174 } else if ( m_number == 0 ) { 00175 return DOMString( "0" ); 00176 } else if ( KJS::isInf( m_number ) ) { 00177 if ( signbit( m_number ) == 0 ) { 00178 return DOMString( "Infinity" ); 00179 } else { 00180 return DOMString( "-Infinity" ); 00181 } 00182 } 00183 return QString::number( m_number ); 00184 case Boolean: 00185 return m_bool ? DOMString( "true" ) 00186 : DOMString( "false" ); 00187 } 00188 return DOMString(); 00189 } 00190 00191 QString Value::dump() const 00192 { 00193 QString s = "<value type=\""; 00194 switch ( m_type ) { 00195 case Nodeset: 00196 s += "nodeset"; 00197 break; 00198 case String: 00199 s += "string"; 00200 break; 00201 case Number: 00202 s += "number"; 00203 break; 00204 case Boolean: 00205 s += "boolean"; 00206 break; 00207 }; 00208 s += "\">" + toString().string() + "</value>"; 00209 return s; 00210 } 00211 00212 EvaluationContext &Expression::evaluationContext() 00213 { 00214 static EvaluationContext evaluationContext; 00215 return evaluationContext; 00216 } 00217 00218 Expression::Expression() 00219 : m_constantValue( 0 ) 00220 { 00221 } 00222 00223 Expression::~Expression() 00224 { 00225 qDeleteAll( m_subExpressions ); 00226 delete m_constantValue; 00227 } 00228 00229 Value Expression::evaluate() const 00230 { 00231 if ( m_constantValue ) { 00232 return *m_constantValue; 00233 } 00234 return doEvaluate(); 00235 } 00236 00237 void Expression::addSubExpression( Expression *expr ) 00238 { 00239 m_subExpressions.append( expr ); 00240 } 00241 00242 void Expression::optimize() 00243 { 00244 bool allSubExpressionsConstant = true; 00245 foreach( Expression *expr, m_subExpressions ) { 00246 if ( expr->isConstant() ) { 00247 expr->optimize(); 00248 } else { 00249 allSubExpressionsConstant = false; 00250 } 00251 } 00252 00253 if ( allSubExpressionsConstant ) { 00254 m_constantValue = new Value( doEvaluate() ); 00255 00256 qDeleteAll( m_subExpressions ); 00257 m_subExpressions.clear(); 00258 } 00259 } 00260 00261 unsigned int Expression::subExprCount() const 00262 { 00263 return m_subExpressions.count(); 00264 } 00265 00266 Expression *Expression::subExpr( unsigned int i ) 00267 { 00268 Q_ASSERT( i < subExprCount() ); 00269 return m_subExpressions.at( i ); 00270 } 00271 00272 const Expression *Expression::subExpr( unsigned int i ) const 00273 { 00274 Q_ASSERT( i < subExprCount() ); 00275 return m_subExpressions.at( i ); 00276 } 00277 00278 bool Expression::isConstant() const 00279 { 00280 foreach( Expression *expr, m_subExpressions ) { 00281 if ( !expr->isConstant() ) { 00282 return false; 00283 } 00284 } 00285 return true; 00286 } 00287 00288 void Expression::reportInvalidExpressionErr() 00289 { 00290 Expression::evaluationContext().reportException(XPathException::toCode(INVALID_EXPRESSION_ERR)); 00291 } 00292 00293 void Expression::reportNamespaceErr() 00294 { 00295 Expression::evaluationContext().reportException(DOMException::NAMESPACE_ERR); 00296 } 00297 00298 // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
KDE 4.6 API Reference