KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xalan > internal > 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.1.2.2 2006/11/10 22:07:02 spericas Exp $
18  */

19
20 package com.sun.org.apache.xalan.internal.xsltc.compiler;
21
22 import java.util.Vector JavaDoc;
23
24 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
25 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
26 import com.sun.org.apache.bcel.internal.generic.ICONST;
27 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
28 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
29 import com.sun.org.apache.bcel.internal.generic.InstructionList;
30 import com.sun.org.apache.bcel.internal.generic.NEW;
31 import com.sun.org.apache.bcel.internal.generic.PUSH;
32 import com.sun.org.apache.xalan.internal.xsltc.DOM;
33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
37 import com.sun.org.apache.xalan.internal.xsltc.dom.Axis;
38 import com.sun.org.apache.xml.internal.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 a parent location path.
145      */

146     private boolean hasParentLocationPath() {
147     return getParent() instanceof ParentLocationPath;
148     }
149     
150     /**
151      * Returns 'true' if this step has any predicates
152      */

153     private boolean hasPredicates() {
154     return _predicates != null && _predicates.size() > 0;
155     }
156
157     /**
158      * Returns 'true' if this step is used within a predicate
159      */

160     private boolean isPredicate() {
161     SyntaxTreeNode parent = this;
162     while (parent != null) {
163         parent = parent.getParent();
164         if (parent instanceof Predicate) return true;
165     }
166     return false;
167     }
168
169     /**
170      * True if this step is the abbreviated step '.'
171      */

172     public boolean isAbbreviatedDot() {
173     return _nodeType == NodeTest.ANODE && _axis == Axis.SELF;
174     }
175
176
177     /**
178      * True if this step is the abbreviated step '..'
179      */

180     public boolean isAbbreviatedDDot() {
181     return _nodeType == NodeTest.ANODE && _axis == Axis.PARENT;
182     }
183
184     /**
185      * Type check this step. The abbreviated steps '.' and '@attr' are
186      * assigned type node if they have no predicates. All other steps
187      * have type node-set.
188      */

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

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

352     public void translatePredicates(ClassGenerator classGen,
353                     MethodGenerator methodGen) {
354     final ConstantPoolGen cpg = classGen.getConstantPool();
355     final InstructionList il = methodGen.getInstructionList();
356
357     int idx = 0;
358
359     if (_predicates.size() == 0) {
360         translate(classGen, methodGen);
361     }
362     else {
363         final Predicate predicate = (Predicate)_predicates.lastElement();
364         _predicates.remove(predicate);
365
366         // Special case for predicates that can use the NodeValueIterator
367
// instead of an auxiliary class. Certain path/predicates pairs
368
// are translated into a base path, on top of which we place a
369
// node value iterator that tests for the desired value:
370
// foo[@attr = 'str'] -> foo/@attr + test(value='str')
371
// foo[bar = 'str'] -> foo/bar + test(value='str')
372
// foo/bar[. = 'str'] -> foo/bar + test(value='str')
373
if (predicate.isNodeValueTest()) {
374         Step step = predicate.getStep();
375
376         il.append(methodGen.loadDOM());
377         // If the predicate's Step is simply '.' we translate this Step
378
// and place the node test on top of the resulting iterator
379
if (step.isAbbreviatedDot()) {
380             translate(classGen, methodGen);
381             il.append(new ICONST(DOM.RETURN_CURRENT));
382         }
383         // Otherwise we create a parent location path with this Step and
384
// the predicates Step, and place the node test on top of that
385
else {
386             ParentLocationPath path = new ParentLocationPath(this, step);
387                     _parent = step._parent = path; // Force re-parenting
388

389             try {
390             path.typeCheck(getParser().getSymbolTable());
391             }
392             catch (TypeCheckError e) { }
393             path.translate(classGen, methodGen);
394             il.append(new ICONST(DOM.RETURN_PARENT));
395         }
396         predicate.translate(classGen, methodGen);
397         idx = cpg.addInterfaceMethodref(DOM_INTF,
398                         GET_NODE_VALUE_ITERATOR,
399                         GET_NODE_VALUE_ITERATOR_SIG);
400         il.append(new INVOKEINTERFACE(idx, 5));
401         }
402         // Handle '//*[n]' expression
403
else if (predicate.isNthDescendant()) {
404         il.append(methodGen.loadDOM());
405         // il.append(new ICONST(NodeTest.ELEMENT));
406
il.append(new ICONST(predicate.getPosType()));
407         predicate.translate(classGen, methodGen);
408         il.append(new ICONST(0));
409         idx = cpg.addInterfaceMethodref(DOM_INTF,
410                         "getNthDescendant",
411                         "(IIZ)"+NODE_ITERATOR_SIG);
412         il.append(new INVOKEINTERFACE(idx, 4));
413         }
414         // Handle 'elem[n]' expression
415
else if (predicate.isNthPositionFilter()) {
416         idx = cpg.addMethodref(NTH_ITERATOR_CLASS,
417                        "<init>",
418                        "("+NODE_ITERATOR_SIG+"I)V");
419         il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS)));
420         il.append(DUP);
421         translatePredicates(classGen, methodGen); // recursive call
422
predicate.translate(classGen, methodGen);
423         il.append(new INVOKESPECIAL(idx));
424         }
425         else {
426         idx = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR,
427                        "<init>",
428                        "("
429                        + NODE_ITERATOR_SIG
430                        + CURRENT_NODE_LIST_FILTER_SIG
431                        + NODE_SIG
432                        + TRANSLET_SIG
433                        + ")V");
434         // create new CurrentNodeListIterator
435
il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
436         il.append(DUP);
437         translatePredicates(classGen, methodGen); // recursive call
438
predicate.translateFilter(classGen, methodGen);
439         
440         il.append(methodGen.loadCurrentNode());
441         il.append(classGen.loadTranslet());
442         if (classGen.isExternal()) {
443             final String JavaDoc className = classGen.getClassName();
444             il.append(new CHECKCAST(cpg.addClass(className)));
445         }
446         il.append(new INVOKESPECIAL(idx));
447         }
448     }
449     }
450
451     /**
452      * Returns a string representation of this step.
453      */

454     public String JavaDoc toString() {
455     final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("step(\"");
456     buffer.append(Axis.names[_axis]).append("\", ").append(_nodeType);
457     if (_predicates != null) {
458         final int n = _predicates.size();
459         for (int i = 0; i < n; i++) {
460         final Predicate pred = (Predicate)_predicates.elementAt(i);
461         buffer.append(", ").append(pred.toString());
462         }
463     }
464     return buffer.append(')').toString();
465     }
466 }
467
Popular Tags