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 }