/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if !defined(XALAN_VARIABLESSTACK_HEADER_GUARD) #define XALAN_VARIABLESSTACK_HEADER_GUARD // Base include file. Must be first. #include #include #include #include #include #include namespace XALAN_CPP_NAMESPACE { class Arg; class ElemTemplateElement; class ElemVariable; class StylesheetExecutionContext; class XalanNode; /** * Defines a class to keep track of a stack for macro arguments. */ class XALAN_XSLT_EXPORT VariablesStack { public: typedef unsigned long size_type; /** * Constructor for a variable stack. */ explicit VariablesStack(MemoryManager& theManager); ~VariablesStack(); /** * Reset the stack. */ void reset(); /** * Push a frame marker for an element. * * @param elem the element */ void pushElementFrame(const ElemTemplateElement* elem); /** * Pop a frame marker for an element. * * @param elem the element */ void popElementFrame(); /** * Push a context marker onto the stack to let us know when to stop * searching for a var. * * @param caller caller node * @param sourceNode source node */ void pushContextMarker(); /** * Pop the current context from the current context stack. */ void popContextMarker(); struct ParamsVectorEntry { ParamsVectorEntry() : m_qname(0), m_value(), m_variable(0) { } ParamsVectorEntry( const XalanQName* qname, const XObjectPtr value) : m_qname(qname), m_value(value), m_variable(0) { } ParamsVectorEntry( const XalanQName* qname, const ElemVariable* variable) : m_qname(qname), m_value(), m_variable(variable) { } const XalanQName* m_qname; XObjectPtr m_value; const ElemVariable* m_variable; }; typedef XalanVector ParamsVectorType; typedef XalanVector RecursionGuardStackType; typedef XalanVector ElemTemplateElementStackType; /** * Push the provided objects as parameters. You must call * popContextMarker() when you are done with the arguments. * * @param theParam The vector containing the parameters. */ void pushParams(const ParamsVectorType& theParams); /** * Given a name, return a string representing the value, but don't look * in the global space. Since the variable may not yet have been * evaluated, this may return a null XObjectPtr. * * @param theName name of variable * @param exeuctionContext the current execution context * @param fNameFound set to true if the name was found, false if not. * @return pointer to XObject for variable */ const XObjectPtr getParamVariable( const XalanQName& qname, StylesheetExecutionContext& executionContext, bool& fNameFound) { return findXObject(qname, executionContext, true, false, fNameFound); } /** * Given a name, find the corresponding XObject. If the variable * exists, but has not yet been evaluated, the variable will be * evaluated and the result returned. This may return a null XObjectPtr, * if the variable was not found. * * @param qname name of variable * @param exeuctionContext the current execution context * @param fNameFound set to true if the name was found, false if not. * @return pointer to the corresponding XObject */ const XObjectPtr getVariable( const XalanQName& qname, StylesheetExecutionContext& executionContext, bool& fNameFound) { return findXObject(qname, executionContext, false, true, fNameFound); } /** * Push a named variable onto the processor variable stack. Don't forget * to call startContext before pushing a series of arguments for a given * template. * * @param name name of variable * @param val pointer to ElemVariable * @param e element marker for variable */ void pushVariable( const XalanQName& name, const ElemVariable* var, const ElemTemplateElement* e); /** * Push a named variable onto the processor variable stack. Don't forget * to call startContext before pushing a series of arguments for a given * template. * * @param name name of variable * @param val pointer to XObject value * @param e element marker for variable */ void pushVariable( const XalanQName& name, const XObjectPtr& val, const ElemTemplateElement* e); /** * Mark the top of the stack. */ void start(); /** * Reset all params in the current stack frame. */ void resetParams(); /** * Mark the top of the global stack frame. */ void markGlobalStackFrame(); /** * Clear the marking of the global stack frame. */ void unmarkGlobalStackFrame(); /** * Set the top of the stack frame from where a search for a variable or * param should take place. Calling with no parameter will cause the * index to be set to the size of the stack. * * @param currentStackFrameIndex new value of index */ void setCurrentStackFrameIndex(size_type currentStackFrameIndex = ~0u) { if (currentStackFrameIndex == ~0u) { assert(size_type(m_stack.size()) == m_stack.size()); m_currentStackFrameIndex = size_type(m_stack.size()); } else { m_currentStackFrameIndex = currentStackFrameIndex; } } /** * Get the top of the stack frame from where a search * for a variable or param should take place. * * @return current value of index */ size_type getCurrentStackFrameIndex() const { return m_currentStackFrameIndex; } /** * Get the top of the global stack frame. * * @return current value of index */ size_type getGlobalStackFrameIndex() const { return m_globalStackFrameIndex; } class InvalidStackContextException : public XSLTProcessorException { public: InvalidStackContextException(XalanDOMString& theResult); virtual ~InvalidStackContextException(); virtual const XalanDOMChar* getType() const { return m_type; } private: static const XalanDOMChar m_type[]; }; class PushParamFunctor { public: PushParamFunctor(VariablesStack& theVariablesStack) : m_variablesStack(theVariablesStack) { } void operator()(const ParamsVectorType::value_type& theEntry) const; private: VariablesStack& m_variablesStack; }; class XALAN_XSLT_EXPORT StackEntry { public: /** * Enumeration for types of stack entries, one of context state, context * marker, element marker, or argument. */ enum eType { eContextMarker, eVariable, eParam, eActiveParam, eElementFrameMarker, eNextValue }; /** * Construct a context marker. */ explicit StackEntry(); /** * Construct a variable that is already evaluated. */ StackEntry( const XalanQName* name, const XObjectPtr& val, bool isParam = false); /** * Construct a variable that has not been evaluated yet. */ StackEntry( const XalanQName* name, const ElemVariable* var, bool isParam = false); /** * Construct an element frame marker. */ StackEntry(const ElemTemplateElement* elem); /** * Copy constructor... */ StackEntry(const StackEntry& theSource); /** * Destructor... */ ~StackEntry(); /** * Determine type of stack entry * * @return enumeration value for type */ eType getType() const { return m_type; } /** * Retrieve object name. Valid only for variables * * @return qualified name of object */ const XalanQName* getName() const { return m_qname; } /** * Retrieve object's XObject pointer. Valid only for variables * * @return pointer to XObject */ const XObjectPtr& getValue() const { return m_value; } /** * Retrieve object's XObject pointer. Valid only for variables * * @return pointer to XObject */ void setValue(const XObjectPtr& theValue) { m_value = theValue; } /** * Retrieve object's XObject pointer. Valid only for variables * * @return pointer to XObject */ const ElemVariable* getVariable() const { return m_variable; } void activate(); void deactivate(); /** * Retrieve the ElemTemplateElem where frame begins. Valid only for element frame markers * * @return ElemTemplateElement corresponding to marker */ const ElemTemplateElement* getElement() const { return m_element; } StackEntry& operator=(const StackEntry& theRHS); bool operator==(const StackEntry& theRHS) const; private: // Data members... eType m_type; const XalanQName* m_qname; XObjectPtr m_value; const ElemVariable* m_variable; const ElemTemplateElement* m_element; }; typedef XalanVector VariableStackStackType; size_type getStackSize() const { return size_type(m_stack.size()); } enum { eDefaultStackSize = 100 }; private: class CommitPushParams { public: CommitPushParams(VariablesStack& theVariablesStack); ~CommitPushParams(); void commit() { m_variablesStack = 0; } private: VariablesStack* m_variablesStack; size_type m_stackSize; }; friend class CommitPushParams; /** * Check to see if an element frame for the particular element has already * been pushed. * * @param elem element in question * @return true if it has been pushed already */ bool elementFrameAlreadyPushed(const ElemTemplateElement* elem) const; /** * Push an entry onto the stack. * * @param stack entry to push */ void push(const StackEntry& theEntry); /** * Pop an entry from the top of the stack. */ void pop(); /** * Get a reference to the entry at the back (top) of the stack. * * @return a reference to the back of the stack. */ const StackEntry& back() const { assert(m_stack.empty() == false); return m_stack.back(); } friend class CommitPushElementFrame; friend class EnsurePop; friend class PushParamFunctor; friend class SetAndRestoreForceGlobalSearch; const XObjectPtr findXObject( const XalanQName& name, StylesheetExecutionContext& executionContext, bool fIsParam, bool fSearchGlobalSpace, bool& fNameFound); size_type findEntry( const XalanQName& name, bool fIsParam, bool fSearchGlobalSpace); VariableStackStackType m_stack; size_type m_globalStackFrameIndex; bool m_globalStackFrameMarked; /** * This is the top of the stack frame from where a search * for a variable or param should take place. It may not * be the real stack top. */ size_type m_currentStackFrameIndex; /** * This will be a stack for any variable definitions * that are being evaluated dynamically, to protect * against circular definitions. */ RecursionGuardStackType m_guardStack; /** * This will be a stack for tracking element frames. * This is only used in debug builds. */ ElemTemplateElementStackType m_elementFrameStack; }; } #endif // #if !defined(XALAN_VARIABLESSTACK_HEADER_GUARD)