dom/xslt/xpath/txExprParser.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial