/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999-2004 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:  
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written 
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * @author <a href="mailto:david_n_bertoni@lotus.com">David N. Bertoni</a>
 */

// Class header file.
#include "XPath.hpp"



#include <cassert>
#include <cfloat>



#include <xalanc/Include/STLHelper.hpp>



#include <xalanc/XalanDOM/XalanNamedNodeMap.hpp>



#include <xalanc/PlatformSupport/DoubleSupport.hpp>
#include <xalanc/PlatformSupport/XalanMessageLoader.hpp>
#include <xalanc/PlatformSupport/PrefixResolver.hpp>



#include <xalanc/DOMSupport/DOMServices.hpp>



#include "FormatterStringLengthCounter.hpp"
#include "MutableNodeRefList.hpp"
#include "XalanQNameByReference.hpp"
#include "XObject.hpp"
#include "XObjectFactory.hpp"
#include "XPathEnvSupport.hpp"



XALAN_CPP_NAMESPACE_BEGIN



const XalanDOMString	XPath::s_emptyString;



XPath::XPath(const LocatorType*		theLocator) :
	m_expression(),
	m_locator(theLocator),
	m_inStylesheet(false)
{
}



XPath::~XPath()
{
}



void
XPath::unknownOpCodeError(
			XalanNode*				context,
			XPathExecutionContext&	executionContext,
			int						opPos) const
{
	XalanDOMString	theOpCode;
			
	LongToDOMString(m_expression.getOpCodeMapValue(opPos), theOpCode);

	executionContext.error(
			XalanMessageLoader::getMessage(XalanMessages::UnknownOpCode_1Param,theOpCode),
			context,
			m_locator);
}



void
XPath::notNodeSetError(
			XalanNode*				context,
			XPathExecutionContext&	executionContext) const
{
	executionContext.error(
		XalanMessageLoader::getMessage(XalanMessages::ExpressionDoesNotEvaluateToNodeSet),
		context,
		m_locator);
}



const XObjectPtr
XPath::execute(
			XalanNode*				context,
			const PrefixResolver&	prefixResolver,
			XPathExecutionContext&	executionContext) const
{
	// Push and pop the PrefixResolver...
	XPathExecutionContext::PrefixResolverSetAndRestore	theResolverSetAndRestore(
									executionContext,
									&prefixResolver);

	// Push and pop the current node...
	XPathExecutionContext::CurrentNodePushAndPop		theNodePushAndPop(
									executionContext,
									context);

	return executeMore(context, 0, executionContext);
}



void
XPath::execute(
			XalanNode*				context,
			const PrefixResolver&	prefixResolver,
			XPathExecutionContext&	executionContext,
			bool&					result) const
{
	assert(context != 0);

	// Push and pop the PrefixResolver...
	XPathExecutionContext::PrefixResolverSetAndRestore	theResolverSetAndRestore(
									executionContext,
									&prefixResolver);

	// Push and pop the current node...
	XPathExecutionContext::CurrentNodePushAndPop		theNodePushAndPop(
									executionContext,
									context);

	executeMore(context, 0, executionContext, result);
}



void
XPath::execute(
			XalanNode*				context,
			const PrefixResolver&	prefixResolver,
			XPathExecutionContext&	executionContext,
			double&					result) const
{
	assert(context != 0);

	// Push and pop the PrefixResolver...
	XPathExecutionContext::PrefixResolverSetAndRestore	theResolverSetAndRestore(
									executionContext,
									&prefixResolver);

	// Push and pop the current node...
	XPathExecutionContext::CurrentNodePushAndPop		theNodePushAndPop(
									executionContext,
									context);

	executeMore(context, 0, executionContext, result);
}



void
XPath::execute(
			XalanNode*				context,
			const PrefixResolver&	prefixResolver,
			XPathExecutionContext&	executionContext,
			XalanDOMString&			result) const
{
	assert(context != 0);

	// Push and pop the PrefixResolver...
	XPathExecutionContext::PrefixResolverSetAndRestore	theResolverSetAndRestore(
									executionContext,
									&prefixResolver);

	// Push and pop the current node...
	XPathExecutionContext::CurrentNodePushAndPop		theNodePushAndPop(
									executionContext,
									context);

	executeMore(context, 0, executionContext, result);
}



void
XPath::execute(
			XalanNode*				context,
			const PrefixResolver&	prefixResolver,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	assert(context != 0);

	// Push and pop the PrefixResolver...
	XPathExecutionContext::PrefixResolverSetAndRestore	theResolverSetAndRestore(
									executionContext,
									&prefixResolver);

	// Push and pop the current node...
	XPathExecutionContext::CurrentNodePushAndPop		theNodePushAndPop(
									executionContext,
									context);

	executeMore(context, 0, executionContext, formatterListener, function);
}



const XObjectPtr
XPath::execute(
			XalanNode*				context,
			const PrefixResolver&	prefixResolver,
			XPathExecutionContext&	executionContext,
			MutableNodeRefList&		result) const
{
	assert(context != 0);
	assert(result.empty() == true);

	// Push and pop the PrefixResolver...
	XPathExecutionContext::PrefixResolverSetAndRestore	theResolverSetAndRestore(
									executionContext,
									&prefixResolver);

	// Push and pop the current node...
	XPathExecutionContext::CurrentNodePushAndPop		theNodePushAndPop(
									executionContext,
									context);

	return executeMore(context, 0, executionContext, result);
}



const XObjectPtr
XPath::executeMore(
			XalanNode* 				context,
			int 					opPos,
			XPathExecutionContext&	executionContext) const
{
	switch(m_expression.getOpCodeMapValue(opPos))
	{
	case XPathExpression::eOP_XPATH:
		return executeMore(context, opPos + 2, executionContext);
		break;

	case XPathExpression::eOP_OR:
		return executionContext.getXObjectFactory().createBoolean(Or(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_AND:
		return executionContext.getXObjectFactory().createBoolean(And(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_NOTEQUALS:
		return executionContext.getXObjectFactory().createBoolean(notequals(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_EQUALS:
		return executionContext.getXObjectFactory().createBoolean(equals(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_LTE:
		return executionContext.getXObjectFactory().createBoolean(lte(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_LT:
		return executionContext.getXObjectFactory().createBoolean(lt(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_GTE:
		return executionContext.getXObjectFactory().createBoolean(gte(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_GT:
		return executionContext.getXObjectFactory().createBoolean(gt(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_PLUS:
		return executionContext.getXObjectFactory().createNumber(plus(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_MINUS:
		return executionContext.getXObjectFactory().createNumber(minus(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_MULT:
		return executionContext.getXObjectFactory().createNumber(mult(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_DIV:
		return executionContext.getXObjectFactory().createNumber(div(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_MOD:
		return executionContext.getXObjectFactory().createNumber(mod(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_NEG:
		return executionContext.getXObjectFactory().createNumber(neg(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_UNION:
		return Union(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_LITERAL:
		return literal(opPos, executionContext);
		break;

	case XPathExpression::eOP_VARIABLE:
		return variable(opPos, executionContext);
		break;

	case XPathExpression::eOP_GROUP:
		return group(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_NUMBERLIT:
		return numberlit(opPos, executionContext);
		break;

	case XPathExpression::eOP_EXTFUNCTION:
		return runExtFunction(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION:
		return runFunction(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_LOCATIONPATH:
		return locationPath(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_POSITION:
		return executionContext.getXObjectFactory().createNumber(functionPosition(context, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_LAST:
		return executionContext.getXObjectFactory().createNumber(functionLast(executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_COUNT:
		return executionContext.getXObjectFactory().createNumber(functionCount(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_NOT:
		return executionContext.getXObjectFactory().createBoolean(functionNot(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_TRUE:
		return executionContext.getXObjectFactory().createBoolean(true);
		break;

	case XPathExpression::eOP_FUNCTION_FALSE:
		return executionContext.getXObjectFactory().createBoolean(false);
		break;

	case XPathExpression::eOP_FUNCTION_BOOLEAN:
		return executionContext.getXObjectFactory().createBoolean(functionBoolean(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_NAME_0:
		return executionContext.getXObjectFactory().createStringReference(functionName(context));
		break;

	case XPathExpression::eOP_FUNCTION_NAME_1:
		return executionContext.getXObjectFactory().createStringReference(functionName(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_0:
		return executionContext.getXObjectFactory().createStringReference(functionLocalName(context));
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_1:
		return executionContext.getXObjectFactory().createStringReference(functionLocalName(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_FLOOR:
		return executionContext.getXObjectFactory().createNumber(functionFloor(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_CEILING:
		return executionContext.getXObjectFactory().createNumber(functionCeiling(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_ROUND:
		return executionContext.getXObjectFactory().createNumber(functionRound(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_0:
		return executionContext.getXObjectFactory().createNumber(functionNumber(context, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_1:
		return executionContext.getXObjectFactory().createNumber(functionNumber(context, opPos, executionContext));
		break;

//	case XPathExpression::eOP_FUNCTION_STRING_0:
//		return functionString(context);
//		break;

//	case XPathExpression::eOP_FUNCTION_STRING_1:
//		return functionString(context, opPos, executionContext);
//		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_0:
		return executionContext.getXObjectFactory().createNumber(functionStringLength(context));
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_1:
		return executionContext.getXObjectFactory().createNumber(functionStringLength(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_SUM:
		return executionContext.getXObjectFactory().createNumber(functionSum(context, opPos, executionContext));
		break;

	default:
		unknownOpCodeError(context, executionContext, opPos);
		break;
	}

	return XObjectPtr();
}



void
XPath::executeMore(
			XalanNode* 				context,
			int 					opPos,
			XPathExecutionContext&	executionContext,
			bool&					result) const
{
	switch(m_expression.getOpCodeMapValue(opPos))
	{
	case XPathExpression::eOP_XPATH:
		executeMore(context, opPos + 2, executionContext, result);
		break;

	case XPathExpression::eOP_OR:
		result = Or(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_AND:
		result = And(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_NOTEQUALS:
		result = notequals(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_EQUALS:
		result = equals(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_LTE:
		result = lte(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_LT:
		result = lt(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_GTE:
		result = gte(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_GT:
		result = gt(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_PLUS:
		result = XObject::boolean(plus(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_MINUS:
		result = XObject::boolean(minus(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_MULT:
		result = XObject::boolean(mult(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_DIV:
		result = XObject::boolean(div(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_MOD:
		result = XObject::boolean(mod(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_NEG:
		result = XObject::boolean(neg(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_UNION:
		Union(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_LITERAL:
		literal(opPos, result);
		break;

	case XPathExpression::eOP_VARIABLE:
		result = variable(opPos, executionContext)->boolean();
		break;

	case XPathExpression::eOP_GROUP:
		group(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_NUMBERLIT:
		numberlit(opPos, result);
		break;

	case XPathExpression::eOP_EXTFUNCTION:
		result = runExtFunction(context, opPos, executionContext)->boolean();
		break;

	case XPathExpression::eOP_FUNCTION:
		result = runFunction(context, opPos, executionContext)->boolean();
		break;

	case XPathExpression::eOP_LOCATIONPATH:
		locationPath(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_FUNCTION_POSITION:
		result = XObject::boolean(functionPosition(context, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_LAST:
		result = XObject::boolean(functionLast(executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_COUNT:
		result = XObject::boolean(functionCount(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_NOT:
		result = functionNot(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_TRUE:
		result = true;
		break;

	case XPathExpression::eOP_FUNCTION_FALSE:
		result = false;
		break;

	case XPathExpression::eOP_FUNCTION_BOOLEAN:
		result = functionBoolean(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_NAME_0:
		result = XObject::boolean(functionName(context));
		break;

	case XPathExpression::eOP_FUNCTION_NAME_1:
		result = XObject::boolean(functionName(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_0:
		result = XObject::boolean(functionLocalName(context));
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_1:
		result = XObject::boolean(functionLocalName(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_FLOOR:
		result = XObject::boolean(functionFloor(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_CEILING:
		result = XObject::boolean(functionCeiling(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_ROUND:
		result = XObject::boolean(functionRound(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_0:
		result = XObject::boolean(functionNumber(context, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_1:
		result = XObject::boolean(functionNumber(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_0:
		result = XObject::boolean(functionStringLength(context));
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_1:
		result = XObject::boolean(functionStringLength(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_SUM:
		result = XObject::boolean(functionSum(context, opPos, executionContext));
		break;

	default:
		unknownOpCodeError(context, executionContext, opPos);
		break;
	}
}



void
XPath::executeMore(
			XalanNode* 				context,
			int 					opPos,
			XPathExecutionContext&	executionContext,
			double&					result) const
{
	switch(m_expression.getOpCodeMapValue(opPos))
	{
	case XPathExpression::eOP_XPATH:
		executeMore(context, opPos + 2, executionContext, result);
		break;

	case XPathExpression::eOP_OR:
		result = XObject::number(Or(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_AND:
		result = XObject::number(And(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_NOTEQUALS:
		result = XObject::number(notequals(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_EQUALS:
		result = XObject::number(equals(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_LTE:
		result = XObject::number(lte(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_LT:
		result = XObject::number(lt(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_GTE:
		result = XObject::number(gte(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_GT:
		result = XObject::number(gt(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_PLUS:
		result = plus(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_MINUS:
		result = minus(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_MULT:
		result = mult(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_DIV:
		result = div(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_MOD:
		result = mod(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_NEG:
		result = neg(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_UNION:
		Union(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_LITERAL:
		literal(opPos, result);
		break;

	case XPathExpression::eOP_VARIABLE:
		result = variable(opPos, executionContext)->num();
		break;

	case XPathExpression::eOP_GROUP:
		group(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_NUMBERLIT:
		result = numberlit(opPos);
		break;

	case XPathExpression::eOP_EXTFUNCTION:
		result = runExtFunction(context, opPos, executionContext)->num();
		break;

	case XPathExpression::eOP_FUNCTION:
		result = runFunction(context, opPos, executionContext)->num();
		break;

	case XPathExpression::eOP_LOCATIONPATH:
		locationPath(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_FUNCTION_POSITION:
		result = functionPosition(context, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_LAST:
		result = functionLast(executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_COUNT:
		result = functionCount(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_NOT:
		result = XObject::number(functionNot(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_TRUE:
		result = XObject::number(true);
		break;

	case XPathExpression::eOP_FUNCTION_FALSE:
		result = XObject::number(false);
		break;

	case XPathExpression::eOP_FUNCTION_BOOLEAN:
		result = XObject::number(functionBoolean(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_NAME_0:
		result = XObject::number(functionName(context));
		break;

	case XPathExpression::eOP_FUNCTION_NAME_1:
		result = XObject::number(functionName(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_0:
		result = XObject::number(functionLocalName(context));
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_1:
		result = XObject::number(functionLocalName(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_FLOOR:
		result = functionFloor(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_CEILING:
		result = functionCeiling(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_ROUND:
		result = functionRound(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_0:
		result = functionNumber(context, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_1:
		result = functionNumber(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_0:
		result = functionStringLength(context);
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_1:
		result = functionStringLength(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION_SUM:
		result = functionSum(context, opPos, executionContext);
		break;

	default:
		unknownOpCodeError(context, executionContext, opPos);
		break;
	}
}



void
XPath::executeMore(
			XalanNode* 				context,
			int 					opPos,
			XPathExecutionContext&	executionContext,
			XalanDOMString&			result) const
{
	switch(m_expression.getOpCodeMapValue(opPos))
	{
	case XPathExpression::eOP_XPATH:
		executeMore(context, opPos + 2, executionContext, result);
		break;

	case XPathExpression::eOP_OR:
		XObject::string(Or(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_AND:
		XObject::string(And(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_NOTEQUALS:
		XObject::string(notequals(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_EQUALS:
		XObject::string(equals(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_LTE:
		XObject::string(lte(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_LT:
		XObject::string(lt(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_GTE:
		XObject::string(gte(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_GT:
		XObject::string(gt(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_PLUS:
		XObject::string(plus(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_MINUS:
		XObject::string(minus(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_MULT:
		XObject::string(mult(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_DIV:
		XObject::string(div(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_MOD:
		XObject::string(mod(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_NEG:
		XObject::string(neg(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_UNION:
		Union(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_LITERAL:
		literal(opPos, result);
		break;

	case XPathExpression::eOP_VARIABLE:
		variable(opPos, executionContext)->str(result);
		break;

	case XPathExpression::eOP_GROUP:
		group(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_NUMBERLIT:
		numberlit(opPos, result);
		break;

	case XPathExpression::eOP_EXTFUNCTION:
		runExtFunction(context, opPos, executionContext)->str(result);
		break;

	case XPathExpression::eOP_FUNCTION:
		runFunction(context, opPos, executionContext)->str(result);
		break;

	case XPathExpression::eOP_LOCATIONPATH:
		locationPath(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_FUNCTION_POSITION:
		XObject::string(functionPosition(context, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_LAST:
		XObject::string(functionLast(executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_COUNT:
		XObject::string(functionCount(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_NOT:
		XObject::string(functionNot(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_TRUE:
		XObject::string(true, result);
		break;

	case XPathExpression::eOP_FUNCTION_FALSE:
		XObject::string(false, result);
		break;

	case XPathExpression::eOP_FUNCTION_BOOLEAN:
		XObject::string(functionBoolean(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_NAME_0:
		result.append(functionName(context));
		break;

	case XPathExpression::eOP_FUNCTION_NAME_1:
		result.append(functionName(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_0:
		result.append(functionLocalName(context));
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_1:
		result.append(functionLocalName(context, opPos, executionContext));
		break;

	case XPathExpression::eOP_FUNCTION_FLOOR:
		XObject::string(functionFloor(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_CEILING:
		XObject::string(functionCeiling(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_ROUND:
		XObject::string(functionRound(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_0:
		XObject::string(functionNumber(context, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_1:
		XObject::string(functionNumber(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_0:
		XObject::string(functionStringLength(context), result);
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_1:
		XObject::string(functionStringLength(context, opPos, executionContext), result);
		break;

	case XPathExpression::eOP_FUNCTION_SUM:
		XObject::string(functionSum(context, opPos, executionContext), result);
		break;

	default:
		unknownOpCodeError(context, executionContext, opPos);
		break;
	}
}



inline void
stringToCharacters(
			const XalanDOMString&		str,
			FormatterListener&			formatterListener,
			XPath::MemberFunctionPtr	function)
{
	(formatterListener.*function)(str.c_str(), str.length());
}



void
XPath::executeMore(
			XalanNode* 				context,
			int 					opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	switch(m_expression.getOpCodeMapValue(opPos))
	{
	case XPathExpression::eOP_XPATH:
		executeMore(context, opPos + 2, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_OR:
		XObject::string(
				Or(context, opPos, executionContext),
				formatterListener,
				function);
		break;

	case XPathExpression::eOP_AND:
		XObject::string(
				And(context, opPos, executionContext),
				formatterListener,
				function);
		break;

	case XPathExpression::eOP_NOTEQUALS:
		XObject::string(
				notequals(context, opPos, executionContext),
				formatterListener,
				function);
		break;

	case XPathExpression::eOP_EQUALS:
		XObject::string(
				equals(context, opPos, executionContext),
				formatterListener,
				function);
		break;

	case XPathExpression::eOP_LTE:
		XObject::string(
				lte(context, opPos, executionContext),
				formatterListener,
				function);
		break;

	case XPathExpression::eOP_LT:
		XObject::string(
				lt(context, opPos, executionContext),
				formatterListener,
				function);
		break;

	case XPathExpression::eOP_GTE:
		XObject::string(
				gte(context, opPos, executionContext),
				formatterListener,
				function);
		break;

	case XPathExpression::eOP_GT:
		XObject::string(
				gt(context, opPos, executionContext),
				formatterListener,
				function);
		break;

	case XPathExpression::eOP_PLUS:
		plus(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_MINUS:
		minus(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_MULT:
		mult(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_DIV:
		div(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_MOD:
		mod(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_NEG:
		neg(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_UNION:
		Union(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_LITERAL:
		literal(opPos, formatterListener, function);
		break;

	case XPathExpression::eOP_VARIABLE:
		variable(opPos, executionContext)->str(formatterListener, function);
		break;

	case XPathExpression::eOP_GROUP:
		group(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_NUMBERLIT:
		numberlit(opPos, formatterListener, function);
		break;

	case XPathExpression::eOP_EXTFUNCTION:
		runExtFunction(context, opPos, executionContext)->str(formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION:
		runFunction(context, opPos, executionContext)->str(formatterListener, function);
		break;

	case XPathExpression::eOP_LOCATIONPATH:
		locationPath(context, opPos, executionContext, formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_POSITION:
		XObject::string(functionPosition(context, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_LAST:
		XObject::string(functionLast(executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_COUNT:
		XObject::string(functionCount(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_NOT:
		XObject::string(functionNot(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_TRUE:
		XObject::string(true, formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_FALSE:
		XObject::string(false, formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_BOOLEAN:
		XObject::string(functionBoolean(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_NAME_0:
		stringToCharacters(functionName(context), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_NAME_1:
		stringToCharacters(functionName(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_0:
		stringToCharacters(functionLocalName(context), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_LOCALNAME_1:
		stringToCharacters(functionLocalName(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_FLOOR:
		XObject::string(functionFloor(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_CEILING:
		XObject::string(functionCeiling(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_ROUND:
		XObject::string(functionRound(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_0:
		XObject::string(functionNumber(context, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_NUMBER_1:
		XObject::string(functionNumber(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_0:
		XObject::string(functionStringLength(context), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_1:
		XObject::string(functionStringLength(context, opPos, executionContext), formatterListener, function);
		break;

	case XPathExpression::eOP_FUNCTION_SUM:
		XObject::string(functionSum(context, opPos, executionContext), formatterListener, function);
		break;

	default:
		unknownOpCodeError(context, executionContext, opPos);
		break;
	}
}



const XObjectPtr
XPath::executeMore(
			XalanNode* 				context,
			int 					opPos,
			XPathExecutionContext&	executionContext,
			MutableNodeRefList&		result) const
{
	XObjectPtr	theXObject;

	switch(m_expression.getOpCodeMapValue(opPos))
	{
	case XPathExpression::eOP_XPATH:
		theXObject = executeMore(context, opPos + 2, executionContext, result);
		break;

	case XPathExpression::eOP_OR:
	case XPathExpression::eOP_AND:
	case XPathExpression::eOP_NOTEQUALS:
	case XPathExpression::eOP_EQUALS:
	case XPathExpression::eOP_LTE:
	case XPathExpression::eOP_LT:
	case XPathExpression::eOP_GTE:
	case XPathExpression::eOP_GT:
	case XPathExpression::eOP_PLUS:
	case XPathExpression::eOP_MINUS:
	case XPathExpression::eOP_MULT:
	case XPathExpression::eOP_DIV:
	case XPathExpression::eOP_MOD:
	case XPathExpression::eOP_NEG:
	case XPathExpression::eOP_LITERAL:
	case XPathExpression::eOP_NUMBERLIT:
	case XPathExpression::eOP_FUNCTION_POSITION:
	case XPathExpression::eOP_FUNCTION_LAST:
	case XPathExpression::eOP_FUNCTION_COUNT:
	case XPathExpression::eOP_FUNCTION_NOT:
	case XPathExpression::eOP_FUNCTION_TRUE:
	case XPathExpression::eOP_FUNCTION_FALSE:
	case XPathExpression::eOP_FUNCTION_BOOLEAN:
	case XPathExpression::eOP_FUNCTION_NAME_0:
	case XPathExpression::eOP_FUNCTION_NAME_1:
	case XPathExpression::eOP_FUNCTION_LOCALNAME_0:
	case XPathExpression::eOP_FUNCTION_LOCALNAME_1:
	case XPathExpression::eOP_FUNCTION_FLOOR:
	case XPathExpression::eOP_FUNCTION_CEILING:
	case XPathExpression::eOP_FUNCTION_ROUND:
	case XPathExpression::eOP_FUNCTION_NUMBER_0:
	case XPathExpression::eOP_FUNCTION_NUMBER_1:
	case XPathExpression::eOP_FUNCTION_STRING_0:
	case XPathExpression::eOP_FUNCTION_STRING_1:
	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_0:
	case XPathExpression::eOP_FUNCTION_STRINGLENGTH_1:
	case XPathExpression::eOP_FUNCTION_NAMESPACEURI_0:
	case XPathExpression::eOP_FUNCTION_NAMESPACEURI_1:
	case XPathExpression::eOP_FUNCTION_SUM:
		notNodeSetError(context, executionContext);
		break;

	case XPathExpression::eOP_UNION:
		Union(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_VARIABLE:
		theXObject = variable(opPos, executionContext);
		break;

	case XPathExpression::eOP_GROUP:
		group(context, opPos, executionContext, result);
		break;

	case XPathExpression::eOP_EXTFUNCTION:
		theXObject = runExtFunction(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_FUNCTION:
		theXObject = runFunction(context, opPos, executionContext);
		break;

	case XPathExpression::eOP_LOCATIONPATH:
		locationPath(context, opPos, executionContext, result);
		break;

	default:
		unknownOpCodeError(context, executionContext, opPos);
		break;
	}

	if (theXObject.null() == false && theXObject->getType() != XObject::eTypeNodeSet)
	{
		notNodeSetError(context, executionContext);
	}

	return theXObject;
}



inline void
XPath::doGetMatchScore(
			XalanNode*				context,
			XPathExecutionContext&	executionContext,
			eMatchScore&			score) const
{
	assert(context != 0);

	int		opPos = 2;

	while(m_expression.m_opMap[opPos] == XPathExpression::eOP_LOCATIONPATHPATTERN)
	{
		const int	nextOpPos = m_expression.getNextOpCodePosition(opPos);

		score = locationPathPattern(executionContext, *context, opPos);

		if(score == eMatchScoreNone)
		{
			opPos = nextOpPos;
		}
		else
		{
			break;
		}
	}
}



XPath::eMatchScore
XPath::getMatchScore(
			XalanNode*				node,
			XPathExecutionContext&	executionContext) const
{
	eMatchScore		score = eMatchScoreNone;

	if(m_expression.getOpCodeMapValue(0) != XPathExpression::eOP_MATCHPATTERN)
	{
		executionContext.error(
			XalanMessageLoader::getMessage(XalanMessages::CannotEvaluateXPathExpressionAsMatchPattern),
			node,
			m_locator);
	}
	else
	{
		assert(node != 0);

		doGetMatchScore(node, executionContext, score);
	}

	return score;
}



XPath::eMatchScore
XPath::getMatchScore(
			XalanNode*				node,
			const PrefixResolver&	resolver,
			XPathExecutionContext&	executionContext) const
{
	const PrefixResolver* const		theCurrentResolver =
		executionContext.getPrefixResolver();

	if (theCurrentResolver == &resolver)
	{
		return getMatchScore(node, executionContext);
	}
	else
	{
		// Push and pop the PrefixResolver...
		XPathExecutionContext::PrefixResolverSetAndRestore	theSetAndRestore(
									executionContext,
									theCurrentResolver,
									&resolver);

		return getMatchScore(node, executionContext);
	}
}



inline const XalanDOMString*
getStringFromTokenQueue(
			const XPathExpression&	expression,
			int						opPos)
{
	const int	tokenPosition =
				expression.getOpCodeMapValue(opPos);

	if (tokenPosition < 0)
	{
		return 0;
	}
	else
	{
		const XObject* const	token =
					expression.getToken(tokenPosition);
		assert(token != 0);

		return &token->str();
	}
}



void
XPath::getTargetData(TargetDataVectorType&	targetData) const
{
	int opPos = 2;

	targetData.reserve(eDefaultTargetDataSize);

	while(m_expression.m_opMap[opPos] == XPathExpression::eOP_LOCATIONPATHPATTERN)
	{
		const int	nextOpPos = m_expression.getNextOpCodePosition(opPos);

		opPos += 2;
	 
		int		stepCount = 0;

		while(m_expression.getOpCodeMapValue(opPos) != XPathExpression::eENDOP)
		{
			++stepCount;

			const int	nextStepPos =
				m_expression.getNextOpCodePosition(opPos);

			const int	nextOp = m_expression.getOpCodeMapValue(nextStepPos);

			if(nextOp == XPathExpression::eENDOP)
			{
				eMatchScore					score = eMatchScoreNone;

				const XalanDOMChar*			targetLocalName = 0;

				TargetData::eTargetType		targetType = TargetData::eOther;

				bool	fIsAttribute = false;

				const int	stepType = m_expression.getOpCodeMapValue(opPos);

				opPos += 3;

				switch(stepType)
				{
				case XPathExpression::eOP_FUNCTION:
					targetLocalName = PSEUDONAME_ANY;
					score = eMatchScoreOther;
					targetType = TargetData::eAny;
					break;

				case XPathExpression::eFROM_ROOT:
					targetLocalName = PSEUDONAME_ROOT;
					score = eMatchScoreOther;
					break;

				case XPathExpression::eMATCH_ATTRIBUTE:
					fIsAttribute = true;
					// fall through on purpose...

				case XPathExpression::eMATCH_ANY_ANCESTOR:
				case XPathExpression::eMATCH_IMMEDIATE_ANCESTOR:
					{
						const int	tok = m_expression.getOpCodeMapValue(opPos);

						switch(tok)
						{
						case XPathExpression::eNODETYPE_COMMENT:
							targetLocalName = PSEUDONAME_COMMENT;
							score = eMatchScoreNodeTest;
							break;

						case XPathExpression::eNODETYPE_TEXT:
							targetLocalName = PSEUDONAME_TEXT;
							score = eMatchScoreNodeTest;
							break;

						case XPathExpression::eNODETYPE_NODE:
							targetLocalName = PSEUDONAME_NODE;
							score = eMatchScoreNodeTest;
							break;

						case XPathExpression::eNODETYPE_ROOT:
							targetLocalName = PSEUDONAME_ROOT;
							score = eMatchScoreNodeTest;
							break;

						case XPathExpression::eNODETYPE_ANYELEMENT:
							targetLocalName = PSEUDONAME_ANY;
							score = eMatchScoreNodeTest;
							targetType = TargetData::eElement;
							break;

						case XPathExpression::eNODETYPE_PI:
							{
								const int	argLen =
									m_expression.getOpCodeMapValue(opPos - 3 + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

								targetLocalName = PSEUDONAME_PI;

								if (argLen == 1)
								{
									score = eMatchScoreNodeTest;
								}
								else if (argLen == 2)
								{
									score = eMatchScoreQName;
								}
							}
							break;

						case XPathExpression::eNODENAME:
							{
								const XalanDOMString* const		targetNamespace =
										getStringFromTokenQueue(m_expression, opPos + 1);

								const XalanDOMString* const		targetLocal =
										getStringFromTokenQueue(m_expression, opPos + 2);

								if (targetLocal == 0)
								{
									targetLocalName = 0;
								}
								else
								{
									targetLocalName = targetLocal->c_str();
								}

								targetType = fIsAttribute ?
									TargetData::eAttribute :
									TargetData::eElement;

								if(targetLocalName != 0)
								{
									if(targetLocalName == PSEUDONAME_ANY)
									{
										targetLocalName = PSEUDONAME_ANY;

										if (targetNamespace == 0 ||
											*targetNamespace == PSEUDONAME_ANY)
										{
											score = eMatchScoreNodeTest;
										}
										else
										{
											score = eMatchScoreNSWild;
										}
									}
									else
									{
										score = eMatchScoreQName;
									}
								}
								else
								{
									targetLocalName = PSEUDONAME_ANY;

									if (targetNamespace == 0 ||
										*targetNamespace == PSEUDONAME_ANY)
									{
										score = eMatchScoreNodeTest;
									}
									else
									{
										score = eMatchScoreNSWild;
									}
								}
							}

							break;

						default:
							targetLocalName = PSEUDONAME_ANY;
							score = eMatchScoreNodeTest;
							break;
						}
					}
					break;
				}

				assert(targetLocalName != 0);

				// If there are multiple steps, or a predicate,
				// the priority is always eMatchScoreOther.
				if (stepCount > 1 ||
					opPos + 3 < nextStepPos)
				{
					score = eMatchScoreOther;
				}

				targetData.push_back(TargetData(targetLocalName, score, targetType));
			}

			opPos = nextStepPos;
		}

		opPos = nextOpPos;
	}
}



bool
XPath::Or(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;

	bool	theResult;

	executeMore(context, opPos, executionContext, theResult);

	if(theResult == false)
	{
		opPos = m_expression.getNextOpCodePosition(opPos);

		executeMore(context, opPos, executionContext, theResult);
	}

	return theResult;
}



bool
XPath::And(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;	

	bool	fResult;

	executeMore(context, opPos, executionContext, fResult);

	if (fResult == true)
	{
		opPos = m_expression.getNextOpCodePosition(opPos);

		executeMore(context, opPos, executionContext, fResult);
	}	

	return fResult;
}



bool
XPath::notequals(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;	

	const XObjectPtr	expr1(executeMore(context, opPos, executionContext));
	assert(expr1.get() != 0);

	opPos = m_expression.getNextOpCodePosition(opPos);

	return expr1->notEquals(
			*executeMore(context, opPos, executionContext).get(),
			executionContext);
}



bool
XPath::equals(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;	

	const XObjectPtr	expr1(executeMore(context, opPos, executionContext));
	assert(expr1.get() != 0);

	opPos = m_expression.getNextOpCodePosition(opPos);

	return expr1->equals(
			*executeMore(context, opPos, executionContext).get(),
			executionContext);
}



bool
XPath::lte(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;	

	const XObjectPtr	expr1(executeMore(context, opPos, executionContext));
	assert(expr1.get() != 0);

	opPos = m_expression.getNextOpCodePosition(opPos);

	return expr1->lessThanOrEquals(
			*executeMore(context, opPos, executionContext).get(),
			executionContext);
}



bool
XPath::lt(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;

	const XObjectPtr	expr1(executeMore(context, opPos, executionContext));
	assert(expr1.get() != 0);

	opPos = m_expression.getNextOpCodePosition(opPos);

	return expr1->lessThan(
			*executeMore(context, opPos, executionContext).get(),
			executionContext);
}



bool
XPath::gte(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;

	const XObjectPtr	expr1(executeMore(context, opPos, executionContext));
	assert(expr1.get() != 0);

	opPos = m_expression.getNextOpCodePosition(opPos);

	return expr1->greaterThanOrEquals(
			*executeMore(context, opPos, executionContext).get(),
			executionContext);
}



bool
XPath::gt(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;

	const XObjectPtr	expr1(executeMore(context, opPos, executionContext));
	assert(expr1.get() != 0);

	opPos = m_expression.getNextOpCodePosition(opPos);

	return expr1->greaterThan(
			*executeMore(context, opPos, executionContext).get(),
			executionContext);
}



double
XPath::getNumericOperand(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	if (m_expression.getOpCodeMapValue(opPos) == XPathExpression::eOP_NUMBERLIT)
	{
		assert(m_expression.m_tokenQueue.size() >
			unsigned(m_expression.getOpCodeMapValue(opPos + 3)));

		return m_expression.getNumberLiteral(m_expression.getOpCodeMapValue(opPos + 2));
	}
	else
	{
		double	theResult;

		executeMore(context, opPos, executionContext, theResult);

		return theResult;
	}
}



double
XPath::plus(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;

	const double	expr1 = getNumericOperand(context, opPos, executionContext);

	opPos = m_expression.getNextOpCodePosition(opPos);

	const double	expr2 = getNumericOperand(context, opPos, executionContext);

	return DoubleSupport::add(expr1, expr2);
}



void
XPath::plus(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	const double	theResult = plus(context, opPos, executionContext);

	XObject::string(theResult, formatterListener, function);
}



double
XPath::minus(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;

	const double	expr1 = getNumericOperand(context, opPos, executionContext);

	opPos = m_expression.getNextOpCodePosition(opPos);

	const double	expr2 = getNumericOperand(context, opPos, executionContext);

	return DoubleSupport::subtract(expr1, expr2);
}



void
XPath::minus(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	const double	theResult = minus(context, opPos, executionContext);

	XObject::string(theResult, formatterListener, function);
}



double
XPath::mult(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;

	const double	expr1 = getNumericOperand(context, opPos, executionContext);

	opPos = m_expression.getNextOpCodePosition(opPos);

	const double	expr2 = getNumericOperand(context, opPos, executionContext);

	return DoubleSupport::multiply(expr1, expr2);
}



void
XPath::mult(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	const double	theResult = mult(context, opPos, executionContext);

	XObject::string(theResult, formatterListener, function);
}



double
XPath::div(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;

	const double	expr1 = getNumericOperand(context, opPos, executionContext);

	opPos = m_expression.getNextOpCodePosition(opPos);

	const double	expr2 = getNumericOperand(context, opPos, executionContext);

	return DoubleSupport::divide(expr1, expr2);
}



void
XPath::div(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	const double	theResult = div(context, opPos, executionContext);

	XObject::string(theResult, formatterListener, function);
}



double
XPath::mod(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	opPos += 2;	

	const double	expr1 = getNumericOperand(context, opPos, executionContext);

	opPos = m_expression.getNextOpCodePosition(opPos);

	const double	expr2 = getNumericOperand(context, opPos, executionContext);

	return DoubleSupport::modulus(expr1, expr2);
}



void
XPath::mod(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	const double	theResult = mod(context, opPos, executionContext);

	XObject::string(theResult, formatterListener, function);
}



double
XPath::neg(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	return DoubleSupport::negative(getNumericOperand(context, opPos + 2, executionContext));
}



void
XPath::neg(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	const double	theResult = neg(context, opPos, executionContext);

	XObject::string(theResult, formatterListener, function);
}



const XObjectPtr
XPath::Union(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	resultNodeList(executionContext);

	Union(context, opPos, executionContext, *resultNodeList);

	return executionContext.getXObjectFactory().createNodeSet(resultNodeList);
}



void
XPath::Union(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			bool&					result) const
{
	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	resultNodeList(executionContext);

	Union(context, opPos, executionContext, *resultNodeList);

	result = XObject::boolean(*resultNodeList);
}



void
XPath::Union(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			double&					result) const
{
	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	resultNodeList(executionContext);

	Union(context, opPos, executionContext, *resultNodeList);

	result = XObject::number(executionContext, *resultNodeList);
}



void
XPath::Union(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			XalanDOMString&			result) const
{
	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	resultNodeList(executionContext);

	Union(context, opPos, executionContext, *resultNodeList);

	XObject::string(*resultNodeList, result);
}



void
XPath::Union(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	resultNodeList(executionContext);

	Union(context, opPos, executionContext, *resultNodeList);

	XObject::string(*resultNodeList, formatterListener, function);
}



void
XPath::Union(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			MutableNodeRefList&		result) const
{
	assert(result.empty() == true);

	opPos += 2;

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	theGuard(executionContext);

	MutableNodeRefList&		tempNodeList = *theGuard;

	while(m_expression.getOpCodeMapValue(opPos) != XPathExpression::eENDOP)
	{
		const XObjectPtr	nodesetResult(executeMore(context, opPos, executionContext, tempNodeList));

		if (nodesetResult.null() == false)
		{
			result.addNodesInDocOrder(nodesetResult->nodeset(), executionContext);
		}
		else
		{
			result.addNodesInDocOrder(tempNodeList, executionContext);

			tempNodeList.clear();
		}

		opPos = m_expression.getNextOpCodePosition(opPos);
	}

	result.setDocumentOrder();
}



const XObjectPtr
XPath::literal(
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 2));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 2]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 2]];

	if (m_inStylesheet == true)
	{
		return executionContext.getXObjectFactory().createString(theLiteral);
	}
	else
	{
		return executionContext.getXObjectFactory().createString(theLiteral.str());
	}
}



void
XPath::literal(
			int		opPos,
			bool&	theResult) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 2));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 2]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 2]];

	theResult = theLiteral.boolean();
}



void
XPath::literal(
			int			opPos,
			double&		theResult) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 2));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 2]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 2]];

	theResult = theLiteral.num();
}



void
XPath::literal(
			int					opPos,
			XalanDOMString&		theString) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 2));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 2]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 2]];

	theLiteral.str(theString);
}



void
XPath::literal(
			int					opPos,
			FormatterListener&	formatterListener,
			MemberFunctionPtr	function) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 2));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 2]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 2]];

	theLiteral.str(formatterListener, function);
}



const XObjectPtr
XPath::variable(
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	const XObject&	ns = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 2]];

	const XObject&	varName = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 3]];

	return executionContext.getVariable(XalanQNameByReference(ns.str(), varName.str()), m_locator);
}



const XObjectPtr
XPath::numberlit(
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 3));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 3]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 3]];

	if (m_inStylesheet == true)
	{
		return executionContext.getXObjectFactory().createNumber(theLiteral);
	}
	else
	{
		return executionContext.getXObjectFactory().createNumber(theLiteral.num());
	}
}



double
XPath::numberlit(int	opPos) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 3));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 3]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 3]];

	return theLiteral.num();
}



void
XPath::numberlit(
			int		opPos,
			bool&	theResult) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 3));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 3]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 3]];

	theResult = theLiteral.boolean();
}



void
XPath::numberlit(
			int					opPos,
			XalanDOMString&		theString) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 3));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 3]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 3]];

	theLiteral.str(theString);
}



void
XPath::numberlit(
			int					opPos,
			FormatterListener&	formatterListener,
			MemberFunctionPtr	function) const
{
	assert(m_expression.m_opMap.size() > unsigned(opPos + 3));
	assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[opPos + 3]));

	const XToken&	theLiteral = m_expression.m_tokenQueue[m_expression.m_opMap[opPos + 3]];

	theLiteral.str(formatterListener, function);
}



const XObjectPtr
XPath::locationPath(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{    
	assert(context != 0);

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	mnl(executionContext);

	locationPath(context, opPos, executionContext, *mnl.get());

	return executionContext.getXObjectFactory().createNodeSet(mnl);
}



void
XPath::locationPath(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			bool&					theResult) const
{
	assert(context != 0);

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	mnl(executionContext);

	locationPath(context, opPos, executionContext, *mnl.get());

	theResult = XObject::boolean(*mnl.get());
}



void
XPath::locationPath(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			double&					theResult) const
{
	assert(context != 0);

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	mnl(executionContext);

	locationPath(context, opPos, executionContext, *mnl.get());

	theResult = XObject::number(executionContext, *mnl.get());
}



void
XPath::locationPath(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			XalanDOMString&			theResult) const
{
	assert(context != 0);

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	mnl(executionContext);

	locationPath(context, opPos, executionContext, *mnl.get());

	XObject::string(*mnl.get(), theResult);
}



void
XPath::locationPath(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext,
			FormatterListener&		formatterListener,
			MemberFunctionPtr		function) const
{
	assert(context != 0);

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	mnl(executionContext);

	locationPath(context, opPos, executionContext, *mnl.get());

	XObject::string(*mnl, formatterListener, function);
}



const XObjectPtr
XPath::runExtFunction(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	assert(context != 0);

	const int	endExtFunc = opPos + m_expression.m_opMap[opPos + 1] - 1;

	opPos += 2;

	const XalanDOMString&	ns = m_expression.m_tokenQueue[m_expression.m_opMap[opPos]].str();

	++opPos;

	const XalanDOMString&	funcName = m_expression.m_tokenQueue[m_expression.m_opMap[opPos]].str();

	++opPos;

	typedef XPathExecutionContext::XObjectArgVectorType		XObjectArgVectorType;

	XObjectArgVectorType	args;

	while(opPos < endExtFunc)
	{
		const int	nextOpPos = m_expression.getNextOpCodePosition(opPos);

		args.push_back(executeMore(context, opPos, executionContext));

		opPos = nextOpPos;
	}

	return extfunction(context, opPos, ns, funcName, args, executionContext);
}



const XObjectPtr
XPath::runFunction(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	const int	endFunc = opPos + m_expression.m_opMap[opPos + 1] - 1;

	opPos += 2;

	// This is index into the function table for the
	// function.
	const int	funcID = m_expression.getOpCodeMapValue(opPos);

	opPos++;

	// Number of args is next.
	const int	argCount = m_expression.getOpCodeMapValue(opPos);

	opPos++;

	if (argCount == 0)
	{
		assert(opPos == endFunc);

		return s_functions[funcID].execute(executionContext, context, m_locator);
	}
	else if (argCount == 1)
	{
		return s_functions[funcID].execute(
			executionContext,
			context,
			executeMore(context, opPos, executionContext),
			m_locator);
	}
	else if (argCount == 2)
	{
		const XObjectPtr	theArg1(executeMore(context, opPos, executionContext));

		opPos = m_expression.getNextOpCodePosition(opPos);

		assert(m_expression.getNextOpCodePosition(opPos) == endFunc);

		return s_functions[funcID].execute(
			executionContext,
			context,
			theArg1,
			executeMore(context, opPos, executionContext),
			m_locator);
	}
	else if (argCount == 3)
	{
		const XObjectPtr	theArg1(executeMore(context, opPos, executionContext));

		opPos = m_expression.getNextOpCodePosition(opPos);

		const XObjectPtr	theArg2(executeMore(context, opPos, executionContext));

		opPos = m_expression.getNextOpCodePosition(opPos);

		assert(m_expression.getNextOpCodePosition(opPos) == endFunc);

		return s_functions[funcID].execute(
			executionContext,
			context,
			theArg1,
			theArg2,
			executeMore(context, opPos, executionContext),
			m_locator);
	}
	else
	{
		typedef XPathExecutionContext::XObjectArgVectorType		XObjectArgVectorType;

		XObjectArgVectorType	args;

		args.reserve(argCount);

		while(opPos < endFunc)
		{
			args.push_back(executeMore(context, opPos, executionContext));

			opPos = m_expression.getNextOpCodePosition(opPos);
		}

		return function(context, funcID, args, executionContext);
	}
}



double
XPath::functionCount(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	assert(context != 0);

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	result(executionContext);

	const XObjectPtr	nodesetResult(executeMore(context, opPos + 2, executionContext, *result));

	if (nodesetResult.null() == false)
	{
		return nodesetResult->nodeset().getLength();
	}
	else
	{
		return result->getLength();
	}
}



const XalanDOMString&
XPath::functionName(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	assert(context != 0);

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	result(executionContext);

	const XObjectPtr	nodesetResult(executeMore(context, opPos + 2, executionContext, *result));

	const NodeRefListBase* const	theNodeList = nodesetResult.null() == false ?
			&nodesetResult->nodeset() : &*result;
	assert(theNodeList != 0);

	if (theNodeList->getLength() == 0)
	{
		return s_emptyString;
	}
	else
	{
		assert(theNodeList->item(0) != 0);

		return functionName(theNodeList->item(0));
	}
}



const XalanDOMString&
XPath::functionLocalName(XalanNode*		context) const
{
	assert(context != 0);

	const XalanDOMString*		theResult = &s_emptyString;

	const XalanNode::NodeType	theType = context->getNodeType();

	if(theType == XalanNode::ELEMENT_NODE ||
	   theType == XalanNode::PROCESSING_INSTRUCTION_NODE)
	{
		theResult = &DOMServices::getLocalNameOfNode(*context);
	}
	else if (theType == XalanNode::ATTRIBUTE_NODE)
	{
		const XalanDOMString&	theLocalName = DOMServices::getLocalNameOfNode(*context);

		if (theLocalName != DOMServices::s_XMLNamespace)
		{
			theResult = &theLocalName;
		}
	}

	return *theResult;
}



const XalanDOMString&
XPath::functionLocalName(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	assert(context != 0);

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	result(executionContext);

	const XObjectPtr	nodesetResult(executeMore(context, opPos + 2, executionContext, *result));

	const NodeRefListBase* const	theNodeList = nodesetResult.null() == false ?
			&nodesetResult->nodeset() : &*result;
	assert(theNodeList != 0);

	if (theNodeList->getLength() == 0)
	{
		return s_emptyString;
	}
	else
	{
		assert(theNodeList->item(0) != 0);

		return functionLocalName(theNodeList->item(0));
	}
}



double
XPath::functionStringLength(XalanNode*	context) const
{
	assert(context != 0);

	FormatterStringLengthCounter	theCounter;

	DOMServices::getNodeData(*context, theCounter, &FormatterListener::characters);

	return theCounter.getCount();
}



double
XPath::functionStringLength(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	assert(context != 0);

	FormatterStringLengthCounter	theCounter;

	executeMore(context, opPos + 2, executionContext, theCounter, &FormatterListener::characters);

	return theCounter.getCount();
}



double
XPath::functionSum(
			XalanNode*				context,
			int						opPos,
			XPathExecutionContext&	executionContext) const
{
	assert(context != 0);

	double	sum = 0.0;

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	result(executionContext);

	const XObjectPtr	nodesetResult(executeMore(context, opPos + 2, executionContext, *result));

	const NodeRefListBase* const	theNodeList = nodesetResult.null() == false ?
			&nodesetResult->nodeset() : &*result;
	assert(theNodeList != 0);

	const NodeRefListBase::size_type	theLength = theNodeList->getLength();

	if (theLength != 0)
	{
		assert(theNodeList->item(0) != 0);

		XPathExecutionContext::GetAndReleaseCachedString	theData(executionContext);

		XalanDOMString&		theString = theData.get();

		for (NodeRefListBase::size_type i = 0; i < theLength; i++)
		{
			DOMServices::getNodeData(*theNodeList->item(i), theString);

			sum = DoubleSupport::add(sum, DoubleSupport::toDouble(theString));

			clear(theString);
		}
	}

	return sum;
}



XPath::eMatchScore
XPath::locationPathPattern(
			XPathExecutionContext&	executionContext,
			XalanNode&				context, 
			int 					opPos) const
{
	eMatchScore	score = eMatchScoreNone;

	stepPattern(executionContext, &context, opPos + 2, score);

	return score;
}



void
XPath::step(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			MutableNodeRefList& 	queryResults) const
{
	const XPathExpression&	currentExpression = getExpression();

	const int	stepType =
		currentExpression.getOpCodeMapValue(opPos);

	int 		argLen = 0;

	typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

	BorrowReturnMutableNodeRefList	subQueryResults(executionContext);

	bool	continueStepRecursion = true;

	switch(stepType)
	{
	case XPathExpression::eOP_VARIABLE:
	case XPathExpression::eOP_EXTFUNCTION:
	case XPathExpression::eOP_FUNCTION:
	case XPathExpression::eOP_GROUP:
		argLen = findNodeSet(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_ROOT:
		argLen = findRoot(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_PARENT:
		argLen = findParent(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_SELF:
		argLen = findSelf(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_ANCESTORS:
		argLen = findAncestors(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_ANCESTORS_OR_SELF:
		argLen = findAncestorsOrSelf(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eMATCH_ATTRIBUTE:
		continueStepRecursion = false;
		// fall-through on purpose.

	case XPathExpression::eFROM_ATTRIBUTES:
		argLen = findAttributes(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eMATCH_ANY_ANCESTOR:
	case XPathExpression::eMATCH_IMMEDIATE_ANCESTOR:
	case XPathExpression::eMATCH_ANY_ANCESTOR_WITH_PREDICATE:
		continueStepRecursion = false;
		// fall-through on purpose.

	case XPathExpression::eFROM_CHILDREN:
		argLen = findChildren(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_DESCENDANTS:
	case XPathExpression::eFROM_DESCENDANTS_OR_SELF:
		argLen = findDescendants(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_FOLLOWING:
		argLen = findFollowing(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_FOLLOWING_SIBLINGS:
		argLen = findFollowingSiblings(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_PRECEDING:
		argLen = findPreceeding(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_PRECEDING_SIBLINGS:
		argLen = findPreceedingSiblings(executionContext, context, opPos, stepType, *subQueryResults);
		break;

	case XPathExpression::eFROM_NAMESPACE:
		argLen = findNamespace(executionContext, context, opPos,  stepType, *subQueryResults);
		break;

	default:
		argLen = findNodesOnUnknownAxis(executionContext, context, opPos, stepType, *subQueryResults);
		break;
	}

	opPos += argLen;

	int		nextStepType = currentExpression.getOpCodeMapValue(opPos);

	// Push and pop the context node list...
		XPathExecutionContext::ContextNodeListPushAndPop	thePushAndPop(
										executionContext,
										*subQueryResults);

	if(XPathExpression::eOP_PREDICATE == nextStepType ||
	   XPathExpression::eOP_PREDICATE_WITH_POSITION == nextStepType)
	{
		opPos = predicates(
			executionContext,
		   opPos, 
		   *subQueryResults);

		nextStepType = currentExpression.getOpCodeMapValue(opPos);
	}

	if(XPathExpression::eENDOP != nextStepType && continueStepRecursion == true)
	{
		const NodeRefListBase::size_type	nContexts = subQueryResults->getLength();

		if (nContexts > 0)
		{
			for(NodeRefListBase::size_type i = 0; i < nContexts; i++)
			{
				XalanNode* const	node = subQueryResults->item(i);
				assert(node != 0);

				BorrowReturnMutableNodeRefList	mnl(executionContext);

				step(executionContext, node, opPos, *mnl);

				if (mnl->empty() == false)
				{
					if(queryResults.empty() == false)
					{
						queryResults.addNodesInDocOrder(*mnl, executionContext);

						queryResults.setDocumentOrder();
					}
					else
					{
						assert(mnl->getDocumentOrder() == true);

						queryResults.swap(*mnl);
					}
				}
			}

			if (queryResults.empty() == true)
			{
				queryResults.setDocumentOrder();
			}
		}
	}
	else
	{
		if (subQueryResults->empty() == true)
		{
			queryResults.clear();
		}
		else if (subQueryResults->getReverseDocumentOrder() == true)
		{
			queryResults.swap(*subQueryResults);

			queryResults.reverse();
		}
		else
		{
			assert(subQueryResults->getDocumentOrder() == true);

			queryResults.swap(*subQueryResults);
		}
	}
}



XalanNode*
XPath::stepPattern(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			eMatchScore& 			scoreHolder) const
{
	const XPathExpression&	currentExpression = getExpression();

	const int	endStep = currentExpression.getNextOpCodePosition(opPos);
	int 		nextStepType = currentExpression.getOpCodeMapValue(endStep);

	if(XPathExpression::eENDOP != nextStepType)
	{
		// Continue step via recursion...
		context = stepPattern(
						executionContext,
						context,
						endStep,
						scoreHolder);

		if(0 == context)
		{
			scoreHolder = eMatchScoreNone;

		}

		if (scoreHolder == eMatchScoreNone)
		{
			// !!!!!!!!!!!!! Big ugly return here !!!!!!!!!!!!!!!!!!!
			return 0;
		}

		scoreHolder = eMatchScoreOther;

		if (nextStepType != XPathExpression::eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL)
		{
			context = DOMServices::getParentOfNode(*context);
		}

		if(0 == context)
		{
			// !!!!!!!!!!!!! Big ugly return here !!!!!!!!!!!!!!!!!!!
			return 0;
		}
	}

	assert(context != 0);

	int				argLen = 0;

	eMatchScore		score = eMatchScoreNone;

	const int		startOpPos = opPos;
	const int		stepType = currentExpression.getOpCodeMapValue(opPos);

	switch(stepType)
	{
	case XPathExpression::eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL:
		score = scoreHolder;
		break;

	case XPathExpression::eOP_FUNCTION:
		{
			argLen = currentExpression.getOpCodeLengthFromOpMap(opPos);

			const XObjectPtr		obj(executeMore(context, opPos, executionContext));
			assert(obj.get() != 0);

			const NodeRefListBase&				nl = obj->nodeset();

			const NodeRefListBase::size_type	len = nl.getLength();

			if (nextStepType == XPathExpression::eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL)
			{
				bool	fFound = false;

				while(context != 0 && fFound == false)
				{
					for(NodeRefListBase::size_type i = 0; i < len; i++)
					{
						XalanNode* const	n = nl.item(i);

						if(n == context)
						{
							score = eMatchScoreOther;

							context = n;

							fFound = true;

							break;
						}
					}

					context = DOMServices::getParentOfNode(*context);
				}
			}
			else
			{
				for(NodeRefListBase::size_type i = 0; i < len; i++)
				{
					XalanNode* const	n = nl.item(i);

					if(n == context)
					{
						score = eMatchScoreOther;

						context = n;

						break;
					}
				}
			}
		}
		break;

	case XPathExpression::eFROM_ROOT:
		{
			// $$ ToDO: Can we reduce this to some call on the
			// XPathExpression interface?
			argLen =
				currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

			opPos += 3;

			const XalanNode::NodeType	nodeType = context->getNodeType();

			if (nodeType == XalanNode::DOCUMENT_NODE ||
				nodeType == XalanNode::DOCUMENT_FRAGMENT_NODE)
			{
				score = eMatchScoreOther;
			}
			else
			{
				const int   prevPos = currentExpression.getNextOpCodePosition(startOpPos);		
				const int	prevStepType = currentExpression.getOpCodeMapValue(prevPos);

				if (eMatchScoreNone == score  && 
				    (prevStepType == XPathExpression::eMATCH_ANY_ANCESTOR ||
					 prevStepType == XPathExpression::eMATCH_ANY_ANCESTOR_WITH_PREDICATE))
				{
					const NodeTester	theTester(
									*this,
									executionContext,
									opPos,
									argLen,
									stepType);

					while(0 != context)
					{
						score =
							theTester(*context, context->getNodeType());
							assert(score == nodeTest(executionContext, context, context->getNodeType(), opPos, argLen, stepType));

						if(eMatchScoreNone != score)
							break;

						context = DOMServices::getParentOfNode(*context);
					}
				}
			}
		}
		break;

	case XPathExpression::eMATCH_ATTRIBUTE:
		{
			// $$ ToDO: Can we reduce this to some call on the
			// XPathExpression interface?
			argLen =
				currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

			opPos += 3;

			score = NodeTester(
							*this,
							executionContext,
							opPos,
							argLen,
							XPathExpression::eFROM_ATTRIBUTES)(*context, context->getNodeType());

			assert(score == nodeTest(
							 executionContext,
							 context,
							 context->getNodeType(),
							 opPos,
							 argLen,
							 XPathExpression::eFROM_ATTRIBUTES));
		}
		break;

	case XPathExpression::eMATCH_ANY_ANCESTOR:
	case XPathExpression::eMATCH_ANY_ANCESTOR_WITH_PREDICATE:
		{
			// $$ ToDO: Can we reduce this to some call on the
			// XPathExpression interface?
			argLen =
					currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

			XalanNode::NodeType		nodeType = context->getNodeType();

			if(nodeType != XalanNode::ATTRIBUTE_NODE)
			{
				opPos += 3;

				const NodeTester	theTester(
									*this,
									executionContext,
									opPos,
									argLen,
									stepType);

				for(;;)
				{
					score = theTester(*context, nodeType);
					assert(score == nodeTest(executionContext, context, nodeType, opPos, argLen, stepType));

					if(eMatchScoreNone != score)
						break;

					context = DOMServices::getParentOfNode(*context);

					if (context == 0)
						break;

					nodeType = context->getNodeType();
				}
			}
		}
		break;

	case XPathExpression::eMATCH_IMMEDIATE_ANCESTOR:
		{
			// $$ ToDO: Can we reduce this to some call on the
			// XPathExpression interface?
			argLen =
				currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

			const XalanNode::NodeType	nodeType = context->getNodeType();

			if(nodeType != XalanNode::ATTRIBUTE_NODE)
			{
				opPos += 3;

				score = NodeTester(
								*this,
								executionContext,
								opPos,
								argLen,
								XPathExpression::eMATCH_IMMEDIATE_ANCESTOR)(*context, nodeType);

				assert(score == nodeTest(
								 executionContext,
								 context,
								 nodeType,
								 opPos,
								 argLen,
								 XPathExpression::eMATCH_IMMEDIATE_ANCESTOR));
			}
		}
		break;

	default:
		executionContext.error(
			XalanMessageLoader::getMessage(XalanMessages::UnknownMatchOperation)
			, context, getLocator());
		break;
	}

	opPos += argLen;

	nextStepType = currentExpression.getOpCodeMapValue(opPos);

	if(score != eMatchScoreNone &&
	   (XPathExpression::eOP_PREDICATE == nextStepType || XPathExpression::eOP_PREDICATE_WITH_POSITION == nextStepType))
	{
		score = eMatchScoreOther;

		while(XPathExpression::eOP_PREDICATE == nextStepType ||
			  XPathExpression::eOP_PREDICATE_WITH_POSITION == nextStepType)
		{
			// This is a quick hack to look ahead and see if we have
			// number literal as the predicate, i.e. match="foo[1]".
			if (XPathExpression::eOP_PREDICATE_WITH_POSITION == nextStepType)
			{
				if (m_expression.getOpCodeMapValue(opPos + 2) == XPathExpression::eOP_NUMBERLIT)
				{
					score = handleFoundIndexPositional(
							executionContext,
							context,
							startOpPos);
				}
				else
				{
					score = handleFoundIndex(
							executionContext,
							context,
							startOpPos);
				}
			}
			else
			{
				const XObjectPtr	pred(predicate(context, opPos, executionContext));
				assert(pred.get() != 0);

				if(XObject::eTypeNumber == pred->getType())
				{
					score = handleFoundIndex(executionContext, context, startOpPos);
				}
				else if(pred->boolean() == false)
				{
					score = eMatchScoreNone;

					break;
				}
			}

			opPos = currentExpression.getNextOpCodePosition(opPos);
			nextStepType = currentExpression.getOpCodeMapValue(opPos);
		}
	}

	if (scoreHolder == eMatchScoreNone || 
        score == eMatchScoreNone)
	{
		scoreHolder = score;
	}

	return score == eMatchScoreNone ? 0 : context;
}



XPath::eMatchScore
XPath::handleFoundIndex(
			XPathExecutionContext&	executionContext,
			XalanNode* 				localContext, 
			int 					startOpPos) const
{
	// We have an index somewhere in our pattern.  So, we have 
	// to do a full search for our step, using the parent as 
	// localContext, then see if the current localContext is found in the 
	// node set.  Seems crazy, but, so far, it seems like the 
	// easiest way.
	XalanNode* const	parentContext =
				DOMServices::getParentOfNode(*localContext);

	if (parentContext == 0)
	{
		return eMatchScoreNone;
	}
	else
	{
		typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

		BorrowReturnMutableNodeRefList	mnl(executionContext);

		step(executionContext, parentContext, startOpPos, *mnl);

		if (mnl->indexOf(localContext) == MutableNodeRefList::npos)
		{
			return eMatchScoreNone;
		}
		else
		{
			return eMatchScoreOther;
		}
	}
}



XPath::eMatchScore
XPath::handleFoundIndexPositional(
			XPathExecutionContext&	executionContext,
			XalanNode* 				localContext,
			int 					startOpPos) const
{
	XalanNode* const	parentContext =
				DOMServices::getParentOfNode(*localContext);

	if (parentContext == 0)
	{
		return eMatchScoreNone;
	}
	else
	{
		typedef XPathExecutionContext::BorrowReturnMutableNodeRefList	BorrowReturnMutableNodeRefList;

		BorrowReturnMutableNodeRefList	mnl(executionContext);

		step(executionContext, parentContext, startOpPos, *mnl);

		if (mnl->empty() == true)
		{
			return eMatchScoreNone;
		}
		else
		{
			assert(mnl->getLength() == 1 && mnl->item(0) == localContext);

			return eMatchScoreOther;
		}
	}
}



int
XPath::findNodeSet(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					/* stepType */,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);

	const XObjectPtr	nodesetResult(executeMore(context, opPos, executionContext, subQueryResults));

	if (nodesetResult.null() == true)
	{
		assert(subQueryResults.getDocumentOrder());
	}
	else
	{
		subQueryResults.addNodesInDocOrder(nodesetResult->nodeset(), executionContext);

		subQueryResults.setDocumentOrder();
	}

	return getExpression().getOpCodeLengthFromOpMap(opPos);
}



int
XPath::findRoot(
			XPathExecutionContext&	/* executionContext */,
			XalanNode*				context, 
			int 					opPos,
			int 					/* stepType */,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	XalanNode* const	docContext = XalanNode::DOCUMENT_NODE == context->getNodeType() ?
									context :
									context->getOwnerDocument();
	assert(docContext != 0);

	subQueryResults.addNode(docContext);

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



int
XPath::findParent(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
			currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	XalanNode* const	theParent = DOMServices::getParentOfNode(*context);

	if(0 != theParent)
	{
		if(argLen > 0)
		{
			opPos += 3;

			const NodeTester	theTester(
							*this,
							executionContext,
							opPos,
							argLen,
							stepType);

			const eMatchScore	score = theTester(*theParent, theParent->getNodeType());
			assert(score == nodeTest(executionContext, theParent, theParent->getNodeType(), opPos, argLen, stepType));

			if(eMatchScoreNone != score)
			{
				subQueryResults.addNode(theParent);
			}
		}
		else
		{
			subQueryResults.addNode(theParent);
		}
	}

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



int
XPath::findSelf(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	if(argLen == 0)
	{
		subQueryResults.addNode(context);
	}
	else
	{
		opPos += 3;

		const NodeTester	theTester(
						*this,
						executionContext,
						opPos,
						argLen,
						stepType);

		const eMatchScore	score =
			theTester(*context, context->getNodeType());
			assert(score == nodeTest(executionContext, context, context->getNodeType(), opPos, argLen, stepType));

		if(eMatchScoreNone != score)
		{
			subQueryResults.addNode(context);
		}
	}

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



int
XPath::findAncestors(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	context = DOMServices::getParentOfNode(*context);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
			currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	if (context != 0)
	{
		opPos += 3;

		const NodeTester	theTester(
						*this,
						executionContext,
						opPos,
						argLen,
						stepType);

		do
		{
			const eMatchScore	score =
				theTester(*context, context->getNodeType());
				assert(score == nodeTest(executionContext, context, context->getNodeType(), opPos, argLen, stepType));

			if(eMatchScoreNone != score)
			{
				subQueryResults.addNode(context);
			}

			context = DOMServices::getParentOfNode(*context);
		} while(0 != context);
	}

	subQueryResults.setReverseDocumentOrder();

	return argLen + 3;
}



int
XPath::findAncestorsOrSelf(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	opPos += 3;

	const NodeTester	theTester(
					*this,
					executionContext,
					opPos,
					argLen,
					stepType);

	do
	{
		const eMatchScore	score =
				theTester(*context, context->getNodeType());
				assert(score == nodeTest(executionContext, context, context->getNodeType(), opPos, argLen, stepType));

		if(eMatchScoreNone != score)
		{
			subQueryResults.addNode(context);
		}

		context = DOMServices::getParentOfNode(*context);
	} while(0 != context);

	subQueryResults.setReverseDocumentOrder();

	return argLen + 3;
}



int
XPath::findAttributes(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
				currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	if(context->getNodeType() == XalanNode::ELEMENT_NODE)
	{
		const XalanNamedNodeMap* const	attributeList = context->getAttributes();

		if(attributeList != 0) 
		{
			opPos += 3;

			const unsigned int	nAttrs = attributeList->getLength();

			if (nAttrs != 0)
			{
				const NodeTester	theTester(
								*this,
								executionContext,
								opPos,
								argLen,
								stepType);

				for(unsigned int j = 0; j < nAttrs; j++)
				{
					XalanNode* const	theNode = attributeList->item(j);
					assert(theNode != 0 && theNode->getNodeType() == XalanNode::ATTRIBUTE_NODE);

					const eMatchScore	score =
						theTester(*theNode, XalanNode::ATTRIBUTE_NODE);
						assert(score == nodeTest(executionContext, theNode, XalanNode::ATTRIBUTE_NODE, opPos, argLen, stepType));

					if(eMatchScoreNone != score)
					{
						subQueryResults.addNode(theNode);
					}
				}
			}
		}
	}

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



int
XPath::findChildren(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	XalanNode*	child = context->getFirstChild();

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	if (child != 0)
	{
		opPos += 3;

		const NodeTester	theTester(
						*this,
						executionContext,
						opPos,
						argLen,
						stepType);

		do
		{
			const eMatchScore	score =
					theTester(*child, child->getNodeType());
					assert(score == nodeTest(executionContext, child, child->getNodeType(), opPos, argLen, stepType));

			if(eMatchScoreNone != score)
			{
				subQueryResults.addNode(child);
			}

			child = child->getNextSibling();
		} while(0 != child);
	}

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



int
XPath::findDescendants(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	// Perform a pre-order traversal of descendents...
	XalanNode*	pos = context;

	opPos += 3;

	const NodeTester	theTester(
						*this,
						executionContext,
						opPos,
						argLen,
						stepType);

	do
	{					
		if(stepType == XPathExpression::eFROM_DESCENDANTS_OR_SELF ||
		   context != pos)
		{
			const eMatchScore	score =
				theTester(*pos, pos->getNodeType());
				assert(score == nodeTest(executionContext, pos, pos->getNodeType(), opPos, argLen, stepType));

			if(score != eMatchScoreNone)
			{
				subQueryResults.addNode(pos);
			}
		}

		XalanNode*	nextNode = pos->getFirstChild();

		while(0 == nextNode)
		{
			if(context == pos)
				break;

			nextNode = pos->getNextSibling();

			if(0 == nextNode)
			{
				pos = DOMServices::getParentOfNode(*pos);

				if(context == pos || pos == 0)
				{
					nextNode = 0;
					break;
				}
			}
		}

		pos = nextNode;
	} while(0 != pos);

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



int
XPath::findFollowing(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	opPos += 3;

	// What fun...
	XalanDocument* const	doc = context->getOwnerDocument();

	XalanNode*				pos = context;

	const NodeTester	theTester(
					*this,
					executionContext,
					opPos,
					argLen,
					stepType);

	while(0 != pos)
	{
		XalanNode*	nextNode = 0;

		if(pos != context)
		{
			const eMatchScore	score =
				theTester(*pos, pos->getNodeType());
				assert(score == nodeTest(executionContext, pos, pos->getNodeType(), opPos, argLen, stepType));

			if(eMatchScoreNone != score)
			{
				subQueryResults.addNodeInDocOrder(pos, executionContext);
			}

			nextNode = pos->getFirstChild();
		}
		else
		{
			nextNode = 0;
		}

		while(0 == nextNode)
		{
			// This requires some explanation.  pos could be an attribute
			// node, so getNextSibling() will always return 0.  In that
			// case, I want to continue the search with the first child of
			// the owner element, as if attribute nodes are children which
			// are always _before_ the first child element.  I don't have to
			// consider following attributes, since they _never_ match the
			// following axis.
			if (pos->getNodeType() == XalanNode::ATTRIBUTE_NODE)
			{
				assert(DOMServices::getParentOfNode(*pos) != 0);

				nextNode = DOMServices::getParentOfNode(*pos)->getFirstChild();
			}
			else
			{
				nextNode = pos->getNextSibling();
			}

			if(0 == nextNode)
			{
				pos = DOMServices::getParentOfNode(*pos);

				if(doc == pos || 0 == pos)
				{
					nextNode = 0;

					break;
				}
			}
		}

		pos = nextNode;
	}

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



int
XPath::findFollowingSiblings(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	XalanNode*	pos = context->getNextSibling();

	if (pos != 0)
	{
		opPos += 3;

		const NodeTester	theTester(
						*this,
						executionContext,
						opPos,
						argLen,
						stepType);

		do
		{
			const eMatchScore	score =
					theTester(*pos, pos->getNodeType());
					assert(score == nodeTest(executionContext, pos, pos->getNodeType(), opPos, argLen, stepType));

			if(eMatchScoreNone != score)
			{
				subQueryResults.addNode(pos);
			}

			pos = pos->getNextSibling();
		} while(0 != pos);
	}

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



/*
 * This is bit of a hack to figure out where we should start for
 * the preceeding axis.  It's mostly to support RTFs which have
 * been coerced to nodesets through the nodeset() extension function.
 */
static XalanNode*
findTopNode(
			XalanNode*				context,
			XalanNode::NodeType		theType)
{
	assert(context != 0);

	if (theType == XalanNode::DOCUMENT_NODE)
	{
		return context;
	}
	else
	{
		XalanDocument* const	theDocument = context->getOwnerDocument();
		assert(theDocument != 0);

		if (theDocument->getDocumentElement() != 0)
		{
			return theDocument;
		}
		else
		{
			XalanNode*	theNode = 0;

			while(context != 0 &&
				  context->getNodeType() != XalanNode::DOCUMENT_NODE)
			{
				theNode = context;

				context = DOMServices::getParentOfNode(*context);
			}

			assert(theNode != 0);

			return theNode;
		}
	}
}



int
XPath::findPreceeding(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	opPos += 3;

	// Ugh.  Reverse document order, no parents, I guess.
	const XalanNode::NodeType	theType = context->getNodeType();

	XalanNode* const	topNode = findTopNode(context, theType);

	XalanNode*			pos = topNode;

	// If the context node is an attribute, we need to perform some
	// magic to stop the search at the appropriate point, which is when
	// we arrive back at the parent.
	const bool				contextIsAttribute =
			theType == XalanNode::ATTRIBUTE_NODE ? true : false;

	const XalanNode* const	theAttributeContextParent =
		contextIsAttribute == true ? DOMServices::getParentOfNode(*context) : 0;

	const NodeTester	theTester(
						*this,
						executionContext,
						opPos,
						argLen,
						stepType);

	while(0 != pos)
	{
		if(context == pos)
		{
			break;
		}

		const eMatchScore	score =
				theTester(*pos, pos->getNodeType());
				assert(score == nodeTest(executionContext, pos, pos->getNodeType(), opPos, argLen, stepType));

		if(eMatchScoreNone != score)
		{
			// Ugh. If I could think a little better tonight, I'm
			// sure there's a better way to check for the parent.
			bool		isParent = false;

			XalanNode*	parent = DOMServices::getParentOfNode(*context);

			while(0 != parent)
			{
				if(parent == pos)
				{
					isParent = true;
					break;
				}

				parent = DOMServices::getParentOfNode(*parent);
			}

			if(isParent == false)
			{
				subQueryResults.addNode(pos);
			}
		}

		XalanNode*	nextNode = 0;

		// Check to see if we're back at the attribute context node's
		// parent, in which case, we should stop.
		if (contextIsAttribute == true &&
			pos == theAttributeContextParent)
		{
			nextNode = context;
		}
		else
		{
			nextNode = pos->getFirstChild();
		}

		while(0 == nextNode)
		{
			nextNode = pos->getNextSibling();

			if(0 == nextNode)
			{
				pos = DOMServices::getParentOfNode(*pos);

				if(topNode == pos)
				{
					nextNode = 0;
					break;
				}
			}
		}

		pos = nextNode;
	}

	// Now, reverse the order of the nodes, since
	// preceeding is a reverse axis, and we searched
	// the document from the root to this node.
	subQueryResults.reverse();

	subQueryResults.setReverseDocumentOrder();

	return argLen + 3;
}



int
XPath::findPreceedingSiblings(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

#if 1
	XalanNode*	pos = context->getPreviousSibling();

	if (pos != 0)
	{
		opPos += 3;

		const NodeTester	theTester(
						*this,
						executionContext,
						opPos,
						argLen,
						stepType);

		do
		{
			const eMatchScore	score = 
				theTester(*pos, pos->getNodeType());
				assert(score == nodeTest(executionContext, pos, pos->getNodeType(), opPos, argLen, stepType));

			if(eMatchScoreNone != score)
			{
				subQueryResults.addNode(pos);
			}

			pos = pos->getPreviousSibling();
		} while(0 != pos);
	}
#else
    // This is some experimental code which avoids using getPreviousSibling(), with the idea that we
    // could reduce our in-memory representation size by not keeping the previous sibling node.
	XalanNode*	pos = context->getParentNode();

	if (pos != 0)
	{
		pos = pos->getFirstChild();

		if (pos != context)
		{
			opPos += 3;

			const NodeTester	theTester(
							*this,
							executionContext,
							opPos,
							argLen,
							stepType);

			do
			{
				const eMatchScore	score = 
					theTester(*pos, pos->getNodeType());
					assert(score == nodeTest(executionContext, pos, pos->getNodeType(), opPos, argLen, stepType));

				if(eMatchScoreNone != score)
				{
					subQueryResults.addNode(pos);
				}

				pos = pos->getNextSibling();
			} while(pos != context);
		}

		// Now, reverse the order of the nodes, since
		// preceeding-sibling is a reverse axis, and we searched
		// the document from the root to this node.
		subQueryResults.reverse();
	}
#endif

	subQueryResults.setReverseDocumentOrder();

	return argLen + 3;
}



int
XPath::findNamespace(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					stepType,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(subQueryResults.empty() == true);
	assert(context != 0);

	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	if(context->getNodeType() == XalanNode::ELEMENT_NODE)
	{
		opPos += 3;

		// Look up the element chain until we hit the document, so that we
		// get all of the attribute/namespace nodes.
		const XalanNode* const	theOwnerDocument = context->getOwnerDocument();
		assert(theOwnerDocument != 0);

		const XalanNode*		theCurrentNode = context;

		const NodeTester	theTester(
						*this,
						executionContext,
						opPos,
						argLen,
						stepType);

		NodeRefListBase::size_type	nNSFound = 0;
		bool						defaultNSFound = false;

		do
		{
			const XalanNamedNodeMap* const	attributeList =
				theCurrentNode->getAttributes();

			if(attributeList != 0) 
			{
				unsigned int	nAttrs = attributeList->getLength();

				while(nAttrs > 0)
				{
					--nAttrs;

					XalanNode* const	attr = attributeList->item(nAttrs);
					assert(attr != 0 && attr->getNodeType() == XalanNode::ATTRIBUTE_NODE);

					const XalanDOMString&	theNodeName = attr->getNodeName();

					// This is an optimization to keep non-namespace attributes out of
					// the call to nodeTest().
					if (startsWith(theNodeName, DOMServices::s_XMLNamespaceWithSeparator) == true ||
						theNodeName == DOMServices::s_XMLNamespace)
					{
						const eMatchScore	score =
							theTester(*attr, XalanNode::ATTRIBUTE_NODE);
							assert(score == nodeTest(executionContext, attr, XalanNode::ATTRIBUTE_NODE, opPos, argLen, stepType));

						if(score != eMatchScoreNone)
						{
							const XalanDOMString&	theNodeValue = attr->getNodeValue();

 							bool			foundNSMatch = false;
 
 							// Need to check default NS slightly differently
 							if (theNodeName == DOMServices::s_XMLNamespace)
 							{
 								// If namespace is empty, don't add anything
 								// as under XPath an empty default is indicated
 								// by no node.
 
 								foundNSMatch = defaultNSFound ||
 									(theNodeValue == DOMServices::s_emptyString);
 								defaultNSFound = true;
 							}
 
 							for (NodeRefListBase::size_type lstIndex = 0; 
 								 foundNSMatch == false && lstIndex < nNSFound;
 								 ++lstIndex)
 							{
 								if (subQueryResults.item(lstIndex)->getNodeName() == theNodeName)
 								{
 									foundNSMatch = true;
 								}
 							}

							if (foundNSMatch == false) 
 							{
 								subQueryResults.addNode(attr);
 								++nNSFound;
 							}
						}
					}
				}
			}

			theCurrentNode = theCurrentNode->getParentNode();
		} while (theCurrentNode != theOwnerDocument && theCurrentNode != 0);
	}

	subQueryResults.reverse();

	subQueryResults.setDocumentOrder();

	return argLen + 3;
}



int
XPath::findNodesOnUnknownAxis(
			XPathExecutionContext&	executionContext,
			XalanNode*				context, 
			int 					opPos,
			int 					/* stepType */,
			MutableNodeRefList& 	/* subQueryResults */) const
{
	const XPathExpression&	currentExpression = getExpression();

	// $$ ToDO: Can we reduce this to some call on the
	// XPathExpression interface?
	const int	argLen =
		currentExpression.getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;

	executionContext.error(
			XalanMessageLoader::getMessage(XalanMessages::UnknownAxis),
			context,
			getLocator());

	return argLen + 3;
}



XPath::eMatchScore
XPath::nodeTest(
			XPathExecutionContext&	executionContext,
			XalanNode* 				context,
			XalanNode::NodeType		nodeType,
			int 					opPos,
			int 					argLen,
			int 					stepType) const
{
	assert(context->getNodeType() == nodeType);

	const XPathExpression&	currentExpression = getExpression();

	eMatchScore		score = eMatchScoreNone;

	const int	testType = currentExpression.getOpCodeMapValue(opPos);

	switch(testType)
	{
	case XPathExpression::eNODETYPE_COMMENT:
		if (XalanNode::COMMENT_NODE == nodeType)
		{
			score = eMatchScoreNodeTest;
		}
		break;

	case XPathExpression::eNODETYPE_TEXT:
		if ((XalanNode::CDATA_SECTION_NODE == nodeType ||
			 XalanNode::TEXT_NODE == nodeType) &&
			executionContext.shouldStripSourceNode(*context) == false)
		{
			  score = eMatchScoreNodeTest;
		}
	  break;

	case XPathExpression::eNODETYPE_PI:
		if(XalanNode::PROCESSING_INSTRUCTION_NODE == nodeType)
		{
			if(argLen == 1)
			{
				score = eMatchScoreNodeTest;
			}
			else if(argLen == 2)
			{
				opPos++;

				const int				tokenPosition =
					currentExpression.getOpCodeMapValue(opPos);

				const XObject* const	name =
					currentExpression.getToken(tokenPosition);
				assert(name != 0);

				if (context->getNodeName() == name->str())
				{
					score = eMatchScoreQName;
				}
			}
			else
			{

				executionContext.error(XalanMessageLoader::getMessage(XalanMessages::ArgLengthNodeTestIsIncorrect_1Param, "processing-instruction()"), context, getLocator());
			}
		}

		break;

	case XPathExpression::eNODETYPE_NODE:
		if (nodeType == XalanNode::CDATA_SECTION_NODE ||
			nodeType == XalanNode::TEXT_NODE)
		{
			if (executionContext.shouldStripSourceNode(*context) == false)
			{
				score = eMatchScoreNodeTest;
			}
		}
		else
		{
			score = eMatchScoreNodeTest;
		}
		break;

	case XPathExpression::eNODETYPE_ROOT:
		if (XalanNode::DOCUMENT_FRAGMENT_NODE == nodeType ||
			XalanNode::DOCUMENT_NODE == nodeType)
		{
			score =  eMatchScoreOther;
		}
		break;

	case XPathExpression::eNODENAME:
		{
			opPos++;

			if (nodeType == XalanNode::ATTRIBUTE_NODE || nodeType == XalanNode::ELEMENT_NODE)
			{
				bool					test = false;

				int 					queueIndex = currentExpression.getOpCodeMapValue(opPos);

				const XalanDOMString&	targetNS = queueIndex >= 0 ?
										currentExpression.getToken(queueIndex)->str() :
											s_emptyString;

				opPos++;

				// From the draft: "Two expanded names are equal if they 
				// have the same local part, and either both have no URI or 
				// both have the same URI."
				// "A node test * is true for any node of the principal node type. 
				// For example, child::* will select all element children of the 
				// context node, and attribute::* will select all attributes of 
				// the context node."
				// "A node test can have the form NCName:*. In this case, the prefix 
				// is expanded in the same way as with a QName using the context 
				// namespace declarations. The node test will be true for any node 
				// of the principal type whose expanded name has the URI to which 
				// the prefix expands, regardless of the local part of the name."
				const bool	isTotallyWild =
							0 == length(targetNS) &&
							currentExpression.getOpCodeMapValue(opPos) == XPathExpression::eELEMWILDCARD;

				bool		didMatchNS = false;

				if(isTotallyWild == false)
				{
					const XalanDOMString&	contextNS = DOMServices::getNamespaceOfNode(*context);

					if(0 != length(targetNS) && 0 != length(contextNS))
					{
						test = contextNS == targetNS;

						didMatchNS = true;
					}
					else
					{
						test = XPathExpression::eELEMWILDCARD == queueIndex || 
						   (0 == length(contextNS) && 0 == length(targetNS));
					}
				}
				else
				{
					test = true;
				}

				queueIndex = currentExpression.getOpCodeMapValue(opPos);

				if(test == true)
				{
					switch(nodeType)
					{
					case XalanNode::ATTRIBUTE_NODE:
						if(stepType == XPathExpression::eFROM_ATTRIBUTES ||
							stepType == XPathExpression::eFROM_NAMESPACE)
						{
							assert(context->getNodeType() == XalanNode::ATTRIBUTE_NODE);

							const XalanDOMString&	attrName =
										context->getNodeName();

							const bool				isNamespace =
									startsWith(attrName, DOMServices::s_XMLNamespaceWithSeparator) ||
									attrName == DOMServices::s_XMLNamespace;

							if(XPathExpression::eELEMWILDCARD == queueIndex)
							{
								if(stepType == XPathExpression::eFROM_ATTRIBUTES)
								{
									if (isNamespace == false)
									{
										if (isTotallyWild == true)
										{
											score = eMatchScoreNodeTest;
										}
										else
										{
											score = eMatchScoreNSWild;
										}
									}
								}
								else
								{
									if (isNamespace == true)
									{
										score = eMatchScoreNodeTest;
									}
								}
							}
							else
							{
								if(stepType == XPathExpression::eFROM_ATTRIBUTES)
								{
									if (isNamespace == false)
									{
										assert(queueIndex >= 0);

										const XalanDOMString&	targetLocalName =
															currentExpression.getToken(queueIndex)->str();

										const XalanDOMString&	localAttrName =
												DOMServices::getLocalNameOfNode(*context);

										if (localAttrName == targetLocalName)
										{
											score = eMatchScoreQName;
										}
									}
								}
								else
								{
									if (isNamespace == true)
									{
										const XalanAttr* const	theAttrNode =
#if defined(XALAN_OLD_STYLE_CASTS)
											(const XalanAttr*)context;
#else
											static_cast<const XalanAttr*>(context);
#endif
										assert(theAttrNode != 0);

										const XalanDOMString&	theNamespace =
													theAttrNode->getLocalName();

										assert(queueIndex >= 0);

										const XalanDOMString&	targetLocalName =
															currentExpression.getToken(queueIndex)->str();

										if (theNamespace == targetLocalName)
										{
											score = eMatchScoreQName;
										}
									}
								}
							}
						}
						break;

					case XalanNode::ELEMENT_NODE:
						if(stepType != XPathExpression::eFROM_ATTRIBUTES)
						{
							if(XPathExpression::eELEMWILDCARD == queueIndex)
							{
								score = didMatchNS == true ?
									eMatchScoreNSWild : eMatchScoreNodeTest;
							}
							else
							{
								assert(queueIndex >= 0);

								const XalanDOMString&	targetLocalName =
															currentExpression.getToken(queueIndex)->str();

								if (DOMServices::getLocalNameOfNode(*context) == targetLocalName)
								{
									score = eMatchScoreQName;
								}
							}
						}
						break;

					default:
						// Trying to match on anything else causes nasty bugs.
						break;
					} // end switch(nodeType)
				} // end if(test)
			} // end if (nodeType == XalanNode::ATTRIBUTE_NODE || nodeType == XalanNode::ELEMENT_NODE)
		} // end case XPathExpression::eNODENAME
		break;

	default:
		break;
	} // end switch(testType)

	return score;
}



int
XPath::predicates(
			XPathExecutionContext&	executionContext,
			int 					opPos,
			MutableNodeRefList& 	subQueryResults) const
{
	assert(&executionContext.getContextNodeList() == &subQueryResults);

	const XPathExpression&	currentExpression = getExpression();

	assert(currentExpression.getOpCodeMapValue(opPos) == XPathExpression::eOP_PREDICATE ||
		   currentExpression.getOpCodeMapValue(opPos) == XPathExpression::eOP_PREDICATE_WITH_POSITION);

	NodeRefListBase::size_type	theLength = subQueryResults.getLength();

	for(;;)
	{
		// If we have no nodes left, then there's no point in executing any
		// predicates.  However, we will continue to loop, since we need to
		// update endPredicatePos.
		if (theLength > 0)
		{
			const int	predOpPos = opPos + 2;

			// OK, this is a huge hack/optimization.  If the predicate is
			// simple a number, such as [2], we can just get the
			// numeric value from the expression, and not bother executing
			// the predicate.  Furthermore, we don't need to execute the
			// predicate for each node, since the evaluation is no dependent
			// on the context node.  All we really have to do is remove all
			// nodes from subQueryResults, _except_ for the node at that
			// position.  The only trick is that XPath indexes from 1, while
			// our node lists index from 0.
			if (m_expression.getOpCodeMapValue(predOpPos) == XPathExpression::eOP_NUMBERLIT)
			{
				assert(m_expression.m_tokenQueue.size() > unsigned(m_expression.m_opMap[predOpPos + 3]));

				// Get the value of the number...
				const double	theIndex =
					m_expression.getNumberLiteral(m_expression.getOpCodeMapValue(predOpPos + 2));

				// If the index is out of range, or not an integer, just clear subQueryResults...
				if (theIndex <= 0.0 ||
					NodeRefListBase::size_type(theIndex) > theLength ||
					double(NodeRefListBase::size_type(theIndex)) != theIndex)
				{
					subQueryResults.clear();
				}
				else if (theLength > 1)
				{
					// Save the matching node...
					XalanNode* const	theNode =
						subQueryResults.item(NodeRefListBase::size_type(theIndex) - 1);

					// Clear the list...
					subQueryResults.clear();

					// Add the node back in...
					subQueryResults.addNode(theNode);

					subQueryResults.setDocumentOrder();
				}
				else
				{
					// OK, if there's only 1 node in the list, then
					// we don't need to bother modifying the list.
					// Just assert that theIndex == 1.0...
					assert(theIndex == 1.0);
				}
			}
			else
			{
				for(NodeRefListBase::size_type i = 0; i < theLength; ++i)
				{
					XalanNode* const	theNode = subQueryResults.item(i);
					assert(theNode != 0);

					const XObjectPtr		pred(predicate(theNode, opPos, executionContext));
					assert(pred.get() != 0);

					// Remove any node that doesn't satisfy the predicate.
					if((XObject::eTypeNumber == pred->getType() && i + 1 != pred->num()) ||
					   pred->boolean() == false)
					{
						// Set the node to 0.  After we're done,
						// we'll clear it out.
						subQueryResults.setNode(i, 0);
					}
				}

				// Clear out any null entries...
				subQueryResults.clearNulls();
			}
		}

		opPos = currentExpression.getNextOpCodePosition(opPos);

		const int	nextStepType = currentExpression.getOpCodeMapValue(opPos);

		if (nextStepType != XPathExpression::eOP_PREDICATE &&
		    nextStepType != XPathExpression::eOP_PREDICATE_WITH_POSITION)
		{
			break;
		}
		else
		{
			theLength = subQueryResults.getLength();
		}
	}

	return opPos;
}



XPath::NodeTester::NodeTester(
			const XPath&			xpath,
			XPathExecutionContext&	executionContext,
			int 					opPos,
			int 					argLen,
			int 					stepType) :
	m_executionContext(executionContext),
	m_targetNamespace(0),
	m_targetLocalName(0),
	m_testFunction(0)
{
	const XPathExpression&	theExpression = xpath.getExpression();

	switch(theExpression.getOpCodeMapValue(opPos))
	{
	case XPathExpression::eNODETYPE_COMMENT:
		m_testFunction = &NodeTester::testComment;
		break;

	case XPathExpression::eNODETYPE_TEXT:
		m_testFunction = &NodeTester::testText;
		break;

	case XPathExpression::eNODETYPE_PI:
		if (argLen == 1)
		{
			m_testFunction = &NodeTester::testPI;
		}
		else if(argLen == 2)
		{
			m_testFunction = &NodeTester::testPIName;

			m_targetLocalName = getStringFromTokenQueue(
				theExpression,
				opPos + 1);
		}
		else
		{

			executionContext.error(XalanMessageLoader::getMessage(XalanMessages::ArgLengthNodeTestIsIncorrect_1Param, "processing-instruction()"), 0, xpath.getLocator());
		}
		break;

	case XPathExpression::eNODETYPE_NODE:
		m_testFunction = &NodeTester::testNode;
		break;

	case XPathExpression::eNODETYPE_ROOT:
		m_testFunction = &NodeTester::testRoot;
		break;

	case XPathExpression::eNODENAME:
		{
			bool	isTotallyWild = false;

			m_targetNamespace = getStringFromTokenQueue(
					theExpression,
					opPos + 1);

			if (m_targetNamespace == 0 &&
				theExpression.getOpCodeMapValue(opPos + 2) == XPathExpression::eELEMWILDCARD)
			{
				isTotallyWild = true;
			}
			else
			{
				m_targetLocalName = getStringFromTokenQueue(
					theExpression,
					opPos + 2);
			}

			if(stepType == XPathExpression::eFROM_ATTRIBUTES)
			{
				if (isTotallyWild == true)
				{
					m_testFunction = &NodeTester::testAttributeTotallyWild;
				}
				else if (m_targetNamespace == 0)
				{
					assert(m_targetLocalName != 0);

					m_testFunction = &NodeTester::testAttributeNCName;
				}
				else if (m_targetLocalName == 0)
				{
					assert(m_targetNamespace != 0);

					m_testFunction = &NodeTester::testAttributeNamespaceOnly;
				}
				else
				{
					assert(m_targetNamespace != 0 && m_targetLocalName != 0);


					m_testFunction = &NodeTester::testAttributeQName;
				}
			}
			else if (stepType == XPathExpression::eFROM_NAMESPACE)
			{
				if (isTotallyWild == true)
				{
					m_testFunction = &NodeTester::testNamespaceTotallyWild;
				}
				else
				{
					m_testFunction = &NodeTester::testNamespaceNCName;
				}
			}
			else
			{
				if (isTotallyWild == true)
				{
					m_testFunction = &NodeTester::testElementTotallyWild;
				}
				else if (m_targetNamespace == 0)
				{
					m_testFunction = &NodeTester::testElementNCName;
				}
				else if (m_targetLocalName == 0)
				{
					assert(m_targetNamespace != 0);

					m_testFunction = &NodeTester::testElementNamespaceOnly;
				}
				else
				{
					assert(m_targetNamespace != 0 && m_targetLocalName != 0);

					m_testFunction = &NodeTester::testElementQName;
				}
			}
		}
		break;

	default:
		m_testFunction = &NodeTester::testDefault;
		break;
	}

	assert(m_testFunction != 0);
}



// MSVC generates some really horrible code for some of these very simple functions when they're inlined...
#if defined(_MSC_VER)
#pragma auto_inline(off)
#endif

XPath::eMatchScore
XPath::NodeTester::testComment(
			const XalanNode& 		/* context */,
			XalanNode::NodeType		nodeType) const
{
	if (XalanNode::COMMENT_NODE == nodeType)
	{
		return eMatchScoreNodeTest;
	}
	else
	{
		return eMatchScoreNone;
	}
}



XPath::eMatchScore
XPath::NodeTester::testText(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	if ((XalanNode::TEXT_NODE == nodeType || XalanNode::CDATA_SECTION_NODE == nodeType) &&
		 shouldStripSourceNode(context) == false)
	{
		return eMatchScoreNodeTest;
	}
	else
	{
		return eMatchScoreNone;
	}
}



XPath::eMatchScore
XPath::NodeTester::testPI(
			const XalanNode& 		/* context */,
			XalanNode::NodeType		nodeType) const
{
	if (XalanNode::PROCESSING_INSTRUCTION_NODE == nodeType)
	{
		return eMatchScoreNodeTest;
	}
	else
	{
		return eMatchScoreNone;
	}
}



XPath::eMatchScore
XPath::NodeTester::testPIName(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetLocalName != 0);

	if (XalanNode::PROCESSING_INSTRUCTION_NODE == nodeType &&
		context.getNodeName() == *m_targetLocalName)
	{
		return eMatchScoreQName;
	}
	else
	{
		return eMatchScoreNone;
	}
}



XPath::eMatchScore
XPath::NodeTester::testNode(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	if ((nodeType != XalanNode::TEXT_NODE && nodeType != XalanNode::CDATA_SECTION_NODE) ||
		shouldStripSourceNode(context) == false)
	{
		return eMatchScoreNodeTest;
	}
	else
	{
		return eMatchScoreNone;
	}
}



XPath::eMatchScore
XPath::NodeTester::testRoot(
			const XalanNode& 		/* context */,
			XalanNode::NodeType		nodeType) const
{
	if (XalanNode::DOCUMENT_NODE == nodeType ||
		XalanNode::DOCUMENT_FRAGMENT_NODE == nodeType)
	{
		return eMatchScoreOther;
	}
	else
	{
		return eMatchScoreNone;
	}
}



inline bool
isNamespaceDeclaration(const XalanNode&		theAttributeNode)
{
	assert(theAttributeNode.getNodeType() == XalanNode::ATTRIBUTE_NODE);

#if defined(XALAN_OLD_STYLE_CASTS)
	return DOMServices::isNamespaceDeclaration((const XalanAttr&)theAttributeNode);
#else
	return DOMServices::isNamespaceDeclaration(static_cast<const XalanAttr&>(theAttributeNode));
#endif
}



XPath::eMatchScore
XPath::NodeTester::testAttributeNCName(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace == 0 && m_targetLocalName != 0);

	if (XalanNode::ATTRIBUTE_NODE != nodeType ||
		isNamespaceDeclaration(context) == true ||
		matchLocalName(context) == false)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreQName;
	}
}



XPath::eMatchScore
XPath::NodeTester::testAttributeQName(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace != 0 && m_targetLocalName != 0);

	if (XalanNode::ATTRIBUTE_NODE != nodeType ||
		isNamespaceDeclaration(context) == true ||
		matchLocalNameAndNamespaceURI(context) == false)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreQName;
	}
}



XPath::eMatchScore
XPath::NodeTester::testAttributeNamespaceOnly(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace != 0 && m_targetLocalName == 0);

	if (XalanNode::ATTRIBUTE_NODE != nodeType ||
		isNamespaceDeclaration(context) == true ||
		matchNamespaceURI(context) == false)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreNSWild;
	}
}



XPath::eMatchScore
XPath::NodeTester::testAttributeTotallyWild(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	if (XalanNode::ATTRIBUTE_NODE != nodeType ||
		isNamespaceDeclaration(context) == true)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreNodeTest;
	}
}



XPath::eMatchScore
XPath::NodeTester::testElementNCName(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace == 0 && m_targetLocalName != 0);

	if (XalanNode::ELEMENT_NODE != nodeType ||
		matchLocalName(context) == false)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreQName;
	}
}



XPath::eMatchScore
XPath::NodeTester::testElementQName(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace != 0 && m_targetLocalName != 0);

	if (XalanNode::ELEMENT_NODE != nodeType ||
		matchLocalNameAndNamespaceURI(context) == false)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreQName;
	}
}



XPath::eMatchScore
XPath::NodeTester::testElementNamespaceOnly(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace != 0 && m_targetLocalName == 0);

	if (XalanNode::ELEMENT_NODE != nodeType ||
		matchNamespaceURI(context) == false)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreNSWild;
	}
}



XPath::eMatchScore
XPath::NodeTester::testElementTotallyWild(
			const XalanNode& 		/* context */,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace == 0 && m_targetLocalName == 0);

	if (XalanNode::ELEMENT_NODE != nodeType)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreNodeTest;
	}
}



XPath::eMatchScore
XPath::NodeTester::testNamespaceNCName(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace == 0 && m_targetLocalName != 0);

	if (XalanNode::ATTRIBUTE_NODE != nodeType ||
		isNamespaceDeclaration(context) == false ||
		matchNamespace(context) == false)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreQName;
	}
}



XPath::eMatchScore
XPath::NodeTester::testNamespaceTotallyWild(
			const XalanNode& 		context,
			XalanNode::NodeType		nodeType) const
{
	assert(m_targetNamespace == 0 && m_targetLocalName == 0);

	if (XalanNode::ATTRIBUTE_NODE != nodeType ||
		isNamespaceDeclaration(context) == false)
	{
		return eMatchScoreNone;
	}
	else
	{
		return eMatchScoreNodeTest;
	}
}



XPath::eMatchScore
XPath::NodeTester::testDefault(
			const XalanNode& 		/* context */,
			XalanNode::NodeType		/* nodeType */) const
{
	return eMatchScoreNone;
}



bool
XPath::NodeTester::matchLocalName(const XalanNode&	context) const
{
	assert(m_targetLocalName != 0);

	return length(context.getNamespaceURI()) == 0 &&
		DOMServices::getLocalNameOfNode(context) == *m_targetLocalName;
}



bool
XPath::NodeTester::matchNamespaceURI(const XalanNode&	context) const
{
	assert(m_targetNamespace != 0);

	return context.getNamespaceURI() == *m_targetNamespace;
}



bool
XPath::NodeTester::matchLocalNameAndNamespaceURI(const XalanNode&	context) const
{
	assert(m_targetNamespace != 0 && m_targetLocalName != 0);

	return DOMServices::getLocalNameOfNode(context) == *m_targetLocalName &&
		   context.getNamespaceURI() == *m_targetNamespace;
}



bool
XPath::NodeTester::matchNamespace(const XalanNode&	context) const
{
	assert(m_targetLocalName != 0);

	return context.getLocalName() == *m_targetLocalName;
}



bool
XPath::NodeTester::shouldStripSourceNode(const XalanNode&	context) const
{
	assert(context.getNodeType() == XalanNode::CDATA_SECTION_NODE ||
		   context.getNodeType() == XalanNode::TEXT_NODE);

	return m_executionContext.shouldStripSourceNode(context);
}



const XalanDOMChar	XPath::PSEUDONAME_ANY[] =
{
	XalanUnicode::charAsterisk,
	0
};

const XalanDOMChar	XPath::PSEUDONAME_ROOT[] =
{
	XalanUnicode::charSolidus,
	0
};

const XalanDOMChar	XPath::PSEUDONAME_TEXT[] =
{
	XalanUnicode::charNumberSign,
	XalanUnicode::charLetter_t,
	XalanUnicode::charLetter_e,
	XalanUnicode::charLetter_x,
	XalanUnicode::charLetter_t,
	0
};

const XalanDOMChar	XPath::PSEUDONAME_COMMENT[] =
{
	XalanUnicode::charNumberSign,
	XalanUnicode::charLetter_c,
	XalanUnicode::charLetter_o,
	XalanUnicode::charLetter_m,
	XalanUnicode::charLetter_m,
	XalanUnicode::charLetter_e,
	XalanUnicode::charLetter_n,
	XalanUnicode::charLetter_t,
	0
};

const XalanDOMChar	XPath::PSEUDONAME_PI[] =
{
	XalanUnicode::charNumberSign,
	XalanUnicode::charLetter_p,
	XalanUnicode::charLetter_i,
	0
};

const XalanDOMChar	XPath::PSEUDONAME_OTHER[] =
{
	XalanUnicode::charAsterisk,
	0
};

const XalanDOMChar	XPath::PSEUDONAME_NODE[] =
{
	XalanUnicode::charNumberSign,
	XalanUnicode::charLetter_n,
	XalanUnicode::charLetter_o,
	XalanUnicode::charLetter_d,
	XalanUnicode::charLetter_e,
	0
};



// Don't auto-create the table...
XPath::FunctionTableType		XPath::s_functions(false);



void
XPath::initialize()
{
	s_functions.CreateTable();
}



void
XPath::terminate()
{
	s_functions.DestroyTable();
}



XALAN_CPP_NAMESPACE_END
