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(XPATHEXPRESSION_HEADER_GUARD_1357924680) 19 #define XPATHEXPRESSION_HEADER_GUARD_1357924680 20 21 22 23 // Base header file. Must be first. 24 #include <xalanc/XPath/XPathDefinitions.hpp> 25 26 27 28 #include <xalanc/Include/XalanVector.hpp> 29 30 31 32 #include <iosfwd> 33 34 35 36 #include <xalanc/XalanDOM/XalanDOMString.hpp> 37 38 39 40 #include <xalanc/PlatformSupport/DOMStringHelper.hpp> 41 #include <xalanc/PlatformSupport/PrintWriter.hpp> 42 43 44 45 #include <xalanc/XPath/XToken.hpp> 46 #include <xalanc/XPath/XalanXPathException.hpp> 47 48 49 50 namespace XALAN_CPP_NAMESPACE { 51 52 53 54 using xercesc::MemoryManager; 55 56 57 58 class XALAN_XPATH_EXPORT XPathExpression 59 { 60 public: 61 62 typedef std::ostream OstreamType; 63 64 typedef XalanVector<int> OpCodeMapType; 65 typedef XalanVector<XToken> TokenQueueType; 66 67 typedef OpCodeMapType::value_type OpCodeMapValueType; 68 typedef OpCodeMapValueType OpCodeMapSizeType; 69 70 typedef XalanVector<OpCodeMapValueType> OpCodeMapValueVectorType; 71 72 typedef XalanVector<double> NumberLiteralValueVectorType; 73 74 #define XALAN_XPATH_EXPRESSION_USE_ITERATORS 75 76 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 77 typedef OpCodeMapType::const_iterator OpCodeMapPositionType; 78 #else 79 typedef OpCodeMapSizeType OpCodeMapPositionType; 80 #endif 81 typedef OpCodeMapType::difference_type OpCodeMapDifferenceType; 82 typedef TokenQueueType::value_type TokenQueueValueType; 83 typedef int TokenQueueSizeType; 84 typedef TokenQueueSizeType TokenQueuePositionType; 85 86 /** 87 * List of operations codes. 88 * 89 * Code for the descriptions of the operations codes: 90 * [UPPER CASE] indicates a literal value, 91 * [lower case] is a description of a value, 92 * ([length] always indicates the length of the operation, 93 * including the operations code and the length integer.) 94 * {UPPER CASE} indicates the given production, 95 * {description} is the description of a new production, 96 * (For instance, {boolean expression} means some expression 97 * that should be resolved to a boolean.) 98 * * means that it occurs zero or more times, 99 * + means that it occurs one or more times, 100 * ? means that it is optional. 101 * 102 * returns: indicates what the production should return. 103 */ 104 enum eOpCodes 105 { 106 /** 107 * [ELEMWILDCARD] 108 * Means ELEMWILDCARD ("*"), used instead 109 * of string index in some places. 110 */ 111 eELEMWILDCARD = -3, 112 113 /** 114 * [EMPTY] 115 * Empty slot to indicate NULL. 116 */ 117 eEMPTY = -2, 118 119 /** 120 * [ENDOP] 121 * Some operators may like to have a terminator. 122 */ 123 eENDOP = -1, 124 125 /** 126 * [OP_XPATH] 127 * [length] 128 * {expression} 129 * 130 * returns: 131 * XNodeSet 132 * XNumber 133 * XString 134 * XBoolean 135 * XRTree 136 * XObject 137 */ 138 eOP_XPATH = 1, 139 140 /** 141 * [OP_OR] 142 * [length] 143 * {boolean expression} 144 * {boolean expression} 145 * 146 * returns: 147 * XBoolean 148 */ 149 eOP_OR = 2, 150 151 /** 152 * [OP_AND] 153 * [length] 154 * {boolean expression} 155 * {boolean expression} 156 * 157 * returns: 158 * XBoolean 159 */ 160 eOP_AND = 3, 161 162 /** 163 * [OP_NOTEQUALS] 164 * [length] 165 * {expression} 166 * {expression} 167 * 168 * returns: 169 * XBoolean 170 */ 171 eOP_NOTEQUALS = 4, 172 173 /** 174 * [OP_EQUALS] 175 * [length] 176 * {expression} 177 * {expression} 178 * 179 * returns: 180 * XBoolean 181 */ 182 eOP_EQUALS = 5, 183 184 /** 185 * [OP_LTE] (less-than-or-equals) 186 * [length] 187 * {number expression} 188 * {number expression} 189 * 190 * returns: 191 * XBoolean 192 */ 193 eOP_LTE = 6, 194 195 /** 196 * [OP_LT] (less-than) 197 * [length] 198 * {number expression} 199 * {number expression} 200 * 201 * returns: 202 * XBoolean 203 */ 204 eOP_LT = 7, 205 206 /** 207 * [OP_GTE] (greater-than-or-equals) 208 * [length] 209 * {number expression} 210 * {number expression} 211 * 212 * returns: 213 * XBoolean 214 */ 215 eOP_GTE = 8, 216 217 /** 218 * [OP_GT] (greater-than) 219 * [length] 220 * {number expression} 221 * {number expression} 222 * 223 * returns: 224 * XBoolean 225 */ 226 eOP_GT = 9, 227 228 /** 229 * [OP_PLUS] 230 * [length] 231 * {number expression} 232 * {number expression} 233 * 234 * returns: 235 * XNumber 236 */ 237 eOP_PLUS = 10, 238 239 /** 240 * [OP_MINUS] 241 * [length] 242 * {number expression} 243 * {number expression} 244 * 245 * returns: 246 * XNumber 247 */ 248 eOP_MINUS = 11, 249 250 /** 251 * [OP_MULT] 252 * [length] 253 * {number expression} 254 * {number expression} 255 * 256 * returns: 257 * XNumber 258 */ 259 eOP_MULT = 12, 260 261 /** 262 * [OP_DIV] 263 * [length] 264 * {number expression} 265 * {number expression} 266 * 267 * returns: 268 * XNumber 269 */ 270 eOP_DIV = 13, 271 272 /** 273 * [OP_MOD] 274 * [length] 275 * {number expression} 276 * {number expression} 277 * 278 * returns: 279 * XNumber 280 */ 281 eOP_MOD = 14, 282 283 /** 284 * [OP_NEG] 285 * [length] 286 * {number expression} 287 * 288 * returns: 289 * XNumber 290 */ 291 eOP_NEG = 15, 292 293 /** 294 * [OP_BOOL] (cast operation) 295 * [length] 296 * {expression} 297 * 298 * returns: 299 * XBoolean 300 */ 301 eOP_BOOL = 16, 302 303 /** 304 * [OP_UNION] 305 * [length] 306 * {PathExpr}+ 307 * 308 * returns: 309 * XNodeSet 310 */ 311 eOP_UNION = 17, 312 313 /** 314 * [OP_LITERAL] 315 * [3] 316 * [index to token] 317 * 318 * returns: 319 * XString 320 */ 321 eOP_LITERAL = 18, 322 323 /** 324 * [OP_VARIABLE] 325 * [3] 326 * [index to token] 327 * 328 * returns: 329 * XString 330 */ 331 eOP_VARIABLE = 19, 332 333 /** 334 * [OP_GROUP] 335 * [length] 336 * {expression} 337 * 338 * returns: 339 * XNodeSet 340 * XNumber 341 * XString 342 * XBoolean 343 * XRTree 344 * XObject 345 */ 346 eOP_GROUP = 20, 347 348 /** 349 * [OP_NUMBERLIT] (Number literal.) 350 * [3] 351 * [index to token] 352 * 353 * returns: 354 * XString 355 */ 356 eOP_NUMBERLIT = 21, 357 358 /** 359 * [OP_ARGUMENT] (Function argument.) 360 * [length] 361 * {expression} 362 * 363 * returns: 364 * XNodeSet 365 * XNumber 366 * XString 367 * XBoolean 368 * XRTree 369 * XObject 370 */ 371 eOP_ARGUMENT = 22, 372 373 /** 374 * [OP_EXTFUNCTION] (Extension function.) 375 * [length] 376 * [index to namespace token] 377 * [index to function name token] 378 * {OP_ARGUMENT}* 379 * 380 * returns: 381 * XNodeSet 382 * XNumber 383 * XString 384 * XBoolean 385 * XRTree 386 * XObject 387 */ 388 eOP_EXTFUNCTION = 23, 389 390 /** 391 * [OP_FUNCTION] 392 * [length] 393 * [FUNC_ID] 394 * [arg count] 395 * {OP_ARGUMENT}* 396 * [ENDOP] 397 * 398 * returns: 399 * XNodeSet 400 * XNumber 401 * XString 402 * XBoolean 403 * XRTree 404 * XObject 405 */ 406 eOP_FUNCTION = 24, 407 408 /** 409 * [OP_LOCATIONPATH] 410 * [length] 411 * {FROM_stepType} 412 * | {function}{predicate}* 413 * [ENDOP] 414 * 415 * (Note that element and attribute namespaces and 416 * names can be wildcarded '*'.) 417 * 418 * returns: 419 * XNodeSet 420 */ 421 eOP_LOCATIONPATH = 25, 422 423 /** 424 * [OP_PREDICATE] 425 * [length] 426 * {expression} 427 * [ENDOP] (For safety) 428 * 429 * returns: 430 * XBoolean or XNumber 431 */ 432 eOP_PREDICATE = 26, 433 434 /** 435 * [NODETYPE_COMMENT] 436 * No size or arguments. 437 * 438 * returns: 439 * XBoolean 440 */ 441 eNODETYPE_COMMENT = 27, 442 443 /** 444 * [NODETYPE_TEXT] 445 * No size or arguments. 446 * 447 * returns: 448 * XBoolean 449 */ 450 eNODETYPE_TEXT = 28, 451 452 /** 453 * [NODETYPE_PI] 454 * [index to token] 455 * 456 * returns: 457 * XBoolean 458 */ 459 eNODETYPE_PI = 29, 460 461 /** 462 * [NODETYPE_NODE] 463 * No size or arguments. 464 * 465 * returns: 466 * XBoolean 467 */ 468 eNODETYPE_NODE = 30, 469 470 /** 471 * [NODENAME] 472 * [index to ns token or EMPTY] 473 * [index to name token] 474 * 475 * returns: 476 * XBoolean 477 */ 478 eNODENAME = 31, 479 480 /** 481 * [NODETYPE_ROOT] 482 * No size or arguments. 483 * 484 * returns: 485 * XBoolean 486 */ 487 eNODETYPE_ROOT = 32, 488 489 /** 490 * [NODETYPE_ANY] 491 * No size or arguments. 492 * 493 * returns: 494 * XBoolean 495 */ 496 eNODETYPE_ANYELEMENT = 33, 497 498 /** 499 * [FROM_stepType] 500 * [length, including predicates] 501 * [length of just the step, without the predicates] 502 * {node test} 503 * {predicates}? 504 * 505 * returns: 506 * XBoolean 507 */ 508 eFROM_ANCESTORS = 34, 509 eFROM_ANCESTORS_OR_SELF = 35, 510 eFROM_ATTRIBUTES = 36, 511 eFROM_CHILDREN = 37, 512 eFROM_DESCENDANTS = 38, 513 eFROM_DESCENDANTS_OR_SELF = 39, 514 eFROM_FOLLOWING = 40, 515 eFROM_FOLLOWING_SIBLINGS = 41, 516 eFROM_PARENT = 42, 517 eFROM_PRECEDING = 43, 518 eFROM_PRECEDING_SIBLINGS = 44, 519 eFROM_SELF = 45, 520 eFROM_NAMESPACE = 46, 521 eFROM_ROOT = 47, 522 523 /** 524 * [OP_UNION] 525 * [length] 526 * {PathExpr}+ 527 * 528 * returns: 529 * XNodeSet 530 */ 531 eOP_MATCHPATTERN = 48, 532 533 /** 534 * [OP_UNION] 535 * [length] 536 * {PathExpr}+ 537 * 538 * returns: 539 * XNodeSet 540 */ 541 eOP_LOCATIONPATHPATTERN = 49, 542 543 // For match patterns 544 eMATCH_ATTRIBUTE = 50, 545 eMATCH_ANY_ANCESTOR = 51, 546 eMATCH_IMMEDIATE_ANCESTOR = 52, 547 eMATCH_ANY_ANCESTOR_WITH_PREDICATE = 53, 548 eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL = 54, 549 550 /** 551 * [OP_PREDICATE_WITH_POSITION] 552 * [length] 553 * {expression} 554 * [ENDOP] (For safety) 555 * 556 * returns: 557 * XBoolean or XNumber 558 */ 559 eOP_PREDICATE_WITH_POSITION = 55, 560 561 /** 562 * These are values for intrinsic functions which 563 * have been compiled directly into the op map. 564 */ 565 eOP_FUNCTION_POSITION = 56, 566 eOP_FUNCTION_LAST = 57, 567 eOP_FUNCTION_COUNT = 58, 568 eOP_FUNCTION_NOT = 59, 569 eOP_FUNCTION_TRUE = 60, 570 eOP_FUNCTION_FALSE = 61, 571 eOP_FUNCTION_BOOLEAN = 62, 572 eOP_FUNCTION_NAME_0 = 63, 573 eOP_FUNCTION_NAME_1 = 64, 574 eOP_FUNCTION_LOCALNAME_0 = 65, 575 eOP_FUNCTION_LOCALNAME_1 = 66, 576 eOP_FUNCTION_FLOOR = 67, 577 eOP_FUNCTION_CEILING = 68, 578 eOP_FUNCTION_ROUND = 69, 579 eOP_FUNCTION_NUMBER_0 = 70, 580 eOP_FUNCTION_NUMBER_1 = 71, 581 eOP_FUNCTION_STRING_0 = 72, 582 eOP_FUNCTION_STRING_1 = 73, 583 eOP_FUNCTION_STRINGLENGTH_0 = 74, 584 eOP_FUNCTION_STRINGLENGTH_1 = 75, 585 eOP_FUNCTION_NAMESPACEURI_0 = 76, 586 eOP_FUNCTION_NAMESPACEURI_1 = 77, 587 eOP_FUNCTION_SUM = 78, 588 eOP_FUNCTION_CONCAT = 79, 589 590 // Always add _before_ this one and update 591 // s_opCodeLengthArray. 592 eOpCodeNextAvailable 593 }; // enum eOpCodes 594 595 /** 596 * Exception class thrown when an invalid XPath expression is encountered 597 */ 598 class XALAN_XPATH_EXPORT XPathExpressionException : public XalanXPathException 599 { 600 public: 601 602 /** 603 * Construct an XPathExpressionException object. 604 * 605 * @param theMessage string error message 606 */ 607 XPathExpressionException(const XalanDOMString& theMessage, 608 MemoryManager& theManager); 609 610 virtual~ 611 XPathExpressionException(); 612 }; 613 614 /** 615 * Exception class thrown when an invalid XPath operation code is encountered 616 */ 617 class XALAN_XPATH_EXPORT InvalidOpCodeException : public XPathExpressionException 618 { 619 public: 620 621 /** 622 * Construct an InvalidOpCodeException object. 623 * 624 * @param theOpCode operation code that caused the exception 625 */ 626 InvalidOpCodeException( 627 OpCodeMapValueType theOpCode, 628 XalanDOMString& theBuffer); 629 630 virtual~ 631 InvalidOpCodeException(); 632 633 private: 634 635 static XalanDOMString& 636 FormatErrorMessage( 637 OpCodeMapValueType theOpCode, 638 XalanDOMString& theBuffer); 639 }; 640 641 /** 642 * Exception class thrown when an invalid number of XPath arguments is 643 * encountered 644 */ 645 class XALAN_XPATH_EXPORT InvalidArgumentCountException : public XPathExpressionException 646 { 647 public: 648 649 /** 650 * Construct an InvalidArgumentCountException object. 651 * 652 * @param theOpCode operation code that caused the exception 653 * @param theExpectedCount the correct number of arguments for "opcode" 654 * @param theSuppliedCount the number of arguments supplied 655 */ 656 InvalidArgumentCountException( 657 OpCodeMapValueType theOpCode, 658 OpCodeMapValueType theExpectedCount, 659 OpCodeMapValueType theSuppliedCount, 660 XalanDOMString& theBuffer); 661 662 virtual~ 663 InvalidArgumentCountException(); 664 665 private: 666 667 static XalanDOMString& 668 FormatErrorMessage( 669 OpCodeMapValueType theOpCode, 670 OpCodeMapValueType theExpectedCount, 671 OpCodeMapValueType theSuppliedCount, 672 XalanDOMString& theBuffer); 673 }; 674 675 /** 676 * Exception class thrown when an invalid XPath argument is encountered 677 */ 678 class XALAN_XPATH_EXPORT InvalidArgumentException : public XPathExpressionException 679 { 680 public: 681 682 /** 683 * Construct an InvalidArgumentException object. 684 * 685 * @param theOpCode operation code that caused the exception 686 * @param theValue invalid argument value 687 */ 688 InvalidArgumentException( 689 OpCodeMapValueType theOpCode, 690 OpCodeMapValueType theValue, 691 XalanDOMString& theBuffer); 692 693 virtual~ 694 InvalidArgumentException(); 695 696 private: 697 698 static XalanDOMString& 699 FormatErrorMessage( 700 OpCodeMapValueType theOpCode, 701 OpCodeMapValueType theValue, 702 XalanDOMString& theBuffer); 703 }; 704 705 706 /** 707 * The length is always the opcode position + 1. Length is always expressed 708 * as the opcode+length bytes, so it is always 2 or greater. This is the 709 * offset from the op code where the length is stored. It will always 710 * remain one. 711 */ 712 enum eDummy 713 { 714 s_opCodeMapLengthIndex = 1 715 }; 716 717 explicit 718 XPathExpression(MemoryManager& theManager); 719 720 ~XPathExpression(); 721 722 MemoryManager& getMemoryManager()723 getMemoryManager() 724 { 725 return m_opMap.getMemoryManager(); 726 } 727 /** 728 * Reset the expression. 729 */ 730 void 731 reset(); 732 733 /** 734 * Shrink internal tables. 735 */ 736 void 737 shrink(); 738 739 /** 740 * Retrieve number of elements in the operations code map. 741 * 742 * @return size of operations code map 743 */ 744 OpCodeMapSizeType opCodeMapSize() const745 opCodeMapSize() const 746 { 747 return OpCodeMapSizeType(m_opMap.size()); 748 } 749 750 /** 751 * Retrieve length of the operations code map stored in the map. The length 752 * of the entire map is stored after the first op code. That offset is 753 * determined by this const static member. Note that as expressions are 754 * defined recursively, this is really just the length of the first 755 * expression in the map, which is the top of the parse tree. Any 756 * subexpression will also have a length entry at the same offset from the 757 * beginning of the subexpression. 758 * 759 * @return length of operations code map 760 */ 761 OpCodeMapValueType opCodeMapLength() const762 opCodeMapLength() const 763 { 764 const OpCodeMapSizeType theSize = opCodeMapSize(); 765 766 if (theSize > s_opCodeMapLengthIndex) 767 { 768 assert(theSize == OpCodeMapSizeType(m_opMap[s_opCodeMapLengthIndex])); 769 770 return m_opMap[s_opCodeMapLengthIndex]; 771 } 772 else 773 { 774 assert(theSize == OpCodeMapValueType(theSize)); 775 776 return OpCodeMapValueType(theSize); 777 } 778 } 779 780 OpCodeMapPositionType getInitialOpCodePosition() const781 getInitialOpCodePosition() const 782 { 783 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 784 return m_opMap.begin(); 785 #else 786 return 0; 787 #endif 788 } 789 790 bool isValidOpCodePosition(OpCodeMapPositionType opPos) const791 isValidOpCodePosition(OpCodeMapPositionType opPos) const 792 { 793 const OpCodeMapDifferenceType theDifference = 794 OpCodeMapDifferenceType(opPos - getInitialOpCodePosition()); 795 796 return theDifference >= 0 && 797 theDifference < opCodeMapSize(); 798 } 799 800 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 801 bool isValidOpCodePosition(OpCodeMapSizeType theIndex) const802 isValidOpCodePosition(OpCodeMapSizeType theIndex) const 803 { 804 return theIndex >= 0 && theIndex < opCodeMapSize(); 805 } 806 807 /** 808 * Retrieve the value of an operation code at a specified index in the 809 * op code map. 810 * 811 * @param theIndex The index in list 812 * @return value of operation code 813 */ 814 OpCodeMapValueType getOpCodeMapValue(OpCodeMapSizeType theIndex) const815 getOpCodeMapValue(OpCodeMapSizeType theIndex) const 816 { 817 assert(theIndex < opCodeMapLength()); 818 819 return m_opMap[theIndex]; 820 } 821 #endif 822 823 /** 824 * Retrieve the value of an operation code at a specified position in the 825 * list. 826 * 827 * @param opPos position in list 828 * @return value of operation code 829 */ 830 OpCodeMapValueType getOpCodeMapValue(OpCodeMapPositionType opPos) const831 getOpCodeMapValue(OpCodeMapPositionType opPos) const 832 { 833 assert(opPos < getInitialOpCodePosition() + opCodeMapLength()); 834 835 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 836 return *opPos; 837 #else 838 839 return m_opMap[opPos]; 840 #endif 841 } 842 843 /** 844 * Set the value of an operation code at a specified index in the 845 * OpCode map. 846 * 847 * @param theOpCodeMapIndex The index in the OpCode map 848 * @param theValue value of operation code 849 */ 850 void setOpCodeMapValue(OpCodeMapSizeType theOpCodeMapIndex,const OpCodeMapValueType & theValue)851 setOpCodeMapValue( 852 OpCodeMapSizeType theOpCodeMapIndex, 853 const OpCodeMapValueType& theValue) 854 { 855 assert(theOpCodeMapIndex < opCodeMapLength()); 856 857 m_opMap[theOpCodeMapIndex] = theValue; 858 } 859 860 OpCodeMapValueType getOpCodeArgumentLength(OpCodeMapPositionType opPos) const861 getOpCodeArgumentLength(OpCodeMapPositionType opPos) const 862 { 863 return getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3; 864 } 865 866 /** 867 * Retrieve the length of an operation code at a specified position in the 868 * op map. 869 * 870 * @param opPos position in the op map 871 * @return length of operation code 872 */ 873 OpCodeMapValueType 874 getOpCodeLengthFromOpMap(OpCodeMapPositionType opPos, 875 MemoryManager& theManager) const; 876 877 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 878 /** 879 * Retrieve the length of an operation code at a specified index in the 880 * op map. 881 * 882 * @param theIndex The index in the op map 883 * @return length of operation code 884 */ 885 OpCodeMapValueType 886 getOpCodeLengthFromOpMap(OpCodeMapSizeType theIndex, 887 MemoryManager& theManager) const; 888 #endif 889 890 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 891 /** 892 * Retrieve the position of the next operation code at a specified position 893 * in the list. 894 * 895 * @param opPos position in list 896 * @return position of next operation code 897 */ 898 OpCodeMapPositionType getNextOpCodePosition(OpCodeMapPositionType opPos) const899 getNextOpCodePosition(OpCodeMapPositionType opPos) const 900 { 901 assert(opPos < getInitialOpCodePosition() + opCodeMapLength()); 902 903 return opPos + *(opPos + s_opCodeMapLengthIndex); 904 } 905 #endif 906 907 /** 908 * Retrieve the position of the next operation code at a specified index 909 * in the list. 910 * 911 * @param theIndex theIndex in list 912 * @return position of next operation code 913 */ 914 OpCodeMapSizeType 915 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) getNextOpCodePosition(OpCodeMapSizeType theIndex) const916 getNextOpCodePosition(OpCodeMapSizeType theIndex) const 917 #else 918 getNextOpCodePosition(OpCodeMapPositionType theIndex) const 919 #endif 920 { 921 assert(theIndex < opCodeMapLength()); 922 923 assert(theIndex + m_opMap[theIndex + s_opCodeMapLengthIndex] == 924 OpCodeMapSizeType(theIndex + m_opMap[theIndex + s_opCodeMapLengthIndex])); 925 926 return OpCodeMapSizeType(theIndex + m_opMap[theIndex + s_opCodeMapLengthIndex]); 927 } 928 929 /** 930 * Set the arguments for an operation code at a specified index in the 931 * list. 932 * 933 * @param opPos position in list 934 * @param theOpCode operation code 935 * @param theIndex index in list 936 * @param theArgs vector or arguments to supply 937 */ 938 void 939 setOpCodeArgs( 940 eOpCodes theOpCode, 941 OpCodeMapSizeType theIndex, 942 const OpCodeMapValueVectorType& theArgs); 943 944 /** 945 * Add an operation code to the list. 946 * 947 * @param theOpCode operation code 948 * @return the position of the op code 949 */ 950 OpCodeMapSizeType 951 appendOpCode(eOpCodes theOpCode); 952 953 /** 954 * Add an operation code with supplied arguments to the list. 955 * 956 * @param theOpCode operation code 957 * @param theArgs vector or arguments to supply 958 */ 959 OpCodeMapSizeType appendOpCode(eOpCodes theOpCode,const OpCodeMapValueVectorType & theArgs)960 appendOpCode( 961 eOpCodes theOpCode, 962 const OpCodeMapValueVectorType& theArgs) 963 { 964 const OpCodeMapSizeType thePosition = appendOpCode(theOpCode); 965 966 setOpCodeArgs(theOpCode, 967 thePosition, 968 theArgs); 969 970 return thePosition; 971 } 972 973 /** 974 * Replace an operation code with supplied code. 975 * 976 * @param theIndex The index of the old operation code 977 * @param theOldOpCode The old operation code 978 * @param theNewOpCode The new operation code 979 */ 980 void 981 replaceOpCode( 982 OpCodeMapSizeType theIndex, 983 eOpCodes theOldOpCode, 984 eOpCodes theNewOpCode); 985 986 /** 987 * Insert an operation code at a specified index in the list. 988 * 989 * @param theOpCode operation code 990 * @param theIndex index in list 991 */ 992 OpCodeMapValueType 993 insertOpCode( 994 eOpCodes theOpCode, 995 OpCodeMapSizeType theIndex); 996 997 /** 998 * Update the length of an operation code at a specified index in the list. 999 * This presumes that the other opcodes have been appended to the 1000 * expression, and that the specified op code's length needs to be set. 1001 * The size includes the normal length of the opcode, plus the length of 1002 * its subexpressions. 1003 * 1004 * @param theIndex index in list 1005 */ 1006 void updateOpCodeLength(OpCodeMapSizeType theIndex)1007 updateOpCodeLength(OpCodeMapSizeType theIndex) 1008 { 1009 assert(theIndex < opCodeMapSize()); 1010 1011 updateOpCodeLength(m_opMap[theIndex], theIndex); 1012 } 1013 1014 /** 1015 * Update the length of an operation code that has moved to a new index in 1016 * the list. 1017 * 1018 * @param theOpCode operation code 1019 * @param theOriginalIndex original index in list 1020 * @param theNewIndex new index in list 1021 */ 1022 void 1023 updateShiftedOpCodeLength( 1024 OpCodeMapValueType theOpCode, 1025 OpCodeMapSizeType theOriginalIndex, 1026 OpCodeMapSizeType theNewIndex); 1027 1028 /** 1029 * Update the length of an operation code at a specified index in the list. 1030 * This presumes that the other opcodes have been appended to the 1031 * expression, and that the specified op code's length needs to be set. 1032 * The size includes the normal length of the opcode, plus the length of 1033 * its subexpressions. 1034 * 1035 * @param theOpCode operation code at specified index 1036 * @param theIndex index in list 1037 */ 1038 void 1039 updateOpCodeLength( 1040 OpCodeMapValueType theOpCode, 1041 OpCodeMapSizeType theIndex); 1042 1043 /** 1044 * Whether the operation code is one of the node test types, for example, 1045 * "ancestor::" or "child::" 1046 * 1047 * @param theOpCode operation code 1048 * @return true if code represents a node test 1049 */ 1050 static bool 1051 isNodeTestOpCode(OpCodeMapValueType theOpCode); 1052 1053 /** 1054 * Update the length of an operation code after a node test code. 1055 * 1056 * @param theIndex index in list 1057 */ 1058 void 1059 updateOpCodeLengthAfterNodeTest(OpCodeMapSizeType theIndex); 1060 1061 /** 1062 * Whether there are any more tokens in the token queue. 1063 * 1064 * @return true if there are more tokens 1065 */ 1066 bool hasMoreTokens() const1067 hasMoreTokens() const 1068 { 1069 return tokenQueueSize() > m_currentPosition ? true : false; 1070 } 1071 1072 /** 1073 * Retrieve number of elements in the token queue. 1074 * 1075 * @return size of token queue 1076 */ 1077 TokenQueueSizeType tokenQueueSize() const1078 tokenQueueSize() const 1079 { 1080 return TokenQueueSizeType(m_tokenQueue.size()); 1081 } 1082 1083 bool isValidTokenQueuePosition(TokenQueueSizeType thePosition) const1084 isValidTokenQueuePosition(TokenQueueSizeType thePosition) const 1085 { 1086 return thePosition < tokenQueueSize(); 1087 } 1088 1089 /** 1090 * Retrieve the current position in the token queue. 1091 * 1092 * @return position in queue 1093 */ 1094 TokenQueueSizeType getTokenPosition() const1095 getTokenPosition() const 1096 { 1097 return m_currentPosition; 1098 } 1099 1100 /** 1101 * Set the current position in the token queue to zero. 1102 */ 1103 void resetTokenPosition()1104 resetTokenPosition() 1105 { 1106 m_currentPosition = 0; 1107 } 1108 1109 /** 1110 * Retrieve a token at the specified position in the token queue. 1111 * 1112 * @param thePosition position in queue 1113 * @return pointer to XObject token 1114 */ 1115 const XToken* getToken(TokenQueuePositionType thePosition) const1116 getToken(TokenQueuePositionType thePosition) const 1117 { 1118 assert(thePosition < tokenQueueSize()); 1119 1120 return &m_tokenQueue[thePosition]; 1121 } 1122 1123 /** 1124 * Retrieve the next token in the token queue. 1125 * 1126 * @return pointer to XObject token 1127 */ 1128 const XToken* getNextToken()1129 getNextToken() 1130 { 1131 if (hasMoreTokens() == true) 1132 { 1133 return getToken(m_currentPosition++); 1134 } 1135 else 1136 { 1137 return 0; 1138 } 1139 } 1140 1141 /** 1142 * Retrieve the previous token in the token queue. 1143 * 1144 * @return pointer to XObject token 1145 */ 1146 const XToken* getPreviousToken()1147 getPreviousToken() 1148 { 1149 if (m_currentPosition > 0) 1150 { 1151 return getToken(--m_currentPosition); 1152 } 1153 else 1154 { 1155 return 0; 1156 } 1157 } 1158 1159 enum eRelativeDirection 1160 { 1161 eRelativeBackward, 1162 eRelativeForward 1163 }; 1164 1165 /** 1166 * Retrieve a token at the specified offset relative to the current 1167 * position in the token queue. 1168 * 1169 * @param theOffset offset from current position 1170 * @param theDirection the direction in which to move 1171 * @return pointer to XObject token 1172 */ 1173 const XToken* getRelativeToken(TokenQueuePositionType theOffset,eRelativeDirection theDirection) const1174 getRelativeToken( 1175 TokenQueuePositionType theOffset, 1176 eRelativeDirection theDirection) const 1177 { 1178 const TokenQueuePositionType thePosition = 1179 calculateRelativePosition(theOffset, theDirection); 1180 1181 if (thePosition == tokenQueueSize()) 1182 { 1183 return 0; 1184 } 1185 else 1186 { 1187 return getToken(thePosition); 1188 } 1189 } 1190 1191 /** 1192 * Push a token onto the token queue. 1193 * 1194 * @param theToken the string value to push 1195 */ 1196 void pushToken(const XalanDOMString & theToken)1197 pushToken(const XalanDOMString& theToken) 1198 { 1199 m_tokenQueue.push_back( 1200 XToken( 1201 1202 DoubleSupport::toDouble(theToken, getMemoryManager()), 1203 theToken, 1204 getMemoryManager())); 1205 } 1206 1207 /** 1208 * Push a token onto the token queue. 1209 * 1210 * @param theNumber the number value to push 1211 * @param theString the string value to push 1212 */ 1213 void pushToken(double theNumber,const XalanDOMString & theString)1214 pushToken( 1215 double theNumber, 1216 const XalanDOMString& theString) 1217 { 1218 m_tokenQueue.push_back( 1219 XToken( 1220 theNumber, 1221 theString, 1222 getMemoryManager())); 1223 } 1224 1225 /** 1226 * Insert a token onto the token queue at the 1227 * current position. 1228 * 1229 * @param theToken the string value to push 1230 */ 1231 void insertToken(const XalanDOMString & theToken)1232 insertToken(const XalanDOMString& theToken) 1233 { 1234 m_tokenQueue.insert( 1235 m_tokenQueue.begin() + (m_currentPosition - 1), 1236 XToken( 1237 theToken, 1238 DoubleSupport::toDouble(theToken, getMemoryManager()), 1239 getMemoryManager())); 1240 } 1241 1242 /** 1243 * Insert a token onto the token queue at the 1244 * current position. 1245 * 1246 * @param theNumber the number value to push 1247 * @param theString the string value to push 1248 */ 1249 void insertToken(double theNumber,const XalanDOMString & theString)1250 insertToken( 1251 double theNumber, 1252 const XalanDOMString& theString) 1253 { 1254 m_tokenQueue.insert( 1255 m_tokenQueue.begin() + (m_currentPosition - 1), 1256 XToken( 1257 theNumber, 1258 theString, 1259 getMemoryManager())); 1260 } 1261 1262 /** 1263 * Replace a token in the token queue. 1264 * 1265 * @param theOffset the offset at which to replace the token. 1266 * @param theString The string data for the token. The instance will keep a pointer to this string, so it must be persistent. 1267 */ 1268 void replaceRelativeToken(TokenQueuePositionType theOffset,eRelativeDirection theDirection,const XalanDOMString & theString)1269 replaceRelativeToken( 1270 TokenQueuePositionType theOffset, 1271 eRelativeDirection theDirection, 1272 const XalanDOMString& theString) 1273 { 1274 const TokenQueuePositionType thePosition = 1275 calculateRelativePosition(theOffset, theDirection); 1276 assert(thePosition < tokenQueueSize()); 1277 1278 m_tokenQueue[thePosition].set( 1279 theString, 1280 DoubleSupport::toDouble(theString, getMemoryManager())); 1281 } 1282 1283 /** 1284 * Diagnostic function to output the operation code map. 1285 * 1286 * @param thePrintWriter output device 1287 * @param theStartPosition starting position in map 1288 */ 1289 void 1290 dumpOpCodeMap( 1291 PrintWriter& thePrintWriter, 1292 OpCodeMapSizeType theStartPosition = 0) const; 1293 1294 /** 1295 * Diagnostic function to output the operation code map. 1296 * 1297 * @param theStream output stream 1298 * @param theStartPosition starting position in map 1299 */ 1300 void 1301 dumpOpCodeMap( 1302 OstreamType& theStream, 1303 OpCodeMapSizeType theStartPosition = 0) const; 1304 1305 /** 1306 * Diagnostic function to output the token queue. 1307 * 1308 * @param thePrintWriter output device 1309 * @param theStartPosition starting position in token queue 1310 */ 1311 void 1312 dumpTokenQueue( 1313 PrintWriter& thePrintWriter, 1314 TokenQueueSizeType theStartPosition = 0) const; 1315 1316 /** 1317 * Diagnostic function to output the token queue. 1318 * 1319 * @param thePrintWriter output device 1320 * @param theStartPosition starting position in token queue 1321 */ 1322 void 1323 dumpTokenQueue( 1324 OstreamType& theStream, 1325 TokenQueueSizeType theStartPosition = 0) const; 1326 1327 /** 1328 * Diagnostic function to output the remaining tokens in the token queue. 1329 * 1330 * @param thePrintWriter output device 1331 */ 1332 void 1333 dumpRemainingTokenQueue(PrintWriter& thePrintWriter) const; 1334 1335 /** 1336 * Diagnostic function to output the remaining tokens in the token queue. 1337 * 1338 * @param theStream The output stream 1339 * @param theMemoryManager The MemoryManager instance. 1340 */ 1341 void 1342 dumpRemainingTokenQueue( 1343 OstreamType& theStream, 1344 MemoryManager& theMemoryManager) const; 1345 1346 /** 1347 * Push a value onto the operations code 1348 * map. 1349 * 1350 * @param theToken string value of the token to push 1351 */ 1352 void pushValueOnOpCodeMap(const OpCodeMapType::value_type & theValue)1353 pushValueOnOpCodeMap(const OpCodeMapType::value_type& theValue) 1354 { 1355 // Push the index onto the op map. 1356 m_opMap.push_back(theValue); 1357 1358 // Update the op map length. 1359 ++m_opMap[s_opCodeMapLengthIndex]; 1360 } 1361 1362 /** 1363 * Push a token onto the token queue and its index onto the operations code 1364 * map. 1365 * 1366 * @param theXToken the XToken to push 1367 */ 1368 void 1369 pushArgumentOnOpCodeMap(const XToken& theXToken); 1370 1371 /** 1372 * Push a token onto the token queue and its index onto the operations code 1373 * map. 1374 * 1375 * @param theString The string data for the token. The instance will keep a pointer to this string, so it must be persistent. 1376 */ 1377 void 1378 pushArgumentOnOpCodeMap(const XalanDOMString& theString); 1379 1380 /** 1381 * Push a token onto the token queue and its index onto the operations code 1382 * map. 1383 * 1384 * @param theNumber The numeric data for the token. This must be consistent with the lexical value in theString. 1385 * @param theString The string data for the token. The instance will keep a pointer to this string, so it must be persistent. 1386 */ 1387 void 1388 pushArgumentOnOpCodeMap( 1389 double theNumber, 1390 const XalanDOMString& theString); 1391 1392 /** 1393 * Push a number literal onto the vector of number literals and its index onto 1394 * the operations code map. 1395 * 1396 * @param theToken number value of the token to push 1397 */ 1398 void 1399 pushNumberLiteralOnOpCodeMap(double theNumber); 1400 1401 /** 1402 * Get a number literal from the vector of number literals. 1403 * 1404 * @param theIndex The index of the desired value. 1405 */ 1406 double getNumberLiteral(int theIndex) const1407 getNumberLiteral(int theIndex) const 1408 { 1409 assert(theIndex >= 0 && 1410 NumberLiteralValueVectorType::size_type(theIndex) < m_numberLiteralValues.size()); 1411 1412 return m_numberLiteralValues[NumberLiteralValueVectorType::size_type(theIndex)]; 1413 } 1414 1415 /** 1416 * Push the current position in the token queue onto the operations code 1417 * map. 1418 */ 1419 void 1420 pushCurrentTokenOnOpCodeMap(); 1421 1422 /** 1423 * Change the current pattern in the pattern map. 1424 * 1425 * @param thePattern match pattern to make current 1426 */ 1427 void setCurrentPattern(const XalanDOMString & thePattern)1428 setCurrentPattern(const XalanDOMString& thePattern) 1429 { 1430 m_currentPattern = &thePattern; 1431 } 1432 1433 /** 1434 * Retrieve the current pattern in the pattern map. 1435 * 1436 * @return string for current match pattern 1437 */ 1438 const XalanDOMString& getCurrentPattern() const1439 getCurrentPattern() const 1440 { 1441 assert(m_currentPattern != 0); 1442 1443 return *m_currentPattern; 1444 } 1445 1446 private: 1447 1448 /** 1449 * Calculate the relative token position given the offset 1450 * and direction. Returns the size of the token queue 1451 * if the offset is not valid. 1452 * 1453 * @param theOffset offset from current position 1454 * @param theDirection the direction in which to move 1455 * @return thePosition 1456 */ 1457 TokenQueuePositionType calculateRelativePosition(TokenQueuePositionType theOffset,eRelativeDirection theDirection) const1458 calculateRelativePosition( 1459 TokenQueuePositionType theOffset, 1460 eRelativeDirection theDirection) const 1461 { 1462 if (theDirection == eRelativeBackward && 1463 theOffset <= m_currentPosition) 1464 { 1465 return m_currentPosition - theOffset; 1466 } 1467 else if (theDirection == eRelativeForward && 1468 m_currentPosition + theOffset < tokenQueueSize()) 1469 { 1470 return m_currentPosition + theOffset; 1471 } 1472 else 1473 { 1474 return tokenQueueSize(); 1475 } 1476 } 1477 1478 /** 1479 * An operations map is used instead of a proper parse tree. It contains 1480 * operations codes and indexes into the m_tokenQueue. We use an array 1481 * instead of a full parse tree in order to cut down on the number of 1482 * objects created. 1483 */ 1484 OpCodeMapType m_opMap; 1485 1486 /** 1487 * The index of the last opcode that was appended or inserted. 1488 * 1489 */ 1490 OpCodeMapSizeType m_lastOpCodeIndex; 1491 1492 /** 1493 * The queue of used tokens. The current token is the token at the end of 1494 * the m_tokenQueue. The idea is that the queue can be marked and a 1495 * sequence of tokens can be reused. 1496 */ 1497 TokenQueueType m_tokenQueue; 1498 1499 /** 1500 * The current position in the token queue. 1501 */ 1502 TokenQueueSizeType m_currentPosition; 1503 1504 /** 1505 * The current pattern string, for diagnostics purposes. 1506 */ 1507 const XalanDOMString* m_currentPattern; 1508 1509 // Default vector allocation sizes. 1510 enum 1511 { 1512 eDefaultOpMapSize = 100, 1513 eDefaultTokenQueueSize = 30 1514 }; 1515 1516 NumberLiteralValueVectorType m_numberLiteralValues; 1517 }; 1518 1519 1520 1521 } 1522 1523 1524 1525 #endif // XPATHEXPRESSION_HEADER_GUARD_1357924680 1526