/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:  
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written 
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, Lotus
 * Development Corporation., http://www.lotus.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
package org.apache.xpath.axes;

import javax.xml.transform.TransformerException;
import org.apache.xalan.res.XSLMessages;
import org.apache.xml.dtm.Axis;
import org.apache.xml.dtm.DTMFilter;
import org.apache.xml.dtm.DTMIterator;
import org.apache.xpath.Expression;
import org.apache.xpath.functions.FuncLast;
import org.apache.xpath.functions.FuncPosition;
import org.apache.xpath.functions.Function;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.operations.Variable;
import org.apache.xpath.parser.Node;
import org.apache.xpath.parser.NodeTest;
import org.apache.xpath.parser.PathExpr;
import org.apache.xpath.parser.PatternAxis;
import org.apache.xpath.parser.Predicates;
import org.apache.xpath.parser.StepExpr;
import org.apache.xpath.res.XPATHErrorResources;

public class WalkerFactory
{
  public static boolean isSet(int analysis, int bits)
  {
    return (0 != (analysis & bits));
  }

  /**
   * Get a corresponding BIT_XXX from an axis.
   * @param axis One of Axis.ANCESTOR, etc.
   * @return One of BIT_ANCESTOR, etc.
   */
  static public int getAnalysisBitFromAxes(int axis)
  {
    switch (axis) // Generate new traverser
    {
      case Axis.ANCESTOR :
        return BIT_ANCESTOR;
      case Axis.ANCESTORORSELF :
        return BIT_ANCESTOR_OR_SELF;
      case Axis.ATTRIBUTE :
        return BIT_ATTRIBUTE;
      case Axis.CHILD :
        return BIT_CHILD;
      case Axis.DESCENDANT :
        return BIT_DESCENDANT;
      case Axis.DESCENDANTORSELF :
        return BIT_DESCENDANT_OR_SELF;
      case Axis.FOLLOWING :
        return BIT_FOLLOWING;
      case Axis.FOLLOWINGSIBLING :
        return BIT_FOLLOWING_SIBLING;
      case Axis.NAMESPACE :
      case Axis.NAMESPACEDECLS :
        return BIT_NAMESPACE;
      case Axis.PARENT :
        return BIT_PARENT;
      case Axis.PRECEDING :
        return BIT_PRECEDING;
      case Axis.PRECEDINGSIBLING :
        return BIT_PRECEDING_SIBLING;
      case Axis.SELF :
        return BIT_SELF;
      case Axis.ALLFROMNODE :
        return BIT_DESCENDANT_OR_SELF;
        // case Axis.PRECEDINGANDANCESTOR :
      case Axis.DESCENDANTSFROMROOT :
      case Axis.ALL :
      case Axis.DESCENDANTSORSELFFROMROOT :
        return BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_ANY_DESCENDANT_FROM_ROOT;
      case Axis.ROOT :
        return BIT_ROOT;
      case Axis.FILTEREDLIST :
        return BIT_FILTER;
      default :
        return BIT_FILTER;
    }
  }

  /**
   * Tell if the given axis goes downword.  Bogus name, if you can think of 
   * a better one, please do tell.  This really has to do with inverting 
   * attribute axis.
   * @param axis One of Axis.XXX.
   * @return true if the axis is not a child axis and does not go up from 
   * the axis root.
   */
  public static boolean isDownwardAxisOfMany(int axis)
  {
    return (
      (Axis.DESCENDANTORSELF == axis)
      || (Axis.DESCENDANT == axis)
      || (Axis.FOLLOWING == axis)
    //          || (Axis.FOLLOWINGSIBLING == axis) 
    || (Axis.PRECEDING == axis)
    //          || (Axis.PRECEDINGSIBLING == axis)
    );
  }

  /**
   * First 8 bits are the number of top-level location steps.  Hopefully
   *  there will never be more that 255 location steps!!!
   */
  public static final int BITS_COUNT = 0x000000FF;

  /** 4 bits are reserved for future use. */
  public static final int BITS_RESERVED = 0x00000F00;

  /** Bit is on if the expression contains a top-level predicate. */
  public static final int BIT_PREDICATE = (0x00001000);

  /** Bit is on if any of the walkers contain an ancestor step. */
  public static final int BIT_ANCESTOR = (0x00001000 << 1);

  /** Bit is on if any of the walkers contain an ancestor-or-self step. */
  public static final int BIT_ANCESTOR_OR_SELF = (0x00001000 << 2);

  /** Bit is on if any of the walkers contain an attribute step. */
  public static final int BIT_ATTRIBUTE = (0x00001000 << 3);

  /** Bit is on if any of the walkers contain a child step. */
  public static final int BIT_CHILD = (0x00001000 << 4);

  /** Bit is on if any of the walkers contain a descendant step. */
  public static final int BIT_DESCENDANT = (0x00001000 << 5);

  /** Bit is on if any of the walkers contain a descendant-or-self step. */
  public static final int BIT_DESCENDANT_OR_SELF = (0x00001000 << 6);

  /** Bit is on if any of the walkers contain a following step. */
  public static final int BIT_FOLLOWING = (0x00001000 << 7);

  /** Bit is on if any of the walkers contain a following-sibiling step. */
  public static final int BIT_FOLLOWING_SIBLING = (0x00001000 << 8);

  /** Bit is on if any of the walkers contain a namespace step. */
  public static final int BIT_NAMESPACE = (0x00001000 << 9);

  /** Bit is on if any of the walkers contain a parent step. */
  public static final int BIT_PARENT = (0x00001000 << 10);

  /** Bit is on if any of the walkers contain a preceding step. */
  public static final int BIT_PRECEDING = (0x00001000 << 11);

  /** Bit is on if any of the walkers contain a preceding-sibling step. */
  public static final int BIT_PRECEDING_SIBLING = (0x00001000 << 12);

  /** Bit is on if any of the walkers contain a self step. */
  public static final int BIT_SELF = (0x00001000 << 13);

  /**
   * Bit is on if any of the walkers contain a filter (i.e. id(), extension
   *  function, etc.) step.
   */
  public static final int BIT_FILTER = (0x00001000 << 14);

  /** Bit is on if any of the walkers contain a root step. */
  public static final int BIT_ROOT = (0x00001000 << 15);

  /**
   * If any of these bits are on, the expression may likely traverse outside
   *  the given subtree.
   */
    public static final int BITMASK_TRAVERSES_OUTSIDE_SUBTREE =
      (BIT_NAMESPACE // ??
    | BIT_PRECEDING_SIBLING
    | BIT_PRECEDING
    | BIT_FOLLOWING_SIBLING
    | BIT_FOLLOWING
    | BIT_PARENT // except parent of attrs.
  | BIT_ANCESTOR_OR_SELF | BIT_ANCESTOR | BIT_FILTER | BIT_ROOT);

  /**
   * Bit is on if any of the walkers can go backwards in document
   *  order from the context node.
   */
  public static final int BIT_BACKWARDS_SELF = (0x00001000 << 16);

  /** Found "//foo" pattern */
  public static final int BIT_ANY_DESCENDANT_FROM_ROOT = (0x00001000 << 17);

  /**
   * Bit is on if any of the walkers contain an node() test.  This is
   *  really only useful if the count is 1.
   */
  public static final int BIT_NODETEST_ANY = (0x00001000 << 18);

  // can't go higher than 18!

  /** Bit is on if the expression is a match pattern. */
  public static final int BIT_MATCH_PATTERN = (0x00001000 << 19);

  /**
   * Analyze a step and give information about it's predicates.  Right now this
   * just returns true or false if the step has a predicate.
   *
   * @param compiler non-null reference to compiler object that has processed
   *                 the XPath operations into an opcode map.
   * @param opPos The opcode position for the step.
   * @param stepType The type of step, one of OP_GROUP, etc.
   *
   * @return true if step has a predicate.
   *
   * @throws javax.xml.transform.TransformerException
   */
  static boolean analyzePredicate(StepExpr stepExpr)
    throws javax.xml.transform.TransformerException
  {

    int childCount = stepExpr.jjtGetNumChildren();
    Node lastChild = stepExpr.jjtGetChild(childCount - 1);
    if (lastChild instanceof Predicates)
    {
      if (lastChild.jjtGetNumChildren() > 0)
      {
        return true;
      }
    }
    return false;
  }

  /**
   * Analyze the location path and return 32 bits that give information about
   * the location path as a whole.  See the BIT_XXX constants for meaning about
   * each of the bits.
   *
   * @param compiler non-null reference to compiler object that has processed
   *                 the XPath operations into an opcode map.
   * @param stepOpCodePos The opcode position for the step.
   * @param stepIndex The top-level step index withing the iterator.
   *
   * @return 32 bits as an integer that give information about the location
   * path as a whole.
   *
   * @throws javax.xml.transform.TransformerException
   */
  private static int analyze(PathExpr pathExpr, int stepIndex)
    throws javax.xml.transform.TransformerException
  {
    int numSteps = pathExpr.jjtGetNumChildren();
    int analysisResult = 0x00000000; // 32 bits of analysis

    for (int i = stepIndex; i < numSteps; i++)
    {
      StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(i);

      boolean predAnalysis = analyzePredicate(stepExpr);

      if (predAnalysis)
        analysisResult |= BIT_PREDICATE;

      Node firstChild = stepExpr.jjtGetChild(0);
      if (firstChild instanceof PatternAxis)
      {
        int axis = ((PatternAxis) firstChild).getAxis();
        switch (axis)
        {
          case Axis.ROOT :
            analysisResult |= BIT_ROOT;
            break;
          case Axis.DESCENDANTSORSELFFROMROOT :
          case Axis.DESCENDANTSFROMROOT :
            analysisResult |= (BIT_ROOT | BIT_ANY_DESCENDANT_FROM_ROOT);
            break;
          case Axis.ANCESTOR :
            analysisResult |= BIT_ANCESTOR;
            break;
          case Axis.ANCESTORORSELF :
            analysisResult |= BIT_ANCESTOR_OR_SELF;
            break;
          case Axis.ATTRIBUTE :
            analysisResult |= BIT_ATTRIBUTE;
            break;
          case Axis.NAMESPACE :
            analysisResult |= BIT_NAMESPACE;
            break;
          case Axis.CHILD :
            analysisResult |= BIT_CHILD;
            break;
          case Axis.DESCENDANT :
            analysisResult |= BIT_DESCENDANT;
            break;
          case Axis.DESCENDANTORSELF :
            analysisResult |= BIT_DESCENDANT_OR_SELF;
            break;
          case Axis.FOLLOWING :
            analysisResult |= BIT_FOLLOWING;
            break;
          case Axis.FOLLOWINGSIBLING :
            analysisResult |= BIT_FOLLOWING_SIBLING;
            break;
          case Axis.PRECEDING :
            analysisResult |= BIT_PRECEDING;
            break;
          case Axis.PRECEDINGSIBLING :
            analysisResult |= BIT_PRECEDING_SIBLING;
            break;
          case Axis.PARENT :
            analysisResult |= BIT_PARENT;
            break;
          case Axis.SELF :
            analysisResult |= BIT_SELF;
            break;
          default :
            // TBD: Change the wording of this expression.
            throw new RuntimeException(
              XSLMessages.createXPATHMessage(
                XPATHErrorResources.ER_NULL_ERROR_HANDLER,
                new Object[] { firstChild.getClass().getName()}));
            //"Programmer's assertion: unknown opcode: "
            //+ stepType);
        }
        Node secondChild = stepExpr.jjtGetChild(1);
        if (secondChild instanceof org.apache.xpath.parser.NodeTest)
        {
          org.apache.xpath.parser.NodeTest nt =
            (org.apache.xpath.parser.NodeTest) secondChild;
          if (nt.getWhatToShow() == org.apache.xml.dtm.DTMFilter.SHOW_ALL)
          {
            analysisResult |= BIT_NODETEST_ANY;
          }
        }

      }
      else
      {
        analysisResult |= BIT_FILTER;
      }

    }

    analysisResult |= (numSteps & BITS_COUNT);

    return analysisResult;
  }

  /**
   * Create a new LocPathIterator iterator.  The exact type of iterator
   * returned is based on an analysis of the XPath operations.
   *
   * @param compiler non-null reference to compiler object that has processed
   *                 the XPath operations into an opcode map.
   * @param opPos The position of the operation code for this itterator.
   *
   * @return non-null reference to a LocPathIterator or derivative.
   *
   * @throws javax.xml.transform.TransformerException
   */
  public static DTMIterator newDTMIterator(
    PathExpr pathExpr,
    boolean isTopLevel)
    throws javax.xml.transform.TransformerException
  {

    int analysis = analyze(pathExpr, 0);
    boolean isOneStep = isOneStep(analysis);
    DTMIterator iter = getPossibleUnion(pathExpr, isTopLevel, isOneStep);
    
    if(null != iter)
      return iter;
    
    // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
    if (isOneStep
      && walksSelfOnly(analysis)
      && isWild(analysis)
      && !hasPredicate(analysis))
    {
      if (DEBUG_ITERATOR_CREATION)
        diagnoseIterator("SelfIteratorNoPredicate", analysis, pathExpr);

      // Then use a simple iteration of the attributes, with node test 
      // and predicate testing.
      iter = new SelfIteratorNoPredicate();
    }
    // Is the iteration exactly one child step?
    else
      if (walksChildrenOnly(analysis) && isOneStep)
      {

        // Does the pattern specify *any* child with no predicate? (i.e. select="child::node()".
        if (isWild(analysis) && !hasPredicate(analysis))
        {
          if (DEBUG_ITERATOR_CREATION)
            diagnoseIterator("ChildIterator", analysis, pathExpr);

          // Use simple child iteration without any test.
          StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
          iter = new ChildIterator(stepExpr, analysis);
        }
        else
        {
          if (DEBUG_ITERATOR_CREATION)
            diagnoseIterator("ChildTestIterator", analysis, pathExpr);

          // Else use simple node test iteration with predicate test.
          StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
          iter = new ChildTestIterator(stepExpr, analysis);
        }
      }
    // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
    else
      if (isOneStep && walksAttributes(analysis))
      {
        if (DEBUG_ITERATOR_CREATION)
          diagnoseIterator("AttributeIterator", analysis, pathExpr);

        // Then use a simple iteration of the attributes, with node test 
        // and predicate testing.
        StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
        iter = new AttributeIterator(stepExpr, analysis);
      }
      else
        if (isOneStep && !walksFilteredList(analysis))
        {
          StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
          if (!walksNamespaces(analysis)
            && (walksInDocOrder(analysis) || isSet(analysis, BIT_PARENT)))
          {
            if (false || DEBUG_ITERATOR_CREATION)
              diagnoseIterator("OneStepIteratorForward", analysis, pathExpr);

            // Then use a simple iteration of the attributes, with node test 
            // and predicate testing.
            iter = new OneStepIteratorForward(stepExpr, analysis);
          }
          else
          {
            if (false || DEBUG_ITERATOR_CREATION)
              diagnoseIterator("OneStepIterator", analysis, pathExpr);

            // Then use a simple iteration of the attributes, with node test 
            // and predicate testing.
            iter = new OneStepIterator(stepExpr, analysis);
          }
        }

    // Analysis of "//center":
    // bits: 1001000000001010000000000000011
    // count: 3
    // root
    // child:node()
    // BIT_DESCENDANT_OR_SELF
    // It's highly possible that we should have a seperate bit set for 
    // "//foo" patterns.
    // For at least the time being, we can't optimize patterns like 
    // "//table[3]", because this has to be analyzed as 
    // "/descendant-or-self::node()/table[3]" in order for the indexes 
    // to work right.
    else
      if (isOptimizableForDescendantIterator(pathExpr,
        0) // && getStepCount(analysis) <= 3 
      // && walksDescendants(analysis) 
      // && walksSubtreeOnlyFromRootOrContext(analysis)
      )
      {
        if (DEBUG_ITERATOR_CREATION)
          diagnoseIterator("DescendantIterator", analysis, pathExpr);
        StepExpr stepExpr;
        if (pathExpr.jjtGetNumChildren() == 2)
        {
          stepExpr = (StepExpr) pathExpr.jjtGetChild(1);
          PatternAxis axisExpr = stepExpr.getAxisExpr();
          axisExpr.setAxis(org.apache.xml.dtm.Axis.DESCENDANTSFROMROOT);
        }
        else
          stepExpr = (StepExpr) pathExpr.jjtGetChild(0);
        iter = new DescendantIterator(stepExpr);
      }
      else
      {
        if (isNaturalDocOrder(pathExpr, 0, analysis))
        {
          if (false || DEBUG_ITERATOR_CREATION)
          {
            diagnoseIterator("WalkingIterator", analysis, pathExpr);
          }

          iter =
            new WalkingIterator(
              pathExpr.getParser().getPrefixResolver(),
              pathExpr);
        }
        else
        {
          //        if (DEBUG_ITERATOR_CREATION)
          //          diagnoseIterator("MatchPatternIterator", analysis, compiler);
          //
          //        return new MatchPatternIterator(compiler, opPos, analysis);
          if (DEBUG_ITERATOR_CREATION)
            diagnoseIterator("WalkingIteratorSorted", analysis, pathExpr);

          iter =
            new WalkingIteratorSorted(
              pathExpr.getParser().getPrefixResolver(),
              pathExpr);
        }
      }
    if (iter instanceof LocPathIterator)
       ((LocPathIterator) iter).setIsTopLevel(isTopLevel);

    return iter;
  }

  /**
   * Check to see if we have a UnionPathIterator contained by a 
   * StepExpr and possibly a predicate, contained in a PathExpr.
   * If this is the case, we just want the UnionPathIterator and 
   * any predicates it may have.
   * It's likely that this reduction should be done somewhere else.
   * 
   * @param pathExpr The path construction node that holds the subtree.
   * @param isTopLevel True if this expression is at the top-level.
   * @param isOneStep True if this expression only has one step.
   * @return DTMIterator The reduced union iterator, or null if not a union.
   * @throws TransformerException
   */
  private static DTMIterator getPossibleUnion(
    PathExpr pathExpr,
    boolean isTopLevel,
    boolean isOneStep)
    throws TransformerException
  {
    Node n;
    if(isOneStep && 
      (n = pathExpr.jjtGetChild(0).jjtGetChild(0)) instanceof UnionPathIterator)
    {
      UnionPathIterator upi = (UnionPathIterator)n;
      StepExpr se = (StepExpr)pathExpr.jjtGetChild(0);
      
      upi.initPredicateInfo(se);
      upi.setWhatToShow(DTMFilter.SHOW_ALL);
        
      upi.setIsTopLevel(isTopLevel);
      return upi;
    }
    else
      return null;
  }

  public static void diagnoseIterator(
    String name,
    int analysis,
    PathExpr pathExpr)
  {
    System.out.println(
      pathExpr.toString()
        + ", "
        + name
        + ", "
        + Integer.toBinaryString(analysis)
        + ", "
        + getAnalysisString(analysis));
  }

  public static String getAnalysisString(int analysis)
  {
    StringBuffer buf = new StringBuffer();
    buf.append("count: " + getStepCount(analysis) + " ");
    if ((analysis & BIT_NODETEST_ANY) != 0)
    {
      buf.append("NTANY|");
    }
    if ((analysis & BIT_PREDICATE) != 0)
    {
      buf.append("PRED|");
    }
    if ((analysis & BIT_ANCESTOR) != 0)
    {
      buf.append("ANC|");
    }
    if ((analysis & BIT_ANCESTOR_OR_SELF) != 0)
    {
      buf.append("ANCOS|");
    }
    if ((analysis & BIT_ATTRIBUTE) != 0)
    {
      buf.append("ATTR|");
    }
    if ((analysis & BIT_CHILD) != 0)
    {
      buf.append("CH|");
    }
    if ((analysis & BIT_DESCENDANT) != 0)
    {
      buf.append("DESC|");
    }
    if ((analysis & BIT_DESCENDANT_OR_SELF) != 0)
    {
      buf.append("DESCOS|");
    }
    if ((analysis & BIT_FOLLOWING) != 0)
    {
      buf.append("FOL|");
    }
    if ((analysis & BIT_FOLLOWING_SIBLING) != 0)
    {
      buf.append("FOLS|");
    }
    if ((analysis & BIT_NAMESPACE) != 0)
    {
      buf.append("NS|");
    }
    if ((analysis & BIT_PARENT) != 0)
    {
      buf.append("P|");
    }
    if ((analysis & BIT_PRECEDING) != 0)
    {
      buf.append("PREC|");
    }
    if ((analysis & BIT_PRECEDING_SIBLING) != 0)
    {
      buf.append("PRECS|");
    }
    if ((analysis & BIT_SELF) != 0)
    {
      buf.append(".|");
    }
    if ((analysis & BIT_FILTER) != 0)
    {
      buf.append("FLT|");
    }
    if ((analysis & BIT_ROOT) != 0)
    {
      buf.append("R|");
    }
    return buf.toString();
  }

  /** Set to true for diagnostics about walker creation */
  static final boolean DEBUG_PATTERN_CREATION = false;

  /** Set to true for diagnostics about walker creation */
  static final boolean DEBUG_WALKER_CREATION = false;

  /** Set to true for diagnostics about iterator creation */
  static final boolean DEBUG_ITERATOR_CREATION = false;

  public static boolean hasPredicate(int analysis)
  {
    return (0 != (analysis & BIT_PREDICATE));
  }

  public static boolean isWild(int analysis)
  {
    return (0 != (analysis & BIT_NODETEST_ANY));
  }

  public static boolean walksAncestors(int analysis)
  {
    return isSet(analysis, BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
  }

  public static boolean walksAttributes(int analysis)
  {
    return (0 != (analysis & BIT_ATTRIBUTE));
  }

  public static boolean walksNamespaces(int analysis)
  {
    return (0 != (analysis & BIT_NAMESPACE));
  }

  public static boolean walksChildren(int analysis)
  {
    return (0 != (analysis & BIT_CHILD));
  }

  public static boolean walksDescendants(int analysis)
  {
    return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_ANY_DESCENDANT_FROM_ROOT);
  }

  public static boolean walksSubtree(int analysis)
  {
    return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_CHILD);
  }

  public static boolean walksSubtreeOnlyMaybeAbsolute(int analysis)
  {
    return walksSubtree(analysis)
      && !walksExtraNodes(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis);
  }

  public static boolean walksSubtreeOnly(int analysis)
  {
    return walksSubtreeOnlyMaybeAbsolute(analysis) && !isAbsolute(analysis);
  }

  public static boolean walksFilteredList(int analysis)
  {
    return isSet(analysis, BIT_FILTER);
  }

  public static boolean walksSubtreeOnlyFromRootOrContext(int analysis)
  {
    return walksSubtree(analysis)
      && !walksExtraNodes(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis)
      && !isSet(analysis, BIT_FILTER);
  }

  public static boolean walksInDocOrder(int analysis)
  {
    return (
      walksSubtreeOnlyMaybeAbsolute(analysis)
        || walksExtraNodesOnly(analysis)
        || walksFollowingOnlyMaybeAbsolute(analysis))
      && !isSet(analysis, BIT_FILTER);
  }

  public static boolean walksFollowingOnlyMaybeAbsolute(int analysis)
  {
    return isSet(analysis, BIT_SELF | BIT_FOLLOWING_SIBLING | BIT_FOLLOWING)
      && !walksSubtree(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis);
  }

  public static boolean walksUp(int analysis)
  {
    return isSet(analysis, BIT_PARENT | BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
  }

  public static boolean walksSideways(int analysis)
  {
    return isSet(
      analysis,
      BIT_FOLLOWING
        | BIT_FOLLOWING_SIBLING
        | BIT_PRECEDING
        | BIT_PRECEDING_SIBLING);
  }

  public static boolean walksExtraNodes(int analysis)
  {
    return isSet(analysis, BIT_NAMESPACE | BIT_ATTRIBUTE);
  }

  public static boolean walksExtraNodesOnly(int analysis)
  {
    return walksExtraNodes(analysis)
      && !isSet(analysis, BIT_SELF)
      && !walksSubtree(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis)
      && !isAbsolute(analysis);
  }

  public static boolean isAbsolute(int analysis)
  {
    return isSet(analysis, BIT_ROOT | BIT_FILTER);
  }

  public static boolean walksChildrenOnly(int analysis)
  {
    return walksChildren(analysis)
      && !isSet(analysis, BIT_SELF)
      && !walksExtraNodes(analysis)
      && !walksDescendants(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis)
      && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT));
  }

  public static boolean walksChildrenAndExtraAndSelfOnly(int analysis)
  {
    return walksChildren(analysis)
      && !walksDescendants(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis)
      && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT));
  }

  public static boolean walksDescendantsAndExtraAndSelfOnly(int analysis)
  {
    return !walksChildren(analysis)
      && walksDescendants(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis)
      && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT));
  }

  public static boolean walksSelfOnly(int analysis)
  {
    return isSet(analysis, BIT_SELF)
      && !walksSubtree(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis)
      && !isAbsolute(analysis);
  }

  public static boolean walksUpOnly(int analysis)
  {
    return !walksSubtree(analysis)
      && walksUp(analysis)
      && !walksSideways(analysis)
      && !isAbsolute(analysis);
  }

  public static boolean walksDownOnly(int analysis)
  {
    return walksSubtree(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis)
      && !isAbsolute(analysis);
  }

  public static boolean walksDownExtraOnly(int analysis)
  {
    return walksSubtree(analysis)
      && walksExtraNodes(analysis)
      && !walksUp(analysis)
      && !walksSideways(analysis)
      && !isAbsolute(analysis);
  }

  public static boolean canSkipSubtrees(int analysis)
  {
    return isSet(analysis, BIT_CHILD) | walksSideways(analysis);
  }

  public static boolean canCrissCross(int analysis)
  {
    // This could be done faster.  Coded for clarity.
    if (walksSelfOnly(analysis))
      return false;
    else
      if (walksDownOnly(analysis) && !canSkipSubtrees(analysis))
        return false;
      else
        if (walksChildrenAndExtraAndSelfOnly(analysis))
          return false;
        else
          if (walksDescendantsAndExtraAndSelfOnly(analysis))
            return false;
          else
            if (walksUpOnly(analysis))
              return false;
            else
              if (walksExtraNodesOnly(analysis))
                return false;
              else
                if (walksSubtree(analysis)
                  && (walksSideways(analysis)
                    || walksUp(analysis)
                    || canSkipSubtrees(analysis)))
                  return true;
                else
                  return false;
  }

  /**
   * Tell if the pattern can be 'walked' with the iteration steps in natural 
   * document order, without duplicates.
   *
   * @param analysis The general analysis of the pattern.
   *
   * @return true if the walk can be done in natural order.
   *
   * @throws javax.xml.transform.TransformerException
   */
  static public boolean isNaturalDocOrder(int analysis)
  {
    if (canCrissCross(analysis)
      || isSet(analysis, BIT_NAMESPACE)
      || walksFilteredList(analysis))
      return false;

    if (walksInDocOrder(analysis))
      return true;

    return false;
  }

  public static boolean isOneStep(int analysis)
  {
    return (analysis & BITS_COUNT) == 0x00000001;
  }

  public static int getStepCount(int analysis)
  {
    return (analysis & BITS_COUNT);
  }

  /**
   * Tell if the pattern can be 'walked' with the iteration steps in natural 
   * document order, without duplicates.
   *
   * @param pathExpr Root of the path expression being analyzed.
   * @param stepIndex The top-level step index withing the iterator.
   * @param analysis The general analysis of the pattern.
   *
   * @return true if the walk can be done in natural order.
   *
   * @throws javax.xml.transform.TransformerException
   */
  private static boolean isNaturalDocOrder(
    PathExpr pathExpr,
    int stepIndex,
    int analysis)
    throws javax.xml.transform.TransformerException
  {
    if (canCrissCross(analysis))
      return false;

    // Namespaces can present some problems, so just punt if we're looking for 
    // these.
    if (isSet(analysis, BIT_NAMESPACE))
      return false;

    // The following, preceding, following-sibling, and preceding sibling can 
    // be found in doc order if we get to this point, but if they occur 
    // together, they produce 
    // duplicates, so it's better for us to eliminate this case so we don't 
    // have to check for duplicates during runtime if we're using a 
    // WalkingIterator.
    if (isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING)
      && isSet(analysis, BIT_PRECEDING | BIT_PRECEDING_SIBLING))
      return false;

    // OK, now we have to check for select="@*/axis::*" patterns, which 
    // can also cause duplicates to happen.  But select="axis*/@::*" patterns 
    // are OK, as are select="@foo/axis::*" patterns.
    // Unfortunately, we can't do this just via the analysis bits.

    int stepType;
    boolean foundWildAttribute = false;

    // Steps that can traverse anything other than down a 
    // subtree or that can produce duplicates when used in 
    // combonation are counted with this variable.
    int potentialDuplicateMakingStepCount = 0;

    int numSteps = pathExpr.jjtGetNumChildren();

    for (int i = 0; i < numSteps; i++)
    {
      StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(stepIndex);

      Node firstChild = stepExpr.jjtGetChild(0);
      if (firstChild instanceof PatternAxis)
      {
        Node secondChild = stepExpr.jjtGetChild(1);
        org.apache.xpath.parser.NodeTest nt;
        boolean isTotallyWild;

        if (secondChild instanceof org.apache.xpath.parser.NodeTest)
        {
          nt = (org.apache.xpath.parser.NodeTest) secondChild;
          isTotallyWild = nt.isTotallyWild();
          // Double check.
          if (0
            != (nt.getWhatToShow() | org.apache.xml.dtm.DTMFilter.SHOW_ALL))
          {
            isTotallyWild = true;
          }
        }
        else
        {
          isTotallyWild = false;
          nt = null;
        }

        int axis = ((PatternAxis) firstChild).getAxis();
        switch (axis)
        {
          case Axis.NAMESPACE :
          case Axis.ATTRIBUTE :
            if (foundWildAttribute) // Maybe not needed, but be safe.
              return false;
            if (isTotallyWild)
              foundWildAttribute = true;
            break;
          case Axis.DESCENDANTSFROMROOT :
          case Axis.DESCENDANTSORSELFFROMROOT :
          case Axis.ANCESTOR :
          case Axis.ANCESTORORSELF :
          case Axis.DESCENDANT :
          case Axis.DESCENDANTORSELF :
          case Axis.FOLLOWING :
          case Axis.FOLLOWINGSIBLING :
          case Axis.PRECEDING :
          case Axis.PRECEDINGSIBLING :
          case Axis.PARENT :
            if (potentialDuplicateMakingStepCount > 0)
              return false;
            potentialDuplicateMakingStepCount++;
          case Axis.ROOT :
          case Axis.CHILD :
          case Axis.SELF :
            if (foundWildAttribute)
              return false;
            break;
          default :
            // TBD: Change the wording of this expression.
            throw new RuntimeException(
              XSLMessages.createXPATHMessage(
                XPATHErrorResources.ER_NULL_ERROR_HANDLER,
                new Object[] { firstChild.getClass().getName()}));
            //"Programmer's assertion: unknown opcode: "
            //+ stepType);
        }
      }
      else
      {
        // For the moment return false if it is a filter expression.  
        // Ideally, we'd like to follow the analysis into a variable or function.
        return false;
      }
    }

    return true;
  }

  /**
   * Special purpose function to see if we can optimize the pattern for 
   * a DescendantIterator.
   *
   * @param pathExpr Root of the path expression being analyzed.
   * @param stepIndex The top-level step index withing the iterator.
   *
   * @return 32 bits as an integer that give information about the location
   * path as a whole.
   *
   * @throws javax.xml.transform.TransformerException
   */
  private static boolean isOptimizableForDescendantIterator(
    PathExpr pathExpr,
    int stepIndex)
    throws javax.xml.transform.TransformerException
  {

    int stepType;
    boolean foundDESCENDANTSFROMROOT = false;

    int nodeTestType = DTMFilter.SHOW_ALL;

    int numSteps = pathExpr.jjtGetNumChildren();

    if (numSteps > 2)
      return false;

    for (int i = 0; i < numSteps; i++)
    {
      StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(i);

      int axis = stepExpr.getAxis();
      switch (axis)
      {
        case Axis.SELF :
        case Axis.ATTRIBUTE :
        case Axis.ROOT :
        case Axis.ANCESTOR :
        case Axis.ANCESTORORSELF :
        case Axis.NAMESPACE :
        case Axis.DESCENDANT :
        case Axis.DESCENDANTORSELF :
        case Axis.FOLLOWING :
        case Axis.FOLLOWINGSIBLING :
        case Axis.PRECEDING :
        case Axis.PRECEDINGSIBLING :
        case Axis.PARENT :
          return false;
        case Axis.DESCENDANTSORSELFFROMROOT :
        case Axis.DESCENDANTSFROMROOT :
          if (0 != i)
            return false;
          foundDESCENDANTSFROMROOT = true;
          if (analyzePredicate(stepExpr))
          {
            return false;
          }
          break;
        case Axis.CHILD :
          if (!foundDESCENDANTSFROMROOT || 1 != i)
            return false;
          if(mightBeProximate(stepExpr))
            return false;
          break;
        default :
          return false;
          // TBD: Change the wording of this expression.
          // throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{firstChild.getClass().getName()})); //"Programmer's assertion: unknown opcode: "
      }

      // TBD: I don't think the code will function properly without this.      
      //      boolean mightBeProximate = mightBeProximate(compiler, stepOpCodePos, stepType);
      //      if(mightBeProximate)
      //        return false;

    }

    return true;
  }

  // TBD: Needs to use methods on the expressions instead of instanceof!
  /**
   * Tell if the predicates need to have proximity knowledge.
   */
  public static boolean mightBeProximate(Expression stepExpr)
    throws javax.xml.transform.TransformerException
  {

    boolean mightBeProximate = false;
    int argLen;

    Node lastChild = stepExpr.jjtGetChild(stepExpr.jjtGetNumChildren() - 1);
    if (lastChild instanceof Predicates)
    {
      Predicates preds = (Predicates) lastChild;
      int numChildren = preds.jjtGetNumChildren();
      for (int i = 0; i < numChildren; i++)
      {
        Expression expr = (Expression) preds.jjtGetChild(i);

        if (expr instanceof org.apache.xpath.operations.Variable)
        {
          return true;
          // Would need more smarts to tell if this could be a number or not!
        }
        else
          if (expr instanceof org.apache.xpath.objects.XNumber)
          {
            return true;
          }
          else
            if (expr instanceof org.apache.xpath.parser.PathExpr
              || expr instanceof LocPathIterator)
            {
              // OK, keep going, we don't want to recurse.
            }
            else
              if (expr instanceof org.apache.xpath.functions.Function)
              {
                boolean isProx =
                  functionProximateOrContainsProximate(
                    (org.apache.xpath.functions.Function) expr);
                if (isProx)
                  return true;
                break;

              }
              else
              {
                int numChildrenOfExpr = expr.jjtGetNumChildren();
                for (int j = 0; j < numChildrenOfExpr; j++)
                {
                  Expression exprChild = (Expression) expr.jjtGetChild(j);
                  boolean prox = isProximateInnerExpr(exprChild);
                  if (prox)
                    return true;
                }
              }

      }
    }

    return mightBeProximate;
  }

  // TBD: Needs to use methods on the expressions instead of instanceof!
  static boolean functionProximateOrContainsProximate(
    org.apache.xpath.functions.Function func)
  {
    if (func instanceof org.apache.xpath.functions.FuncLast
      || func instanceof org.apache.xpath.functions.FuncPosition)
    {
      return true;
    }
    else
    {
      int numChildren = func.jjtGetNumChildren();
      for (int i = 0; i < numChildren; i++)
      {
        Expression expr = (Expression) func.jjtGetChild(i);
        boolean prox = isProximateInnerExpr(expr);
        if (prox)
          return true;
      }
    }
    return false;
  }

  // TBD: Needs to use methods on the expressions instead of instanceof!
  static boolean isProximateInnerExpr(Expression expr)
  {
    boolean mightBeProximate = false;
    int argLen;

    if (expr instanceof org.apache.xpath.parser.PathExpr
      || expr instanceof LocPathIterator)
    {
      // OK, we don't want to recurse!
    }
    else
      if (expr instanceof org.apache.xpath.functions.Function)
      {
        boolean isProx =
          functionProximateOrContainsProximate(
            (org.apache.xpath.functions.Function) expr);
        if (isProx)
          return true;
      }
      else
      {
        int numChildrenOfExpr = expr.jjtGetNumChildren();
        for (int j = 0; j < numChildrenOfExpr; j++)
        {
          Expression exprChild = (Expression) expr.jjtGetChild(j);
          boolean prox = isProximateInnerExpr(exprChild);
          if (prox)
            return true;
        }
      }
    return mightBeProximate;
  }

  /**
   * Create the proper Walker from the axes type.
   *
   * @param compiler non-null reference to compiler object that has processed
   *                 the XPath operations into an opcode map.
   * @param opPos The opcode position for the step.
   * @param lpi The owning location path iterator.
   * @param analysis 32 bits of analysis, from which the type of AxesWalker
   *                 may be influenced.
   *
   * @return non-null reference to AxesWalker derivative.
   * @throws RuntimeException if the input is bad.
   */
  private static AxesWalker createDefaultWalker(
    StepExpr stepExpr,
    WalkingIterator lpi,
    int analysis)
  {

    AxesWalker ai = null;

    PatternAxis patternAxis = stepExpr.getAxisExpr();
    if (null != patternAxis)
    {
      boolean isTotallyWild = stepExpr.isTotallyWild();

      int axis = stepExpr.getAxis();
      switch (axis)
      {
        case Axis.ROOT :
          ai = new AxesWalker(lpi, Axis.ROOT);
          break;
        case Axis.DESCENDANTSFROMROOT :
          ai = new AxesWalker(lpi, Axis.DESCENDANTSFROMROOT);
          break;
        case Axis.DESCENDANTSORSELFFROMROOT :
          ai = new AxesWalker(lpi, Axis.DESCENDANTSORSELFFROMROOT);
          break;
        case Axis.ANCESTOR :
          ai = new ReverseAxesWalker(lpi, Axis.ANCESTOR);
          break;
        case Axis.ANCESTORORSELF :
          ai = new ReverseAxesWalker(lpi, Axis.ANCESTORORSELF);
          break;
        case Axis.ATTRIBUTE :
          ai = new AxesWalker(lpi, Axis.ATTRIBUTE);
          break;
        case Axis.NAMESPACE :
          ai = new AxesWalker(lpi, Axis.NAMESPACE);
          break;
        case Axis.CHILD :
          ai = new AxesWalker(lpi, Axis.CHILD);
          break;
        case Axis.DESCENDANT :
          ai = new AxesWalker(lpi, Axis.DESCENDANT);
          break;
        case Axis.DESCENDANTORSELF :
          ai = new AxesWalker(lpi, Axis.DESCENDANTORSELF);
          break;
        case Axis.FOLLOWING :
          ai = new AxesWalker(lpi, Axis.FOLLOWING);
          break;
        case Axis.FOLLOWINGSIBLING :
          ai = new AxesWalker(lpi, Axis.FOLLOWINGSIBLING);
          break;
        case Axis.PRECEDING :
          ai = new ReverseAxesWalker(lpi, Axis.PRECEDING);
          break;
        case Axis.PRECEDINGSIBLING :
          ai = new ReverseAxesWalker(lpi, Axis.PRECEDINGSIBLING);
          break;
        case Axis.PARENT :
          ai = new ReverseAxesWalker(lpi, Axis.PARENT);
          break;
        case Axis.SELF :
          ai = new AxesWalker(lpi, Axis.SELF);
          break;
        default :
          throw new RuntimeException(
            XSLMessages.createXPATHMessage(
              XPATHErrorResources.ER_NULL_ERROR_HANDLER,
              new Object[] { StepExpr.class.getName()}));
          //"Programmer's assertion: unknown opcode: "
          //+ stepType);
      }
      int whatToShow = stepExpr.getWhatToShow();

      /*
      System.out.print("construct: ");
      NodeTest.debugWhatToShow(whatToShow);
      System.out.println("or stuff: "+(whatToShow & (DTMFilter.SHOW_ATTRIBUTE
                             | DTMFilter.SHOW_ELEMENT
                             | DTMFilter.SHOW_PROCESSING_INSTRUCTION)));
      */
      if ((0
        == (whatToShow
          & (DTMFilter.SHOW_ATTRIBUTE
            | DTMFilter.SHOW_NAMESPACE
            | DTMFilter.SHOW_ELEMENT
            | DTMFilter.SHOW_PROCESSING_INSTRUCTION)))
        || (whatToShow == DTMFilter.SHOW_ALL))
        ai.initNodeTest(whatToShow);
      else
      {
        ai.initNodeTest(
          whatToShow,
          stepExpr.getNamespaceURI(),
          stepExpr.getLocalName());
      }
    }
    else
    {
      // FilterWalker
      if (DEBUG_WALKER_CREATION)
        System.out.println(
          "new walker:  FilterExprWalker: "
            + analysis
            + ", "
            + stepExpr.toString());

      ai = new FilterExprWalker(lpi);
      try
      {
        ai.init(stepExpr);
      }
      catch (TransformerException te)
      {
        throw new org.apache.xml.utils.WrappedRuntimeException(te);
      }
      ai.initNodeTest(DTMFilter.SHOW_ALL);
    }

    return ai;
  }

  /**
   * <meta name="usage" content="advanced"/>
   * This method is for building an array of possible levels
   * where the target element(s) could be found for a match.
   * @param xpath The xpath that is executing.
   * @param context The current source tree context node.
   *
   * @param lpi The owning location path iterator object.
   * @param compiler non-null reference to compiler object that has processed
   *                 the XPath operations into an opcode map.
   * @param stepOpCodePos The opcode position for the step.
   * @param stepIndex The top-level step index withing the iterator.
   *
   * @return non-null AxesWalker derivative.
   *
   * @throws javax.xml.transform.TransformerException
   */
  static AxesWalker loadWalkers(
    org.apache.xpath.parser.PathExpr pathExpr,
    WalkingIterator lpi)
    throws javax.xml.transform.TransformerException
  {

    int stepType;
    AxesWalker firstWalker = null;
    AxesWalker walker, prevWalker = null;
    int analysis = analyze(pathExpr, 0);
    int numSteps = pathExpr.jjtGetNumChildren();

    for (int i = 0; i < numSteps; i++)
    {
      StepExpr stepExpr = (StepExpr) pathExpr.jjtGetChild(i);

      walker = createDefaultWalker(stepExpr, lpi, analysis);
      walker.init(stepExpr);

      // walker.setAnalysis(analysis);
      if (null == firstWalker)
      {
        firstWalker = walker;
        walker.exprSetParent(lpi);
      }
      else
      {
        prevWalker.setNextWalker(walker);
        walker.setPrevWalker(prevWalker);
        walker.exprSetParent(prevWalker);
      }

      prevWalker = walker;
    }

    return firstWalker;
  }

}

//import org.apache.xpath.compiler.OpCodes;
//import org.apache.xpath.compiler.Compiler;
//import org.apache.xpath.compiler.FunctionTable;
//import org.apache.xpath.patterns.NodeTest;
//import org.apache.xpath.patterns.StepPattern;
//import org.apache.xpath.patterns.ContextMatchStepPattern;
//import org.apache.xpath.patterns.FunctionPattern;
//import org.apache.xpath.Expression;
//import org.apache.xpath.objects.XNumber;
//import org.apache.xalan.res.XSLMessages;
//import org.apache.xpath.res.XPATHErrorResources;
//
//import org.apache.xml.dtm.DTMFilter;
//import org.apache.xml.dtm.DTMIterator;
//import org.apache.xml.dtm.Axis;
//
///**
// * This class is both a factory for XPath location path expressions,
// * which are built from the opcode map output, and an analysis engine
// * for the location path expressions in order to provide optimization hints.
// */
//public class WalkerFactory
//{
//
//  /**
//   * <meta name="usage" content="advanced"/>
//   * This method is for building an array of possible levels
//   * where the target element(s) could be found for a match.
//   * @param xpath The xpath that is executing.
//   * @param context The current source tree context node.
//   *
//   * @param lpi The owning location path iterator.
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param stepOpCodePos The opcode position for the step.
//   *
//   * @return non-null AxesWalker derivative.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  static AxesWalker loadOneWalker(
//          WalkingIterator lpi, Compiler compiler, int stepOpCodePos)
//            throws javax.xml.transform.TransformerException
//  {
//
//    AxesWalker firstWalker = null;
//    int stepType = compiler.getOpMap()[stepOpCodePos];
//
//    if (stepType != OpCodes.ENDOP)
//    {
//
//      // m_axesWalkers = new AxesWalker[1];
//      // As we unwind from the recursion, create the iterators.
//      firstWalker = createDefaultWalker(compiler, stepType, lpi, 0);
//
//      firstWalker.init(compiler, stepOpCodePos, stepType);
//    }
//
//    return firstWalker;
//  }
//
//  /**
//   * <meta name="usage" content="advanced"/>
//   * This method is for building an array of possible levels
//   * where the target element(s) could be found for a match.
//   * @param xpath The xpath that is executing.
//   * @param context The current source tree context node.
//   *
//   * @param lpi The owning location path iterator object.
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param stepOpCodePos The opcode position for the step.
//   * @param stepIndex The top-level step index withing the iterator.
//   *
//   * @return non-null AxesWalker derivative.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  static AxesWalker loadWalkers(
//          WalkingIterator lpi, Compiler compiler, int stepOpCodePos, int stepIndex)
//            throws javax.xml.transform.TransformerException
//  {
//
//    int stepType;
//    AxesWalker firstWalker = null;
//    AxesWalker walker, prevWalker = null;
//    int ops[] = compiler.getOpMap();
//    int analysis = analyze(compiler, stepOpCodePos, stepIndex);
//
//    while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
//    {
//      walker = createDefaultWalker(compiler, stepOpCodePos, lpi, analysis);
//
//      walker.init(compiler, stepOpCodePos, stepType);
//      walker.exprSetParent(lpi);
//
//      // walker.setAnalysis(analysis);
//      if (null == firstWalker)
//      {
//        firstWalker = walker;
//      }
//      else
//      {
//        prevWalker.setNextWalker(walker);
//        walker.setPrevWalker(prevWalker);
//      }
//
//      prevWalker = walker;
//      stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
//      if (stepOpCodePos < 0)
//        break;
//    }
//
//    return firstWalker;
//  }
//  
//  public static boolean isSet(int analysis, int bits)
//  {
//    return (0 != (analysis & bits));
//  }
//  
//  public static void diagnoseIterator(String name, int analysis, Compiler compiler)
//  {
//    System.out.println(compiler.toString()+", "+name+", "
//                             + Integer.toBinaryString(analysis) + ", "
//                             + getAnalysisString(analysis));
//  }
//
//  /**
//   * Create a new LocPathIterator iterator.  The exact type of iterator
//   * returned is based on an analysis of the XPath operations.
//   *
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param opPos The position of the operation code for this itterator.
//   *
//   * @return non-null reference to a LocPathIterator or derivative.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  public static DTMIterator newDTMIterator(
//          Compiler compiler, int opPos,
//          boolean isTopLevel)
//            throws javax.xml.transform.TransformerException
//  {
//
//    int firstStepPos = compiler.getFirstChildPos(opPos);
//    int analysis = analyze(compiler, firstStepPos, 0);
//    boolean isOneStep = isOneStep(analysis);
//    DTMIterator iter;
//
//    // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
//    if (isOneStep && walksSelfOnly(analysis) && 
//        isWild(analysis) && !hasPredicate(analysis))
//    {
//      if (DEBUG_ITERATOR_CREATION)
//        diagnoseIterator("SelfIteratorNoPredicate", analysis, compiler);
//
//      // Then use a simple iteration of the attributes, with node test 
//      // and predicate testing.
//      iter = new SelfIteratorNoPredicate(compiler, opPos, analysis);
//    }
//    // Is the iteration exactly one child step?
//    else if (walksChildrenOnly(analysis) && isOneStep)
//    {
//
//      // Does the pattern specify *any* child with no predicate? (i.e. select="child::node()".
//      if (isWild(analysis) && !hasPredicate(analysis))
//      {
//        if (DEBUG_ITERATOR_CREATION)
//          diagnoseIterator("ChildIterator", analysis, compiler);
//
//        // Use simple child iteration without any test.
//        iter = new ChildIterator(compiler, opPos, analysis);
//      }
//      else
//      {
//        if (DEBUG_ITERATOR_CREATION)
//          diagnoseIterator("ChildTestIterator", analysis, compiler);
//
//        // Else use simple node test iteration with predicate test.
//        iter = new ChildTestIterator(compiler, opPos, analysis);
//      }
//    }
//    // Is the iteration a one-step attribute pattern (i.e. select="@foo")?
//    else if (isOneStep && walksAttributes(analysis))
//    {
//      if (DEBUG_ITERATOR_CREATION)
//        diagnoseIterator("AttributeIterator", analysis, compiler);
//
//      // Then use a simple iteration of the attributes, with node test 
//      // and predicate testing.
//      iter = new AttributeIterator(compiler, opPos, analysis);
//    }
//    else if(isOneStep && !walksFilteredList(analysis))
//    {
//      if( !walksNamespaces(analysis) 
//      && (walksInDocOrder(analysis) || isSet(analysis, BIT_PARENT)))
//      {
//        if (false || DEBUG_ITERATOR_CREATION)
//          diagnoseIterator("OneStepIteratorForward", analysis, compiler);
//  
//        // Then use a simple iteration of the attributes, with node test 
//        // and predicate testing.
//        iter = new OneStepIteratorForward(compiler, opPos, analysis);
//      }
//      else
//      {
//        if (false || DEBUG_ITERATOR_CREATION)
//          diagnoseIterator("OneStepIterator", analysis, compiler);
//  
//        // Then use a simple iteration of the attributes, with node test 
//        // and predicate testing.
//        iter = new OneStepIterator(compiler, opPos, analysis);
//      }
//    }
//
//    // Analysis of "//center":
//    // bits: 1001000000001010000000000000011
//    // count: 3
//    // root
//    // child:node()
//    // BIT_DESCENDANT_OR_SELF
//    // It's highly possible that we should have a seperate bit set for 
//    // "//foo" patterns.
//    // For at least the time being, we can't optimize patterns like 
//    // "//table[3]", because this has to be analyzed as 
//    // "/descendant-or-self::node()/table[3]" in order for the indexes 
//    // to work right.
//    else if (isOptimizableForDescendantIterator(compiler, firstStepPos, 0)
//              // && getStepCount(analysis) <= 3 
//              // && walksDescendants(analysis) 
//              // && walksSubtreeOnlyFromRootOrContext(analysis)
//             )
//    {
//      if (DEBUG_ITERATOR_CREATION)
//        diagnoseIterator("DescendantIterator", analysis, compiler);
//
//      iter = new DescendantIterator(compiler, opPos, analysis);
//    }
//    else
//    { 
//      if(isNaturalDocOrder(compiler, firstStepPos, 0, analysis))
//      {
//        if (false || DEBUG_ITERATOR_CREATION)
//        {
//          diagnoseIterator("WalkingIterator", analysis, compiler);
//        }
//  
//        iter = new WalkingIterator(compiler, opPos, analysis, true);
//      }
//      else
//      {
////        if (DEBUG_ITERATOR_CREATION)
////          diagnoseIterator("MatchPatternIterator", analysis, compiler);
////
////        return new MatchPatternIterator(compiler, opPos, analysis);
//        if (DEBUG_ITERATOR_CREATION)
//          diagnoseIterator("WalkingIteratorSorted", analysis, compiler);
//
//        iter = new WalkingIteratorSorted(compiler, opPos, analysis, true);
//      }
//    }
//    if(iter instanceof LocPathIterator)
//      ((LocPathIterator)iter).setIsTopLevel(isTopLevel);
//      
//    return iter;
//  }
//  
//  /**
//   * Special purpose function to see if we can optimize the pattern for 
//   * a DescendantIterator.
//   *
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param stepOpCodePos The opcode position for the step.
//   * @param stepIndex The top-level step index withing the iterator.
//   *
//   * @return 32 bits as an integer that give information about the location
//   * path as a whole.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  public static int getAxisFromStep(
//          Compiler compiler, int stepOpCodePos)
//            throws javax.xml.transform.TransformerException
//  {
//
//    int ops[] = compiler.getOpMap();
//    int stepType = ops[stepOpCodePos];
//
//    switch (stepType)
//    {
//    case OpCodes.FROM_FOLLOWING :
//      return Axis.FOLLOWING;
//    case OpCodes.FROM_FOLLOWING_SIBLINGS :
//      return Axis.FOLLOWINGSIBLING;
//    case OpCodes.FROM_PRECEDING :
//      return Axis.PRECEDING;
//    case OpCodes.FROM_PRECEDING_SIBLINGS :
//      return Axis.PRECEDINGSIBLING;
//    case OpCodes.FROM_PARENT :
//      return Axis.PARENT;
//    case OpCodes.FROM_NAMESPACE :
//      return Axis.NAMESPACE;
//    case OpCodes.FROM_ANCESTORS :
//      return Axis.ANCESTOR;
//    case OpCodes.FROM_ANCESTORS_OR_SELF :
//      return Axis.ANCESTORORSELF;
//    case OpCodes.FROM_ATTRIBUTES :
//      return Axis.ATTRIBUTE;
//    case OpCodes.FROM_ROOT :
//      return Axis.ROOT;
//    case OpCodes.FROM_CHILDREN :
//      return Axis.CHILD;
//    case OpCodes.FROM_DESCENDANTS_OR_SELF :
//      return Axis.DESCENDANTORSELF;
//    case OpCodes.FROM_DESCENDANTS :
//      return Axis.DESCENDANT;
//    case OpCodes.FROM_SELF :
//      return Axis.SELF;
//    case OpCodes.OP_EXTFUNCTION :
//    case OpCodes.OP_FUNCTION :
//    case OpCodes.OP_GROUP :
//    case OpCodes.OP_VARIABLE :
//      return Axis.FILTEREDLIST;
//    }
//
//    throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
//                               //+ stepType);
//   }
//    
//    /**
//     * Get a corresponding BIT_XXX from an axis.
//     * @param axis One of Axis.ANCESTOR, etc.
//     * @return One of BIT_ANCESTOR, etc.
//     */
//    static public int getAnalysisBitFromAxes(int axis)
//    {
//      switch (axis) // Generate new traverser
//        {
//        case Axis.ANCESTOR :
//          return BIT_ANCESTOR;
//        case Axis.ANCESTORORSELF :
//          return BIT_ANCESTOR_OR_SELF;
//        case Axis.ATTRIBUTE :
//          return BIT_ATTRIBUTE;
//        case Axis.CHILD :
//          return BIT_CHILD;
//        case Axis.DESCENDANT :
//          return BIT_DESCENDANT;
//        case Axis.DESCENDANTORSELF :
//          return BIT_DESCENDANT_OR_SELF;
//        case Axis.FOLLOWING :
//          return BIT_FOLLOWING;
//        case Axis.FOLLOWINGSIBLING :
//          return BIT_FOLLOWING_SIBLING;
//        case Axis.NAMESPACE :
//        case Axis.NAMESPACEDECLS :
//          return BIT_NAMESPACE;
//        case Axis.PARENT :
//          return BIT_PARENT;
//        case Axis.PRECEDING :
//          return BIT_PRECEDING;
//        case Axis.PRECEDINGSIBLING :
//          return BIT_PRECEDING_SIBLING;
//        case Axis.SELF :
//          return BIT_SELF;
//        case Axis.ALLFROMNODE :
//          return BIT_DESCENDANT_OR_SELF;
//          // case Axis.PRECEDINGANDANCESTOR :
//        case Axis.DESCENDANTSFROMROOT :
//        case Axis.ALL :
//        case Axis.DESCENDANTSORSELFFROMROOT :
//          return BIT_ANY_DESCENDANT_FROM_ROOT;
//        case Axis.ROOT :
//          return BIT_ROOT;
//        case Axis.FILTEREDLIST :
//          return BIT_FILTER;
//        default :
//          return BIT_FILTER;
//      }
//    }
//  
//  static boolean functionProximateOrContainsProximate(Compiler compiler, 
//                                                      int opPos)
//  {
//    int endFunc = opPos + compiler.getOp(opPos + 1) - 1;
//    opPos = compiler.getFirstChildPos(opPos);
//    int funcID = compiler.getOp(opPos);
//    //  System.out.println("funcID: "+funcID);
//    //  System.out.println("opPos: "+opPos);
//    //  System.out.println("endFunc: "+endFunc);
//    switch(funcID)
//    {
//      case FunctionTable.FUNC_LAST:
//      case FunctionTable.FUNC_POSITION:
//        return true;
//      default:
//        opPos++;
//        int i = 0;
//        for (int p = opPos; p < endFunc; p = compiler.getNextOpPos(p), i++)
//        {
//          int innerExprOpPos = p+2;
//          int argOp = compiler.getOp(innerExprOpPos);
//          boolean prox = isProximateInnerExpr(compiler, innerExprOpPos);
//          if(prox)
//            return true;
//        }
//
//    }
//    return false;
//  }
//  
//  static boolean isProximateInnerExpr(Compiler compiler, int opPos)
//  {
//    int op = compiler.getOp(opPos);
//    int innerExprOpPos = opPos+2;
//    switch(op)
//    {
//      case OpCodes.OP_ARGUMENT:
//        if(isProximateInnerExpr(compiler, innerExprOpPos))
//          return true;
//        break;
//      case OpCodes.OP_VARIABLE:
//      case OpCodes.OP_NUMBERLIT:
//      case OpCodes.OP_LITERAL:
//      case OpCodes.OP_LOCATIONPATH:
//        break; // OK
//      case OpCodes.OP_FUNCTION:
//        boolean isProx = functionProximateOrContainsProximate(compiler, opPos);
//        if(isProx)
//          return true;
//        break;
//      case OpCodes.OP_GT:
//      case OpCodes.OP_GTE:
//      case OpCodes.OP_LT:
//      case OpCodes.OP_LTE:
//      case OpCodes.OP_EQUALS:
//        int leftPos = compiler.getFirstChildPos(op);
//        int rightPos = compiler.getNextOpPos(leftPos);
//        isProx = isProximateInnerExpr(compiler, leftPos);
//        if(isProx)
//          return true;
//        isProx = isProximateInnerExpr(compiler, rightPos);
//        if(isProx)
//          return true;
//        break;
//      default:
//        return true; // be conservative...
//    }
//    return false;
//  }
//    
//  /**
//   * Tell if the predicates need to have proximity knowledge.
//   */
//  public static boolean mightBeProximate(Compiler compiler, int opPos, int stepType)
//          throws javax.xml.transform.TransformerException
//  {
//
//    boolean mightBeProximate = false;
//    int argLen;
//
//    switch (stepType)
//    {
//    case OpCodes.OP_VARIABLE :
//    case OpCodes.OP_EXTFUNCTION :
//    case OpCodes.OP_FUNCTION :
//    case OpCodes.OP_GROUP :
//      argLen = compiler.getArgLength(opPos);
//      break;
//    default :
//      argLen = compiler.getArgLengthOfStep(opPos);
//    }
//
//    int predPos = compiler.getFirstPredicateOpPos(opPos);
//    int count = 0;
//
//    while (OpCodes.OP_PREDICATE == compiler.getOp(predPos))
//    {
//      count++;
//      
//      int innerExprOpPos = predPos+2;
//      int predOp = compiler.getOp(innerExprOpPos);
//
//      switch(predOp)
//      {
//        case OpCodes.OP_VARIABLE:
//        	return true; // Would need more smarts to tell if this could be a number or not!
//        case OpCodes.OP_LOCATIONPATH:
//          // OK.
//          break;
//        case OpCodes.OP_NUMBER:
//        case OpCodes.OP_NUMBERLIT:
//          return true; // that's all she wrote!
//        case OpCodes.OP_FUNCTION:
//          boolean isProx 
//            = functionProximateOrContainsProximate(compiler, innerExprOpPos);
//          if(isProx)
//            return true;
//          break;
//        case OpCodes.OP_GT:
//        case OpCodes.OP_GTE:
//        case OpCodes.OP_LT:
//        case OpCodes.OP_LTE:
//        case OpCodes.OP_EQUALS:
//          int leftPos = compiler.getFirstChildPos(innerExprOpPos);
//          int rightPos = compiler.getNextOpPos(leftPos);
//          isProx = isProximateInnerExpr(compiler, leftPos);
//          if(isProx)
//            return true;
//          isProx = isProximateInnerExpr(compiler, rightPos);
//          if(isProx)
//            return true;
//          break;
//        default:
//          return true; // be conservative...
//      }
//
//      predPos = compiler.getNextOpPos(predPos);
//    }
//
//    return mightBeProximate;
//  }
//  
//  /**
//   * Special purpose function to see if we can optimize the pattern for 
//   * a DescendantIterator.
//   *
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param stepOpCodePos The opcode position for the step.
//   * @param stepIndex The top-level step index withing the iterator.
//   *
//   * @return 32 bits as an integer that give information about the location
//   * path as a whole.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  private static boolean isOptimizableForDescendantIterator(
//          Compiler compiler, int stepOpCodePos, int stepIndex)
//            throws javax.xml.transform.TransformerException
//  {
//
//    int stepType;
//    int ops[] = compiler.getOpMap();
//    int stepCount = 0;
//    boolean foundDorDS = false;
//    boolean foundSelf = false;
//    boolean foundDS = false;
//    
//    int nodeTestType = OpCodes.NODETYPE_NODE;
//    
//    while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
//    {
//      // The DescendantIterator can only do one node test.  If there's more 
//      // than one, use another iterator.
//      if(nodeTestType != OpCodes.NODETYPE_NODE && nodeTestType != OpCodes.NODETYPE_ROOT)
//        return false;
//        
//      stepCount++;
//      if(stepCount > 3)
//        return false;
//        
//      boolean mightBeProximate = mightBeProximate(compiler, stepOpCodePos, stepType);
//      if(mightBeProximate)
//        return false;
//
//      switch (stepType)
//      {
//      case OpCodes.FROM_FOLLOWING :
//      case OpCodes.FROM_FOLLOWING_SIBLINGS :
//      case OpCodes.FROM_PRECEDING :
//      case OpCodes.FROM_PRECEDING_SIBLINGS :
//      case OpCodes.FROM_PARENT :
//      case OpCodes.OP_VARIABLE :
//      case OpCodes.OP_EXTFUNCTION :
//      case OpCodes.OP_FUNCTION :
//      case OpCodes.OP_GROUP :
//      case OpCodes.FROM_NAMESPACE :
//      case OpCodes.FROM_ANCESTORS :
//      case OpCodes.FROM_ANCESTORS_OR_SELF :
//      case OpCodes.FROM_ATTRIBUTES :
//      case OpCodes.MATCH_ATTRIBUTE :
//      case OpCodes.MATCH_ANY_ANCESTOR :
//      case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
//        return false;
//      case OpCodes.FROM_ROOT :
//        if(1 != stepCount)
//          return false;
//        break;
//      case OpCodes.FROM_CHILDREN :
//        if(!foundDS && !(foundDorDS && foundSelf))
//          return false;
//        break;
//      case OpCodes.FROM_DESCENDANTS_OR_SELF :
//        foundDS = true;
//      case OpCodes.FROM_DESCENDANTS :
//        if(3 == stepCount)
//          return false;
//        foundDorDS = true;
//        break;
//      case OpCodes.FROM_SELF :
//        if(1 != stepCount)
//          return false;
//        foundSelf = true;
//        break;
//      default :
//        throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
//                                  // + stepType);
//      }
//      
//      nodeTestType = compiler.getStepTestType(stepOpCodePos);
//
//      int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
//      if (nextStepOpCodePos < 0)
//        break;
//        
//      if(OpCodes.ENDOP != ops[nextStepOpCodePos])
//      {
//        if(compiler.countPredicates(stepOpCodePos) > 0)
//        {
//          return false;
//        }
//      }
//      
//      stepOpCodePos = nextStepOpCodePos;
//    }
//
//    return true;
//  }
//
//  /**
//   * Analyze the location path and return 32 bits that give information about
//   * the location path as a whole.  See the BIT_XXX constants for meaning about
//   * each of the bits.
//   *
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param stepOpCodePos The opcode position for the step.
//   * @param stepIndex The top-level step index withing the iterator.
//   *
//   * @return 32 bits as an integer that give information about the location
//   * path as a whole.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  private static int analyze(
//          Compiler compiler, int stepOpCodePos, int stepIndex)
//            throws javax.xml.transform.TransformerException
//  {
//
//    int stepType;
//    int ops[] = compiler.getOpMap();
//    int stepCount = 0;
//    int analysisResult = 0x00000000;  // 32 bits of analysis
//
//    while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
//    {
//      stepCount++;
//
//      // String namespace = compiler.getStepNS(stepOpCodePos);
//      // boolean isNSWild = (null != namespace) 
//      //                   ? namespace.equals(NodeTest.WILD) : false;
//      // String localname = compiler.getStepLocalName(stepOpCodePos);
//      // boolean isWild = (null != localname) ? localname.equals(NodeTest.WILD) : false;
//      boolean predAnalysis = analyzePredicate(compiler, stepOpCodePos,
//                                              stepType);
//
//      if (predAnalysis)
//        analysisResult |= BIT_PREDICATE;
//
//      switch (stepType)
//      {
//      case OpCodes.OP_VARIABLE :
//      case OpCodes.OP_EXTFUNCTION :
//      case OpCodes.OP_FUNCTION :
//      case OpCodes.OP_GROUP :
//        analysisResult |= BIT_FILTER;
//        break;
//      case OpCodes.FROM_ROOT :
//        analysisResult |= BIT_ROOT;
//        break;
//      case OpCodes.FROM_ANCESTORS :
//        analysisResult |= BIT_ANCESTOR;
//        break;
//      case OpCodes.FROM_ANCESTORS_OR_SELF :
//        analysisResult |= BIT_ANCESTOR_OR_SELF;
//        break;
//      case OpCodes.FROM_ATTRIBUTES :
//        analysisResult |= BIT_ATTRIBUTE;
//        break;
//      case OpCodes.FROM_NAMESPACE :
//        analysisResult |= BIT_NAMESPACE;
//        break;
//      case OpCodes.FROM_CHILDREN :
//        analysisResult |= BIT_CHILD;
//        break;
//      case OpCodes.FROM_DESCENDANTS :
//        analysisResult |= BIT_DESCENDANT;
//        break;
//      case OpCodes.FROM_DESCENDANTS_OR_SELF :
//
//        // Use a special bit to to make sure we get the right analysis of "//foo".
//        if (2 == stepCount && BIT_ROOT == analysisResult)
//        {
//          analysisResult |= BIT_ANY_DESCENDANT_FROM_ROOT;
//        }
//
//        analysisResult |= BIT_DESCENDANT_OR_SELF;
//        break;
//      case OpCodes.FROM_FOLLOWING :
//        analysisResult |= BIT_FOLLOWING;
//        break;
//      case OpCodes.FROM_FOLLOWING_SIBLINGS :
//        analysisResult |= BIT_FOLLOWING_SIBLING;
//        break;
//      case OpCodes.FROM_PRECEDING :
//        analysisResult |= BIT_PRECEDING;
//        break;
//      case OpCodes.FROM_PRECEDING_SIBLINGS :
//        analysisResult |= BIT_PRECEDING_SIBLING;
//        break;
//      case OpCodes.FROM_PARENT :
//        analysisResult |= BIT_PARENT;
//        break;
//      case OpCodes.FROM_SELF :
//        analysisResult |= BIT_SELF;
//        break;
//      case OpCodes.MATCH_ATTRIBUTE :
//        analysisResult |= (BIT_MATCH_PATTERN | BIT_ATTRIBUTE);
//        break;
//      case OpCodes.MATCH_ANY_ANCESTOR :
//        analysisResult |= (BIT_MATCH_PATTERN | BIT_ANCESTOR);
//        break;
//      case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
//        analysisResult |= (BIT_MATCH_PATTERN | BIT_PARENT);
//        break;
//      default :
//        throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
//                                   //+ stepType);
//      }
//
//      if (OpCodes.NODETYPE_NODE == ops[stepOpCodePos + 3])  // child::node()
//      {
//        analysisResult |= BIT_NODETEST_ANY;
//      }
//
//      stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
//      if (stepOpCodePos < 0)
//        break;
//    }
//
//    analysisResult |= (stepCount & BITS_COUNT);
//
//    return analysisResult;
//  }
//  
//  /**
//   * Tell if the given axis goes downword.  Bogus name, if you can think of 
//   * a better one, please do tell.  This really has to do with inverting 
//   * attribute axis.
//   * @param axis One of Axis.XXX.
//   * @return true if the axis is not a child axis and does not go up from 
//   * the axis root.
//   */
//  public static boolean isDownwardAxisOfMany(int axis)
//  {
//    return ((Axis.DESCENDANTORSELF == axis) ||
//          (Axis.DESCENDANT == axis) 
//          || (Axis.FOLLOWING == axis) 
////          || (Axis.FOLLOWINGSIBLING == axis) 
//          || (Axis.PRECEDING == axis) 
////          || (Axis.PRECEDINGSIBLING == axis)
//          );
//  }
//
//  /**
//   * Read a <a href="http://www.w3.org/TR/xpath#location-paths">LocationPath</a>
//   * as a generalized match pattern.  What this means is that the LocationPath
//   * is read backwards, as a test on a given node, to see if it matches the
//   * criteria of the selection, and ends up at the context node.  Essentially,
//   * this is a backwards query from a given node, to find the context node.
//   * <p>So, the selection "foo/daz[2]" is, in non-abreviated expanded syntax,
//   * "self::node()/following-sibling::foo/child::daz[position()=2]".
//   * Taking this as a match pattern for a probable node, it works out to
//   * "self::daz/parent::foo[child::daz[position()=2 and isPrevStepNode()]
//   * precedingSibling::node()[isContextNodeOfLocationPath()]", adding magic
//   * isPrevStepNode and isContextNodeOfLocationPath operations.  Predicates in
//   * the location path have to be executed by the following step,
//   * because they have to know the context of their execution.
//   *
//   * @param mpi The MatchPatternIterator to which the steps will be attached.
//   * @param compiler The compiler that holds the syntax tree/op map to
//   * construct from.
//   * @param stepOpCodePos The current op code position within the opmap.
//   * @param stepIndex The top-level step index withing the iterator.
//   *
//   * @return A StepPattern object, which may contain relative StepPatterns.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  static StepPattern loadSteps(
//          MatchPatternIterator mpi, Compiler compiler, int stepOpCodePos, 
//                                                       int stepIndex)
//            throws javax.xml.transform.TransformerException
//  {
//    if (DEBUG_PATTERN_CREATION)
//    {
//      System.out.println("================");
//      System.out.println("loadSteps for: "+compiler.getPatternString());
//    }
//    int stepType;
//    StepPattern step = null;
//    StepPattern firstStep = null, prevStep = null;
//    int ops[] = compiler.getOpMap();
//    int analysis = analyze(compiler, stepOpCodePos, stepIndex);
//
//    while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
//    {
//      step = createDefaultStepPattern(compiler, stepOpCodePos, mpi, analysis,
//                                      firstStep, prevStep);
//
//      if (null == firstStep)
//      {
//        firstStep = step;
//      }
//      else
//      {
//
//        //prevStep.setNextWalker(step);
//        step.setRelativePathPattern(prevStep);
//      }
//
//      prevStep = step;
//      stepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
//      if (stepOpCodePos < 0)
//        break;
//    }
//    
//    int axis = Axis.SELF;
//    int paxis = Axis.SELF;
//    StepPattern tail = step;
//    for (StepPattern pat = step; null != pat; 
//         pat = pat.getRelativePathPattern()) 
//    {
//      int nextAxis = pat.getAxis();
//      //int nextPaxis = pat.getPredicateAxis();
//      pat.setAxis(axis);
//      
//      // The predicate axis can't be moved!!!  Test Axes103
//      // pat.setPredicateAxis(paxis);
//      
//      // If we have an attribute or namespace axis that went up, then 
//      // it won't find the attribute in the inverse, since the select-to-match
//      // axes are not invertable (an element is a parent of an attribute, but 
//      // and attribute is not a child of an element).
//      // If we don't do the magic below, then "@*/ancestor-or-self::*" gets
//      // inverted for match to "self::*/descendant-or-self::@*/parent::node()",
//      // which obviously won't work.
//      // So we will rewrite this as:
//      // "self::*/descendant-or-self::*/attribute::*/parent::node()"
//      // Child has to be rewritten a little differently:
//      // select: "@*/parent::*"
//      // inverted match: "self::*/child::@*/parent::node()"
//      // rewrite: "self::*/attribute::*/parent::node()"
//      // Axes that go down in the select, do not have to have special treatment 
//      // in the rewrite. The following inverted match will still not select 
//      // anything.
//      // select: "@*/child::*"
//      // inverted match: "self::*/parent::@*/parent::node()"
//      // Lovely business, this.
//      // -sb
//      int whatToShow = pat.getWhatToShow();
//      if(whatToShow == DTMFilter.SHOW_ATTRIBUTE || 
//         whatToShow == DTMFilter.SHOW_NAMESPACE)
//      {
//        int newAxis = (whatToShow == DTMFilter.SHOW_ATTRIBUTE) ? 
//                       Axis.ATTRIBUTE : Axis.NAMESPACE;
//        if(isDownwardAxisOfMany(axis))
//        {
//          StepPattern attrPat = new StepPattern(whatToShow, 
//                                    pat.getNamespace(),
//                                    pat.getLocalName(),
//                                //newAxis, pat.getPredicateAxis);
//                                                newAxis, 0); // don't care about the predicate axis
//          XNumber score = pat.getStaticScore();
//          pat.setNamespace(null);
//          pat.setLocalName(NodeTest.WILD);
//          attrPat.setPredicates(pat.getPredicates());
//          pat.setPredicates(null);
//          pat.setWhatToShow(DTMFilter.SHOW_ELEMENT);
//          StepPattern rel = pat.getRelativePathPattern();
//          pat.setRelativePathPattern(attrPat);
//          attrPat.setRelativePathPattern(rel);
//          attrPat.setStaticScore(score);
//          
//          // This is needed to inverse a following pattern, because of the 
//          // wacky Xalan rules for following from an attribute.  See axes108.
//          // By these rules, following from an attribute is not strictly 
//          // inverseable.
//          if(Axis.PRECEDING == pat.getAxis())
//            pat.setAxis(Axis.PRECEDINGANDANCESTOR);
//            
//          else if(Axis.DESCENDANT == pat.getAxis())
//            pat.setAxis(Axis.DESCENDANTORSELF);
//          
//          pat = attrPat;
//        }
//        else if(Axis.CHILD == pat.getAxis())
//        {
//          // In this case just change the axis.
//          // pat.setWhatToShow(whatToShow);
//          pat.setAxis(Axis.ATTRIBUTE);
//        }
//      }
//      axis = nextAxis;
//      //paxis = nextPaxis;
//      tail = pat;
//    }
//    
//    if(axis < Axis.ALL)
//    {
//      StepPattern selfPattern = new ContextMatchStepPattern(axis, paxis);
//      // We need to keep the new nodetest from affecting the score...
//      XNumber score = tail.getStaticScore();
//      tail.setRelativePathPattern(selfPattern);
//      tail.setStaticScore(score);
//      selfPattern.setStaticScore(score);
//    }        
//
//    if (DEBUG_PATTERN_CREATION)
//    {
//      System.out.println("Done loading steps: "+step.toString());
//            
//      System.out.println("");
//    }
//    return step;  // start from last pattern?? //firstStep;
//  }
//
//  /**
//   * Create a StepPattern that is contained within a LocationPath.
//   *
//   *
//   * @param compiler The compiler that holds the syntax tree/op map to
//   * construct from.
//   * @param stepOpCodePos The current op code position within the opmap.
//   * @param mpi The MatchPatternIterator to which the steps will be attached.
//   * @param analysis 32 bits of analysis, from which the type of AxesWalker
//   *                 may be influenced.
//   * @param tail The step that is the first step analyzed, but the last 
//   *                  step in the relative match linked list, i.e. the tail.
//   *                  May be null.
//   * @param head The step that is the current head of the relative 
//   *                 match step linked list.
//   *                 May be null.
//   *
//   * @return the head of the list.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  private static StepPattern createDefaultStepPattern(
//          Compiler compiler, int opPos, MatchPatternIterator mpi, 
//          int analysis, StepPattern tail, StepPattern head)
//            throws javax.xml.transform.TransformerException
//  {
//
//    int stepType = compiler.getOp(opPos);
//    boolean simpleInit = false;
//    int totalNumberWalkers = (analysis & BITS_COUNT);
//    boolean prevIsOneStepDown = true;
//    int firstStepPos = compiler.getFirstChildPos(opPos);
//    
//    int whatToShow = compiler.getWhatToShow(opPos);
//    StepPattern ai = null;
//    int axis, predicateAxis;
//    
//    switch (stepType)
//    {
//    case OpCodes.OP_VARIABLE :
//    case OpCodes.OP_EXTFUNCTION :
//    case OpCodes.OP_FUNCTION :
//    case OpCodes.OP_GROUP :
//      prevIsOneStepDown = false;
//
//      Expression expr;
//
//      switch (stepType)
//      {
//      case OpCodes.OP_VARIABLE :
//      case OpCodes.OP_EXTFUNCTION :
//      case OpCodes.OP_FUNCTION :
//      case OpCodes.OP_GROUP :
//        expr = compiler.compile(opPos);
//        break;
//      default :
//        expr = compiler.compile(opPos + 2);
//      }
//
//      axis = Axis.FILTEREDLIST;
//      predicateAxis = Axis.FILTEREDLIST;
//      ai = new FunctionPattern(expr, axis, predicateAxis);
//      simpleInit = true;
//      break;
//    case OpCodes.FROM_ROOT :
//      whatToShow = DTMFilter.SHOW_DOCUMENT
//                   | DTMFilter.SHOW_DOCUMENT_FRAGMENT;
//
//      axis = Axis.ROOT;
//      predicateAxis = Axis.ROOT;
//      ai = new StepPattern(DTMFilter.SHOW_DOCUMENT | 
//                                DTMFilter.SHOW_DOCUMENT_FRAGMENT,
//                                axis, predicateAxis);
//      break;
//    case OpCodes.FROM_ATTRIBUTES :
//      whatToShow = DTMFilter.SHOW_ATTRIBUTE;
//      axis = Axis.PARENT;
//      predicateAxis = Axis.ATTRIBUTE;
//      // ai = new StepPattern(whatToShow, Axis.SELF, Axis.SELF);
//      break;
//    case OpCodes.FROM_NAMESPACE :
//      whatToShow = DTMFilter.SHOW_NAMESPACE;
//      axis = Axis.PARENT;
//      predicateAxis = Axis.NAMESPACE;
//      // ai = new StepPattern(whatToShow, axis, predicateAxis);
//      break;
//    case OpCodes.FROM_ANCESTORS :
//      axis = Axis.DESCENDANT;
//      predicateAxis = Axis.ANCESTOR;
//      break;
//    case OpCodes.FROM_CHILDREN :
//      axis = Axis.PARENT;
//      predicateAxis = Axis.CHILD;
//      break;
//    case OpCodes.FROM_ANCESTORS_OR_SELF :
//      axis = Axis.DESCENDANTORSELF;
//      predicateAxis = Axis.ANCESTORORSELF;
//      break;
//    case OpCodes.FROM_SELF :
//      axis = Axis.SELF;
//      predicateAxis = Axis.SELF;
//      break;
//    case OpCodes.FROM_PARENT :
//      axis = Axis.CHILD;
//      predicateAxis = Axis.PARENT;
//      break;
//    case OpCodes.FROM_PRECEDING_SIBLINGS :
//      axis = Axis.FOLLOWINGSIBLING;
//      predicateAxis = Axis.PRECEDINGSIBLING;
//      break;
//    case OpCodes.FROM_PRECEDING :
//      axis = Axis.FOLLOWING;
//      predicateAxis = Axis.PRECEDING;
//      break;
//    case OpCodes.FROM_FOLLOWING_SIBLINGS :
//      axis = Axis.PRECEDINGSIBLING;
//      predicateAxis = Axis.FOLLOWINGSIBLING;
//      break;
//    case OpCodes.FROM_FOLLOWING :
//      axis = Axis.PRECEDING;
//      predicateAxis = Axis.FOLLOWING;
//      break;
//    case OpCodes.FROM_DESCENDANTS_OR_SELF :
//      axis = Axis.ANCESTORORSELF;
//      predicateAxis = Axis.DESCENDANTORSELF;
//      break;
//    case OpCodes.FROM_DESCENDANTS :
//      axis = Axis.ANCESTOR;
//      predicateAxis = Axis.DESCENDANT;
//      break;
//    default :
//      throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
//                                 //+ stepType);
//    }
//    if(null == ai)
//    {
//      whatToShow = compiler.getWhatToShow(opPos); // %REVIEW%
//      ai = new StepPattern(whatToShow, compiler.getStepNS(opPos),
//                                compiler.getStepLocalName(opPos),
//                                axis, predicateAxis);
//    }
//   
//    if (false || DEBUG_PATTERN_CREATION)
//    {
//      System.out.print("new step: "+ ai);
//      System.out.print(", axis: " + Axis.names[ai.getAxis()]);
//      System.out.print(", predAxis: " + Axis.names[ai.getAxis()]);
//      System.out.print(", what: ");
//      System.out.print("    ");
//      ai.debugWhatToShow(ai.getWhatToShow());
//    }
//
//    int argLen = compiler.getFirstPredicateOpPos(opPos);
//
//    ai.setPredicates(compiler.getCompiledPredicates(argLen));
//
//    return ai;
//  }
//
//  /**
//   * Analyze a step and give information about it's predicates.  Right now this
//   * just returns true or false if the step has a predicate.
//   *
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param opPos The opcode position for the step.
//   * @param stepType The type of step, one of OP_GROUP, etc.
//   *
//   * @return true if step has a predicate.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  static boolean analyzePredicate(Compiler compiler, int opPos, int stepType)
//          throws javax.xml.transform.TransformerException
//  {
//
//    int argLen;
//
//    switch (stepType)
//    {
//    case OpCodes.OP_VARIABLE :
//    case OpCodes.OP_EXTFUNCTION :
//    case OpCodes.OP_FUNCTION :
//    case OpCodes.OP_GROUP :
//      argLen = compiler.getArgLength(opPos);
//      break;
//    default :
//      argLen = compiler.getArgLengthOfStep(opPos);
//    }
//
//    int pos = compiler.getFirstPredicateOpPos(opPos);
//    int nPredicates = compiler.countPredicates(pos);
//
//    return (nPredicates > 0) ? true : false;
//  }
//
//  /**
//   * Create the proper Walker from the axes type.
//   *
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param opPos The opcode position for the step.
//   * @param lpi The owning location path iterator.
//   * @param analysis 32 bits of analysis, from which the type of AxesWalker
//   *                 may be influenced.
//   *
//   * @return non-null reference to AxesWalker derivative.
//   * @throws RuntimeException if the input is bad.
//   */
//  private static AxesWalker createDefaultWalker(Compiler compiler, int opPos,
//          WalkingIterator lpi, int analysis)
//  {
//
//    AxesWalker ai = null;
//    int stepType = compiler.getOp(opPos);
//
//    /*
//    System.out.println("0: "+compiler.getOp(opPos));
//    System.out.println("1: "+compiler.getOp(opPos+1));
//    System.out.println("2: "+compiler.getOp(opPos+2));
//    System.out.println("3: "+compiler.getOp(opPos+3));
//    System.out.println("4: "+compiler.getOp(opPos+4));
//    System.out.println("5: "+compiler.getOp(opPos+5));
//    */
//    boolean simpleInit = false;
//    int totalNumberWalkers = (analysis & BITS_COUNT);
//    boolean prevIsOneStepDown = true;
//
//    switch (stepType)
//    {
//    case OpCodes.OP_VARIABLE :
//    case OpCodes.OP_EXTFUNCTION :
//    case OpCodes.OP_FUNCTION :
//    case OpCodes.OP_GROUP :
//      prevIsOneStepDown = false;
//
//      if (DEBUG_WALKER_CREATION)
//        System.out.println("new walker:  FilterExprWalker: " + analysis
//                           + ", " + compiler.toString());
//
//      ai = new FilterExprWalker(lpi);
//      simpleInit = true;
//      break;
//    case OpCodes.FROM_ROOT :
//      ai = new AxesWalker(lpi, Axis.ROOT);
//      break;
//    case OpCodes.FROM_ANCESTORS :
//      prevIsOneStepDown = false;
//      ai = new ReverseAxesWalker(lpi, Axis.ANCESTOR);
//      break;
//    case OpCodes.FROM_ANCESTORS_OR_SELF :
//      prevIsOneStepDown = false;
//      ai = new ReverseAxesWalker(lpi, Axis.ANCESTORORSELF);
//      break;
//    case OpCodes.FROM_ATTRIBUTES :
//      ai = new AxesWalker(lpi, Axis.ATTRIBUTE);
//      break;
//    case OpCodes.FROM_NAMESPACE :
//      ai = new AxesWalker(lpi, Axis.NAMESPACE);
//      break;
//    case OpCodes.FROM_CHILDREN :
//      ai = new AxesWalker(lpi, Axis.CHILD);
//      break;
//    case OpCodes.FROM_DESCENDANTS :
//      prevIsOneStepDown = false;
//      ai = new AxesWalker(lpi, Axis.DESCENDANT);
//      break;
//    case OpCodes.FROM_DESCENDANTS_OR_SELF :
//      prevIsOneStepDown = false;
//      ai = new AxesWalker(lpi, Axis.DESCENDANTORSELF);
//      break;
//    case OpCodes.FROM_FOLLOWING :
//      prevIsOneStepDown = false;
//      ai = new AxesWalker(lpi, Axis.FOLLOWING);
//      break;
//    case OpCodes.FROM_FOLLOWING_SIBLINGS :
//      prevIsOneStepDown = false;
//      ai = new AxesWalker(lpi, Axis.FOLLOWINGSIBLING);
//      break;
//    case OpCodes.FROM_PRECEDING :
//      prevIsOneStepDown = false;
//      ai = new ReverseAxesWalker(lpi, Axis.PRECEDING);
//      break;
//    case OpCodes.FROM_PRECEDING_SIBLINGS :
//      prevIsOneStepDown = false;
//      ai = new ReverseAxesWalker(lpi, Axis.PRECEDINGSIBLING);
//      break;
//    case OpCodes.FROM_PARENT :
//      prevIsOneStepDown = false;
//      ai = new ReverseAxesWalker(lpi, Axis.PARENT);
//      break;
//    case OpCodes.FROM_SELF :
//      ai = new AxesWalker(lpi, Axis.SELF);
//      break;
//    default :
//      throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
//                                 //+ stepType);
//    }
//
//    if (simpleInit)
//    {
//      ai.initNodeTest(DTMFilter.SHOW_ALL);
//    }
//    else
//    {
//      int whatToShow = compiler.getWhatToShow(opPos);
//
//      /*
//      System.out.print("construct: ");
//      NodeTest.debugWhatToShow(whatToShow);
//      System.out.println("or stuff: "+(whatToShow & (DTMFilter.SHOW_ATTRIBUTE
//                             | DTMFilter.SHOW_ELEMENT
//                             | DTMFilter.SHOW_PROCESSING_INSTRUCTION)));
//      */
//      if ((0 == (whatToShow
//                 & (DTMFilter.SHOW_ATTRIBUTE | DTMFilter.SHOW_NAMESPACE | DTMFilter.SHOW_ELEMENT
//                    | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) || (whatToShow == DTMFilter.SHOW_ALL))
//        ai.initNodeTest(whatToShow);
//      else
//      {
//        ai.initNodeTest(whatToShow, compiler.getStepNS(opPos),
//                        compiler.getStepLocalName(opPos));
//      }
//    }
//
//    return ai;
//  }
//  
//  public static String getAnalysisString(int analysis)
//  {
//    StringBuffer buf = new StringBuffer();
//    buf.append("count: "+getStepCount(analysis)+" ");
//    if((analysis & BIT_NODETEST_ANY) != 0)
//    {
//      buf.append("NTANY|");
//    }
//    if((analysis & BIT_PREDICATE) != 0)
//    {
//      buf.append("PRED|");
//    }
//    if((analysis & BIT_ANCESTOR) != 0)
//    {
//      buf.append("ANC|");
//    }
//    if((analysis & BIT_ANCESTOR_OR_SELF) != 0)
//    {
//      buf.append("ANCOS|");
//    }
//    if((analysis & BIT_ATTRIBUTE) != 0)
//    {
//      buf.append("ATTR|");
//    }
//    if((analysis & BIT_CHILD) != 0)
//    {
//      buf.append("CH|");
//    }
//    if((analysis & BIT_DESCENDANT) != 0)
//    {
//      buf.append("DESC|");
//    }
//    if((analysis & BIT_DESCENDANT_OR_SELF) != 0)
//    {
//      buf.append("DESCOS|");
//    }
//    if((analysis & BIT_FOLLOWING) != 0)
//    {
//      buf.append("FOL|");
//    }
//    if((analysis & BIT_FOLLOWING_SIBLING) != 0)
//    {
//      buf.append("FOLS|");
//    }
//    if((analysis & BIT_NAMESPACE) != 0)
//    {
//      buf.append("NS|");
//    }
//    if((analysis & BIT_PARENT) != 0)
//    {
//      buf.append("P|");
//    }
//    if((analysis & BIT_PRECEDING) != 0)
//    {
//      buf.append("PREC|");
//    }
//    if((analysis & BIT_PRECEDING_SIBLING) != 0)
//    {
//      buf.append("PRECS|");
//    }
//    if((analysis & BIT_SELF) != 0)
//    {
//      buf.append(".|");
//    }
//    if((analysis & BIT_FILTER) != 0)
//    {
//      buf.append("FLT|");
//    }
//    if((analysis & BIT_ROOT) != 0)
//    {
//      buf.append("R|");
//    }
//    return buf.toString();
//  }
//
//  /** Set to true for diagnostics about walker creation */
//  static final boolean DEBUG_PATTERN_CREATION = false;
//
//  /** Set to true for diagnostics about walker creation */
//  static final boolean DEBUG_WALKER_CREATION = false;
//
//  /** Set to true for diagnostics about iterator creation */
//  static final boolean DEBUG_ITERATOR_CREATION = false;
//  
//  public static boolean hasPredicate(int analysis)
//  {
//    return (0 != (analysis & BIT_PREDICATE));
//  }
//
//  public static boolean isWild(int analysis)
//  {
//    return (0 != (analysis & BIT_NODETEST_ANY));
//  }
//
//  public static boolean walksAncestors(int analysis)
//  {
//    return isSet(analysis, BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
//  }
//  
//  public static boolean walksAttributes(int analysis)
//  {
//    return (0 != (analysis & BIT_ATTRIBUTE));
//  }
//
//  public static boolean walksNamespaces(int analysis)
//  {
//    return (0 != (analysis & BIT_NAMESPACE));
//  }  
//
//  public static boolean walksChildren(int analysis)
//  {
//    return (0 != (analysis & BIT_CHILD));
//  }
//
//  public static boolean walksDescendants(int analysis)
//  {
//    return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF);
//  }
//
//  public static boolean walksSubtree(int analysis)
//  {
//    return isSet(analysis, BIT_DESCENDANT | BIT_DESCENDANT_OR_SELF | BIT_CHILD);
//  }
//  
//  public static boolean walksSubtreeOnlyMaybeAbsolute(int analysis)
//  {
//    return walksSubtree(analysis)
//           && !walksExtraNodes(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           ;
//  }
//  
//  public static boolean walksSubtreeOnly(int analysis)
//  {
//    return walksSubtreeOnlyMaybeAbsolute(analysis) 
//           && !isAbsolute(analysis) 
//           ;
//  }
//
//  public static boolean walksFilteredList(int analysis)
//  {
//    return isSet(analysis, BIT_FILTER);
//  }
//  
//  public static boolean walksSubtreeOnlyFromRootOrContext(int analysis)
//  {
//    return walksSubtree(analysis)
//           && !walksExtraNodes(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && !isSet(analysis, BIT_FILTER) 
//           ;
//  }
//
//  public static boolean walksInDocOrder(int analysis)
//  {
//    return (walksSubtreeOnlyMaybeAbsolute(analysis)
//           || walksExtraNodesOnly(analysis)
//           || walksFollowingOnlyMaybeAbsolute(analysis)) 
//           && !isSet(analysis, BIT_FILTER) 
//           ;
//  }
//  
//  public static boolean walksFollowingOnlyMaybeAbsolute(int analysis)
//  {
//    return isSet(analysis, BIT_SELF | BIT_FOLLOWING_SIBLING | BIT_FOLLOWING)
//           && !walksSubtree(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           ;
//  }
//  
//  public static boolean walksUp(int analysis)
//  {
//    return isSet(analysis, BIT_PARENT | BIT_ANCESTOR | BIT_ANCESTOR_OR_SELF);
//  }
//  
//  public static boolean walksSideways(int analysis)
//  {
//    return isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING | 
//                           BIT_PRECEDING | BIT_PRECEDING_SIBLING);
//  }
//  
//  public static boolean walksExtraNodes(int analysis)
//  {
//    return isSet(analysis, BIT_NAMESPACE | BIT_ATTRIBUTE);
//  }
//
//  public static boolean walksExtraNodesOnly(int analysis)
//  {
//    return walksExtraNodes(analysis)
//           && !isSet(analysis, BIT_SELF) 
//           && !walksSubtree(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && !isAbsolute(analysis) 
//           ;
//  }
//
//  public static boolean isAbsolute(int analysis)
//  {
//    return isSet(analysis, BIT_ROOT | BIT_FILTER);
//  }
//  
//  public static boolean walksChildrenOnly(int analysis)
//  {
//    return walksChildren(analysis)
//           && !isSet(analysis, BIT_SELF)
//           && !walksExtraNodes(analysis)
//           && !walksDescendants(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
//           ;
//  }
//  
//  public static boolean walksChildrenAndExtraAndSelfOnly(int analysis)
//  {
//    return walksChildren(analysis)
//           && !walksDescendants(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
//           ;
//  }
//  
//  public static boolean walksDescendantsAndExtraAndSelfOnly(int analysis)
//  {
//    return !walksChildren(analysis)
//           && walksDescendants(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && (!isAbsolute(analysis) || isSet(analysis, BIT_ROOT))
//           ;
//  }
//  
//  public static boolean walksSelfOnly(int analysis)
//  {
//    return isSet(analysis, BIT_SELF) 
//           && !walksSubtree(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && !isAbsolute(analysis) 
//           ;
//  }
//
//  
//  public static boolean walksUpOnly(int analysis)
//  {
//    return !walksSubtree(analysis) 
//           && walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && !isAbsolute(analysis) 
//           ;
//  }
//  
//  public static boolean walksDownOnly(int analysis)
//  {
//    return walksSubtree(analysis) 
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && !isAbsolute(analysis) 
//           ;
//  }
//
//  public static boolean walksDownExtraOnly(int analysis)
//  {
//    return walksSubtree(analysis) &&  walksExtraNodes(analysis)
//           && !walksUp(analysis) 
//           && !walksSideways(analysis) 
//           && !isAbsolute(analysis) 
//           ;
//  }
//  
//  public static boolean canSkipSubtrees(int analysis)
//  {
//    return isSet(analysis, BIT_CHILD) | walksSideways(analysis);
//  }
//  
//  public static boolean canCrissCross(int analysis)
//  {
//    // This could be done faster.  Coded for clarity.
//    if(walksSelfOnly(analysis))
//      return false;
//    else if(walksDownOnly(analysis) && !canSkipSubtrees(analysis))
//      return false;
//    else if(walksChildrenAndExtraAndSelfOnly(analysis))
//      return false;
//    else if(walksDescendantsAndExtraAndSelfOnly(analysis))
//      return false;
//    else if(walksUpOnly(analysis))
//      return false;
//    else if(walksExtraNodesOnly(analysis))
//      return false;
//    else if(walksSubtree(analysis) 
//           && (walksSideways(analysis) 
//            || walksUp(analysis) 
//            || canSkipSubtrees(analysis)))
//      return true;
//    else
//      return false;
//  }
//  
//  /**
//   * Tell if the pattern can be 'walked' with the iteration steps in natural 
//   * document order, without duplicates.
//   *
//   * @param analysis The general analysis of the pattern.
//   *
//   * @return true if the walk can be done in natural order.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  static public boolean isNaturalDocOrder(int analysis)
//  {
//    if(canCrissCross(analysis) || isSet(analysis, BIT_NAMESPACE) ||
//       walksFilteredList(analysis))
//      return false;
//      
//    if(walksInDocOrder(analysis))
//      return true;
//      
//    return false;
//  }
//  
//  /**
//   * Tell if the pattern can be 'walked' with the iteration steps in natural 
//   * document order, without duplicates.
//   *
//   * @param compiler non-null reference to compiler object that has processed
//   *                 the XPath operations into an opcode map.
//   * @param stepOpCodePos The opcode position for the step.
//   * @param stepIndex The top-level step index withing the iterator.
//   * @param analysis The general analysis of the pattern.
//   *
//   * @return true if the walk can be done in natural order.
//   *
//   * @throws javax.xml.transform.TransformerException
//   */
//  private static boolean isNaturalDocOrder(
//          Compiler compiler, int stepOpCodePos, int stepIndex, int analysis)
//            throws javax.xml.transform.TransformerException
//  {
//    if(canCrissCross(analysis))
//      return false;
//      
//    // Namespaces can present some problems, so just punt if we're looking for 
//    // these.
//    if(isSet(analysis, BIT_NAMESPACE))
//      return false;
//      
//    // The following, preceding, following-sibling, and preceding sibling can 
//    // be found in doc order if we get to this point, but if they occur 
//    // together, they produce 
//    // duplicates, so it's better for us to eliminate this case so we don't 
//    // have to check for duplicates during runtime if we're using a 
//    // WalkingIterator.
//    if(isSet(analysis, BIT_FOLLOWING | BIT_FOLLOWING_SIBLING) && 
//       isSet(analysis, BIT_PRECEDING | BIT_PRECEDING_SIBLING))
//      return  false;
//      
//    // OK, now we have to check for select="@*/axis::*" patterns, which 
//    // can also cause duplicates to happen.  But select="axis*/@::*" patterns 
//    // are OK, as are select="@foo/axis::*" patterns.
//    // Unfortunately, we can't do this just via the analysis bits.
//    
//    int stepType;
//    int ops[] = compiler.getOpMap();
//    int stepCount = 0;
//    boolean foundWildAttribute = false;
//    
//    // Steps that can traverse anything other than down a 
//    // subtree or that can produce duplicates when used in 
//    // combonation are counted with this variable.
//    int potentialDuplicateMakingStepCount = 0;
//    
//    while (OpCodes.ENDOP != (stepType = ops[stepOpCodePos]))
//    {        
//      stepCount++;
//        
//      switch (stepType)
//      {
//      case OpCodes.FROM_ATTRIBUTES :
//      case OpCodes.MATCH_ATTRIBUTE :
//        if(foundWildAttribute) // Maybe not needed, but be safe.
//          return false;
//        
//        // This doesn't seem to work as a test for wild card.  Hmph.
//        // int nodeTestType = compiler.getStepTestType(stepOpCodePos);  
//        
//        String localName = compiler.getStepLocalName(stepOpCodePos);
//        // System.err.println("localName: "+localName);
//        if(localName.equals("*"))
//        {
//          foundWildAttribute = true;
//        }
//        break;
//      case OpCodes.FROM_FOLLOWING :
//      case OpCodes.FROM_FOLLOWING_SIBLINGS :
//      case OpCodes.FROM_PRECEDING :
//      case OpCodes.FROM_PRECEDING_SIBLINGS :
//      case OpCodes.FROM_PARENT :
//      case OpCodes.OP_VARIABLE :
//      case OpCodes.OP_EXTFUNCTION :
//      case OpCodes.OP_FUNCTION :
//      case OpCodes.OP_GROUP :
//      case OpCodes.FROM_NAMESPACE :
//      case OpCodes.FROM_ANCESTORS :
//      case OpCodes.FROM_ANCESTORS_OR_SELF :      
//      case OpCodes.MATCH_ANY_ANCESTOR :
//      case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
//      case OpCodes.FROM_DESCENDANTS_OR_SELF :
//      case OpCodes.FROM_DESCENDANTS :
//        if(potentialDuplicateMakingStepCount > 0)
//            return false;
//        potentialDuplicateMakingStepCount++;
//      case OpCodes.FROM_ROOT :
//      case OpCodes.FROM_CHILDREN :
//      case OpCodes.FROM_SELF :
//        if(foundWildAttribute)
//          return false;
//        break;
//      default :
//        throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, new Object[]{Integer.toString(stepType)})); //"Programmer's assertion: unknown opcode: "
//                                  // + stepType);
//      }
//
//      int nextStepOpCodePos = compiler.getNextStepPos(stepOpCodePos);
//
//      if (nextStepOpCodePos < 0)
//        break;
//              
//      stepOpCodePos = nextStepOpCodePos;
//    }
//
//    return true;
//  }
//  
//  public static boolean isOneStep(int analysis)
//  {
//    return (analysis & BITS_COUNT) == 0x00000001;
//  }
//
//  public static int getStepCount(int analysis)
//  {
//    return (analysis & BITS_COUNT);
//  }
//
//  /**
//   * First 8 bits are the number of top-level location steps.  Hopefully
//   *  there will never be more that 255 location steps!!!
//   */
//  public static final int BITS_COUNT = 0x000000FF;
//
//  /** 4 bits are reserved for future use. */
//  public static final int BITS_RESERVED = 0x00000F00;
//
//  /** Bit is on if the expression contains a top-level predicate. */
//  public static final int BIT_PREDICATE = (0x00001000);
//
//  /** Bit is on if any of the walkers contain an ancestor step. */
//  public static final int BIT_ANCESTOR = (0x00001000 << 1);
//
//  /** Bit is on if any of the walkers contain an ancestor-or-self step. */
//  public static final int BIT_ANCESTOR_OR_SELF = (0x00001000 << 2);
//
//  /** Bit is on if any of the walkers contain an attribute step. */
//  public static final int BIT_ATTRIBUTE = (0x00001000 << 3);
//
//  /** Bit is on if any of the walkers contain a child step. */
//  public static final int BIT_CHILD = (0x00001000 << 4);
//
//  /** Bit is on if any of the walkers contain a descendant step. */
//  public static final int BIT_DESCENDANT = (0x00001000 << 5);
//
//  /** Bit is on if any of the walkers contain a descendant-or-self step. */
//  public static final int BIT_DESCENDANT_OR_SELF = (0x00001000 << 6);
//
//  /** Bit is on if any of the walkers contain a following step. */
//  public static final int BIT_FOLLOWING = (0x00001000 << 7);
//
//  /** Bit is on if any of the walkers contain a following-sibiling step. */
//  public static final int BIT_FOLLOWING_SIBLING = (0x00001000 << 8);
//
//  /** Bit is on if any of the walkers contain a namespace step. */
//  public static final int BIT_NAMESPACE = (0x00001000 << 9);
//
//  /** Bit is on if any of the walkers contain a parent step. */
//  public static final int BIT_PARENT = (0x00001000 << 10);
//
//  /** Bit is on if any of the walkers contain a preceding step. */
//  public static final int BIT_PRECEDING = (0x00001000 << 11);
//
//  /** Bit is on if any of the walkers contain a preceding-sibling step. */
//  public static final int BIT_PRECEDING_SIBLING = (0x00001000 << 12);
//
//  /** Bit is on if any of the walkers contain a self step. */
//  public static final int BIT_SELF = (0x00001000 << 13);
//
//  /**
//   * Bit is on if any of the walkers contain a filter (i.e. id(), extension
//   *  function, etc.) step.
//   */
//  public static final int BIT_FILTER = (0x00001000 << 14);
//
//  /** Bit is on if any of the walkers contain a root step. */
//  public static final int BIT_ROOT = (0x00001000 << 15);
//
//  /**
//   * If any of these bits are on, the expression may likely traverse outside
//   *  the given subtree.
//   */
//  public static final int BITMASK_TRAVERSES_OUTSIDE_SUBTREE = (BIT_NAMESPACE  // ??
//                                                                | BIT_PRECEDING_SIBLING
//                                                                | BIT_PRECEDING
//                                                                | BIT_FOLLOWING_SIBLING
//                                                                | BIT_FOLLOWING
//                                                                | BIT_PARENT  // except parent of attrs.
//                                                                | BIT_ANCESTOR_OR_SELF
//                                                                | BIT_ANCESTOR
//                                                                | BIT_FILTER
//                                                                | BIT_ROOT);
//
//  /**
//   * Bit is on if any of the walkers can go backwards in document
//   *  order from the context node.
//   */
//  public static final int BIT_BACKWARDS_SELF = (0x00001000 << 16);
//
//  /** Found "//foo" pattern */
//  public static final int BIT_ANY_DESCENDANT_FROM_ROOT = (0x00001000 << 17);
//
//  /**
//   * Bit is on if any of the walkers contain an node() test.  This is
//   *  really only useful if the count is 1.
//   */
//  public static final int BIT_NODETEST_ANY = (0x00001000 << 18);
//
//  // can't go higher than 18!
//
//  /** Bit is on if the expression is a match pattern. */
//  public static final int BIT_MATCH_PATTERN = (0x00001000 << 19);
//}
