|
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/. */ |
|
5 |
|
6 /** |
|
7 * ExprParser |
|
8 * This class is used to parse XSL Expressions |
|
9 * @see ExprLexer |
|
10 **/ |
|
11 |
|
12 #include "txExprParser.h" |
|
13 #include "txExprLexer.h" |
|
14 #include "txExpr.h" |
|
15 #include "txStack.h" |
|
16 #include "nsGkAtoms.h" |
|
17 #include "nsError.h" |
|
18 #include "txIXPathContext.h" |
|
19 #include "txStringUtils.h" |
|
20 #include "txXPathNode.h" |
|
21 #include "txXPathOptimizer.h" |
|
22 |
|
23 /** |
|
24 * Creates an Attribute Value Template using the given value |
|
25 * This should move to XSLProcessor class |
|
26 */ |
|
27 nsresult |
|
28 txExprParser::createAVT(const nsSubstring& aAttrValue, |
|
29 txIParseContext* aContext, |
|
30 Expr** aResult) |
|
31 { |
|
32 *aResult = nullptr; |
|
33 nsresult rv = NS_OK; |
|
34 nsAutoPtr<Expr> expr; |
|
35 FunctionCall* concat = nullptr; |
|
36 |
|
37 nsAutoString literalString; |
|
38 bool inExpr = false; |
|
39 nsSubstring::const_char_iterator iter, start, end, avtStart; |
|
40 aAttrValue.BeginReading(iter); |
|
41 aAttrValue.EndReading(end); |
|
42 avtStart = iter; |
|
43 |
|
44 while (iter != end) { |
|
45 // Every iteration through this loop parses either a literal section |
|
46 // or an expression |
|
47 start = iter; |
|
48 nsAutoPtr<Expr> newExpr; |
|
49 if (!inExpr) { |
|
50 // Parse literal section |
|
51 literalString.Truncate(); |
|
52 while (iter != end) { |
|
53 char16_t q = *iter; |
|
54 if (q == '{' || q == '}') { |
|
55 // Store what we've found so far and set a new |start| to |
|
56 // skip the (first) brace |
|
57 literalString.Append(Substring(start, iter)); |
|
58 start = ++iter; |
|
59 // Unless another brace follows we've found the start of |
|
60 // an expression (in case of '{') or an unbalanced brace |
|
61 // (in case of '}') |
|
62 if (iter == end || *iter != q) { |
|
63 if (q == '}') { |
|
64 aContext->SetErrorOffset(iter - avtStart); |
|
65 return NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE; |
|
66 } |
|
67 |
|
68 inExpr = true; |
|
69 break; |
|
70 } |
|
71 // We found a second brace, let that be part of the next |
|
72 // literal section being parsed and continue looping |
|
73 } |
|
74 ++iter; |
|
75 } |
|
76 |
|
77 if (start == iter && literalString.IsEmpty()) { |
|
78 // Restart the loop since we didn't create an expression |
|
79 continue; |
|
80 } |
|
81 newExpr = new txLiteralExpr(literalString + |
|
82 Substring(start, iter)); |
|
83 } |
|
84 else { |
|
85 // Parse expressions, iter is already past the initial '{' when |
|
86 // we get here. |
|
87 while (iter != end) { |
|
88 if (*iter == '}') { |
|
89 rv = createExprInternal(Substring(start, iter), |
|
90 start - avtStart, aContext, |
|
91 getter_Transfers(newExpr)); |
|
92 NS_ENSURE_SUCCESS(rv, rv); |
|
93 |
|
94 inExpr = false; |
|
95 ++iter; // skip closing '}' |
|
96 break; |
|
97 } |
|
98 else if (*iter == '\'' || *iter == '"') { |
|
99 char16_t q = *iter; |
|
100 while (++iter != end && *iter != q) {} /* do nothing */ |
|
101 if (iter == end) { |
|
102 break; |
|
103 } |
|
104 } |
|
105 ++iter; |
|
106 } |
|
107 |
|
108 if (inExpr) { |
|
109 aContext->SetErrorOffset(start - avtStart); |
|
110 return NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE; |
|
111 } |
|
112 } |
|
113 |
|
114 // Add expression, create a concat() call if necessary |
|
115 if (!expr) { |
|
116 expr = newExpr; |
|
117 } |
|
118 else { |
|
119 if (!concat) { |
|
120 concat = new txCoreFunctionCall(txCoreFunctionCall::CONCAT); |
|
121 NS_ENSURE_TRUE(concat, NS_ERROR_OUT_OF_MEMORY); |
|
122 |
|
123 rv = concat->addParam(expr.forget()); |
|
124 expr = concat; |
|
125 NS_ENSURE_SUCCESS(rv, rv); |
|
126 } |
|
127 |
|
128 rv = concat->addParam(newExpr.forget()); |
|
129 NS_ENSURE_SUCCESS(rv, rv); |
|
130 } |
|
131 } |
|
132 |
|
133 if (inExpr) { |
|
134 aContext->SetErrorOffset(iter - avtStart); |
|
135 return NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE; |
|
136 } |
|
137 |
|
138 if (!expr) { |
|
139 expr = new txLiteralExpr(EmptyString()); |
|
140 } |
|
141 |
|
142 *aResult = expr.forget(); |
|
143 |
|
144 return NS_OK; |
|
145 } |
|
146 |
|
147 nsresult |
|
148 txExprParser::createExprInternal(const nsSubstring& aExpression, |
|
149 uint32_t aSubStringPos, |
|
150 txIParseContext* aContext, Expr** aExpr) |
|
151 { |
|
152 NS_ENSURE_ARG_POINTER(aExpr); |
|
153 *aExpr = nullptr; |
|
154 txExprLexer lexer; |
|
155 nsresult rv = lexer.parse(aExpression); |
|
156 if (NS_FAILED(rv)) { |
|
157 nsASingleFragmentString::const_char_iterator start; |
|
158 aExpression.BeginReading(start); |
|
159 aContext->SetErrorOffset(lexer.mPosition - start + aSubStringPos); |
|
160 return rv; |
|
161 } |
|
162 nsAutoPtr<Expr> expr; |
|
163 rv = createExpr(lexer, aContext, getter_Transfers(expr)); |
|
164 if (NS_SUCCEEDED(rv) && lexer.peek()->mType != Token::END) { |
|
165 rv = NS_ERROR_XPATH_BINARY_EXPECTED; |
|
166 } |
|
167 if (NS_FAILED(rv)) { |
|
168 nsASingleFragmentString::const_char_iterator start; |
|
169 aExpression.BeginReading(start); |
|
170 aContext->SetErrorOffset(lexer.peek()->mStart - start + aSubStringPos); |
|
171 |
|
172 return rv; |
|
173 } |
|
174 |
|
175 txXPathOptimizer optimizer; |
|
176 Expr* newExpr = nullptr; |
|
177 rv = optimizer.optimize(expr, &newExpr); |
|
178 NS_ENSURE_SUCCESS(rv, rv); |
|
179 |
|
180 *aExpr = newExpr ? newExpr : expr.forget(); |
|
181 |
|
182 return NS_OK; |
|
183 } |
|
184 |
|
185 /** |
|
186 * Private Methods |
|
187 */ |
|
188 |
|
189 /** |
|
190 * Creates a binary Expr for the given operator |
|
191 */ |
|
192 nsresult |
|
193 txExprParser::createBinaryExpr(nsAutoPtr<Expr>& left, nsAutoPtr<Expr>& right, |
|
194 Token* op, Expr** aResult) |
|
195 { |
|
196 NS_ASSERTION(op, "internal error"); |
|
197 *aResult = nullptr; |
|
198 |
|
199 Expr* expr = nullptr; |
|
200 switch (op->mType) { |
|
201 //-- math ops |
|
202 case Token::ADDITION_OP : |
|
203 expr = new txNumberExpr(left, right, txNumberExpr::ADD); |
|
204 break; |
|
205 case Token::SUBTRACTION_OP: |
|
206 expr = new txNumberExpr(left, right, txNumberExpr::SUBTRACT); |
|
207 break; |
|
208 case Token::DIVIDE_OP : |
|
209 expr = new txNumberExpr(left, right, txNumberExpr::DIVIDE); |
|
210 break; |
|
211 case Token::MODULUS_OP : |
|
212 expr = new txNumberExpr(left, right, txNumberExpr::MODULUS); |
|
213 break; |
|
214 case Token::MULTIPLY_OP : |
|
215 expr = new txNumberExpr(left, right, txNumberExpr::MULTIPLY); |
|
216 break; |
|
217 |
|
218 //-- case boolean ops |
|
219 case Token::AND_OP: |
|
220 expr = new BooleanExpr(left, right, BooleanExpr::AND); |
|
221 break; |
|
222 case Token::OR_OP: |
|
223 expr = new BooleanExpr(left, right, BooleanExpr::OR); |
|
224 break; |
|
225 |
|
226 //-- equality ops |
|
227 case Token::EQUAL_OP : |
|
228 expr = new RelationalExpr(left, right, RelationalExpr::EQUAL); |
|
229 break; |
|
230 case Token::NOT_EQUAL_OP : |
|
231 expr = new RelationalExpr(left, right, RelationalExpr::NOT_EQUAL); |
|
232 break; |
|
233 |
|
234 //-- relational ops |
|
235 case Token::LESS_THAN_OP: |
|
236 expr = new RelationalExpr(left, right, RelationalExpr::LESS_THAN); |
|
237 break; |
|
238 case Token::GREATER_THAN_OP: |
|
239 expr = new RelationalExpr(left, right, |
|
240 RelationalExpr::GREATER_THAN); |
|
241 break; |
|
242 case Token::LESS_OR_EQUAL_OP: |
|
243 expr = new RelationalExpr(left, right, |
|
244 RelationalExpr::LESS_OR_EQUAL); |
|
245 break; |
|
246 case Token::GREATER_OR_EQUAL_OP: |
|
247 expr = new RelationalExpr(left, right, |
|
248 RelationalExpr::GREATER_OR_EQUAL); |
|
249 break; |
|
250 |
|
251 default: |
|
252 NS_NOTREACHED("operator tokens should be already checked"); |
|
253 return NS_ERROR_UNEXPECTED; |
|
254 } |
|
255 NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY); |
|
256 |
|
257 left.forget(); |
|
258 right.forget(); |
|
259 |
|
260 *aResult = expr; |
|
261 return NS_OK; |
|
262 } |
|
263 |
|
264 |
|
265 nsresult |
|
266 txExprParser::createExpr(txExprLexer& lexer, txIParseContext* aContext, |
|
267 Expr** aResult) |
|
268 { |
|
269 *aResult = nullptr; |
|
270 |
|
271 nsresult rv = NS_OK; |
|
272 bool done = false; |
|
273 |
|
274 nsAutoPtr<Expr> expr; |
|
275 |
|
276 txStack exprs; |
|
277 txStack ops; |
|
278 |
|
279 while (!done) { |
|
280 |
|
281 uint16_t negations = 0; |
|
282 while (lexer.peek()->mType == Token::SUBTRACTION_OP) { |
|
283 negations++; |
|
284 lexer.nextToken(); |
|
285 } |
|
286 |
|
287 rv = createUnionExpr(lexer, aContext, getter_Transfers(expr)); |
|
288 if (NS_FAILED(rv)) { |
|
289 break; |
|
290 } |
|
291 |
|
292 if (negations > 0) { |
|
293 if (negations % 2 == 0) { |
|
294 FunctionCall* fcExpr = new txCoreFunctionCall(txCoreFunctionCall::NUMBER); |
|
295 |
|
296 rv = fcExpr->addParam(expr); |
|
297 if (NS_FAILED(rv)) |
|
298 return rv; |
|
299 expr.forget(); |
|
300 expr = fcExpr; |
|
301 } |
|
302 else { |
|
303 expr = new UnaryExpr(expr.forget()); |
|
304 } |
|
305 } |
|
306 |
|
307 short tokPrecedence = precedence(lexer.peek()); |
|
308 if (tokPrecedence != 0) { |
|
309 Token* tok = lexer.nextToken(); |
|
310 while (!exprs.isEmpty() && tokPrecedence |
|
311 <= precedence(static_cast<Token*>(ops.peek()))) { |
|
312 // can't use expr as argument due to order of evaluation |
|
313 nsAutoPtr<Expr> left(static_cast<Expr*>(exprs.pop())); |
|
314 nsAutoPtr<Expr> right(expr); |
|
315 rv = createBinaryExpr(left, right, |
|
316 static_cast<Token*>(ops.pop()), |
|
317 getter_Transfers(expr)); |
|
318 if (NS_FAILED(rv)) { |
|
319 done = true; |
|
320 break; |
|
321 } |
|
322 } |
|
323 exprs.push(expr.forget()); |
|
324 ops.push(tok); |
|
325 } |
|
326 else { |
|
327 done = true; |
|
328 } |
|
329 } |
|
330 |
|
331 while (NS_SUCCEEDED(rv) && !exprs.isEmpty()) { |
|
332 nsAutoPtr<Expr> left(static_cast<Expr*>(exprs.pop())); |
|
333 nsAutoPtr<Expr> right(expr); |
|
334 rv = createBinaryExpr(left, right, static_cast<Token*>(ops.pop()), |
|
335 getter_Transfers(expr)); |
|
336 } |
|
337 // clean up on error |
|
338 while (!exprs.isEmpty()) { |
|
339 delete static_cast<Expr*>(exprs.pop()); |
|
340 } |
|
341 NS_ENSURE_SUCCESS(rv, rv); |
|
342 |
|
343 *aResult = expr.forget(); |
|
344 return NS_OK; |
|
345 } |
|
346 |
|
347 nsresult |
|
348 txExprParser::createFilterOrStep(txExprLexer& lexer, txIParseContext* aContext, |
|
349 Expr** aResult) |
|
350 { |
|
351 *aResult = nullptr; |
|
352 |
|
353 nsresult rv = NS_OK; |
|
354 Token* tok = lexer.peek(); |
|
355 |
|
356 nsAutoPtr<Expr> expr; |
|
357 switch (tok->mType) { |
|
358 case Token::FUNCTION_NAME_AND_PAREN: |
|
359 rv = createFunctionCall(lexer, aContext, getter_Transfers(expr)); |
|
360 NS_ENSURE_SUCCESS(rv, rv); |
|
361 break; |
|
362 case Token::VAR_REFERENCE : |
|
363 lexer.nextToken(); |
|
364 { |
|
365 nsCOMPtr<nsIAtom> prefix, lName; |
|
366 int32_t nspace; |
|
367 nsresult rv = resolveQName(tok->Value(), getter_AddRefs(prefix), |
|
368 aContext, getter_AddRefs(lName), |
|
369 nspace); |
|
370 NS_ENSURE_SUCCESS(rv, rv); |
|
371 expr = new VariableRefExpr(prefix, lName, nspace); |
|
372 } |
|
373 break; |
|
374 case Token::L_PAREN: |
|
375 lexer.nextToken(); |
|
376 rv = createExpr(lexer, aContext, getter_Transfers(expr)); |
|
377 NS_ENSURE_SUCCESS(rv, rv); |
|
378 |
|
379 if (lexer.peek()->mType != Token::R_PAREN) { |
|
380 return NS_ERROR_XPATH_PAREN_EXPECTED; |
|
381 } |
|
382 lexer.nextToken(); |
|
383 break; |
|
384 case Token::LITERAL : |
|
385 lexer.nextToken(); |
|
386 expr = new txLiteralExpr(tok->Value()); |
|
387 break; |
|
388 case Token::NUMBER: |
|
389 { |
|
390 lexer.nextToken(); |
|
391 expr = new txLiteralExpr(txDouble::toDouble(tok->Value())); |
|
392 break; |
|
393 } |
|
394 default: |
|
395 return createLocationStep(lexer, aContext, aResult); |
|
396 } |
|
397 |
|
398 if (lexer.peek()->mType == Token::L_BRACKET) { |
|
399 nsAutoPtr<FilterExpr> filterExpr(new FilterExpr(expr)); |
|
400 |
|
401 expr.forget(); |
|
402 |
|
403 //-- handle predicates |
|
404 rv = parsePredicates(filterExpr, lexer, aContext); |
|
405 NS_ENSURE_SUCCESS(rv, rv); |
|
406 expr = filterExpr.forget(); |
|
407 } |
|
408 |
|
409 *aResult = expr.forget(); |
|
410 return NS_OK; |
|
411 } |
|
412 |
|
413 nsresult |
|
414 txExprParser::createFunctionCall(txExprLexer& lexer, txIParseContext* aContext, |
|
415 Expr** aResult) |
|
416 { |
|
417 *aResult = nullptr; |
|
418 |
|
419 nsAutoPtr<FunctionCall> fnCall; |
|
420 |
|
421 Token* tok = lexer.nextToken(); |
|
422 NS_ASSERTION(tok->mType == Token::FUNCTION_NAME_AND_PAREN, |
|
423 "FunctionCall expected"); |
|
424 |
|
425 //-- compare function names |
|
426 nsCOMPtr<nsIAtom> prefix, lName; |
|
427 int32_t namespaceID; |
|
428 nsresult rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext, |
|
429 getter_AddRefs(lName), namespaceID); |
|
430 NS_ENSURE_SUCCESS(rv, rv); |
|
431 |
|
432 txCoreFunctionCall::eType type; |
|
433 if (namespaceID == kNameSpaceID_None && |
|
434 txCoreFunctionCall::getTypeFromAtom(lName, type)) { |
|
435 // It is a known built-in function. |
|
436 fnCall = new txCoreFunctionCall(type); |
|
437 } |
|
438 |
|
439 // check extension functions and xslt |
|
440 if (!fnCall) { |
|
441 rv = aContext->resolveFunctionCall(lName, namespaceID, |
|
442 getter_Transfers(fnCall)); |
|
443 |
|
444 if (rv == NS_ERROR_NOT_IMPLEMENTED) { |
|
445 // this should just happen for unparsed-entity-uri() |
|
446 NS_ASSERTION(!fnCall, "Now is it implemented or not?"); |
|
447 rv = parseParameters(0, lexer, aContext); |
|
448 NS_ENSURE_SUCCESS(rv, rv); |
|
449 |
|
450 *aResult = new txLiteralExpr(tok->Value() + |
|
451 NS_LITERAL_STRING(" not implemented.")); |
|
452 |
|
453 return NS_OK; |
|
454 } |
|
455 |
|
456 NS_ENSURE_SUCCESS(rv, rv); |
|
457 } |
|
458 |
|
459 //-- handle parametes |
|
460 rv = parseParameters(fnCall, lexer, aContext); |
|
461 NS_ENSURE_SUCCESS(rv, rv); |
|
462 |
|
463 *aResult = fnCall.forget(); |
|
464 return NS_OK; |
|
465 } |
|
466 |
|
467 nsresult |
|
468 txExprParser::createLocationStep(txExprLexer& lexer, txIParseContext* aContext, |
|
469 Expr** aExpr) |
|
470 { |
|
471 *aExpr = nullptr; |
|
472 |
|
473 //-- child axis is default |
|
474 LocationStep::LocationStepType axisIdentifier = LocationStep::CHILD_AXIS; |
|
475 nsAutoPtr<txNodeTest> nodeTest; |
|
476 |
|
477 //-- get Axis Identifier or AbbreviatedStep, if present |
|
478 Token* tok = lexer.peek(); |
|
479 switch (tok->mType) { |
|
480 case Token::AXIS_IDENTIFIER: |
|
481 { |
|
482 //-- eat token |
|
483 lexer.nextToken(); |
|
484 nsCOMPtr<nsIAtom> axis = do_GetAtom(tok->Value()); |
|
485 if (axis == nsGkAtoms::ancestor) { |
|
486 axisIdentifier = LocationStep::ANCESTOR_AXIS; |
|
487 } |
|
488 else if (axis == nsGkAtoms::ancestorOrSelf) { |
|
489 axisIdentifier = LocationStep::ANCESTOR_OR_SELF_AXIS; |
|
490 } |
|
491 else if (axis == nsGkAtoms::attribute) { |
|
492 axisIdentifier = LocationStep::ATTRIBUTE_AXIS; |
|
493 } |
|
494 else if (axis == nsGkAtoms::child) { |
|
495 axisIdentifier = LocationStep::CHILD_AXIS; |
|
496 } |
|
497 else if (axis == nsGkAtoms::descendant) { |
|
498 axisIdentifier = LocationStep::DESCENDANT_AXIS; |
|
499 } |
|
500 else if (axis == nsGkAtoms::descendantOrSelf) { |
|
501 axisIdentifier = LocationStep::DESCENDANT_OR_SELF_AXIS; |
|
502 } |
|
503 else if (axis == nsGkAtoms::following) { |
|
504 axisIdentifier = LocationStep::FOLLOWING_AXIS; |
|
505 } |
|
506 else if (axis == nsGkAtoms::followingSibling) { |
|
507 axisIdentifier = LocationStep::FOLLOWING_SIBLING_AXIS; |
|
508 } |
|
509 else if (axis == nsGkAtoms::_namespace) { |
|
510 axisIdentifier = LocationStep::NAMESPACE_AXIS; |
|
511 } |
|
512 else if (axis == nsGkAtoms::parent) { |
|
513 axisIdentifier = LocationStep::PARENT_AXIS; |
|
514 } |
|
515 else if (axis == nsGkAtoms::preceding) { |
|
516 axisIdentifier = LocationStep::PRECEDING_AXIS; |
|
517 } |
|
518 else if (axis == nsGkAtoms::precedingSibling) { |
|
519 axisIdentifier = LocationStep::PRECEDING_SIBLING_AXIS; |
|
520 } |
|
521 else if (axis == nsGkAtoms::self) { |
|
522 axisIdentifier = LocationStep::SELF_AXIS; |
|
523 } |
|
524 else { |
|
525 return NS_ERROR_XPATH_INVALID_AXIS; |
|
526 } |
|
527 break; |
|
528 } |
|
529 case Token::AT_SIGN: |
|
530 //-- eat token |
|
531 lexer.nextToken(); |
|
532 axisIdentifier = LocationStep::ATTRIBUTE_AXIS; |
|
533 break; |
|
534 case Token::PARENT_NODE : |
|
535 //-- eat token |
|
536 lexer.nextToken(); |
|
537 axisIdentifier = LocationStep::PARENT_AXIS; |
|
538 nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); |
|
539 break; |
|
540 case Token::SELF_NODE : |
|
541 //-- eat token |
|
542 lexer.nextToken(); |
|
543 axisIdentifier = LocationStep::SELF_AXIS; |
|
544 nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); |
|
545 break; |
|
546 default: |
|
547 break; |
|
548 } |
|
549 |
|
550 //-- get NodeTest unless an AbbreviatedStep was found |
|
551 nsresult rv = NS_OK; |
|
552 if (!nodeTest) { |
|
553 tok = lexer.peek(); |
|
554 |
|
555 if (tok->mType == Token::CNAME) { |
|
556 lexer.nextToken(); |
|
557 // resolve QName |
|
558 nsCOMPtr<nsIAtom> prefix, lName; |
|
559 int32_t nspace; |
|
560 rv = resolveQName(tok->Value(), getter_AddRefs(prefix), |
|
561 aContext, getter_AddRefs(lName), |
|
562 nspace, true); |
|
563 NS_ENSURE_SUCCESS(rv, rv); |
|
564 |
|
565 nodeTest = |
|
566 new txNameTest(prefix, lName, nspace, |
|
567 axisIdentifier == LocationStep::ATTRIBUTE_AXIS ? |
|
568 static_cast<uint16_t>(txXPathNodeType::ATTRIBUTE_NODE) : |
|
569 static_cast<uint16_t>(txXPathNodeType::ELEMENT_NODE)); |
|
570 } |
|
571 else { |
|
572 rv = createNodeTypeTest(lexer, getter_Transfers(nodeTest)); |
|
573 NS_ENSURE_SUCCESS(rv, rv); |
|
574 } |
|
575 } |
|
576 |
|
577 nsAutoPtr<LocationStep> lstep(new LocationStep(nodeTest, axisIdentifier)); |
|
578 |
|
579 nodeTest.forget(); |
|
580 |
|
581 //-- handle predicates |
|
582 rv = parsePredicates(lstep, lexer, aContext); |
|
583 NS_ENSURE_SUCCESS(rv, rv); |
|
584 |
|
585 *aExpr = lstep.forget(); |
|
586 return NS_OK; |
|
587 } |
|
588 |
|
589 /** |
|
590 * This method only handles comment(), text(), processing-instructing() |
|
591 * and node() |
|
592 */ |
|
593 nsresult |
|
594 txExprParser::createNodeTypeTest(txExprLexer& lexer, txNodeTest** aTest) |
|
595 { |
|
596 *aTest = 0; |
|
597 nsAutoPtr<txNodeTypeTest> nodeTest; |
|
598 |
|
599 Token* nodeTok = lexer.peek(); |
|
600 |
|
601 switch (nodeTok->mType) { |
|
602 case Token::COMMENT_AND_PAREN: |
|
603 lexer.nextToken(); |
|
604 nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE); |
|
605 break; |
|
606 case Token::NODE_AND_PAREN: |
|
607 lexer.nextToken(); |
|
608 nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); |
|
609 break; |
|
610 case Token::PROC_INST_AND_PAREN: |
|
611 lexer.nextToken(); |
|
612 nodeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE); |
|
613 break; |
|
614 case Token::TEXT_AND_PAREN: |
|
615 lexer.nextToken(); |
|
616 nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE); |
|
617 break; |
|
618 default: |
|
619 return NS_ERROR_XPATH_NO_NODE_TYPE_TEST; |
|
620 } |
|
621 |
|
622 NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY); |
|
623 |
|
624 if (nodeTok->mType == Token::PROC_INST_AND_PAREN && |
|
625 lexer.peek()->mType == Token::LITERAL) { |
|
626 Token* tok = lexer.nextToken(); |
|
627 nodeTest->setNodeName(tok->Value()); |
|
628 } |
|
629 if (lexer.peek()->mType != Token::R_PAREN) { |
|
630 return NS_ERROR_XPATH_PAREN_EXPECTED; |
|
631 } |
|
632 lexer.nextToken(); |
|
633 |
|
634 *aTest = nodeTest.forget(); |
|
635 return NS_OK; |
|
636 } |
|
637 |
|
638 /** |
|
639 * Creates a PathExpr using the given txExprLexer |
|
640 * @param lexer the txExprLexer for retrieving Tokens |
|
641 */ |
|
642 nsresult |
|
643 txExprParser::createPathExpr(txExprLexer& lexer, txIParseContext* aContext, |
|
644 Expr** aResult) |
|
645 { |
|
646 *aResult = nullptr; |
|
647 |
|
648 nsAutoPtr<Expr> expr; |
|
649 |
|
650 Token* tok = lexer.peek(); |
|
651 |
|
652 // is this a root expression? |
|
653 if (tok->mType == Token::PARENT_OP) { |
|
654 if (!isLocationStepToken(lexer.peekAhead())) { |
|
655 lexer.nextToken(); |
|
656 *aResult = new RootExpr(); |
|
657 return NS_OK; |
|
658 } |
|
659 } |
|
660 |
|
661 // parse first step (possibly a FilterExpr) |
|
662 nsresult rv = NS_OK; |
|
663 if (tok->mType != Token::PARENT_OP && |
|
664 tok->mType != Token::ANCESTOR_OP) { |
|
665 rv = createFilterOrStep(lexer, aContext, getter_Transfers(expr)); |
|
666 NS_ENSURE_SUCCESS(rv, rv); |
|
667 |
|
668 // is this a singlestep path expression? |
|
669 tok = lexer.peek(); |
|
670 if (tok->mType != Token::PARENT_OP && |
|
671 tok->mType != Token::ANCESTOR_OP) { |
|
672 *aResult = expr.forget(); |
|
673 return NS_OK; |
|
674 } |
|
675 } |
|
676 else { |
|
677 expr = new RootExpr(); |
|
678 |
|
679 #ifdef TX_TO_STRING |
|
680 static_cast<RootExpr*>(expr.get())->setSerialize(false); |
|
681 #endif |
|
682 } |
|
683 |
|
684 // We have a PathExpr containing several steps |
|
685 nsAutoPtr<PathExpr> pathExpr(new PathExpr()); |
|
686 |
|
687 rv = pathExpr->addExpr(expr, PathExpr::RELATIVE_OP); |
|
688 NS_ENSURE_SUCCESS(rv, rv); |
|
689 |
|
690 expr.forget(); |
|
691 |
|
692 // this is ugly |
|
693 while (1) { |
|
694 PathExpr::PathOperator pathOp; |
|
695 switch (lexer.peek()->mType) { |
|
696 case Token::ANCESTOR_OP : |
|
697 pathOp = PathExpr::DESCENDANT_OP; |
|
698 break; |
|
699 case Token::PARENT_OP : |
|
700 pathOp = PathExpr::RELATIVE_OP; |
|
701 break; |
|
702 default: |
|
703 *aResult = pathExpr.forget(); |
|
704 return NS_OK; |
|
705 } |
|
706 lexer.nextToken(); |
|
707 |
|
708 rv = createLocationStep(lexer, aContext, getter_Transfers(expr)); |
|
709 NS_ENSURE_SUCCESS(rv, rv); |
|
710 |
|
711 rv = pathExpr->addExpr(expr, pathOp); |
|
712 NS_ENSURE_SUCCESS(rv, rv); |
|
713 |
|
714 expr.forget(); |
|
715 } |
|
716 NS_NOTREACHED("internal xpath parser error"); |
|
717 return NS_ERROR_UNEXPECTED; |
|
718 } |
|
719 |
|
720 /** |
|
721 * Creates a PathExpr using the given txExprLexer |
|
722 * @param lexer the txExprLexer for retrieving Tokens |
|
723 */ |
|
724 nsresult |
|
725 txExprParser::createUnionExpr(txExprLexer& lexer, txIParseContext* aContext, |
|
726 Expr** aResult) |
|
727 { |
|
728 *aResult = nullptr; |
|
729 |
|
730 nsAutoPtr<Expr> expr; |
|
731 nsresult rv = createPathExpr(lexer, aContext, getter_Transfers(expr)); |
|
732 NS_ENSURE_SUCCESS(rv, rv); |
|
733 |
|
734 if (lexer.peek()->mType != Token::UNION_OP) { |
|
735 *aResult = expr.forget(); |
|
736 return NS_OK; |
|
737 } |
|
738 |
|
739 nsAutoPtr<UnionExpr> unionExpr(new UnionExpr()); |
|
740 |
|
741 rv = unionExpr->addExpr(expr); |
|
742 NS_ENSURE_SUCCESS(rv, rv); |
|
743 |
|
744 expr.forget(); |
|
745 |
|
746 while (lexer.peek()->mType == Token::UNION_OP) { |
|
747 lexer.nextToken(); //-- eat token |
|
748 |
|
749 rv = createPathExpr(lexer, aContext, getter_Transfers(expr)); |
|
750 NS_ENSURE_SUCCESS(rv, rv); |
|
751 |
|
752 rv = unionExpr->addExpr(expr.forget()); |
|
753 NS_ENSURE_SUCCESS(rv, rv); |
|
754 } |
|
755 |
|
756 *aResult = unionExpr.forget(); |
|
757 return NS_OK; |
|
758 } |
|
759 |
|
760 bool |
|
761 txExprParser::isLocationStepToken(Token* aToken) |
|
762 { |
|
763 // We could put these in consecutive order in ExprLexer.h for speed |
|
764 return aToken->mType == Token::AXIS_IDENTIFIER || |
|
765 aToken->mType == Token::AT_SIGN || |
|
766 aToken->mType == Token::PARENT_NODE || |
|
767 aToken->mType == Token::SELF_NODE || |
|
768 aToken->mType == Token::CNAME || |
|
769 aToken->mType == Token::COMMENT_AND_PAREN || |
|
770 aToken->mType == Token::NODE_AND_PAREN || |
|
771 aToken->mType == Token::PROC_INST_AND_PAREN || |
|
772 aToken->mType == Token::TEXT_AND_PAREN; |
|
773 } |
|
774 |
|
775 /** |
|
776 * Using the given lexer, parses the tokens if they represent a predicate list |
|
777 * If an error occurs a non-zero String pointer will be returned containing the |
|
778 * error message. |
|
779 * @param predicateList, the PredicateList to add predicate expressions to |
|
780 * @param lexer the txExprLexer to use for parsing tokens |
|
781 * @return 0 if successful, or a String pointer to the error message |
|
782 */ |
|
783 nsresult |
|
784 txExprParser::parsePredicates(PredicateList* aPredicateList, |
|
785 txExprLexer& lexer, txIParseContext* aContext) |
|
786 { |
|
787 nsAutoPtr<Expr> expr; |
|
788 nsresult rv = NS_OK; |
|
789 while (lexer.peek()->mType == Token::L_BRACKET) { |
|
790 //-- eat Token |
|
791 lexer.nextToken(); |
|
792 |
|
793 rv = createExpr(lexer, aContext, getter_Transfers(expr)); |
|
794 NS_ENSURE_SUCCESS(rv, rv); |
|
795 |
|
796 rv = aPredicateList->add(expr); |
|
797 NS_ENSURE_SUCCESS(rv, rv); |
|
798 |
|
799 expr.forget(); |
|
800 |
|
801 if (lexer.peek()->mType != Token::R_BRACKET) { |
|
802 return NS_ERROR_XPATH_BRACKET_EXPECTED; |
|
803 } |
|
804 lexer.nextToken(); |
|
805 } |
|
806 return NS_OK; |
|
807 } |
|
808 |
|
809 |
|
810 /** |
|
811 * Using the given lexer, parses the tokens if they represent a parameter list |
|
812 * If an error occurs a non-zero String pointer will be returned containing the |
|
813 * error message. |
|
814 * @param list, the List to add parameter expressions to |
|
815 * @param lexer the txExprLexer to use for parsing tokens |
|
816 * @return NS_OK if successful, or another rv otherwise |
|
817 */ |
|
818 nsresult |
|
819 txExprParser::parseParameters(FunctionCall* aFnCall, txExprLexer& lexer, |
|
820 txIParseContext* aContext) |
|
821 { |
|
822 if (lexer.peek()->mType == Token::R_PAREN) { |
|
823 lexer.nextToken(); |
|
824 return NS_OK; |
|
825 } |
|
826 |
|
827 nsAutoPtr<Expr> expr; |
|
828 nsresult rv = NS_OK; |
|
829 while (1) { |
|
830 rv = createExpr(lexer, aContext, getter_Transfers(expr)); |
|
831 NS_ENSURE_SUCCESS(rv, rv); |
|
832 |
|
833 if (aFnCall) { |
|
834 rv = aFnCall->addParam(expr.forget()); |
|
835 NS_ENSURE_SUCCESS(rv, rv); |
|
836 } |
|
837 |
|
838 switch (lexer.peek()->mType) { |
|
839 case Token::R_PAREN : |
|
840 lexer.nextToken(); |
|
841 return NS_OK; |
|
842 case Token::COMMA: //-- param separator |
|
843 lexer.nextToken(); |
|
844 break; |
|
845 default: |
|
846 return NS_ERROR_XPATH_PAREN_EXPECTED; |
|
847 } |
|
848 } |
|
849 |
|
850 NS_NOTREACHED("internal xpath parser error"); |
|
851 return NS_ERROR_UNEXPECTED; |
|
852 } |
|
853 |
|
854 short |
|
855 txExprParser::precedence(Token* aToken) |
|
856 { |
|
857 switch (aToken->mType) { |
|
858 case Token::OR_OP: |
|
859 return 1; |
|
860 case Token::AND_OP: |
|
861 return 2; |
|
862 //-- equality |
|
863 case Token::EQUAL_OP: |
|
864 case Token::NOT_EQUAL_OP: |
|
865 return 3; |
|
866 //-- relational |
|
867 case Token::LESS_THAN_OP: |
|
868 case Token::GREATER_THAN_OP: |
|
869 case Token::LESS_OR_EQUAL_OP: |
|
870 case Token::GREATER_OR_EQUAL_OP: |
|
871 return 4; |
|
872 //-- additive operators |
|
873 case Token::ADDITION_OP: |
|
874 case Token::SUBTRACTION_OP: |
|
875 return 5; |
|
876 //-- multiplicative |
|
877 case Token::DIVIDE_OP: |
|
878 case Token::MULTIPLY_OP: |
|
879 case Token::MODULUS_OP: |
|
880 return 6; |
|
881 default: |
|
882 break; |
|
883 } |
|
884 return 0; |
|
885 } |
|
886 |
|
887 nsresult |
|
888 txExprParser::resolveQName(const nsAString& aQName, |
|
889 nsIAtom** aPrefix, txIParseContext* aContext, |
|
890 nsIAtom** aLocalName, int32_t& aNamespace, |
|
891 bool aIsNameTest) |
|
892 { |
|
893 aNamespace = kNameSpaceID_None; |
|
894 int32_t idx = aQName.FindChar(':'); |
|
895 if (idx > 0) { |
|
896 *aPrefix = NS_NewAtom(StringHead(aQName, (uint32_t)idx)).take(); |
|
897 if (!*aPrefix) { |
|
898 return NS_ERROR_OUT_OF_MEMORY; |
|
899 } |
|
900 *aLocalName = NS_NewAtom(Substring(aQName, (uint32_t)idx + 1, |
|
901 aQName.Length() - (idx + 1))).take(); |
|
902 if (!*aLocalName) { |
|
903 NS_RELEASE(*aPrefix); |
|
904 return NS_ERROR_OUT_OF_MEMORY; |
|
905 } |
|
906 return aContext->resolveNamespacePrefix(*aPrefix, aNamespace); |
|
907 } |
|
908 // the lexer dealt with idx == 0 |
|
909 *aPrefix = 0; |
|
910 if (aIsNameTest && aContext->caseInsensitiveNameTests()) { |
|
911 nsAutoString lcname; |
|
912 nsContentUtils::ASCIIToLower(aQName, lcname); |
|
913 *aLocalName = NS_NewAtom(lcname).take(); |
|
914 } |
|
915 else { |
|
916 *aLocalName = NS_NewAtom(aQName).take(); |
|
917 } |
|
918 if (!*aLocalName) { |
|
919 return NS_ERROR_OUT_OF_MEMORY; |
|
920 } |
|
921 return NS_OK; |
|
922 } |