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