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