tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

txExprParser.cpp (25841B)


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