Bug 208172: Implement optimizable XPath. r=peterv sr=jst

git-svn-id: svn://10.0.0.236/trunk@188201 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
cvshook%sicking.cc
2006-01-26 01:50:30 +00:00
parent f8953bac47
commit 1c9ffd71d5
50 changed files with 1635 additions and 76 deletions

View File

@@ -231,6 +231,26 @@ void txList::clear()
itemCount = 0;
}
void*
txList::replace(PRUint32 aIndex, void* aObjPtr)
{
PRUint32 i = 0;
ListItem* item = firstItem;
while (i < aIndex && item) {
item = item->nextItem;
++i;
}
if (!item) {
return nsnull;
}
void* oldObj = item->objPtr;
item->objPtr = aObjPtr;
return oldObj;
}
//------------------------------------/
//- Implementation of txListIterator -/
//------------------------------------/

View File

@@ -74,6 +74,14 @@ public:
**/
PRInt32 getLength();
/**
* Returns true if there are no items in this txList
*/
inline PRBool isEmpty()
{
return itemCount == 0;
}
/**
* Adds the given Object to the specified position in the list
**/
@@ -94,6 +102,14 @@ public:
*/
void clear();
/**
* Replaces the Object at the given index with a new Object.
* If the given index is outside the list null is returned.
* @param aIndex index of Object to replace.
* @param aObjPtr new Object to put in the list.
* @return the old Object pointer
*/
void* replace(PRUint32 aIndex, void* aObjPtr);
protected:

View File

@@ -78,6 +78,7 @@ CPPSRCS = txAdditiveExpr.cpp \
txNumberFunctionCall.cpp \
txNumberResult.cpp \
txPathExpr.cpp \
txPredicatedNodeTest.cpp \
txPredicateList.cpp \
txRelationalExpr.cpp \
txRootExpr.cpp \
@@ -86,6 +87,7 @@ CPPSRCS = txAdditiveExpr.cpp \
txErrorExpr.cpp \
txLiteralExpr.cpp \
txNameTest.cpp \
txNamedAttributeStep.cpp \
txNodeSet.cpp \
txNodeTypeTest.cpp \
txForwardContext.cpp \
@@ -93,7 +95,8 @@ CPPSRCS = txAdditiveExpr.cpp \
txResultRecycler.cpp \
txUnionExpr.cpp \
txUnaryExpr.cpp \
txVariableRefExpr.cpp
txVariableRefExpr.cpp \
txXPathOptimizer.cpp
ifndef MOZ_XSLT_STANDALONE
CPPSRCS += nsXPathEvaluator.cpp \
nsXPathExpression.cpp \

View File

@@ -83,6 +83,15 @@ AdditiveExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return aContext->recycler()->getNumberResult(result, aResult);
} //-- evaluate
TX_IMPL_EXPR_STUBS_2(AdditiveExpr, NUMBER_RESULT, leftExpr, rightExpr)
PRBool
AdditiveExpr::isSensitiveTo(ContextSensitivity aContext)
{
return leftExpr->isSensitiveTo(aContext) ||
rightExpr->isSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
void
AdditiveExpr::toString(nsAString& str)
@@ -103,4 +112,3 @@ AdditiveExpr::toString(nsAString& str)
}
#endif

View File

@@ -85,6 +85,15 @@ BooleanExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_OK;
} //-- evaluate
TX_IMPL_EXPR_STUBS_2(BooleanExpr, BOOLEAN_RESULT, leftExpr, rightExpr)
PRBool
BooleanExpr::isSensitiveTo(ContextSensitivity aContext)
{
return leftExpr->isSensitiveTo(aContext) ||
rightExpr->isSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
void
BooleanExpr::toString(nsAString& str)

View File

@@ -143,6 +143,19 @@ BooleanFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_ERROR_UNEXPECTED;
}
Expr::ResultType
BooleanFunctionCall::getReturnType()
{
return BOOLEAN_RESULT;
}
PRBool
BooleanFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return argsSensitiveTo(aContext) ||
(mType == TX_LANG && (aContext & NODE_CONTEXT));
}
#ifdef TX_TO_STRING
nsresult
BooleanFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -57,6 +57,16 @@ txErrorExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_ERROR_XPATH_INVALID_EXPRESSION_EVALUATED;
}
TX_IMPL_EXPR_STUBS_0(txErrorExpr, ANY_RESULT)
PRBool
txErrorExpr::isSensitiveTo(ContextSensitivity aContext)
{
// It doesn't really matter what we return here, but it might
// be a good idea to try to keep this as unoptimizable as possible
return PR_TRUE;
}
#ifdef TX_TO_STRING
void
txErrorExpr::toString(nsAString& aStr)

View File

@@ -87,6 +87,69 @@ public:
virtual nsresult evaluate(txIEvalContext* aContext,
txAExprResult** aResult) = 0;
/**
* Returns the type of this expression.
*/
enum ExprType {
LOCATIONSTEP_ATTRIBUTE_EXPR,
LOCATIONSTEP_OTHER_EXPR,
OTHER_EXPR
};
virtual ExprType getType()
{
return OTHER_EXPR;
}
/**
* Returns the type or types of results this Expr return.
*/
typedef PRUint16 ResultType;
enum {
NODESET_RESULT = 0x01,
BOOLEAN_RESULT = 0x02,
NUMBER_RESULT = 0x04,
STRING_RESULT = 0x08,
RTF_RESULT = 0x10,
ANY_RESULT = 0xFFFF
};
virtual ResultType getReturnType() = 0;
PRBool canReturnType(ResultType aType)
{
return (getReturnType() & aType) != 0;
}
typedef PRUint16 ContextSensitivity;
enum {
NO_CONTEXT = 0x00,
DOCUMENT_CONTEXT = 0x01,
NODE_ONLY_CONTEXT = 0x02,
NODE_CONTEXT = DOCUMENT_CONTEXT | NODE_ONLY_CONTEXT,
POSITION_CONTEXT = 0x04,
SIZE_CONTEXT = 0x08,
NODESET_CONTEXT = POSITION_CONTEXT | SIZE_CONTEXT,
VARIABLES_CONTEXT = 0x10,
PRIVATE_CONTEXT = 0x20,
ANY_CONTEXT = 0xFFFF
};
/**
* Returns true if this expression is sensitive to *any* of
* the requested contexts in aContexts.
*/
virtual PRBool isSensitiveTo(ContextSensitivity aContexts) = 0;
/**
* Returns sub-expression at given position
*/
virtual Expr* getSubExprAt(PRUint32 aPos) = 0;
/**
* Replace sub-expression at given position. Does not delete the old
* expression, that is the responsibility of the caller.
*/
virtual void setSubExprAt(PRUint32 aPos, Expr* aExpr) = 0;
#ifdef TX_TO_STRING
/**
* Returns the String representation of this Expr.
@@ -100,21 +163,118 @@ public:
#endif
}; //-- Expr
#define TX_DECL_EVALUATE \
nsresult evaluate(txIEvalContext* aContext, txAExprResult** aResult)
#ifndef TX_TO_STRING
#define TX_DECL_EXPR TX_DECL_EVALUATE
#define TX_DECL_FUNCTION TX_DECL_EVALUATE
#ifdef TX_TO_STRING
#define TX_DECL_TOSTRING \
void toString(nsAString& aDest);
#define TX_DECL_GETNAMEATOM \
nsresult getNameAtom(nsIAtom** aAtom);
#else
#define TX_DECL_TOSTRING
#define TX_DECL_GETNAMEATOM
#endif
#define TX_DECL_EXPR_BASE \
nsresult evaluate(txIEvalContext* aContext, txAExprResult** aResult); \
ResultType getReturnType(); \
PRBool isSensitiveTo(ContextSensitivity aContexts)
#define TX_DECL_EXPR \
TX_DECL_EVALUATE; \
void toString(nsAString& aDest)
TX_DECL_EXPR_BASE; \
TX_DECL_TOSTRING \
Expr* getSubExprAt(PRUint32 aPos); \
void setSubExprAt(PRUint32 aPos, Expr* aExpr)
#define TX_DECL_OPTIMIZABLE_EXPR \
TX_DECL_EXPR; \
ExprType getType()
#define TX_DECL_FUNCTION \
TX_DECL_EVALUATE; \
nsresult getNameAtom(nsIAtom** aAtom)
#endif
TX_DECL_GETNAMEATOM \
TX_DECL_EXPR_BASE
#define TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
Expr::ResultType \
_class::getReturnType() \
{ \
return _ReturnType; \
}
#define TX_IMPL_EXPR_STUBS_0(_class, _ReturnType) \
TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
Expr* \
_class::getSubExprAt(PRUint32 aPos) \
{ \
return nsnull; \
} \
void \
_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \
{ \
NS_NOTREACHED("setting bad subexpression index"); \
}
#define TX_IMPL_EXPR_STUBS_1(_class, _ReturnType, _Expr1) \
TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
Expr* \
_class::getSubExprAt(PRUint32 aPos) \
{ \
if (aPos == 0) { \
return _Expr1; \
} \
return nsnull; \
} \
void \
_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \
{ \
NS_ASSERTION(aPos < 1, "setting bad subexpression index");\
_Expr1.forget(); \
_Expr1 = aExpr; \
}
#define TX_IMPL_EXPR_STUBS_2(_class, _ReturnType, _Expr1, _Expr2) \
TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
Expr* \
_class::getSubExprAt(PRUint32 aPos) \
{ \
switch(aPos) { \
case 0: \
return _Expr1; \
case 1: \
return _Expr2; \
default: \
break; \
} \
return nsnull; \
} \
void \
_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \
{ \
NS_ASSERTION(aPos < 2, "setting bad subexpression index");\
if (aPos == 0) { \
_Expr1.forget(); \
_Expr1 = aExpr; \
} \
else { \
_Expr2.forget(); \
_Expr2 = aExpr; \
} \
}
#define TX_IMPL_EXPR_STUBS_LIST(_class, _ReturnType, _ExprList) \
TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
Expr* \
_class::getSubExprAt(PRUint32 aPos) \
{ \
return NS_STATIC_CAST(Expr*, _ExprList.get(aPos)); \
} \
void \
_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \
{ \
NS_ASSERTION(aPos < (PRUint32)_ExprList.getLength(), \
"setting bad subexpression index"); \
_ExprList.replace(aPos, aExpr); \
}
/**
* This class represents a FunctionCall as defined by the XPath 1.0
@@ -149,9 +309,9 @@ public:
PRInt32 aParamCountMax,
txIEvalContext* aContext);
#ifdef TX_TO_STRING
void toString(nsAString& aDest);
#endif
TX_DECL_TOSTRING
Expr* getSubExprAt(PRUint32 aPos);
void setSubExprAt(PRUint32 aPos, Expr* aExpr);
protected:
@@ -183,6 +343,12 @@ protected:
nsresult evaluateToNodeSet(Expr* aExpr, txIEvalContext* aContext,
txNodeSet** aResult);
/**
* Returns true if any argument is sensitive to the given context.
*/
PRBool argsSensitiveTo(ContextSensitivity aContexts);
#ifdef TX_TO_STRING
/*
* Returns the name of the function as an atom.
@@ -232,22 +398,34 @@ public:
txIMatchContext* aContext) = 0;
virtual double getDefaultPriority() = 0;
/**
* Returns the type of this nodetest.
*/
enum NodeTestType {
NAME_TEST,
OTHER_TEST
};
virtual NodeTestType getType()
{
return OTHER_TEST;
}
/**
* Returns true if this expression is sensitive to *any* of
* the requested flags.
*/
virtual PRBool isSensitiveTo(Expr::ContextSensitivity aContext) = 0;
#ifdef TX_TO_STRING
virtual void toString(nsAString& aDest) = 0;
#endif
};
#define TX_DECL_NODE_TEST_BASE \
PRBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \
double getDefaultPriority()
#ifndef TX_TO_STRING
#define TX_DECL_NODE_TEST TX_DECL_NODE_TEST_BASE
#else
#define TX_DECL_NODE_TEST \
TX_DECL_NODE_TEST_BASE; \
void toString(nsAString& aDest)
#endif
TX_DECL_TOSTRING \
PRBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \
double getDefaultPriority(); \
PRBool isSensitiveTo(Expr::ContextSensitivity aContext);
/*
* This class represents a NameTest as defined by the XPath spec
@@ -262,14 +440,14 @@ public:
txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID,
PRUint16 aNodeType);
~txNameTest();
NodeTestType getType();
TX_DECL_NODE_TEST;
private:
nsCOMPtr<nsIAtom> mPrefix;
nsCOMPtr<nsIAtom> mLocalName;
PRInt32 mNamespace;
private:
PRUint16 mNodeType;
};
@@ -291,8 +469,6 @@ public:
*/
txNodeTypeTest(NodeType aNodeType);
~txNodeTypeTest();
/*
* Sets the name of the node to match. Only availible for pi nodes
*/
@@ -305,6 +481,21 @@ private:
nsCOMPtr<nsIAtom> mNodeName;
};
/**
* Class representing a nodetest combined with a predicate. May only be used
* if the predicate is not sensitive to the context-nodelist.
*/
class txPredicatedNodeTest : public txNodeTest
{
public:
txPredicatedNodeTest(txNodeTest* aNodeTest, Expr* aPredicate);
TX_DECL_NODE_TEST;
private:
nsAutoPtr<txNodeTest> mNodeTest;
nsAutoPtr<Expr> mPredicate;
};
/**
* Represents an ordered list of Predicates,
* for use with Step and Filter Expressions
@@ -334,6 +525,11 @@ public:
nsresult evaluatePredicates(txNodeSet* aNodes, txIMatchContext* aContext);
/**
* Drops the first predicate without deleting it.
*/
void dropFirst();
/**
* returns true if this predicate list is empty
**/
@@ -352,6 +548,10 @@ public:
#endif
protected:
PRBool isSensitiveTo(Expr::ContextSensitivity aContext);
Expr* getSubExprAt(PRUint32 aPos);
void setSubExprAt(PRUint32 aPos, Expr* aExpr);
//-- list of predicates
List predicates;
}; //-- PredicateList
@@ -388,7 +588,17 @@ public:
{
}
TX_DECL_EXPR;
TX_DECL_OPTIMIZABLE_EXPR;
txNodeTest* getNodeTest()
{
return mNodeTest;
}
void setNodeTest(txNodeTest* aNodeTest)
{
mNodeTest.forget();
mNodeTest = aNodeTest;
}
private:
void fromDescendants(const txXPathNode& aNode, txIMatchContext* aCs,
@@ -588,7 +798,6 @@ class VariableRefExpr : public Expr {
public:
VariableRefExpr(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID);
~VariableRefExpr();
TX_DECL_EXPR;
@@ -717,6 +926,24 @@ private:
}; //-- UnionExpr
/**
* Class specializing in executing expressions like "@foo" where we are
* interested in different result-types, and expressions like "@foo = 'hi'"
*/
class txNamedAttributeStep : public Expr
{
public:
txNamedAttributeStep(PRInt32 aNsID, nsIAtom* aPrefix,
nsIAtom* aLocalName);
TX_DECL_EXPR;
private:
PRInt32 mNamespace;
nsCOMPtr<nsIAtom> mPrefix;
nsCOMPtr<nsIAtom> mLocalName;
};
/**
* Expression that failed to parse
*/

View File

@@ -51,6 +51,7 @@
#include "txIXPathContext.h"
#include "txStringUtils.h"
#include "txXPathNode.h"
#include "txXPathOptimizer.h"
/**
* Creates an Attribute Value Template using the given value
@@ -193,10 +194,9 @@ txExprParser::createExprInternal(const nsSubstring& aExpression,
aContext->SetErrorOffset(lexer.mPosition - start + aSubStringPos);
return rv;
}
rv = createExpr(lexer, aContext, aExpr);
nsAutoPtr<Expr> expr;
rv = createExpr(lexer, aContext, getter_Transfers(expr));
if (NS_SUCCEEDED(rv) && lexer.peek()->mType != Token::END) {
delete *aExpr;
*aExpr = nsnull;
rv = NS_ERROR_XPATH_BINARY_EXPECTED;
}
if (NS_FAILED(rv)) {
@@ -204,7 +204,15 @@ txExprParser::createExprInternal(const nsSubstring& aExpression,
aExpression.BeginReading(start);
aContext->SetErrorOffset(lexer.peek()->mStart - start + aSubStringPos);
}
return rv;
txXPathOptimizer optimizer;
Expr* newExpr = nsnull;
rv = optimizer.optimize(expr, &newExpr);
NS_ENSURE_SUCCESS(rv, rv);
*aExpr = newExpr ? newExpr : expr.forget();
return NS_OK;
}
/**

View File

@@ -58,8 +58,10 @@ class txAExprResult : public TxObject
{
public:
friend class txResultRecycler;
// Update txLiteralExpr::getReturnType if this enum is changed.
enum ResultType {
NODESET,
NODESET = 0,
BOOLEAN,
NUMBER,
STRING,

View File

@@ -86,6 +86,36 @@ FilterExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_OK;
} //-- evaluate
TX_IMPL_EXPR_STUBS_BASE(FilterExpr, NODESET_RESULT)
Expr*
FilterExpr::getSubExprAt(PRUint32 aPos)
{
if (aPos == 0) {
return expr;
}
return PredicateList::getSubExprAt(aPos - 1);
}
void
FilterExpr::setSubExprAt(PRUint32 aPos, Expr* aExpr)
{
if (aPos == 0) {
expr.forget();
expr = aExpr;
}
else {
PredicateList::setSubExprAt(aPos - 1, aExpr);
}
}
PRBool
FilterExpr::isSensitiveTo(ContextSensitivity aContext)
{
return expr->isSensitiveTo(aContext) ||
PredicateList::isSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
void
FilterExpr::toString(nsAString& str)

View File

@@ -171,6 +171,33 @@ PRBool FunctionCall::requireParams(PRInt32 aParamCountMin,
return PR_TRUE;
}
Expr*
FunctionCall::getSubExprAt(PRUint32 aPos)
{
return NS_STATIC_CAST(Expr*, params.get(aPos));
}
void
FunctionCall::setSubExprAt(PRUint32 aPos, Expr* aExpr)
{
NS_ASSERTION(aPos < (PRUint32)params.getLength(),
"setting bad subexpression index");
params.replace(aPos, aExpr);
}
PRBool
FunctionCall::argsSensitiveTo(ContextSensitivity aContext)
{
txListIterator iter(&params);
while (iter.hasNext()) {
if (NS_STATIC_CAST(Expr*, iter.next())->isSensitiveTo(aContext)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
#ifdef TX_TO_STRING
void
FunctionCall::toString(nsAString& aDest)

View File

@@ -60,6 +60,38 @@ txLiteralExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_OK;
}
static Expr::ResultType resultTypes[] =
{
Expr::NODESET_RESULT, // NODESET
Expr::BOOLEAN_RESULT, // BOOLEAN
Expr::NUMBER_RESULT, // NUMBER
Expr::STRING_RESULT, // STRING
Expr::RTF_RESULT // RESULT_TREE_FRAGMENT
};
Expr::ResultType
txLiteralExpr::getReturnType()
{
return resultTypes[mValue->getResultType()];
}
Expr*
txLiteralExpr::getSubExprAt(PRUint32 aPos)
{
return nsnull;
}
void
txLiteralExpr::setSubExprAt(PRUint32 aPos, Expr* aExpr)
{
NS_NOTREACHED("setting bad subexpression index");
}
PRBool
txLiteralExpr::isSensitiveTo(ContextSensitivity aContext)
{
return PR_FALSE;
}
#ifdef TX_TO_STRING
void
txLiteralExpr::toString(nsAString& aStr)

View File

@@ -276,6 +276,37 @@ void LocationStep::fromDescendantsRev(const txXPathNode& aNode,
} while (walker.moveToPreviousSibling());
}
Expr::ExprType
LocationStep::getType()
{
return mAxisIdentifier == ATTRIBUTE_AXIS ?
LOCATIONSTEP_ATTRIBUTE_EXPR :
LOCATIONSTEP_OTHER_EXPR;
}
TX_IMPL_EXPR_STUBS_BASE(LocationStep, NODESET_RESULT)
Expr*
LocationStep::getSubExprAt(PRUint32 aPos)
{
return PredicateList::getSubExprAt(aPos);
}
void
LocationStep::setSubExprAt(PRUint32 aPos, Expr* aExpr)
{
return PredicateList::setSubExprAt(aPos, aExpr);
}
PRBool
LocationStep::isSensitiveTo(ContextSensitivity aContext)
{
return (aContext & NODE_CONTEXT) ||
mNodeTest->isSensitiveTo(aContext) ||
PredicateList::isSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
void
LocationStep::toString(nsAString& str)

View File

@@ -151,6 +151,25 @@ txXPathTreeWalker::moveToValidAttribute(PRUint32 aStartIndex)
return PR_FALSE;
}
PRBool
txXPathTreeWalker::moveToNamedAttribute(nsIAtom* aLocalName, PRInt32 aNSID)
{
if (!mPosition.isContent()) {
return PR_FALSE;
}
const nsAttrName* name;
PRUint32 i;
for (i = 0; (name = mPosition.mContent->GetAttrNameAt(i)); ++i) {
if (name->Equals(aLocalName, aNSID)) {
mPosition.mIndex = i;
return PR_TRUE;
}
}
return PR_FALSE;
}
PRBool
txXPathTreeWalker::moveToFirstChild()
{

View File

@@ -114,6 +114,15 @@ MultiplicativeExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return aContext->recycler()->getNumberResult(result, aResult);
} //-- evaluate
TX_IMPL_EXPR_STUBS_2(MultiplicativeExpr, NUMBER_RESULT, leftExpr, rightExpr)
PRBool
MultiplicativeExpr::isSensitiveTo(ContextSensitivity aContext)
{
return leftExpr->isSensitiveTo(aContext) ||
rightExpr->isSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
void
MultiplicativeExpr::toString(nsAString& str)

View File

@@ -56,10 +56,6 @@ txNameTest::txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID,
"Go fix txNameTest::matches");
}
txNameTest::~txNameTest()
{
}
PRBool txNameTest::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
if ((mNodeType == txXPathNodeType::ELEMENT_NODE &&
@@ -100,6 +96,18 @@ double txNameTest::getDefaultPriority()
return 0;
}
txNodeTest::NodeTestType
txNameTest::getType()
{
return NAME_TEST;
}
PRBool
txNameTest::isSensitiveTo(Expr::ContextSensitivity aContext)
{
return !!(aContext & Expr::NODE_CONTEXT);
}
#ifdef TX_TO_STRING
void
txNameTest::toString(nsAString& aDest)

View File

@@ -0,0 +1,96 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 TransforMiiX XSLT processor.
*
* The Initial Developer of the Original Code is
* IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* IBM Corporation
*
* 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 "nsIAtom.h"
#include "txIXPathContext.h"
#include "txNodeSet.h"
#include "txExpr.h"
txNamedAttributeStep::txNamedAttributeStep(PRInt32 aNsID,
nsIAtom* aPrefix,
nsIAtom* aLocalName)
: mNamespace(aNsID),
mPrefix(aPrefix),
mLocalName(aLocalName)
{
}
nsresult
txNamedAttributeStep::evaluate(txIEvalContext* aContext,
txAExprResult** aResult)
{
*aResult = nsnull;
nsRefPtr<txNodeSet> nodes;
nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
NS_ENSURE_SUCCESS(rv, rv);
txXPathTreeWalker walker(aContext->getContextNode());
if (walker.moveToNamedAttribute(mLocalName, mNamespace)) {
rv = nodes->append(walker.getCurrentPosition());
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ADDREF(*aResult = nodes);
return NS_OK;
}
TX_IMPL_EXPR_STUBS_0(txNamedAttributeStep, NODESET_RESULT);
PRBool
txNamedAttributeStep::isSensitiveTo(ContextSensitivity aContext)
{
return !!(aContext & NODE_CONTEXT);
}
#ifdef TX_TO_STRING
void
txNamedAttributeStep::toString(nsAString& aDest)
{
aDest.Append(PRUnichar('@'));
if (mPrefix) {
nsAutoString prefix;
mPrefix->ToString(prefix);
aDest.Append(prefix);
aDest.Append(PRUnichar(':'));
}
nsAutoString localName;
mLocalName->ToString(localName);
aDest.Append(localName);
}
#endif

View File

@@ -227,6 +227,59 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_ERROR_UNEXPECTED;
}
static Expr::ResultType resultTypes[] =
{
Expr::NUMBER_RESULT, // COUNT
Expr::NODESET_RESULT, // ID
Expr::NUMBER_RESULT, // LAST
Expr::STRING_RESULT, // LOCAL_NAME
Expr::STRING_RESULT, // NAMESPACE_URI
Expr::STRING_RESULT, // NAME
Expr::NUMBER_RESULT // POSITION
};
Expr::ResultType
NodeSetFunctionCall::getReturnType()
{
return resultTypes[mType];
}
PRBool
NodeSetFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
switch (mType) {
case COUNT:
{
return argsSensitiveTo(aContext);
}
case ID:
{
return (aContext & DOCUMENT_CONTEXT) ||
argsSensitiveTo(aContext);
}
case LAST:
{
return !!(aContext & SIZE_CONTEXT);
}
case LOCAL_NAME:
case NAME:
case NAMESPACE_URI:
{
if (params.isEmpty()) {
return !!(aContext & NODE_CONTEXT);
}
return argsSensitiveTo(aContext);
}
case POSITION:
{
return !!(aContext & POSITION_CONTEXT);
}
}
NS_NOTREACHED("how'd we get here?");
return PR_TRUE;
}
#ifdef TX_TO_STRING
nsresult
NodeSetFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -49,10 +49,6 @@ txNodeTypeTest::txNodeTypeTest(NodeType aNodeType)
{
}
txNodeTypeTest::~txNodeTypeTest()
{
}
void txNodeTypeTest::setNodeName(const nsAString& aName)
{
mNodeName = do_GetAtom(aName);
@@ -94,6 +90,12 @@ double txNodeTypeTest::getDefaultPriority()
return mNodeName ? 0 : -0.5;
}
PRBool
txNodeTypeTest::isSensitiveTo(Expr::ContextSensitivity aContext)
{
return !!(aContext & Expr::NODE_CONTEXT);
}
#ifdef TX_TO_STRING
void
txNodeTypeTest::toString(nsAString& aDest)

View File

@@ -153,6 +153,22 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_ERROR_UNEXPECTED;
}
Expr::ResultType
NumberFunctionCall::getReturnType()
{
return NUMBER_RESULT;
}
PRBool
NumberFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
if (mType == NUMBER && params.isEmpty()) {
return !!(aContext & NODE_CONTEXT);
}
return argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
NumberFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -102,13 +102,29 @@ PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
{
*aResult = nsnull;
nsRefPtr<txNodeSet> nodes;
nsresult rv = aContext->recycler()->getNodeSet(aContext->getContextNode(),
getter_AddRefs(nodes));
// We need to evaluate the first step with the current context since it
// can depend on the context size and position. For example:
// key('books', concat('book', position()))
txListIterator iter(&expressions);
PathExprItem* pxi = NS_STATIC_CAST(PathExprItem*, iter.next());
nsRefPtr<txAExprResult> res;
nsresult rv = pxi->expr->evaluate(aContext, getter_AddRefs(res));
NS_ENSURE_SUCCESS(rv, rv);
txListIterator iter(&expressions);
PathExprItem* pxi;
NS_ENSURE_TRUE(res->getResultType() == txAExprResult::NODESET,
NS_ERROR_XSLT_NODESET_EXPECTED);
nsRefPtr<txNodeSet> nodes = NS_STATIC_CAST(txNodeSet*,
NS_STATIC_CAST(txAExprResult*,
res));
if (nodes->isEmpty()) {
res.swap(*aResult);
return NS_OK;
}
res = nsnull; // To allow recycling
// Evaluate remaining steps
while ((pxi = (PathExprItem*)iter.next())) {
nsRefPtr<txNodeSet> tmpNodes;
txNodeSetContext eContext(nodes, aContext);
@@ -216,6 +232,53 @@ PathExpr::evalDescendants(Expr* aStep, const txXPathNode& aNode,
return NS_OK;
} //-- evalDescendants
TX_IMPL_EXPR_STUBS_BASE(PathExpr, NODESET_RESULT)
Expr*
PathExpr::getSubExprAt(PRUint32 aPos)
{
PathExprItem* pxi = NS_STATIC_CAST(PathExprItem*, expressions.get(aPos));
return pxi ? pxi->expr.get() : nsnull;
}
void
PathExpr::setSubExprAt(PRUint32 aPos, Expr* aExpr)
{
NS_ASSERTION(aPos < (PRUint32)expressions.getLength(),
"setting bad subexpression index");
PathExprItem* pxi = NS_STATIC_CAST(PathExprItem*, expressions.get(aPos));
pxi->expr.forget();
pxi->expr = aExpr;
}
PRBool
PathExpr::isSensitiveTo(ContextSensitivity aContext)
{
txListIterator iter(&expressions);
PathExprItem* pxi = NS_STATIC_CAST(PathExprItem*, iter.next());
if (pxi->expr->isSensitiveTo(aContext)) {
return PR_TRUE;
}
// We're creating a new node/nodeset so we can ignore those bits.
Expr::ContextSensitivity context =
aContext & ~(Expr::NODE_CONTEXT | Expr::NODESET_CONTEXT);
if (context == NO_CONTEXT) {
return PR_FALSE;
}
while ((pxi = NS_STATIC_CAST(PathExprItem*, iter.next()))) {
NS_ASSERTION(!pxi->expr->isSensitiveTo(Expr::NODESET_CONTEXT),
"Step cannot depend on nodeset-context");
if (pxi->expr->isSensitiveTo(context)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
#ifdef TX_TO_STRING
void
PathExpr::toString(nsAString& dest)

View File

@@ -116,6 +116,12 @@ PredicateList::evaluatePredicates(txNodeSet* nodes,
return NS_OK;
}
void
PredicateList::dropFirst()
{
predicates.remove(predicates.get(0));
}
/*
* returns true if this predicate list is empty
*/
@@ -124,6 +130,40 @@ MBool PredicateList::isEmpty()
return (MBool)(predicates.getLength() == 0);
} // isEmpty
Expr*
PredicateList::getSubExprAt(PRUint32 aPos)
{
return NS_STATIC_CAST(Expr*, predicates.get(aPos));
}
void
PredicateList::setSubExprAt(PRUint32 aPos, Expr* aExpr)
{
NS_ASSERTION(aPos < (PRUint32)predicates.getLength(),
"setting bad subexpression index");
predicates.replace(aPos, aExpr);
}
PRBool
PredicateList::isSensitiveTo(Expr::ContextSensitivity aContext)
{
// We're creating a new node/nodeset so we can ignore those bits.
Expr::ContextSensitivity context =
aContext & ~(Expr::NODE_CONTEXT | Expr::NODESET_CONTEXT);
if (context == Expr::NO_CONTEXT) {
return PR_FALSE;
}
txListIterator iter(&predicates);
while (iter.hasNext()) {
if (NS_STATIC_CAST(Expr*, iter.next())->isSensitiveTo(context)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
#ifdef TX_TO_STRING
void PredicateList::toString(nsAString& dest)
{

View File

@@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 TransforMiiX XSLT processor.
*
* The Initial Developer of the Original Code is
* IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* IBM Corporation
*
* 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 "txExpr.h"
#include "txExprResult.h"
#include "txSingleNodeContext.h"
txPredicatedNodeTest::txPredicatedNodeTest(txNodeTest* aNodeTest,
Expr* aPredicate)
: mNodeTest(aNodeTest),
mPredicate(aPredicate)
{
NS_ASSERTION(!mPredicate->isSensitiveTo(Expr::NODESET_CONTEXT),
"predicate must not be context-nodeset-sensitive");
}
PRBool
txPredicatedNodeTest::matches(const txXPathNode& aNode,
txIMatchContext* aContext)
{
if (!mNodeTest->matches(aNode, aContext)) {
return PR_FALSE;
}
txSingleNodeContext context(aNode, aContext);
nsRefPtr<txAExprResult> res;
nsresult rv = mPredicate->evaluate(&context, getter_AddRefs(res));
NS_ENSURE_SUCCESS(rv, PR_FALSE);
return res->booleanValue();
}
double
txPredicatedNodeTest::getDefaultPriority()
{
return 0.5;
}
PRBool
txPredicatedNodeTest::isSensitiveTo(Expr::ContextSensitivity aContext)
{
return mNodeTest->isSensitiveTo(aContext) ||
mPredicate->isSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
void
txPredicatedNodeTest::toString(nsAString& aDest)
{
mNodeTest->toString(aDest);
aDest.Append(PRUnichar('['));
mPredicate->toString(aDest);
aDest.Append(PRUnichar(']'));
}
#endif

View File

@@ -205,6 +205,15 @@ RelationalExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_OK;
}
TX_IMPL_EXPR_STUBS_2(RelationalExpr, BOOLEAN_RESULT, mLeftExpr, mRightExpr)
PRBool
RelationalExpr::isSensitiveTo(ContextSensitivity aContext)
{
return mLeftExpr->isSensitiveTo(aContext) ||
mRightExpr->isSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
void
RelationalExpr::toString(nsAString& str)

View File

@@ -67,6 +67,14 @@ RootExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return aContext->recycler()->getNodeSet(*document, aResult);
} //-- evaluate
TX_IMPL_EXPR_STUBS_0(RootExpr, NODESET_RESULT)
PRBool
RootExpr::isSensitiveTo(ContextSensitivity aContext)
{
return !!(aContext & DOCUMENT_CONTEXT);
}
#ifdef TX_TO_STRING
void
RootExpr::toString(nsAString& dest)

View File

@@ -133,6 +133,31 @@ txXPathTreeWalker::moveToNextAttribute()
return PR_FALSE;
}
PRBool
txXPathTreeWalker::moveToNamedAttribute(nsIAtom* aLocalName, PRInt32 aNSID)
{
if (INNER->nodeType != Node::ELEMENT_NODE) {
return PR_FALSE;
}
Element* element = NS_STATIC_CAST(Element*, INNER);
NamedNodeMap* attrs = element->getAttributes();
NodeListDefinition::ListItem* item = attrs->firstItem;
// find requested attribute
nsCOMPtr<nsIAtom> localName;
while (item && (item->node->getNamespaceID() != aNSID ||
!item->node->getLocalName(getter_AddRefs(localName)) ||
localName != aLocalName) {
item = item->next;
}
if (!item) {
return PR_FALSE;
}
INNER = NS_STATIC_CAST(NodeDefinition*, item->node);
return PR_TRUE;
}
PRBool
txXPathTreeWalker::moveToFirstChild()
{

View File

@@ -350,6 +350,39 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_ERROR_UNEXPECTED;
}
static Expr::ResultType resultTypes[] =
{
Expr::STRING_RESULT, // CONCAT
Expr::BOOLEAN_RESULT, // CONTAINS
Expr::STRING_RESULT, // NORMALIZE_SPACE
Expr::BOOLEAN_RESULT, // STARTS_WITH
Expr::STRING_RESULT, // STRING
Expr::NUMBER_RESULT, // STRING_LENGTH
Expr::STRING_RESULT, // SUBSTRING
Expr::STRING_RESULT, // SUBSTRING_AFTER
Expr::STRING_RESULT, // SUBSTRING_BEFORE
Expr::STRING_RESULT // TRANSLATE
};
Expr::ResultType
StringFunctionCall::getReturnType()
{
return resultTypes[mType];
}
PRBool
StringFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
if (params.isEmpty() &&
(mType == NORMALIZE_SPACE ||
mType == STRING ||
mType == STRING_LENGTH)) {
return !!(aContext & NODE_CONTEXT);
}
return argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
StringFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -69,6 +69,14 @@ UnaryExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
#endif
}
TX_IMPL_EXPR_STUBS_1(UnaryExpr, NODESET_RESULT, expr)
PRBool
UnaryExpr::isSensitiveTo(ContextSensitivity aContext)
{
return expr->isSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
void
UnaryExpr::toString(nsAString& str)

View File

@@ -125,6 +125,21 @@ UnionExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_OK;
} //-- evaluate
TX_IMPL_EXPR_STUBS_LIST(UnionExpr, NODESET_RESULT, expressions)
PRBool
UnionExpr::isSensitiveTo(ContextSensitivity aContext)
{
txListIterator iter(&expressions);
while (iter.hasNext()) {
if (NS_STATIC_CAST(Expr*, iter.next())->isSensitiveTo(aContext)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
#ifdef TX_TO_STRING
void
UnionExpr::toString(nsAString& dest)

View File

@@ -58,13 +58,6 @@ VariableRefExpr::VariableRefExpr(nsIAtom* aPrefix, nsIAtom* aLocalName,
mPrefix = 0;
}
/*
* Release the local name atom
*/
VariableRefExpr::~VariableRefExpr()
{
}
/**
* Evaluates this Expr based on the given context node and processor state
* @param context the context node for evaluation of this Expr
@@ -83,6 +76,14 @@ VariableRefExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_OK;
}
TX_IMPL_EXPR_STUBS_0(VariableRefExpr, ANY_RESULT)
PRBool
VariableRefExpr::isSensitiveTo(ContextSensitivity aContext)
{
return !!(aContext & VARIABLES_CONTEXT);
}
#ifdef TX_TO_STRING
void
VariableRefExpr::toString(nsAString& aDest)

View File

@@ -517,6 +517,22 @@ XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_ERROR_UNEXPECTED;
}
Expr::ResultType
XFormsFunctionCall::getReturnType()
{
// It doesn't really matter what we return here, but it might
// be a good idea to try to keep this as unoptimizable as possible
return ANY_RESULT;
}
PRBool
XFormsFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
// It doesn't really matter what we return here, but it might
// be a good idea to try to keep this as unoptimizable as possible
return PR_TRUE;
}
#ifdef TX_TO_STRING
nsresult
XFormsFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -0,0 +1,126 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 TransforMiiX XSLT processor.
*
* The Initial Developer of the Original Code is
* IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* IBM Corporation
*
* 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 "txXPathOptimizer.h"
#include "txExprResult.h"
#include "nsIAtom.h"
#include "txAtoms.h"
#include "txXPathNode.h"
#include "txExpr.h"
nsresult
txXPathOptimizer::optimize(Expr* aInExpr, Expr** aOutExpr)
{
*aOutExpr = nsnull;
nsresult rv = NS_OK;
// First optimize sub expressions
PRUint32 i = 0;
Expr* subExpr;
while ((subExpr = aInExpr->getSubExprAt(i))) {
Expr* newExpr = nsnull;
rv = optimize(subExpr, &newExpr);
NS_ENSURE_SUCCESS(rv, rv);
if (newExpr) {
delete subExpr;
aInExpr->setSubExprAt(i, newExpr);
}
++i;
}
// Then see if current expression can be optimized
switch (aInExpr->getType()) {
case Expr::LOCATIONSTEP_ATTRIBUTE_EXPR:
return optimizeAttributeStep(aInExpr, aOutExpr);
case Expr::LOCATIONSTEP_OTHER_EXPR:
return optimizeStep(aInExpr, aOutExpr);
default:
break;
}
return NS_OK;
}
nsresult
txXPathOptimizer::optimizeAttributeStep(Expr* aInExpr, Expr** aOutExpr)
{
LocationStep* step = NS_STATIC_CAST(LocationStep*, aInExpr);
// Test for @foo type steps.
txNameTest* nameTest = nsnull;
if (!step->getSubExprAt(0) &&
step->getNodeTest()->getType() == txNameTest::NAME_TEST &&
(nameTest = NS_STATIC_CAST(txNameTest*, step->getNodeTest()))->
mLocalName != txXPathAtoms::_asterix) {
*aOutExpr = new txNamedAttributeStep(nameTest->mNamespace,
nameTest->mPrefix,
nameTest->mLocalName);
NS_ENSURE_TRUE(*aOutExpr, NS_ERROR_OUT_OF_MEMORY);
return NS_OK; // return since we no longer have a step-object.
}
// Do general step optimizations
return optimizeStep(aInExpr, aOutExpr);
}
nsresult
txXPathOptimizer::optimizeStep(Expr* aInExpr, Expr** aOutExpr)
{
LocationStep* step = NS_STATIC_CAST(LocationStep*, aInExpr);
// Test for predicates that can be combined into the nodetest
Expr* pred;
while ((pred = step->getSubExprAt(0)) &&
!pred->canReturnType(Expr::NUMBER_RESULT) &&
!pred->isSensitiveTo(Expr::NODESET_CONTEXT)) {
txNodeTest* predTest = new txPredicatedNodeTest(step->getNodeTest(), pred);
NS_ENSURE_TRUE(predTest, NS_ERROR_OUT_OF_MEMORY);
step->dropFirst();
step->setNodeTest(predTest);
}
return NS_OK;
}

View File

@@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 TransforMiiX XSLT processor.
*
* The Initial Developer of the Original Code is
* IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* IBM Corporation
*
* 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 ***** */
#ifndef txXPathOptimizer_h__
#define txXPathOptimizer_h__
#include "txCore.h"
class Expr;
class txXPathOptimizer
{
public:
/**
* Optimize the given expression.
* @param aInExpr Expression to optimize.
* @param aOutExpr Resulting expression, null if optimization didn't
* result in a new expression.
*/
nsresult optimize(Expr* aInExpr, Expr** aOutExpr);
private:
// Helper methods for optimizing specific classes
nsresult optimizeAttributeStep(Expr* aInExpr, Expr** aOutExpr);
nsresult optimizeStep(Expr* aInExpr, Expr** aOutExpr);
};
#endif

View File

@@ -87,6 +87,7 @@ public:
PRBool moveToElementById(const nsAString& aID);
PRBool moveToFirstAttribute();
PRBool moveToNextAttribute();
PRBool moveToNamedAttribute(nsIAtom* aLocalName, PRInt32 aNSID);
PRBool moveToFirstChild();
PRBool moveToLastChild();
PRBool moveToNextSibling();

View File

@@ -94,6 +94,7 @@ CPPSRCS = \
txToplevelItems.cpp \
txXSLTNumber.cpp \
txXSLTNumberCounters.cpp \
txPatternOptimizer.cpp \
txXSLTPatterns.cpp \
txXSLTProcessor.cpp \
txPatternParser.cpp \

View File

@@ -35,7 +35,19 @@ CurrentFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_ERROR_UNEXPECTED;
}
return aContext->recycler()->getNodeSet(
es->getEvalContext()->getContextNode(), aResult);
es->getEvalContext()->getContextNode(), aResult);
}
Expr::ResultType
CurrentFunctionCall::getReturnType()
{
return NODESET_RESULT;
}
PRBool
CurrentFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return (aContext & PRIVATE_CONTEXT);
}
#ifdef TX_TO_STRING

View File

@@ -177,6 +177,18 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext,
return NS_OK;
}
Expr::ResultType
DocumentFunctionCall::getReturnType()
{
return NODESET_RESULT;
}
PRBool
DocumentFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
DocumentFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -130,6 +130,18 @@ ElementAvailableFunctionCall::evaluate(txIEvalContext* aContext,
return NS_OK;
}
Expr::ResultType
ElementAvailableFunctionCall::getReturnType()
{
return BOOLEAN_RESULT;
}
PRBool
ElementAvailableFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
ElementAvailableFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -406,6 +406,18 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext,
return aContext->recycler()->getStringResult(res, aResult);
} //-- evaluate
Expr::ResultType
txFormatNumberFunctionCall::getReturnType()
{
return STRING_RESULT;
}
PRBool
txFormatNumberFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
txFormatNumberFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -129,6 +129,18 @@ FunctionAvailableFunctionCall::evaluate(txIEvalContext* aContext,
}
Expr::ResultType
FunctionAvailableFunctionCall::getReturnType()
{
return BOOLEAN_RESULT;
}
PRBool
FunctionAvailableFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
FunctionAvailableFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -105,6 +105,22 @@ GenerateIdFunctionCall::evaluate(txIEvalContext* aContext,
return NS_OK;
}
Expr::ResultType
GenerateIdFunctionCall::getReturnType()
{
return STRING_RESULT;
}
PRBool
GenerateIdFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
if (params.isEmpty()) {
return !!(aContext & NODE_CONTEXT);
}
return argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
GenerateIdFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -126,6 +126,18 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
return NS_OK;
}
Expr::ResultType
txKeyFunctionCall::getReturnType()
{
return NODESET_RESULT;
}
PRBool
txKeyFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return (aContext & DOCUMENT_CONTEXT) || argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
txKeyFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -0,0 +1,109 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 TransforMiiX XSLT processor.
*
* The Initial Developer of the Original Code is
* IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* IBM Corporation
*
* 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 "txPatternOptimizer.h"
#include "txXSLTPatterns.h"
nsresult
txPatternOptimizer::optimize(txPattern* aInPattern, txPattern** aOutPattern)
{
*aOutPattern = nsnull;
nsresult rv = NS_OK;
// First optimize sub expressions
PRUint32 i = 0;
Expr* subExpr;
while ((subExpr = aInPattern->getSubExprAt(i))) {
Expr* newExpr = nsnull;
rv = mXPathOptimizer.optimize(subExpr, &newExpr);
NS_ENSURE_SUCCESS(rv, rv);
if (newExpr) {
delete subExpr;
aInPattern->setSubExprAt(i, newExpr);
}
++i;
}
// Then optimize sub patterns
txPattern* subPattern;
i = 0;
while ((subPattern = aInPattern->getSubPatternAt(i))) {
txPattern* newPattern = nsnull;
rv = optimize(subPattern, &newPattern);
NS_ENSURE_SUCCESS(rv, rv);
if (newPattern) {
delete subPattern;
aInPattern->setSubPatternAt(i, newPattern);
}
++i;
}
// Finally see if current pattern can be optimized
switch (aInPattern->getType()) {
case txPattern::STEP_PATTERN:
return optimizeStep(aInPattern, aOutPattern);
default:
break;
}
return NS_OK;
}
nsresult
txPatternOptimizer::optimizeStep(txPattern* aInPattern,
txPattern** aOutPattern)
{
txStepPattern* step = NS_STATIC_CAST(txStepPattern*, aInPattern);
// Test for predicates that can be combined into the nodetest
Expr* pred;
while ((pred = step->getSubExprAt(0)) &&
!pred->canReturnType(Expr::NUMBER_RESULT) &&
!pred->isSensitiveTo(Expr::NODESET_CONTEXT)) {
txNodeTest* predTest = new txPredicatedNodeTest(step->getNodeTest(),
pred);
step->dropFirst();
step->setNodeTest(predTest);
}
return NS_OK;
}

View File

@@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 TransforMiiX XSLT processor.
*
* The Initial Developer of the Original Code is
* IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* IBM Corporation. All Rights Reserved.
*
* Contributor(s):
* IBM Corporation
*
* 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 ***** */
#ifndef txPatternOptimizer_h__
#define txPatternOptimizer_h__
#include "txXPathOptimizer.h"
class txPattern;
class txPatternOptimizer
{
public:
/**
* Optimize the given pattern.
* @param aInPattern Pattern to optimize.
* @param aOutPattern Resulting pattern, null if optimization didn't
* result in a new pattern.
*/
nsresult optimize(txPattern* aInPattern, txPattern** aOutPattern);
private:
// Helper methods for optimizing specific classes
nsresult optimizeStep(txPattern* aInPattern, txPattern** aOutPattern);
txXPathOptimizer mXPathOptimizer;
};
#endif //txPatternOptimizer_h__

View File

@@ -43,23 +43,31 @@
#include "txStringUtils.h"
#include "txXSLTPatterns.h"
#include "txIXPathContext.h"
#include "txPatternOptimizer.h"
txPattern* txPatternParser::createPattern(const nsAFlatString& aPattern,
txIParseContext* aContext)
{
txPattern* pattern = 0;
txExprLexer lexer;
nsresult rv = lexer.parse(aPattern);
if (NS_FAILED(rv)) {
// XXX error report parsing error
return 0;
}
rv = createUnionPattern(lexer, aContext, pattern);
nsAutoPtr<txPattern> pattern;
rv = createUnionPattern(lexer, aContext, *getter_Transfers(pattern));
if (NS_FAILED(rv)) {
// XXX error report parsing error
return 0;
}
return pattern;
txPatternOptimizer optimizer;
txPattern* newPattern = nsnull;
rv = optimizer.optimize(pattern, &newPattern);
NS_ENSURE_SUCCESS(rv, nsnull);
return newPattern ? newPattern : pattern.forget();
}
nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer,

View File

@@ -884,6 +884,22 @@ txErrorFunctionCall::evaluate(txIEvalContext* aContext,
return NS_ERROR_XPATH_BAD_EXTENSION_FUNCTION;
}
Expr::ResultType
txErrorFunctionCall::getReturnType()
{
// It doesn't really matter what we return here, but it might
// be a good idea to try to keep this as unoptimizable as possible
return ANY_RESULT;
}
PRBool
txErrorFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
// It doesn't really matter what we return here, but it might
// be a good idea to try to keep this as unoptimizable as possible
return PR_TRUE;
}
#ifdef TX_TO_STRING
nsresult
txErrorFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -109,6 +109,18 @@ SystemPropertyFunctionCall::evaluate(txIEvalContext* aContext,
}
Expr::ResultType
SystemPropertyFunctionCall::getReturnType()
{
return STRING_RESULT | NUMBER_RESULT;
}
PRBool
SystemPropertyFunctionCall::isSensitiveTo(ContextSensitivity aContext)
{
return argsSensitiveTo(aContext);
}
#ifdef TX_TO_STRING
nsresult
SystemPropertyFunctionCall::getNameAtom(nsIAtom** aAtom)

View File

@@ -129,6 +129,22 @@ nsresult txUnionPattern::getSimplePatterns(txList& aList)
return NS_OK;
}
TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txUnionPattern);
txPattern*
txUnionPattern::getSubPatternAt(PRUint32 aPos)
{
return NS_STATIC_CAST(txPattern*, mLocPathPatterns.get(aPos));
}
void
txUnionPattern::setSubPatternAt(PRUint32 aPos, txPattern* aPattern)
{
NS_ASSERTION(aPos < (PRUint32)mLocPathPatterns.getLength(),
"setting bad subexpression index");
mLocPathPatterns.replace(aPos, aPattern);
}
#ifdef TX_TO_STRING
void
txUnionPattern::toString(nsAString& aDest)
@@ -254,6 +270,25 @@ double txLocPathPattern::getDefaultPriority()
return ((Step*)mSteps.get(0))->pattern->getDefaultPriority();
}
TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txLocPathPattern);
txPattern*
txLocPathPattern::getSubPatternAt(PRUint32 aPos)
{
Step* step = NS_STATIC_CAST(Step*, mSteps.get(aPos));
return step ? step->pattern.get() : nsnull;
}
void
txLocPathPattern::setSubPatternAt(PRUint32 aPos, txPattern* aPattern)
{
NS_ASSERTION(aPos < (PRUint32)mSteps.getLength(),
"setting bad subexpression index");
Step* step = NS_STATIC_CAST(Step*, mSteps.get(aPos));
step->pattern.forget();
step->pattern = aPattern;
}
#ifdef TX_TO_STRING
void
txLocPathPattern::toString(nsAString& aDest)
@@ -300,6 +335,9 @@ double txRootPattern::getDefaultPriority()
return 0.5;
}
TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txRootPattern);
TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(txRootPattern);
#ifdef TX_TO_STRING
void
txRootPattern::toString(nsAString& aDest)
@@ -383,6 +421,9 @@ double txIdPattern::getDefaultPriority()
return 0.5;
}
TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txIdPattern);
TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(txIdPattern);
#ifdef TX_TO_STRING
void
txIdPattern::toString(nsAString& aDest)
@@ -436,6 +477,9 @@ double txKeyPattern::getDefaultPriority()
return 0.5;
}
TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txKeyPattern);
TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(txKeyPattern);
#ifdef TX_TO_STRING
void
txKeyPattern::toString(nsAString& aDest)
@@ -467,11 +511,6 @@ txKeyPattern::toString(nsAString& aDest)
* a txPattern to hold the NodeTest and the Predicates of a StepPattern
*/
txStepPattern::~txStepPattern()
{
delete mNodeTest;
}
MBool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
{
NS_ASSERTION(mNodeTest, "Internal error");
@@ -586,6 +625,25 @@ double txStepPattern::getDefaultPriority()
return 0.5;
}
txPattern::Type
txStepPattern::getType()
{
return STEP_PATTERN;
}
TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(txStepPattern);
Expr*
txStepPattern::getSubExprAt(PRUint32 aPos)
{
return PredicateList::getSubExprAt(aPos);
}
void
txStepPattern::setSubExprAt(PRUint32 aPos, Expr* aExpr)
{
return PredicateList::setSubExprAt(aPos, aExpr);
}
#ifdef TX_TO_STRING
void
txStepPattern::toString(nsAString& aDest)

View File

@@ -74,6 +74,40 @@ public:
*/
virtual nsresult getSimplePatterns(txList &aList);
/**
* Returns the type of this pattern.
*/
enum Type {
STEP_PATTERN,
OTHER_PATTERN
};
virtual Type getType()
{
return OTHER_PATTERN;
}
/**
* Returns sub-expression at given position
*/
virtual Expr* getSubExprAt(PRUint32 aPos) = 0;
/**
* Replace sub-expression at given position. Does not delete the old
* expression, that is the responsibility of the caller.
*/
virtual void setSubExprAt(PRUint32 aPos, Expr* aExpr) = 0;
/**
* Returns sub-pattern at given position
*/
virtual txPattern* getSubPatternAt(PRUint32 aPos) = 0;
/**
* Replace sub-pattern at given position. Does not delete the old
* pattern, that is the responsibility of the caller.
*/
virtual void setSubPatternAt(PRUint32 aPos, txPattern* aPattern) = 0;
#ifdef TX_TO_STRING
/*
* Returns the String representation of this Pattern.
@@ -89,7 +123,11 @@ public:
#define TX_DECL_PATTERN_BASE \
MBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \
double getDefaultPriority()
double getDefaultPriority(); \
virtual Expr* getSubExprAt(PRUint32 aPos); \
virtual void setSubExprAt(PRUint32 aPos, Expr* aExpr); \
virtual txPattern* getSubPatternAt(PRUint32 aPos); \
virtual void setSubPatternAt(PRUint32 aPos, txPattern* aPattern)
#ifndef TX_TO_STRING
#define TX_DECL_PATTERN TX_DECL_PATTERN_BASE
@@ -103,6 +141,29 @@ public:
TX_DECL_PATTERN; \
nsresult getSimplePatterns(txList &aList)
#define TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(_class) \
Expr* \
_class::getSubExprAt(PRUint32 aPos) \
{ \
return nsnull; \
} \
void \
_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \
{ \
NS_NOTREACHED("setting bad subexpression index"); \
}
#define TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(_class) \
txPattern* \
_class::getSubPatternAt(PRUint32 aPos) \
{ \
return nsnull; \
} \
void \
_class::setSubPatternAt(PRUint32 aPos, txPattern* aPattern) \
{ \
NS_NOTREACHED("setting bad subexpression index"); \
}
class txUnionPattern : public txPattern
{
@@ -142,12 +203,7 @@ private:
{
}
~Step()
{
delete pattern;
}
txPattern* pattern;
nsAutoPtr<txPattern> pattern;
MBool isChild;
};
@@ -221,12 +277,21 @@ public:
{
}
~txStepPattern();
TX_DECL_PATTERN;
Type getType();
txNodeTest* getNodeTest()
{
return mNodeTest;
}
void setNodeTest(txNodeTest* aNodeTest)
{
mNodeTest.forget();
mNodeTest = aNodeTest;
}
private:
txNodeTest* mNodeTest;
nsAutoPtr<txNodeTest> mNodeTest;
MBool mIsAttr;
};