1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #if !defined(XALAN_VARIABLESSTACK_HEADER_GUARD)
19 #define XALAN_VARIABLESSTACK_HEADER_GUARD
20 
21 
22 
23 // Base include file.  Must be first.
24 #include <xalanc/XSLT/XSLTDefinitions.hpp>
25 
26 
27 
28 #include <cassert>
29 
30 
31 
32 #include <xalanc/Include/XalanVector.hpp>
33 
34 
35 
36 #include <xalanc/XPath/XalanQName.hpp>
37 #include <xalanc/XPath/XObject.hpp>
38 
39 
40 
41 #include <xalanc/XSLT/XSLTProcessorException.hpp>
42 
43 
44 
45 namespace XALAN_CPP_NAMESPACE {
46 
47 
48 
49 class Arg;
50 class ElemTemplateElement;
51 class ElemVariable;
52 class StylesheetExecutionContext;
53 class XalanNode;
54 
55 
56 
57 /**
58  * Defines a class to keep track of a stack for macro arguments.
59  */
60 class XALAN_XSLT_EXPORT VariablesStack
61 {
62 public:
63 
64     typedef unsigned long   size_type;
65 
66     /**
67      * Constructor for a variable stack.
68      */
69     explicit
70     VariablesStack(MemoryManager& theManager);
71 
72     ~VariablesStack();
73 
74     /**
75      * Reset the stack.
76      */
77     void
78     reset();
79 
80     /**
81      * Push a frame marker for an element.
82      *
83      * @param elem the element
84      */
85     void
86     pushElementFrame(const ElemTemplateElement*     elem);
87 
88     /**
89      * Pop a frame marker for an element.
90      *
91      * @param elem the element
92      */
93     void
94     popElementFrame();
95 
96     /**
97      * Push a context marker onto the stack to let us know when to stop
98      * searching for a var.
99      *
100      * @param caller     caller node
101      * @param sourceNode source node
102      */
103     void
104     pushContextMarker();
105 
106     /**
107      * Pop the current context from the current context stack.
108      */
109     void
110     popContextMarker();
111 
112     struct ParamsVectorEntry
113     {
ParamsVectorEntryXALAN_CPP_NAMESPACE::VariablesStack::ParamsVectorEntry114         ParamsVectorEntry() :
115             m_qname(0),
116             m_value(),
117             m_variable(0)
118         {
119         }
120 
ParamsVectorEntryXALAN_CPP_NAMESPACE::VariablesStack::ParamsVectorEntry121         ParamsVectorEntry(
122                 const XalanQName*   qname,
123                 const XObjectPtr    value) :
124             m_qname(qname),
125             m_value(value),
126             m_variable(0)
127         {
128         }
129 
ParamsVectorEntryXALAN_CPP_NAMESPACE::VariablesStack::ParamsVectorEntry130         ParamsVectorEntry(
131                 const XalanQName*       qname,
132                 const ElemVariable*     variable) :
133             m_qname(qname),
134             m_value(),
135             m_variable(variable)
136         {
137         }
138 
139         const XalanQName*       m_qname;
140 
141         XObjectPtr              m_value;
142 
143         const ElemVariable*     m_variable;
144     };
145 
146     typedef XalanVector<ParamsVectorEntry>          ParamsVectorType;
147     typedef XalanVector<const ElemVariable*>            RecursionGuardStackType;
148     typedef XalanVector<const ElemTemplateElement*> ElemTemplateElementStackType;
149 
150     /**
151      * Push the provided objects as parameters.  You must call
152      * popContextMarker() when you are done with the arguments.
153      *
154      * @param theParam The vector containing the parameters.
155      */
156     void
157     pushParams(const ParamsVectorType&  theParams);
158 
159     /**
160      * Given a name, return a string representing the value, but don't look
161      * in the global space.  Since the variable may not yet have been
162      * evaluated, this may return a null XObjectPtr.
163      *
164      * @param theName name of variable
165      * @param exeuctionContext the current execution context
166      * @param fNameFound set to true if the name was found, false if not.
167      * @return pointer to XObject for variable
168      */
169     const XObjectPtr
getParamVariable(const XalanQName & qname,StylesheetExecutionContext & executionContext,bool & fNameFound)170     getParamVariable(
171             const XalanQName&               qname,
172             StylesheetExecutionContext&     executionContext,
173             bool&                           fNameFound)
174     {
175         return findXObject(qname, executionContext, true, false, fNameFound);
176     }
177 
178     /**
179      * Given a name, find the corresponding XObject.  If the variable
180      * exists, but has not yet been evaluated, the variable will be
181      * evaluated and the result returned.  This may return a null XObjectPtr,
182      * if the variable was not found.
183      *
184      * @param qname name of variable
185      * @param exeuctionContext the current execution context
186      * @param fNameFound set to true if the name was found, false if not.
187      * @return pointer to the corresponding XObject
188      */
189     const XObjectPtr
getVariable(const XalanQName & qname,StylesheetExecutionContext & executionContext,bool & fNameFound)190     getVariable(
191             const XalanQName&               qname,
192             StylesheetExecutionContext&     executionContext,
193             bool&                           fNameFound)
194     {
195         return findXObject(qname, executionContext, false, true, fNameFound);
196     }
197 
198     /**
199      * Push a named variable onto the processor variable stack. Don't forget
200      * to call startContext before pushing a series of arguments for a given
201      * template.
202      *
203      * @param name    name of variable
204      * @param val     pointer to ElemVariable
205      * @param e       element marker for variable
206      */
207     void
208     pushVariable(
209             const XalanQName&           name,
210             const ElemVariable*         var,
211             const ElemTemplateElement*  e);
212 
213     /**
214      * Push a named variable onto the processor variable stack. Don't forget
215      * to call startContext before pushing a series of arguments for a given
216      * template.
217      *
218      * @param name    name of variable
219      * @param val     pointer to XObject value
220      * @param e       element marker for variable
221      */
222     void
223     pushVariable(
224             const XalanQName&           name,
225             const XObjectPtr&           val,
226             const ElemTemplateElement*  e);
227 
228     /**
229      * Mark the top of the stack.
230      */
231     void
232     start();
233 
234     /**
235      * Reset all params in the current stack frame.
236      */
237     void
238     resetParams();
239 
240     /**
241      * Mark the top of the global stack frame.
242      */
243     void
244     markGlobalStackFrame();
245 
246     /**
247      * Clear the marking of the global stack frame.
248      */
249     void
250     unmarkGlobalStackFrame();
251 
252     /**
253      * Set the top of the stack frame from where a search for a variable or
254      * param should take place.  Calling with no parameter will cause the
255      * index to be set to the size of the stack.
256      *
257      * @param currentStackFrameIndex new value of index
258      */
259     void
setCurrentStackFrameIndex(size_type currentStackFrameIndex=~0u)260     setCurrentStackFrameIndex(size_type     currentStackFrameIndex = ~0u)
261     {
262         if (currentStackFrameIndex == ~0u)
263         {
264             assert(size_type(m_stack.size()) == m_stack.size());
265 
266             m_currentStackFrameIndex = size_type(m_stack.size());
267         }
268         else
269         {
270             m_currentStackFrameIndex = currentStackFrameIndex;
271         }
272     }
273 
274     /**
275      * Get the top of the stack frame from where a search
276      * for a variable or param should take place.
277      *
278      * @return current value of index
279      */
280     size_type
getCurrentStackFrameIndex() const281     getCurrentStackFrameIndex() const
282     {
283         return m_currentStackFrameIndex;
284     }
285 
286     /**
287      * Get the top of the global stack frame.
288      *
289      * @return current value of index
290      */
291     size_type
getGlobalStackFrameIndex() const292     getGlobalStackFrameIndex() const
293     {
294         return m_globalStackFrameIndex;
295     }
296 
297     class InvalidStackContextException : public XSLTProcessorException
298     {
299     public:
300 
301         InvalidStackContextException(XalanDOMString& theResult);
302 
303         virtual
304         ~InvalidStackContextException();
305 
306 
307         virtual const XalanDOMChar*
getType() const308             getType() const
309         {
310             return m_type;
311         }
312 
313     private:
314 
315         static const XalanDOMChar   m_type[];
316 
317     };
318 
319     class PushParamFunctor
320     {
321     public:
322 
PushParamFunctor(VariablesStack & theVariablesStack)323         PushParamFunctor(VariablesStack&    theVariablesStack) :
324             m_variablesStack(theVariablesStack)
325         {
326         }
327 
328         void
329         operator()(const ParamsVectorType::value_type&  theEntry) const;
330 
331     private:
332 
333         VariablesStack&     m_variablesStack;
334     };
335 
336     class XALAN_XSLT_EXPORT StackEntry
337     {
338     public:
339 
340         /**
341          * Enumeration for types of stack entries, one of context state, context
342          * marker, element marker, or argument.
343          */
344         enum eType { eContextMarker,
345                     eVariable,
346                     eParam,
347                     eActiveParam,
348                     eElementFrameMarker,
349                     eNextValue };
350 
351         /**
352          * Construct a context marker.
353          */
354         explicit
355         StackEntry();
356 
357         /**
358          * Construct a variable that is already evaluated.
359          */
360         StackEntry(
361             const XalanQName*   name,
362             const XObjectPtr&   val,
363             bool                isParam = false);
364 
365         /**
366          * Construct a variable that has not been evaluated yet.
367          */
368         StackEntry(
369             const XalanQName*       name,
370             const ElemVariable*     var,
371             bool                    isParam = false);
372 
373         /**
374          * Construct an element frame marker.
375          */
376         StackEntry(const ElemTemplateElement*   elem);
377 
378 
379         /**
380          * Copy constructor...
381          */
382         StackEntry(const StackEntry&    theSource);
383 
384         /**
385          * Destructor...
386          */
387         ~StackEntry();
388 
389         /**
390          * Determine type of stack entry
391          *
392          * @return enumeration value for type
393          */
394         eType
getType() const395         getType() const
396         {
397             return m_type;
398         }
399 
400         /**
401          * Retrieve object name.  Valid only for variables
402          *
403          * @return qualified name of object
404          */
405         const XalanQName*
getName() const406         getName() const
407         {
408             return m_qname;
409         }
410 
411         /**
412          * Retrieve object's XObject pointer.  Valid only for variables
413          *
414          * @return pointer to XObject
415          */
416         const XObjectPtr&
getValue() const417         getValue() const
418         {
419             return m_value;
420         }
421 
422         /**
423          * Retrieve object's XObject pointer.  Valid only for variables
424          *
425          * @return pointer to XObject
426          */
427         void
setValue(const XObjectPtr & theValue)428         setValue(const XObjectPtr&  theValue)
429         {
430             m_value = theValue;
431         }
432 
433         /**
434          * Retrieve object's XObject pointer.  Valid only for variables
435          *
436          * @return pointer to XObject
437          */
438         const ElemVariable*
getVariable() const439         getVariable() const
440         {
441             return m_variable;
442         }
443 
444         void
445         activate();
446 
447         void
448         deactivate();
449 
450         /**
451          * Retrieve the ElemTemplateElem where frame begins.  Valid only for element frame markers
452          *
453          * @return ElemTemplateElement corresponding to marker
454          */
455         const ElemTemplateElement*
getElement() const456         getElement() const
457         {
458             return m_element;
459         }
460 
461         StackEntry&
462         operator=(const StackEntry&     theRHS);
463 
464         bool
465         operator==(const StackEntry&    theRHS) const;
466 
467     private:
468 
469         // Data members...
470         eType                       m_type;
471 
472         const XalanQName*           m_qname;
473 
474         XObjectPtr                  m_value;
475 
476         const ElemVariable*         m_variable;
477 
478         const ElemTemplateElement*  m_element;
479     };
480 
481     typedef XalanVector<StackEntry>         VariableStackStackType;
482 
483     size_type
getStackSize() const484     getStackSize() const
485     {
486         return size_type(m_stack.size());
487     }
488 
489     enum { eDefaultStackSize = 100 };
490 
491 private:
492 
493     class CommitPushParams
494     {
495     public:
496 
497         CommitPushParams(VariablesStack&    theVariablesStack);
498 
499         ~CommitPushParams();
500 
501         void
commit()502         commit()
503         {
504             m_variablesStack = 0;
505         }
506 
507     private:
508 
509         VariablesStack*     m_variablesStack;
510 
511         size_type           m_stackSize;
512     };
513 
514     friend class CommitPushParams;
515 
516     /**
517      * Check to see if an element frame for the particular element has already
518      * been pushed.
519      *
520      * @param elem element in question
521      * @return true if it has been pushed already
522      */
523     bool
524     elementFrameAlreadyPushed(const ElemTemplateElement*    elem) const;
525 
526     /**
527      * Push an entry onto the stack.
528      *
529      * @param stack entry to push
530      */
531     void
532     push(const StackEntry&  theEntry);
533 
534     /**
535      * Pop an entry from the top of the stack.
536      */
537     void
538     pop();
539 
540     /**
541      * Get a reference to the entry at the back (top) of the stack.
542      *
543      * @return a reference to the back of the stack.
544      */
545     const StackEntry&
back() const546     back() const
547     {
548         assert(m_stack.empty() == false);
549 
550         return m_stack.back();
551     }
552 
553     friend class CommitPushElementFrame;
554     friend class EnsurePop;
555     friend class PushParamFunctor;
556     friend class SetAndRestoreForceGlobalSearch;
557 
558     const XObjectPtr
559     findXObject(
560             const XalanQName&               name,
561             StylesheetExecutionContext&     executionContext,
562             bool                            fIsParam,
563             bool                            fSearchGlobalSpace,
564             bool&                           fNameFound);
565 
566     size_type
567     findEntry(
568             const XalanQName&   name,
569             bool                fIsParam,
570             bool                fSearchGlobalSpace);
571 
572 
573     VariableStackStackType      m_stack;
574 
575     size_type                   m_globalStackFrameIndex;
576 
577     bool                        m_globalStackFrameMarked;
578 
579     /**
580      * This is the top of the stack frame from where a search
581      * for a variable or param should take place.  It may not
582      * be the real stack top.
583      */
584     size_type                   m_currentStackFrameIndex;
585 
586     /**
587      * This will be a stack for any variable definitions
588      * that are being evaluated dynamically, to protect
589      * against circular definitions.
590      */
591     RecursionGuardStackType         m_guardStack;
592 
593     /**
594      * This will be a stack for tracking element frames.
595      * This is only used in debug builds.
596      */
597     ElemTemplateElementStackType    m_elementFrameStack;
598 };
599 
600 
601 
602 }
603 
604 
605 
606 #endif  // #if !defined(XALAN_VARIABLESSTACK_HEADER_GUARD)
607