View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: ForEach.java,v 1.2.4.1 2005/09/01 15:23:46 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import java.util.Enumeration;
27  import java.util.Vector;
28  
29  import com.sun.org.apache.bcel.internal.generic.BranchHandle;
30  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
31  import com.sun.org.apache.bcel.internal.generic.GOTO;
32  import com.sun.org.apache.bcel.internal.generic.IFGT;
33  import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
34  import com.sun.org.apache.bcel.internal.generic.InstructionList;
35  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
36  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
37  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
38  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
39  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
40  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
41  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
42  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
43  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
44  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
45  
46  /**
47   * @author Jacek Ambroziak
48   * @author Santiago Pericas-Geertsen
49   * @author Morten Jorgensen
50   */
51  final class ForEach extends Instruction {
52  
53      private Expression _select;
54      private Type       _type;
55  
56      public void display(int indent) {
57          indent(indent);
58          Util.println("ForEach");
59          indent(indent + IndentIncrement);
60          Util.println("select " + _select.toString());
61          displayContents(indent + IndentIncrement);
62      }
63  
64      public void parseContents(Parser parser) {
65          _select = parser.parseExpression(this, "select", null);
66  
67          parseChildren(parser);
68  
69          // make sure required attribute(s) have been set
70          if (_select.isDummy()) {
71              reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "select");
72          }
73      }
74  
75      public Type typeCheck(SymbolTable stable) throws TypeCheckError {
76          _type = _select.typeCheck(stable);
77  
78          if (_type instanceof ReferenceType || _type instanceof NodeType) {
79              _select = new CastExpr(_select, Type.NodeSet);
80              typeCheckContents(stable);
81              return Type.Void;
82          }
83          if (_type instanceof NodeSetType||_type instanceof ResultTreeType) {
84              typeCheckContents(stable);
85              return Type.Void;
86          }
87          throw new TypeCheckError(this);
88      }
89  
90      public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
91          final ConstantPoolGen cpg = classGen.getConstantPool();
92          final InstructionList il = methodGen.getInstructionList();
93  
94          // Save current node and current iterator on the stack
95          il.append(methodGen.loadCurrentNode());
96          il.append(methodGen.loadIterator());
97  
98          // Collect sort objects associated with this instruction
99          final Vector sortObjects = new Vector();
100         Enumeration children = elements();
101         while (children.hasMoreElements()) {
102             final Object child = children.nextElement();
103             if (child instanceof Sort) {
104                 sortObjects.addElement(child);
105             }
106         }
107 
108         if ((_type != null) && (_type instanceof ResultTreeType)) {
109             // Store existing DOM on stack - must be restored when loop is done
110             il.append(methodGen.loadDOM());
111 
112             // <xsl:sort> cannot be applied to a result tree - issue warning
113             if (sortObjects.size() > 0) {
114                 ErrorMsg msg = new ErrorMsg(ErrorMsg.RESULT_TREE_SORT_ERR,this);
115                 getParser().reportError(WARNING, msg);
116             }
117 
118             // Put the result tree on the stack (DOM)
119             _select.translate(classGen, methodGen);
120             // Get an iterator for the whole DOM - excluding the root node
121             _type.translateTo(classGen, methodGen, Type.NodeSet);
122             // Store the result tree as the default DOM
123             il.append(SWAP);
124             il.append(methodGen.storeDOM());
125         }
126         else {
127             // Compile node iterator
128             if (sortObjects.size() > 0) {
129                 Sort.translateSortIterator(classGen, methodGen,
130                                            _select, sortObjects);
131             }
132             else {
133                 _select.translate(classGen, methodGen);
134             }
135 
136             if (_type instanceof ReferenceType == false) {
137                 il.append(methodGen.loadContextNode());
138                 il.append(methodGen.setStartNode());
139             }
140         }
141 
142 
143         // Overwrite current iterator
144         il.append(methodGen.storeIterator());
145 
146         // Give local variables (if any) default values before starting loop
147         initializeVariables(classGen, methodGen);
148 
149         final BranchHandle nextNode = il.append(new GOTO(null));
150         final InstructionHandle loop = il.append(NOP);
151 
152         translateContents(classGen, methodGen);
153 
154         nextNode.setTarget(il.append(methodGen.loadIterator()));
155         il.append(methodGen.nextNode());
156         il.append(DUP);
157         il.append(methodGen.storeCurrentNode());
158         il.append(new IFGT(loop));
159 
160         // Restore current DOM (if result tree was used instead for this loop)
161         if ((_type != null) && (_type instanceof ResultTreeType)) {
162             il.append(methodGen.storeDOM());
163         }
164 
165         // Restore current node and current iterator from the stack
166         il.append(methodGen.storeIterator());
167         il.append(methodGen.storeCurrentNode());
168     }
169 
170     /**
171      * The code that is generated by nested for-each loops can appear to some
172      * JVMs as if it is accessing un-initialized variables. We must add some
173      * code that pushes the default variable value on the stack and pops it
174      * into the variable slot. This is done by the Variable.initialize()
175      * method. The code that we compile for this loop looks like this:
176      *
177      *           initialize iterator
178      *           initialize variables <-- HERE!!!
179      *           goto   Iterate
180      *  Loop:    :
181      *           : (code for <xsl:for-each> contents)
182      *           :
183      *  Iterate: node = iterator.next();
184      *           if (node != END) goto Loop
185      */
186     public void initializeVariables(ClassGenerator classGen,
187                                    MethodGenerator methodGen) {
188         final int n = elementCount();
189         for (int i = 0; i < n; i++) {
190             final Object child = getContents().elementAt(i);
191             if (child instanceof Variable) {
192                 Variable var = (Variable)child;
193                 var.initialize(classGen, methodGen);
194             }
195         }
196     }
197 
198 }