/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla XForms support. * * The Initial Developer of the Original Code is * Novell, Inc. * Portions created by the Initial Developer are Copyright (C) 2004 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Allan Beaufour * David Landwehr * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsXFormsXPathParser.h" #include "nscore.h" /* * @todo GIANT hack. Without exceptions everything had to be rewritten, and * that was to overdo it a bit, when the code probably does not survive... (XXX) */ void XPathCompilerException(const char *aMsg, const nsAString &aExpression, PRInt32 aOffset = -1, PRInt32 aLength = -1) { printf("XPathCompilerException: %s, %s [o: %d, l: %d]\n", aMsg, NS_ConvertUTF16toUTF8(aExpression).get(), aOffset, aLength); printf("WARNING: Houston we have a problem, and unlike Apollo 13, we're not going to make it!\n"); NS_ABORT(); } MOZ_DECL_CTOR_COUNTER(nsXFormsXPathParser) nsXFormsXPathParser::nsXFormsXPathParser() : mUsesDynamicFunc(PR_FALSE), mHead(nsnull), mAnalyzeStackPointer(nsnull) { MOZ_COUNT_CTOR(nsXFormsXPathParser); } nsXFormsXPathParser::~nsXFormsXPathParser() { MOZ_COUNT_DTOR(nsXFormsXPathParser); } void nsXFormsXPathParser::PushContext(PRInt32 aStartIndex) { mHead = new nsXFormsXPathNode(mHead); if (aStartIndex == -100) { mHead->mStartIndex = mScanner.Offset() + 1; } else { mHead->mStartIndex = aStartIndex; } mStack[++mAnalyzeStackPointer] = mHead; mHead->mPredicate = mPredicateLevel != 0; mHead->mLiteral = PR_FALSE; } void nsXFormsXPathParser::PushContext(nsXFormsXPathNode* aNode) { mStack[++mAnalyzeStackPointer] = aNode; mHead = aNode; } void nsXFormsXPathParser::EndContext() { if (mHead) { mHead->mEndIndex = mScanner.Offset() + 1; } } void nsXFormsXPathParser::RestartContext() { nsXFormsXPathNode* temp = new nsXFormsXPathNode(nsnull, PR_TRUE); temp->mStartIndex = mScanner.Offset() + 1; temp->mSibling = mHead->mChild; temp->mPredicate = mPredicateLevel != 0; mHead->mChild = temp; mHead = temp; mStack[mAnalyzeStackPointer] = mHead; } nsXFormsXPathNode* nsXFormsXPathParser::JustContext() { nsXFormsXPathNode* t = mStack[mAnalyzeStackPointer]; mHead = mStack[--mAnalyzeStackPointer]; return t; } nsXFormsXPathNode* nsXFormsXPathParser::PopContext() { if (mHead->mEndIndex == -100) { mHead->mEndIndex = mScanner.Offset() + 1; } NS_ASSERTION(mHead->mStartIndex <= mHead->mEndIndex, ""); NS_ASSERTION(mAnalyzeStackPointer - 1 >= 0, ""); mHead = mStack[--mAnalyzeStackPointer]; return mHead; } void nsXFormsXPathParser::AbbreviatedStep() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::DOT: PopToken(); break; case nsXFormsXPathScanner::DOTDOT: PopToken(); break; default: XPathCompilerException("Expected . or ..", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); break; } } void nsXFormsXPathParser::AbsoluteLocationPath() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); nsXFormsXPathScanner::XPATHTOKEN r; switch (t) { case nsXFormsXPathScanner::SLASH: PopToken(); r = PeekToken(); switch (r) { case nsXFormsXPathScanner::ANCESTOR: case nsXFormsXPathScanner::ANCESTOR_OR_SELF: case nsXFormsXPathScanner::ATTRIBUTE: case nsXFormsXPathScanner::CHILD: case nsXFormsXPathScanner::DESCENDANT: case nsXFormsXPathScanner::DESCENDANT_OR_SELF: case nsXFormsXPathScanner::FOLLOWING: case nsXFormsXPathScanner::FOLLOWING_SIBLING: case nsXFormsXPathScanner::NAMESPACE: case nsXFormsXPathScanner::PARENT: case nsXFormsXPathScanner::PRECEDING: case nsXFormsXPathScanner::PRECEDING_SIBLING: case nsXFormsXPathScanner::SELF: case nsXFormsXPathScanner::AT: case nsXFormsXPathScanner::STAR: case nsXFormsXPathScanner::NCNAME: case nsXFormsXPathScanner::QNAME: case nsXFormsXPathScanner::COMMENT: case nsXFormsXPathScanner::TEXT: case nsXFormsXPathScanner::PI: case nsXFormsXPathScanner::NODE: case nsXFormsXPathScanner::DOT: case nsXFormsXPathScanner::DOTDOT: RelativeLocationPath(); break; default: break; } break; case nsXFormsXPathScanner::SLASHSLASH: PopToken(); if (DoRelative()) { RelativeLocationPath(); } break; default: XPathCompilerException("Not an absolute location path", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } } void nsXFormsXPathParser::AdditiveExpression() { PRBool con = PR_TRUE; MultiplicationExpr(); while (con) { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::PLUS: PopToken(); MultiplicationExpr(); break; case nsXFormsXPathScanner::MINUS: PopToken(); MultiplicationExpr(); break; default: con = PR_FALSE; } } } void nsXFormsXPathParser::AndExpr() { EqualityExpr(); if (PeekToken() == nsXFormsXPathScanner::AND) { PopToken(); AndExpr(); } } void nsXFormsXPathParser::AxisSpecifier() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::ANCESTOR: case nsXFormsXPathScanner::ANCESTOR_OR_SELF: case nsXFormsXPathScanner::ATTRIBUTE: case nsXFormsXPathScanner::CHILD: case nsXFormsXPathScanner::DESCENDANT: case nsXFormsXPathScanner::DESCENDANT_OR_SELF: case nsXFormsXPathScanner::FOLLOWING: case nsXFormsXPathScanner::FOLLOWING_SIBLING: case nsXFormsXPathScanner::NAMESPACE: case nsXFormsXPathScanner::PARENT: case nsXFormsXPathScanner::PRECEDING: case nsXFormsXPathScanner::PRECEDING_SIBLING: case nsXFormsXPathScanner::SELF: PopToken(); case nsXFormsXPathScanner::AT: PopToken(); break; default: XPathCompilerException("Not a axis specifier", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); break; } } PRBool nsXFormsXPathParser::DoRelative() { PRBool ret = PR_FALSE; nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::ANCESTOR: case nsXFormsXPathScanner::ANCESTOR_OR_SELF: case nsXFormsXPathScanner::ATTRIBUTE: case nsXFormsXPathScanner::CHILD: case nsXFormsXPathScanner::DESCENDANT: case nsXFormsXPathScanner::DESCENDANT_OR_SELF: case nsXFormsXPathScanner::FOLLOWING: case nsXFormsXPathScanner::FOLLOWING_SIBLING: case nsXFormsXPathScanner::NAMESPACE: case nsXFormsXPathScanner::PARENT: case nsXFormsXPathScanner::PRECEDING: case nsXFormsXPathScanner::PRECEDING_SIBLING: case nsXFormsXPathScanner::SELF: case nsXFormsXPathScanner::AT: case nsXFormsXPathScanner::STAR: case nsXFormsXPathScanner::NCNAME: case nsXFormsXPathScanner::QNAME: case nsXFormsXPathScanner::COMMENT: case nsXFormsXPathScanner::TEXT: case nsXFormsXPathScanner::PI: case nsXFormsXPathScanner::NODE: case nsXFormsXPathScanner::DOT: case nsXFormsXPathScanner::DOTDOT: ret = PR_TRUE; break; default: break; } return ret; } void nsXFormsXPathParser::EqualityExpr() { RelationalExpression(); PRBool con = PR_TRUE; while (con) { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::EQUAL: PopToken(); RelationalExpression(); break; case nsXFormsXPathScanner::NOTEQUAL: PopToken(); RelationalExpression(); break; default: con = PR_FALSE; } } } void nsXFormsXPathParser::Expr() { OrExpr(); } void nsXFormsXPathParser::FilterExpr() { if (PrimaryExpr() && PeekToken() == nsXFormsXPathScanner::LBRACK) { Predicate(); } } void nsXFormsXPathParser::FunctionCall() { nsDependentSubstring fname = Substring(mScanner.Expression(), mScanner.Offset() + 1, mScanner.Length()); if (!mUsesDynamicFunc && fname.Equals(NS_LITERAL_STRING("now"))) { mUsesDynamicFunc = PR_TRUE; } PopToken(); PopToken(); nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); PRBool con = t == nsXFormsXPathScanner::RPARAN ? PR_FALSE : PR_TRUE; while (con) { if (t == nsXFormsXPathScanner::XPATHEOF) { XPathCompilerException("Expected ) got EOF", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } nsXFormsXPathNode* c = JustContext(); Expr(); if (fname.Equals(NS_LITERAL_STRING("index"))) { c->mIsIndex = PR_TRUE; } PushContext(c); t = PeekToken(); con = (t == nsXFormsXPathScanner::COMMA); if (con) { PopToken(); // Another Argument } } if (t != nsXFormsXPathScanner::RPARAN) { XPathCompilerException("Expected )", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } PopToken(); } void nsXFormsXPathParser::LocationPath() { if (DoRelative()) { PushContext(); RelativeLocationPath(); PopContext(); } else { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::SLASH: case nsXFormsXPathScanner::SLASHSLASH: PushContext(); AbsoluteLocationPath(); PopContext(); break; default: XPathCompilerException("Not a location path", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } } } void nsXFormsXPathParser::MultiplicationExpr() { UnaryExpr(); PRBool con = PR_TRUE; while (con) { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::MULTIPLYOPERATOR: case nsXFormsXPathScanner::DIV: case nsXFormsXPathScanner::MOD: PopToken(); UnaryExpr(); break; default: con = PR_FALSE; } } } void nsXFormsXPathParser::NameTest() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::STAR: case nsXFormsXPathScanner::NCNAME: case nsXFormsXPathScanner::QNAME: PopToken(); break; default: XPathCompilerException("NodeTest error", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } } void nsXFormsXPathParser::NodeTest() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::STAR: case nsXFormsXPathScanner::NCNAME: case nsXFormsXPathScanner::QNAME: NameTest(); break; case nsXFormsXPathScanner::COMMENT: case nsXFormsXPathScanner::TEXT: case nsXFormsXPathScanner::PI: case nsXFormsXPathScanner::NODE: NodeType(); break; default: XPathCompilerException("Not a node test", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } } void nsXFormsXPathParser::NodeType() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::COMMENT: PopToken(); PopToken(); PopToken(); break; case nsXFormsXPathScanner::TEXT: PopToken(); PopToken(); PopToken(); break; case nsXFormsXPathScanner::PI: PopToken(); if ((t = PeekToken()) == nsXFormsXPathScanner::LPARAN) { PopToken(); PopToken(); PopToken(); } break; case nsXFormsXPathScanner::NODE: PopToken(); PopToken(); PopToken(); break; default: XPathCompilerException("Not a valid NodeType", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } } void nsXFormsXPathParser::OrExpr() { AndExpr(); if (PeekToken() == nsXFormsXPathScanner::OR) { PopToken(); OrExpr(); } } void nsXFormsXPathParser::PathExpr() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::ANCESTOR: case nsXFormsXPathScanner::ANCESTOR_OR_SELF: case nsXFormsXPathScanner::ATTRIBUTE: case nsXFormsXPathScanner::CHILD: case nsXFormsXPathScanner::DESCENDANT: case nsXFormsXPathScanner::DESCENDANT_OR_SELF: case nsXFormsXPathScanner::FOLLOWING: case nsXFormsXPathScanner::FOLLOWING_SIBLING: case nsXFormsXPathScanner::NAMESPACE: case nsXFormsXPathScanner::PARENT: case nsXFormsXPathScanner::PRECEDING: case nsXFormsXPathScanner::PRECEDING_SIBLING: case nsXFormsXPathScanner::SELF: case nsXFormsXPathScanner::AT: case nsXFormsXPathScanner::STAR: case nsXFormsXPathScanner::NCNAME: case nsXFormsXPathScanner::QNAME: case nsXFormsXPathScanner::COMMENT: case nsXFormsXPathScanner::TEXT: case nsXFormsXPathScanner::PI: case nsXFormsXPathScanner::NODE: case nsXFormsXPathScanner::DOT: case nsXFormsXPathScanner::DOTDOT: case nsXFormsXPathScanner::SLASH: case nsXFormsXPathScanner::SLASHSLASH: LocationPath(); break; default: PushContext(); FilterExpr(); t = PeekToken(); if (t == nsXFormsXPathScanner::SLASH || t == nsXFormsXPathScanner::SLASHSLASH) { PopToken(); if (DoRelative()) { RelativeLocationPath(); } else { XPathCompilerException("After / in a filter expression it is required to have a reletive path expression", EmptyString()); } } PopContext(); } } nsXFormsXPathScanner::XPATHTOKEN nsXFormsXPathParser::PeekToken() { return mPeek; } nsXFormsXPathScanner::XPATHTOKEN nsXFormsXPathParser::PopToken() { nsXFormsXPathScanner::XPATHTOKEN temp = mPeek; mPeek = mScanner.NextToken(); if (mPeek == nsXFormsXPathScanner::WHITESPACE) { // Skip whitespaces mPeek = mScanner.NextToken(); } NS_WARN_IF_FALSE(mPeek != nsXFormsXPathScanner::ERRORXPATHTOKEN, "Scanner returned ERROR token!"); return temp; } void nsXFormsXPathParser::Predicate() { EndContext(); mPredicateLevel++; while (PeekToken() == nsXFormsXPathScanner::LBRACK) { PopToken(); Expr(); nsXFormsXPathScanner::XPATHTOKEN t = PopToken(); if (t != nsXFormsXPathScanner::RBRACK) { XPathCompilerException("Expected ]", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } } mPredicateLevel--; RestartContext(); } PRBool nsXFormsXPathParser::PrimaryExpr() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::VARIABLE: PopToken(); break; case nsXFormsXPathScanner::LPARAN: { PopToken(); nsXFormsXPathNode* c = JustContext(); Expr(); PushContext(c); if (PeekToken() == nsXFormsXPathScanner::RPARAN) { PopToken(); } else { XPathCompilerException("Expected )", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } } break; case nsXFormsXPathScanner::LITERAL: mHead->mLiteral = PR_TRUE; PopToken(); break; case nsXFormsXPathScanner::NUMBER: mHead->mLiteral = PR_TRUE; PopToken(); break; case nsXFormsXPathScanner::FUNCTIONNAME: FunctionCall(); return PeekToken() == nsXFormsXPathScanner::SLASH || PeekToken() == nsXFormsXPathScanner::SLASHSLASH || PeekToken() == nsXFormsXPathScanner::LBRACK; break; default: XPathCompilerException("Not a primary expression", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } return PR_FALSE; } void nsXFormsXPathParser::RelationalExpression() { AdditiveExpression(); PRBool con = PR_TRUE; while (con) { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::LESS: PopToken(); AdditiveExpression(); break; case nsXFormsXPathScanner::LEQUAL: PopToken(); AdditiveExpression(); break; case nsXFormsXPathScanner::GREATER: PopToken(); AdditiveExpression(); break; case nsXFormsXPathScanner::GEQUAL: PopToken(); AdditiveExpression(); break; default: con = PR_FALSE; } } } void nsXFormsXPathParser::RelativeLocationPath() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::ANCESTOR: case nsXFormsXPathScanner::ANCESTOR_OR_SELF: case nsXFormsXPathScanner::ATTRIBUTE: case nsXFormsXPathScanner::CHILD: case nsXFormsXPathScanner::DESCENDANT: case nsXFormsXPathScanner::DESCENDANT_OR_SELF: case nsXFormsXPathScanner::FOLLOWING: case nsXFormsXPathScanner::FOLLOWING_SIBLING: case nsXFormsXPathScanner::NAMESPACE: case nsXFormsXPathScanner::PARENT: case nsXFormsXPathScanner::PRECEDING: case nsXFormsXPathScanner::PRECEDING_SIBLING: case nsXFormsXPathScanner::SELF: case nsXFormsXPathScanner::AT: case nsXFormsXPathScanner::STAR: case nsXFormsXPathScanner::NCNAME: case nsXFormsXPathScanner::QNAME: case nsXFormsXPathScanner::COMMENT: case nsXFormsXPathScanner::TEXT: case nsXFormsXPathScanner::PI: case nsXFormsXPathScanner::NODE: Step(); break; case nsXFormsXPathScanner::DOT: case nsXFormsXPathScanner::DOTDOT: AbbreviatedStep(); break; default: XPathCompilerException("Not a relative location path ", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } t = PeekToken(); if (t == nsXFormsXPathScanner::SLASH || t == nsXFormsXPathScanner::SLASHSLASH) { PopToken(); if (DoRelative()) { RelativeLocationPath(); } } } void nsXFormsXPathParser::Step() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::ANCESTOR: case nsXFormsXPathScanner::ANCESTOR_OR_SELF: case nsXFormsXPathScanner::ATTRIBUTE: case nsXFormsXPathScanner::CHILD: case nsXFormsXPathScanner::DESCENDANT: case nsXFormsXPathScanner::DESCENDANT_OR_SELF: case nsXFormsXPathScanner::FOLLOWING: case nsXFormsXPathScanner::FOLLOWING_SIBLING: case nsXFormsXPathScanner::NAMESPACE: case nsXFormsXPathScanner::PARENT: case nsXFormsXPathScanner::PRECEDING: case nsXFormsXPathScanner::PRECEDING_SIBLING: case nsXFormsXPathScanner::SELF: case nsXFormsXPathScanner::AT: AxisSpecifier(); break; default: break; } t = PeekToken(); switch (t) { case nsXFormsXPathScanner::STAR: case nsXFormsXPathScanner::NCNAME: case nsXFormsXPathScanner::QNAME: case nsXFormsXPathScanner::COMMENT: case nsXFormsXPathScanner::TEXT: case nsXFormsXPathScanner::PI: case nsXFormsXPathScanner::NODE: NodeTest(); break; default: XPathCompilerException("Expected a NodeTest expression", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } t = PeekToken(); if (t == nsXFormsXPathScanner::LBRACK) { Predicate(); // set the predicates } } void nsXFormsXPathParser::UnaryExpr() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::MINUS: PopToken(); UnaryExpr(); break; default: UnionExpr(); } } void nsXFormsXPathParser::UnionExpr() { nsXFormsXPathScanner::XPATHTOKEN t = PeekToken(); switch (t) { case nsXFormsXPathScanner::ANCESTOR: case nsXFormsXPathScanner::ANCESTOR_OR_SELF: case nsXFormsXPathScanner::ATTRIBUTE: case nsXFormsXPathScanner::CHILD: case nsXFormsXPathScanner::DESCENDANT: case nsXFormsXPathScanner::DESCENDANT_OR_SELF: case nsXFormsXPathScanner::FOLLOWING: case nsXFormsXPathScanner::FOLLOWING_SIBLING: case nsXFormsXPathScanner::NAMESPACE: case nsXFormsXPathScanner::PARENT: case nsXFormsXPathScanner::PRECEDING: case nsXFormsXPathScanner::PRECEDING_SIBLING: case nsXFormsXPathScanner::SELF: case nsXFormsXPathScanner::AT: case nsXFormsXPathScanner::STAR: case nsXFormsXPathScanner::NCNAME: case nsXFormsXPathScanner::QNAME: case nsXFormsXPathScanner::COMMENT: case nsXFormsXPathScanner::TEXT: case nsXFormsXPathScanner::PI: case nsXFormsXPathScanner::NODE: case nsXFormsXPathScanner::DOT: case nsXFormsXPathScanner::DOTDOT: case nsXFormsXPathScanner::SLASH: case nsXFormsXPathScanner::SLASHSLASH: PathExpr(); t = PeekToken(); if (t == nsXFormsXPathScanner::UNION) { PopToken(); UnionExpr(); } break; case nsXFormsXPathScanner::VARIABLE: case nsXFormsXPathScanner::LPARAN: case nsXFormsXPathScanner::LITERAL: case nsXFormsXPathScanner::NUMBER: case nsXFormsXPathScanner::FUNCTIONNAME: PathExpr(); t = PeekToken(); if (t == nsXFormsXPathScanner::UNION) { PopToken(); UnionExpr(); } break; default: XPathCompilerException("Unexpected union token", mScanner.Expression(), mScanner.Offset(), mScanner.Length()); } } nsXFormsXPathNode* nsXFormsXPathParser::Parse(const nsAString& aExpression) { #ifdef DEBUG_XF_PARSER printf("=====================================\n"); printf("Parsing: %s\n", NS_ConvertUTF16toUTF8(aExpression).get()); printf("=====================================\n"); #endif mScanner.Init(aExpression); mAnalyzeStackPointer = 0; mPredicateLevel = 0; mHead = nsnull; PopToken(); PushContext(); nsXFormsXPathNode* root = mHead; Expr(); PopContext(); #ifdef DEBUG_XF_PARSER Dump(root); printf("-------------------------------------\n"); #endif return root; } PRBool nsXFormsXPathParser::UsesDynamicFunc() const { return mUsesDynamicFunc; } #ifdef DEBUG_XF_PARSER void nsXFormsXPathParser::Dump(nsXFormsXPathNode* aNode) { DumpWithLevel(aNode->mChild, 0); } void nsXFormsXPathParser::DumpWithLevel(nsXFormsXPathNode* aNode, PRInt32 aLevel) { while (aNode) { if (aNode->mStartIndex < aNode->mEndIndex) { for (int i = 0; i < aLevel; i++) { printf(" "); } if (aNode->mCon) { printf("(+)"); } else { printf("(|)"); } OutputSubExpression(aNode->mStartIndex, aNode->mEndIndex); } DumpWithLevel(aNode->mChild, aLevel + 2); aNode = aNode->mSibling; } } void nsXFormsXPathParser::OutputSubExpression(PRInt32 aOffset, PRInt32 aEndOffset) { const nsDependentSubstring expr = Substring(mScanner.Expression(), aOffset, aEndOffset - aOffset); printf("%s\n", NS_ConvertUTF16toUTF8(expr).get()); } #endif