19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one
39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * or more contributor license agreements. See the NOTICE file
49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed with this work for additional information
59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * regarding copyright ownership. The ASF licenses this file
69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to you under the Apache License, Version 2.0 (the  "License");
79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * you may not use this file except in compliance with the License.
89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * You may obtain a copy of the License at
99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Unless required by applicable law or agreed to in writing, software
139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * See the License for the specific language governing permissions and
169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * limitations under the License.
179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * $Id: RedundentExprEliminator.java 468643 2006-10-28 06:56:03Z minchau $
209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpackage org.apache.xalan.templates;
229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.util.Vector;
249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xalan.res.XSLMessages;
269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xalan.res.XSLTErrorResources;
279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.utils.QName;
289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.utils.WrappedRuntimeException;
299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.Expression;
309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.ExpressionNode;
319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.ExpressionOwner;
329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.XPath;
339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.axes.AxesWalker;
349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.axes.FilterExprIteratorSimple;
359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.axes.FilterExprWalker;
369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.axes.LocPathIterator;
379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.axes.SelfIteratorNoPredicate;
389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.axes.WalkerFactory;
399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.axes.WalkingIterator;
409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.operations.Variable;
419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.operations.VariableSafeAbsRef;
429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/**
449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This class eleminates redundent XPaths from a given subtree,
459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * and also collects all absolute paths within the subtree.  First
469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * it must be called as a visitor to the subtree, and then
479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * eleminateRedundent must be called.
489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpublic class RedundentExprEliminator extends XSLTVisitor
509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  Vector m_paths;
529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  Vector m_absPaths;
539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  boolean m_isSameContext;
549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  AbsPathChecker m_absPathChecker = new AbsPathChecker();
559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private static int m_uniquePseudoVarID = 1;
579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  static final String PSUEDOVARNAMESPACE = Constants.S_VENDORURL+"/xalan/psuedovar";
589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public static final boolean DEBUG = false;
609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public static final boolean DIAGNOSE_NUM_PATHS_REDUCED = false;
619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public static final boolean DIAGNOSE_MULTISTEPLIST = false;
629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * So we can reuse it over and over again.
659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  VarNameCollector m_varNameCollector = new VarNameCollector();
679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Construct a RedundentExprEliminator.
709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public RedundentExprEliminator()
729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_isSameContext = true;
749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_absPaths = new Vector();
759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_paths = null;
769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Method to be called after the all expressions within an
819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * node context have been visited.  It eliminates redundent
829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * expressions by creating a variable in the psuedoVarRecipient
839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * for each redundent expression, and then rewriting the redundent
849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * expression to be a variable reference.
859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param psuedoVarRecipient The recipient of the psuedo vars.  The
879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * variables will be inserted as first children of the element, before
889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * any existing variables.
899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void eleminateRedundentLocals(ElemTemplateElement psuedoVarRecipient)
919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eleminateRedundent(psuedoVarRecipient, m_paths);
939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Method to be called after the all global expressions within a stylesheet
979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * have been collected.  It eliminates redundent
989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * expressions by creating a variable in the psuedoVarRecipient
999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * for each redundent expression, and then rewriting the redundent
1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * expression to be a variable reference.
1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void eleminateRedundentGlobals(StylesheetRoot stylesheet)
1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eleminateRedundent(stylesheet, m_absPaths);
1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Method to be called after the all expressions within an
1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * node context have been visited.  It eliminates redundent
1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * expressions by creating a variable in the psuedoVarRecipient
1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * for each redundent expression, and then rewriting the redundent
1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * expression to be a variable reference.
1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param psuedoVarRecipient The owner of the subtree from where the
1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *                           paths were collected.
1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param paths A vector of paths that hold ExpressionOwner objects,
1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *              which must yield LocationPathIterators.
1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected void eleminateRedundent(ElemTemplateElement psuedoVarRecipient, Vector paths)
1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int n = paths.size();
1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int numPathsEliminated = 0;
1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int numUniquePathsEliminated = 0;
1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    for (int i = 0; i < n; i++)
1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      ExpressionOwner owner = (ExpressionOwner) paths.elementAt(i);
1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (null != owner)
1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        int found = findAndEliminateRedundant(i + 1, i, owner, psuedoVarRecipient, paths);
1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (found > 0)
1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                  numUniquePathsEliminated++;
1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        numPathsEliminated += found;
1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eleminateSharedPartialPaths(psuedoVarRecipient, paths);
1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(DIAGNOSE_NUM_PATHS_REDUCED)
1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		diagnoseNumPaths(paths, numPathsEliminated, numUniquePathsEliminated);
1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Eliminate the shared partial paths in the expression list.
1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param psuedoVarRecipient The recipient of the psuedo vars.
1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param paths A vector of paths that hold ExpressionOwner objects,
1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *              which must yield LocationPathIterators.
1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected void eleminateSharedPartialPaths(ElemTemplateElement psuedoVarRecipient, Vector paths)
1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	MultistepExprHolder list = createMultistepExprList(paths);
1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(null != list)
1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(DIAGNOSE_MULTISTEPLIST)
1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        	list.diagnose();
1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        boolean isGlobal = (paths == m_absPaths);
1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Iterate over the list, starting with the most number of paths,
1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // trying to find the longest matches first.
1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        int longestStepsCount = list.m_stepCount;
1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    	for (int i = longestStepsCount-1; i >= 1; i--)
1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    	{
1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    		MultistepExprHolder next = list;
1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        	while(null != next)
1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        	{
1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        		if(next.m_stepCount < i)
1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        			break;
1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				list = matchAndEliminatePartialPaths(next, list, isGlobal, i, psuedoVarRecipient);
1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				next = next.m_next;
1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        	}
1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    	}
1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * For a given path, see if there are any partitial matches in the list,
1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * and, if there are, replace those partial paths with psuedo variable refs,
1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * and create the psuedo variable decl.
1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return The head of the list, which may have changed.
1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected MultistepExprHolder matchAndEliminatePartialPaths(MultistepExprHolder testee,
1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                               MultistepExprHolder head,
1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                               boolean isGlobal,
1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                               int lengthToTest,
1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                               ElemTemplateElement varScope)
1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(null == testee.m_exprOwner)
1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		return head;
1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Start with the longest possible match, and move down.
1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    WalkingIterator iter1 = (WalkingIterator) testee.m_exprOwner.getExpression();
1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(partialIsVariable(testee, lengthToTest))
1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    	return head;
1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    MultistepExprHolder matchedPaths = null;
2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    MultistepExprHolder matchedPathsTail = null;
2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    MultistepExprHolder meh = head;
2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    while( null != meh)
2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if ((meh != testee) && (null != meh.m_exprOwner))
2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	      WalkingIterator iter2 = (WalkingIterator) meh.m_exprOwner.getExpression();
2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	      if (stepsEqual(iter1, iter2, lengthToTest))
2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	      {
2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        if (null == matchedPaths)
2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        {
2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          try
2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          {
2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          	matchedPaths = (MultistepExprHolder)testee.clone();
2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          	testee.m_exprOwner = null; // So it won't be processed again.
2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          }
2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          catch(CloneNotSupportedException cnse){}
2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          matchedPathsTail = matchedPaths;
2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          matchedPathsTail.m_next = null;
2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        }
2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        try
2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        {
2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          matchedPathsTail.m_next = (MultistepExprHolder)meh.clone();
2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	          meh.m_exprOwner = null; // So it won't be processed again.
2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        }
2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        catch(CloneNotSupportedException cnse){}
2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        matchedPathsTail = matchedPathsTail.m_next;
2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	        matchedPathsTail.m_next = null;
2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	      }
2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      meh = meh.m_next;
2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int matchCount = 0;
2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if(null != matchedPaths)
2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ElemTemplateElement root = isGlobal ? varScope : findCommonAncestor(matchedPaths);
2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		WalkingIterator sharedIter = (WalkingIterator)matchedPaths.m_exprOwner.getExpression();
2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		WalkingIterator newIter = createIteratorFromSteps(sharedIter, lengthToTest);
2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ElemVariable var = createPseudoVarDecl(root, newIter, isGlobal);
2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if(DIAGNOSE_MULTISTEPLIST)
2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			System.err.println("Created var: "+var.getName()+(isGlobal ? "(Global)" : ""));
2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		while(null != matchedPaths)
2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			ExpressionOwner owner = matchedPaths.m_exprOwner;
2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			WalkingIterator iter = (WalkingIterator)owner.getExpression();
2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if(DIAGNOSE_MULTISTEPLIST)
2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				diagnoseLineNumber(iter);
2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			LocPathIterator newIter2 =
2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			    changePartToRef(var.getName(), iter, lengthToTest, isGlobal);
2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			owner.setExpression(newIter2);
2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			matchedPaths = matchedPaths.m_next;
2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if(DIAGNOSE_MULTISTEPLIST)
2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		diagnoseMultistepList(matchCount, lengthToTest, isGlobal);
2619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return head;
2629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
2659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Check if results of partial reduction will just be a variable, in
2669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * which case, skip it.
2679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
2689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  boolean partialIsVariable(MultistepExprHolder testee, int lengthToTest)
2699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(1 == lengthToTest)
2719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
2729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		WalkingIterator wi = (WalkingIterator)testee.m_exprOwner.getExpression();
2739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(wi.getFirstWalker() instanceof FilterExprWalker)
2749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			return true;
2759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
2769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return false;
2779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
2809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Tell what line number belongs to a given expression.
2819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
2829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected void diagnoseLineNumber(Expression expr)
2839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    ElemTemplateElement e = getElemFromExpression(expr);
2859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    System.err.println("   " + e.getSystemId() + " Line " + e.getLineNumber());
2869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
2899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Given a linked list of expressions, find the common ancestor that is
2909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * suitable for holding a psuedo variable for shared access.
2919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
2929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected ElemTemplateElement findCommonAncestor(MultistepExprHolder head)
2939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// Not sure this algorithm is the best, but will do for the moment.
2959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	int numExprs = head.getLength();
2969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// The following could be made cheaper by pre-allocating large arrays,
2979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// but then we would have to assume a max number of reductions,
2989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// which I am not inclined to do right now.
2999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    ElemTemplateElement[] elems = new ElemTemplateElement[numExprs];
3009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int[] ancestorCounts = new int[numExprs];
3019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Loop through, getting the parent elements, and counting the
3039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // ancestors.
3049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	MultistepExprHolder next = head;
3059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	int shortestAncestorCount = 10000;
3069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	for(int i = 0; i < numExprs; i++)
3079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
3089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		ElemTemplateElement elem =
3099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			getElemFromExpression(next.m_exprOwner.getExpression());
3109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		elems[i] = elem;
3119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		int numAncestors = countAncestors(elem);
3129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		ancestorCounts[i] = numAncestors;
3139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(numAncestors < shortestAncestorCount)
3149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
3159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			shortestAncestorCount = numAncestors;
3169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
3179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		next = next.m_next;
3189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
3199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// Now loop through and "correct" the elements that have more ancestors.
3219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	for(int i = 0; i < numExprs; i++)
3229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
3239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(ancestorCounts[i] > shortestAncestorCount)
3249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
3259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			int numStepCorrection = ancestorCounts[i] - shortestAncestorCount;
3269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			for(int j = 0; j < numStepCorrection; j++)
3279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			{
3289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				elems[i] = elems[i].getParentElem();
3299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			}
3309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
3319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
3329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// Now everyone has an equal number of ancestors.  Walk up from here
3349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// equally until all are equal.
3359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	ElemTemplateElement first = null;
3369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	while(shortestAncestorCount-- >= 0)
3379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
3389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		boolean areEqual = true;
3399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		first = elems[0];
3409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		for(int i = 1; i < numExprs; i++)
3419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
3429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			if(first != elems[i])
3439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			{
3449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				areEqual = false;
3459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				break;
3469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			}
3479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
3489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		// This second check is to make sure we have a common ancestor that is not the same
3499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		// as the expression owner... i.e. the var decl has to go above the expression owner.
3509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(areEqual && isNotSameAsOwner(head, first) && first.canAcceptVariables())
3519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
3529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			if(DIAGNOSE_MULTISTEPLIST)
3539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			{
3549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				System.err.print(first.getClass().getName());
3559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				System.err.println(" at   " + first.getSystemId() + " Line " + first.getLineNumber());
3569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			}
3579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			return first;
3589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
3599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		for(int i = 0; i < numExprs; i++)
3619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
3629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			elems[i] = elems[i].getParentElem();
3639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
3649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
3659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	assertion(false, "Could not find common ancestor!!!");
3679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return null;
3689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
3719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Find out if the given ElemTemplateElement is not the same as one of
3729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the ElemTemplateElement owners of the expressions.
3739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
3749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param head Head of linked list of expression owners.
3759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param ete The ElemTemplateElement that is a candidate for a psuedo
3769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * variable parent.
3779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return true if the given ElemTemplateElement is not the same as one of
3789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the ElemTemplateElement owners of the expressions.  This is to make sure
3799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * we find an ElemTemplateElement that is in a viable position to hold
3809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * psuedo variables that are visible to the references.
3819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
3829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected boolean isNotSameAsOwner(MultistepExprHolder head, ElemTemplateElement ete)
3839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	MultistepExprHolder next = head;
3859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	while(null != next)
3869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
3879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		ElemTemplateElement elemOwner = getElemFromExpression(next.m_exprOwner.getExpression());
3889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(elemOwner == ete)
3899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			return false;
3909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		next = next.m_next;
3919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
3929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return true;
3939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
3969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Count the number of ancestors that a ElemTemplateElement has.
3979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
3989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param elem An representation of an element in an XSLT stylesheet.
3999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return The number of ancestors of elem (including the element itself).
4009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
4019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected int countAncestors(ElemTemplateElement elem)
4029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	int count = 0;
4049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	while(null != elem)
4059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
4069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		count++;
4079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		elem = elem.getParentElem();
4089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
4099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return count;
4109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
4139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Print out diagnostics about partial multistep evaluation.
4149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
4159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected void diagnoseMultistepList(
4169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      int matchCount,
4179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      int lengthToTest,
4189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      boolean isGlobal)
4199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (matchCount > 0)
4219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
4229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        System.err.print(
4239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          "Found multistep matches: " + matchCount + ", " + lengthToTest + " length");
4249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (isGlobal)
4259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              System.err.println(" (global)");
4269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        else
4279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              System.err.println();
4289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
4299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
4329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Change a given number of steps to a single variable reference.
4339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param uniquePseudoVarName The name of the variable reference.
4359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param wi The walking iterator that is to be changed.
4369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param numSteps The number of steps to be changed.
4379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param isGlobal true if this will be a global reference.
4389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
4399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected LocPathIterator changePartToRef(final QName uniquePseudoVarName, WalkingIterator wi,
4409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                 final int numSteps, final boolean isGlobal)
4419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	Variable var = new Variable();
4439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	var.setQName(uniquePseudoVarName);
4449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	var.setIsGlobal(isGlobal);
4459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(isGlobal)
4469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{	ElemTemplateElement elem = getElemFromExpression(wi);
4479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		StylesheetRoot root = elem.getStylesheetRoot();
4489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		Vector vars = root.getVariablesAndParamsComposed();
4499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		var.setIndex(vars.size()-1);
4509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
4519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// Walk to the first walker after the one's we are replacing.
4539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	AxesWalker walker = wi.getFirstWalker();
4549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	for(int i = 0; i < numSteps; i++)
4559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
4569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		assertion(null != walker, "Walker should not be null!");
4579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		walker = walker.getNextWalker();
4589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
4599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(null != walker)
4619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
4629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  FilterExprWalker few = new FilterExprWalker(wi);
4649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  few.setInnerExpression(var);
4659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  few.exprSetParent(wi);
4669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  few.setNextWalker(walker);
4679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  walker.setPrevWalker(few);
4689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  wi.setFirstWalker(few);
4699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  return wi;
4709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
4719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	else
4729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
4739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  FilterExprIteratorSimple feis = new FilterExprIteratorSimple(var);
4749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  feis.exprSetParent(wi.exprGetParent());
4759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  return feis;
4769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
4779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
4809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Create a new WalkingIterator from the steps in another WalkingIterator.
4819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param wi The iterator from where the steps will be taken.
4839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param numSteps The number of steps from the first to copy into the new
4849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *                 iterator.
4859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return The new iterator.
4869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
4879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected WalkingIterator createIteratorFromSteps(final WalkingIterator wi, int numSteps)
4889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	WalkingIterator newIter = new WalkingIterator(wi.getPrefixResolver());
4909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	try
4919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
4929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		AxesWalker walker = (AxesWalker)wi.getFirstWalker().clone();
4939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		newIter.setFirstWalker(walker);
4949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		walker.setLocPathIterator(newIter);
4959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		for(int i = 1; i < numSteps; i++)
4969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
4979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			AxesWalker next = (AxesWalker)walker.getNextWalker().clone();
4989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			walker.setNextWalker(next);
4999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			next.setLocPathIterator(newIter);
5009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			walker = next;
5019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
5029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		walker.setNextWalker(null);
5039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
5049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	catch(CloneNotSupportedException cnse)
5059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
5069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		throw new WrappedRuntimeException(cnse);
5079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
5089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return newIter;
5099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
5109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
5129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Compare a given number of steps between two iterators, to see if they are equal.
5139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
5149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param iter1 The first iterator to compare.
5159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param iter2 The second iterator to compare.
5169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param numSteps The number of steps to compare.
5179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return true If the given number of steps are equal.
5189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
5199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
5209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected boolean stepsEqual(WalkingIterator iter1, WalkingIterator iter2,
5219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                         int numSteps)
5229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
5239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	AxesWalker aw1 = iter1.getFirstWalker();
5249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	AxesWalker aw2 = iter2.getFirstWalker();
5259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	for(int i = 0; (i < numSteps); i++)
5279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
5289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if((null == aw1) || (null == aw2))
5299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		 	return false;
5309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(!aw1.deepEquals(aw2))
5329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			return false;
5339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		aw1 = aw1.getNextWalker();
5359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		aw2 = aw2.getNextWalker();
5369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
5379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	assertion((null != aw1) || (null != aw2), "Total match is incorrect!");
5399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return true;
5419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
5429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
5449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * For the reduction of location path parts, create a list of all
5459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the multistep paths with more than one step, sorted by the
5469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * number of steps, with the most steps occuring earlier in the list.
5479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * If the list is only one member, don't bother returning it.
5489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
5499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param paths Vector of ExpressionOwner objects, which may contain null entries.
5509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *              The ExpressionOwner objects must own LocPathIterator objects.
5519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return null if no multipart paths are found or the list is only of length 1,
5529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * otherwise the first MultistepExprHolder in a linked list of these objects.
5539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
5549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected MultistepExprHolder createMultistepExprList(Vector paths)
5559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
5569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	MultistepExprHolder first = null;
5579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	int n = paths.size();
5589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	for(int i = 0; i < n; i++)
5599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
5609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		ExpressionOwner eo = (ExpressionOwner)paths.elementAt(i);
5619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(null == eo)
5629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			continue;
5639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		// Assuming location path iterators should be OK.
5659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		LocPathIterator lpi = (LocPathIterator)eo.getExpression();
5669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		int numPaths = countSteps(lpi);
5679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(numPaths > 1)
5689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
5699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			if(null == first)
5709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				first = new MultistepExprHolder(eo, numPaths, null);
5719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			else
5729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				first = first.addInSortedOrder(eo, numPaths);
5739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
5749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
5759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if((null == first) || (first.getLength() <= 1))
5779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		return null;
5789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	else
5799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		return first;
5809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
5819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
5839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Look through the vector from start point, looking for redundant occurances.
5849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * When one or more are found, create a psuedo variable declaration, insert
5859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * it into the stylesheet, and replace the occurance with a reference to
5869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the psuedo variable.  When a redundent variable is found, it's slot in
5879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the vector will be replaced by null.
5889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
5899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param start The position to start looking in the vector.
5909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param firstOccuranceIndex The position of firstOccuranceOwner.
5919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param firstOccuranceOwner The owner of the expression we are looking for.
5929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param psuedoVarRecipient Where to put the psuedo variables.
5939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
5949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return The number of expression occurances that were modified.
5959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
5969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected int findAndEliminateRedundant(int start, int firstOccuranceIndex,
5979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                         ExpressionOwner firstOccuranceOwner,
5989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                         ElemTemplateElement psuedoVarRecipient,
5999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                         Vector paths)
6009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 throws org.w3c.dom.DOMException
6019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
6029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	MultistepExprHolder head = null;
6039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	MultistepExprHolder tail = null;
6049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int numPathsFound = 0;
6059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int n = paths.size();
6069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	Expression expr1 = firstOccuranceOwner.getExpression();
6089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if(DEBUG)
6099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		assertIsLocPathIterator(expr1, firstOccuranceOwner);
6109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	boolean isGlobal = (paths == m_absPaths);
6119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	LocPathIterator lpi = (LocPathIterator)expr1;
6129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int stepCount = countSteps(lpi);
6139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	for(int j = start; j < n; j++)
6149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
6159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ExpressionOwner owner2 = (ExpressionOwner)paths.elementAt(j);
6169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if(null != owner2)
6179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
6189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			Expression expr2 = owner2.getExpression();
6199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			boolean isEqual = expr2.deepEquals(lpi);
6209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if(isEqual)
6219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			{
6229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				LocPathIterator lpi2  = (LocPathIterator)expr2;
6239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				if(null == head)
6249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				{
6259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					head = new MultistepExprHolder(firstOccuranceOwner, stepCount, null);
6269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					tail = head;
6279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					numPathsFound++;
6289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				}
6299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				tail.m_next = new MultistepExprHolder(owner2, stepCount, null);
6309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				tail = tail.m_next;
6319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				// Null out the occurance, so we don't have to test it again.
6339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				paths.setElementAt(null, j);
6349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				// foundFirst = true;
6369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				numPathsFound++;
6379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			}
6389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
6399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
6409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	// Change all globals in xsl:templates, etc, to global vars no matter what.
6429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if((0 == numPathsFound) && isGlobal)
6439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
6449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      head = new MultistepExprHolder(firstOccuranceOwner, stepCount, null);
6459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      numPathsFound++;
6469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
6479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if(null != head)
6499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
6509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ElemTemplateElement root = isGlobal ? psuedoVarRecipient : findCommonAncestor(head);
6519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		LocPathIterator sharedIter = (LocPathIterator)head.m_exprOwner.getExpression();
6529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ElemVariable var = createPseudoVarDecl(root, sharedIter, isGlobal);
6539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if(DIAGNOSE_MULTISTEPLIST)
6549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			System.err.println("Created var: "+var.getName()+(isGlobal ? "(Global)" : ""));
6559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		QName uniquePseudoVarName = var.getName();
6569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		while(null != head)
6579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
6589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			ExpressionOwner owner = head.m_exprOwner;
6599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if(DIAGNOSE_MULTISTEPLIST)
6609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				diagnoseLineNumber(owner.getExpression());
6619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			changeToVarRef(uniquePseudoVarName, owner, paths, root);
6629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			head = head.m_next;
6639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
6649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		// Replace the first occurance with the variable's XPath, so
6659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		// that further reduction may take place if needed.
6669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		paths.setElementAt(var.getSelect(), firstOccuranceIndex);
6679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
6689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return numPathsFound;
6709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
6719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
6739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * To be removed.
6749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
6759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected int oldFindAndEliminateRedundant(int start, int firstOccuranceIndex,
6769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                         ExpressionOwner firstOccuranceOwner,
6779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                         ElemTemplateElement psuedoVarRecipient,
6789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                         Vector paths)
6799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 throws org.w3c.dom.DOMException
6809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
6819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	QName uniquePseudoVarName = null;
6829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	boolean foundFirst = false;
6839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int numPathsFound = 0;
6849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int n = paths.size();
6859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	Expression expr1 = firstOccuranceOwner.getExpression();
6869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if(DEBUG)
6879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		assertIsLocPathIterator(expr1, firstOccuranceOwner);
6889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	boolean isGlobal = (paths == m_absPaths);
6899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	LocPathIterator lpi = (LocPathIterator)expr1;
6909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	for(int j = start; j < n; j++)
6919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
6929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ExpressionOwner owner2 = (ExpressionOwner)paths.elementAt(j);
6939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if(null != owner2)
6949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
6959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			Expression expr2 = owner2.getExpression();
6969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			boolean isEqual = expr2.deepEquals(lpi);
6979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if(isEqual)
6989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			{
6999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				LocPathIterator lpi2  = (LocPathIterator)expr2;
7009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				if(!foundFirst)
7019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				{
7029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					foundFirst = true;
7039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					// Insert variable decl into psuedoVarRecipient
7049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					// We want to insert this into the first legitimate
7059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					// position for a variable.
7069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				    ElemVariable var = createPseudoVarDecl(psuedoVarRecipient, lpi, isGlobal);
7079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				    if(null == var)
7089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				    	return 0;
7099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				    uniquePseudoVarName = var.getName();
7109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					changeToVarRef(uniquePseudoVarName, firstOccuranceOwner,
7129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					               paths, psuedoVarRecipient);
7139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					// Replace the first occurance with the variable's XPath, so
7159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					// that further reduction may take place if needed.
7169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					paths.setElementAt(var.getSelect(), firstOccuranceIndex);
7179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					numPathsFound++;
7189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				}
7199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				changeToVarRef(uniquePseudoVarName, owner2, paths, psuedoVarRecipient);
7219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				// Null out the occurance, so we don't have to test it again.
7239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				paths.setElementAt(null, j);
7249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				// foundFirst = true;
7269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				numPathsFound++;
7279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			}
7289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
7299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
7309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	// Change all globals in xsl:templates, etc, to global vars no matter what.
7329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if((0 == numPathsFound) && (paths == m_absPaths))
7339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
7349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      ElemVariable var = createPseudoVarDecl(psuedoVarRecipient, lpi, true);
7359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(null == var)
7369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return 0;
7379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	  uniquePseudoVarName = var.getName();
7389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      changeToVarRef(uniquePseudoVarName, firstOccuranceOwner, paths, psuedoVarRecipient);
7399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      paths.setElementAt(var.getSelect(), firstOccuranceIndex);
7409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      numPathsFound++;
7419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
7429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return numPathsFound;
7439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
7449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
7469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Count the steps in a given location path.
7479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
7489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param lpi The location path iterator that owns the steps.
7499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return The number of steps in the given location path.
7509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
7519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected int countSteps(LocPathIterator lpi)
7529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
7539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(lpi instanceof WalkingIterator)
7549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
7559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		WalkingIterator wi = (WalkingIterator)lpi;
7569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		AxesWalker aw = wi.getFirstWalker();
7579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		int count = 0;
7589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		while(null != aw)
7599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
7609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			count++;
7619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			aw = aw.getNextWalker();
7629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
7639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		return count;
7649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
7659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	else
7669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		return 1;
7679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
7689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
7709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Change the expression owned by the owner argument to a variable reference
7719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * of the given name.
7729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
7739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Warning: For global vars, this function relies on the variable declaration
7749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * to which it refers having been added just prior to this function being called,
7759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * so that the reference index can be determined from the size of the global variables
7769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * list minus one.
7779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
7789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param varName The name of the variable which will be referenced.
7799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param owner The owner of the expression which will be replaced by a variable ref.
7809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param paths The paths list that the iterator came from, mainly to determine
7819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *              if this is a local or global reduction.
7829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param psuedoVarRecipient The element within whose scope the variable is
7839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *                           being inserted, possibly a StylesheetRoot.
7849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
7859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected void changeToVarRef(QName varName, ExpressionOwner owner,
7869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                Vector paths, ElemTemplateElement psuedoVarRecipient)
7879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
7889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	Variable varRef = (paths == m_absPaths) ? new VariableSafeAbsRef() : new Variable();
7899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	varRef.setQName(varName);
7909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	if(paths == m_absPaths)
7919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
7929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		StylesheetRoot root = (StylesheetRoot)psuedoVarRecipient;
7939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		Vector globalVars = root.getVariablesAndParamsComposed();
7949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		// Assume this operation is occuring just after the decl has
7959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		// been added.
7969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		varRef.setIndex(globalVars.size()-1);
7979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		varRef.setIsGlobal(true);
7989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
7999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	owner.setExpression(varRef);
8009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
8019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private synchronized static int getPseudoVarID(){
8039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      return m_uniquePseudoVarID++;
8049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
8059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
8079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Create a psuedo variable reference that will represent the
8089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * shared redundent XPath, and add it to the stylesheet.
8099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
8109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param psuedoVarRecipient The broadest scope of where the variable
8119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * should be inserted, usually an xsl:template or xsl:for-each.
8129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param lpi The LocationPathIterator that the variable should represent.
8139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param isGlobal true if the paths are global.
8149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return The new psuedo var element.
8159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
8169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected ElemVariable createPseudoVarDecl(
8179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      ElemTemplateElement psuedoVarRecipient,
8189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      LocPathIterator lpi, boolean isGlobal)
8199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throws org.w3c.dom.DOMException
8209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
8219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    QName uniquePseudoVarName = new QName (PSUEDOVARNAMESPACE, "#"+getPseudoVarID());
8229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(isGlobal)
8249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
8259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  return createGlobalPseudoVarDecl(uniquePseudoVarName,
8269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	                                  (StylesheetRoot)psuedoVarRecipient, lpi);
8279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
8289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	else
8299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      return createLocalPseudoVarDecl(uniquePseudoVarName, psuedoVarRecipient, lpi);
8309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
8319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
8339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Create a psuedo variable reference that will represent the
8349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * shared redundent XPath, for a local reduction.
8359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
8369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param uniquePseudoVarName The name of the new variable.
8379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param stylesheetRoot The broadest scope of where the variable
8389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *        should be inserted, which must be a StylesheetRoot element in this case.
8399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param lpi The LocationPathIterator that the variable should represent.
8409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return null if the decl was not created, otherwise the new Pseudo var
8419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *              element.
8429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
8439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected ElemVariable createGlobalPseudoVarDecl(QName uniquePseudoVarName,
8449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                           StylesheetRoot stylesheetRoot,
8459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                           LocPathIterator lpi)
8469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        throws org.w3c.dom.DOMException
8479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
8489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	ElemVariable psuedoVar = new ElemVariable();
8499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	psuedoVar.setIsTopLevel(true);
8509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	XPath xpath = new XPath(lpi);
8519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	psuedoVar.setSelect(xpath);
8529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	psuedoVar.setName(uniquePseudoVarName);
8539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	Vector globalVars = stylesheetRoot.getVariablesAndParamsComposed();
8559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	psuedoVar.setIndex(globalVars.size());
8569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	globalVars.addElement(psuedoVar);
8579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	return psuedoVar;
8589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
8599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
8649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Create a psuedo variable reference that will represent the
8659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * shared redundent XPath, for a local reduction.
8669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
8679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param uniquePseudoVarName The name of the new variable.
8689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param psuedoVarRecipient The broadest scope of where the variable
8699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * should be inserted, usually an xsl:template or xsl:for-each.
8709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param lpi The LocationPathIterator that the variable should represent.
8719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return null if the decl was not created, otherwise the new Pseudo var
8729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *              element.
8739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
8749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected ElemVariable createLocalPseudoVarDecl(QName uniquePseudoVarName,
8759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                           ElemTemplateElement psuedoVarRecipient,
8769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                           LocPathIterator lpi)
8779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        throws org.w3c.dom.DOMException
8789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
8799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ElemVariable psuedoVar = new ElemVariablePsuedo();
8809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		XPath xpath = new XPath(lpi);
8829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		psuedoVar.setSelect(xpath);
8839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		psuedoVar.setName(uniquePseudoVarName);
8849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ElemVariable var = addVarDeclToElem(psuedoVarRecipient, lpi, psuedoVar);
8869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		lpi.exprSetParent(var);
8889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return var;
8909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
8919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
8929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
8939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Add the given variable to the psuedoVarRecipient.
8949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
8959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected ElemVariable addVarDeclToElem(
8969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    ElemTemplateElement psuedoVarRecipient,
8979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    LocPathIterator lpi,
8989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    ElemVariable psuedoVar)
8999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    throws org.w3c.dom.DOMException
9009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
9019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Create psuedo variable element
9029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    ElemTemplateElement ete = psuedoVarRecipient.getFirstChildElem();
9039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
9049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    lpi.callVisitors(null, m_varNameCollector);
9059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
9069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // If the location path contains variables, we have to insert the
9079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // psuedo variable after the reference. (Otherwise, we want to
9089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // insert it as close as possible to the top, so we'll be sure
9099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // it is in scope for any other vars.
9109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (m_varNameCollector.getVarCount() > 0)
9119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
9129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      ElemTemplateElement baseElem = getElemFromExpression(lpi);
9139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      ElemVariable varElem = getPrevVariableElem(baseElem);
9149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      while (null != varElem)
9159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
9169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (m_varNameCollector.doesOccur(varElem.getName()))
9179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          {
9189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          psuedoVarRecipient = varElem.getParentElem();
9199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          ete = varElem.getNextSiblingElem();
9209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          break;
9219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
9229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        varElem = getPrevVariableElem(varElem);
9239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
9249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
9259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
9269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if ((null != ete) && (Constants.ELEMNAME_PARAMVARIABLE == ete.getXSLToken()))
9279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
9289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Can't stick something in front of a param, so abandon! (see variable13.xsl)
9299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(isParam(lpi))
9309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return null;
9319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
9329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      while (null != ete)
9339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
9349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        ete = ete.getNextSiblingElem();
9359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if ((null != ete) && Constants.ELEMNAME_PARAMVARIABLE != ete.getXSLToken())
9369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            break;
9379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
9389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
9399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    psuedoVarRecipient.insertBefore(psuedoVar, ete);
9409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_varNameCollector.reset();
9419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return psuedoVar;
9429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
9439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
9449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
9459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Tell if the expr param is contained within an xsl:param.
9469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
9479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected boolean isParam(ExpressionNode expr)
9489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
9499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	while(null != expr)
9509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
9519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(expr instanceof ElemTemplateElement)
9529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			break;
9539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		expr = expr.exprGetParent();
9549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
9559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(null != expr)
9569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
9579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		ElemTemplateElement ete = (ElemTemplateElement)expr;
9589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		while(null != ete)
9599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
9609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			int type = ete.getXSLToken();
9619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			switch(type)
9629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			{
9639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				case Constants.ELEMNAME_PARAMVARIABLE:
9649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  					return true;
9659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				case Constants.ELEMNAME_TEMPLATE:
9669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				case Constants.ELEMNAME_STYLESHEET:
9679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  					return false;
9689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			}
9699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			ete = ete.getParentElem();
9709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
9719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
9729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return false;
9739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
9749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
9759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
9769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
9779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Find the previous occurance of a xsl:variable.  Stop
9789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the search when a xsl:for-each, xsl:template, or xsl:stylesheet is
9799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * encountered.
9809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
9819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param elem Should be non-null template element.
9829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return The first previous occurance of an xsl:variable or xsl:param,
9839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * or null if none is found.
9849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
9859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected ElemVariable getPrevVariableElem(ElemTemplateElement elem)
9869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
9879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// This could be somewhat optimized.  since getPreviousSiblingElem is a
9889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// fairly expensive operation.
9899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	while(null != (elem = getPrevElementWithinContext(elem)))
9909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
9919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		int type = elem.getXSLToken();
9929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
9939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if((Constants.ELEMNAME_VARIABLE == type) ||
9949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		   (Constants.ELEMNAME_PARAMVARIABLE == type))
9959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
9969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			return (ElemVariable)elem;
9979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
9989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
9999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return null;
10009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
10019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
10029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
10039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Get the previous sibling or parent of the given template, stopping at
10049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * xsl:for-each, xsl:template, or xsl:stylesheet.
10059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
10069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param elem Should be non-null template element.
10079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return previous sibling or parent, or null if previous is xsl:for-each,
10089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * xsl:template, or xsl:stylesheet.
10099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
10109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected ElemTemplateElement getPrevElementWithinContext(ElemTemplateElement elem)
10119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
10129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	ElemTemplateElement prev = elem.getPreviousSiblingElem();
10139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(null == prev)
10149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		prev = elem.getParentElem();
10159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(null != prev)
10169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
10179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  int type = prev.getXSLToken();
10189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  if((Constants.ELEMNAME_FOREACH == type) ||
10199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	     (Constants.ELEMNAME_TEMPLATE == type) ||
10209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	     (Constants.ELEMNAME_STYLESHEET == type))
10219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  {
10229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  	prev = null;
10239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	  }
10249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
10259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return prev;
10269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
10279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
10289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
10299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * From an XPath expression component, get the ElemTemplateElement
10309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * owner.
10319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
10329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param expr Should be static expression with proper parentage.
10339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return Valid ElemTemplateElement, or throw a runtime exception
10349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * if it is not found.
10359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
10369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected ElemTemplateElement getElemFromExpression(Expression expr)
10379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
10389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	ExpressionNode parent = expr.exprGetParent();
10399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	while(null != parent)
10409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
10419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if(parent instanceof ElemTemplateElement)
10429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			return (ElemTemplateElement)parent;
10439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		parent = parent.exprGetParent();
10449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
10459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	throw new RuntimeException(XSLMessages.createMessage(XSLTErrorResources.ER_ASSERT_NO_TEMPLATE_PARENT, null));
10469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// "Programmer's error! expr has no ElemTemplateElement parent!");
10479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
10489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
10499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
10509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Tell if the given LocPathIterator is relative to an absolute path, i.e.
10519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * in not dependent on the context.
10529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
10539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return true if the LocPathIterator is not dependent on the context node.
10549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
10559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public boolean isAbsolute(LocPathIterator path)
10569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
10579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	int analysis = path.getAnalysisBits();
10589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    boolean isAbs = (WalkerFactory.isSet(analysis, WalkerFactory.BIT_ROOT) ||
10599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson           WalkerFactory.isSet(analysis, WalkerFactory.BIT_ANY_DESCENDANT_FROM_ROOT));
10609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(isAbs)
10619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
10629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    	isAbs = m_absPathChecker.checkAbsolute(path);
10639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
10649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return isAbs;
10659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
10669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
10679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
10689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
10699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Visit a LocationPath.
10709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param owner The owner of the expression, to which the expression can
10719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *              be reset if rewriting takes place.
10729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param path The LocationPath object.
10739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return true if the sub expressions should be traversed.
10749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
10759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public boolean visitLocationPath(ExpressionOwner owner, LocPathIterator path)
10769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
10779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// Don't optimize "." or single step variable paths.
10789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	// Both of these cases could use some further optimization by themselves.
10799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(path instanceof SelfIteratorNoPredicate)
10809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
10819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		return true;
10829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
10839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	else if(path instanceof WalkingIterator)
10849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
10859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		WalkingIterator wi = (WalkingIterator)path;
10869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		AxesWalker aw = wi.getFirstWalker();
10879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		if((aw instanceof FilterExprWalker) && (null == aw.getNextWalker()))
10889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		{
10899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			FilterExprWalker few = (FilterExprWalker)aw;
10909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			Expression exp = few.getInnerExpression();
10919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  			if(exp instanceof Variable)
10929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  				return true;
10939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		}
10949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
10959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
10969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (isAbsolute(path) && (null != m_absPaths))
10979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
10989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(DEBUG)
10999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        validateNewAddition(m_absPaths, owner, path);
11009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_absPaths.addElement(owner);
11019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
11029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    else if (m_isSameContext && (null != m_paths))
11039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
11049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(DEBUG)
11059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        validateNewAddition(m_paths, owner, path);
11069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_paths.addElement(owner);
11079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
11089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return true;
11109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
11119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
11139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Visit a predicate within a location path.  Note that there isn't a
11149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * proper unique component for predicates, and that the expression will
11159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * be called also for whatever type Expression is.
11169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
11179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param owner The owner of the expression, to which the expression can
11189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *              be reset if rewriting takes place.
11199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param pred The predicate object.
11209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return true if the sub expressions should be traversed.
11219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
11229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public boolean visitPredicate(ExpressionOwner owner, Expression pred)
11239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
11249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    boolean savedIsSame = m_isSameContext;
11259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_isSameContext = false;
11269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Any further down, just collect the absolute paths.
11289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    pred.callVisitors(owner, this);
11299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_isSameContext = savedIsSame;
11319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // We've already gone down the subtree, so don't go have the caller
11339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // go any further.
11349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return false;
11359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
11369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
11389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Visit an XSLT top-level instruction.
11399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
11409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param elem The xsl instruction element object.
11419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return true if the sub expressions should be traversed.
11429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
11439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   public boolean visitTopLevelInstruction(ElemTemplateElement elem)
11449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   {
11459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     int type = elem.getXSLToken();
11469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     switch(type)
11479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     {
11489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       case Constants.ELEMNAME_TEMPLATE :
11499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         return visitInstruction(elem);
11509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       default:
11519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         return true;
11529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     }
11539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   }
11549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
11579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Visit an XSLT instruction.  Any element that isn't called by one
11589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * of the other visit methods, will be called by this method.
11599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
11609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param elem The xsl instruction element object.
11619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return true if the sub expressions should be traversed.
11629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
11639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public boolean visitInstruction(ElemTemplateElement elem)
11649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
11659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int type = elem.getXSLToken();
11669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    switch (type)
11679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
11689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      case Constants.ELEMNAME_CALLTEMPLATE :
11699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      case Constants.ELEMNAME_TEMPLATE :
11709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      case Constants.ELEMNAME_FOREACH :
11719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
11729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          // Just get the select value.
11749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          if(type == Constants.ELEMNAME_FOREACH)
11759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          {
11769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            ElemForEach efe = (ElemForEach) elem;
11779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		    Expression select = efe.getSelect();
11799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		    select.callVisitors(efe, this);
11809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          }
11819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		  Vector savedPaths = m_paths;
11839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		  m_paths = new Vector();
11849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		  // Visit children.  Call the superclass callChildVisitors, because
11869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		  // we don't want to visit the xsl:for-each select attribute, or, for
11879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		  // that matter, the xsl:template's match attribute.
11889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		  elem.callChildVisitors(this, false);
11899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		  eleminateRedundentLocals(elem);
11909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		  m_paths = savedPaths;
11929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
11939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          // select.callVisitors(efe, this);
11949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          return false;
11959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
11969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      case Constants.ELEMNAME_NUMBER :
11979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      case Constants.ELEMNAME_SORT :
11989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Just collect absolute paths until and unless we can fully
11999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // analyze these cases.
12009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        boolean savedIsSame = m_isSameContext;
12019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        m_isSameContext = false;
12029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        elem.callChildVisitors(this);
12039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        m_isSameContext = savedIsSame;
12049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return false;
12059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      default :
12079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return true;
12089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
12099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
12109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // ==== DIAGNOSTIC AND DEBUG FUNCTIONS ====
12129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
12149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Print out to std err the number of paths reduced.
12159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
12169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected void diagnoseNumPaths(Vector paths, int numPathsEliminated,
12179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                  int numUniquePathsEliminated)
12189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
12199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if (numPathsEliminated > 0)
12209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
12219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		  if(paths == m_paths)
12229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		  {
12239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		    System.err.println("Eliminated " + numPathsEliminated + " total paths!");
12249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		    System.err.println(
12259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		      "Consolodated " + numUniquePathsEliminated + " redundent paths!");
12269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		  }
12279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		  else
12289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		  {
12299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		    System.err.println("Eliminated " + numPathsEliminated + " total global paths!");
12309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		    System.err.println(
12319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		      "Consolodated " + numUniquePathsEliminated + " redundent global paths!");
12329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		  }
12339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
12349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
12359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
12389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Assert that the expression is a LocPathIterator, and, if
12399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * not, try to give some diagnostic info.
12409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
12419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private final void assertIsLocPathIterator(Expression expr1, ExpressionOwner eo)
12429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    throws RuntimeException
12439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
12449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		if(!(expr1 instanceof LocPathIterator))
12459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
12469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			String errMsg;
12479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if(expr1 instanceof Variable)
12489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			{
12499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				errMsg = "Programmer's assertion: expr1 not an iterator: "+
12509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				          ((Variable)expr1).getQName();
12519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			}
12529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			else
12539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			{
12549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				errMsg = "Programmer's assertion: expr1 not an iterator: "+
12559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				          expr1.getClass().getName();
12569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			}
12579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			throw new RuntimeException(errMsg + ", "+
12589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				          eo.getClass().getName()+" "+
12599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				          expr1.exprGetParent());
12609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
12619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
12629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
12659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Validate some assumptions about the new LocPathIterator and it's
12669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * owner and the state of the list.
12679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
12689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private static void validateNewAddition(Vector paths, ExpressionOwner owner,
12699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                          LocPathIterator path)
12709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		throws RuntimeException
12719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
12729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	assertion(owner.getExpression() == path, "owner.getExpression() != path!!!");
12739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int n = paths.size();
12749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	// There should never be any duplicates in the list!
12759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	for(int i = 0; i < n; i++)
12769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
12779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		ExpressionOwner ew = (ExpressionOwner)paths.elementAt(i);
12789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		assertion(ew != owner, "duplicate owner on the list!!!");
12799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		assertion(ew.getExpression() != path, "duplicate expression on the list!!!");
12809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
12819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
12829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
12849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Simple assertion.
12859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
12869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected static void assertion(boolean b, String msg)
12879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
12889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(!b)
12899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
12909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		throw new RuntimeException(XSLMessages.createMessage(XSLTErrorResources.ER_ASSERT_REDUNDENT_EXPR_ELIMINATOR, new Object[]{msg}));
12919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		// "Programmer's assertion in RundundentExprEliminator: "+msg);
12929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
12939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
12949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
12959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
12969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Since we want to sort multistep expressions by length, use
12979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * a linked list with elements of type MultistepExprHolder.
12989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
12999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  class MultistepExprHolder implements Cloneable
13009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
13019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	ExpressionOwner m_exprOwner; // Will change to null once we have processed this item.
13029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	final int m_stepCount;
13039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	MultistepExprHolder m_next;
13049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/**
13069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * Clone this object.
13079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 */
13089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	public Object clone()
13099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		throws CloneNotSupportedException
13109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
13119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return super.clone();
13129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
13139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/**
13159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * Create a MultistepExprHolder.
13169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 *
13179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * @param exprOwner the owner of the expression we are holding.
13189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 *                  It must hold a LocationPathIterator.
13199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * @param stepCount The number of steps in the location path.
13209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 */
13219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	MultistepExprHolder(ExpressionOwner exprOwner, int stepCount, MultistepExprHolder next)
13229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	{
13239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		m_exprOwner = exprOwner;
13249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		assertion(null != m_exprOwner, "exprOwner can not be null!");
13259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		m_stepCount = stepCount;
13269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  		m_next = next;
13279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	}
13289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/**
13309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * Add a new MultistepExprHolder in sorted order in the list.
13319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 *
13329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * @param exprOwner the owner of the expression we are holding.
13339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 *                  It must hold a LocationPathIterator.
13349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * @param stepCount The number of steps in the location path.
13359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * @return The new head of the linked list.
13369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 */
13379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	MultistepExprHolder addInSortedOrder(ExpressionOwner exprOwner, int stepCount)
13389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
13399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		MultistepExprHolder first = this;
13409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		MultistepExprHolder next = this;
13419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		MultistepExprHolder prev = null;
13429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		while(null != next)
13439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
13449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if(stepCount >= next.m_stepCount)
13459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			{
13469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				MultistepExprHolder newholder = new MultistepExprHolder(exprOwner, stepCount, next);
13479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				if(null == prev)
13489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					first = newholder;
13499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				else
13509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					prev.m_next = newholder;
13519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				return first;
13539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			}
13549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			prev = next;
13559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			next = next.m_next;
13569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
13579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		prev.m_next = new MultistepExprHolder(exprOwner, stepCount, null);
13599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return first;
13609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
13619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/**
13639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * Remove the given element from the list.  'this' should
13649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * be the head of the list.  If the item to be removed is not
13659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * found, an assertion will be made.
13669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 *
13679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * @param itemToRemove The item to remove from the list.
13689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * @return The head of the list, which may have changed if itemToRemove
13699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * is the same as this element.  Null if the item to remove is the
13709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * only item in the list.
13719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 */
13729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	MultistepExprHolder unlink(MultistepExprHolder itemToRemove)
13739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
13749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		MultistepExprHolder first = this;
13759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		MultistepExprHolder next = this;
13769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		MultistepExprHolder prev = null;
13779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		while(null != next)
13789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
13799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			if(next == itemToRemove)
13809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			{
13819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				if(null == prev)
13829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					first = next.m_next;
13839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				else
13849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson					prev.m_next = next.m_next;
13859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				next.m_next = null;
13879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson				return first;
13899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			}
13909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			prev = next;
13919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			next = next.m_next;
13929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
13939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		assertion(false, "unlink failed!!!");
13959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return null;
13969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
13979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
13989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	/**
13999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 * Get the number of linked list items.
14009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	 */
14019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	int getLength()
14029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
14039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		int count = 0;
14049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		MultistepExprHolder next = this;
14059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		while(null != next)
14069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		{
14079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			count++;
14089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson			next = next.m_next;
14099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		}
14109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson		return count;
14119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
14129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
14139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
14149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Print diagnostics out for the multistep list.
14159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
14169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    protected void diagnose()
14179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
14189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      System.err.print("Found multistep iterators: " + this.getLength() + "  ");
14199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      MultistepExprHolder next = this;
14209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      while (null != next)
14219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
14229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        System.err.print("" + next.m_stepCount);
14239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        next = next.m_next;
14249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (null != next)
14259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              System.err.print(", ");
14269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
14279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      System.err.println();
14289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
14299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
14309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
14319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
14329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
1433