blob: e34ee0a4dfdee394068e308e7a1810c6aef96c8f [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999-2002 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/>.
*/
#if !defined(XPATHEXPRESSION_HEADER_GUARD_1357924680)
#define XPATHEXPRESSION_HEADER_GUARD_1357924680
// Base header file. Must be first.
#include <XPath/XPathDefinitions.hpp>
#include <vector>
#if defined(XALAN_OLD_STREAMS)
#include <iostream.h>
#else
#include <iosfwd>
#endif
#include <XalanDOM/XalanDOMString.hpp>
#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/PrintWriter.hpp>
#include <XPath/XToken.hpp>
#include <XPath/XalanXPathException.hpp>
class XALAN_XPATH_EXPORT XPathExpression
{
public:
/**
* List of operations codes.
*
* Code for the descriptions of the operations codes:
* [UPPER CASE] indicates a literal value,
* [lower case] is a description of a value,
* ([length] always indicates the length of the operation,
* including the operations code and the length integer.)
* {UPPER CASE} indicates the given production,
* {description} is the description of a new production,
* (For instance, {boolean expression} means some expression
* that should be resolved to a boolean.)
* * means that it occurs zero or more times,
* + means that it occurs one or more times,
* ? means that it is optional.
*
* returns: indicates what the production should return.
*/
enum eOpCodes
{
/**
* [ELEMWILDCARD]
* Means ELEMWILDCARD ("*"), used instead
* of string index in some places.
*/
eELEMWILDCARD = -3,
/**
* [EMPTY]
* Empty slot to indicate NULL.
*/
eEMPTY = -2,
/**
* [ENDOP]
* Some operators may like to have a terminator.
*/
eENDOP = -1,
/**
* [OP_XPATH]
* [length]
* {expression}
*
* returns:
* XNodeSet
* XNumber
* XString
* XBoolean
* XRTree
* XObject
*/
eOP_XPATH = 1,
/**
* [OP_OR]
* [length]
* {boolean expression}
* {boolean expression}
*
* returns:
* XBoolean
*/
eOP_OR = 2,
/**
* [OP_AND]
* [length]
* {boolean expression}
* {boolean expression}
*
* returns:
* XBoolean
*/
eOP_AND = 3,
/**
* [OP_NOTEQUALS]
* [length]
* {expression}
* {expression}
*
* returns:
* XBoolean
*/
eOP_NOTEQUALS = 4,
/**
* [OP_EQUALS]
* [length]
* {expression}
* {expression}
*
* returns:
* XBoolean
*/
eOP_EQUALS = 5,
/**
* [OP_LTE] (less-than-or-equals)
* [length]
* {number expression}
* {number expression}
*
* returns:
* XBoolean
*/
eOP_LTE = 6,
/**
* [OP_LT] (less-than)
* [length]
* {number expression}
* {number expression}
*
* returns:
* XBoolean
*/
eOP_LT = 7,
/**
* [OP_GTE] (greater-than-or-equals)
* [length]
* {number expression}
* {number expression}
*
* returns:
* XBoolean
*/
eOP_GTE = 8,
/**
* [OP_GT] (greater-than)
* [length]
* {number expression}
* {number expression}
*
* returns:
* XBoolean
*/
eOP_GT = 9,
/**
* [OP_PLUS]
* [length]
* {number expression}
* {number expression}
*
* returns:
* XNumber
*/
eOP_PLUS = 10,
/**
* [OP_MINUS]
* [length]
* {number expression}
* {number expression}
*
* returns:
* XNumber
*/
eOP_MINUS = 11,
/**
* [OP_MULT]
* [length]
* {number expression}
* {number expression}
*
* returns:
* XNumber
*/
eOP_MULT = 12,
/**
* [OP_DIV]
* [length]
* {number expression}
* {number expression}
*
* returns:
* XNumber
*/
eOP_DIV = 13,
/**
* [OP_MOD]
* [length]
* {number expression}
* {number expression}
*
* returns:
* XNumber
*/
eOP_MOD = 14,
/**
* [OP_NEG]
* [length]
* {number expression}
*
* returns:
* XNumber
*/
eOP_NEG = 15,
/**
* [OP_BOOL] (cast operation)
* [length]
* {expression}
*
* returns:
* XBoolean
*/
eOP_BOOL = 16,
/**
* [OP_UNION]
* [length]
* {PathExpr}+
*
* returns:
* XNodeSet
*/
eOP_UNION = 17,
/**
* [OP_LITERAL]
* [3]
* [index to token]
*
* returns:
* XString
*/
eOP_LITERAL = 18,
/**
* [OP_VARIABLE]
* [3]
* [index to token]
*
* returns:
* XString
*/
eOP_VARIABLE = 19,
/**
* [OP_GROUP]
* [length]
* {expression}
*
* returns:
* XNodeSet
* XNumber
* XString
* XBoolean
* XRTree
* XObject
*/
eOP_GROUP = 20,
/**
* [OP_NUMBERLIT] (Number literal.)
* [3]
* [index to token]
*
* returns:
* XString
*/
eOP_NUMBERLIT = 21,
/**
* [OP_ARGUMENT] (Function argument.)
* [length]
* {expression}
*
* returns:
* XNodeSet
* XNumber
* XString
* XBoolean
* XRTree
* XObject
*/
eOP_ARGUMENT = 22,
/**
* [OP_EXTFUNCTION] (Extension function.)
* [length]
* [index to namespace token]
* [index to function name token]
* {OP_ARGUMENT}*
*
* returns:
* XNodeSet
* XNumber
* XString
* XBoolean
* XRTree
* XObject
*/
eOP_EXTFUNCTION = 23,
/**
* [OP_FUNCTION]
* [length]
* [FUNC_name]
* {OP_ARGUMENT}*
* [ENDOP]
*
* returns:
* XNodeSet
* XNumber
* XString
* XBoolean
* XRTree
* XObject
*/
eOP_FUNCTION = 24,
/**
* [OP_LOCATIONPATH]
* [length]
* {FROM_stepType}
* | {function}{predicate}*
* [ENDOP]
*
* (Note that element and attribute namespaces and
* names can be wildcarded '*'.)
*
* returns:
* XNodeSet
*/
eOP_LOCATIONPATH = 25,
/**
* [OP_PREDICATE]
* [length]
* {expression}
* [ENDOP] (For safety)
*
* returns:
* XBoolean or XNumber
*/
eOP_PREDICATE = 26,
/**
* [NODETYPE_COMMENT]
* No size or arguments.
*
* returns:
* XBoolean
*/
eNODETYPE_COMMENT = 27,
/**
* [NODETYPE_TEXT]
* No size or arguments.
*
* returns:
* XBoolean
*/
eNODETYPE_TEXT = 28,
/**
* [NODETYPE_PI]
* [index to token]
*
* returns:
* XBoolean
*/
eNODETYPE_PI = 29,
/**
* [NODETYPE_NODE]
* No size or arguments.
*
* returns:
* XBoolean
*/
eNODETYPE_NODE = 30,
/**
* [NODENAME]
* [index to ns token or EMPTY]
* [index to name token]
*
* returns:
* XBoolean
*/
eNODENAME = 31,
/**
* [NODETYPE_ROOT]
* No size or arguments.
*
* returns:
* XBoolean
*/
eNODETYPE_ROOT = 32,
/**
* [NODETYPE_ANY]
* No size or arguments.
*
* returns:
* XBoolean
*/
eNODETYPE_ANYELEMENT = 33,
/**
* [FROM_stepType]
* [length, including predicates]
* [length of just the step, without the predicates]
* {node test}
* {predicates}?
*
* returns:
* XBoolean
*/
eFROM_ANCESTORS = 34,
eFROM_ANCESTORS_OR_SELF = 35,
eFROM_ATTRIBUTES = 36,
eFROM_CHILDREN = 37,
eFROM_DESCENDANTS = 38,
eFROM_DESCENDANTS_OR_SELF = 39,
eFROM_FOLLOWING = 40,
eFROM_FOLLOWING_SIBLINGS = 41,
eFROM_PARENT = 42,
eFROM_PRECEDING = 43,
eFROM_PRECEDING_SIBLINGS = 44,
eFROM_SELF = 45,
eFROM_NAMESPACE = 46,
eFROM_ROOT = 47,
/**
* [OP_UNION]
* [length]
* {PathExpr}+
*
* returns:
* XNodeSet
*/
eOP_MATCHPATTERN = 48,
/**
* [OP_UNION]
* [length]
* {PathExpr}+
*
* returns:
* XNodeSet
*/
eOP_LOCATIONPATHPATTERN = 49,
// For match patterns
eMATCH_ATTRIBUTE = 50,
eMATCH_ANY_ANCESTOR = 51,
eMATCH_IMMEDIATE_ANCESTOR = 52,
eMATCH_ANY_ANCESTOR_WITH_PREDICATE = 53,
eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL = 54,
/**
* [OP_PREDICATE_WITH_POSITION]
* [length]
* {expression}
* [ENDOP] (For safety)
*
* returns:
* XBoolean or XNumber
*/
eOP_PREDICATE_WITH_POSITION = 55,
// Always add _before_ this one and update
// s_opCodeLengthArray.
eOpCodeNextAvailable
}; // enum eOpCodes
/**
* Exception class thrown when an invalid XPath expression is encountered
*/
class XALAN_XPATH_EXPORT XPathExpressionException : public XalanXPathException
{
public:
/**
* Construct an XPathExpressionException object.
*
* @param theMessage string error message
*/
XPathExpressionException(const XalanDOMString& theMessage);
virtual~
XPathExpressionException();
};
/**
* Exception class thrown when an invalid XPath operation code is encountered
*/
class XALAN_XPATH_EXPORT InvalidOpCodeException : public XPathExpressionException
{
public:
/**
* Construct an InvalidOpCodeException object.
*
* @param theOpCode operation code that caused the exception
*/
InvalidOpCodeException(int theOpCode);
virtual~
InvalidOpCodeException();
private:
static XalanDOMString
FormatErrorMessage(int theOpCode);
};
/**
* Exception class thrown when an invalid number of XPath arguments is
* encountered
*/
class XALAN_XPATH_EXPORT InvalidArgumentCountException : public XPathExpressionException
{
public:
/**
* Construct an InvalidArgumentCountException object.
*
* @param theOpCode operation code that caused the exception
* @param theExpectedCount the correct number of arguments for "opcode"
* @param theSuppliedCount the number of arguments supplied
*/
InvalidArgumentCountException(
int theOpCode,
int theExpectedCount,
int theSuppliedCount);
virtual~
InvalidArgumentCountException();
private:
static XalanDOMString
FormatErrorMessage(
int theOpCode,
int theExpectedCount,
int theSuppliedCount);
};
/**
* Exception class thrown when an invalid XPath argument is encountered
*/
class XALAN_XPATH_EXPORT InvalidArgumentException : public XPathExpressionException
{
public:
/**
* Construct an InvalidArgumentException object.
*
* @param theOpCode operation code that caused the exception
* @param theValue invalid argument value
*/
InvalidArgumentException(
int theOpCode,
int theValue);
virtual~
InvalidArgumentException();
private:
static XalanDOMString
FormatErrorMessage(
int theOpCode,
int theValue);
};
/**
* Exception class thrown when an invalid token position is encountered
*/
class XALAN_XPATH_EXPORT InvalidRelativeTokenPosition : public XPathExpressionException
{
public:
/**
* Construct an InvalidRelativeTokenPosition object.
*
* @param theOffset the offset that caused the problem.
*/
InvalidRelativeTokenPosition(int theOffset);
virtual~
InvalidRelativeTokenPosition();
private:
static XalanDOMString
FormatErrorMessage(int theOffset);
};
#if defined(XALAN_NO_NAMESPACES)
typedef vector<int> OpCodeMapType;
typedef vector<XToken> TokenQueueType;
typedef vector<int> PatternMapType;
typedef OpCodeMapType::value_type OpCodeMapValueType;
typedef OpCodeMapType::size_type OpCodeMapSizeType;
typedef vector<OpCodeMapValueType> OpCodeMapValueVectorType;
typedef vector<double> NumberLiteralValueVectorType;
#else
typedef std::vector<int> OpCodeMapType;
typedef std::vector<XToken> TokenQueueType;
typedef std::vector<int> PatternMapType;
typedef OpCodeMapType::value_type OpCodeMapValueType;
typedef OpCodeMapType::size_type OpCodeMapSizeType;
typedef std::vector<OpCodeMapValueType> OpCodeMapValueVectorType;
typedef std::vector<double> NumberLiteralValueVectorType;
#endif
typedef TokenQueueType::value_type TokenQueueValueType;
typedef TokenQueueType::size_type TokenQueueSizeType;
typedef PatternMapType::value_type PatternMapValueType;
typedef PatternMapType::size_type PatternMapSizeType;
/**
* The length is always the opcode position + 1. Length is always expressed
* as the opcode+length bytes, so it is always 2 or greater. This is the
* offset from the op code where the length is stored. It will always
* remain one.
*/
#if defined(XALAN_INLINE_INITIALIZATION)
static const TokenQueueSizeType s_opCodeMapLengthIndex = 1;
#else
enum eDummy
{
s_opCodeMapLengthIndex = 1
};
#endif
explicit
XPathExpression();
~XPathExpression();
/**
* Reset the expression.
*/
void
reset();
/**
* Shrink internal tables.
*/
void
shrink();
/**
* Retrieve number of elements in the operations code map.
*
* @return size of operations code map
*/
OpCodeMapSizeType
opCodeMapSize() const
{
return m_opMap.size();
}
/**
* Retrieve length of the operations code map stored in the map. The length
* of the entire map is stored after the first op code. That offset is
* determined by this const static member. Note that as expressions are
* defined recursively, this is really just the length of the first
* expression in the map, which is the top of the parse tree. Any
* subexpression will also have a length entry at the same offset from the
* beginning of the subexpression.
*
* @return length of operations code map
*/
OpCodeMapValueType
opCodeMapLength() const
{
const OpCodeMapSizeType theSize = opCodeMapSize();
if (theSize > s_opCodeMapLengthIndex)
{
assert(theSize == OpCodeMapSizeType(m_opMap[s_opCodeMapLengthIndex]));
return m_opMap[s_opCodeMapLengthIndex];
}
else
{
assert(theSize == OpCodeMapValueType(theSize));
return OpCodeMapValueType(theSize);
}
}
/**
* Retrieve number of elements in the token queue.
*
* @return size of token queue
*/
TokenQueueSizeType
tokenQueueSize() const
{
return m_tokenQueue.size();
}
/**
* Retrieve number of elements in the pattern map.
*
* @return size of pattern map
*/
PatternMapSizeType
patternMapSize() const
{
return m_patternMap.size();
}
/**
* Retrieve the value of an operation code at a specified position in the
* list.
*
* @param opPos position in list
* @return value of operation code
*/
OpCodeMapValueType
getOpCodeMapValue(OpCodeMapSizeType opPos) const
{
return m_opMap[opPos];
}
OpCodeMapValueType
getOpCodeArgumentLength(OpCodeMapSizeType opPos) const
{
return getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3;
}
/**
* Retrieve the length of an operation code at a specified position in the
* op map.
*
* @param opPos position in the op map
* @return length of operation code
*/
OpCodeMapValueType
getOpCodeLengthFromOpMap(OpCodeMapSizeType opPos) const;
/**
* Retrieve the position of the next operation code at a specified position
* in the list.
*
* @param opPos position in list
* @return position of next operation code
*/
OpCodeMapValueType
getNextOpCodePosition(OpCodeMapSizeType opPos) const
{
assert(opPos < opCodeMapSize());
assert(opPos + m_opMap[opPos + s_opCodeMapLengthIndex] == OpCodeMapValueType(opPos + m_opMap[opPos + s_opCodeMapLengthIndex]));
return OpCodeMapValueType(opPos + m_opMap[opPos + s_opCodeMapLengthIndex]);
}
/**
* Set the arguments for an operation code at a specified index in the
* list.
*
* @param opPos position in list
* @param theOpCode operation code
* @param theIndex index in list
* @param theArgs vector or arguments to supply
*/
void
setOpCodeArgs(
eOpCodes theOpCode,
OpCodeMapSizeType theIndex,
const OpCodeMapValueVectorType& theArgs);
/**
* Add an operation code to the list.
*
* @param theOpCode operation code
*/
void
appendOpCode(eOpCodes theOpCode);
/**
* Add an operation code with supplied arguments to the list.
*
* @param theOpCode operation code
* @param theArgs vector or arguments to supply
*/
void
appendOpCode(eOpCodes theOpCode,
const OpCodeMapValueVectorType& theArgs)
{
appendOpCode(theOpCode);
setOpCodeArgs(theOpCode,
m_lastOpCodeIndex,
theArgs);
}
/**
* Replace an operation code with supplied code.
*
* @param theIndex The index of the old operation code
* @param theOldOpCode The old operation code
* @param theNewOpCode The new operation code
*/
void
replaceOpCode(
OpCodeMapSizeType theIndex,
eOpCodes theOldOpCode,
eOpCodes theNewOpCode);
/**
* Insert an operation code at a specified index in the list.
*
* @param theOpCode operation code
* @param theIndex index in list
*/
OpCodeMapValueType
insertOpCode(
eOpCodes theOpCode,
OpCodeMapSizeType theIndex);
/**
* Update the length of an operation code at a specified index in the list.
* This presumes that the other opcodes have been appended to the
* expression, and that the specified op code's length needs to be set.
* The size includes the normal length of the opcode, plus the length of
* its subexpressions.
*
* @param theIndex index in list
*/
void
updateOpCodeLength(OpCodeMapSizeType theIndex)
{
assert(theIndex < opCodeMapSize());
updateOpCodeLength(m_opMap[theIndex], theIndex);
}
/**
* Update the length of an operation code that has moved to a new index in
* the list.
*
* @param theOpCode operation code
* @param theOriginalIndex original index in list
* @param theNewIndex new index in list
*/
void
updateShiftedOpCodeLength(
OpCodeMapValueType theOpCode,
OpCodeMapSizeType theOriginalIndex,
OpCodeMapSizeType theNewIndex);
/**
* Update the length of an operation code at a specified index in the list.
* This presumes that the other opcodes have been appended to the
* expression, and that the specified op code's length needs to be set.
* The size includes the normal length of the opcode, plus the length of
* its subexpressions.
*
* @param theOpCode operation code at specified index
* @param theIndex index in list
*/
void
updateOpCodeLength(
OpCodeMapValueType theOpCode,
OpCodeMapSizeType theIndex);
/**
* Whether the operation code is one of the node test types, for example,
* "ancestor::" or "child::"
*
* @param theOpCode operation code
* @return true if code represents a node test
*/
static bool
isNodeTestOpCode(OpCodeMapValueType theOpCode);
/**
* Update the length of an operation code after a node test code.
*
* @param theIndex index in list
*/
void
updateOpCodeLengthAfterNodeTest(OpCodeMapSizeType theIndex);
/**
* Whether there are any more tokens in the token queue.
*
* @return true if there are more tokens
*/
bool
hasMoreTokens() const
{
return tokenQueueSize() - m_currentPosition > 0 ? true : false;
}
/**
* Retrieve the current position in the token queue.
*
* @return position in queue
*/
TokenQueueSizeType
getTokenPosition() const
{
return m_currentPosition;
}
/**
* Set the current position in the token queue to zero.
*/
void
resetTokenPosition()
{
m_currentPosition = 0;
}
/**
* Set the current position in the token queue to a specified value.
*
* @param thePosition value of position to set
*/
void
setTokenPosition(TokenQueueSizeType thePosition)
{
const TokenQueueSizeType theSize = tokenQueueSize();
m_currentPosition = thePosition > theSize ? theSize : thePosition;
}
/**
* Set the current position in the token queue to a specified value.
*
* @param thePosition value of position to set
*/
void
setTokenPosition(int thePosition)
{
setTokenPosition(thePosition > 0 ? TokenQueueSizeType(thePosition) : 0);
}
/**
* Retrieve a token at the specified position in the token queue.
*
* @param thePosition position in queue
* @return pointer to XObject token
*/
const XObject*
getToken(TokenQueueSizeType thePosition) const
{
assert(thePosition < tokenQueueSize());
return &m_tokenQueue[thePosition];
}
/**
* Retrieve the next token in the token queue.
*
* @return pointer to XObject token
*/
const XObject*
getNextToken()
{
if (hasMoreTokens() == true)
{
return getToken(m_currentPosition++);
}
else
{
return 0;
}
}
/**
* Retrieve the previous token in the token queue.
*
* @return pointer to XObject token
*/
const XObject*
getPreviousToken()
{
if (m_currentPosition > 0)
{
return getToken(--m_currentPosition);
}
else
{
return 0;
}
}
/**
* Retrieve a token at the specified offset relative to the current
* position in the token queue.
*
* @param theOffset offset from current position
* @return pointer to XObject token
*/
const XObject*
getRelativeToken(int theOffset) const
{
const int thePosition = int(m_currentPosition) + theOffset;
if (thePosition < 0 ||
thePosition >= int(tokenQueueSize()))
{
return 0;
}
else
{
return getToken(thePosition);
}
}
/**
* Push a token onto the token queue.
*
* @param theToken the string value to push
*/
void
pushToken(const XalanDOMString& theToken)
{
m_tokenQueue.push_back(XToken(theToken));
}
/**
* Push a token onto the token queue.
*
* @param theToken the number value to push
*/
void
pushToken(double theToken)
{
m_tokenQueue.push_back(XToken(theToken));
}
/**
* Insert a token onto the token queue at the
* current position.
*
* @param theToken the string value to push
*/
void
insertToken(const XalanDOMString& theToken)
{
m_tokenQueue.insert(m_tokenQueue.begin() + (m_currentPosition - 1), XToken(theToken));
}
/**
* Insert a token onto the token queue at the
* current position.
*
* @param theToken the string value to push
*/
void
insertToken(double theToken)
{
m_tokenQueue.insert(m_tokenQueue.begin() + (m_currentPosition - 1), XToken(theToken));
}
/**
* Replace a token in the token queue.
*
* @param theOffset the offset at which to replace the token.
* @param theToken string value for the new token
*/
void
replaceRelativeToken(
int theOffset,
const XalanDOMString& theToken)
{
assert(c_wstr(theToken) != 0);
const int thePosition = int(m_currentPosition) + theOffset;
if (thePosition < 0 ||
thePosition >= int(tokenQueueSize()))
{
throw InvalidRelativeTokenPosition(theOffset);
}
m_tokenQueue[thePosition] = theToken;
}
/**
* Replace a token in the token queue.
*
* @param theOffset the offset at which to replace the token.
* @param theToken double value for the new token
*/
void
replaceRelativeToken(
int theOffset,
double theToken)
{
assert(theToken != 0);
const int thePosition = int(m_currentPosition) + theOffset;
if (thePosition < 0 || thePosition >= int(tokenQueueSize()))
{
throw InvalidRelativeTokenPosition(theOffset);
}
m_tokenQueue[thePosition] = theToken;
}
/**
* Diagnostic function to output the operation code map.
*
* @param thePrintWriter output device
* @param theStartPosition starting position in map
*/
void
dumpOpCodeMap(PrintWriter& thePrintWriter,
OpCodeMapSizeType theStartPosition = 0) const;
/**
* Diagnostic function to output the operation code map.
*
* @param theStream output stream
* @param theStartPosition starting position in map
*/
void
dumpOpCodeMap(
#if defined(XALAN_NO_NAMESPACES)
ostream& theStream,
#else
std::ostream& theStream,
#endif
OpCodeMapSizeType theStartPosition = 0) const;
/**
* Diagnostic function to output the token queue.
*
* @param thePrintWriter output device
* @param theStartPosition starting position in token queue
*/
void
dumpTokenQueue(PrintWriter& thePrintWriter,
TokenQueueSizeType theStartPosition = 0) const;
/**
* Diagnostic function to output the token queue.
*
* @param thePrintWriter output device
* @param theStartPosition starting position in token queue
*/
void
dumpTokenQueue(
#if defined(XALAN_NO_NAMESPACES)
ostream& theStream,
#else
std::ostream& theStream,
#endif
TokenQueueSizeType theStartPosition = 0) const;
/**
* Diagnostic function to output the remaining tokens in the token queue.
*
* @param thePrintWriter output device
*/
void
dumpRemainingTokenQueue(PrintWriter& thePrintWriter) const;
/**
* Diagnostic function to output the remaining tokens in the token queue.
*
* @param theStream The output stream
*/
void
#if defined(XALAN_NO_NAMESPACES)
dumpRemainingTokenQueue(ostream& theStream) const;
#else
dumpRemainingTokenQueue(std::ostream& theStream) const;
#endif
/**
* Push a value onto the operations code
* map.
*
* @param theToken string value of the token to push
*/
void
pushValueOnOpCodeMap(const OpCodeMapType::value_type& theValue)
{
// Push the index onto the op map.
m_opMap.push_back(theValue);
// Update the op map length.
m_opMap[s_opCodeMapLengthIndex]++;
}
/**
* Push a token onto the token queue and its index onto the operations code
* map.
*
* @param theToken string value of the token to push
*/
void
pushArgumentOnOpCodeMap(const XalanDOMString& theToken);
/**
* Push a token onto the token queue and its index onto the operations code
* map.
*
* @param theToken number value of the token to push
*/
void
pushArgumentOnOpCodeMap(double theToken);
/**
* Push a number literal onto the vector of number literals and its index onto
* the operations code map.
*
* @param theToken number value of the token to push
*/
void
pushNumberLiteralOnOpCodeMap(double theNumber);
/**
* Get a number literal from the vector of number literals.
*
* @param theIndex The index of the desired value.
*/
double
getNumberLiteral(int theIndex) const
{
assert(theIndex >= 0 &&
NumberLiteralValueVectorType::size_type(theIndex) < m_numberLiteralValues.size());
return m_numberLiteralValues[NumberLiteralValueVectorType::size_type(theIndex)];
}
/**
* Push the current position in the token queue onto the operations code
* map.
*/
void
pushCurrentTokenOnOpCodeMap();
/**
* Retrieve a pattern in the pattern map at the specified position.
* position in the token queue.
*
* @param thePatternPosition position in pattern map
* @return match pattern
*/
PatternMapValueType
getPattern(int thePatternPosition) const
{
assert(int(patternMapSize()) > thePatternPosition);
return m_patternMap[thePatternPosition];
}
/**
* Retrieve a pattern in the pattern map at the specified position.
* position in the token queue.
*
* @param thePatternPosition position in pattern map
* @return match pattern
*/
PatternMapValueType
getPattern(PatternMapSizeType thePatternPosition) const
{
assert(patternMapSize() > thePatternPosition);
return m_patternMap[thePatternPosition];
}
/**
* Push a pattern onto the pattern map.
*
* @param thePattern match pattern to push
*/
void
pushPattern(PatternMapValueType thePattern)
{
m_patternMap.push_back(thePattern);
}
/**
* Adjust the value of a pattern at a specified index in the pattern map.
*
* @param theIndex index in map
* @param theAdjustment value of adjustment to add
*/
void
adjustPattern(
OpCodeMapSizeType theIndex,
PatternMapValueType theAdjustment)
{
m_patternMap[theIndex] += theAdjustment;
}
/**
* Change the current pattern in the pattern map.
*
* @param thePattern match pattern to make current
*/
void
setCurrentPattern(const XalanDOMString& thePattern)
{
m_currentPattern = thePattern;
}
/**
* Retrieve the current pattern in the pattern map.
*
* @return string for current match pattern
*/
const XalanDOMString&
getCurrentPattern() const
{
return m_currentPattern;
}
/**
* An operations map is used instead of a proper parse tree. It contains
* operations codes and indexes into the m_tokenQueue. We use an array
* instead of a full parse tree in order to cut down on the number of
* objects created.
*/
OpCodeMapType m_opMap;
/**
* The index of the last opcode that was appended or inserted.
*
*/
OpCodeMapSizeType m_lastOpCodeIndex;
/**
* The queue of used tokens. The current token is the token at the end of
* the m_tokenQueue. The idea is that the queue can be marked and a
* sequence of tokens can be reused.
*/
TokenQueueType m_tokenQueue;
/**
* The current position in the token queue.
*/
TokenQueueSizeType m_currentPosition;
/**
* This holds a map to the m_tokenQueue that tells where the top-level
* elements are. It is used for pattern matching so the m_tokenQueue can be
* walked backwards. Each element that is a 'target', (right-most top level
* element name) has TARGETEXTRA added to it.
*
*/
// Ignore this, it is going away.
PatternMapType m_patternMap;
/**
* The current pattern string, for diagnostics purposes.
*/
XalanDOMString m_currentPattern;
private:
// Default vector allocation sizes.
enum
{
eDefaultOpMapSize = 100,
eDefaultPatternMapSize = 100
};
NumberLiteralValueVectorType m_numberLiteralValues;
};
#endif // XPATHEXPRESSION_HEADER_GUARD_1357924680