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