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