Back to index

lightning-sunbird  0.9+nobinonly
RelationalExpr.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * The MITRE Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Keith Visco <kvisco@ziplink.net> (Original Author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "Expr.h"
00040 #include "txNodeSet.h"
00041 #include "txIXPathContext.h"
00042 
00046 PRBool
00047 RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
00048                                txAExprResult* aRight)
00049 {
00050     short ltype = aLeft->getResultType();
00051     short rtype = aRight->getResultType();
00052     nsresult rv = NS_OK;
00053 
00054     // Handle case for just Left NodeSet or Both NodeSets
00055     if (ltype == txAExprResult::NODESET) {
00056         if (rtype == txAExprResult::BOOLEAN) {
00057             BooleanResult leftBool(aLeft->booleanValue());
00058             return compareResults(aContext, &leftBool, aRight);
00059         }
00060 
00061         txNodeSet* nodeSet = NS_STATIC_CAST(txNodeSet*, aLeft);
00062         nsRefPtr<StringResult> strResult;
00063         rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult));
00064         NS_ENSURE_SUCCESS(rv, rv);
00065 
00066         PRInt32 i;
00067         for (i = 0; i < nodeSet->size(); ++i) {
00068             strResult->mValue.Truncate();
00069             txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
00070                                               strResult->mValue);
00071             if (compareResults(aContext, strResult, aRight)) {
00072                 return PR_TRUE;
00073             }
00074         }
00075 
00076         return PR_FALSE;
00077     }
00078 
00079     // Handle case for Just Right NodeSet
00080     if (rtype == txAExprResult::NODESET) {
00081         if (ltype == txAExprResult::BOOLEAN) {
00082             BooleanResult rightBool(aRight->booleanValue());
00083             return compareResults(aContext, aLeft, &rightBool);
00084         }
00085 
00086         txNodeSet* nodeSet = NS_STATIC_CAST(txNodeSet*, aRight);
00087         nsRefPtr<StringResult> strResult;
00088         rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult));
00089         NS_ENSURE_SUCCESS(rv, rv);
00090 
00091         PRInt32 i;
00092         for (i = 0; i < nodeSet->size(); ++i) {
00093             strResult->mValue.Truncate();
00094             txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
00095                                               strResult->mValue);
00096             if (compareResults(aContext, aLeft, strResult)) {
00097                 return PR_TRUE;
00098             }
00099         }
00100 
00101         return PR_FALSE;
00102     }
00103 
00104     // Neither is a NodeSet
00105     if (mOp == EQUAL || mOp == NOT_EQUAL) {
00106         PRBool result;
00107         nsAString *lString, *rString;
00108 
00109         // If either is a bool, compare as bools.
00110         if (ltype == txAExprResult::BOOLEAN ||
00111             rtype == txAExprResult::BOOLEAN) {
00112             result = aLeft->booleanValue() == aRight->booleanValue();
00113         }
00114 
00115         // If either is a number, compare as numbers.
00116         else if (ltype == txAExprResult::NUMBER ||
00117                  rtype == txAExprResult::NUMBER) {
00118             double lval = aLeft->numberValue();
00119             double rval = aRight->numberValue();
00120 #if defined(XP_WIN)
00121             if (Double::isNaN(lval) || Double::isNaN(rval))
00122                 result = PR_FALSE;
00123             else
00124                 result = lval == rval;
00125 #else
00126             result = lval == rval;
00127 #endif
00128         }
00129 
00130         // Otherwise compare as strings. Try to use the stringobject in
00131         // StringResult if possible since that is a common case.
00132         else if ((lString = aLeft->stringValuePointer())) {
00133             if ((rString = aRight->stringValuePointer())) {
00134                 result = lString->Equals(*rString);
00135             }
00136             else {
00137                 nsAutoString rStr;
00138                 aRight->stringValue(rStr);
00139                 result = rStr.Equals(*lString);
00140             }
00141         }
00142         else if ((rString = aRight->stringValuePointer())) {
00143             nsAutoString lStr;
00144             aLeft->stringValue(lStr);
00145             result = rString->Equals(lStr);
00146         }
00147         else {
00148             nsAutoString lStr, rStr;
00149             aLeft->stringValue(lStr);
00150             aRight->stringValue(rStr);
00151             result = lStr.Equals(rStr);
00152         }
00153 
00154         return mOp == EQUAL ? result : !result;
00155     }
00156 
00157     double leftDbl = aLeft->numberValue();
00158     double rightDbl = aRight->numberValue();
00159 #if defined(XP_WIN)
00160     if (Double::isNaN(leftDbl) || Double::isNaN(rightDbl))
00161         return PR_FALSE;
00162 #endif
00163 
00164     switch (mOp) {
00165         case LESS_THAN:
00166         {
00167             return leftDbl < rightDbl;
00168         }
00169         case LESS_OR_EQUAL:
00170         {
00171             return leftDbl <= rightDbl;
00172         }
00173         case GREATER_THAN:
00174         {
00175             return leftDbl > rightDbl;
00176         }
00177         case GREATER_OR_EQUAL:
00178         {
00179             return leftDbl >= rightDbl;
00180         }
00181         default:
00182         {
00183             NS_NOTREACHED("We should have caught all cases");
00184         }
00185     }
00186 
00187     return PR_FALSE;
00188 }
00189 
00190 nsresult
00191 RelationalExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
00192 {
00193     *aResult = nsnull;
00194     nsRefPtr<txAExprResult> lResult;
00195     nsresult rv = mLeftExpr->evaluate(aContext, getter_AddRefs(lResult));
00196     NS_ENSURE_SUCCESS(rv, rv);
00197 
00198     nsRefPtr<txAExprResult> rResult;
00199     rv = mRightExpr->evaluate(aContext, getter_AddRefs(rResult));
00200     NS_ENSURE_SUCCESS(rv, rv);
00201     
00202     aContext->recycler()->
00203         getBoolResult(compareResults(aContext, lResult, rResult), aResult);
00204 
00205     return NS_OK;
00206 }
00207 
00208 #ifdef TX_TO_STRING
00209 void
00210 RelationalExpr::toString(nsAString& str)
00211 {
00212     mLeftExpr->toString(str);
00213 
00214     switch (mOp) {
00215         case NOT_EQUAL:
00216             str.AppendLiteral("!=");
00217             break;
00218         case LESS_THAN:
00219             str.Append(PRUnichar('<'));
00220             break;
00221         case LESS_OR_EQUAL:
00222             str.AppendLiteral("<=");
00223             break;
00224         case GREATER_THAN :
00225             str.Append(PRUnichar('>'));
00226             break;
00227         case GREATER_OR_EQUAL:
00228             str.AppendLiteral(">=");
00229             break;
00230         default:
00231             str.Append(PRUnichar('='));
00232             break;
00233     }
00234 
00235     mRightExpr->toString(str);
00236 }
00237 #endif