WalkerFactory.java revision 9f8118474e9513f7a5b7d2a05e4a0fb15d1a6569
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/*
19 * $Id: WalkerFactory.java 469314 2006-10-30 23:31:59Z minchau $
20 */
21package org.apache.xpath.axes;
22
23import org.apache.xalan.res.XSLMessages;
24import org.apache.xml.dtm.Axis;
25import org.apache.xml.dtm.DTMFilter;
26import org.apache.xml.dtm.DTMIterator;
27import org.apache.xpath.Expression;
28import org.apache.xpath.compiler.Compiler;
29import org.apache.xpath.compiler.FunctionTable;
30import org.apache.xpath.compiler.OpCodes;
31import org.apache.xpath.compiler.OpMap;
32import org.apache.xpath.objects.XNumber;
33import org.apache.xpath.patterns.ContextMatchStepPattern;
34import org.apache.xpath.patterns.FunctionPattern;
35import org.apache.xpath.patterns.NodeTest;
36import org.apache.xpath.patterns.StepPattern;
37import org.apache.xpath.res.XPATHErrorResources;
38
39/**
40 * This class is both a factory for XPath location path expressions,
41 * which are built from the opcode map output, and an analysis engine
42 * for the location path expressions in order to provide optimization hints.
43 */
44public class WalkerFactory
45{
46
47  /**
48   * This method is for building an array of possible levels
49   * where the target element(s) could be found for a match.
50   * @param lpi The owning location path iterator.
51   * @param compiler non-null reference to compiler object that has processed
52   *                 the XPath operations into an opcode map.
53   * @param stepOpCodePos The opcode position for the step.
54   *
55   * @return non-null AxesWalker derivative.
56   *
57   * @throws javax.xml.transform.TransformerException
58   * @xsl.usage advanced
59   */
60  static AxesWalker loadOneWalker(
61          WalkingIterator lpi, Compiler compiler, int stepOpCodePos)
62            throws javax.xml.transform.TransformerException
63  {
64
65    AxesWalker firstWalker = null;
66    int stepType = compiler.getOp(stepOpCodePos);
67
68    if (stepType != OpCodes.ENDOP)
69    {
70
71      // m_axesWalkers = new AxesWalker[1];
72      // As we unwind from the recursion, create the iterators.
73      firstWalker = createDefaultWalker(compiler, stepType, lpi, 0);
74
75      firstWalker.init(compiler, stepOpCodePos, stepType);
76    }
77
78    return firstWalker;
79  }
80
81  /**
82   * This method is for building an array of possible levels
83   * where the target element(s) could be found for a match.
84   * @param lpi The owning location path iterator object.
85   * @param compiler non-null reference to compiler object that has processed
86   *                 the XPath operations into an opcode map.
87   * @param stepOpCodePos The opcode position for the step.
88   * @param stepIndex The top-level step index withing the iterator.
89   *
90   * @return non-null AxesWalker derivative.
91   *
92   * @throws javax.xml.transform.TransformerException
93   * @xsl.usage advanced
94   */
95  static AxesWalker loadWalkers(
96          WalkingIterator lpi, Compiler compiler, int stepOpCodePos, int stepIndex)
97            throws javax.xml.transform.TransformerException
98  {
99
100    int stepType;
101    AxesWalker firstWalker = null;
102    AxesWalker walker, prevWalker = null;
103
104    int analysis = analyze(compiler, stepOpCodePos, stepIndex);
105
106    while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
107    {
108      walker = createDefaultWalker(compiler, stepOpCodePos, lpi, analysis);
109
110      walker.init(compiler, stepOpCodePos, stepType);
111      walker.exprSetParent(lpi);
112
113      // walker.setAnalysis(analysis);
114      if (null == firstWalker)
115      {
116        firstWalker = walker;
117      }
118      else
119      {
120        prevWalker.setNextWalker(walker);
121        walker.setPrevWalker(prevWalker);
122      }
123
124      prevWalker = walker;
125      stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
126
127      if (stepOpCodePos < 0)
128        break;
129    }
130
131    return firstWalker;
132  }
133
134  public static boolean isSet(int analysis, int bits)
135  {
136    return (0 != (analysis & bits));
137  }
138
139  public static void diagnoseIterator(String name, int analysis, Compiler compiler)
140  {
141    System.out.println(compiler.toString()+", "+name+", "
142                             + Integer.toBinaryString(analysis) + ", "
143                             + getAnalysisString(analysis));
144  }
145
146  /**
147   * Create a new LocPathIterator iterator.  The exact type of iterator
148   * returned is based on an analysis of the XPath operations.
149   *
150   * @param compiler non-null reference to compiler object that has processed
151   *                 the XPath operations into an opcode map.
152   * @param opPos The position of the operation code for this itterator.
153   *
154   * @return non-null reference to a LocPathIterator or derivative.
155   *
156   * @throws javax.xml.transform.TransformerException
157   */
158  public static DTMIterator newDTMIterator(
159          Compiler compiler, int opPos,
160          boolean isTopLevel)
161            throws javax.xml.transform.TransformerException
162  {
163
164    int firstStepPos = OpMap.getFirstChildPos(opPos);
165    int analysis = analyze(compiler, firstStepPos, 0);
166    boolean isOneStep = isOneStep(analysis);
167    DTMIterator iter;
168
169    // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
170    if (isOneStep && walksSelfOnly(analysis) &&
171        isWild(analysis) && !hasPredicate(analysis))
172    {
173      if (DEBUG_ITERATOR_CREATION)
174        diagnoseIterator("SelfIteratorNoPredicate", analysis, compiler);
175
176      // Then use a simple iteration of the attributes, with node test
177      // and predicate testing.
178      iter = new SelfIteratorNoPredicate(compiler, opPos, analysis);
179    }
180    // Is the iteration exactly one child step?
181    else if (walksChildrenOnly(analysis) && isOneStep)
182    {
183
184      // Does the pattern specify *any* child with no predicate? (i.e. select="child::node()".
185      if (isWild(analysis) && !hasPredicate(analysis))
186      {
187        if (DEBUG_ITERATOR_CREATION)
188          diagnoseIterator("ChildIterator", analysis, compiler);
189
190        // Use simple child iteration without any test.
191        iter = new ChildIterator(compiler, opPos, analysis);
192      }
193      else
194      {
195        if (DEBUG_ITERATOR_CREATION)
196          diagnoseIterator("ChildTestIterator", analysis, compiler);
197
198        // Else use simple node test iteration with predicate test.
199        iter = new ChildTestIterator(compiler, opPos, analysis);
200      }
201    }
202    // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
203    else if (isOneStep && walksAttributes(analysis))
204    {
205      if (DEBUG_ITERATOR_CREATION)
206        diagnoseIterator("AttributeIterator", analysis, compiler);
207
208      // Then use a simple iteration of the attributes, with node test
209      // and predicate testing.
210      iter = new AttributeIterator(compiler, opPos, analysis);
211    }
212    else if(isOneStep && !walksFilteredList(analysis))
213    {
214      if( !walksNamespaces(analysis)
215      && (walksInDocOrder(analysis) || isSet(analysis, BIT_PARENT)))
216      {
217        if (false || DEBUG_ITERATOR_CREATION)
218          diagnoseIterator("OneStepIteratorForward", analysis, compiler);
219
220        // Then use a simple iteration of the attributes, with node test
221        // and predicate testing.
222        iter = new OneStepIteratorForward(compiler, opPos, analysis);
223      }
224      else
225      {
226        if (false || DEBUG_ITERATOR_CREATION)
227          diagnoseIterator("OneStepIterator", analysis, compiler);
228
229        // Then use a simple iteration of the attributes, with node test
230        // and predicate testing.
231        iter = new OneStepIterator(compiler, opPos, analysis);
232      }
233    }
234
235    // Analysis of "//center":
236    // bits: 1001000000001010000000000000011
237    // count: 3
238    // root
239    // child:node()
240    // BIT_DESCENDANT_OR_SELF
241    // It's highly possible that we should have a seperate bit set for
242    // "//foo" patterns.
243    // For at least the time being, we can't optimize patterns like
244    // "//table[3]", because this has to be analyzed as
245    // "/descendant-or-self::node()/table[3]" in order for the indexes
246    // to work right.
247    else if (isOptimizableForDescendantIterator(compiler, firstStepPos, 0)
248              // && getStepCount(analysis) <= 3
249              // && walksDescendants(analysis)
250              // && walksSubtreeOnlyFromRootOrContext(analysis)
251             )
252    {
253      if (DEBUG_ITERATOR_CREATION)
254        diagnoseIterator("DescendantIterator", analysis, compiler);
255
256      iter = new DescendantIterator(compiler, opPos, analysis);
257    }
258    else
259    {
260      if(isNaturalDocOrder(compiler, firstStepPos, 0, analysis))
261      {
262        if (false || DEBUG_ITERATOR_CREATION)
263        {
264          diagnoseIterator("WalkingIterator", analysis, compiler);
265        }
266
267        iter = new WalkingIterator(compiler, opPos, analysis, true);
268      }
269      else
270      {
271//        if (DEBUG_ITERATOR_CREATION)
272//          diagnoseIterator("MatchPatternIterator", analysis, compiler);
273//
274//        return new MatchPatternIterator(compiler, opPos, analysis);
275        if (DEBUG_ITERATOR_CREATION)
276          diagnoseIterator("WalkingIteratorSorted", analysis, compiler);
277
278        iter = new WalkingIteratorSorted(compiler, opPos, analysis, true);
279      }
280    }
281    if(iter instanceof LocPathIterator)
282      ((LocPathIterator)iter).setIsTopLevel(isTopLevel);
283
284    return iter;
285  }
286
287  /**
288   * Special purpose function to see if we can optimize the pattern for
289   * a DescendantIterator.
290   *
291   * @param compiler non-null reference to compiler object that has processed
292   *                 the XPath operations into an opcode map.
293   * @param stepOpCodePos The opcode position for the step.
294   *
295   * @return 32 bits as an integer that give information about the location
296   * path as a whole.
297   *
298   * @throws javax.xml.transform.TransformerException
299   */
300  public static int getAxisFromStep(
301          Compiler compiler, int stepOpCodePos)
302            throws javax.xml.transform.TransformerException
303  {
304
305    int stepType = compiler.getOp(stepOpCodePos);
306
307    switch (stepType)
308    {
309    case OpCodes.FROM_FOLLOWING :
310      return Axis.FOLLOWING;
311    case OpCodes.FROM_FOLLOWING_SIBLINGS :
312      return Axis.FOLLOWINGSIBLING;
313    case OpCodes.FROM_PRECEDING :
314      return Axis.PRECEDING;
315    case OpCodes.FROM_PRECEDING_SIBLINGS :
316      return Axis.PRECEDINGSIBLING;
317    case OpCodes.FROM_PARENT :
318      return Axis.PARENT;
319    case OpCodes.FROM_NAMESPACE :
320      return Axis.NAMESPACE;
321    case OpCodes.FROM_ANCESTORS :
322      return Axis.ANCESTOR;
323    case OpCodes.FROM_ANCESTORS_OR_SELF :
324      return Axis.ANCESTORORSELF;
325    case OpCodes.FROM_ATTRIBUTES :
326      return Axis.ATTRIBUTE;
327    case OpCodes.FROM_ROOT :
328      return Axis.ROOT;
329    case OpCodes.FROM_CHILDREN :
330      return Axis.CHILD;
331    case OpCodes.FROM_DESCENDANTS_OR_SELF :
332      return Axis.DESCENDANTORSELF;
333    case OpCodes.FROM_DESCENDANTS :
334      return Axis.DESCENDANT;
335    case OpCodes.FROM_SELF :
336      return Axis.SELF;
337    case OpCodes.OP_EXTFUNCTION :
338    case OpCodes.OP_FUNCTION :
339    case OpCodes.OP_GROUP :
340    case OpCodes.OP_VARIABLE :
341      return Axis.FILTEREDLIST;
342    }
343
344    throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
345                               //+ stepType);
346   }
347
348    /**
349     * Get a corresponding BIT_XXX from an axis.
350     * @param axis One of Axis.ANCESTOR, etc.
351     * @return One of BIT_ANCESTOR, etc.
352     */
353    static public int getAnalysisBitFromAxes(int axis)
354    {
355      switch (axis) // Generate new traverser
356        {
357        case Axis.ANCESTOR :
358          return BIT_ANCESTOR;
359        case Axis.ANCESTORORSELF :
360          return BIT_ANCESTOR_OR_SELF;
361        case Axis.ATTRIBUTE :
362          return BIT_ATTRIBUTE;
363        case Axis.CHILD :
364          return BIT_CHILD;
365        case Axis.DESCENDANT :
366          return BIT_DESCENDANT;
367        case Axis.DESCENDANTORSELF :
368          return BIT_DESCENDANT_OR_SELF;
369        case Axis.FOLLOWING :
370          return BIT_FOLLOWING;
371        case Axis.FOLLOWINGSIBLING :
372          return BIT_FOLLOWING_SIBLING;
373        case Axis.NAMESPACE :
374        case Axis.NAMESPACEDECLS :
375          return BIT_NAMESPACE;
376        case Axis.PARENT :
377          return BIT_PARENT;
378        case Axis.PRECEDING :
379          return BIT_PRECEDING;
380        case Axis.PRECEDINGSIBLING :
381          return BIT_PRECEDING_SIBLING;
382        case Axis.SELF :
383          return BIT_SELF;
384        case Axis.ALLFROMNODE :
385          return BIT_DESCENDANT_OR_SELF;
386          // case Axis.PRECEDINGANDANCESTOR :
387        case Axis.DESCENDANTSFROMROOT :
388        case Axis.ALL :
389        case Axis.DESCENDANTSORSELFFROMROOT :
390          return BIT_ANY_DESCENDANT_FROM_ROOT;
391        case Axis.ROOT :
392          return BIT_ROOT;
393        case Axis.FILTEREDLIST :
394          return BIT_FILTER;
395        default :
396          return BIT_FILTER;
397      }
398    }
399
400  static boolean functionProximateOrContainsProximate(Compiler compiler,
401                                                      int opPos)
402  {
403    int endFunc = opPos + compiler.getOp(opPos + 1) - 1;
404    opPos = OpMap.getFirstChildPos(opPos);
405    int funcID = compiler.getOp(opPos);
406    //  System.out.println("funcID: "+funcID);
407    //  System.out.println("opPos: "+opPos);
408    //  System.out.println("endFunc: "+endFunc);
409    switch(funcID)
410    {
411      case FunctionTable.FUNC_LAST:
412      case FunctionTable.FUNC_POSITION:
413        return true;
414      default:
415        opPos++;
416        int i = 0;
417        for (int p = opPos; p < endFunc; p = compiler.getNextOpPos(p), i++)
418        {
419          int innerExprOpPos = p+2;
420          int argOp = compiler.getOp(innerExprOpPos);
421          boolean prox = isProximateInnerExpr(compiler, innerExprOpPos);
422          if(prox)
423            return true;
424        }
425
426    }
427    return false;
428  }
429
430  static boolean isProximateInnerExpr(Compiler compiler, int opPos)
431  {
432    int op = compiler.getOp(opPos);
433    int innerExprOpPos = opPos+2;
434    switch(op)
435    {
436      case OpCodes.OP_ARGUMENT:
437        if(isProximateInnerExpr(compiler, innerExprOpPos))
438          return true;
439        break;
440      case OpCodes.OP_VARIABLE:
441      case OpCodes.OP_NUMBERLIT:
442      case OpCodes.OP_LITERAL:
443      case OpCodes.OP_LOCATIONPATH:
444        break; // OK
445      case OpCodes.OP_FUNCTION:
446        boolean isProx = functionProximateOrContainsProximate(compiler, opPos);
447        if(isProx)
448          return true;
449        break;
450      case OpCodes.OP_GT:
451      case OpCodes.OP_GTE:
452      case OpCodes.OP_LT:
453      case OpCodes.OP_LTE:
454      case OpCodes.OP_EQUALS:
455        int leftPos = OpMap.getFirstChildPos(op);
456        int rightPos = compiler.getNextOpPos(leftPos);
457        isProx = isProximateInnerExpr(compiler, leftPos);
458        if(isProx)
459          return true;
460        isProx = isProximateInnerExpr(compiler, rightPos);
461        if(isProx)
462          return true;
463        break;
464      default:
465        return true; // be conservative...
466    }
467    return false;
468  }
469
470  /**
471   * Tell if the predicates need to have proximity knowledge.
472   */
473  public static boolean mightBeProximate(Compiler compiler, int opPos, int stepType)
474          throws javax.xml.transform.TransformerException
475  {
476
477    boolean mightBeProximate = false;
478    int argLen;
479
480    switch (stepType)
481    {
482    case OpCodes.OP_VARIABLE :
483    case OpCodes.OP_EXTFUNCTION :
484    case OpCodes.OP_FUNCTION :
485    case OpCodes.OP_GROUP :
486      argLen = compiler.getArgLength(opPos);
487      break;
488    default :
489      argLen = compiler.getArgLengthOfStep(opPos);
490    }
491
492    int predPos = compiler.getFirstPredicateOpPos(opPos);
493    int count = 0;
494
495    while (OpCodes.OP_PREDICATE == compiler.getOp(predPos))
496    {
497      count++;
498
499      int innerExprOpPos = predPos+2;
500      int predOp = compiler.getOp(innerExprOpPos);
501
502      switch(predOp)
503      {
504        case OpCodes.OP_VARIABLE:
505        	return true; // Would need more smarts to tell if this could be a number or not!
506        case OpCodes.OP_LOCATIONPATH:
507          // OK.
508          break;
509        case OpCodes.OP_NUMBER:
510        case OpCodes.OP_NUMBERLIT:
511          return true; // that's all she wrote!
512        case OpCodes.OP_FUNCTION:
513          boolean isProx
514            = functionProximateOrContainsProximate(compiler, innerExprOpPos);
515          if(isProx)
516            return true;
517          break;
518        case OpCodes.OP_GT:
519        case OpCodes.OP_GTE:
520        case OpCodes.OP_LT:
521        case OpCodes.OP_LTE:
522        case OpCodes.OP_EQUALS:
523          int leftPos = OpMap.getFirstChildPos(innerExprOpPos);
524          int rightPos = compiler.getNextOpPos(leftPos);
525          isProx = isProximateInnerExpr(compiler, leftPos);
526          if(isProx)
527            return true;
528          isProx = isProximateInnerExpr(compiler, rightPos);
529          if(isProx)
530            return true;
531          break;
532        default:
533          return true; // be conservative...
534      }
535
536      predPos = compiler.getNextOpPos(predPos);
537    }
538
539    return mightBeProximate;
540  }
541
542  /**
543   * Special purpose function to see if we can optimize the pattern for
544   * a DescendantIterator.
545   *
546   * @param compiler non-null reference to compiler object that has processed
547   *                 the XPath operations into an opcode map.
548   * @param stepOpCodePos The opcode position for the step.
549   * @param stepIndex The top-level step index withing the iterator.
550   *
551   * @return 32 bits as an integer that give information about the location
552   * path as a whole.
553   *
554   * @throws javax.xml.transform.TransformerException
555   */
556  private static boolean isOptimizableForDescendantIterator(
557          Compiler compiler, int stepOpCodePos, int stepIndex)
558            throws javax.xml.transform.TransformerException
559  {
560
561    int stepType;
562    int stepCount = 0;
563    boolean foundDorDS = false;
564    boolean foundSelf = false;
565    boolean foundDS = false;
566
567    int nodeTestType = OpCodes.NODETYPE_NODE;
568
569    while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
570    {
571      // The DescendantIterator can only do one node test.  If there's more
572      // than one, use another iterator.
573      if(nodeTestType != OpCodes.NODETYPE_NODE && nodeTestType != OpCodes.NODETYPE_ROOT)
574        return false;
575
576      stepCount++;
577      if(stepCount > 3)
578        return false;
579
580      boolean mightBeProximate = mightBeProximate(compiler, stepOpCodePos, stepType);
581      if(mightBeProximate)
582        return false;
583
584      switch (stepType)
585      {
586      case OpCodes.FROM_FOLLOWING :
587      case OpCodes.FROM_FOLLOWING_SIBLINGS :
588      case OpCodes.FROM_PRECEDING :
589      case OpCodes.FROM_PRECEDING_SIBLINGS :
590      case OpCodes.FROM_PARENT :
591      case OpCodes.OP_VARIABLE :
592      case OpCodes.OP_EXTFUNCTION :
593      case OpCodes.OP_FUNCTION :
594      case OpCodes.OP_GROUP :
595      case OpCodes.FROM_NAMESPACE :
596      case OpCodes.FROM_ANCESTORS :
597      case OpCodes.FROM_ANCESTORS_OR_SELF :
598      case OpCodes.FROM_ATTRIBUTES :
599      case OpCodes.MATCH_ATTRIBUTE :
600      case OpCodes.MATCH_ANY_ANCESTOR :
601      case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
602        return false;
603      case OpCodes.FROM_ROOT :
604        if(1 != stepCount)
605          return false;
606        break;
607      case OpCodes.FROM_CHILDREN :
608        if(!foundDS && !(foundDorDS && foundSelf))
609          return false;
610        break;
611      case OpCodes.FROM_DESCENDANTS_OR_SELF :
612        foundDS = true;
613      case OpCodes.FROM_DESCENDANTS :
614        if(3 == stepCount)
615          return false;
616        foundDorDS = true;
617        break;
618      case OpCodes.FROM_SELF :
619        if(1 != stepCount)
620          return false;
621        foundSelf = true;
622        break;
623      default :
624        throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
625                                  // + stepType);
626      }
627
628      nodeTestType = compiler.getStepTestType(stepOpCodePos);
629
630      int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
631
632      if (nextStepOpCodePos < 0)
633        break;
634
635      if(OpCodes.ENDOP != compiler.getOp(nextStepOpCodePos))
636      {
637        if(compiler.countPredicates(stepOpCodePos) > 0)
638        {
639          return false;
640        }
641      }
642
643      stepOpCodePos = nextStepOpCodePos;
644    }
645
646    return true;
647  }
648
649  /**
650   * Analyze the location path and return 32 bits that give information about
651   * the location path as a whole.  See the BIT_XXX constants for meaning about
652   * each of the bits.
653   *
654   * @param compiler non-null reference to compiler object that has processed
655   *                 the XPath operations into an opcode map.
656   * @param stepOpCodePos The opcode position for the step.
657   * @param stepIndex The top-level step index withing the iterator.
658   *
659   * @return 32 bits as an integer that give information about the location
660   * path as a whole.
661   *
662   * @throws javax.xml.transform.TransformerException
663   */
664  private static int analyze(
665          Compiler compiler, int stepOpCodePos, int stepIndex)
666            throws javax.xml.transform.TransformerException
667  {
668
669    int stepType;
670    int stepCount = 0;
671    int analysisResult = 0x00000000;  // 32 bits of analysis
672
673    while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
674    {
675      stepCount++;
676
677      // String namespace = compiler.getStepNS(stepOpCodePos);
678      // boolean isNSWild = (null != namespace)
679      //                   ? namespace.equals(NodeTest.WILD) : false;
680      // String localname = compiler.getStepLocalName(stepOpCodePos);
681      // boolean isWild = (null != localname) ? localname.equals(NodeTest.WILD) : false;
682      boolean predAnalysis = analyzePredicate(compiler, stepOpCodePos,
683                                              stepType);
684
685      if (predAnalysis)
686        analysisResult |= BIT_PREDICATE;
687
688      switch (stepType)
689      {
690      case OpCodes.OP_VARIABLE :
691      case OpCodes.OP_EXTFUNCTION :
692      case OpCodes.OP_FUNCTION :
693      case OpCodes.OP_GROUP :
694        analysisResult |= BIT_FILTER;
695        break;
696      case OpCodes.FROM_ROOT :
697        analysisResult |= BIT_ROOT;
698        break;
699      case OpCodes.FROM_ANCESTORS :
700        analysisResult |= BIT_ANCESTOR;
701        break;
702      case OpCodes.FROM_ANCESTORS_OR_SELF :
703        analysisResult |= BIT_ANCESTOR_OR_SELF;
704        break;
705      case OpCodes.FROM_ATTRIBUTES :
706        analysisResult |= BIT_ATTRIBUTE;
707        break;
708      case OpCodes.FROM_NAMESPACE :
709        analysisResult |= BIT_NAMESPACE;
710        break;
711      case OpCodes.FROM_CHILDREN :
712        analysisResult |= BIT_CHILD;
713        break;
714      case OpCodes.FROM_DESCENDANTS :
715        analysisResult |= BIT_DESCENDANT;
716        break;
717      case OpCodes.FROM_DESCENDANTS_OR_SELF :
718
719        // Use a special bit to to make sure we get the right analysis of "//foo".
720        if (2 == stepCount && BIT_ROOT == analysisResult)
721        {
722          analysisResult |= BIT_ANY_DESCENDANT_FROM_ROOT;
723        }
724
725        analysisResult |= BIT_DESCENDANT_OR_SELF;
726        break;
727      case OpCodes.FROM_FOLLOWING :
728        analysisResult |= BIT_FOLLOWING;
729        break;
730      case OpCodes.FROM_FOLLOWING_SIBLINGS :
731        analysisResult |= BIT_FOLLOWING_SIBLING;
732        break;
733      case OpCodes.FROM_PRECEDING :
734        analysisResult |= BIT_PRECEDING;
735        break;
736      case OpCodes.FROM_PRECEDING_SIBLINGS :
737        analysisResult |= BIT_PRECEDING_SIBLING;
738        break;
739      case OpCodes.FROM_PARENT :
740        analysisResult |= BIT_PARENT;
741        break;
742      case OpCodes.FROM_SELF :
743        analysisResult |= BIT_SELF;
744        break;
745      case OpCodes.MATCH_ATTRIBUTE :
746        analysisResult |= (BIT_MATCH_PATTERN | BIT_ATTRIBUTE);
747        break;
748      case OpCodes.MATCH_ANY_ANCESTOR :
749        analysisResult |= (BIT_MATCH_PATTERN | BIT_ANCESTOR);
750        break;
751      case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
752        analysisResult |= (BIT_MATCH_PATTERN | BIT_PARENT);
753        break;
754      default :
755        throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
756                                   //+ stepType);
757      }
758
759      if (OpCodes.NODETYPE_NODE == compiler.getOp(stepOpCodePos + 3))  // child::node()
760      {
761        analysisResult |= BIT_NODETEST_ANY;
762      }
763
764      stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
765
766      if (stepOpCodePos < 0)
767        break;
768    }
769
770    analysisResult |= (stepCount & BITS_COUNT);
771
772    return analysisResult;
773  }
774
775  /**
776   * Tell if the given axis goes downword.  Bogus name, if you can think of
777   * a better one, please do tell.  This really has to do with inverting
778   * attribute axis.
779   * @param axis One of Axis.XXX.
780   * @return true if the axis is not a child axis and does not go up from
781   * the axis root.
782   */
783  public static boolean isDownwardAxisOfMany(int axis)
784  {
785    return ((Axis.DESCENDANTORSELF == axis) ||
786          (Axis.DESCENDANT == axis)
787          || (Axis.FOLLOWING == axis)
788//          || (Axis.FOLLOWINGSIBLING == axis)
789          || (Axis.PRECEDING == axis)
790//          || (Axis.PRECEDINGSIBLING == axis)
791          );
792  }
793
794  /**
795   * Read a <a href="http://www.w3.org/TR/xpath#location-paths">LocationPath</a>
796   * as a generalized match pattern.  What this means is that the LocationPath
797   * is read backwards, as a test on a given node, to see if it matches the
798   * criteria of the selection, and ends up at the context node.  Essentially,
799   * this is a backwards query from a given node, to find the context node.
800   * <p>So, the selection "foo/daz[2]" is, in non-abreviated expanded syntax,
801   * "self::node()/following-sibling::foo/child::daz[position()=2]".
802   * Taking this as a match pattern for a probable node, it works out to
803   * "self::daz/parent::foo[child::daz[position()=2 and isPrevStepNode()]
804   * precedingSibling::node()[isContextNodeOfLocationPath()]", adding magic
805   * isPrevStepNode and isContextNodeOfLocationPath operations.  Predicates in
806   * the location path have to be executed by the following step,
807   * because they have to know the context of their execution.
808   *
809   * @param mpi The MatchPatternIterator to which the steps will be attached.
810   * @param compiler The compiler that holds the syntax tree/op map to
811   * construct from.
812   * @param stepOpCodePos The current op code position within the opmap.
813   * @param stepIndex The top-level step index withing the iterator.
814   *
815   * @return A StepPattern object, which may contain relative StepPatterns.
816   *
817   * @throws javax.xml.transform.TransformerException
818   */
819  static StepPattern loadSteps(
820          MatchPatternIterator mpi, Compiler compiler, int stepOpCodePos,
821                                                       int stepIndex)
822            throws javax.xml.transform.TransformerException
823  {
824    if (DEBUG_PATTERN_CREATION)
825    {
826      System.out.println("================");
827      System.out.println("loadSteps for: "+compiler.getPatternString());
828    }
829    int stepType;
830    StepPattern step = null;
831    StepPattern firstStep = null, prevStep = null;
832    int analysis = analyze(compiler, stepOpCodePos, stepIndex);
833
834    while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
835    {
836      step = createDefaultStepPattern(compiler, stepOpCodePos, mpi, analysis,
837                                      firstStep, prevStep);
838
839      if (null == firstStep)
840      {
841        firstStep = step;
842      }
843      else
844      {
845
846        //prevStep.setNextWalker(step);
847        step.setRelativePathPattern(prevStep);
848      }
849
850      prevStep = step;
851      stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
852
853      if (stepOpCodePos < 0)
854        break;
855    }
856
857    int axis = Axis.SELF;
858    int paxis = Axis.SELF;
859    StepPattern tail = step;
860    for (StepPattern pat = step; null != pat;
861         pat = pat.getRelativePathPattern())
862    {
863      int nextAxis = pat.getAxis();
864      //int nextPaxis = pat.getPredicateAxis();
865      pat.setAxis(axis);
866
867      // The predicate axis can't be moved!!!  Test Axes103
868      // pat.setPredicateAxis(paxis);
869
870      // If we have an attribute or namespace axis that went up, then
871      // it won't find the attribute in the inverse, since the select-to-match
872      // axes are not invertable (an element is a parent of an attribute, but
873      // and attribute is not a child of an element).
874      // If we don't do the magic below, then "@*/ancestor-or-self::*" gets
875      // inverted for match to "self::*/descendant-or-self::@*/parent::node()",
876      // which obviously won't work.
877      // So we will rewrite this as:
878      // "self::*/descendant-or-self::*/attribute::*/parent::node()"
879      // Child has to be rewritten a little differently:
880      // select: "@*/parent::*"
881      // inverted match: "self::*/child::@*/parent::node()"
882      // rewrite: "self::*/attribute::*/parent::node()"
883      // Axes that go down in the select, do not have to have special treatment
884      // in the rewrite. The following inverted match will still not select
885      // anything.
886      // select: "@*/child::*"
887      // inverted match: "self::*/parent::@*/parent::node()"
888      // Lovely business, this.
889      // -sb
890      int whatToShow = pat.getWhatToShow();
891      if(whatToShow == DTMFilter.SHOW_ATTRIBUTE ||
892         whatToShow == DTMFilter.SHOW_NAMESPACE)
893      {
894        int newAxis = (whatToShow == DTMFilter.SHOW_ATTRIBUTE) ?
895                       Axis.ATTRIBUTE : Axis.NAMESPACE;
896        if(isDownwardAxisOfMany(axis))
897        {
898          StepPattern attrPat = new StepPattern(whatToShow,
899                                    pat.getNamespace(),
900                                    pat.getLocalName(),
901                                //newAxis, pat.getPredicateAxis);
902                                                newAxis, 0); // don't care about the predicate axis
903          XNumber score = pat.getStaticScore();
904          pat.setNamespace(null);
905          pat.setLocalName(NodeTest.WILD);
906          attrPat.setPredicates(pat.getPredicates());
907          pat.setPredicates(null);
908          pat.setWhatToShow(DTMFilter.SHOW_ELEMENT);
909          StepPattern rel = pat.getRelativePathPattern();
910          pat.setRelativePathPattern(attrPat);
911          attrPat.setRelativePathPattern(rel);
912          attrPat.setStaticScore(score);
913
914          // This is needed to inverse a following pattern, because of the
915          // wacky Xalan rules for following from an attribute.  See axes108.
916          // By these rules, following from an attribute is not strictly
917          // inverseable.
918          if(Axis.PRECEDING == pat.getAxis())
919            pat.setAxis(Axis.PRECEDINGANDANCESTOR);
920
921          else if(Axis.DESCENDANT == pat.getAxis())
922            pat.setAxis(Axis.DESCENDANTORSELF);
923
924          pat = attrPat;
925        }
926        else if(Axis.CHILD == pat.getAxis())
927        {
928          // In this case just change the axis.
929          // pat.setWhatToShow(whatToShow);
930          pat.setAxis(Axis.ATTRIBUTE);
931        }
932      }
933      axis = nextAxis;
934      //paxis = nextPaxis;
935      tail = pat;
936    }
937
938    if(axis < Axis.ALL)
939    {
940      StepPattern selfPattern = new ContextMatchStepPattern(axis, paxis);
941      // We need to keep the new nodetest from affecting the score...
942      XNumber score = tail.getStaticScore();
943      tail.setRelativePathPattern(selfPattern);
944      tail.setStaticScore(score);
945      selfPattern.setStaticScore(score);
946    }
947
948    if (DEBUG_PATTERN_CREATION)
949    {
950      System.out.println("Done loading steps: "+step.toString());
951
952      System.out.println("");
953    }
954    return step;  // start from last pattern?? //firstStep;
955  }
956
957  /**
958   * Create a StepPattern that is contained within a LocationPath.
959   *
960   *
961   * @param compiler The compiler that holds the syntax tree/op map to
962   * construct from.
963   * @param stepOpCodePos The current op code position within the opmap.
964   * @param mpi The MatchPatternIterator to which the steps will be attached.
965   * @param analysis 32 bits of analysis, from which the type of AxesWalker
966   *                 may be influenced.
967   * @param tail The step that is the first step analyzed, but the last
968   *                  step in the relative match linked list, i.e. the tail.
969   *                  May be null.
970   * @param head The step that is the current head of the relative
971   *                 match step linked list.
972   *                 May be null.
973   *
974   * @return the head of the list.
975   *
976   * @throws javax.xml.transform.TransformerException
977   */
978  private static StepPattern createDefaultStepPattern(
979          Compiler compiler, int opPos, MatchPatternIterator mpi,
980          int analysis, StepPattern tail, StepPattern head)
981            throws javax.xml.transform.TransformerException
982  {
983
984    int stepType = compiler.getOp(opPos);
985    boolean simpleInit = false;
986    boolean prevIsOneStepDown = true;
987
988    int whatToShow = compiler.getWhatToShow(opPos);
989    StepPattern ai = null;
990    int axis, predicateAxis;
991
992    switch (stepType)
993    {
994    case OpCodes.OP_VARIABLE :
995    case OpCodes.OP_EXTFUNCTION :
996    case OpCodes.OP_FUNCTION :
997    case OpCodes.OP_GROUP :
998      prevIsOneStepDown = false;
999
1000      Expression expr;
1001
1002      switch (stepType)
1003      {
1004      case OpCodes.OP_VARIABLE :
1005      case OpCodes.OP_EXTFUNCTION :
1006      case OpCodes.OP_FUNCTION :
1007      case OpCodes.OP_GROUP :
1008        expr = compiler.compile(opPos);
1009        break;
1010      default :
1011        expr = compiler.compile(opPos + 2);
1012      }
1013
1014      axis = Axis.FILTEREDLIST;
1015      predicateAxis = Axis.FILTEREDLIST;
1016      ai = new FunctionPattern(expr, axis, predicateAxis);
1017      simpleInit = true;
1018      break;
1019    case OpCodes.FROM_ROOT :
1020      whatToShow = DTMFilter.SHOW_DOCUMENT
1021                   | DTMFilter.SHOW_DOCUMENT_FRAGMENT;
1022
1023      axis = Axis.ROOT;
1024      predicateAxis = Axis.ROOT;
1025      ai = new StepPattern(DTMFilter.SHOW_DOCUMENT |
1026                                DTMFilter.SHOW_DOCUMENT_FRAGMENT,
1027                                axis, predicateAxis);
1028      break;
1029    case OpCodes.FROM_ATTRIBUTES :
1030      whatToShow = DTMFilter.SHOW_ATTRIBUTE;
1031      axis = Axis.PARENT;
1032      predicateAxis = Axis.ATTRIBUTE;
1033      // ai = new StepPattern(whatToShow, Axis.SELF, Axis.SELF);
1034      break;
1035    case OpCodes.FROM_NAMESPACE :
1036      whatToShow = DTMFilter.SHOW_NAMESPACE;
1037      axis = Axis.PARENT;
1038      predicateAxis = Axis.NAMESPACE;
1039      // ai = new StepPattern(whatToShow, axis, predicateAxis);
1040      break;
1041    case OpCodes.FROM_ANCESTORS :
1042      axis = Axis.DESCENDANT;
1043      predicateAxis = Axis.ANCESTOR;
1044      break;
1045    case OpCodes.FROM_CHILDREN :
1046      axis = Axis.PARENT;
1047      predicateAxis = Axis.CHILD;
1048      break;
1049    case OpCodes.FROM_ANCESTORS_OR_SELF :
1050      axis = Axis.DESCENDANTORSELF;
1051      predicateAxis = Axis.ANCESTORORSELF;
1052      break;
1053    case OpCodes.FROM_SELF :
1054      axis = Axis.SELF;
1055      predicateAxis = Axis.SELF;
1056      break;
1057    case OpCodes.FROM_PARENT :
1058      axis = Axis.CHILD;
1059      predicateAxis = Axis.PARENT;
1060      break;
1061    case OpCodes.FROM_PRECEDING_SIBLINGS :
1062      axis = Axis.FOLLOWINGSIBLING;
1063      predicateAxis = Axis.PRECEDINGSIBLING;
1064      break;
1065    case OpCodes.FROM_PRECEDING :
1066      axis = Axis.FOLLOWING;
1067      predicateAxis = Axis.PRECEDING;
1068      break;
1069    case OpCodes.FROM_FOLLOWING_SIBLINGS :
1070      axis = Axis.PRECEDINGSIBLING;
1071      predicateAxis = Axis.FOLLOWINGSIBLING;
1072      break;
1073    case OpCodes.FROM_FOLLOWING :
1074      axis = Axis.PRECEDING;
1075      predicateAxis = Axis.FOLLOWING;
1076      break;
1077    case OpCodes.FROM_DESCENDANTS_OR_SELF :
1078      axis = Axis.ANCESTORORSELF;
1079      predicateAxis = Axis.DESCENDANTORSELF;
1080      break;
1081    case OpCodes.FROM_DESCENDANTS :
1082      axis = Axis.ANCESTOR;
1083      predicateAxis = Axis.DESCENDANT;
1084      break;
1085    default :
1086      throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
1087                                 //+ stepType);
1088    }
1089    if(null == ai)
1090    {
1091      whatToShow = compiler.getWhatToShow(opPos); // %REVIEW%
1092      ai = new StepPattern(whatToShow, compiler.getStepNS(opPos),
1093                                compiler.getStepLocalName(opPos),
1094                                axis, predicateAxis);
1095    }
1096
1097    if (false || DEBUG_PATTERN_CREATION)
1098    {
1099      System.out.print("new step: "+ ai);
1100      System.out.print(", axis: " + Axis.getNames(ai.getAxis()));
1101      System.out.print(", predAxis: " + Axis.getNames(ai.getAxis()));
1102      System.out.print(", what: ");
1103      System.out.print("    ");
1104      ai.debugWhatToShow(ai.getWhatToShow());
1105    }
1106
1107    int argLen = compiler.getFirstPredicateOpPos(opPos);
1108
1109    ai.setPredicates(compiler.getCompiledPredicates(argLen));
1110
1111    return ai;
1112  }
1113
1114  /**
1115   * Analyze a step and give information about it's predicates.  Right now this
1116   * just returns true or false if the step has a predicate.
1117   *
1118   * @param compiler non-null reference to compiler object that has processed
1119   *                 the XPath operations into an opcode map.
1120   * @param opPos The opcode position for the step.
1121   * @param stepType The type of step, one of OP_GROUP, etc.
1122   *
1123   * @return true if step has a predicate.
1124   *
1125   * @throws javax.xml.transform.TransformerException
1126   */
1127  static boolean analyzePredicate(Compiler compiler, int opPos, int stepType)
1128          throws javax.xml.transform.TransformerException
1129  {
1130
1131    int argLen;
1132
1133    switch (stepType)
1134    {
1135    case OpCodes.OP_VARIABLE :
1136    case OpCodes.OP_EXTFUNCTION :
1137    case OpCodes.OP_FUNCTION :
1138    case OpCodes.OP_GROUP :
1139      argLen = compiler.getArgLength(opPos);
1140      break;
1141    default :
1142      argLen = compiler.getArgLengthOfStep(opPos);
1143    }
1144
1145    int pos = compiler.getFirstPredicateOpPos(opPos);
1146    int nPredicates = compiler.countPredicates(pos);
1147
1148    return (nPredicates > 0) ? true : false;
1149  }
1150
1151  /**
1152   * Create the proper Walker from the axes type.
1153   *
1154   * @param compiler non-null reference to compiler object that has processed
1155   *                 the XPath operations into an opcode map.
1156   * @param opPos The opcode position for the step.
1157   * @param lpi The owning location path iterator.
1158   * @param analysis 32 bits of analysis, from which the type of AxesWalker
1159   *                 may be influenced.
1160   *
1161   * @return non-null reference to AxesWalker derivative.
1162   * @throws RuntimeException if the input is bad.
1163   */
1164  private static AxesWalker createDefaultWalker(Compiler compiler, int opPos,
1165          WalkingIterator lpi, int analysis)
1166  {
1167
1168    AxesWalker ai = null;
1169    int stepType = compiler.getOp(opPos);
1170
1171    /*
1172    System.out.println("0: "+compiler.getOp(opPos));
1173    System.out.println("1: "+compiler.getOp(opPos+1));
1174    System.out.println("2: "+compiler.getOp(opPos+2));
1175    System.out.println("3: "+compiler.getOp(opPos+3));
1176    System.out.println("4: "+compiler.getOp(opPos+4));
1177    System.out.println("5: "+compiler.getOp(opPos+5));
1178    */
1179    boolean simpleInit = false;
1180    int totalNumberWalkers = (analysis & BITS_COUNT);
1181    boolean prevIsOneStepDown = true;
1182
1183    switch (stepType)
1184    {
1185    case OpCodes.OP_VARIABLE :
1186    case OpCodes.OP_EXTFUNCTION :
1187    case OpCodes.OP_FUNCTION :
1188    case OpCodes.OP_GROUP :
1189      prevIsOneStepDown = false;
1190
1191      if (DEBUG_WALKER_CREATION)
1192        System.out.println("new walker:  FilterExprWalker: " + analysis
1193                           + ", " + compiler.toString());
1194
1195      ai = new FilterExprWalker(lpi);
1196      simpleInit = true;
1197      break;
1198    case OpCodes.FROM_ROOT :
1199      ai = new AxesWalker(lpi, Axis.ROOT);
1200      break;
1201    case OpCodes.FROM_ANCESTORS :
1202      prevIsOneStepDown = false;
1203      ai = new ReverseAxesWalker(lpi, Axis.ANCESTOR);
1204      break;
1205    case OpCodes.FROM_ANCESTORS_OR_SELF :
1206      prevIsOneStepDown = false;
1207      ai = new ReverseAxesWalker(lpi, Axis.ANCESTORORSELF);
1208      break;
1209    case OpCodes.FROM_ATTRIBUTES :
1210      ai = new AxesWalker(lpi, Axis.ATTRIBUTE);
1211      break;
1212    case OpCodes.FROM_NAMESPACE :
1213      ai = new AxesWalker(lpi, Axis.NAMESPACE);
1214      break;
1215    case OpCodes.FROM_CHILDREN :
1216      ai = new AxesWalker(lpi, Axis.CHILD);
1217      break;
1218    case OpCodes.FROM_DESCENDANTS :
1219      prevIsOneStepDown = false;
1220      ai = new AxesWalker(lpi, Axis.DESCENDANT);
1221      break;
1222    case OpCodes.FROM_DESCENDANTS_OR_SELF :
1223      prevIsOneStepDown = false;
1224      ai = new AxesWalker(lpi, Axis.DESCENDANTORSELF);
1225      break;
1226    case OpCodes.FROM_FOLLOWING :
1227      prevIsOneStepDown = false;
1228      ai = new AxesWalker(lpi, Axis.FOLLOWING);
1229      break;
1230    case OpCodes.FROM_FOLLOWING_SIBLINGS :
1231      prevIsOneStepDown = false;
1232      ai = new AxesWalker(lpi, Axis.FOLLOWINGSIBLING);
1233      break;
1234    case OpCodes.FROM_PRECEDING :
1235      prevIsOneStepDown = false;
1236      ai = new ReverseAxesWalker(lpi, Axis.PRECEDING);
1237      break;
1238    case OpCodes.FROM_PRECEDING_SIBLINGS :
1239      prevIsOneStepDown = false;
1240      ai = new ReverseAxesWalker(lpi, Axis.PRECEDINGSIBLING);
1241      break;
1242    case OpCodes.FROM_PARENT :
1243      prevIsOneStepDown = false;
1244      ai = new ReverseAxesWalker(lpi, Axis.PARENT);
1245      break;
1246    case OpCodes.FROM_SELF :
1247      ai = new AxesWalker(lpi, Axis.SELF);
1248      break;
1249    default :
1250      throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
1251                                 //+ stepType);
1252    }
1253
1254    if (simpleInit)
1255    {
1256      ai.initNodeTest(DTMFilter.SHOW_ALL);
1257    }
1258    else
1259    {
1260      int whatToShow = compiler.getWhatToShow(opPos);
1261
1262      /*
1263      System.out.print("construct: ");
1264      NodeTest.debugWhatToShow(whatToShow);
1265      System.out.println("or stuff: "+(whatToShow & (DTMFilter.SHOW_ATTRIBUTE
1266                             | DTMFilter.SHOW_ELEMENT
1267                             | DTMFilter.SHOW_PROCESSING_INSTRUCTION)));
1268      */
1269      if ((0 == (whatToShow
1270                 & (DTMFilter.SHOW_ATTRIBUTE | DTMFilter.SHOW_NAMESPACE | DTMFilter.SHOW_ELEMENT
1271                    | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) || (whatToShow == DTMFilter.SHOW_ALL))
1272        ai.initNodeTest(whatToShow);
1273      else
1274      {
1275        ai.initNodeTest(whatToShow, compiler.getStepNS(opPos),
1276                        compiler.getStepLocalName(opPos));
1277      }
1278    }
1279
1280    return ai;
1281  }
1282
1283  public static String getAnalysisString(int analysis)
1284  {
1285    StringBuffer buf = new StringBuffer();
1286    buf.append("count: "+getStepCount(analysis)+" ");
1287    if((analysis & BIT_NODETEST_ANY) != 0)
1288    {
1289      buf.append("NTANY|");
1290    }
1291    if((analysis & BIT_PREDICATE) != 0)
1292    {
1293      buf.append("PRED|");
1294    }
1295    if((analysis & BIT_ANCESTOR) != 0)
1296    {
1297      buf.append("ANC|");
1298    }
1299    if((analysis & BIT_ANCESTOR_OR_SELF) != 0)
1300    {
1301      buf.append("ANCOS|");
1302    }
1303    if((analysis & BIT_ATTRIBUTE) != 0)
1304    {
1305      buf.append("ATTR|");
1306    }
1307    if((analysis & BIT_CHILD) != 0)
1308    {
1309      buf.append("CH|");
1310    }
1311    if((analysis & BIT_DESCENDANT) != 0)
1312    {
1313      buf.append("DESC|");
1314    }
1315    if((analysis & BIT_DESCENDANT_OR_SELF) != 0)
1316    {
1317      buf.append("DESCOS|");
1318    }
1319    if((analysis & BIT_FOLLOWING) != 0)
1320    {
1321      buf.append("FOL|");
1322    }
1323    if((analysis & BIT_FOLLOWING_SIBLING) != 0)
1324    {
1325      buf.append("FOLS|");
1326    }
1327    if((analysis & BIT_NAMESPACE) != 0)
1328    {
1329      buf.append("NS|");
1330    }
1331    if((analysis & BIT_PARENT) != 0)
1332    {
1333      buf.append("P|");
1334    }
1335    if((analysis & BIT_PRECEDING) != 0)
1336    {
1337      buf.append("PREC|");
1338    }
1339    if((analysis & BIT_PRECEDING_SIBLING) != 0)
1340    {
1341      buf.append("PRECS|");
1342    }
1343    if((analysis & BIT_SELF) != 0)
1344    {
1345      buf.append(".|");
1346    }
1347    if((analysis & BIT_FILTER) != 0)
1348    {
1349      buf.append("FLT|");
1350    }
1351    if((analysis & BIT_ROOT) != 0)
1352    {
1353      buf.append("R|");
1354    }
1355    return buf.toString();
1356  }
1357
1358  /** Set to true for diagnostics about walker creation */
1359  static final boolean DEBUG_PATTERN_CREATION = false;
1360
1361  /** Set to true for diagnostics about walker creation */
1362  static final boolean DEBUG_WALKER_CREATION = false;
1363
1364  /** Set to true for diagnostics about iterator creation */
1365  static final boolean DEBUG_ITERATOR_CREATION = false;
1366
1367  public static boolean hasPredicate(int analysis)
1368  {
1369    return (0 != (analysis & BIT_PREDICATE));
1370  }
1371
1372  public static boolean isWild(int analysis)
1373  {
1374    return (0 != (analysis & BIT_NODETEST_ANY));
1375  }
1376
1377  public static boolean walksAncestors(int analysis)
1378  {
1379    return isSet(analysis, BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
1380  }
1381
1382  public static boolean walksAttributes(int analysis)
1383  {
1384    return (0 != (analysis & BIT_ATTRIBUTE));
1385  }
1386
1387  public static boolean walksNamespaces(int analysis)
1388  {
1389    return (0 != (analysis & BIT_NAMESPACE));
1390  }
1391
1392  public static boolean walksChildren(int analysis)
1393  {
1394    return (0 != (analysis & BIT_CHILD));
1395  }
1396
1397  public static boolean walksDescendants(int analysis)
1398  {
1399    return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF);
1400  }
1401
1402  public static boolean walksSubtree(int analysis)
1403  {
1404    return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_CHILD);
1405  }
1406
1407  public static boolean walksSubtreeOnlyMaybeAbsolute(int analysis)
1408  {
1409    return walksSubtree(analysis)
1410           && !walksExtraNodes(analysis)
1411           && !walksUp(analysis)
1412           && !walksSideways(analysis)
1413           ;
1414  }
1415
1416  public static boolean walksSubtreeOnly(int analysis)
1417  {
1418    return walksSubtreeOnlyMaybeAbsolute(analysis)
1419           && !isAbsolute(analysis)
1420           ;
1421  }
1422
1423  public static boolean walksFilteredList(int analysis)
1424  {
1425    return isSet(analysis, BIT_FILTER);
1426  }
1427
1428  public static boolean walksSubtreeOnlyFromRootOrContext(int analysis)
1429  {
1430    return walksSubtree(analysis)
1431           && !walksExtraNodes(analysis)
1432           && !walksUp(analysis)
1433           && !walksSideways(analysis)
1434           && !isSet(analysis, BIT_FILTER)
1435           ;
1436  }
1437
1438  public static boolean walksInDocOrder(int analysis)
1439  {
1440    return (walksSubtreeOnlyMaybeAbsolute(analysis)
1441           || walksExtraNodesOnly(analysis)
1442           || walksFollowingOnlyMaybeAbsolute(analysis))
1443           && !isSet(analysis, BIT_FILTER)
1444           ;
1445  }
1446
1447  public static boolean walksFollowingOnlyMaybeAbsolute(int analysis)
1448  {
1449    return isSet(analysis, BIT_SELF | BIT_FOLLOWING_SIBLING | BIT_FOLLOWING)
1450           && !walksSubtree(analysis)
1451           && !walksUp(analysis)
1452           && !walksSideways(analysis)
1453           ;
1454  }
1455
1456  public static boolean walksUp(int analysis)
1457  {
1458    return isSet(analysis, BIT_PARENT | BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
1459  }
1460
1461  public static boolean walksSideways(int analysis)
1462  {
1463    return isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING |
1464                           BIT_PRECEDING | BIT_PRECEDING_SIBLING);
1465  }
1466
1467  public static boolean walksExtraNodes(int analysis)
1468  {
1469    return isSet(analysis, BIT_NAMESPACE | BIT_ATTRIBUTE);
1470  }
1471
1472  public static boolean walksExtraNodesOnly(int analysis)
1473  {
1474    return walksExtraNodes(analysis)
1475           && !isSet(analysis, BIT_SELF)
1476           && !walksSubtree(analysis)
1477           && !walksUp(analysis)
1478           && !walksSideways(analysis)
1479           && !isAbsolute(analysis)
1480           ;
1481  }
1482
1483  public static boolean isAbsolute(int analysis)
1484  {
1485    return isSet(analysis, BIT_ROOT | BIT_FILTER);
1486  }
1487
1488  public static boolean walksChildrenOnly(int analysis)
1489  {
1490    return walksChildren(analysis)
1491           && !isSet(analysis, BIT_SELF)
1492           && !walksExtraNodes(analysis)
1493           && !walksDescendants(analysis)
1494           && !walksUp(analysis)
1495           && !walksSideways(analysis)
1496           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
1497           ;
1498  }
1499
1500  public static boolean walksChildrenAndExtraAndSelfOnly(int analysis)
1501  {
1502    return walksChildren(analysis)
1503           && !walksDescendants(analysis)
1504           && !walksUp(analysis)
1505           && !walksSideways(analysis)
1506           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
1507           ;
1508  }
1509
1510  public static boolean walksDescendantsAndExtraAndSelfOnly(int analysis)
1511  {
1512    return !walksChildren(analysis)
1513           && walksDescendants(analysis)
1514           && !walksUp(analysis)
1515           && !walksSideways(analysis)
1516           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
1517           ;
1518  }
1519
1520  public static boolean walksSelfOnly(int analysis)
1521  {
1522    return isSet(analysis, BIT_SELF)
1523           && !walksSubtree(analysis)
1524           && !walksUp(analysis)
1525           && !walksSideways(analysis)
1526           && !isAbsolute(analysis)
1527           ;
1528  }
1529
1530
1531  public static boolean walksUpOnly(int analysis)
1532  {
1533    return !walksSubtree(analysis)
1534           && walksUp(analysis)
1535           && !walksSideways(analysis)
1536           && !isAbsolute(analysis)
1537           ;
1538  }
1539
1540  public static boolean walksDownOnly(int analysis)
1541  {
1542    return walksSubtree(analysis)
1543           && !walksUp(analysis)
1544           && !walksSideways(analysis)
1545           && !isAbsolute(analysis)
1546           ;
1547  }
1548
1549  public static boolean walksDownExtraOnly(int analysis)
1550  {
1551    return walksSubtree(analysis) &&  walksExtraNodes(analysis)
1552           && !walksUp(analysis)
1553           && !walksSideways(analysis)
1554           && !isAbsolute(analysis)
1555           ;
1556  }
1557
1558  public static boolean canSkipSubtrees(int analysis)
1559  {
1560    return isSet(analysis, BIT_CHILD) | walksSideways(analysis);
1561  }
1562
1563  public static boolean canCrissCross(int analysis)
1564  {
1565    // This could be done faster.  Coded for clarity.
1566    if(walksSelfOnly(analysis))
1567      return false;
1568    else if(walksDownOnly(analysis) && !canSkipSubtrees(analysis))
1569      return false;
1570    else if(walksChildrenAndExtraAndSelfOnly(analysis))
1571      return false;
1572    else if(walksDescendantsAndExtraAndSelfOnly(analysis))
1573      return false;
1574    else if(walksUpOnly(analysis))
1575      return false;
1576    else if(walksExtraNodesOnly(analysis))
1577      return false;
1578    else if(walksSubtree(analysis)
1579           && (walksSideways(analysis)
1580            || walksUp(analysis)
1581            || canSkipSubtrees(analysis)))
1582      return true;
1583    else
1584      return false;
1585  }
1586
1587  /**
1588   * Tell if the pattern can be 'walked' with the iteration steps in natural
1589   * document order, without duplicates.
1590   *
1591   * @param analysis The general analysis of the pattern.
1592   *
1593   * @return true if the walk can be done in natural order.
1594   *
1595   * @throws javax.xml.transform.TransformerException
1596   */
1597  static public boolean isNaturalDocOrder(int analysis)
1598  {
1599    if(canCrissCross(analysis) || isSet(analysis, BIT_NAMESPACE) ||
1600       walksFilteredList(analysis))
1601      return false;
1602
1603    if(walksInDocOrder(analysis))
1604      return true;
1605
1606    return false;
1607  }
1608
1609  /**
1610   * Tell if the pattern can be 'walked' with the iteration steps in natural
1611   * document order, without duplicates.
1612   *
1613   * @param compiler non-null reference to compiler object that has processed
1614   *                 the XPath operations into an opcode map.
1615   * @param stepOpCodePos The opcode position for the step.
1616   * @param stepIndex The top-level step index withing the iterator.
1617   * @param analysis The general analysis of the pattern.
1618   *
1619   * @return true if the walk can be done in natural order.
1620   *
1621   * @throws javax.xml.transform.TransformerException
1622   */
1623  private static boolean isNaturalDocOrder(
1624          Compiler compiler, int stepOpCodePos, int stepIndex, int analysis)
1625            throws javax.xml.transform.TransformerException
1626  {
1627    if(canCrissCross(analysis))
1628      return false;
1629
1630    // Namespaces can present some problems, so just punt if we're looking for
1631    // these.
1632    if(isSet(analysis, BIT_NAMESPACE))
1633      return false;
1634
1635    // The following, preceding, following-sibling, and preceding sibling can
1636    // be found in doc order if we get to this point, but if they occur
1637    // together, they produce
1638    // duplicates, so it's better for us to eliminate this case so we don't
1639    // have to check for duplicates during runtime if we're using a
1640    // WalkingIterator.
1641    if(isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING) &&
1642       isSet(analysis, BIT_PRECEDING | BIT_PRECEDING_SIBLING))
1643      return  false;
1644
1645    // OK, now we have to check for select="@*/axis::*" patterns, which
1646    // can also cause duplicates to happen.  But select="axis*/@::*" patterns
1647    // are OK, as are select="@foo/axis::*" patterns.
1648    // Unfortunately, we can't do this just via the analysis bits.
1649
1650    int stepType;
1651    int stepCount = 0;
1652    boolean foundWildAttribute = false;
1653
1654    // Steps that can traverse anything other than down a
1655    // subtree or that can produce duplicates when used in
1656    // combonation are counted with this variable.
1657    int potentialDuplicateMakingStepCount = 0;
1658
1659    while (OpCodes.ENDOP != (stepType = compiler.getOp(stepOpCodePos)))
1660    {
1661      stepCount++;
1662
1663      switch (stepType)
1664      {
1665      case OpCodes.FROM_ATTRIBUTES :
1666      case OpCodes.MATCH_ATTRIBUTE :
1667        if(foundWildAttribute) // Maybe not needed, but be safe.
1668          return false;
1669
1670        // This doesn't seem to work as a test for wild card.  Hmph.
1671        // int nodeTestType = compiler.getStepTestType(stepOpCodePos);
1672
1673        String localName = compiler.getStepLocalName(stepOpCodePos);
1674        // System.err.println("localName: "+localName);
1675        if(localName.equals("*"))
1676        {
1677          foundWildAttribute = true;
1678        }
1679        break;
1680      case OpCodes.FROM_FOLLOWING :
1681      case OpCodes.FROM_FOLLOWING_SIBLINGS :
1682      case OpCodes.FROM_PRECEDING :
1683      case OpCodes.FROM_PRECEDING_SIBLINGS :
1684      case OpCodes.FROM_PARENT :
1685      case OpCodes.OP_VARIABLE :
1686      case OpCodes.OP_EXTFUNCTION :
1687      case OpCodes.OP_FUNCTION :
1688      case OpCodes.OP_GROUP :
1689      case OpCodes.FROM_NAMESPACE :
1690      case OpCodes.FROM_ANCESTORS :
1691      case OpCodes.FROM_ANCESTORS_OR_SELF :
1692      case OpCodes.MATCH_ANY_ANCESTOR :
1693      case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
1694      case OpCodes.FROM_DESCENDANTS_OR_SELF :
1695      case OpCodes.FROM_DESCENDANTS :
1696        if(potentialDuplicateMakingStepCount > 0)
1697            return false;
1698        potentialDuplicateMakingStepCount++;
1699      case OpCodes.FROM_ROOT :
1700      case OpCodes.FROM_CHILDREN :
1701      case OpCodes.FROM_SELF :
1702        if(foundWildAttribute)
1703          return false;
1704        break;
1705      default :
1706        throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
1707                                  // + stepType);
1708      }
1709
1710      int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
1711
1712      if (nextStepOpCodePos < 0)
1713        break;
1714
1715      stepOpCodePos = nextStepOpCodePos;
1716    }
1717
1718    return true;
1719  }
1720
1721  public static boolean isOneStep(int analysis)
1722  {
1723    return (analysis & BITS_COUNT) == 0x00000001;
1724  }
1725
1726  public static int getStepCount(int analysis)
1727  {
1728    return (analysis & BITS_COUNT);
1729  }
1730
1731  /**
1732   * First 8 bits are the number of top-level location steps.  Hopefully
1733   *  there will never be more that 255 location steps!!!
1734   */
1735  public static final int BITS_COUNT = 0x000000FF;
1736
1737  /** 4 bits are reserved for future use. */
1738  public static final int BITS_RESERVED = 0x00000F00;
1739
1740  /** Bit is on if the expression contains a top-level predicate. */
1741  public static final int BIT_PREDICATE = (0x00001000);
1742
1743  /** Bit is on if any of the walkers contain an ancestor step. */
1744  public static final int BIT_ANCESTOR = (0x00001000 << 1);
1745
1746  /** Bit is on if any of the walkers contain an ancestor-or-self step. */
1747  public static final int BIT_ANCESTOR_OR_SELF = (0x00001000 << 2);
1748
1749  /** Bit is on if any of the walkers contain an attribute step. */
1750  public static final int BIT_ATTRIBUTE = (0x00001000 << 3);
1751
1752  /** Bit is on if any of the walkers contain a child step. */
1753  public static final int BIT_CHILD = (0x00001000 << 4);
1754
1755  /** Bit is on if any of the walkers contain a descendant step. */
1756  public static final int BIT_DESCENDANT = (0x00001000 << 5);
1757
1758  /** Bit is on if any of the walkers contain a descendant-or-self step. */
1759  public static final int BIT_DESCENDANT_OR_SELF = (0x00001000 << 6);
1760
1761  /** Bit is on if any of the walkers contain a following step. */
1762  public static final int BIT_FOLLOWING = (0x00001000 << 7);
1763
1764  /** Bit is on if any of the walkers contain a following-sibiling step. */
1765  public static final int BIT_FOLLOWING_SIBLING = (0x00001000 << 8);
1766
1767  /** Bit is on if any of the walkers contain a namespace step. */
1768  public static final int BIT_NAMESPACE = (0x00001000 << 9);
1769
1770  /** Bit is on if any of the walkers contain a parent step. */
1771  public static final int BIT_PARENT = (0x00001000 << 10);
1772
1773  /** Bit is on if any of the walkers contain a preceding step. */
1774  public static final int BIT_PRECEDING = (0x00001000 << 11);
1775
1776  /** Bit is on if any of the walkers contain a preceding-sibling step. */
1777  public static final int BIT_PRECEDING_SIBLING = (0x00001000 << 12);
1778
1779  /** Bit is on if any of the walkers contain a self step. */
1780  public static final int BIT_SELF = (0x00001000 << 13);
1781
1782  /**
1783   * Bit is on if any of the walkers contain a filter (i.e. id(), extension
1784   *  function, etc.) step.
1785   */
1786  public static final int BIT_FILTER = (0x00001000 << 14);
1787
1788  /** Bit is on if any of the walkers contain a root step. */
1789  public static final int BIT_ROOT = (0x00001000 << 15);
1790
1791  /**
1792   * If any of these bits are on, the expression may likely traverse outside
1793   *  the given subtree.
1794   */
1795  public static final int BITMASK_TRAVERSES_OUTSIDE_SUBTREE = (BIT_NAMESPACE  // ??
1796                                                                | BIT_PRECEDING_SIBLING
1797                                                                | BIT_PRECEDING
1798                                                                | BIT_FOLLOWING_SIBLING
1799                                                                | BIT_FOLLOWING
1800                                                                | BIT_PARENT  // except parent of attrs.
1801                                                                | BIT_ANCESTOR_OR_SELF
1802                                                                | BIT_ANCESTOR
1803                                                                | BIT_FILTER
1804                                                                | BIT_ROOT);
1805
1806  /**
1807   * Bit is on if any of the walkers can go backwards in document
1808   *  order from the context node.
1809   */
1810  public static final int BIT_BACKWARDS_SELF = (0x00001000 << 16);
1811
1812  /** Found "//foo" pattern */
1813  public static final int BIT_ANY_DESCENDANT_FROM_ROOT = (0x00001000 << 17);
1814
1815  /**
1816   * Bit is on if any of the walkers contain an node() test.  This is
1817   *  really only useful if the count is 1.
1818   */
1819  public static final int BIT_NODETEST_ANY = (0x00001000 << 18);
1820
1821  // can't go higher than 18!
1822
1823  /** Bit is on if the expression is a match pattern. */
1824  public static final int BIT_MATCH_PATTERN = (0x00001000 << 19);
1825}
1826