Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsXPathParser.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Mozilla XForms support.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Novell, Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Allan Beaufour <abeaufour@novell.com>
00024  *  David Landwehr <dlandwehr@novell.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsXFormsXPathParser.h"
00041 #include "nscore.h"
00042 
00043 /*
00044  * @todo GIANT hack. Without exceptions everything had to be rewritten, and
00045  * that was to overdo it a bit, when the code probably does not survive... (XXX)
00046  */
00047 void
00048 XPathCompilerException(const char      *aMsg,
00049                        const nsAString &aExpression,
00050                        PRInt32         aOffset = -1,
00051                        PRInt32         aLength = -1)
00052 {
00053   printf("XPathCompilerException: %s, %s [o: %d, l: %d]\n",
00054          aMsg,
00055          NS_ConvertUTF16toUTF8(aExpression).get(), aOffset, aLength);
00056 
00057   printf("WARNING: Houston we have a problem, and unlike Apollo 13, we're not going to make it!\n");
00058   NS_ABORT();
00059 }
00060 
00061 
00062 nsXFormsXPathParser::nsXFormsXPathParser()
00063     : mUsesDynamicFunc(PR_FALSE), mHead(nsnull), mAnalyzeStackPointer(nsnull)
00064 {
00065   MOZ_COUNT_CTOR(nsXFormsXPathParser);
00066 }
00067 
00068 nsXFormsXPathParser::~nsXFormsXPathParser()
00069 {
00070   MOZ_COUNT_DTOR(nsXFormsXPathParser);
00071 }
00072 
00073 void
00074 nsXFormsXPathParser::PushContext(PRInt32 aStartIndex)
00075 {
00076   mHead = new nsXFormsXPathNode(mHead);
00077   if (aStartIndex == -100) {
00078     mHead->mStartIndex = mScanner.Offset() + 1;
00079   } else {
00080     mHead->mStartIndex = aStartIndex;
00081   }
00082   mStack[++mAnalyzeStackPointer] = mHead;
00083   mHead->mPredicate = mPredicateLevel != 0;
00084   mHead->mLiteral = PR_FALSE;
00085 }
00086 
00087 void
00088 nsXFormsXPathParser::PushContext(nsXFormsXPathNode* aNode)
00089 {
00090   mStack[++mAnalyzeStackPointer] = aNode;
00091   mHead = aNode;
00092 }
00093 
00094 void
00095 nsXFormsXPathParser::EndContext()
00096 {
00097   if (mHead) {
00098     mHead->mEndIndex = mScanner.Offset() + 1;
00099   }
00100 }
00101 
00102 void
00103 nsXFormsXPathParser::RestartContext()
00104 {
00105   nsXFormsXPathNode* temp = new nsXFormsXPathNode(nsnull, PR_TRUE);
00106   temp->mStartIndex = mScanner.Offset() + 1;
00107   temp->mSibling = mHead->mChild;
00108   temp->mPredicate = mPredicateLevel != 0;
00109   mHead->mChild = temp;
00110   mHead = temp;
00111   mStack[mAnalyzeStackPointer] = mHead;
00112 }
00113 
00114 nsXFormsXPathNode*
00115 nsXFormsXPathParser::JustContext()
00116 {
00117   nsXFormsXPathNode* t = mStack[mAnalyzeStackPointer];
00118   mHead = mStack[--mAnalyzeStackPointer];
00119   return t;
00120 }
00121 
00122 
00123 nsXFormsXPathNode*
00124 nsXFormsXPathParser::PopContext()
00125 {
00126   if (mHead->mEndIndex == -100) {
00127     mHead->mEndIndex = mScanner.Offset() + 1;
00128   }
00129 
00130   NS_ASSERTION(mHead->mStartIndex <= mHead->mEndIndex, "");
00131   NS_ASSERTION(mAnalyzeStackPointer - 1 >= 0, "");
00132   mHead = mStack[--mAnalyzeStackPointer];
00133 
00134   return mHead;
00135 }
00136 
00137 void
00138 nsXFormsXPathParser::AbbreviatedStep()
00139 {
00140   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00141   switch (t) {
00142   case nsXFormsXPathScanner::DOT:
00143     PopToken();
00144     break;
00145 
00146   case nsXFormsXPathScanner::DOTDOT:
00147     PopToken();
00148     break;
00149 
00150   default:
00151     XPathCompilerException("Expected . or ..", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00152     break;
00153   }
00154 }
00155 
00156 void
00157 nsXFormsXPathParser::AbsoluteLocationPath()
00158 {
00159   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00160   nsXFormsXPathScanner::XPATHTOKEN r;
00161   switch (t) {
00162   case nsXFormsXPathScanner::SLASH:
00163     PopToken();
00164     r = PeekToken();
00165     switch (r) {
00166     case nsXFormsXPathScanner::ANCESTOR:
00167     case nsXFormsXPathScanner::ANCESTOR_OR_SELF:
00168     case nsXFormsXPathScanner::ATTRIBUTE:
00169     case nsXFormsXPathScanner::CHILD:
00170     case nsXFormsXPathScanner::DESCENDANT:
00171     case nsXFormsXPathScanner::DESCENDANT_OR_SELF:
00172     case nsXFormsXPathScanner::FOLLOWING:
00173     case nsXFormsXPathScanner::FOLLOWING_SIBLING:
00174     case nsXFormsXPathScanner::NAMESPACE:
00175     case nsXFormsXPathScanner::PARENT:
00176     case nsXFormsXPathScanner::PRECEDING:
00177     case nsXFormsXPathScanner::PRECEDING_SIBLING:
00178     case nsXFormsXPathScanner::SELF:
00179     case nsXFormsXPathScanner::AT:
00180     case nsXFormsXPathScanner::STAR:
00181     case nsXFormsXPathScanner::NCNAME:
00182     case nsXFormsXPathScanner::QNAME:
00183     case nsXFormsXPathScanner::COMMENT:
00184     case nsXFormsXPathScanner::TEXT:
00185     case nsXFormsXPathScanner::PI:
00186     case nsXFormsXPathScanner::NODE:
00187     case nsXFormsXPathScanner::DOT:
00188     case nsXFormsXPathScanner::DOTDOT:
00189       RelativeLocationPath();
00190       break;
00191       
00192     default:
00193       break;
00194     }
00195     break;
00196 
00197   case nsXFormsXPathScanner::SLASHSLASH:
00198     PopToken();
00199     if (DoRelative()) {
00200       RelativeLocationPath();
00201     }
00202     break;
00203 
00204   default:
00205     XPathCompilerException("Not an absolute location path", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00206   }
00207 }
00208 
00209 void
00210 nsXFormsXPathParser::AdditiveExpression()
00211 {
00212   PRBool con = PR_TRUE;
00213 
00214   MultiplicationExpr();
00215 
00216   while (con) {
00217     nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00218     switch (t) {
00219     case nsXFormsXPathScanner::PLUS:
00220       PopToken();
00221       MultiplicationExpr();
00222       break;
00223 
00224     case nsXFormsXPathScanner::MINUS:
00225       PopToken();
00226       MultiplicationExpr();
00227       break;
00228 
00229     default:
00230       con = PR_FALSE;
00231     }
00232   }
00233 }
00234 
00235 void
00236 nsXFormsXPathParser::AndExpr()
00237 {
00238   EqualityExpr();
00239   if (PeekToken() == nsXFormsXPathScanner::AND) {
00240     PopToken();
00241     AndExpr();
00242   }
00243 }
00244 
00245 void
00246 nsXFormsXPathParser::AxisSpecifier()
00247 {
00248   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00249   switch (t) {
00250   case nsXFormsXPathScanner::ANCESTOR:
00251   case nsXFormsXPathScanner::ANCESTOR_OR_SELF:
00252   case nsXFormsXPathScanner::ATTRIBUTE:
00253   case nsXFormsXPathScanner::CHILD:
00254   case nsXFormsXPathScanner::DESCENDANT:
00255   case nsXFormsXPathScanner::DESCENDANT_OR_SELF:
00256   case nsXFormsXPathScanner::FOLLOWING:
00257   case nsXFormsXPathScanner::FOLLOWING_SIBLING:
00258   case nsXFormsXPathScanner::NAMESPACE:
00259   case nsXFormsXPathScanner::PARENT:
00260   case nsXFormsXPathScanner::PRECEDING:
00261   case nsXFormsXPathScanner::PRECEDING_SIBLING:
00262   case nsXFormsXPathScanner::SELF:
00263     PopToken();
00264   case nsXFormsXPathScanner::AT:
00265     PopToken();
00266     break;
00267     
00268   default:
00269     XPathCompilerException("Not a axis specifier", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00270     break;
00271   }
00272 }
00273 
00274 PRBool
00275 nsXFormsXPathParser::DoRelative()
00276 {
00277   PRBool ret = PR_FALSE;
00278 
00279   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00280   switch (t) {
00281   case nsXFormsXPathScanner::ANCESTOR:
00282   case nsXFormsXPathScanner::ANCESTOR_OR_SELF:
00283   case nsXFormsXPathScanner::ATTRIBUTE:
00284   case nsXFormsXPathScanner::CHILD:
00285   case nsXFormsXPathScanner::DESCENDANT:
00286   case nsXFormsXPathScanner::DESCENDANT_OR_SELF:
00287   case nsXFormsXPathScanner::FOLLOWING:
00288   case nsXFormsXPathScanner::FOLLOWING_SIBLING:
00289   case nsXFormsXPathScanner::NAMESPACE:
00290   case nsXFormsXPathScanner::PARENT:
00291   case nsXFormsXPathScanner::PRECEDING:
00292   case nsXFormsXPathScanner::PRECEDING_SIBLING:
00293   case nsXFormsXPathScanner::SELF:
00294   case nsXFormsXPathScanner::AT:
00295   case nsXFormsXPathScanner::STAR:
00296   case nsXFormsXPathScanner::NCNAME:
00297   case nsXFormsXPathScanner::QNAME:
00298   case nsXFormsXPathScanner::COMMENT:
00299   case nsXFormsXPathScanner::TEXT:
00300   case nsXFormsXPathScanner::PI:
00301   case nsXFormsXPathScanner::NODE:
00302   case nsXFormsXPathScanner::DOT:
00303   case nsXFormsXPathScanner::DOTDOT:
00304     ret = PR_TRUE;
00305     break;
00306     
00307   default:
00308     break;
00309   }
00310   return ret;
00311 }
00312 
00313 void
00314 nsXFormsXPathParser::EqualityExpr()
00315 {
00316   RelationalExpression();
00317 
00318   PRBool con = PR_TRUE;
00319   while (con) {
00320     nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00321     switch (t) {
00322     case nsXFormsXPathScanner::EQUAL:
00323       PopToken();
00324       RelationalExpression();
00325       break;
00326 
00327     case nsXFormsXPathScanner::NOTEQUAL:
00328       PopToken();
00329       RelationalExpression();
00330       break;
00331 
00332     default:
00333       con = PR_FALSE;
00334     }
00335   }
00336 }
00337 
00338 void
00339 nsXFormsXPathParser::Expr()
00340 {
00341   OrExpr();
00342 }
00343 
00344 void
00345 nsXFormsXPathParser::FilterExpr()
00346 {
00347   if (PrimaryExpr() && PeekToken() == nsXFormsXPathScanner::LBRACK) {
00348       Predicate();
00349   }
00350 }
00351 
00352 void
00353 nsXFormsXPathParser::FunctionCall()
00354 {
00355   nsDependentSubstring fname = Substring(mScanner.Expression(),
00356                                          mScanner.Offset() + 1,
00357                                          mScanner.Length());
00358   if (!mUsesDynamicFunc && fname.Equals(NS_LITERAL_STRING("now"))) {
00359     mUsesDynamicFunc = PR_TRUE;
00360   }
00361 
00362   PopToken();
00363   PopToken();
00364   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00365 
00366   PRBool con = t == nsXFormsXPathScanner::RPARAN ? PR_FALSE : PR_TRUE;
00367   while (con) {
00368     if (t == nsXFormsXPathScanner::XPATHEOF) {
00369       XPathCompilerException("Expected ) got EOF",
00370                              mScanner.Expression(),
00371                              mScanner.Offset(),
00372                              mScanner.Length());
00373     }
00374     nsXFormsXPathNode* c = JustContext();
00375     Expr();
00376     if (fname.Equals(NS_LITERAL_STRING("index"))) {
00377       c->mIsIndex = PR_TRUE;
00378     }
00379     PushContext(c);
00380 
00381     t = PeekToken();
00382     con = (t == nsXFormsXPathScanner::COMMA);
00383     if (con) {
00384       PopToken(); // Another Argument
00385     }
00386   }
00387 
00388   if (t != nsXFormsXPathScanner::RPARAN) {
00389     XPathCompilerException("Expected )", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00390   }
00391 
00392   PopToken();
00393 }
00394 
00395 void
00396 nsXFormsXPathParser::LocationPath()
00397 {
00398   if (DoRelative()) {
00399     PushContext();
00400     RelativeLocationPath();
00401     PopContext();
00402   } else {
00403     nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00404     switch (t) {
00405     case nsXFormsXPathScanner::SLASH:
00406     case nsXFormsXPathScanner::SLASHSLASH:
00407       PushContext();
00408       AbsoluteLocationPath();
00409       PopContext();
00410       break;
00411 
00412     default:
00413       XPathCompilerException("Not a location path", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00414     }
00415   }
00416 }
00417 
00418 void
00419 nsXFormsXPathParser::MultiplicationExpr()
00420 {
00421   UnaryExpr();
00422   PRBool con = PR_TRUE;
00423   while (con) {
00424     nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00425     switch (t) {
00426     case nsXFormsXPathScanner::MULTIPLYOPERATOR:
00427     case nsXFormsXPathScanner::DIV:
00428     case nsXFormsXPathScanner::MOD:
00429       PopToken();
00430       UnaryExpr();
00431       break;
00432     default:
00433       con = PR_FALSE;
00434     }
00435   }
00436 }
00437 
00438 void
00439 nsXFormsXPathParser::NameTest()
00440 {
00441   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00442   switch (t) {
00443   case nsXFormsXPathScanner::STAR:
00444   case nsXFormsXPathScanner::NCNAME:
00445   case nsXFormsXPathScanner::QNAME:
00446     PopToken();
00447     break;
00448   default:
00449     XPathCompilerException("NodeTest error", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00450   }
00451 }
00452 
00453 void
00454 nsXFormsXPathParser::NodeTest()
00455 {
00456   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00457   switch (t) {
00458   case nsXFormsXPathScanner::STAR:
00459   case nsXFormsXPathScanner::NCNAME:
00460   case nsXFormsXPathScanner::QNAME:
00461     NameTest();
00462     break;
00463   case nsXFormsXPathScanner::COMMENT:
00464   case nsXFormsXPathScanner::TEXT:
00465   case nsXFormsXPathScanner::PI:
00466   case nsXFormsXPathScanner::NODE:
00467     NodeType();
00468     break;
00469   default:
00470     XPathCompilerException("Not a node test", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00471   }
00472 }
00473 
00474 void
00475 nsXFormsXPathParser::NodeType()
00476 {
00477   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00478   switch (t) {
00479   case nsXFormsXPathScanner::COMMENT:
00480     PopToken();
00481     PopToken();
00482     PopToken();
00483     break;
00484   case nsXFormsXPathScanner::TEXT:
00485     PopToken();
00486     PopToken();
00487     PopToken();
00488     break;
00489   case nsXFormsXPathScanner::PI:
00490     PopToken();
00491     if ((t = PeekToken()) == nsXFormsXPathScanner::LPARAN) {
00492       PopToken();
00493       PopToken();
00494       PopToken();
00495     }
00496     break;
00497 
00498   case nsXFormsXPathScanner::NODE:
00499     PopToken();
00500     PopToken();
00501     PopToken();
00502     break;
00503 
00504   default:
00505     XPathCompilerException("Not a valid NodeType", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00506   }
00507 }
00508 
00509 void
00510 nsXFormsXPathParser::OrExpr()
00511 {
00512   AndExpr();
00513   if (PeekToken() == nsXFormsXPathScanner::OR) {
00514     PopToken();
00515     OrExpr();
00516   }
00517 }
00518 
00519 void
00520 nsXFormsXPathParser::PathExpr()
00521 {
00522   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00523   switch (t) {
00524   case nsXFormsXPathScanner::ANCESTOR:
00525   case nsXFormsXPathScanner::ANCESTOR_OR_SELF:
00526   case nsXFormsXPathScanner::ATTRIBUTE:
00527   case nsXFormsXPathScanner::CHILD:
00528   case nsXFormsXPathScanner::DESCENDANT:
00529   case nsXFormsXPathScanner::DESCENDANT_OR_SELF:
00530   case nsXFormsXPathScanner::FOLLOWING:
00531   case nsXFormsXPathScanner::FOLLOWING_SIBLING:
00532   case nsXFormsXPathScanner::NAMESPACE:
00533   case nsXFormsXPathScanner::PARENT:
00534   case nsXFormsXPathScanner::PRECEDING:
00535   case nsXFormsXPathScanner::PRECEDING_SIBLING:
00536   case nsXFormsXPathScanner::SELF:
00537   case nsXFormsXPathScanner::AT:
00538   case nsXFormsXPathScanner::STAR:
00539   case nsXFormsXPathScanner::NCNAME:
00540   case nsXFormsXPathScanner::QNAME:
00541   case nsXFormsXPathScanner::COMMENT:
00542   case nsXFormsXPathScanner::TEXT:
00543   case nsXFormsXPathScanner::PI:
00544   case nsXFormsXPathScanner::NODE:
00545   case nsXFormsXPathScanner::DOT:
00546   case nsXFormsXPathScanner::DOTDOT:
00547   case nsXFormsXPathScanner::SLASH:
00548   case nsXFormsXPathScanner::SLASHSLASH:
00549     LocationPath();
00550     break;
00551     
00552   default:
00553     PushContext();
00554     FilterExpr();
00555     t = PeekToken();
00556     if (t == nsXFormsXPathScanner::SLASH || t == nsXFormsXPathScanner::SLASHSLASH) {
00557       PopToken();
00558 
00559       if (DoRelative()) {
00560         RelativeLocationPath();
00561       } else {
00562         XPathCompilerException("After / in a filter expression it is required to have a reletive path expression", EmptyString());
00563       }
00564 
00565     }
00566     PopContext();
00567   }
00568 }
00569 
00570 nsXFormsXPathScanner::XPATHTOKEN
00571 nsXFormsXPathParser::PeekToken()
00572 {
00573   return mPeek;
00574 }
00575 
00576 nsXFormsXPathScanner::XPATHTOKEN
00577 nsXFormsXPathParser::PopToken()
00578 {
00579   nsXFormsXPathScanner::XPATHTOKEN temp = mPeek;
00580   mPeek = mScanner.NextToken();
00581   if (mPeek == nsXFormsXPathScanner::WHITESPACE) { // Skip whitespaces
00582     mPeek = mScanner.NextToken();
00583   }
00584   NS_WARN_IF_FALSE(mPeek != nsXFormsXPathScanner::ERRORXPATHTOKEN,
00585                    "Scanner returned ERROR token!");
00586   return temp;
00587 }
00588 
00589 
00590 void
00591 nsXFormsXPathParser::Predicate()
00592 {
00593   EndContext();
00594   mPredicateLevel++;
00595   while (PeekToken() == nsXFormsXPathScanner::LBRACK) {
00596     PopToken();
00597     Expr();
00598 
00599     nsXFormsXPathScanner::XPATHTOKEN t = PopToken();
00600     if (t != nsXFormsXPathScanner::RBRACK) {
00601       XPathCompilerException("Expected ]", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00602     }
00603   }
00604   mPredicateLevel--;
00605   RestartContext();
00606 }
00607 
00608 PRBool
00609 nsXFormsXPathParser::PrimaryExpr()
00610 {
00611   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00612   switch (t) {
00613   case nsXFormsXPathScanner::VARIABLE:
00614     PopToken();
00615     break;
00616     
00617   case nsXFormsXPathScanner::LPARAN: {
00618       PopToken();
00619       nsXFormsXPathNode* c = JustContext();
00620       Expr();
00621       PushContext(c);
00622       if (PeekToken() == nsXFormsXPathScanner::RPARAN) {
00623         PopToken(); 
00624       } else {
00625         XPathCompilerException("Expected )", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00626       }
00627     }
00628     break;
00629     
00630   case nsXFormsXPathScanner::LITERAL:
00631     mHead->mLiteral = PR_TRUE;
00632     PopToken();
00633     break;
00634     
00635   case nsXFormsXPathScanner::NUMBER:
00636     mHead->mLiteral = PR_TRUE;
00637     PopToken();
00638     break;
00639     
00640   case nsXFormsXPathScanner::FUNCTIONNAME:
00641     FunctionCall();
00642     return PeekToken() == nsXFormsXPathScanner::SLASH || PeekToken() == nsXFormsXPathScanner::SLASHSLASH || PeekToken() == nsXFormsXPathScanner::LBRACK;
00643     break;
00644     
00645   default:
00646     XPathCompilerException("Not a primary expression", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00647   }
00648   
00649   return PR_FALSE;
00650 }
00651 
00652 void
00653 nsXFormsXPathParser::RelationalExpression()
00654 {
00655   AdditiveExpression();
00656   PRBool con = PR_TRUE;
00657   while (con) {
00658     nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00659     switch (t) {
00660     case nsXFormsXPathScanner::LESS:
00661       PopToken();
00662       AdditiveExpression();
00663       break;
00664 
00665     case nsXFormsXPathScanner::LEQUAL:
00666       PopToken();
00667       AdditiveExpression();
00668       break;
00669 
00670     case nsXFormsXPathScanner::GREATER:
00671       PopToken();
00672       AdditiveExpression();
00673       break;
00674 
00675     case nsXFormsXPathScanner::GEQUAL:
00676       PopToken();
00677       AdditiveExpression();
00678       break;
00679       
00680     default:
00681       con = PR_FALSE;
00682     }
00683   }
00684 }
00685 
00686 void
00687 nsXFormsXPathParser::RelativeLocationPath()
00688 {
00689   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00690   switch (t) {
00691   case nsXFormsXPathScanner::ANCESTOR:
00692   case nsXFormsXPathScanner::ANCESTOR_OR_SELF:
00693   case nsXFormsXPathScanner::ATTRIBUTE:
00694   case nsXFormsXPathScanner::CHILD:
00695   case nsXFormsXPathScanner::DESCENDANT:
00696   case nsXFormsXPathScanner::DESCENDANT_OR_SELF:
00697   case nsXFormsXPathScanner::FOLLOWING:
00698   case nsXFormsXPathScanner::FOLLOWING_SIBLING:
00699   case nsXFormsXPathScanner::NAMESPACE:
00700   case nsXFormsXPathScanner::PARENT:
00701   case nsXFormsXPathScanner::PRECEDING:
00702   case nsXFormsXPathScanner::PRECEDING_SIBLING:
00703   case nsXFormsXPathScanner::SELF:
00704   case nsXFormsXPathScanner::AT:
00705   case nsXFormsXPathScanner::STAR:
00706   case nsXFormsXPathScanner::NCNAME:
00707   case nsXFormsXPathScanner::QNAME:
00708   case nsXFormsXPathScanner::COMMENT:
00709   case nsXFormsXPathScanner::TEXT:
00710   case nsXFormsXPathScanner::PI:
00711   case nsXFormsXPathScanner::NODE:
00712     Step();
00713     break;
00714     
00715   case nsXFormsXPathScanner::DOT:
00716   case nsXFormsXPathScanner::DOTDOT:
00717     AbbreviatedStep();
00718     break;
00719 
00720   default:
00721     XPathCompilerException("Not a relative location path ", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00722   }
00723 
00724   t = PeekToken();
00725   
00726   if (t == nsXFormsXPathScanner::SLASH || t == nsXFormsXPathScanner::SLASHSLASH) {
00727     PopToken();
00728     if (DoRelative()) {
00729       RelativeLocationPath();
00730     }
00731   }
00732 }
00733 
00734 void
00735 nsXFormsXPathParser::Step()
00736 {
00737   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00738   switch (t) {
00739   case nsXFormsXPathScanner::ANCESTOR:
00740   case nsXFormsXPathScanner::ANCESTOR_OR_SELF:
00741   case nsXFormsXPathScanner::ATTRIBUTE:
00742   case nsXFormsXPathScanner::CHILD:
00743   case nsXFormsXPathScanner::DESCENDANT:
00744   case nsXFormsXPathScanner::DESCENDANT_OR_SELF:
00745   case nsXFormsXPathScanner::FOLLOWING:
00746   case nsXFormsXPathScanner::FOLLOWING_SIBLING:
00747   case nsXFormsXPathScanner::NAMESPACE:
00748   case nsXFormsXPathScanner::PARENT:
00749   case nsXFormsXPathScanner::PRECEDING:
00750   case nsXFormsXPathScanner::PRECEDING_SIBLING:
00751   case nsXFormsXPathScanner::SELF:
00752   case nsXFormsXPathScanner::AT:
00753     AxisSpecifier();
00754     break;
00755 
00756   default:
00757     break;
00758   }
00759   
00760   t = PeekToken();
00761   switch (t) {
00762   case nsXFormsXPathScanner::STAR:
00763   case nsXFormsXPathScanner::NCNAME:
00764   case nsXFormsXPathScanner::QNAME:
00765   case nsXFormsXPathScanner::COMMENT:
00766   case nsXFormsXPathScanner::TEXT:
00767   case nsXFormsXPathScanner::PI:
00768   case nsXFormsXPathScanner::NODE:
00769     NodeTest();
00770     break;
00771     
00772   default:
00773     XPathCompilerException("Expected a NodeTest expression", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00774   }
00775   
00776   t = PeekToken();
00777   if (t == nsXFormsXPathScanner::LBRACK) {
00778     Predicate(); // set the predicates
00779   }
00780 }
00781 
00782 void
00783 nsXFormsXPathParser::UnaryExpr()
00784 {
00785   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00786   switch (t) {
00787   case nsXFormsXPathScanner::MINUS:
00788     PopToken();
00789     UnaryExpr();
00790     break;
00791     
00792   default:
00793     UnionExpr();
00794   }
00795 }
00796 
00797 void
00798 nsXFormsXPathParser::UnionExpr()
00799 {
00800   nsXFormsXPathScanner::XPATHTOKEN t = PeekToken();
00801   switch (t) {
00802   case nsXFormsXPathScanner::ANCESTOR:
00803   case nsXFormsXPathScanner::ANCESTOR_OR_SELF:
00804   case nsXFormsXPathScanner::ATTRIBUTE:
00805   case nsXFormsXPathScanner::CHILD:
00806   case nsXFormsXPathScanner::DESCENDANT:
00807   case nsXFormsXPathScanner::DESCENDANT_OR_SELF:
00808   case nsXFormsXPathScanner::FOLLOWING:
00809   case nsXFormsXPathScanner::FOLLOWING_SIBLING:
00810   case nsXFormsXPathScanner::NAMESPACE:
00811   case nsXFormsXPathScanner::PARENT:
00812   case nsXFormsXPathScanner::PRECEDING:
00813   case nsXFormsXPathScanner::PRECEDING_SIBLING:
00814   case nsXFormsXPathScanner::SELF:
00815   case nsXFormsXPathScanner::AT:
00816   case nsXFormsXPathScanner::STAR:
00817   case nsXFormsXPathScanner::NCNAME:
00818   case nsXFormsXPathScanner::QNAME:
00819   case nsXFormsXPathScanner::COMMENT:
00820   case nsXFormsXPathScanner::TEXT:
00821   case nsXFormsXPathScanner::PI:
00822   case nsXFormsXPathScanner::NODE:
00823   case nsXFormsXPathScanner::DOT:
00824   case nsXFormsXPathScanner::DOTDOT:
00825   case nsXFormsXPathScanner::SLASH:
00826   case nsXFormsXPathScanner::SLASHSLASH:
00827     PathExpr();
00828     t = PeekToken();
00829     if (t == nsXFormsXPathScanner::UNION) {
00830       PopToken();
00831       UnionExpr();
00832     }
00833     break;
00834     
00835   case nsXFormsXPathScanner::VARIABLE:
00836   case nsXFormsXPathScanner::LPARAN:
00837   case nsXFormsXPathScanner::LITERAL:
00838   case nsXFormsXPathScanner::NUMBER:
00839   case nsXFormsXPathScanner::FUNCTIONNAME:
00840     PathExpr();
00841     t = PeekToken();
00842     if (t == nsXFormsXPathScanner::UNION) {
00843       PopToken();
00844       UnionExpr();
00845     }
00846     break;
00847     
00848   default:
00849     XPathCompilerException("Unexpected union token", mScanner.Expression(), mScanner.Offset(), mScanner.Length());
00850   }
00851 }
00852 
00853 nsXFormsXPathNode*
00854 nsXFormsXPathParser::Parse(const nsAString& aExpression)
00855 {
00856 #ifdef DEBUG_XF_PARSER
00857   printf("=====================================\n");
00858   printf("Parsing: %s\n", NS_ConvertUTF16toUTF8(aExpression).get());
00859   printf("=====================================\n");
00860 #endif
00861 
00862   mScanner.Init(aExpression);
00863   mAnalyzeStackPointer = 0;
00864   mPredicateLevel = 0;
00865   mHead = nsnull;
00866   PopToken();
00867   PushContext();
00868   
00869   nsXFormsXPathNode* root = mHead;
00870   Expr();
00871   PopContext();
00872 
00873 #ifdef DEBUG_XF_PARSER
00874   Dump(root);
00875   printf("-------------------------------------\n");
00876 #endif
00877 
00878   return root;
00879 }
00880 
00881 PRBool
00882 nsXFormsXPathParser::UsesDynamicFunc() const {
00883   return mUsesDynamicFunc;
00884 }
00885 
00886 #ifdef DEBUG_XF_PARSER
00887 void
00888 nsXFormsXPathParser::Dump(nsXFormsXPathNode* aNode)
00889 {
00890   DumpWithLevel(aNode->mChild, 0);
00891 }
00892 
00893 void
00894 nsXFormsXPathParser::DumpWithLevel(nsXFormsXPathNode* aNode, PRInt32 aLevel)
00895 {
00896   while (aNode) {
00897     if (aNode->mStartIndex < aNode->mEndIndex) {
00898       for (int i = 0; i < aLevel; i++) {
00899         printf(" ");
00900       }
00901       if (aNode->mCon) {
00902         printf("(+)");
00903       } else {
00904         printf("(|)");
00905       }
00906       OutputSubExpression(aNode->mStartIndex, aNode->mEndIndex);
00907     }
00908     DumpWithLevel(aNode->mChild, aLevel + 2);
00909     aNode = aNode->mSibling;
00910   }
00911 }
00912 
00913 void
00914 nsXFormsXPathParser::OutputSubExpression(PRInt32 aOffset, PRInt32 aEndOffset)
00915 {
00916   const nsDependentSubstring expr = Substring(mScanner.Expression(), aOffset, aEndOffset - aOffset);
00917   printf("%s\n", NS_ConvertUTF16toUTF8(expr).get());
00918 }
00919 #endif