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