00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one 00003 * or more contributor license agreements. See the NOTICE file 00004 * distributed with this work for additional information 00005 * regarding copyright ownership. The ASF licenses this file 00006 * to you under the Apache License, Version 2.0 (the "License"); 00007 * you may not use this file except in compliance with the License. 00008 * You may obtain a copy of the License at 00009 * 00010 * http://www.apache.org/licenses/LICENSE-2.0 00011 * 00012 * Unless required by applicable law or agreed to in writing, software 00013 * distributed under the License is distributed on an "AS IS" BASIS, 00014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 * See the License for the specific language governing permissions and 00016 * limitations under the License. 00017 */ 00018 #if !defined(XPATHEXPRESSION_HEADER_GUARD_1357924680) 00019 #define XPATHEXPRESSION_HEADER_GUARD_1357924680 00020 00021 00022 00023 // Base header file. Must be first. 00024 #include <xalanc/XPath/XPathDefinitions.hpp> 00025 00026 00027 00028 #include <xalanc/Include/XalanVector.hpp> 00029 00030 00031 00032 #if defined(XALAN_CLASSIC_IOSTREAMS) 00033 #include <iostream.h> 00034 #else 00035 #include <iosfwd> 00036 #endif 00037 00038 00039 00040 #include <xalanc/XalanDOM/XalanDOMString.hpp> 00041 00042 00043 00044 #include <xalanc/PlatformSupport/DOMStringHelper.hpp> 00045 #include <xalanc/PlatformSupport/PrintWriter.hpp> 00046 00047 00048 00049 #include <xalanc/XPath/XToken.hpp> 00050 #include <xalanc/XPath/XalanXPathException.hpp> 00051 00052 00053 00054 XALAN_CPP_NAMESPACE_BEGIN 00055 00056 00057 00058 XALAN_USING_XERCES(MemoryManager) 00059 00060 00061 00062 class XALAN_XPATH_EXPORT XPathExpression 00063 { 00064 public: 00065 00066 typedef XALAN_STD_QUALIFIER ostream OstreamType; 00067 00068 typedef XalanVector<int> OpCodeMapType; 00069 typedef XalanVector<XToken> TokenQueueType; 00070 00071 typedef OpCodeMapType::value_type OpCodeMapValueType; 00072 typedef OpCodeMapValueType OpCodeMapSizeType; 00073 00074 typedef XalanVector<OpCodeMapValueType> OpCodeMapValueVectorType; 00075 00076 typedef XalanVector<double> NumberLiteralValueVectorType; 00077 00078 #define XALAN_XPATH_EXPRESSION_USE_ITERATORS 00079 00080 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 00081 typedef OpCodeMapType::const_iterator OpCodeMapPositionType; 00082 #else 00083 typedef OpCodeMapSizeType OpCodeMapPositionType; 00084 #endif 00085 typedef OpCodeMapType::difference_type OpCodeMapDifferenceType; 00086 typedef TokenQueueType::value_type TokenQueueValueType; 00087 typedef int TokenQueueSizeType; 00088 typedef TokenQueueSizeType TokenQueuePositionType; 00089 00090 /** 00091 * List of operations codes. 00092 * 00093 * Code for the descriptions of the operations codes: 00094 * [UPPER CASE] indicates a literal value, 00095 * [lower case] is a description of a value, 00096 * ([length] always indicates the length of the operation, 00097 * including the operations code and the length integer.) 00098 * {UPPER CASE} indicates the given production, 00099 * {description} is the description of a new production, 00100 * (For instance, {boolean expression} means some expression 00101 * that should be resolved to a boolean.) 00102 * * means that it occurs zero or more times, 00103 * + means that it occurs one or more times, 00104 * ? means that it is optional. 00105 * 00106 * returns: indicates what the production should return. 00107 */ 00108 enum eOpCodes 00109 { 00110 /** 00111 * [ELEMWILDCARD] 00112 * Means ELEMWILDCARD ("*"), used instead 00113 * of string index in some places. 00114 */ 00115 eELEMWILDCARD = -3, 00116 00117 /** 00118 * [EMPTY] 00119 * Empty slot to indicate NULL. 00120 */ 00121 eEMPTY = -2, 00122 00123 /** 00124 * [ENDOP] 00125 * Some operators may like to have a terminator. 00126 */ 00127 eENDOP = -1, 00128 00129 /** 00130 * [OP_XPATH] 00131 * [length] 00132 * {expression} 00133 * 00134 * returns: 00135 * XNodeSet 00136 * XNumber 00137 * XString 00138 * XBoolean 00139 * XRTree 00140 * XObject 00141 */ 00142 eOP_XPATH = 1, 00143 00144 /** 00145 * [OP_OR] 00146 * [length] 00147 * {boolean expression} 00148 * {boolean expression} 00149 * 00150 * returns: 00151 * XBoolean 00152 */ 00153 eOP_OR = 2, 00154 00155 /** 00156 * [OP_AND] 00157 * [length] 00158 * {boolean expression} 00159 * {boolean expression} 00160 * 00161 * returns: 00162 * XBoolean 00163 */ 00164 eOP_AND = 3, 00165 00166 /** 00167 * [OP_NOTEQUALS] 00168 * [length] 00169 * {expression} 00170 * {expression} 00171 * 00172 * returns: 00173 * XBoolean 00174 */ 00175 eOP_NOTEQUALS = 4, 00176 00177 /** 00178 * [OP_EQUALS] 00179 * [length] 00180 * {expression} 00181 * {expression} 00182 * 00183 * returns: 00184 * XBoolean 00185 */ 00186 eOP_EQUALS = 5, 00187 00188 /** 00189 * [OP_LTE] (less-than-or-equals) 00190 * [length] 00191 * {number expression} 00192 * {number expression} 00193 * 00194 * returns: 00195 * XBoolean 00196 */ 00197 eOP_LTE = 6, 00198 00199 /** 00200 * [OP_LT] (less-than) 00201 * [length] 00202 * {number expression} 00203 * {number expression} 00204 * 00205 * returns: 00206 * XBoolean 00207 */ 00208 eOP_LT = 7, 00209 00210 /** 00211 * [OP_GTE] (greater-than-or-equals) 00212 * [length] 00213 * {number expression} 00214 * {number expression} 00215 * 00216 * returns: 00217 * XBoolean 00218 */ 00219 eOP_GTE = 8, 00220 00221 /** 00222 * [OP_GT] (greater-than) 00223 * [length] 00224 * {number expression} 00225 * {number expression} 00226 * 00227 * returns: 00228 * XBoolean 00229 */ 00230 eOP_GT = 9, 00231 00232 /** 00233 * [OP_PLUS] 00234 * [length] 00235 * {number expression} 00236 * {number expression} 00237 * 00238 * returns: 00239 * XNumber 00240 */ 00241 eOP_PLUS = 10, 00242 00243 /** 00244 * [OP_MINUS] 00245 * [length] 00246 * {number expression} 00247 * {number expression} 00248 * 00249 * returns: 00250 * XNumber 00251 */ 00252 eOP_MINUS = 11, 00253 00254 /** 00255 * [OP_MULT] 00256 * [length] 00257 * {number expression} 00258 * {number expression} 00259 * 00260 * returns: 00261 * XNumber 00262 */ 00263 eOP_MULT = 12, 00264 00265 /** 00266 * [OP_DIV] 00267 * [length] 00268 * {number expression} 00269 * {number expression} 00270 * 00271 * returns: 00272 * XNumber 00273 */ 00274 eOP_DIV = 13, 00275 00276 /** 00277 * [OP_MOD] 00278 * [length] 00279 * {number expression} 00280 * {number expression} 00281 * 00282 * returns: 00283 * XNumber 00284 */ 00285 eOP_MOD = 14, 00286 00287 /** 00288 * [OP_NEG] 00289 * [length] 00290 * {number expression} 00291 * 00292 * returns: 00293 * XNumber 00294 */ 00295 eOP_NEG = 15, 00296 00297 /** 00298 * [OP_BOOL] (cast operation) 00299 * [length] 00300 * {expression} 00301 * 00302 * returns: 00303 * XBoolean 00304 */ 00305 eOP_BOOL = 16, 00306 00307 /** 00308 * [OP_UNION] 00309 * [length] 00310 * {PathExpr}+ 00311 * 00312 * returns: 00313 * XNodeSet 00314 */ 00315 eOP_UNION = 17, 00316 00317 /** 00318 * [OP_LITERAL] 00319 * [3] 00320 * [index to token] 00321 * 00322 * returns: 00323 * XString 00324 */ 00325 eOP_LITERAL = 18, 00326 00327 /** 00328 * [OP_VARIABLE] 00329 * [3] 00330 * [index to token] 00331 * 00332 * returns: 00333 * XString 00334 */ 00335 eOP_VARIABLE = 19, 00336 00337 /** 00338 * [OP_GROUP] 00339 * [length] 00340 * {expression} 00341 * 00342 * returns: 00343 * XNodeSet 00344 * XNumber 00345 * XString 00346 * XBoolean 00347 * XRTree 00348 * XObject 00349 */ 00350 eOP_GROUP = 20, 00351 00352 /** 00353 * [OP_NUMBERLIT] (Number literal.) 00354 * [3] 00355 * [index to token] 00356 * 00357 * returns: 00358 * XString 00359 */ 00360 eOP_NUMBERLIT = 21, 00361 00362 /** 00363 * [OP_ARGUMENT] (Function argument.) 00364 * [length] 00365 * {expression} 00366 * 00367 * returns: 00368 * XNodeSet 00369 * XNumber 00370 * XString 00371 * XBoolean 00372 * XRTree 00373 * XObject 00374 */ 00375 eOP_ARGUMENT = 22, 00376 00377 /** 00378 * [OP_EXTFUNCTION] (Extension function.) 00379 * [length] 00380 * [index to namespace token] 00381 * [index to function name token] 00382 * {OP_ARGUMENT}* 00383 * 00384 * returns: 00385 * XNodeSet 00386 * XNumber 00387 * XString 00388 * XBoolean 00389 * XRTree 00390 * XObject 00391 */ 00392 eOP_EXTFUNCTION = 23, 00393 00394 /** 00395 * [OP_FUNCTION] 00396 * [length] 00397 * [FUNC_ID] 00398 * [arg count] 00399 * {OP_ARGUMENT}* 00400 * [ENDOP] 00401 * 00402 * returns: 00403 * XNodeSet 00404 * XNumber 00405 * XString 00406 * XBoolean 00407 * XRTree 00408 * XObject 00409 */ 00410 eOP_FUNCTION = 24, 00411 00412 /** 00413 * [OP_LOCATIONPATH] 00414 * [length] 00415 * {FROM_stepType} 00416 * | {function}{predicate}* 00417 * [ENDOP] 00418 * 00419 * (Note that element and attribute namespaces and 00420 * names can be wildcarded '*'.) 00421 * 00422 * returns: 00423 * XNodeSet 00424 */ 00425 eOP_LOCATIONPATH = 25, 00426 00427 /** 00428 * [OP_PREDICATE] 00429 * [length] 00430 * {expression} 00431 * [ENDOP] (For safety) 00432 * 00433 * returns: 00434 * XBoolean or XNumber 00435 */ 00436 eOP_PREDICATE = 26, 00437 00438 /** 00439 * [NODETYPE_COMMENT] 00440 * No size or arguments. 00441 * 00442 * returns: 00443 * XBoolean 00444 */ 00445 eNODETYPE_COMMENT = 27, 00446 00447 /** 00448 * [NODETYPE_TEXT] 00449 * No size or arguments. 00450 * 00451 * returns: 00452 * XBoolean 00453 */ 00454 eNODETYPE_TEXT = 28, 00455 00456 /** 00457 * [NODETYPE_PI] 00458 * [index to token] 00459 * 00460 * returns: 00461 * XBoolean 00462 */ 00463 eNODETYPE_PI = 29, 00464 00465 /** 00466 * [NODETYPE_NODE] 00467 * No size or arguments. 00468 * 00469 * returns: 00470 * XBoolean 00471 */ 00472 eNODETYPE_NODE = 30, 00473 00474 /** 00475 * [NODENAME] 00476 * [index to ns token or EMPTY] 00477 * [index to name token] 00478 * 00479 * returns: 00480 * XBoolean 00481 */ 00482 eNODENAME = 31, 00483 00484 /** 00485 * [NODETYPE_ROOT] 00486 * No size or arguments. 00487 * 00488 * returns: 00489 * XBoolean 00490 */ 00491 eNODETYPE_ROOT = 32, 00492 00493 /** 00494 * [NODETYPE_ANY] 00495 * No size or arguments. 00496 * 00497 * returns: 00498 * XBoolean 00499 */ 00500 eNODETYPE_ANYELEMENT = 33, 00501 00502 /** 00503 * [FROM_stepType] 00504 * [length, including predicates] 00505 * [length of just the step, without the predicates] 00506 * {node test} 00507 * {predicates}? 00508 * 00509 * returns: 00510 * XBoolean 00511 */ 00512 eFROM_ANCESTORS = 34, 00513 eFROM_ANCESTORS_OR_SELF = 35, 00514 eFROM_ATTRIBUTES = 36, 00515 eFROM_CHILDREN = 37, 00516 eFROM_DESCENDANTS = 38, 00517 eFROM_DESCENDANTS_OR_SELF = 39, 00518 eFROM_FOLLOWING = 40, 00519 eFROM_FOLLOWING_SIBLINGS = 41, 00520 eFROM_PARENT = 42, 00521 eFROM_PRECEDING = 43, 00522 eFROM_PRECEDING_SIBLINGS = 44, 00523 eFROM_SELF = 45, 00524 eFROM_NAMESPACE = 46, 00525 eFROM_ROOT = 47, 00526 00527 /** 00528 * [OP_UNION] 00529 * [length] 00530 * {PathExpr}+ 00531 * 00532 * returns: 00533 * XNodeSet 00534 */ 00535 eOP_MATCHPATTERN = 48, 00536 00537 /** 00538 * [OP_UNION] 00539 * [length] 00540 * {PathExpr}+ 00541 * 00542 * returns: 00543 * XNodeSet 00544 */ 00545 eOP_LOCATIONPATHPATTERN = 49, 00546 00547 // For match patterns 00548 eMATCH_ATTRIBUTE = 50, 00549 eMATCH_ANY_ANCESTOR = 51, 00550 eMATCH_IMMEDIATE_ANCESTOR = 52, 00551 eMATCH_ANY_ANCESTOR_WITH_PREDICATE = 53, 00552 eMATCH_ANY_ANCESTOR_WITH_FUNCTION_CALL = 54, 00553 00554 /** 00555 * [OP_PREDICATE_WITH_POSITION] 00556 * [length] 00557 * {expression} 00558 * [ENDOP] (For safety) 00559 * 00560 * returns: 00561 * XBoolean or XNumber 00562 */ 00563 eOP_PREDICATE_WITH_POSITION = 55, 00564 00565 /** 00566 * These are values for intrinsic functions which 00567 * have been compiled directly into the op map. 00568 */ 00569 eOP_FUNCTION_POSITION = 56, 00570 eOP_FUNCTION_LAST = 57, 00571 eOP_FUNCTION_COUNT = 58, 00572 eOP_FUNCTION_NOT = 59, 00573 eOP_FUNCTION_TRUE = 60, 00574 eOP_FUNCTION_FALSE = 61, 00575 eOP_FUNCTION_BOOLEAN = 62, 00576 eOP_FUNCTION_NAME_0 = 63, 00577 eOP_FUNCTION_NAME_1 = 64, 00578 eOP_FUNCTION_LOCALNAME_0 = 65, 00579 eOP_FUNCTION_LOCALNAME_1 = 66, 00580 eOP_FUNCTION_FLOOR = 67, 00581 eOP_FUNCTION_CEILING = 68, 00582 eOP_FUNCTION_ROUND = 69, 00583 eOP_FUNCTION_NUMBER_0 = 70, 00584 eOP_FUNCTION_NUMBER_1 = 71, 00585 eOP_FUNCTION_STRING_0 = 72, 00586 eOP_FUNCTION_STRING_1 = 73, 00587 eOP_FUNCTION_STRINGLENGTH_0 = 74, 00588 eOP_FUNCTION_STRINGLENGTH_1 = 75, 00589 eOP_FUNCTION_NAMESPACEURI_0 = 76, 00590 eOP_FUNCTION_NAMESPACEURI_1 = 77, 00591 eOP_FUNCTION_SUM = 78, 00592 eOP_FUNCTION_CONCAT = 79, 00593 00594 // Always add _before_ this one and update 00595 // s_opCodeLengthArray. 00596 eOpCodeNextAvailable 00597 }; // enum eOpCodes 00598 00599 /** 00600 * Exception class thrown when an invalid XPath expression is encountered 00601 */ 00602 class XALAN_XPATH_EXPORT XPathExpressionException : public XalanXPathException 00603 { 00604 public: 00605 00606 /** 00607 * Construct an XPathExpressionException object. 00608 * 00609 * @param theMessage string error message 00610 */ 00611 XPathExpressionException(const XalanDOMString& theMessage, 00612 MemoryManager& theManager); 00613 00614 virtual~ 00615 XPathExpressionException(); 00616 }; 00617 00618 /** 00619 * Exception class thrown when an invalid XPath operation code is encountered 00620 */ 00621 class XALAN_XPATH_EXPORT InvalidOpCodeException : public XPathExpressionException 00622 { 00623 public: 00624 00625 /** 00626 * Construct an InvalidOpCodeException object. 00627 * 00628 * @param theOpCode operation code that caused the exception 00629 */ 00630 InvalidOpCodeException( 00631 OpCodeMapValueType theOpCode, 00632 XalanDOMString& theBuffer); 00633 00634 virtual~ 00635 InvalidOpCodeException(); 00636 00637 private: 00638 00639 static XalanDOMString& 00640 FormatErrorMessage( 00641 OpCodeMapValueType theOpCode, 00642 XalanDOMString& theBuffer); 00643 }; 00644 00645 /** 00646 * Exception class thrown when an invalid number of XPath arguments is 00647 * encountered 00648 */ 00649 class XALAN_XPATH_EXPORT InvalidArgumentCountException : public XPathExpressionException 00650 { 00651 public: 00652 00653 /** 00654 * Construct an InvalidArgumentCountException object. 00655 * 00656 * @param theOpCode operation code that caused the exception 00657 * @param theExpectedCount the correct number of arguments for "opcode" 00658 * @param theSuppliedCount the number of arguments supplied 00659 */ 00660 InvalidArgumentCountException( 00661 OpCodeMapValueType theOpCode, 00662 OpCodeMapValueType theExpectedCount, 00663 OpCodeMapValueType theSuppliedCount, 00664 XalanDOMString& theBuffer); 00665 00666 virtual~ 00667 InvalidArgumentCountException(); 00668 00669 private: 00670 00671 static XalanDOMString& 00672 FormatErrorMessage( 00673 OpCodeMapValueType theOpCode, 00674 OpCodeMapValueType theExpectedCount, 00675 OpCodeMapValueType theSuppliedCount, 00676 XalanDOMString& theBuffer); 00677 }; 00678 00679 /** 00680 * Exception class thrown when an invalid XPath argument is encountered 00681 */ 00682 class XALAN_XPATH_EXPORT InvalidArgumentException : public XPathExpressionException 00683 { 00684 public: 00685 00686 /** 00687 * Construct an InvalidArgumentException object. 00688 * 00689 * @param theOpCode operation code that caused the exception 00690 * @param theValue invalid argument value 00691 */ 00692 InvalidArgumentException( 00693 OpCodeMapValueType theOpCode, 00694 OpCodeMapValueType theValue, 00695 XalanDOMString& theBuffer); 00696 00697 virtual~ 00698 InvalidArgumentException(); 00699 00700 private: 00701 00702 static XalanDOMString& 00703 FormatErrorMessage( 00704 OpCodeMapValueType theOpCode, 00705 OpCodeMapValueType theValue, 00706 XalanDOMString& theBuffer); 00707 }; 00708 00709 00710 /** 00711 * The length is always the opcode position + 1. Length is always expressed 00712 * as the opcode+length bytes, so it is always 2 or greater. This is the 00713 * offset from the op code where the length is stored. It will always 00714 * remain one. 00715 */ 00716 #if defined(XALAN_INLINE_INITIALIZATION) 00717 static const TokenQueueSizeType s_opCodeMapLengthIndex = 1; 00718 #else 00719 enum eDummy 00720 { 00721 s_opCodeMapLengthIndex = 1 00722 }; 00723 #endif 00724 00725 explicit 00726 XPathExpression(MemoryManager& theManager); 00727 00728 ~XPathExpression(); 00729 00730 MemoryManager& 00731 getMemoryManager() 00732 { 00733 return m_opMap.getMemoryManager(); 00734 } 00735 /** 00736 * Reset the expression. 00737 */ 00738 void 00739 reset(); 00740 00741 /** 00742 * Shrink internal tables. 00743 */ 00744 void 00745 shrink(); 00746 00747 /** 00748 * Retrieve number of elements in the operations code map. 00749 * 00750 * @return size of operations code map 00751 */ 00752 OpCodeMapSizeType 00753 opCodeMapSize() const 00754 { 00755 return OpCodeMapSizeType(m_opMap.size()); 00756 } 00757 00758 /** 00759 * Retrieve length of the operations code map stored in the map. The length 00760 * of the entire map is stored after the first op code. That offset is 00761 * determined by this const static member. Note that as expressions are 00762 * defined recursively, this is really just the length of the first 00763 * expression in the map, which is the top of the parse tree. Any 00764 * subexpression will also have a length entry at the same offset from the 00765 * beginning of the subexpression. 00766 * 00767 * @return length of operations code map 00768 */ 00769 OpCodeMapValueType 00770 opCodeMapLength() const 00771 { 00772 const OpCodeMapSizeType theSize = opCodeMapSize(); 00773 00774 if (theSize > s_opCodeMapLengthIndex) 00775 { 00776 assert(theSize == OpCodeMapSizeType(m_opMap[s_opCodeMapLengthIndex])); 00777 00778 return m_opMap[s_opCodeMapLengthIndex]; 00779 } 00780 else 00781 { 00782 assert(theSize == OpCodeMapValueType(theSize)); 00783 00784 return OpCodeMapValueType(theSize); 00785 } 00786 } 00787 00788 OpCodeMapPositionType 00789 getInitialOpCodePosition() const 00790 { 00791 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 00792 return m_opMap.begin(); 00793 #else 00794 return 0; 00795 #endif 00796 } 00797 00798 bool 00799 isValidOpCodePosition(OpCodeMapPositionType opPos) const 00800 { 00801 const OpCodeMapDifferenceType theDifference = 00802 OpCodeMapDifferenceType(opPos - getInitialOpCodePosition()); 00803 00804 return theDifference >= 0 && 00805 theDifference < opCodeMapSize(); 00806 } 00807 00808 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 00809 bool 00810 isValidOpCodePosition(OpCodeMapSizeType theIndex) const 00811 { 00812 return theIndex >= 0 && theIndex < opCodeMapSize(); 00813 } 00814 00815 /** 00816 * Retrieve the value of an operation code at a specified index in the 00817 * op code map. 00818 * 00819 * @param theIndex The index in list 00820 * @return value of operation code 00821 */ 00822 OpCodeMapValueType 00823 getOpCodeMapValue(OpCodeMapSizeType theIndex) const 00824 { 00825 assert(theIndex < opCodeMapLength()); 00826 00827 return m_opMap[theIndex]; 00828 } 00829 #endif 00830 00831 /** 00832 * Retrieve the value of an operation code at a specified position in the 00833 * list. 00834 * 00835 * @param opPos position in list 00836 * @return value of operation code 00837 */ 00838 OpCodeMapValueType 00839 getOpCodeMapValue(OpCodeMapPositionType opPos) const 00840 { 00841 assert(opPos < getInitialOpCodePosition() + opCodeMapLength()); 00842 00843 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 00844 return *opPos; 00845 #else 00846 00847 return m_opMap[opPos]; 00848 #endif 00849 } 00850 00851 /** 00852 * Set the value of an operation code at a specified index in the 00853 * OpCode map. 00854 * 00855 * @param theOpCodeMapIndex The index in the OpCode map 00856 * @param theValue value of operation code 00857 */ 00858 void 00859 setOpCodeMapValue( 00860 OpCodeMapSizeType theOpCodeMapIndex, 00861 const OpCodeMapValueType& theValue) 00862 { 00863 assert(theOpCodeMapIndex < opCodeMapLength()); 00864 00865 m_opMap[theOpCodeMapIndex] = theValue; 00866 } 00867 00868 OpCodeMapValueType 00869 getOpCodeArgumentLength(OpCodeMapPositionType opPos) const 00870 { 00871 return getOpCodeMapValue(opPos + XPathExpression::s_opCodeMapLengthIndex + 1) - 3; 00872 } 00873 00874 /** 00875 * Retrieve the length of an operation code at a specified position in the 00876 * op map. 00877 * 00878 * @param opPos position in the op map 00879 * @return length of operation code 00880 */ 00881 OpCodeMapValueType 00882 getOpCodeLengthFromOpMap(OpCodeMapPositionType opPos, 00883 MemoryManager& theManager) const; 00884 00885 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 00886 /** 00887 * Retrieve the length of an operation code at a specified index in the 00888 * op map. 00889 * 00890 * @param theIndex The index in the op map 00891 * @return length of operation code 00892 */ 00893 OpCodeMapValueType 00894 getOpCodeLengthFromOpMap(OpCodeMapSizeType theIndex, 00895 MemoryManager& theManager) const; 00896 #endif 00897 00898 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 00899 /** 00900 * Retrieve the position of the next operation code at a specified position 00901 * in the list. 00902 * 00903 * @param opPos position in list 00904 * @return position of next operation code 00905 */ 00906 OpCodeMapPositionType 00907 getNextOpCodePosition(OpCodeMapPositionType opPos) const 00908 { 00909 assert(opPos < getInitialOpCodePosition() + opCodeMapLength()); 00910 00911 return opPos + *(opPos + s_opCodeMapLengthIndex); 00912 } 00913 #endif 00914 00915 /** 00916 * Retrieve the position of the next operation code at a specified index 00917 * in the list. 00918 * 00919 * @param theIndex theIndex in list 00920 * @return position of next operation code 00921 */ 00922 OpCodeMapSizeType 00923 #if defined(XALAN_XPATH_EXPRESSION_USE_ITERATORS) 00924 getNextOpCodePosition(OpCodeMapSizeType theIndex) const 00925 #else 00926 getNextOpCodePosition(OpCodeMapPositionType theIndex) const 00927 #endif 00928 { 00929 assert(theIndex < opCodeMapLength()); 00930 00931 assert(theIndex + m_opMap[theIndex + s_opCodeMapLengthIndex] == 00932 OpCodeMapSizeType(theIndex + m_opMap[theIndex + s_opCodeMapLengthIndex])); 00933 00934 return OpCodeMapSizeType(theIndex + m_opMap[theIndex + s_opCodeMapLengthIndex]); 00935 } 00936 00937 /** 00938 * Set the arguments for an operation code at a specified index in the 00939 * list. 00940 * 00941 * @param opPos position in list 00942 * @param theOpCode operation code 00943 * @param theIndex index in list 00944 * @param theArgs vector or arguments to supply 00945 */ 00946 void 00947 setOpCodeArgs( 00948 eOpCodes theOpCode, 00949 OpCodeMapSizeType theIndex, 00950 const OpCodeMapValueVectorType& theArgs); 00951 00952 /** 00953 * Add an operation code to the list. 00954 * 00955 * @param theOpCode operation code 00956 * @return the position of the op code 00957 */ 00958 OpCodeMapSizeType 00959 appendOpCode(eOpCodes theOpCode); 00960 00961 /** 00962 * Add an operation code with supplied arguments to the list. 00963 * 00964 * @param theOpCode operation code 00965 * @param theArgs vector or arguments to supply 00966 */ 00967 OpCodeMapSizeType 00968 appendOpCode( 00969 eOpCodes theOpCode, 00970 const OpCodeMapValueVectorType& theArgs) 00971 { 00972 const OpCodeMapSizeType thePosition = appendOpCode(theOpCode); 00973 00974 setOpCodeArgs(theOpCode, 00975 thePosition, 00976 theArgs); 00977 00978 return thePosition; 00979 } 00980 00981 /** 00982 * Replace an operation code with supplied code. 00983 * 00984 * @param theIndex The index of the old operation code 00985 * @param theOldOpCode The old operation code 00986 * @param theNewOpCode The new operation code 00987 */ 00988 void 00989 replaceOpCode( 00990 OpCodeMapSizeType theIndex, 00991 eOpCodes theOldOpCode, 00992 eOpCodes theNewOpCode); 00993 00994 /** 00995 * Insert an operation code at a specified index in the list. 00996 * 00997 * @param theOpCode operation code 00998 * @param theIndex index in list 00999 */ 01000 OpCodeMapValueType 01001 insertOpCode( 01002 eOpCodes theOpCode, 01003 OpCodeMapSizeType theIndex); 01004 01005 /** 01006 * Update the length of an operation code at a specified index in the list. 01007 * This presumes that the other opcodes have been appended to the 01008 * expression, and that the specified op code's length needs to be set. 01009 * The size includes the normal length of the opcode, plus the length of 01010 * its subexpressions. 01011 * 01012 * @param theIndex index in list 01013 */ 01014 void 01015 updateOpCodeLength(OpCodeMapSizeType theIndex) 01016 { 01017 assert(theIndex < opCodeMapSize()); 01018 01019 updateOpCodeLength(m_opMap[theIndex], theIndex); 01020 } 01021 01022 /** 01023 * Update the length of an operation code that has moved to a new index in 01024 * the list. 01025 * 01026 * @param theOpCode operation code 01027 * @param theOriginalIndex original index in list 01028 * @param theNewIndex new index in list 01029 */ 01030 void 01031 updateShiftedOpCodeLength( 01032 OpCodeMapValueType theOpCode, 01033 OpCodeMapSizeType theOriginalIndex, 01034 OpCodeMapSizeType theNewIndex); 01035 01036 /** 01037 * Update the length of an operation code at a specified index in the list. 01038 * This presumes that the other opcodes have been appended to the 01039 * expression, and that the specified op code's length needs to be set. 01040 * The size includes the normal length of the opcode, plus the length of 01041 * its subexpressions. 01042 * 01043 * @param theOpCode operation code at specified index 01044 * @param theIndex index in list 01045 */ 01046 void 01047 updateOpCodeLength( 01048 OpCodeMapValueType theOpCode, 01049 OpCodeMapSizeType theIndex); 01050 01051 /** 01052 * Whether the operation code is one of the node test types, for example, 01053 * "ancestor::" or "child::" 01054 * 01055 * @param theOpCode operation code 01056 * @return true if code represents a node test 01057 */ 01058 static bool 01059 isNodeTestOpCode(OpCodeMapValueType theOpCode); 01060 01061 /** 01062 * Update the length of an operation code after a node test code. 01063 * 01064 * @param theIndex index in list 01065 */ 01066 void 01067 updateOpCodeLengthAfterNodeTest(OpCodeMapSizeType theIndex); 01068 01069 /** 01070 * Whether there are any more tokens in the token queue. 01071 * 01072 * @return true if there are more tokens 01073 */ 01074 bool 01075 hasMoreTokens() const 01076 { 01077 return tokenQueueSize() > m_currentPosition ? true : false; 01078 } 01079 01080 /** 01081 * Retrieve number of elements in the token queue. 01082 * 01083 * @return size of token queue 01084 */ 01085 TokenQueueSizeType 01086 tokenQueueSize() const 01087 { 01088 return TokenQueueSizeType(m_tokenQueue.size()); 01089 } 01090 01091 bool 01092 isValidTokenQueuePosition(TokenQueueSizeType thePosition) const 01093 { 01094 return thePosition < tokenQueueSize(); 01095 } 01096 01097 /** 01098 * Retrieve the current position in the token queue. 01099 * 01100 * @return position in queue 01101 */ 01102 TokenQueueSizeType 01103 getTokenPosition() const 01104 { 01105 return m_currentPosition; 01106 } 01107 01108 /** 01109 * Set the current position in the token queue to zero. 01110 */ 01111 void 01112 resetTokenPosition() 01113 { 01114 m_currentPosition = 0; 01115 } 01116 01117 /** 01118 * Retrieve a token at the specified position in the token queue. 01119 * 01120 * @param thePosition position in queue 01121 * @return pointer to XObject token 01122 */ 01123 const XToken* 01124 getToken(TokenQueuePositionType thePosition) const 01125 { 01126 assert(thePosition < tokenQueueSize()); 01127 01128 return &m_tokenQueue[thePosition]; 01129 } 01130 01131 /** 01132 * Retrieve the next token in the token queue. 01133 * 01134 * @return pointer to XObject token 01135 */ 01136 const XToken* 01137 getNextToken() 01138 { 01139 if (hasMoreTokens() == true) 01140 { 01141 return getToken(m_currentPosition++); 01142 } 01143 else 01144 { 01145 return 0; 01146 } 01147 } 01148 01149 /** 01150 * Retrieve the previous token in the token queue. 01151 * 01152 * @return pointer to XObject token 01153 */ 01154 const XToken* 01155 getPreviousToken() 01156 { 01157 if (m_currentPosition > 0) 01158 { 01159 return getToken(--m_currentPosition); 01160 } 01161 else 01162 { 01163 return 0; 01164 } 01165 } 01166 01167 enum eRelativeDirection 01168 { 01169 eRelativeBackward, 01170 eRelativeForward 01171 }; 01172 01173 /** 01174 * Retrieve a token at the specified offset relative to the current 01175 * position in the token queue. 01176 * 01177 * @param theOffset offset from current position 01178 * @param theDirection the direction in which to move 01179 * @return pointer to XObject token 01180 */ 01181 const XToken* 01182 getRelativeToken( 01183 TokenQueuePositionType theOffset, 01184 eRelativeDirection theDirection) const 01185 { 01186 const TokenQueuePositionType thePosition = 01187 calculateRelativePosition(theOffset, theDirection); 01188 01189 if (thePosition == tokenQueueSize()) 01190 { 01191 return 0; 01192 } 01193 else 01194 { 01195 return getToken(thePosition); 01196 } 01197 } 01198 01199 /** 01200 * Push a token onto the token queue. 01201 * 01202 * @param theToken the string value to push 01203 */ 01204 void 01205 pushToken(const XalanDOMString& theToken) 01206 { 01207 m_tokenQueue.push_back( 01208 XToken( 01209 01210 DoubleSupport::toDouble(theToken, getMemoryManager()), 01211 theToken, 01212 getMemoryManager())); 01213 } 01214 01215 /** 01216 * Push a token onto the token queue. 01217 * 01218 * @param theNumber the number value to push 01219 * @param theString the string value to push 01220 */ 01221 void 01222 pushToken( 01223 double theNumber, 01224 const XalanDOMString& theString) 01225 { 01226 m_tokenQueue.push_back( 01227 XToken( 01228 theNumber, 01229 theString, 01230 getMemoryManager())); 01231 } 01232 01233 /** 01234 * Insert a token onto the token queue at the 01235 * current position. 01236 * 01237 * @param theToken the string value to push 01238 */ 01239 void 01240 insertToken(const XalanDOMString& theToken) 01241 { 01242 m_tokenQueue.insert( 01243 m_tokenQueue.begin() + (m_currentPosition - 1), 01244 XToken( 01245 theToken, 01246 DoubleSupport::toDouble(theToken, getMemoryManager()), 01247 getMemoryManager())); 01248 } 01249 01250 /** 01251 * Insert a token onto the token queue at the 01252 * current position. 01253 * 01254 * @param theNumber the number value to push 01255 * @param theString the string value to push 01256 */ 01257 void 01258 insertToken( 01259 double theNumber, 01260 const XalanDOMString& theString) 01261 { 01262 m_tokenQueue.insert( 01263 m_tokenQueue.begin() + (m_currentPosition - 1), 01264 XToken( 01265 theNumber, 01266 theString, 01267 getMemoryManager())); 01268 } 01269 01270 /** 01271 * Replace a token in the token queue. 01272 * 01273 * @param theOffset the offset at which to replace the token. 01274 * @param theString The string data for the token. The instance will keep a pointer to this string, so it must be persistent. 01275 */ 01276 void 01277 replaceRelativeToken( 01278 TokenQueuePositionType theOffset, 01279 eRelativeDirection theDirection, 01280 const XalanDOMString& theString) 01281 { 01282 const TokenQueuePositionType thePosition = 01283 calculateRelativePosition(theOffset, theDirection); 01284 assert(thePosition < tokenQueueSize()); 01285 01286 m_tokenQueue[thePosition].set( 01287 theString, 01288 DoubleSupport::toDouble(theString, getMemoryManager())); 01289 } 01290 01291 /** 01292 * Diagnostic function to output the operation code map. 01293 * 01294 * @param thePrintWriter output device 01295 * @param theStartPosition starting position in map 01296 */ 01297 void 01298 dumpOpCodeMap( 01299 PrintWriter& thePrintWriter, 01300 OpCodeMapSizeType theStartPosition = 0) const; 01301 01302 /** 01303 * Diagnostic function to output the operation code map. 01304 * 01305 * @param theStream output stream 01306 * @param theStartPosition starting position in map 01307 */ 01308 void 01309 dumpOpCodeMap( 01310 OstreamType& theStream, 01311 OpCodeMapSizeType theStartPosition = 0) const; 01312 01313 /** 01314 * Diagnostic function to output the token queue. 01315 * 01316 * @param thePrintWriter output device 01317 * @param theStartPosition starting position in token queue 01318 */ 01319 void 01320 dumpTokenQueue( 01321 PrintWriter& thePrintWriter, 01322 TokenQueueSizeType theStartPosition = 0) const; 01323 01324 /** 01325 * Diagnostic function to output the token queue. 01326 * 01327 * @param thePrintWriter output device 01328 * @param theStartPosition starting position in token queue 01329 */ 01330 void 01331 dumpTokenQueue( 01332 OstreamType& theStream, 01333 TokenQueueSizeType theStartPosition = 0) const; 01334 01335 /** 01336 * Diagnostic function to output the remaining tokens in the token queue. 01337 * 01338 * @param thePrintWriter output device 01339 */ 01340 void 01341 dumpRemainingTokenQueue(PrintWriter& thePrintWriter) const; 01342 01343 /** 01344 * Diagnostic function to output the remaining tokens in the token queue. 01345 * 01346 * @param theStream The output stream 01347 * @param theMemoryManager The MemoryManager instance. 01348 */ 01349 void 01350 dumpRemainingTokenQueue( 01351 OstreamType& theStream, 01352 MemoryManager& theMemoryManager) const; 01353 01354 /** 01355 * Push a value onto the operations code 01356 * map. 01357 * 01358 * @param theToken string value of the token to push 01359 */ 01360 void 01361 pushValueOnOpCodeMap(const OpCodeMapType::value_type& theValue) 01362 { 01363 // Push the index onto the op map. 01364 m_opMap.push_back(theValue); 01365 01366 // Update the op map length. 01367 ++m_opMap[s_opCodeMapLengthIndex]; 01368 } 01369 01370 /** 01371 * Push a token onto the token queue and its index onto the operations code 01372 * map. 01373 * 01374 * @param theXToken the XToken to push 01375 */ 01376 void 01377 pushArgumentOnOpCodeMap(const XToken& theXToken); 01378 01379 /** 01380 * Push a token onto the token queue and its index onto the operations code 01381 * map. 01382 * 01383 * @param theString The string data for the token. The instance will keep a pointer to this string, so it must be persistent. 01384 */ 01385 void 01386 pushArgumentOnOpCodeMap(const XalanDOMString& theString); 01387 01388 /** 01389 * Push a token onto the token queue and its index onto the operations code 01390 * map. 01391 * 01392 * @param theNumber The numeric data for the token. This must be consistent with the lexical value in theString. 01393 * @param theString The string data for the token. The instance will keep a pointer to this string, so it must be persistent. 01394 */ 01395 void 01396 pushArgumentOnOpCodeMap( 01397 double theNumber, 01398 const XalanDOMString& theString); 01399 01400 /** 01401 * Push a number literal onto the vector of number literals and its index onto 01402 * the operations code map. 01403 * 01404 * @param theToken number value of the token to push 01405 */ 01406 void 01407 pushNumberLiteralOnOpCodeMap(double theNumber); 01408 01409 /** 01410 * Get a number literal from the vector of number literals. 01411 * 01412 * @param theIndex The index of the desired value. 01413 */ 01414 double 01415 getNumberLiteral(int theIndex) const 01416 { 01417 assert(theIndex >= 0 && 01418 NumberLiteralValueVectorType::size_type(theIndex) < m_numberLiteralValues.size()); 01419 01420 return m_numberLiteralValues[NumberLiteralValueVectorType::size_type(theIndex)]; 01421 } 01422 01423 /** 01424 * Push the current position in the token queue onto the operations code 01425 * map. 01426 */ 01427 void 01428 pushCurrentTokenOnOpCodeMap(); 01429 01430 /** 01431 * Change the current pattern in the pattern map. 01432 * 01433 * @param thePattern match pattern to make current 01434 */ 01435 void 01436 setCurrentPattern(const XalanDOMString& thePattern) 01437 { 01438 m_currentPattern = &thePattern; 01439 } 01440 01441 /** 01442 * Retrieve the current pattern in the pattern map. 01443 * 01444 * @return string for current match pattern 01445 */ 01446 const XalanDOMString& 01447 getCurrentPattern() const 01448 { 01449 assert(m_currentPattern != 0); 01450 01451 return *m_currentPattern; 01452 } 01453 01454 private: 01455 01456 /** 01457 * Calculate the relative token position given the offset 01458 * and direction. Returns the size of the token queue 01459 * if the offset is not valid. 01460 * 01461 * @param theOffset offset from current position 01462 * @param theDirection the direction in which to move 01463 * @return thePosition 01464 */ 01465 TokenQueuePositionType 01466 calculateRelativePosition( 01467 TokenQueuePositionType theOffset, 01468 eRelativeDirection theDirection) const 01469 { 01470 if (theDirection == eRelativeBackward && 01471 theOffset <= m_currentPosition) 01472 { 01473 return m_currentPosition - theOffset; 01474 } 01475 else if (theDirection == eRelativeForward && 01476 m_currentPosition + theOffset < tokenQueueSize()) 01477 { 01478 return m_currentPosition + theOffset; 01479 } 01480 else 01481 { 01482 return tokenQueueSize(); 01483 } 01484 } 01485 01486 /** 01487 * An operations map is used instead of a proper parse tree. It contains 01488 * operations codes and indexes into the m_tokenQueue. We use an array 01489 * instead of a full parse tree in order to cut down on the number of 01490 * objects created. 01491 */ 01492 OpCodeMapType m_opMap; 01493 01494 /** 01495 * The index of the last opcode that was appended or inserted. 01496 * 01497 */ 01498 OpCodeMapSizeType m_lastOpCodeIndex; 01499 01500 /** 01501 * The queue of used tokens. The current token is the token at the end of 01502 * the m_tokenQueue. The idea is that the queue can be marked and a 01503 * sequence of tokens can be reused. 01504 */ 01505 TokenQueueType m_tokenQueue; 01506 01507 /** 01508 * The current position in the token queue. 01509 */ 01510 TokenQueueSizeType m_currentPosition; 01511 01512 /** 01513 * The current pattern string, for diagnostics purposes. 01514 */ 01515 const XalanDOMString* m_currentPattern; 01516 01517 // Default vector allocation sizes. 01518 enum 01519 { 01520 eDefaultOpMapSize = 100, 01521 eDefaultTokenQueueSize = 30 01522 }; 01523 01524 NumberLiteralValueVectorType m_numberLiteralValues; 01525 }; 01526 01527 01528 01529 XALAN_CPP_NAMESPACE_END 01530 01531 01532 01533 #endif // XPATHEXPRESSION_HEADER_GUARD_1357924680
Doxygen and GraphViz are used to generate this API documentation from the Xalan-C header files.
Xalan-C++ XSLT Processor Version 1.11 |
|