Bug 1874684 - Part 4: Prefer const references instead of copying Instant values....
[gecko.git] / dom / xslt / xpath / txLocationStep.cpp
blobc10d9e8cb1122d900cc0fd06786701a146230942
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/. */
6 /*
7 Implementation of an XPath LocationStep
8 */
10 #include "txExpr.h"
11 #include "txIXPathContext.h"
12 #include "txNodeSet.h"
13 #include "txXPathTreeWalker.h"
15 //-----------------------------/
16 //- Virtual methods from Expr -/
17 //-----------------------------/
19 /**
20 * Evaluates this Expr based on the given context node and processor state
21 * @param context the context node for evaluation of this Expr
22 * @param ps the ProcessorState containing the stack information needed
23 * for evaluation
24 * @return the result of the evaluation
25 * @see Expr
26 **/
27 nsresult LocationStep::evaluate(txIEvalContext* aContext,
28 txAExprResult** aResult) {
29 NS_ASSERTION(aContext, "internal error");
30 *aResult = nullptr;
32 RefPtr<txNodeSet> nodes;
33 nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
34 NS_ENSURE_SUCCESS(rv, rv);
36 txXPathTreeWalker walker(aContext->getContextNode());
38 switch (mAxisIdentifier) {
39 case ANCESTOR_AXIS: {
40 if (!walker.moveToParent()) {
41 break;
43 [[fallthrough]];
45 case ANCESTOR_OR_SELF_AXIS: {
46 nodes->setReverse();
48 do {
49 rv = appendIfMatching(walker, aContext, nodes);
50 NS_ENSURE_SUCCESS(rv, rv);
51 } while (walker.moveToParent());
53 break;
55 case ATTRIBUTE_AXIS: {
56 if (!walker.moveToFirstAttribute()) {
57 break;
60 do {
61 rv = appendIfMatching(walker, aContext, nodes);
62 NS_ENSURE_SUCCESS(rv, rv);
63 } while (walker.moveToNextAttribute());
64 break;
66 case DESCENDANT_OR_SELF_AXIS: {
67 rv = appendIfMatching(walker, aContext, nodes);
68 NS_ENSURE_SUCCESS(rv, rv);
69 [[fallthrough]];
71 case DESCENDANT_AXIS: {
72 rv = appendMatchingDescendants(walker, aContext, nodes);
73 NS_ENSURE_SUCCESS(rv, rv);
74 break;
76 case FOLLOWING_AXIS: {
77 if (txXPathNodeUtils::isAttribute(walker.getCurrentPosition())) {
78 walker.moveToParent();
79 rv = appendMatchingDescendants(walker, aContext, nodes);
80 NS_ENSURE_SUCCESS(rv, rv);
82 bool cont = true;
83 while (!walker.moveToNextSibling()) {
84 if (!walker.moveToParent()) {
85 cont = false;
86 break;
89 while (cont) {
90 rv = appendIfMatching(walker, aContext, nodes);
91 NS_ENSURE_SUCCESS(rv, rv);
93 rv = appendMatchingDescendants(walker, aContext, nodes);
94 NS_ENSURE_SUCCESS(rv, rv);
96 while (!walker.moveToNextSibling()) {
97 if (!walker.moveToParent()) {
98 cont = false;
99 break;
103 break;
105 case FOLLOWING_SIBLING_AXIS: {
106 while (walker.moveToNextSibling()) {
107 rv = appendIfMatching(walker, aContext, nodes);
108 NS_ENSURE_SUCCESS(rv, rv);
110 break;
112 case NAMESPACE_AXIS: //-- not yet implemented
113 #if 0
114 // XXX DEBUG OUTPUT
115 cout << "namespace axis not yet implemented"<<endl;
116 #endif
117 break;
118 case PARENT_AXIS: {
119 if (walker.moveToParent()) {
120 rv = appendIfMatching(walker, aContext, nodes);
121 NS_ENSURE_SUCCESS(rv, rv);
123 break;
125 case PRECEDING_AXIS: {
126 nodes->setReverse();
128 bool cont = true;
129 while (!walker.moveToPreviousSibling()) {
130 if (!walker.moveToParent()) {
131 cont = false;
132 break;
135 while (cont) {
136 rv = appendMatchingDescendantsRev(walker, aContext, nodes);
137 NS_ENSURE_SUCCESS(rv, rv);
139 rv = appendIfMatching(walker, aContext, nodes);
140 NS_ENSURE_SUCCESS(rv, rv);
142 while (!walker.moveToPreviousSibling()) {
143 if (!walker.moveToParent()) {
144 cont = false;
145 break;
149 break;
151 case PRECEDING_SIBLING_AXIS: {
152 nodes->setReverse();
154 while (walker.moveToPreviousSibling()) {
155 rv = appendIfMatching(walker, aContext, nodes);
156 NS_ENSURE_SUCCESS(rv, rv);
158 break;
160 case SELF_AXIS: {
161 rv = appendIfMatching(walker, aContext, nodes);
162 NS_ENSURE_SUCCESS(rv, rv);
163 break;
165 default: // Children Axis
167 if (!walker.moveToFirstChild()) {
168 break;
171 do {
172 rv = appendIfMatching(walker, aContext, nodes);
173 NS_ENSURE_SUCCESS(rv, rv);
174 } while (walker.moveToNextSibling());
175 break;
179 // Apply predicates
180 if (!isEmpty()) {
181 rv = evaluatePredicates(nodes, aContext);
182 NS_ENSURE_SUCCESS(rv, rv);
185 nodes->unsetReverse();
187 NS_ADDREF(*aResult = nodes);
189 return NS_OK;
192 nsresult LocationStep::appendIfMatching(const txXPathTreeWalker& aWalker,
193 txIMatchContext* aContext,
194 txNodeSet* aNodes) {
195 bool matched;
196 const txXPathNode& child = aWalker.getCurrentPosition();
197 nsresult rv = mNodeTest->matches(child, aContext, matched);
198 NS_ENSURE_SUCCESS(rv, rv);
200 if (matched) {
201 aNodes->append(child);
203 return NS_OK;
206 nsresult LocationStep::appendMatchingDescendants(
207 const txXPathTreeWalker& aWalker, txIMatchContext* aContext,
208 txNodeSet* aNodes) {
209 txXPathTreeWalker walker(aWalker);
210 if (!walker.moveToFirstChild()) {
211 return NS_OK;
214 do {
215 nsresult rv = appendIfMatching(walker, aContext, aNodes);
216 NS_ENSURE_SUCCESS(rv, rv);
218 rv = appendMatchingDescendants(walker, aContext, aNodes);
219 NS_ENSURE_SUCCESS(rv, rv);
220 } while (walker.moveToNextSibling());
222 return NS_OK;
225 nsresult LocationStep::appendMatchingDescendantsRev(
226 const txXPathTreeWalker& aWalker, txIMatchContext* aContext,
227 txNodeSet* aNodes) {
228 txXPathTreeWalker walker(aWalker);
229 if (!walker.moveToLastChild()) {
230 return NS_OK;
233 do {
234 nsresult rv = appendMatchingDescendantsRev(walker, aContext, aNodes);
235 NS_ENSURE_SUCCESS(rv, rv);
237 rv = appendIfMatching(walker, aContext, aNodes);
238 NS_ENSURE_SUCCESS(rv, rv);
239 } while (walker.moveToPreviousSibling());
241 return NS_OK;
244 Expr::ExprType LocationStep::getType() { return LOCATIONSTEP_EXPR; }
246 TX_IMPL_EXPR_STUBS_BASE(LocationStep, NODESET_RESULT)
248 Expr* LocationStep::getSubExprAt(uint32_t aPos) {
249 return PredicateList::getSubExprAt(aPos);
252 void LocationStep::setSubExprAt(uint32_t aPos, Expr* aExpr) {
253 PredicateList::setSubExprAt(aPos, aExpr);
256 bool LocationStep::isSensitiveTo(ContextSensitivity aContext) {
257 return (aContext & NODE_CONTEXT) || mNodeTest->isSensitiveTo(aContext) ||
258 PredicateList::isSensitiveTo(aContext);
261 #ifdef TX_TO_STRING
262 void LocationStep::toString(nsAString& str) {
263 switch (mAxisIdentifier) {
264 case ANCESTOR_AXIS:
265 str.AppendLiteral("ancestor::");
266 break;
267 case ANCESTOR_OR_SELF_AXIS:
268 str.AppendLiteral("ancestor-or-self::");
269 break;
270 case ATTRIBUTE_AXIS:
271 str.Append(char16_t('@'));
272 break;
273 case DESCENDANT_AXIS:
274 str.AppendLiteral("descendant::");
275 break;
276 case DESCENDANT_OR_SELF_AXIS:
277 str.AppendLiteral("descendant-or-self::");
278 break;
279 case FOLLOWING_AXIS:
280 str.AppendLiteral("following::");
281 break;
282 case FOLLOWING_SIBLING_AXIS:
283 str.AppendLiteral("following-sibling::");
284 break;
285 case NAMESPACE_AXIS:
286 str.AppendLiteral("namespace::");
287 break;
288 case PARENT_AXIS:
289 str.AppendLiteral("parent::");
290 break;
291 case PRECEDING_AXIS:
292 str.AppendLiteral("preceding::");
293 break;
294 case PRECEDING_SIBLING_AXIS:
295 str.AppendLiteral("preceding-sibling::");
296 break;
297 case SELF_AXIS:
298 str.AppendLiteral("self::");
299 break;
300 default:
301 break;
303 NS_ASSERTION(mNodeTest, "mNodeTest is null, that's verboten");
304 mNodeTest->toString(str);
306 PredicateList::toString(str);
308 #endif