santiagopg    2002/07/29 14:30:52

  Modified:    java/src/org/apache/xalan/xsltc/compiler Expression.java
                        FlowList.java Mode.java StepPattern.java
                        TestSeq.java
  Log:
  Fix for Bugzilla 11166.
  
  Revision  Changes    Path
  1.14      +9 -1      
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Expression.java
  
  Index: Expression.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Expression.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- Expression.java   26 Jun 2002 21:25:35 -0000      1.13
  +++ Expression.java   29 Jul 2002 21:30:51 -0000      1.14
  @@ -214,6 +214,14 @@
        _falseList.add(il.append(new IFEQ(null)));
       }
   
  +    public FlowList getFalseList() {
  +     return _falseList;
  +    }
  +
  +    public FlowList getTrueList() {
  +     return _trueList;
  +    }
  +
       public void backPatchFalseList(InstructionHandle ih) {
        _falseList.backPatch(ih);
       }
  
  
  
  1.3       +31 -1     
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/FlowList.java
  
  Index: FlowList.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/FlowList.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FlowList.java     1 Feb 2002 20:07:08 -0000       1.2
  +++ FlowList.java     29 Jul 2002 21:30:51 -0000      1.3
  @@ -64,6 +64,7 @@
   package org.apache.xalan.xsltc.compiler;
   
   import java.util.Vector;
  +import java.util.Iterator;
   import org.apache.bcel.generic.*;
   
   public final class FlowList {
  @@ -118,5 +119,34 @@
            }
            _elements.clear();          // avoid backpatching more than once
        }
  +    }
  +
  +    /**
  +     * Redirect the handles from oldList to newList. "This" flow list
  +     * is assumed to be relative to oldList.
  +     */
  +    public FlowList copyAndRedirect(InstructionList oldList, 
  +     InstructionList newList) 
  +    {
  +     final FlowList result = new FlowList();
  +     if (_elements == null) {
  +         return result;
  +     }
  +
  +     final int n = _elements.size();
  +     final Iterator oldIter = oldList.iterator();
  +     final Iterator newIter = newList.iterator();
  +     
  +     while (oldIter.hasNext()) {
  +         final InstructionHandle oldIh = (InstructionHandle) oldIter.next();
  +         final InstructionHandle newIh = (InstructionHandle) newIter.next();
  +
  +         for (int i = 0; i < n; i++) {
  +             if (_elements.elementAt(i) == oldIh) {
  +                 result.add(newIh);
  +             }
  +         }
  +     }
  +     return result;
       }
   }
  
  
  
  1.23      +162 -61   
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Mode.java
  
  Index: Mode.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Mode.java,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- Mode.java 15 Jul 2002 19:48:19 -0000      1.22
  +++ Mode.java 29 Jul 2002 21:30:51 -0000      1.23
  @@ -77,8 +77,9 @@
   import org.apache.xalan.xsltc.DOM;
   
   /**
  - * Mode gathers all the templates belonging to a given mode; it is 
responsible
  - * for generating an appropriate applyTemplates + (mode name) function
  + * Mode gathers all the templates belonging to a given mode; 
  + * it is responsible for generating an appropriate 
  + * applyTemplates + (mode name) method in the translet.
    */
   final class Mode implements Constants {
   
  @@ -120,32 +121,67 @@
       /**
        * Test sequence for patterns with id() or key()-type kernel.
        */
  -    private TestSeq  _idxTestSeq = null;
  +    private TestSeq _idxTestSeq = null;
   
       /**
        * Group for patterns with any other kernel type.
        */
  -    private Vector[]  _patternGroups;
  +    private Vector[] _patternGroups;
   
       /**
        * Test sequence for patterns with any other kernel type.
        */
       private TestSeq[] _testSeq;
   
  +    /**
  +     * A mapping between patterns and instruction lists used by 
  +     * test sequences to avoid compiling the same pattern multiple 
  +     * times. Note that patterns whose kernels are "*", "node()" 
  +     * and "@*" can between shared by test sequences.
  +     */
  +    private Hashtable _preCompiled = new Hashtable();
  +
  +    /**
  +     * A mapping between templates and test sequences.
  +     */
       private Hashtable _neededTemplates = new Hashtable();
  +
  +    /**
  +     * A mapping between named templates and Mode objects.
  +     */
       private Hashtable _namedTemplates = new Hashtable();
  +
  +    /**
  +     * A mapping between templates and instruction handles.
  +     */
       private Hashtable _templateIHs = new Hashtable();
  +
  +    /**
  +     * A mapping between templates and instruction lists.
  +     */
       private Hashtable _templateILs = new Hashtable();
  +
  +    /**
  +     * A reference to the pattern matching the root node.
  +     */
       private LocationPathPattern _rootPattern = null;
   
  +    /**
  +     * Stores ranges of template precendences for the compilation 
  +     * of apply-imports (a Hashtable for historical reasons).
  +     */
       private Hashtable _importLevels = null;
   
  +    /**
  +     * A mapping between key names and keys.
  +     */
       private Hashtable _keys = null;
   
  -    // Variable index for the current node - used in code generation
  +    /**
  +     * Variable index for the current node used in code generation.
  +     */
       private int _currentIndex;
   
  -
       /**
        * Creates a new Mode.
        *
  @@ -155,19 +191,18 @@
        *               (normally a sequence number - still in a String).
        */
       public Mode(QName name, Stylesheet stylesheet, String suffix) {
  -     // Save global info
        _name = name;
        _stylesheet = stylesheet;
        _methodName = APPLY_TEMPLATES + suffix;
  -     // Initialise some data structures
        _templates = new Vector();
        _patternGroups = new Vector[32];
       }
   
       /**
  -     * Returns the name of the method (_not_ function) that will be compiled
  -     * for this mode. Normally takes the form 'applyTemplates()' or
  -     * 'applyTemplates2()'.
  +     * Returns the name of the method (_not_ function) that will be 
  +     * compiled for this mode. Normally takes the form 'applyTemplates()' 
  +     * or * 'applyTemplates2()'.
  +     *
        * @return Method name for this mode
        */
       public String functionName() {
  @@ -175,9 +210,28 @@
       }
   
       public String functionName(int min, int max) {
  -     if (_importLevels == null) _importLevels = new Hashtable();
  +     if (_importLevels == null) {
  +         _importLevels = new Hashtable();
  +     }
        _importLevels.put(new Integer(max), new Integer(min));
  -     return _methodName+'_'+max;
  +     return _methodName + '_' + max;
  +    }
  +
  +    /**
  +     * Add a pre-compiled pattern to this mode. 
  +     */
  +    public void addInstructionList(Pattern pattern, 
  +     InstructionList ilist) 
  +    {
  +     _preCompiled.put(pattern, ilist);
  +    }
  +
  +    /**
  +     * Get the instruction list for a pre-compiled pattern. Used by 
  +     * test sequences to avoid compiling patterns more than once.
  +     */
  +    public InstructionList getInstructionList(Pattern pattern) {
  +     return (InstructionList) _preCompiled.get(pattern);
       }
   
       /**
  @@ -187,10 +241,10 @@
        return _stylesheet.getClassName();
       }
   
  -    /**
  -     * Add a template to this mode
  -     * @param template The template to add
  -     */
  +    public Stylesheet getStylesheet() {
  +     return _stylesheet;
  +    }
  +
       public void addTemplate(Template template) {
        _templates.addElement(template);
       }
  @@ -304,10 +358,32 @@
       }
   
       /**
  +     * Group patterns by NodeTests of their last Step
  +     * Keep them sorted by priority within group
  +     */
  +    private void addPatternToGroup(final LocationPathPattern lpp) {
  +     // id() and key()-type patterns do not have a kernel type
  +     if (lpp instanceof IdKeyPattern) {
  +         addPattern(-1, lpp);
  +     }
  +     // Otherwise get the kernel pattern from the LPP
  +     else {
  +         // kernel pattern is the last (maybe only) Step
  +         final StepPattern kernel = lpp.getKernelPattern();
  +         if (kernel != null) {
  +             addPattern(kernel.getNodeType(), lpp);
  +         }
  +         else if (_rootPattern == null ||
  +                  lpp.noSmallerThan(_rootPattern)) {
  +             _rootPattern = lpp;
  +         }
  +     }
  +    }
  +
  +    /**
        * Adds a pattern to a pattern group
        */
       private void addPattern(int kernelType, LocationPathPattern pattern) {
  -
        // Make sure the array of pattern groups is long enough
        final int oldLength = _patternGroups.length;
        if (kernelType >= oldLength) {
  @@ -326,10 +402,13 @@
        if (patterns == null) {
            patterns = new Vector(2);
            patterns.addElement(pattern);
  -         if (kernelType == -1)
  +
  +         if (kernelType == -1) {
                _nodeGroup = patterns;
  -         else
  +         }
  +         else {
                _patternGroups[kernelType] = patterns;
  +         }
        }
        // Otherwise make sure patterns are ordered by precedence/priorities
        else {
  @@ -350,40 +429,58 @@
       }
       
       /**
  -     * Group patterns by NodeTests of their last Step
  -     * Keep them sorted by priority within group
  +     * Build test sequences. The first step is to complete the test 
sequences 
  +     * by including patterns of "*" and "node()" kernel to all element test 
  +     * sequences, and of "@*" to all attribute test sequences.
        */
  -    private void addPatternToGroup(final LocationPathPattern lpp) {
  -     // id() and key()-type patterns do not have a kernel type
  -     if (lpp instanceof IdKeyPattern) {
  -         addPattern(-1, lpp);
  -     }
  -     // Otherwise get the kernel pattern from the LPP
  -     else {
  -         // kernel pattern is the last (maybe only) Step
  -         final StepPattern kernel = lpp.getKernelPattern();
  -         if (kernel != null) {
  -             addPattern(kernel.getNodeType(), lpp);
  -         }
  -         else if (_rootPattern == null ||
  -                  lpp.noSmallerThan(_rootPattern)) {
  -             _rootPattern = lpp;
  +    private void prepareTestSequences() {
  +     final Vector names = _stylesheet.getXSLTC().getNamesIndex();
  +
  +     final Vector starGroup = _patternGroups[DOM.ELEMENT];
  +     final Vector atStarGroup = _patternGroups[DOM.ATTRIBUTE];
  +
  +     // Complete test sequences with "*", "@*" and "node()"
  +     if (starGroup != null || atStarGroup != null || _nodeGroup != null) {
  +         final int n = DOM.NTYPES + names.size();
  +
  +         for (int m, i = DOM.NTYPES; i < n; i++) {
  +             if (_patternGroups[i] == null) continue;
  +
  +             final String name = (String) names.elementAt(i - DOM.NTYPES);
  +
  +             if (isAttributeName(name)) {
  +                 // If an attribute then copy "@*" to its test sequence
  +                 m = (atStarGroup != null) ? atStarGroup.size() : 0;
  +                 for (int j = 0; j < m; j++) {
  +                     addPattern(i, 
  +                         (LocationPathPattern) atStarGroup.elementAt(j));
  +                 }
  +             }
  +             else {
  +                 // If an element then copy "*" to its test sequence
  +                 m = (starGroup != null) ? starGroup.size() : 0;
  +                 for (int j = 0; j < m; j++) {
  +                     addPattern(i, 
  +                         (LocationPathPattern) starGroup.elementAt(j));
  +                 }
  +
  +                 // And also copy "node()" to its test sequence
  +                 m = (_nodeGroup != null) ? _nodeGroup.size() : 0;
  +                 for (int j = 0; j < m; j++) {
  +                     addPattern(i, 
  +                         (LocationPathPattern) _nodeGroup.elementAt(j));
  +                 }
  +             }
            }
        }
  -    }
   
  -    /**
  -     * Build test sequences
  -     */
  -    private void prepareTestSequences() {
  -     final Vector names = _stylesheet.getXSLTC().getNamesIndex();
        _testSeq = new TestSeq[DOM.NTYPES + names.size()];
        
        final int n = _patternGroups.length;
        for (int i = 0; i < n; i++) {
            final Vector patterns = _patternGroups[i];
            if (patterns != null) {
  -             final TestSeq testSeq = new TestSeq(patterns, this);
  +             final TestSeq testSeq = new TestSeq(patterns, i, this);
                testSeq.reduce();
                _testSeq[i] = testSeq;
                testSeq.findTemplates(_neededTemplates);
  @@ -391,7 +488,7 @@
        }
   
        if ((_nodeGroup != null) && (_nodeGroup.size() > 0)) {
  -         _nodeTestSeq = new TestSeq(_nodeGroup, this);
  +         _nodeTestSeq = new TestSeq(_nodeGroup, -1, this);
            _nodeTestSeq.reduce();
            _nodeTestSeq.findTemplates(_neededTemplates);
        }
  @@ -619,20 +716,7 @@
        }
       }
   
  -    /**
  -     * Auxiliary method to determine if a qname describes an 
attribute/element
  -     */
  -    private static boolean isAttributeName(String qname) {
  -     final int col = qname.lastIndexOf(':') + 1;
  -     return (qname.charAt(col) == '@');
  -    }
  -
  -    private static boolean isNamespaceName(String qname) {
  -     final int col = qname.lastIndexOf(':');
  -     return (col > -1 && qname.charAt(qname.length()-1) == '*');
  -    }
  -
  -    /**
  +   /**
        * Compiles the applyTemplates() method and adds it to the translet.
        * This is the main dispatch method.
        */
  @@ -742,7 +826,6 @@
        // If there is a match on node() we need to replace ihElem
        // and ihText if the priority of node() is higher
        if (_nodeTestSeq != null) {
  -
            // Compare priorities of node() and "*"
            double nodePrio = _nodeTestSeq.getPriority();
            int    nodePos  = _nodeTestSeq.getPosition();
  @@ -815,6 +898,7 @@
            }
        }
   
  +
        // Handle pattern with match on root node - default: traverse children
        targets[DOM.ROOT] = _rootPattern != null
            ? getTemplateInstructionHandle(_rootPattern.getTemplate())
  @@ -1320,5 +1404,22 @@
   
       public InstructionHandle getTemplateInstructionHandle(Template template) 
{
        return (InstructionHandle)_templateIHs.get(template);
  +    }
  +
  +    /**
  +     * Auxiliary method to determine if a qname is an attribute.
  +     */
  +    private static boolean isAttributeName(String qname) {
  +     final int col = qname.lastIndexOf(':') + 1;
  +     return (qname.charAt(col) == '@');
  +    }
  +
  +    /**
  +     * Auxiliary method to determine if a qname is a namespace 
  +     * qualified "*".
  +     */
  +    private static boolean isNamespaceName(String qname) {
  +     final int col = qname.lastIndexOf(':');
  +     return (col > -1 && qname.charAt(qname.length()-1) == '*');
       }
   }
  
  
  
  1.17      +4 -2      
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/StepPattern.java
  
  Index: StepPattern.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/StepPattern.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- StepPattern.java  6 May 2002 13:53:22 -0000       1.16
  +++ StepPattern.java  29 Jul 2002 21:30:51 -0000      1.17
  @@ -150,7 +150,9 @@
        final StringBuffer buffer = new StringBuffer("stepPattern(\"");
        buffer.append(Axis.names[_axis])
            .append("\", ")
  -         .append(_isEpsilon ? "epsilon" : Integer.toString(_nodeType));
  +         .append(_isEpsilon ? 
  +                     ("epsilon{" + Integer.toString(_nodeType) + "}") :
  +                      Integer.toString(_nodeType));
        if (_predicates != null)
            buffer.append(", ").append(_predicates.toString());
        return buffer.append(')').toString();
  
  
  
  1.8       +154 -101  
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/TestSeq.java
  
  Index: TestSeq.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/TestSeq.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- TestSeq.java      3 May 2002 14:20:25 -0000       1.7
  +++ TestSeq.java      29 Jul 2002 21:30:51 -0000      1.8
  @@ -69,6 +69,7 @@
   import java.util.Hashtable;
   import java.util.Dictionary;
   import java.util.Enumeration;
  +import java.util.Iterator;
   
   import org.apache.bcel.generic.*;
   import org.apache.xalan.xsltc.compiler.util.*;
  @@ -77,110 +78,149 @@
    * A test sequence is a sequence of patterns that
    *
    *  (1) occured in templates in the same mode
  - *  (2) share the same kernel node type (such as A/B and C/C/B).
  + *  (2) share the same kernel node type (e.g. A/B and C/C/B)
  + *  (3) may also contain patterns matching "*" and "node()"
  + *      (element sequence only) or matching "@*" (attribute
  + *      sequence only).
    *
  - * A test sequence may have a default template, which will be run if
  - * none of the patterns do not match. This template is always a template
  - * that matches solely on the shared kernel node type.
  + * A test sequence may have a default template, which will be 
  + * instantiated if none of the other patterns match. 
    */
   final class TestSeq {
   
  -    private Vector   _patterns = null; // all patterns
  -    private Mode     _mode     = null; // the shared mode
  -    private Template _default  = null; // the default template
  +    /**
  +     * Integer code for the kernel type of this test sequence
  +     */
  +    private int _kernelType;
  +
  +    /**
  +     * Vector of all patterns in the test sequence. May include
  +     * patterns with "*", "@*" or "node()" kernel.
  +     */
  +    private Vector _patterns = null;
  +
  +    /**
  +     * A reference to the Mode object.
  +     */
  +    private Mode _mode = null;
  +
  +    /**
  +     * Default template for this test sequence
  +     */
  +    private Template _default = null;
   
  +    /**
  +     * Instruction list representing this test sequence.
  +     */
       private InstructionList _instructionList;
   
       /**
  -     * Creates a new test sequence, given a set of patterns and a mode.
  +     * Cached handle to avoid compiling more than once.
  +     */
  +    private InstructionHandle _start = null;
  +
  +    /**
  +     * Creates a new test sequence given a set of patterns and a mode.
        */
       public TestSeq(Vector patterns, Mode mode) {
  +     this(patterns, -2, mode);
  +    }
  +
  +    public TestSeq(Vector patterns, int kernelType, Mode mode) {
        _patterns = patterns;
  +     _kernelType = kernelType;
        _mode = mode;
       }
   
       /**
  -     * The priority is only calculated if the test sequence has a default
  -     * template. This is bad, bad, bad. We should get the priority from the
  -     * other templates that make up the test sequence.
  +     * Returns a string representation of this test sequence. Notice
  +     * that test sequences are mutable, so the value returned by this
  +     * method is different before and after calling reduce().
        */
  -    public double getPriority() {
  -     double prio = (0 - Double.MAX_VALUE);
  +    public String toString() {
        final int count = _patterns.size();
  +     final StringBuffer result = new StringBuffer();
   
        for (int i = 0; i < count; i++) {
  -         final Pattern pattern = (Pattern)_patterns.elementAt(i);
  -         final Template template = pattern.getTemplate();
  -         final double tp = template.getPriority();
  -         if (tp > prio) prio = tp;
  -     }
  -     if (_default != null) {
  -         final double tp = _default.getPriority();
  -         if (tp > prio) prio = tp;
  +         final LocationPathPattern pattern =
  +             (LocationPathPattern) _patterns.elementAt(i);
  +
  +         if (i == 0) {
  +             result.append("Testseq for kernel " + _kernelType)
  +                   .append('\n');
  +         }
  +         result.append("   pattern " + i + ": ")
  +               .append(pattern.toString())
  +               .append('\n');
        }
  -     return prio;
  +     return result.toString();
       }
   
       /**
  -     * This method should return the last position of any template included
  -     * in this test sequence.
  +     * Returns the instruction list for this test sequence
        */
  -    public int getPosition() {
  -     int pos = Integer.MIN_VALUE;
  -     final int count = _patterns.size();
  +    public InstructionList getInstructionList() {
  +     return _instructionList;
  +    }
   
  -     for (int i = 0; i < count; i++) {
  -         final Pattern pattern = (Pattern)_patterns.elementAt(i);
  -         final Template template = pattern.getTemplate();
  -         final int tp = template.getPosition();
  -         if (tp > pos) pos = tp;
  -     }
  -     if (_default != null) {
  -         final int tp = _default.getPosition();
  -         if (tp > pos) pos = tp;
  -     }
  -     return pos;
  +    /**
  +     * Return the highest priority for a pattern in this test
  +     * sequence. This is either the priority of the first or
  +     * of the default pattern.
  +     */
  +    public double getPriority() {
  +     final Template template = (_patterns.size() == 0) ? _default 
  +         : ((Pattern) _patterns.elementAt(0)).getTemplate();
  +     return template.getPriority();
       }
  -     
  +
  +    /**
  +     * Returns the position of the highest priority pattern in 
  +     * this test sequence.
  +     */
  +    public int getPosition() {
  +     final Template template = (_patterns.size() == 0) ? _default 
  +         : ((Pattern) _patterns.elementAt(0)).getTemplate();
  +     return template.getPosition();
  +    }
  +
       /**
  -     * Reduce the patterns in this test sequence to exclude the shared
  -     * kernel node type. After the switch() in the translet's 
applyTemplates()
  -     * we already know that we have a hit for the kernel node type, we only
  -     * have the check the rest of the pattern.
  +     * Reduce the patterns in this test sequence. Creates a new
  +     * vector of patterns and sets the default pattern if it
  +     * finds a patterns that is fully reduced.
        */
       public void reduce() {
        final Vector newPatterns = new Vector();
  -     final int count = _patterns.size();
   
  -     // Traverse the existing set of patterns (they are in prioritised order)
  +     final int count = _patterns.size();
        for (int i = 0; i < count; i++) {
            final LocationPathPattern pattern =
                (LocationPathPattern)_patterns.elementAt(i);
  -         // Reduce this pattern (get rid of kernel node type)
  +             
  +         // Reduce this pattern
            pattern.reduceKernelPattern();
                        
  -         // Add this pattern to the new vector of patterns.
  -         if (!pattern.isWildcard()) {
  -             newPatterns.addElement(pattern);
  +         // Is this pattern fully reduced?
  +         if (pattern.isWildcard()) {
  +             _default = pattern.getTemplate();
  +             break;          // Ignore following patterns 
            }
  -         // Set template as default if its pattern matches purely on kernel
            else {
  -             _default = pattern.getTemplate();
  -             // Following patterns can be ignored since default has priority
  -             break;
  +             newPatterns.addElement(pattern);
            }
        }
        _patterns = newPatterns;
       }
   
       /**
  -     * Returns, by reference, the templates that are included in this test
  -     * sequence. Remember that a single template can occur in several test
  -     * sequences if its pattern is a union (ex. match="A/B | A/C").
  +     * Returns, by reference, the templates that are included in 
  +     * this test sequence. Note that a single template can occur 
  +     * in several test sequences if its pattern is a union.
        */
       public void findTemplates(Dictionary templates) {
  -     if (_default != null)
  +     if (_default != null) {
            templates.put(_default, this);
  +     }
        for (int i = 0; i < _patterns.size(); i++) {
            final LocationPathPattern pattern =
                (LocationPathPattern)_patterns.elementAt(i);
  @@ -189,9 +229,10 @@
       }
   
       /**
  -     * Get the instruction handle to a template's code. This is used when
  -     * a single template occurs in several test sequences; that is, if its
  -     * pattern is a union of patterns (ex. match="A/B | A/C").
  +     * Get the instruction handle to a template's code. This is 
  +     * used when a single template occurs in several test 
  +     * sequences; that is, if its pattern is a union of patterns 
  +     * (e.g. match="A/B | A/C").
        */
       private InstructionHandle getTemplateHandle(Template template) {
        return (InstructionHandle)_mode.getTemplateInstructionHandle(template);
  @@ -204,71 +245,83 @@
        return (LocationPathPattern)_patterns.elementAt(n);
       }
   
  -
  -    private InstructionHandle _start = null;
  -
       /**
  -     * Copile the code for this test sequence. The code will first test for
  -     * the pattern with the highest priority, then go on to the next ones,
  -     * until it hits or finds the default template.
  +     * Compile the code for this test sequence. Compile patterns 
  +     * from highest to lowest priority. Note that since patterns 
  +     * can be share by multiple test sequences, instruction lists 
  +     * must be copied before backpatching.
        */
       public InstructionHandle compile(ClassGenerator classGen,
                                     MethodGenerator methodGen,
  -                                  InstructionHandle continuation) {
  +                                  InstructionHandle continuation) 
  +    {
  +     // Returned cached value if already compiled
  +     if (_start != null) {
  +         return _start;
  +     }
   
  +     // If not patterns, then return handle for default template
        final int count = _patterns.size();
  -     
  -     if (_start != null) return(_start);
  -
  -     // EZ DC if there is only one (default) pattern
  -     if (count == 0) getTemplateHandle(_default);
  +     if (count == 0) {
  +         return (_start = getTemplateHandle(_default));
  +     }
   
  -     // The 'fail' instruction handle represents a branch to go to when
  -     // test fails. It is updated in each iteration, so that the tests
  -     // are linked together in the  if-elseif-elseif-else fashion.
  -     InstructionHandle fail;
  +     // Init handle to jump when all patterns failed
  +     InstructionHandle fail = (_default == null) ? continuation
  +         : getTemplateHandle(_default);
        
  -     // Initialize 'fail' to either the code for the default template
  -     if (_default != null)
  -         fail = getTemplateHandle(_default);
  -     // ..or if that does not exist, to a location set by the caller.
  -     else
  -         fail = continuation;
  -
  -     for (int n = (count - 1); n >= 0; n--) {
  +     // Compile all patterns in reverse order
  +     for (int n = count - 1; n >= 0; n--) {
            final LocationPathPattern pattern = getPattern(n);
            final Template template = pattern.getTemplate();
            final InstructionList il = new InstructionList();
   
            // Patterns expect current node on top of stack
            il.append(methodGen.loadCurrentNode());
  +
            // Apply the test-code compiled for the pattern
  -         il.append(pattern.compile(classGen, methodGen));
  +         InstructionList ilist = _mode.getInstructionList(pattern);
  +         if (ilist == null) {
  +             ilist = pattern.compile(classGen, methodGen);
  +             _mode.addInstructionList(pattern, ilist);
  +         }
  +
  +         // Make a copy of the instruction list for backpatching
  +         InstructionList copyOfilist = ilist.copy();
  +
  +         FlowList trueList = pattern.getTrueList();
  +         if (trueList != null) {
  +             trueList = trueList.copyAndRedirect(ilist, copyOfilist);
  +         }
  +         FlowList falseList = pattern.getFalseList();
  +         if (falseList != null) {
  +             falseList = falseList.copyAndRedirect(ilist, copyOfilist);
  +         }
  +
  +         il.append(copyOfilist);
   
            // On success branch to the template code
            final InstructionHandle gtmpl = getTemplateHandle(template);
            final InstructionHandle success = il.append(new GOTO_W(gtmpl));
  -         pattern.backPatchTrueList(success);
  -         pattern.backPatchFalseList(fail);
   
  -         // We're working backwards here. The next pattern's 'fail' target
  -         // is this pattern's first instruction
  +         if (trueList != null) {
  +             trueList.backPatch(success);
  +         }
  +         if (falseList != null) {
  +             falseList.backPatch(fail);
  +         } 
  +
  +         // Next pattern's 'fail' target is this pattern's first instruction
            fail = il.getStart();
   
            // Append existing instruction list to the end of this one
  -         if (_instructionList != null) il.append(_instructionList);
  +         if (_instructionList != null) {
  +             il.append(_instructionList);
  +         }
   
  -         // Set current instruction list to be this one.
  +         // Set current instruction list to be this one
            _instructionList = il;
        }
  -     return(_start = fail);
  -    }
  -
  -    /**
  -     * Returns the instruction list for this test sequence
  -     */
  -    public InstructionList getInstructionList() {
  -     return _instructionList;
  +     return (_start = fail);
       }
  -
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to