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