Back to index

lightning-sunbird  0.9+nobinonly
ExprParser.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * The MITRE Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Keith Visco <kvisco@ziplink.net> (Original Author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00045 #include "ExprParser.h"
00046 #include "ExprLexer.h"
00047 #include "FunctionLib.h"
00048 #include "txStack.h"
00049 #include "txAtoms.h"
00050 #include "txError.h"
00051 #include "txIXPathContext.h"
00052 #include "txStringUtils.h"
00053 #include "txXPathNode.h"
00054 
00059 AttributeValueTemplate* txExprParser::createAttributeValueTemplate
00060     (const nsAFlatString& attValue, txIParseContext* aContext)
00061 {
00062     AttributeValueTemplate* avt = new AttributeValueTemplate();
00063     if (!avt) {
00064         // XXX ErrorReport: out of memory
00065         return 0;
00066     }
00067 
00068     if (attValue.IsEmpty())
00069         return avt;
00070 
00071     PRUint32 size = attValue.Length();
00072     PRUint32 cc = 0;
00073     PRUnichar nextCh;
00074     PRUnichar ch;
00075     nsAutoString buffer;
00076     MBool inExpr    = MB_FALSE;
00077     MBool inLiteral = MB_FALSE;
00078     PRUnichar endLiteral = 0;
00079 
00080     nextCh = attValue.CharAt(cc);
00081     while (cc++ < size) {
00082         ch = nextCh;
00083         nextCh = cc != size ? attValue.CharAt(cc) : 0;
00084         
00085         // if in literal just add ch to buffer
00086         if (inLiteral && (ch != endLiteral)) {
00087                 buffer.Append(ch);
00088                 continue;
00089         }
00090         switch ( ch ) {
00091             case '\'' :
00092             case '"' :
00093                 buffer.Append(ch);
00094                 if (inLiteral)
00095                     inLiteral = MB_FALSE;
00096                 else if (inExpr) {
00097                     inLiteral = MB_TRUE;
00098                     endLiteral = ch;
00099                 }
00100                 break;
00101             case  '{' :
00102                 if (!inExpr) {
00103                     // Ignore case where we find two {
00104                     if (nextCh == ch) {
00105                         buffer.Append(ch); //-- append '{'
00106                         cc++;
00107                         nextCh = cc != size ? attValue.CharAt(cc) : 0;
00108                     }
00109                     else {
00110                         if (!buffer.IsEmpty()) {
00111                             Expr* strExpr = new txLiteralExpr(buffer);
00112                             if (!strExpr) {
00113                                 // XXX ErrorReport: out of memory
00114                                 delete avt;
00115                                 return 0;
00116                             }
00117                             avt->addExpr(strExpr);
00118                         }
00119                         buffer.Truncate();
00120                         inExpr = MB_TRUE;
00121                     }
00122                 }
00123                 else
00124                     buffer.Append(ch); //-- simply append '{'
00125                 break;
00126             case '}':
00127                 if (inExpr) {
00128                     inExpr = MB_FALSE;
00129                     txExprLexer lexer;
00130                     nsresult rv = lexer.parse(buffer);
00131                     if (NS_FAILED(rv)) {
00132                         delete avt;
00133                         return 0;
00134                     }
00135                     Expr* expr;
00136                     rv = createExpr(lexer, aContext, &expr);
00137                     if (NS_FAILED(rv)) {
00138                         delete avt;
00139                         return 0;
00140                     }
00141                     avt->addExpr(expr);
00142                     buffer.Truncate();
00143                 }
00144                 else if (nextCh == ch) {
00145                     buffer.Append(ch);
00146                     cc++;
00147                     nextCh = cc != size ? attValue.CharAt(cc) : 0;
00148                 }
00149                 else {
00150                     //XXX ErrorReport: unmatched '}' found
00151                     delete avt;
00152                     return 0;
00153                 }
00154                 break;
00155             default:
00156                 buffer.Append(ch);
00157                 break;
00158         }
00159     }
00160 
00161     if (inExpr) {
00162         //XXX ErrorReport: ending '}' missing
00163         delete avt;
00164         return 0;
00165     }
00166 
00167     if (!buffer.IsEmpty()) {
00168         Expr* strExpr = new txLiteralExpr(buffer);
00169         if (!strExpr) {
00170             // XXX ErrorReport: out of memory
00171             delete avt;
00172             return 0;
00173         }
00174         avt->addExpr(strExpr);
00175     }
00176 
00177     return avt;
00178 
00179 }
00180 
00181 nsresult
00182 txExprParser::createExpr(const nsASingleFragmentString& aExpression,
00183                          txIParseContext* aContext, Expr** aExpr)
00184 {
00185     NS_ENSURE_ARG_POINTER(aExpr);
00186     *aExpr = nsnull;
00187     txExprLexer lexer;
00188     nsresult rv = lexer.parse(aExpression);
00189     if (NS_FAILED(rv)) {
00190         nsASingleFragmentString::const_char_iterator start;
00191         aExpression.BeginReading(start);
00192         aContext->SetErrorOffset(lexer.mPosition - start);
00193         return rv;
00194     }
00195     rv = createExpr(lexer, aContext, aExpr);
00196     if (NS_SUCCEEDED(rv) && lexer.peek()->mType != Token::END) {
00197         delete *aExpr;
00198         *aExpr = nsnull;
00199         rv = NS_ERROR_XPATH_BINARY_EXPECTED;
00200     }
00201     if (NS_FAILED(rv)) {
00202         nsASingleFragmentString::const_char_iterator start;
00203         aExpression.BeginReading(start);
00204         aContext->SetErrorOffset(lexer.peek()->mStart - start);
00205     }
00206     return rv;
00207 }
00208 
00216 nsresult
00217 txExprParser::createBinaryExpr(nsAutoPtr<Expr>& left, nsAutoPtr<Expr>& right,
00218                                Token* op, Expr** aResult)
00219 {
00220     NS_ASSERTION(op, "internal error");
00221     *aResult = nsnull;
00222 
00223     Expr* expr = nsnull;
00224     switch (op->mType) {
00225         //-- additive ops
00226         case Token::ADDITION_OP :
00227             expr = new AdditiveExpr(left, right, AdditiveExpr::ADDITION);
00228             break;
00229         case Token::SUBTRACTION_OP:
00230             expr = new AdditiveExpr(left, right, AdditiveExpr::SUBTRACTION);
00231             break;
00232 
00233         //-- case boolean ops
00234         case Token::AND_OP:
00235             expr = new BooleanExpr(left, right, BooleanExpr::AND);
00236             break;
00237         case Token::OR_OP:
00238             expr = new BooleanExpr(left, right, BooleanExpr::OR);
00239             break;
00240 
00241         //-- equality ops
00242         case Token::EQUAL_OP :
00243             expr = new RelationalExpr(left, right, RelationalExpr::EQUAL);
00244             break;
00245         case Token::NOT_EQUAL_OP :
00246             expr = new RelationalExpr(left, right, RelationalExpr::NOT_EQUAL);
00247             break;
00248 
00249         //-- relational ops
00250         case Token::LESS_THAN_OP:
00251             expr = new RelationalExpr(left, right, RelationalExpr::LESS_THAN);
00252             break;
00253         case Token::GREATER_THAN_OP:
00254             expr = new RelationalExpr(left, right,
00255                                       RelationalExpr::GREATER_THAN);
00256             break;
00257         case Token::LESS_OR_EQUAL_OP:
00258             expr = new RelationalExpr(left, right,
00259                                       RelationalExpr::LESS_OR_EQUAL);
00260             break;
00261         case Token::GREATER_OR_EQUAL_OP:
00262             expr = new RelationalExpr(left, right,
00263                                       RelationalExpr::GREATER_OR_EQUAL);
00264             break;
00265 
00266         //-- multiplicative ops
00267         case Token::DIVIDE_OP :
00268             expr = new MultiplicativeExpr(left, right,
00269                                           MultiplicativeExpr::DIVIDE);
00270             break;
00271         case Token::MODULUS_OP :
00272             expr = new MultiplicativeExpr(left, right,
00273                                           MultiplicativeExpr::MODULUS);
00274             break;
00275         case Token::MULTIPLY_OP :
00276             expr = new MultiplicativeExpr(left, right,
00277                                           MultiplicativeExpr::MULTIPLY);
00278             break;
00279         default:
00280             NS_NOTREACHED("operator tokens should be already checked");
00281             return NS_ERROR_UNEXPECTED;
00282     }
00283     NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY);
00284 
00285     *aResult = expr;
00286     return NS_OK;
00287 }
00288 
00289 
00290 nsresult
00291 txExprParser::createExpr(txExprLexer& lexer, txIParseContext* aContext,
00292                          Expr** aResult)
00293 {
00294     *aResult = nsnull;
00295 
00296     nsresult rv = NS_OK;
00297     MBool done = MB_FALSE;
00298 
00299     nsAutoPtr<Expr> expr;
00300 
00301     txStack exprs;
00302     txStack ops;
00303     
00304     while (!done) {
00305 
00306         MBool unary = MB_FALSE;
00307         while (lexer.peek()->mType == Token::SUBTRACTION_OP) {
00308             unary = !unary;
00309             lexer.nextToken();
00310         }
00311 
00312         rv = createUnionExpr(lexer, aContext, getter_Transfers(expr));
00313         if (NS_FAILED(rv)) {
00314             break;
00315         }
00316 
00317         if (unary) {
00318             Expr* uExpr = new UnaryExpr(expr);
00319             if (!uExpr) {
00320                 rv = NS_ERROR_OUT_OF_MEMORY;
00321                 break;
00322             }
00323             expr = uExpr;
00324         }
00325 
00326         Token* tok = lexer.nextToken();
00327         switch (tok->mType) {
00328             case Token::ADDITION_OP:
00329             case Token::DIVIDE_OP:
00330             //-- boolean ops
00331             case Token::AND_OP :
00332             case Token::OR_OP :
00333             //-- equality ops
00334             case Token::EQUAL_OP:
00335             case Token::NOT_EQUAL_OP:
00336             //-- relational ops
00337             case Token::LESS_THAN_OP:
00338             case Token::GREATER_THAN_OP:
00339             case Token::LESS_OR_EQUAL_OP:
00340             case Token::GREATER_OR_EQUAL_OP:
00341             //-- multiplicative ops
00342             case Token::MODULUS_OP:
00343             case Token::MULTIPLY_OP:
00344             case Token::SUBTRACTION_OP:
00345             {
00346                 while (!exprs.isEmpty() && precedence(tok) 
00347                        <= precedence(NS_STATIC_CAST(Token*, ops.peek()))) {
00348                     // can't use expr as result due to order of evaluation
00349                     nsAutoPtr<Expr> left(NS_STATIC_CAST(Expr*, exprs.pop()));
00350                     nsAutoPtr<Expr> right(expr);
00351                     rv = createBinaryExpr(left, right,
00352                                           NS_STATIC_CAST(Token*, ops.pop()),
00353                                           getter_Transfers(expr));
00354                     if (NS_FAILED(rv)) {
00355                         break;
00356                     }
00357                 }
00358                 exprs.push(expr.forget());
00359                 ops.push(tok);
00360                 break;
00361             }
00362             default:
00363                 lexer.pushBack();
00364                 done = MB_TRUE;
00365                 break;
00366         }
00367     }
00368 
00369     while (NS_SUCCEEDED(rv) && !exprs.isEmpty()) {
00370         nsAutoPtr<Expr> left(NS_STATIC_CAST(Expr*, exprs.pop()));
00371         nsAutoPtr<Expr> right(expr);
00372         rv = createBinaryExpr(left, right, NS_STATIC_CAST(Token*, ops.pop()),
00373                               getter_Transfers(expr));
00374     }
00375     // clean up on error
00376     while (!exprs.isEmpty()) {
00377         delete NS_STATIC_CAST(Expr*, exprs.pop());
00378     }
00379     NS_ENSURE_SUCCESS(rv, rv);
00380 
00381     *aResult = expr.forget();
00382     return NS_OK;
00383 }
00384 
00385 nsresult
00386 txExprParser::createFilter(txExprLexer& lexer, txIParseContext* aContext,
00387                            Expr** aResult)
00388 {
00389     *aResult = nsnull;
00390 
00391     nsresult rv = NS_OK;
00392     Token* tok = lexer.nextToken();
00393 
00394     nsAutoPtr<Expr> expr;
00395     switch (tok->mType) {
00396         case Token::FUNCTION_NAME :
00397             lexer.pushBack();
00398             rv = createFunctionCall(lexer, aContext, getter_Transfers(expr));
00399             NS_ENSURE_SUCCESS(rv, rv);
00400             break;
00401         case Token::VAR_REFERENCE :
00402             {
00403                 nsCOMPtr<nsIAtom> prefix, lName;
00404                 PRInt32 nspace;
00405                 nsresult rv = resolveQName(tok->Value(), getter_AddRefs(prefix),
00406                                            aContext, getter_AddRefs(lName),
00407                                            nspace);
00408                 NS_ENSURE_SUCCESS(rv, rv);
00409                 expr = new VariableRefExpr(prefix, lName, nspace);
00410                 NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY);
00411             }
00412             break;
00413         case Token::L_PAREN:
00414             rv = createExpr(lexer, aContext, getter_Transfers(expr));
00415             NS_ENSURE_SUCCESS(rv, rv);
00416 
00417             if (lexer.nextToken()->mType != Token::R_PAREN) {
00418                 lexer.pushBack();
00419                 return NS_ERROR_XPATH_PAREN_EXPECTED;
00420             }
00421             break;
00422         case Token::LITERAL :
00423             expr = new txLiteralExpr(tok->Value());
00424             NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY);
00425             break;
00426         case Token::NUMBER:
00427         {
00428             expr = new txLiteralExpr(Double::toDouble(tok->Value()));
00429             NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY);
00430             break;
00431         }
00432         default:
00433             NS_NOTREACHED("internal error, this is not a filter token");
00434             lexer.pushBack();
00435             return NS_ERROR_UNEXPECTED;
00436     }
00437 
00438     if (lexer.peek()->mType == Token::L_BRACKET) {
00439         nsAutoPtr<FilterExpr> filterExpr(new FilterExpr(expr));
00440         NS_ENSURE_TRUE(filterExpr, NS_ERROR_OUT_OF_MEMORY);
00441 
00442         //-- handle predicates
00443         rv = parsePredicates(filterExpr, lexer, aContext);
00444         NS_ENSURE_SUCCESS(rv, rv);
00445         expr = filterExpr.forget();
00446     }
00447 
00448     *aResult = expr.forget();
00449     return NS_OK;
00450 }
00451 
00452 nsresult
00453 txExprParser::createFunctionCall(txExprLexer& lexer, txIParseContext* aContext,
00454                                  Expr** aResult)
00455 {
00456     *aResult = nsnull;
00457 
00458     nsAutoPtr<FunctionCall> fnCall;
00459 
00460     Token* tok = lexer.nextToken();
00461     NS_ASSERTION(tok->mType == Token::FUNCTION_NAME, "FunctionCall expected");
00462 
00463     //-- compare function names
00464     nsCOMPtr<nsIAtom> prefix, lName;
00465     PRInt32 namespaceID;
00466     nsresult rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext,
00467                                getter_AddRefs(lName), namespaceID);
00468     NS_ENSURE_SUCCESS(rv, rv);
00469 
00470     if (namespaceID == kNameSpaceID_None) {
00471         PRBool isOutOfMem = PR_TRUE;
00472         if (lName == txXPathAtoms::boolean) {
00473             fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_BOOLEAN);
00474         }
00475         else if (lName == txXPathAtoms::concat) {
00476             fnCall = new StringFunctionCall(StringFunctionCall::CONCAT);
00477         }
00478         else if (lName == txXPathAtoms::contains) {
00479             fnCall = new StringFunctionCall(StringFunctionCall::CONTAINS);
00480         }
00481         else if (lName == txXPathAtoms::count) {
00482             fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::COUNT);
00483         }
00484         else if (lName == txXPathAtoms::_false) {
00485             fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_FALSE);
00486         }
00487         else if (lName == txXPathAtoms::id) {
00488             fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::ID);
00489         }
00490         else if (lName == txXPathAtoms::lang) {
00491             fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_LANG);
00492         }
00493         else if (lName == txXPathAtoms::last) {
00494             fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::LAST);
00495         }
00496         else if (lName == txXPathAtoms::localName) {
00497             fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::LOCAL_NAME);
00498         }
00499         else if (lName == txXPathAtoms::name) {
00500             fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::NAME);
00501         }
00502         else if (lName == txXPathAtoms::namespaceUri) {
00503             fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::NAMESPACE_URI);
00504         }
00505         else if (lName == txXPathAtoms::normalizeSpace) {
00506             fnCall = new StringFunctionCall(StringFunctionCall::NORMALIZE_SPACE);
00507         }
00508         else if (lName == txXPathAtoms::_not) {
00509             fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_NOT);
00510         }
00511         else if (lName == txXPathAtoms::position) {
00512             fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::POSITION);
00513         }
00514         else if (lName == txXPathAtoms::startsWith) {
00515             fnCall = new StringFunctionCall(StringFunctionCall::STARTS_WITH);
00516         }
00517         else if (lName == txXPathAtoms::string) {
00518             fnCall = new StringFunctionCall(StringFunctionCall::STRING);
00519         }
00520         else if (lName == txXPathAtoms::stringLength) {
00521             fnCall = new StringFunctionCall(StringFunctionCall::STRING_LENGTH);
00522         }
00523         else if (lName == txXPathAtoms::substring) {
00524             fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING);
00525         }
00526         else if (lName == txXPathAtoms::substringAfter) {
00527             fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING_AFTER);
00528         }
00529         else if (lName == txXPathAtoms::substringBefore) {
00530             fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING_BEFORE);
00531         }
00532         else if (lName == txXPathAtoms::sum) {
00533             fnCall = new NumberFunctionCall(NumberFunctionCall::SUM);
00534         }
00535         else if (lName == txXPathAtoms::translate) {
00536             fnCall = new StringFunctionCall(StringFunctionCall::TRANSLATE);
00537         }
00538         else if (lName == txXPathAtoms::_true) {
00539             fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_TRUE);
00540         }
00541         else if (lName == txXPathAtoms::number) {
00542             fnCall = new NumberFunctionCall(NumberFunctionCall::NUMBER);
00543         }
00544         else if (lName == txXPathAtoms::round) {
00545             fnCall = new NumberFunctionCall(NumberFunctionCall::ROUND);
00546         }
00547         else if (lName == txXPathAtoms::ceiling) {
00548             fnCall = new NumberFunctionCall(NumberFunctionCall::CEILING);
00549         }
00550         else if (lName == txXPathAtoms::floor) {
00551             fnCall = new NumberFunctionCall(NumberFunctionCall::FLOOR);
00552         }
00553         else {
00554             // didn't find functioncall here, fnCall should be null
00555             isOutOfMem = PR_FALSE;
00556         }
00557         if (!fnCall && isOutOfMem) {
00558             NS_ERROR("XPath FunctionLib failed on out-of-memory");
00559             return NS_ERROR_OUT_OF_MEMORY;
00560         }
00561     }
00562     // check extension functions and xslt
00563     if (!fnCall) {
00564         rv = aContext->resolveFunctionCall(lName, namespaceID,
00565                                            *getter_Transfers(fnCall));
00566 
00567         if (rv == NS_ERROR_NOT_IMPLEMENTED) {
00568             // this should just happen for unparsed-entity-uri()
00569             NS_ASSERTION(!fnCall, "Now is it implemented or not?");
00570             rv = parseParameters(0, lexer, aContext);
00571             NS_ENSURE_SUCCESS(rv, rv);
00572             *aResult = new txLiteralExpr(tok->Value() +
00573                                          NS_LITERAL_STRING(" not implemented."));
00574             NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
00575             return NS_OK;
00576         }
00577 
00578         if (NS_FAILED(rv)) {
00579             NS_ERROR("Creation of FunctionCall failed");
00580             return rv;
00581         }
00582     }
00583     
00584     //-- handle parametes
00585     rv = parseParameters(fnCall, lexer, aContext);
00586     NS_ENSURE_SUCCESS(rv, rv);
00587 
00588     *aResult = fnCall.forget();
00589     return NS_OK;
00590 }
00591 
00592 nsresult
00593 txExprParser::createLocationStep(txExprLexer& lexer, txIParseContext* aContext,
00594                                  Expr** aExpr)
00595 {
00596     *aExpr = nsnull;
00597 
00598     //-- child axis is default
00599     LocationStep::LocationStepType axisIdentifier = LocationStep::CHILD_AXIS;
00600     nsAutoPtr<txNodeTest> nodeTest;
00601 
00602     //-- get Axis Identifier or AbbreviatedStep, if present
00603     Token* tok = lexer.peek();
00604     switch (tok->mType) {
00605         case Token::AXIS_IDENTIFIER:
00606         {
00607             //-- eat token
00608             lexer.nextToken();
00609             nsCOMPtr<nsIAtom> axis = do_GetAtom(tok->Value());
00610             if (axis == txXPathAtoms::ancestor) {
00611                 axisIdentifier = LocationStep::ANCESTOR_AXIS;
00612             }
00613             else if (axis == txXPathAtoms::ancestorOrSelf) {
00614                 axisIdentifier = LocationStep::ANCESTOR_OR_SELF_AXIS;
00615             }
00616             else if (axis == txXPathAtoms::attribute) {
00617                 axisIdentifier = LocationStep::ATTRIBUTE_AXIS;
00618             }
00619             else if (axis == txXPathAtoms::child) {
00620                 axisIdentifier = LocationStep::CHILD_AXIS;
00621             }
00622             else if (axis == txXPathAtoms::descendant) {
00623                 axisIdentifier = LocationStep::DESCENDANT_AXIS;
00624             }
00625             else if (axis == txXPathAtoms::descendantOrSelf) {
00626                 axisIdentifier = LocationStep::DESCENDANT_OR_SELF_AXIS;
00627             }
00628             else if (axis == txXPathAtoms::following) {
00629                 axisIdentifier = LocationStep::FOLLOWING_AXIS;
00630             }
00631             else if (axis == txXPathAtoms::followingSibling) {
00632                 axisIdentifier = LocationStep::FOLLOWING_SIBLING_AXIS;
00633             }
00634             else if (axis == txXPathAtoms::_namespace) {
00635                 axisIdentifier = LocationStep::NAMESPACE_AXIS;
00636             }
00637             else if (axis == txXPathAtoms::parent) {
00638                 axisIdentifier = LocationStep::PARENT_AXIS;
00639             }
00640             else if (axis == txXPathAtoms::preceding) {
00641                 axisIdentifier = LocationStep::PRECEDING_AXIS;
00642             }
00643             else if (axis == txXPathAtoms::precedingSibling) {
00644                 axisIdentifier = LocationStep::PRECEDING_SIBLING_AXIS;
00645             }
00646             else if (axis == txXPathAtoms::self) {
00647                 axisIdentifier = LocationStep::SELF_AXIS;
00648             }
00649             else {
00650                 return NS_ERROR_XPATH_INVALID_AXIS;
00651             }
00652             break;
00653         }
00654         case Token::AT_SIGN:
00655             //-- eat token
00656             lexer.nextToken();
00657             axisIdentifier = LocationStep::ATTRIBUTE_AXIS;
00658             break;
00659         case Token::PARENT_NODE :
00660             //-- eat token
00661             lexer.nextToken();
00662             axisIdentifier = LocationStep::PARENT_AXIS;
00663             nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE);
00664             NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);
00665             break;
00666         case Token::SELF_NODE :
00667             //-- eat token
00668             lexer.nextToken();
00669             axisIdentifier = LocationStep::SELF_AXIS;
00670             nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE);
00671             NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);
00672             break;
00673         default:
00674             break;
00675     }
00676 
00677     //-- get NodeTest unless an AbbreviatedStep was found
00678     nsresult rv = NS_OK;
00679     if (!nodeTest) {
00680         tok = lexer.nextToken();
00681 
00682         switch (tok->mType) {
00683             case Token::CNAME :
00684                 {
00685                     // resolve QName
00686                     nsCOMPtr<nsIAtom> prefix, lName;
00687                     PRInt32 nspace;
00688                     rv = resolveQName(tok->Value(), getter_AddRefs(prefix),
00689                                       aContext, getter_AddRefs(lName),
00690                                       nspace, PR_TRUE);
00691                     NS_ENSURE_SUCCESS(rv, rv);
00692                     switch (axisIdentifier) {
00693                         case LocationStep::ATTRIBUTE_AXIS:
00694                             nodeTest = new txNameTest(prefix, lName, nspace,
00695                                                       txXPathNodeType::ATTRIBUTE_NODE);
00696                             break;
00697                         default:
00698                             nodeTest = new txNameTest(prefix, lName, nspace,
00699                                                       txXPathNodeType::ELEMENT_NODE);
00700                             break;
00701                     }
00702                     NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);
00703                 }
00704                 break;
00705             default:
00706                 lexer.pushBack();
00707                 rv = createNodeTypeTest(lexer, getter_Transfers(nodeTest));
00708                 NS_ENSURE_SUCCESS(rv, rv);
00709         }
00710     }
00711     
00712     nsAutoPtr<LocationStep> lstep(new LocationStep(nodeTest, axisIdentifier));
00713     NS_ENSURE_TRUE(lstep, NS_ERROR_OUT_OF_MEMORY);
00714 
00715     //-- handle predicates
00716     rv = parsePredicates(lstep, lexer, aContext);
00717     NS_ENSURE_SUCCESS(rv, rv);
00718 
00719     *aExpr = lstep.forget();
00720     return NS_OK;
00721 }
00722 
00727 nsresult
00728 txExprParser::createNodeTypeTest(txExprLexer& lexer, txNodeTest** aTest)
00729 {
00730     *aTest = 0;
00731     nsAutoPtr<txNodeTypeTest> nodeTest;
00732 
00733     Token* nodeTok = lexer.nextToken();
00734 
00735     switch (nodeTok->mType) {
00736         case Token::COMMENT:
00737             nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE);
00738             break;
00739         case Token::NODE :
00740             nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE);
00741             break;
00742         case Token::PROC_INST :
00743             nodeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE);
00744             break;
00745         case Token::TEXT :
00746             nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE);
00747             break;
00748         default:
00749             lexer.pushBack();
00750             return NS_ERROR_XPATH_NO_NODE_TYPE_TEST;
00751     }
00752     NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);
00753 
00754     if (lexer.nextToken()->mType != Token::L_PAREN) {
00755         lexer.pushBack();
00756         NS_NOTREACHED("txExprLexer doesn't generate nodetypetest without(");
00757         return NS_ERROR_UNEXPECTED;
00758     }
00759     if (nodeTok->mType == Token::PROC_INST &&
00760         lexer.peek()->mType == Token::LITERAL) {
00761         Token* tok = lexer.nextToken();
00762         nodeTest->setNodeName(tok->Value());
00763     }
00764     if (lexer.nextToken()->mType != Token::R_PAREN) {
00765         lexer.pushBack();
00766         return NS_ERROR_XPATH_PAREN_EXPECTED;
00767     }
00768 
00769     *aTest = nodeTest.forget();
00770     return NS_OK;
00771 }
00772 
00777 nsresult
00778 txExprParser::createPathExpr(txExprLexer& lexer, txIParseContext* aContext,
00779                              Expr** aResult)
00780 {
00781     *aResult = nsnull;
00782 
00783     nsAutoPtr<Expr> expr;
00784 
00785     Token* tok = lexer.peek();
00786 
00787     // is this a root expression?
00788     if (tok->mType == Token::PARENT_OP) {
00789         lexer.nextToken();
00790         if (!isLocationStepToken(lexer.peek())) {
00791             *aResult = new RootExpr();
00792             NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
00793             return NS_OK;
00794         }
00795         lexer.pushBack();
00796     }
00797 
00798     // parse first step (possibly a FilterExpr)
00799     nsresult rv = NS_OK;
00800     if (tok->mType != Token::PARENT_OP &&
00801         tok->mType != Token::ANCESTOR_OP) {
00802         if (isFilterExprToken(tok)) {
00803             rv = createFilter(lexer, aContext, getter_Transfers(expr));
00804         }
00805         else {
00806             rv = createLocationStep(lexer, aContext, getter_Transfers(expr));
00807         }
00808         NS_ENSURE_SUCCESS(rv, rv);
00809 
00810         // is this a singlestep path expression?
00811         tok = lexer.peek();
00812         if (tok->mType != Token::PARENT_OP &&
00813             tok->mType != Token::ANCESTOR_OP) {
00814             *aResult = expr.forget();
00815             return NS_OK;
00816         }
00817     }
00818     else {
00819         expr = new RootExpr();
00820         NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY);
00821 
00822 #ifdef TX_TO_STRING
00823         NS_STATIC_CAST(RootExpr*, expr.get())->setSerialize(PR_FALSE);
00824 #endif
00825     }
00826     
00827     // We have a PathExpr containing several steps
00828     nsAutoPtr<PathExpr> pathExpr(new PathExpr());
00829     NS_ENSURE_TRUE(pathExpr, NS_ERROR_OUT_OF_MEMORY);
00830 
00831     rv = pathExpr->addExpr(expr.forget(), PathExpr::RELATIVE_OP);
00832     NS_ENSURE_SUCCESS(rv, rv);
00833 
00834     // this is ugly
00835     while (1) {
00836         PathExpr::PathOperator pathOp;
00837         tok = lexer.nextToken();
00838         switch (tok->mType) {
00839             case Token::ANCESTOR_OP :
00840                 pathOp = PathExpr::DESCENDANT_OP;
00841                 break;
00842             case Token::PARENT_OP :
00843                 pathOp = PathExpr::RELATIVE_OP;
00844                 break;
00845             default:
00846                 lexer.pushBack();
00847                 *aResult = pathExpr.forget();
00848                 return NS_OK;
00849         }
00850         
00851         rv = createLocationStep(lexer, aContext, getter_Transfers(expr));
00852         NS_ENSURE_SUCCESS(rv, rv);
00853 
00854         rv = pathExpr->addExpr(expr.forget(), pathOp);
00855         NS_ENSURE_SUCCESS(rv, rv);
00856     }
00857     NS_NOTREACHED("internal xpath parser error");
00858     return NS_ERROR_UNEXPECTED;
00859 }
00860 
00865 nsresult
00866 txExprParser::createUnionExpr(txExprLexer& lexer, txIParseContext* aContext,
00867                               Expr** aResult)
00868 {
00869     *aResult = nsnull;
00870 
00871     nsAutoPtr<Expr> expr;
00872     nsresult rv = createPathExpr(lexer, aContext, getter_Transfers(expr));
00873     NS_ENSURE_SUCCESS(rv, rv);
00874     
00875     if (lexer.peek()->mType != Token::UNION_OP) {
00876         *aResult = expr.forget();
00877         return NS_OK;
00878     }
00879 
00880     nsAutoPtr<UnionExpr> unionExpr(new UnionExpr());
00881     NS_ENSURE_TRUE(unionExpr, NS_ERROR_OUT_OF_MEMORY);
00882 
00883     rv = unionExpr->addExpr(expr.forget());
00884     NS_ENSURE_SUCCESS(rv, rv);
00885 
00886     while (lexer.peek()->mType == Token::UNION_OP) {
00887         lexer.nextToken(); //-- eat token
00888 
00889         rv = createPathExpr(lexer, aContext, getter_Transfers(expr));
00890         NS_ENSURE_SUCCESS(rv, rv);
00891 
00892         rv = unionExpr->addExpr(expr.forget());
00893         NS_ENSURE_SUCCESS(rv, rv);
00894     }
00895 
00896     *aResult = unionExpr.forget();
00897     return NS_OK;
00898 }
00899 
00900 PRBool
00901 txExprParser::isFilterExprToken(Token* aToken)
00902 {
00903     switch (aToken->mType) {
00904         case Token::LITERAL:
00905         case Token::NUMBER:
00906         case Token::FUNCTION_NAME:
00907         case Token::VAR_REFERENCE:
00908         case Token::L_PAREN:            // grouping expr
00909             return PR_TRUE;
00910         default:
00911             return PR_FALSE;
00912     }
00913 }
00914 
00915 PRBool
00916 txExprParser::isLocationStepToken(Token* aToken)
00917 {
00918     switch (aToken->mType) {
00919         case Token::AXIS_IDENTIFIER :
00920         case Token::AT_SIGN :
00921         case Token::PARENT_NODE :
00922         case Token::SELF_NODE :
00923             return PR_TRUE;
00924         default:
00925             return isNodeTypeToken(aToken);
00926     }
00927 }
00928 
00929 PRBool
00930 txExprParser::isNodeTypeToken(Token* aToken)
00931 {
00932     switch (aToken->mType) {
00933         case Token::CNAME:
00934         case Token::COMMENT:
00935         case Token::NODE :
00936         case Token::PROC_INST :
00937         case Token::TEXT :
00938             return PR_TRUE;
00939         default:
00940             return PR_FALSE;
00941     }
00942 }
00943 
00952 nsresult
00953 txExprParser::parsePredicates(PredicateList* aPredicateList,
00954                               txExprLexer& lexer, txIParseContext* aContext)
00955 {
00956     nsAutoPtr<Expr> expr;
00957     nsresult rv = NS_OK;
00958     while (lexer.peek()->mType == Token::L_BRACKET) {
00959         //-- eat Token
00960         lexer.nextToken();
00961 
00962         rv = createExpr(lexer, aContext, getter_Transfers(expr));
00963         NS_ENSURE_SUCCESS(rv, rv);
00964 
00965         rv = aPredicateList->add(expr.forget());
00966         NS_ENSURE_SUCCESS(rv, rv);
00967 
00968         if (lexer.nextToken()->mType != Token::R_BRACKET) {
00969             lexer.pushBack();
00970             return NS_ERROR_XPATH_BRACKET_EXPECTED;
00971         }
00972     }
00973     return NS_OK;
00974 }
00975 
00976 
00985 nsresult
00986 txExprParser::parseParameters(FunctionCall* aFnCall, txExprLexer& lexer,
00987                               txIParseContext* aContext)
00988 {
00989     if (lexer.nextToken()->mType != Token::L_PAREN) {
00990         lexer.pushBack();
00991         NS_NOTREACHED("txExprLexer doesn't generate functions without(");
00992         return NS_ERROR_UNEXPECTED;
00993     }
00994 
00995     if (lexer.peek()->mType == Token::R_PAREN) {
00996         lexer.nextToken();
00997         return NS_OK;
00998     }
00999 
01000     nsAutoPtr<Expr> expr;
01001     nsresult rv = NS_OK;
01002     while (1) {
01003         rv = createExpr(lexer, aContext, getter_Transfers(expr));
01004         NS_ENSURE_SUCCESS(rv, rv);
01005 
01006         if (aFnCall) {
01007             rv = aFnCall->addParam(expr.forget());
01008             NS_ENSURE_SUCCESS(rv, rv);
01009         }
01010                     
01011         switch (lexer.nextToken()->mType) {
01012             case Token::R_PAREN :
01013                 return NS_OK;
01014             case Token::COMMA: //-- param separator
01015                 break;
01016             default:
01017                 lexer.pushBack();
01018                 return NS_ERROR_XPATH_PAREN_EXPECTED;
01019         }
01020     }
01021 
01022     NS_NOTREACHED("internal xpath parser error");
01023     return NS_ERROR_UNEXPECTED;
01024 }
01025 
01026 short
01027 txExprParser::precedence(Token* aToken)
01028 {
01029     switch (aToken->mType) {
01030         case Token::OR_OP:
01031             return 1;
01032         case Token::AND_OP:
01033             return 2;
01034         //-- equality
01035         case Token::EQUAL_OP:
01036         case Token::NOT_EQUAL_OP:
01037             return 3;
01038         //-- relational
01039         case Token::LESS_THAN_OP:
01040         case Token::GREATER_THAN_OP:
01041         case Token::LESS_OR_EQUAL_OP:
01042         case Token::GREATER_OR_EQUAL_OP:
01043             return 4;
01044         //-- additive operators
01045         case Token::ADDITION_OP:
01046         case Token::SUBTRACTION_OP:
01047             return 5;
01048         //-- multiplicative
01049         case Token::DIVIDE_OP:
01050         case Token::MULTIPLY_OP:
01051         case Token::MODULUS_OP:
01052             return 6;
01053         default:
01054             break;
01055     }
01056     return 0;
01057 }
01058 
01059 nsresult
01060 txExprParser::resolveQName(const nsAString& aQName,
01061                            nsIAtom** aPrefix, txIParseContext* aContext,
01062                            nsIAtom** aLocalName, PRInt32& aNamespace,
01063                            PRBool aIsNameTest)
01064 {
01065     aNamespace = kNameSpaceID_None;
01066     PRInt32 idx = aQName.FindChar(':');
01067     if (idx > 0) {
01068         *aPrefix = NS_NewAtom(Substring(aQName, 0, (PRUint32)idx));
01069         if (!*aPrefix) {
01070             return NS_ERROR_OUT_OF_MEMORY;
01071         }
01072         *aLocalName = NS_NewAtom(Substring(aQName, (PRUint32)idx + 1,
01073                                            aQName.Length() - (idx + 1)));
01074         if (!*aLocalName) {
01075             NS_RELEASE(*aPrefix);
01076             return NS_ERROR_OUT_OF_MEMORY;
01077         }
01078         return aContext->resolveNamespacePrefix(*aPrefix, aNamespace);
01079     }
01080     // the lexer dealt with idx == 0
01081     *aPrefix = 0;
01082     if (aIsNameTest && aContext->caseInsensitiveNameTests()) {
01083         nsAutoString lcname;
01084         TX_ToLowerCase(aQName, lcname);
01085         *aLocalName = NS_NewAtom(lcname);
01086     }
01087     else {
01088         *aLocalName = NS_NewAtom(aQName);
01089     }
01090     if (!*aLocalName) {
01091         return NS_ERROR_OUT_OF_MEMORY;
01092     }
01093     return NS_OK;
01094 }