| /* |
| * 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 <xalanc/XSLT/XSLTDefinitions.hpp> |
| |
| |
| |
| #include <cassert> |
| |
| |
| |
| #include <xalanc/Include/XalanVector.hpp> |
| |
| |
| |
| #include <xalanc/XPath/XalanQName.hpp> |
| #include <xalanc/XPath/XObject.hpp> |
| |
| |
| |
| #include <xalanc/XSLT/XSLTProcessorException.hpp> |
| |
| |
| |
| 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<ParamsVectorEntry> ParamsVectorType; |
| typedef XalanVector<const ElemVariable*> RecursionGuardStackType; |
| typedef XalanVector<const ElemTemplateElement*> 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<StackEntry> 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) |