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 /*
7   Implementation of an XPath LocationStep
8 */
9 
10 #include "txExpr.h"
11 #include "txIXPathContext.h"
12 #include "txNodeSet.h"
13 #include "txXPathTreeWalker.h"
14 
15 //-----------------------------/
16 //- Virtual methods from Expr -/
17 //-----------------------------/
18 
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  **/
evaluate(txIEvalContext * aContext,txAExprResult ** aResult)27 nsresult LocationStep::evaluate(txIEvalContext* aContext,
28                                 txAExprResult** aResult) {
29   NS_ASSERTION(aContext, "internal error");
30   *aResult = nullptr;
31 
32   RefPtr<txNodeSet> nodes;
33   nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
34   NS_ENSURE_SUCCESS(rv, rv);
35 
36   txXPathTreeWalker walker(aContext->getContextNode());
37 
38   switch (mAxisIdentifier) {
39     case ANCESTOR_AXIS: {
40       if (!walker.moveToParent()) {
41         break;
42       }
43       [[fallthrough]];
44     }
45     case ANCESTOR_OR_SELF_AXIS: {
46       nodes->setReverse();
47 
48       do {
49         rv = appendIfMatching(walker, aContext, nodes);
50         NS_ENSURE_SUCCESS(rv, rv);
51       } while (walker.moveToParent());
52 
53       break;
54     }
55     case ATTRIBUTE_AXIS: {
56       if (!walker.moveToFirstAttribute()) {
57         break;
58       }
59 
60       do {
61         rv = appendIfMatching(walker, aContext, nodes);
62         NS_ENSURE_SUCCESS(rv, rv);
63       } while (walker.moveToNextAttribute());
64       break;
65     }
66     case DESCENDANT_OR_SELF_AXIS: {
67       rv = appendIfMatching(walker, aContext, nodes);
68       NS_ENSURE_SUCCESS(rv, rv);
69       [[fallthrough]];
70     }
71     case DESCENDANT_AXIS: {
72       rv = appendMatchingDescendants(walker, aContext, nodes);
73       NS_ENSURE_SUCCESS(rv, rv);
74       break;
75     }
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);
81       }
82       bool cont = true;
83       while (!walker.moveToNextSibling()) {
84         if (!walker.moveToParent()) {
85           cont = false;
86           break;
87         }
88       }
89       while (cont) {
90         rv = appendIfMatching(walker, aContext, nodes);
91         NS_ENSURE_SUCCESS(rv, rv);
92 
93         rv = appendMatchingDescendants(walker, aContext, nodes);
94         NS_ENSURE_SUCCESS(rv, rv);
95 
96         while (!walker.moveToNextSibling()) {
97           if (!walker.moveToParent()) {
98             cont = false;
99             break;
100           }
101         }
102       }
103       break;
104     }
105     case FOLLOWING_SIBLING_AXIS: {
106       while (walker.moveToNextSibling()) {
107         rv = appendIfMatching(walker, aContext, nodes);
108         NS_ENSURE_SUCCESS(rv, rv);
109       }
110       break;
111     }
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);
122       }
123       break;
124     }
125     case PRECEDING_AXIS: {
126       nodes->setReverse();
127 
128       bool cont = true;
129       while (!walker.moveToPreviousSibling()) {
130         if (!walker.moveToParent()) {
131           cont = false;
132           break;
133         }
134       }
135       while (cont) {
136         rv = appendMatchingDescendantsRev(walker, aContext, nodes);
137         NS_ENSURE_SUCCESS(rv, rv);
138 
139         rv = appendIfMatching(walker, aContext, nodes);
140         NS_ENSURE_SUCCESS(rv, rv);
141 
142         while (!walker.moveToPreviousSibling()) {
143           if (!walker.moveToParent()) {
144             cont = false;
145             break;
146           }
147         }
148       }
149       break;
150     }
151     case PRECEDING_SIBLING_AXIS: {
152       nodes->setReverse();
153 
154       while (walker.moveToPreviousSibling()) {
155         rv = appendIfMatching(walker, aContext, nodes);
156         NS_ENSURE_SUCCESS(rv, rv);
157       }
158       break;
159     }
160     case SELF_AXIS: {
161       rv = appendIfMatching(walker, aContext, nodes);
162       NS_ENSURE_SUCCESS(rv, rv);
163       break;
164     }
165     default:  // Children Axis
166     {
167       if (!walker.moveToFirstChild()) {
168         break;
169       }
170 
171       do {
172         rv = appendIfMatching(walker, aContext, nodes);
173         NS_ENSURE_SUCCESS(rv, rv);
174       } while (walker.moveToNextSibling());
175       break;
176     }
177   }
178 
179   // Apply predicates
180   if (!isEmpty()) {
181     rv = evaluatePredicates(nodes, aContext);
182     NS_ENSURE_SUCCESS(rv, rv);
183   }
184 
185   nodes->unsetReverse();
186 
187   NS_ADDREF(*aResult = nodes);
188 
189   return NS_OK;
190 }
191 
appendIfMatching(const txXPathTreeWalker & aWalker,txIMatchContext * aContext,txNodeSet * aNodes)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);
199 
200   if (matched) {
201     aNodes->append(child);
202   }
203   return NS_OK;
204 }
205 
appendMatchingDescendants(const txXPathTreeWalker & aWalker,txIMatchContext * aContext,txNodeSet * aNodes)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;
212   }
213 
214   do {
215     nsresult rv = appendIfMatching(walker, aContext, aNodes);
216     NS_ENSURE_SUCCESS(rv, rv);
217 
218     rv = appendMatchingDescendants(walker, aContext, aNodes);
219     NS_ENSURE_SUCCESS(rv, rv);
220   } while (walker.moveToNextSibling());
221 
222   return NS_OK;
223 }
224 
appendMatchingDescendantsRev(const txXPathTreeWalker & aWalker,txIMatchContext * aContext,txNodeSet * aNodes)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;
231   }
232 
233   do {
234     nsresult rv = appendMatchingDescendantsRev(walker, aContext, aNodes);
235     NS_ENSURE_SUCCESS(rv, rv);
236 
237     rv = appendIfMatching(walker, aContext, aNodes);
238     NS_ENSURE_SUCCESS(rv, rv);
239   } while (walker.moveToPreviousSibling());
240 
241   return NS_OK;
242 }
243 
getType()244 Expr::ExprType LocationStep::getType() { return LOCATIONSTEP_EXPR; }
245 
TX_IMPL_EXPR_STUBS_BASE(LocationStep,NODESET_RESULT)246 TX_IMPL_EXPR_STUBS_BASE(LocationStep, NODESET_RESULT)
247 
248 Expr* LocationStep::getSubExprAt(uint32_t aPos) {
249   return PredicateList::getSubExprAt(aPos);
250 }
251 
setSubExprAt(uint32_t aPos,Expr * aExpr)252 void LocationStep::setSubExprAt(uint32_t aPos, Expr* aExpr) {
253   PredicateList::setSubExprAt(aPos, aExpr);
254 }
255 
isSensitiveTo(ContextSensitivity aContext)256 bool LocationStep::isSensitiveTo(ContextSensitivity aContext) {
257   return (aContext & NODE_CONTEXT) || mNodeTest->isSensitiveTo(aContext) ||
258          PredicateList::isSensitiveTo(aContext);
259 }
260 
261 #ifdef TX_TO_STRING
toString(nsAString & str)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;
302   }
303   NS_ASSERTION(mNodeTest, "mNodeTest is null, that's verboten");
304   mNodeTest->toString(str);
305 
306   PredicateList::toString(str);
307 }
308 #endif
309