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