KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > compiler > TestSeq


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: TestSeq.java,v 1.11 2004/02/16 22:25:10 minchau Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import java.util.Dictionary JavaDoc;
23 import java.util.Vector JavaDoc;
24
25 import org.apache.bcel.generic.GOTO_W;
26 import org.apache.bcel.generic.InstructionHandle;
27 import org.apache.bcel.generic.InstructionList;
28 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
29 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
30
31 /**
32  * A test sequence is a sequence of patterns that
33  *
34  * (1) occured in templates in the same mode
35  * (2) share the same kernel node type (e.g. A/B and C/C/B)
36  * (3) may also contain patterns matching "*" and "node()"
37  * (element sequence only) or matching "@*" (attribute
38  * sequence only).
39  *
40  * A test sequence may have a default template, which will be
41  * instantiated if none of the other patterns match.
42  * @author Jacek Ambroziak
43  * @author Santiago Pericas-Geertsen
44  * @author Erwin Bolwidt <ejb@klomp.org>
45  * @author Morten Jorgensen <morten.jorgensen@sun.com>
46  */

47 final class TestSeq {
48
49     /**
50      * Integer code for the kernel type of this test sequence
51      */

52     private int _kernelType;
53
54     /**
55      * Vector of all patterns in the test sequence. May include
56      * patterns with "*", "@*" or "node()" kernel.
57      */

58     private Vector JavaDoc _patterns = null;
59
60     /**
61      * A reference to the Mode object.
62      */

63     private Mode _mode = null;
64
65     /**
66      * Default template for this test sequence
67      */

68     private Template _default = null;
69
70     /**
71      * Instruction list representing this test sequence.
72      */

73     private InstructionList _instructionList;
74
75     /**
76      * Cached handle to avoid compiling more than once.
77      */

78     private InstructionHandle _start = null;
79
80     /**
81      * Creates a new test sequence given a set of patterns and a mode.
82      */

83     public TestSeq(Vector JavaDoc patterns, Mode mode) {
84     this(patterns, -2, mode);
85     }
86
87     public TestSeq(Vector JavaDoc patterns, int kernelType, Mode mode) {
88     _patterns = patterns;
89     _kernelType = kernelType;
90     _mode = mode;
91     }
92
93     /**
94      * Returns a string representation of this test sequence. Notice
95      * that test sequences are mutable, so the value returned by this
96      * method is different before and after calling reduce().
97      */

98     public String JavaDoc toString() {
99     final int count = _patterns.size();
100     final StringBuffer JavaDoc result = new StringBuffer JavaDoc();
101
102     for (int i = 0; i < count; i++) {
103         final LocationPathPattern pattern =
104         (LocationPathPattern) _patterns.elementAt(i);
105
106         if (i == 0) {
107         result.append("Testseq for kernel " + _kernelType)
108               .append('\n');
109         }
110         result.append(" pattern " + i + ": ")
111               .append(pattern.toString())
112           .append('\n');
113     }
114     return result.toString();
115     }
116
117     /**
118      * Returns the instruction list for this test sequence
119      */

120     public InstructionList getInstructionList() {
121     return _instructionList;
122     }
123
124     /**
125      * Return the highest priority for a pattern in this test
126      * sequence. This is either the priority of the first or
127      * of the default pattern.
128      */

129     public double getPriority() {
130     final Template template = (_patterns.size() == 0) ? _default
131         : ((Pattern) _patterns.elementAt(0)).getTemplate();
132     return template.getPriority();
133     }
134
135     /**
136      * Returns the position of the highest priority pattern in
137      * this test sequence.
138      */

139     public int getPosition() {
140     final Template template = (_patterns.size() == 0) ? _default
141         : ((Pattern) _patterns.elementAt(0)).getTemplate();
142     return template.getPosition();
143     }
144
145     /**
146      * Reduce the patterns in this test sequence. Creates a new
147      * vector of patterns and sets the default pattern if it
148      * finds a patterns that is fully reduced.
149      */

150     public void reduce() {
151     final Vector JavaDoc newPatterns = new Vector JavaDoc();
152
153     final int count = _patterns.size();
154     for (int i = 0; i < count; i++) {
155         final LocationPathPattern pattern =
156         (LocationPathPattern)_patterns.elementAt(i);
157         
158         // Reduce this pattern
159
pattern.reduceKernelPattern();
160             
161         // Is this pattern fully reduced?
162
if (pattern.isWildcard()) {
163         _default = pattern.getTemplate();
164         break; // Ignore following patterns
165
}
166         else {
167         newPatterns.addElement(pattern);
168         }
169     }
170     _patterns = newPatterns;
171     }
172
173     /**
174      * Returns, by reference, the templates that are included in
175      * this test sequence. Note that a single template can occur
176      * in several test sequences if its pattern is a union.
177      */

178     public void findTemplates(Dictionary JavaDoc templates) {
179     if (_default != null) {
180         templates.put(_default, this);
181     }
182     for (int i = 0; i < _patterns.size(); i++) {
183         final LocationPathPattern pattern =
184         (LocationPathPattern)_patterns.elementAt(i);
185         templates.put(pattern.getTemplate(), this);
186     }
187     }
188
189     /**
190      * Get the instruction handle to a template's code. This is
191      * used when a single template occurs in several test
192      * sequences; that is, if its pattern is a union of patterns
193      * (e.g. match="A/B | A/C").
194      */

195     private InstructionHandle getTemplateHandle(Template template) {
196     return (InstructionHandle)_mode.getTemplateInstructionHandle(template);
197     }
198
199     /**
200      * Returns pattern n in this test sequence
201      */

202     private LocationPathPattern getPattern(int n) {
203     return (LocationPathPattern)_patterns.elementAt(n);
204     }
205
206     /**
207      * Compile the code for this test sequence. Compile patterns
208      * from highest to lowest priority. Note that since patterns
209      * can be share by multiple test sequences, instruction lists
210      * must be copied before backpatching.
211      */

212     public InstructionHandle compile(ClassGenerator classGen,
213                      MethodGenerator methodGen,
214                      InstructionHandle continuation)
215     {
216     // Returned cached value if already compiled
217
if (_start != null) {
218         return _start;
219     }
220
221     // If not patterns, then return handle for default template
222
final int count = _patterns.size();
223     if (count == 0) {
224         return (_start = getTemplateHandle(_default));
225     }
226
227     // Init handle to jump when all patterns failed
228
InstructionHandle fail = (_default == null) ? continuation
229         : getTemplateHandle(_default);
230     
231     // Compile all patterns in reverse order
232
for (int n = count - 1; n >= 0; n--) {
233         final LocationPathPattern pattern = getPattern(n);
234         final Template template = pattern.getTemplate();
235         final InstructionList il = new InstructionList();
236
237         // Patterns expect current node on top of stack
238
il.append(methodGen.loadCurrentNode());
239
240         // Apply the test-code compiled for the pattern
241
InstructionList ilist = _mode.getInstructionList(pattern);
242         if (ilist == null) {
243         ilist = pattern.compile(classGen, methodGen);
244         _mode.addInstructionList(pattern, ilist);
245         }
246
247         // Make a copy of the instruction list for backpatching
248
InstructionList copyOfilist = ilist.copy();
249
250         FlowList trueList = pattern.getTrueList();
251         if (trueList != null) {
252         trueList = trueList.copyAndRedirect(ilist, copyOfilist);
253         }
254         FlowList falseList = pattern.getFalseList();
255         if (falseList != null) {
256         falseList = falseList.copyAndRedirect(ilist, copyOfilist);
257         }
258
259         il.append(copyOfilist);
260
261         // On success branch to the template code
262
final InstructionHandle gtmpl = getTemplateHandle(template);
263         final InstructionHandle success = il.append(new GOTO_W(gtmpl));
264
265         if (trueList != null) {
266         trueList.backPatch(success);
267         }
268         if (falseList != null) {
269         falseList.backPatch(fail);
270         }
271
272         // Next pattern's 'fail' target is this pattern's first instruction
273
fail = il.getStart();
274
275         // Append existing instruction list to the end of this one
276
if (_instructionList != null) {
277         il.append(_instructionList);
278         }
279
280         // Set current instruction list to be this one
281
_instructionList = il;
282     }
283     return (_start = fail);
284     }
285 }
286
Popular Tags