2004-10-13 09:51:52 +00:00
|
|
|
/* -*- 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 <abeaufour@novell.com>
|
|
|
|
* David Landwehr <dlandwehr@novell.com>
|
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
|
|
|
|
/*
|
2005-01-19 16:05:31 +00:00
|
|
|
* @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)
|
2004-10-13 09:51:52 +00:00
|
|
|
*/
|
|
|
|
void
|
2005-01-19 16:05:31 +00:00
|
|
|
XPathCompilerException(const char *aMsg,
|
|
|
|
nsAString &aExpression,
|
|
|
|
PRInt32 aOffset = -1,
|
|
|
|
PRInt32 aLength = -1)
|
|
|
|
{
|
2004-10-13 09:51:52 +00:00
|
|
|
printf("XPathCompilerException: %s, %s [o: %d, l: %d]\n",
|
|
|
|
aMsg,
|
|
|
|
NS_ConvertUCS2toUTF8(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()
|
|
|
|
{
|
|
|
|
if (!mUsesDynamicFunc) {
|
|
|
|
nsDependentSubstring fname = Substring(mScanner.Expression(), mScanner.Offset() + 1, mScanner.Offset() + mScanner.Length() + 1);
|
|
|
|
if (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();
|
|
|
|
PushContext(c);
|
|
|
|
|
|
|
|
t = PeekToken();
|
|
|
|
if (t == nsXFormsXPathScanner::COMMA) {
|
|
|
|
PopToken(); // Another Argument
|
|
|
|
con = PR_TRUE;
|
|
|
|
} else {
|
|
|
|
con = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
nsAutoString nullstr;
|
|
|
|
XPathCompilerException("After / in a filter expression it is required to have a reletive path expression", nullstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
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_ConvertUCS2toUTF8(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_ConvertUCS2toUTF8(expr).get());
|
|
|
|
}
|
|
|
|
#endif
|