Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
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
28 LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
29 {
30 NS_ASSERTION(aContext, "internal error");
31 *aResult = nullptr;
33 nsRefPtr<txNodeSet> nodes;
34 nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
35 NS_ENSURE_SUCCESS(rv, rv);
37 txXPathTreeWalker walker(aContext->getContextNode());
39 switch (mAxisIdentifier) {
40 case ANCESTOR_AXIS:
41 {
42 if (!walker.moveToParent()) {
43 break;
44 }
45 // do not break here
46 }
47 case ANCESTOR_OR_SELF_AXIS:
48 {
49 nodes->setReverse();
51 do {
52 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
53 nodes->append(walker.getCurrentPosition());
54 }
55 } while (walker.moveToParent());
57 break;
58 }
59 case ATTRIBUTE_AXIS:
60 {
61 if (!walker.moveToFirstAttribute()) {
62 break;
63 }
65 do {
66 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
67 nodes->append(walker.getCurrentPosition());
68 }
69 } while (walker.moveToNextAttribute());
70 break;
71 }
72 case DESCENDANT_OR_SELF_AXIS:
73 {
74 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
75 nodes->append(walker.getCurrentPosition());
76 }
77 // do not break here
78 }
79 case DESCENDANT_AXIS:
80 {
81 fromDescendants(walker.getCurrentPosition(), aContext, nodes);
82 break;
83 }
84 case FOLLOWING_AXIS:
85 {
86 if (txXPathNodeUtils::isAttribute(walker.getCurrentPosition())) {
87 walker.moveToParent();
88 fromDescendants(walker.getCurrentPosition(), aContext, nodes);
89 }
90 bool cont = true;
91 while (!walker.moveToNextSibling()) {
92 if (!walker.moveToParent()) {
93 cont = false;
94 break;
95 }
96 }
97 while (cont) {
98 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
99 nodes->append(walker.getCurrentPosition());
100 }
102 fromDescendants(walker.getCurrentPosition(), aContext, nodes);
104 while (!walker.moveToNextSibling()) {
105 if (!walker.moveToParent()) {
106 cont = false;
107 break;
108 }
109 }
110 }
111 break;
112 }
113 case FOLLOWING_SIBLING_AXIS:
114 {
115 while (walker.moveToNextSibling()) {
116 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
117 nodes->append(walker.getCurrentPosition());
118 }
119 }
120 break;
121 }
122 case NAMESPACE_AXIS: //-- not yet implemented
123 #if 0
124 // XXX DEBUG OUTPUT
125 cout << "namespace axis not yet implemented"<<endl;
126 #endif
127 break;
128 case PARENT_AXIS :
129 {
130 if (walker.moveToParent() &&
131 mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
132 nodes->append(walker.getCurrentPosition());
133 }
134 break;
135 }
136 case PRECEDING_AXIS:
137 {
138 nodes->setReverse();
140 bool cont = true;
141 while (!walker.moveToPreviousSibling()) {
142 if (!walker.moveToParent()) {
143 cont = false;
144 break;
145 }
146 }
147 while (cont) {
148 fromDescendantsRev(walker.getCurrentPosition(), aContext, nodes);
150 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
151 nodes->append(walker.getCurrentPosition());
152 }
154 while (!walker.moveToPreviousSibling()) {
155 if (!walker.moveToParent()) {
156 cont = false;
157 break;
158 }
159 }
160 }
161 break;
162 }
163 case PRECEDING_SIBLING_AXIS:
164 {
165 nodes->setReverse();
167 while (walker.moveToPreviousSibling()) {
168 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
169 nodes->append(walker.getCurrentPosition());
170 }
171 }
172 break;
173 }
174 case SELF_AXIS:
175 {
176 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
177 nodes->append(walker.getCurrentPosition());
178 }
179 break;
180 }
181 default: // Children Axis
182 {
183 if (!walker.moveToFirstChild()) {
184 break;
185 }
187 do {
188 if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
189 nodes->append(walker.getCurrentPosition());
190 }
191 } while (walker.moveToNextSibling());
192 break;
193 }
194 }
196 // Apply predicates
197 if (!isEmpty()) {
198 rv = evaluatePredicates(nodes, aContext);
199 NS_ENSURE_SUCCESS(rv, rv);
200 }
202 nodes->unsetReverse();
204 NS_ADDREF(*aResult = nodes);
206 return NS_OK;
207 }
209 void LocationStep::fromDescendants(const txXPathNode& aNode,
210 txIMatchContext* aCs,
211 txNodeSet* aNodes)
212 {
213 txXPathTreeWalker walker(aNode);
214 if (!walker.moveToFirstChild()) {
215 return;
216 }
218 do {
219 const txXPathNode& child = walker.getCurrentPosition();
220 if (mNodeTest->matches(child, aCs)) {
221 aNodes->append(child);
222 }
223 fromDescendants(child, aCs, aNodes);
224 } while (walker.moveToNextSibling());
225 }
227 void LocationStep::fromDescendantsRev(const txXPathNode& aNode,
228 txIMatchContext* aCs,
229 txNodeSet* aNodes)
230 {
231 txXPathTreeWalker walker(aNode);
232 if (!walker.moveToLastChild()) {
233 return;
234 }
236 do {
237 const txXPathNode& child = walker.getCurrentPosition();
238 fromDescendantsRev(child, aCs, aNodes);
240 if (mNodeTest->matches(child, aCs)) {
241 aNodes->append(child);
242 }
244 } while (walker.moveToPreviousSibling());
245 }
247 Expr::ExprType
248 LocationStep::getType()
249 {
250 return LOCATIONSTEP_EXPR;
251 }
254 TX_IMPL_EXPR_STUBS_BASE(LocationStep, NODESET_RESULT)
256 Expr*
257 LocationStep::getSubExprAt(uint32_t aPos)
258 {
259 return PredicateList::getSubExprAt(aPos);
260 }
262 void
263 LocationStep::setSubExprAt(uint32_t aPos, Expr* aExpr)
264 {
265 PredicateList::setSubExprAt(aPos, aExpr);
266 }
268 bool
269 LocationStep::isSensitiveTo(ContextSensitivity aContext)
270 {
271 return (aContext & NODE_CONTEXT) ||
272 mNodeTest->isSensitiveTo(aContext) ||
273 PredicateList::isSensitiveTo(aContext);
274 }
276 #ifdef TX_TO_STRING
277 void
278 LocationStep::toString(nsAString& str)
279 {
280 switch (mAxisIdentifier) {
281 case ANCESTOR_AXIS :
282 str.AppendLiteral("ancestor::");
283 break;
284 case ANCESTOR_OR_SELF_AXIS :
285 str.AppendLiteral("ancestor-or-self::");
286 break;
287 case ATTRIBUTE_AXIS:
288 str.Append(char16_t('@'));
289 break;
290 case DESCENDANT_AXIS:
291 str.AppendLiteral("descendant::");
292 break;
293 case DESCENDANT_OR_SELF_AXIS:
294 str.AppendLiteral("descendant-or-self::");
295 break;
296 case FOLLOWING_AXIS :
297 str.AppendLiteral("following::");
298 break;
299 case FOLLOWING_SIBLING_AXIS:
300 str.AppendLiteral("following-sibling::");
301 break;
302 case NAMESPACE_AXIS:
303 str.AppendLiteral("namespace::");
304 break;
305 case PARENT_AXIS :
306 str.AppendLiteral("parent::");
307 break;
308 case PRECEDING_AXIS :
309 str.AppendLiteral("preceding::");
310 break;
311 case PRECEDING_SIBLING_AXIS :
312 str.AppendLiteral("preceding-sibling::");
313 break;
314 case SELF_AXIS :
315 str.AppendLiteral("self::");
316 break;
317 default:
318 break;
319 }
320 NS_ASSERTION(mNodeTest, "mNodeTest is null, that's verboten");
321 mNodeTest->toString(str);
323 PredicateList::toString(str);
324 }
325 #endif