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