KickJava   Java API By Example, From Geeks To Geeks.

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


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: Step.java,v 1.46 2004/02/24 04:21:22 zongaro Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import java.util.Vector JavaDoc;
23
24 import org.apache.bcel.generic.CHECKCAST;
25 import org.apache.bcel.generic.ConstantPoolGen;
26 import org.apache.bcel.generic.ICONST;
27 import org.apache.bcel.generic.INVOKEINTERFACE;
28 import org.apache.bcel.generic.INVOKESPECIAL;
29 import org.apache.bcel.generic.InstructionList;
30 import org.apache.bcel.generic.NEW;
31 import org.apache.bcel.generic.PUSH;
32 import org.apache.xalan.xsltc.DOM;
33 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
34 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
35 import org.apache.xalan.xsltc.compiler.util.Type;
36 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
37 import org.apache.xalan.xsltc.dom.Axis;
38 import org.apache.xml.dtm.DTM;
39
40 /**
41  * @author Jacek Ambroziak
42  * @author Santiago Pericas-Geertsen
43  * @author Morten Jorgensen
44  */

45 final class Step extends RelativeLocationPath {
46
47     /**
48      * This step's axis as defined in class Axis.
49      */

50     private int _axis;
51
52     /**
53      * A vector of predicates (filters) defined on this step - may be null
54      */

55     private Vector JavaDoc _predicates;
56
57     /**
58      * Some simple predicates can be handled by this class (and not by the
59      * Predicate class) and will be removed from the above vector as they are
60      * handled. We use this boolean to remember if we did have any predicates.
61      */

62     private boolean _hadPredicates = false;
63
64     /**
65      * Type of the node test.
66      */

67     private int _nodeType;
68
69     public Step(int axis, int nodeType, Vector JavaDoc predicates) {
70     _axis = axis;
71     _nodeType = nodeType;
72     _predicates = predicates;
73     }
74
75     /**
76      * Set the parser for this element and all child predicates
77      */

78     public void setParser(Parser parser) {
79     super.setParser(parser);
80     if (_predicates != null) {
81         final int n = _predicates.size();
82         for (int i = 0; i < n; i++) {
83         final Predicate exp = (Predicate)_predicates.elementAt(i);
84         exp.setParser(parser);
85         exp.setParent(this);
86         }
87     }
88     }
89     
90     /**
91      * Define the axis (defined in Axis class) for this step
92      */

93     public int getAxis() {
94     return _axis;
95     }
96     
97     /**
98      * Get the axis (defined in Axis class) for this step
99      */

100     public void setAxis(int axis) {
101     _axis = axis;
102     }
103
104     /**
105      * Returns the node-type for this step
106      */

107     public int getNodeType() {
108     return _nodeType;
109     }
110
111     /**
112      * Returns the vector containing all predicates for this step.
113      */

114     public Vector JavaDoc getPredicates() {
115     return _predicates;
116     }
117
118     /**
119      * Returns the vector containing all predicates for this step.
120      */

121     public void addPredicates(Vector JavaDoc predicates) {
122     if (_predicates == null) {
123         _predicates = predicates;
124     }
125     else {
126         _predicates.addAll(predicates);
127     }
128     }
129
130     /**
131      * Returns 'true' if this step has a parent pattern.
132      * This method will return 'false' if this step occurs on its own under
133      * an element like <xsl:for-each> or <xsl:apply-templates>.
134      */

135     private boolean hasParentPattern() {
136     final SyntaxTreeNode parent = getParent();
137     return (parent instanceof ParentPattern ||
138         parent instanceof ParentLocationPath ||
139         parent instanceof UnionPathExpr ||
140         parent instanceof FilterParentPath);
141     }
142     
143     /**
144      * Returns 'true' if this step has any predicates
145      */

146     private boolean hasPredicates() {
147     return _predicates != null && _predicates.size() > 0;
148     }
149
150     /**
151      * Returns 'true' if this step is used within a predicate
152      */

153     private boolean isPredicate() {
154     SyntaxTreeNode parent = this;
155     while (parent != null) {
156         parent = parent.getParent();
157         if (parent instanceof Predicate) return true;
158     }
159     return false;
160     }
161
162     /**
163      * True if this step is the abbreviated step '.'
164      */

165     public boolean isAbbreviatedDot() {
166     return _nodeType == NodeTest.ANODE && _axis == Axis.SELF;
167     }
168
169
170     /**
171      * True if this step is the abbreviated step '..'
172      */

173     public boolean isAbbreviatedDDot() {
174     return _nodeType == NodeTest.ANODE && _axis == Axis.PARENT;
175     }
176
177     /**
178      * Type check this step. The abbreviated steps '.' and '@attr' are
179      * assigned type node if they have no predicates. All other steps
180      * have type node-set.
181      */

182     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
183
184     // Save this value for later - important for testing for special
185
// combinations of steps and patterns than can be optimised
186
_hadPredicates = hasPredicates();
187
188     // Special case for '.'
189
// in the case where '.' has a context such as book/.
190
// or .[false()] we can not optimize the nodeset to a single node.
191
if (isAbbreviatedDot()) {
192         _type = (hasParentPattern() || hasPredicates() ) ?
193         Type.NodeSet : Type.Node;
194     }
195     else {
196         _type = Type.NodeSet;
197     }
198
199     // Type check all predicates (expressions applied to the step)
200
if (_predicates != null) {
201         final int n = _predicates.size();
202         for (int i = 0; i < n; i++) {
203         final Expression pred = (Expression)_predicates.elementAt(i);
204         pred.typeCheck(stable);
205         }
206     }
207
208     // Return either Type.Node or Type.NodeSet
209
return _type;
210     }
211
212     /**
213      * Translate a step by pushing the appropriate iterator onto the stack.
214      * The abbreviated steps '.' and '@attr' do not create new iterators
215      * if they are not part of a LocationPath and have no filters.
216      * In these cases a node index instead of an iterator is pushed
217      * onto the stack.
218      */

219     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
220     final ConstantPoolGen cpg = classGen.getConstantPool();
221     final InstructionList il = methodGen.getInstructionList();
222
223     if (hasPredicates()) {
224         translatePredicates(classGen, methodGen);
225     } else {
226             int star = 0;
227             String JavaDoc name = null;
228             final XSLTC xsltc = getParser().getXSLTC();
229
230             if (_nodeType >= DTM.NTYPES) {
231         final Vector JavaDoc ni = xsltc.getNamesIndex();
232         
233                 name = (String JavaDoc)ni.elementAt(_nodeType-DTM.NTYPES);
234                 star = name.lastIndexOf('*');
235             }
236
237         // If it is an attribute, but not '@*', '@pre:*' or '@node()',
238
// and has no parent
239
if (_axis == Axis.ATTRIBUTE && _nodeType != NodeTest.ATTRIBUTE
240         && _nodeType != NodeTest.ANODE && !hasParentPattern()
241                 && star == 0)
242         {
243         int iter = cpg.addInterfaceMethodref(DOM_INTF,
244                              "getTypedAxisIterator",
245                              "(II)"+NODE_ITERATOR_SIG);
246         il.append(methodGen.loadDOM());
247         il.append(new PUSH(cpg, Axis.ATTRIBUTE));
248         il.append(new PUSH(cpg, _nodeType));
249         il.append(new INVOKEINTERFACE(iter, 3));
250         return;
251         }
252
253         // Special case for '.'
254
if (isAbbreviatedDot()) {
255         if (_type == Type.Node) {
256             // Put context node on stack if using Type.Node
257
il.append(methodGen.loadContextNode());
258         }
259         else {
260             // Wrap the context node in a singleton iterator if not.
261
int init = cpg.addMethodref(SINGLETON_ITERATOR,
262                         "<init>", "("+NODE_SIG+")V");
263             il.append(new NEW(cpg.addClass(SINGLETON_ITERATOR)));
264             il.append(DUP);
265             il.append(methodGen.loadContextNode());
266             il.append(new INVOKESPECIAL(init));
267         }
268         return;
269         }
270
271         // Special case for /foo/*/bar
272
SyntaxTreeNode parent = getParent();
273         if ((parent instanceof ParentLocationPath) &&
274         (parent.getParent() instanceof ParentLocationPath)) {
275         if ((_nodeType == NodeTest.ELEMENT) && (!_hadPredicates)) {
276             _nodeType = NodeTest.ANODE;
277         }
278         }
279
280         // "ELEMENT" or "*" or "@*" or ".." or "@attr" with a parent.
281
switch (_nodeType) {
282         case NodeTest.ATTRIBUTE:
283         _axis = Axis.ATTRIBUTE;
284         case NodeTest.ANODE:
285         // DOM.getAxisIterator(int axis);
286
int git = cpg.addInterfaceMethodref(DOM_INTF,
287                             "getAxisIterator",
288                             "(I)"+NODE_ITERATOR_SIG);
289         il.append(methodGen.loadDOM());
290         il.append(new PUSH(cpg, _axis));
291         il.append(new INVOKEINTERFACE(git, 2));
292         break;
293         default:
294         if (star > 1) {
295             final String JavaDoc namespace;
296             if (_axis == Axis.ATTRIBUTE)
297             namespace = name.substring(0,star-2);
298             else
299             namespace = name.substring(0,star-1);
300
301             final int nsType = xsltc.registerNamespace(namespace);
302             final int ns = cpg.addInterfaceMethodref(DOM_INTF,
303                             "getNamespaceAxisIterator",
304                             "(II)"+NODE_ITERATOR_SIG);
305             il.append(methodGen.loadDOM());
306             il.append(new PUSH(cpg, _axis));
307             il.append(new PUSH(cpg, nsType));
308             il.append(new INVOKEINTERFACE(ns, 3));
309             break;
310         }
311         case NodeTest.ELEMENT:
312         // DOM.getTypedAxisIterator(int axis, int type);
313
final int ty = cpg.addInterfaceMethodref(DOM_INTF,
314                         "getTypedAxisIterator",
315                         "(II)"+NODE_ITERATOR_SIG);
316         // Get the typed iterator we're after
317
il.append(methodGen.loadDOM());
318         il.append(new PUSH(cpg, _axis));
319         il.append(new PUSH(cpg, _nodeType));
320         il.append(new INVOKEINTERFACE(ty, 3));
321
322         break;
323         }
324     }
325     }
326
327
328     /**
329      * Translate a sequence of predicates. Each predicate is translated
330      * by constructing an instance of <code>CurrentNodeListIterator</code>
331      * which is initialized from another iterator (recursive call),
332      * a filter and a closure (call to translate on the predicate) and "this".
333      */

334     public void translatePredicates(ClassGenerator classGen,
335                     MethodGenerator methodGen) {
336     final ConstantPoolGen cpg = classGen.getConstantPool();
337     final InstructionList il = methodGen.getInstructionList();
338
339     int idx = 0;
340
341     if (_predicates.size() == 0) {
342         translate(classGen, methodGen);
343     }
344     else {
345         final Predicate predicate = (Predicate)_predicates.lastElement();
346         _predicates.remove(predicate);
347
348         // Special case for predicates that can use the NodeValueIterator
349
// instead of an auxiliary class. Certain path/predicates pairs
350
// are translated into a base path, on top of which we place a
351
// node value iterator that tests for the desired value:
352
// foo[@attr = 'str'] -> foo/@attr + test(value='str')
353
// foo[bar = 'str'] -> foo/bar + test(value='str')
354
// foo/bar[. = 'str'] -> foo/bar + test(value='str')
355
if (predicate.isNodeValueTest()) {
356         Step step = predicate.getStep();
357
358         il.append(methodGen.loadDOM());
359         // If the predicate's Step is simply '.' we translate this Step
360
// and place the node test on top of the resulting iterator
361
if (step.isAbbreviatedDot()) {
362             translate(classGen, methodGen);
363             il.append(new ICONST(DOM.RETURN_CURRENT));
364         }
365         // Otherwise we create a parent location path with this Step and
366
// the predicates Step, and place the node test on top of that
367
else {
368             ParentLocationPath path = new ParentLocationPath(this,step);
369             try {
370             path.typeCheck(getParser().getSymbolTable());
371             }
372             catch (TypeCheckError e) { }
373             path.translate(classGen, methodGen);
374             il.append(new ICONST(DOM.RETURN_PARENT));
375         }
376         predicate.translate(classGen, methodGen);
377         idx = cpg.addInterfaceMethodref(DOM_INTF,
378                         GET_NODE_VALUE_ITERATOR,
379                         GET_NODE_VALUE_ITERATOR_SIG);
380         il.append(new INVOKEINTERFACE(idx, 5));
381         }
382         // Handle '//*[n]' expression
383
else if (predicate.isNthDescendant()) {
384         il.append(methodGen.loadDOM());
385         // il.append(new ICONST(NodeTest.ELEMENT));
386
il.append(new ICONST(predicate.getPosType()));
387         predicate.translate(classGen, methodGen);
388         il.append(new ICONST(0));
389         idx = cpg.addInterfaceMethodref(DOM_INTF,
390                         "getNthDescendant",
391                         "(IIZ)"+NODE_ITERATOR_SIG);
392         il.append(new INVOKEINTERFACE(idx, 4));
393         }
394         // Handle 'elem[n]' expression
395
else if (predicate.isNthPositionFilter()) {
396         idx = cpg.addMethodref(NTH_ITERATOR_CLASS,
397                        "<init>",
398                        "("+NODE_ITERATOR_SIG+"I)V");
399         il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS)));
400         il.append(DUP);
401         translatePredicates(classGen, methodGen); // recursive call
402
predicate.translate(classGen, methodGen);
403         il.append(new INVOKESPECIAL(idx));
404         }
405         else {
406         idx = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR,
407                        "<init>",
408                        "("
409                        + NODE_ITERATOR_SIG
410                        + CURRENT_NODE_LIST_FILTER_SIG
411                        + NODE_SIG
412                        + TRANSLET_SIG
413                        + ")V");
414         // create new CurrentNodeListIterator
415
il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
416         il.append(DUP);
417         translatePredicates(classGen, methodGen); // recursive call
418
predicate.translateFilter(classGen, methodGen);
419         
420         il.append(methodGen.loadCurrentNode());
421         il.append(classGen.loadTranslet());
422         if (classGen.isExternal()) {
423             final String JavaDoc className = classGen.getClassName();
424             il.append(new CHECKCAST(cpg.addClass(className)));
425         }
426         il.append(new INVOKESPECIAL(idx));
427         }
428     }
429     }
430
431     /**
432      * Returns a string representation of this step.
433      */

434     public String JavaDoc toString() {
435     final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("step(\"");
436     buffer.append(Axis.names[_axis]).append("\", ").append(_nodeType);
437     if (_predicates != null) {
438         final int n = _predicates.size();
439         for (int i = 0; i < n; i++) {
440         final Predicate pred = (Predicate)_predicates.elementAt(i);
441         buffer.append(", ").append(pred.toString());
442         }
443     }
444     return buffer.append(')').toString();
445     }
446 }
447
Popular Tags