txRelationalExpr.cpp 5.9 KB

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