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/. */
8 #include "txIXPathContext.h"
9 #include "txXPathTreeWalker.h"
12 * Compares the two ExprResults based on XPath 1.0 Recommendation (section 3.4)
14 bool RelationalExpr::compareResults(txIEvalContext
* aContext
,
16 txAExprResult
* aRight
) {
17 short ltype
= aLeft
->getResultType();
18 short rtype
= aRight
->getResultType();
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
);
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);
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
)) {
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
);
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);
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
)) {
69 // Neither is a NodeSet
70 if (mOp
== EQUAL
|| mOp
== NOT_EQUAL
) {
72 const nsString
*lString
, *rString
;
74 // If either is a bool, compare as bools.
75 if (ltype
== txAExprResult::BOOLEAN
|| rtype
== txAExprResult::BOOLEAN
) {
76 result
= aLeft
->booleanValue() == aRight
->booleanValue();
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
);
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
);
93 aRight
->stringValue(rStr
);
94 result
= lString
->Equals(rStr
);
96 } else if ((rString
= aRight
->stringValuePointer())) {
98 aLeft
->stringValue(lStr
);
99 result
= rString
->Equals(lStr
);
101 nsAutoString lStr
, rStr
;
102 aLeft
->stringValue(lStr
);
103 aRight
->stringValue(rStr
);
104 result
= lStr
.Equals(rStr
);
107 return mOp
== EQUAL
? result
: !result
;
110 double leftDbl
= aLeft
->numberValue();
111 double rightDbl
= aRight
->numberValue();
114 return (leftDbl
< rightDbl
);
116 case LESS_OR_EQUAL
: {
117 return (leftDbl
<= rightDbl
);
120 return (leftDbl
> rightDbl
);
122 case GREATER_OR_EQUAL
: {
123 return (leftDbl
>= rightDbl
);
126 MOZ_ASSERT_UNREACHABLE("We should have caught all cases");
133 nsresult
RelationalExpr::evaluate(txIEvalContext
* aContext
,
134 txAExprResult
** aResult
) {
136 RefPtr
<txAExprResult
> lResult
;
137 nsresult rv
= mLeftExpr
->evaluate(aContext
, getter_AddRefs(lResult
));
138 NS_ENSURE_SUCCESS(rv
, rv
);
140 RefPtr
<txAExprResult
> rResult
;
141 rv
= mRightExpr
->evaluate(aContext
, getter_AddRefs(rResult
));
142 NS_ENSURE_SUCCESS(rv
, rv
);
144 aContext
->recycler()->getBoolResult(
145 compareResults(aContext
, lResult
, rResult
), aResult
);
150 TX_IMPL_EXPR_STUBS_2(RelationalExpr
, BOOLEAN_RESULT
, mLeftExpr
, mRightExpr
)
152 bool RelationalExpr::isSensitiveTo(ContextSensitivity aContext
) {
153 return mLeftExpr
->isSensitiveTo(aContext
) ||
154 mRightExpr
->isSensitiveTo(aContext
);
158 void RelationalExpr::toString(nsAString
& str
) {
159 mLeftExpr
->toString(str
);
163 str
.AppendLiteral("!=");
166 str
.Append(char16_t('<'));
169 str
.AppendLiteral("<=");
172 str
.Append(char16_t('>'));
174 case GREATER_OR_EQUAL
:
175 str
.AppendLiteral(">=");
178 str
.Append(char16_t('='));
182 mRightExpr
->toString(str
);