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