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 package com.sun.org.apache.xalan.internal.xsltc.compiler; 22 23 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 24 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 25 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 26 import com.sun.org.apache.bcel.internal.generic.InstructionList; 27 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 28 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType; 32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType; 33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType; 34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 37 import com.sun.org.apache.xml.internal.utils.XML11Char; 38 import java.util.ArrayList; 39 import java.util.List; 40 41 /** 42 * @author Jacek Ambroziak 43 * @author Santiago Pericas-Geertsen 44 * @LastModified: Oct 2017 45 */ 46 final class ApplyTemplates extends Instruction { 47 private Expression _select; 48 private Type _type = null; 49 private QName _modeName; 50 private String _functionName; 51 52 public void display(int indent) { 53 indent(indent); 54 Util.println("ApplyTemplates"); 55 indent(indent + IndentIncrement); 56 Util.println("select " + _select.toString()); 57 if (_modeName != null) { 58 indent(indent + IndentIncrement); 59 Util.println("mode " + _modeName); 60 } 61 } 62 63 public boolean hasWithParams() { 64 return hasContents(); 65 } 66 67 public void parseContents(Parser parser) { 68 final String select = getAttribute("select"); 69 final String mode = getAttribute("mode"); 70 71 if (select.length() > 0) { 72 _select = parser.parseExpression(this, "select", null); 73 74 } 75 76 if (mode.length() > 0) { 77 if (!XML11Char.isXML11ValidQName(mode)) { 78 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this); 79 parser.reportError(Constants.ERROR, err); 80 } 81 _modeName = parser.getQNameIgnoreDefaultNs(mode); 82 } 83 84 // instantiate Mode if needed, cache (apply temp) function name 85 _functionName = 86 parser.getTopLevelStylesheet().getMode(_modeName).functionName(); 87 parseChildren(parser);// with-params 88 } 89 90 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 91 if (_select != null) { 92 _type = _select.typeCheck(stable); 93 if (_type instanceof NodeType || _type instanceof ReferenceType) { 94 _select = new CastExpr(_select, Type.NodeSet); 95 _type = Type.NodeSet; 96 } 97 if (_type instanceof NodeSetType||_type instanceof ResultTreeType) { 98 typeCheckContents(stable); // with-params 99 return Type.Void; 100 } 101 throw new TypeCheckError(this); 102 } 103 else { 104 typeCheckContents(stable); // with-params 105 return Type.Void; 106 } 107 } 108 109 /** 110 * Translate call-template. A parameter frame is pushed only if 111 * some template in the stylesheet uses parameters. 112 */ 113 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 114 boolean setStartNodeCalled = false; 115 final Stylesheet stylesheet = classGen.getStylesheet(); 116 final ConstantPoolGen cpg = classGen.getConstantPool(); 117 final InstructionList il = methodGen.getInstructionList(); 118 final int current = methodGen.getLocalIndex("current"); 119 120 // check if sorting nodes is required 121 final List<Sort> sortObjects = new ArrayList<>(); 122 for (final SyntaxTreeNode child : getContents()) { 123 if (child instanceof Sort) { 124 sortObjects.add((Sort)child); 125 } 126 } 127 128 // Push a new parameter frame 129 if (stylesheet.hasLocalParams() || hasContents()) { 130 il.append(classGen.loadTranslet()); 131 final int pushFrame = cpg.addMethodref(TRANSLET_CLASS, 132 PUSH_PARAM_FRAME, 133 PUSH_PARAM_FRAME_SIG); 134 il.append(new INVOKEVIRTUAL(pushFrame)); 135 // translate with-params 136 translateContents(classGen, methodGen); 137 } 138 139 140 il.append(classGen.loadTranslet()); 141 142 // The 'select' expression is a result-tree 143 if ((_type != null) && (_type instanceof ResultTreeType)) { 144 // <xsl:sort> cannot be applied to a result tree - issue warning 145 if (sortObjects.size() > 0) { 146 ErrorMsg err = new ErrorMsg(ErrorMsg.RESULT_TREE_SORT_ERR,this); 147 getParser().reportError(WARNING, err); 148 } 149 // Put the result tree (a DOM adapter) on the stack 150 _select.translate(classGen, methodGen); 151 // Get back the DOM and iterator (not just iterator!!!) 152 _type.translateTo(classGen, methodGen, Type.NodeSet); 153 } 154 else { 155 il.append(methodGen.loadDOM()); 156 157 // compute node iterator for applyTemplates 158 if (sortObjects.size() > 0) { 159 Sort.translateSortIterator(classGen, methodGen, 160 _select, sortObjects); 161 int setStartNode = cpg.addInterfaceMethodref(NODE_ITERATOR, 162 SET_START_NODE, 163 "(I)"+ 164 NODE_ITERATOR_SIG); 165 il.append(methodGen.loadCurrentNode()); 166 il.append(new INVOKEINTERFACE(setStartNode,2)); 167 setStartNodeCalled = true; 168 } 169 else { 170 if (_select == null) 171 Mode.compileGetChildren(classGen, methodGen, current); 172 else 173 _select.translate(classGen, methodGen); 174 } 175 } 176 177 if (_select != null && !setStartNodeCalled) { 178 _select.startIterator(classGen, methodGen); 179 } 180 181 //!!! need to instantiate all needed modes 182 final String className = classGen.getStylesheet().getClassName(); 183 il.append(methodGen.loadHandler()); 184 final String applyTemplatesSig = classGen.getApplyTemplatesSig(); 185 final int applyTemplates = cpg.addMethodref(className, 186 _functionName, 187 applyTemplatesSig); 188 il.append(new INVOKEVIRTUAL(applyTemplates)); 189 190 // unmap parameters to release temporary result trees 191 for (final SyntaxTreeNode child : getContents()) { 192 if (child instanceof WithParam) { 193 ((WithParam)child).releaseResultTree(classGen, methodGen); 194 } 195 } 196 197 // Pop parameter frame 198 if (stylesheet.hasLocalParams() || hasContents()) { 199 il.append(classGen.loadTranslet()); 200 final int popFrame = cpg.addMethodref(TRANSLET_CLASS, 201 POP_PARAM_FRAME, 202 POP_PARAM_FRAME_SIG); 203 il.append(new INVOKEVIRTUAL(popFrame)); 204 } 205 } 206 }