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