Coverage Report

Created: 2018-09-25 14:53

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