txRelationalExpr.cpp (5380B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "txExpr.h" 7 #include "txIXPathContext.h" 8 #include "txNodeSet.h" 9 #include "txXPathTreeWalker.h" 10 11 /** 12 * Compares the two ExprResults based on XPath 1.0 Recommendation (section 3.4) 13 */ 14 bool RelationalExpr::compareResults(txIEvalContext* aContext, 15 txAExprResult* aLeft, 16 txAExprResult* aRight) { 17 short ltype = aLeft->getResultType(); 18 short rtype = aRight->getResultType(); 19 nsresult rv = NS_OK; 20 21 // Handle case for just Left NodeSet or Both NodeSets 22 if (ltype == txAExprResult::NODESET) { 23 if (rtype == txAExprResult::BOOLEAN) { 24 BooleanResult leftBool(aLeft->booleanValue()); 25 return compareResults(aContext, &leftBool, aRight); 26 } 27 28 txNodeSet* nodeSet = static_cast<txNodeSet*>(aLeft); 29 RefPtr<StringResult> strResult; 30 rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult)); 31 NS_ENSURE_SUCCESS(rv, false); 32 33 int32_t i; 34 for (i = 0; i < nodeSet->size(); ++i) { 35 strResult->mValue.Truncate(); 36 txXPathNodeUtils::appendNodeValue(nodeSet->get(i), strResult->mValue); 37 if (compareResults(aContext, strResult, aRight)) { 38 return true; 39 } 40 } 41 42 return false; 43 } 44 45 // Handle case for Just Right NodeSet 46 if (rtype == txAExprResult::NODESET) { 47 if (ltype == txAExprResult::BOOLEAN) { 48 BooleanResult rightBool(aRight->booleanValue()); 49 return compareResults(aContext, aLeft, &rightBool); 50 } 51 52 txNodeSet* nodeSet = static_cast<txNodeSet*>(aRight); 53 RefPtr<StringResult> strResult; 54 rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult)); 55 NS_ENSURE_SUCCESS(rv, false); 56 57 int32_t i; 58 for (i = 0; i < nodeSet->size(); ++i) { 59 strResult->mValue.Truncate(); 60 txXPathNodeUtils::appendNodeValue(nodeSet->get(i), strResult->mValue); 61 if (compareResults(aContext, aLeft, strResult)) { 62 return true; 63 } 64 } 65 66 return false; 67 } 68 69 // Neither is a NodeSet 70 if (mOp == EQUAL || mOp == NOT_EQUAL) { 71 bool result; 72 const nsString *lString, *rString; 73 74 // If either is a bool, compare as bools. 75 if (ltype == txAExprResult::BOOLEAN || rtype == txAExprResult::BOOLEAN) { 76 result = aLeft->booleanValue() == aRight->booleanValue(); 77 } 78 79 // If either is a number, compare as numbers. 80 else if (ltype == txAExprResult::NUMBER || rtype == txAExprResult::NUMBER) { 81 double lval = aLeft->numberValue(); 82 double rval = aRight->numberValue(); 83 result = (lval == rval); 84 } 85 86 // Otherwise compare as strings. Try to use the stringobject in 87 // StringResult if possible since that is a common case. 88 else if ((lString = aLeft->stringValuePointer())) { 89 if ((rString = aRight->stringValuePointer())) { 90 result = lString->Equals(*rString); 91 } else { 92 nsAutoString rStr; 93 aRight->stringValue(rStr); 94 result = lString->Equals(rStr); 95 } 96 } else if ((rString = aRight->stringValuePointer())) { 97 nsAutoString lStr; 98 aLeft->stringValue(lStr); 99 result = rString->Equals(lStr); 100 } else { 101 nsAutoString lStr, rStr; 102 aLeft->stringValue(lStr); 103 aRight->stringValue(rStr); 104 result = lStr.Equals(rStr); 105 } 106 107 return mOp == EQUAL ? result : !result; 108 } 109 110 double leftDbl = aLeft->numberValue(); 111 double rightDbl = aRight->numberValue(); 112 switch (mOp) { 113 case LESS_THAN: { 114 return (leftDbl < rightDbl); 115 } 116 case LESS_OR_EQUAL: { 117 return (leftDbl <= rightDbl); 118 } 119 case GREATER_THAN: { 120 return (leftDbl > rightDbl); 121 } 122 case GREATER_OR_EQUAL: { 123 return (leftDbl >= rightDbl); 124 } 125 default: { 126 MOZ_ASSERT_UNREACHABLE("We should have caught all cases"); 127 } 128 } 129 130 return false; 131 } 132 133 nsresult RelationalExpr::evaluate(txIEvalContext* aContext, 134 txAExprResult** aResult) { 135 *aResult = nullptr; 136 RefPtr<txAExprResult> lResult; 137 nsresult rv = mLeftExpr->evaluate(aContext, getter_AddRefs(lResult)); 138 NS_ENSURE_SUCCESS(rv, rv); 139 140 RefPtr<txAExprResult> rResult; 141 rv = mRightExpr->evaluate(aContext, getter_AddRefs(rResult)); 142 NS_ENSURE_SUCCESS(rv, rv); 143 144 aContext->recycler()->getBoolResult( 145 compareResults(aContext, lResult, rResult), aResult); 146 147 return NS_OK; 148 } 149 150 TX_IMPL_EXPR_STUBS_2(RelationalExpr, BOOLEAN_RESULT, mLeftExpr, mRightExpr) 151 152 bool RelationalExpr::isSensitiveTo(ContextSensitivity aContext) { 153 return mLeftExpr->isSensitiveTo(aContext) || 154 mRightExpr->isSensitiveTo(aContext); 155 } 156 157 #ifdef TX_TO_STRING 158 void RelationalExpr::toString(nsAString& str) { 159 mLeftExpr->toString(str); 160 161 switch (mOp) { 162 case NOT_EQUAL: 163 str.AppendLiteral("!="); 164 break; 165 case LESS_THAN: 166 str.Append(char16_t('<')); 167 break; 168 case LESS_OR_EQUAL: 169 str.AppendLiteral("<="); 170 break; 171 case GREATER_THAN: 172 str.Append(char16_t('>')); 173 break; 174 case GREATER_OR_EQUAL: 175 str.AppendLiteral(">="); 176 break; 177 default: 178 str.Append(char16_t('=')); 179 break; 180 } 181 182 mRightExpr->toString(str); 183 } 184 #endif