1 /* 2 * Copyright (c) 2015, 2017, 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.ArrayList; 43 import java.util.Iterator; 44 import java.util.List; 45 46 /** 47 * @author Jacek Ambroziak 48 * @author Santiago Pericas-Geertsen 49 * @author Morten Jorgensen 50 * @LastModified: Oct 2017 51 */ 52 final 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 List<Sort> sortObjects = new ArrayList<>(); 101 Iterator<SyntaxTreeNode> children = elements(); 102 while (children.hasNext()) { 103 final SyntaxTreeNode child = children.next(); 104 if (child instanceof Sort) { 105 sortObjects.add((Sort)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 }