1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * @LastModified: Oct 2017 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xalan.internal.xsltc.compiler; 23 24 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 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.Type; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 33 import com.sun.org.apache.xml.internal.utils.XML11Char; 34 import java.util.List; 35 36 /** 37 * @author Jacek Ambroziak 38 * @author Santiago Pericas-Geertsen 39 * @author Erwin Bolwidt <ejb@klomp.org> 40 */ 41 final class CallTemplate extends Instruction { 42 43 /** 44 * Name of template to call. 45 */ 46 private QName _name; 47 48 /** 49 * The array of effective parameters in this CallTemplate. An object in 50 * this array can be either a WithParam or a Param if no WithParam 51 * exists for a particular parameter. 52 */ 53 private SyntaxTreeNode[] _parameters = null; 54 55 /** 56 * The corresponding template which this CallTemplate calls. 57 */ 58 private Template _calleeTemplate = null; 59 60 public void display(int indent) { 61 indent(indent); 62 System.out.print("CallTemplate"); 63 Util.println(" name " + _name); 64 displayContents(indent + IndentIncrement); 65 } 66 67 public boolean hasWithParams() { 68 return elementCount() > 0; 69 } 70 71 public void parseContents(Parser parser) { 72 final String name = getAttribute("name"); 73 if (name.length() > 0) { 74 if (!XML11Char.isXML11ValidQName(name)) { 75 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this); 76 parser.reportError(Constants.ERROR, err); 77 } 78 _name = parser.getQNameIgnoreDefaultNs(name); 79 } 80 else { 81 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name"); 82 } 83 parseChildren(parser); 84 } 85 86 /** 87 * Verify that a template with this name exists. 88 */ 89 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 90 final Template template = stable.lookupTemplate(_name); 91 if (template != null) { 92 typeCheckContents(stable); 93 } 94 else { 95 ErrorMsg err = new ErrorMsg(ErrorMsg.TEMPLATE_UNDEF_ERR,_name,this); 96 throw new TypeCheckError(err); 97 } 98 return Type.Void; 99 } 100 101 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 102 final Stylesheet stylesheet = classGen.getStylesheet(); 103 final ConstantPoolGen cpg = classGen.getConstantPool(); 104 final InstructionList il = methodGen.getInstructionList(); 105 106 // If there are Params in the stylesheet or WithParams in this call? 107 if (stylesheet.hasLocalParams() || hasContents()) { 108 _calleeTemplate = getCalleeTemplate(); 109 110 // Build the parameter list if the called template is simple named 111 if (_calleeTemplate != null) { 112 buildParameterList(); 113 } 114 // This is only needed when the called template is not 115 // a simple named template. 116 else { 117 // Push parameter frame 118 final int push = cpg.addMethodref(TRANSLET_CLASS, 119 PUSH_PARAM_FRAME, 120 PUSH_PARAM_FRAME_SIG); 121 il.append(classGen.loadTranslet()); 122 il.append(new INVOKEVIRTUAL(push)); 123 translateContents(classGen, methodGen); 124 } 125 } 126 127 // Generate a valid Java method name 128 final String className = stylesheet.getClassName(); 129 String methodName = Util.escape(_name.toString()); 130 131 // Load standard arguments 132 il.append(classGen.loadTranslet()); 133 il.append(methodGen.loadDOM()); 134 il.append(methodGen.loadIterator()); 135 il.append(methodGen.loadHandler()); 136 il.append(methodGen.loadCurrentNode()); 137 138 // Initialize prefix of method signature 139 StringBuffer methodSig = new StringBuffer("(" + DOM_INTF_SIG 140 + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + NODE_SIG); 141 142 // If calling a simply named template, push actual arguments 143 if (_calleeTemplate != null) { 144 int numParams = _parameters.length; 145 146 for (int i = 0; i < numParams; i++) { 147 SyntaxTreeNode node = _parameters[i]; 148 methodSig.append(OBJECT_SIG); // append Object to signature 149 150 // Push 'null' if Param to indicate no actual parameter specified 151 if (node instanceof Param) { 152 il.append(ACONST_NULL); 153 } 154 else { // translate WithParam 155 node.translate(classGen, methodGen); 156 } 157 } 158 } 159 160 // Complete signature and generate invokevirtual call 161 methodSig.append(")V"); 162 il.append(new INVOKEVIRTUAL(cpg.addMethodref(className, 163 methodName, 164 methodSig.toString()))); 165 166 // release temporary result trees 167 if (_parameters != null) { 168 for (int i = 0; i < _parameters.length; i++) { 169 if (_parameters[i] instanceof WithParam) { 170 ((WithParam)_parameters[i]).releaseResultTree(classGen, methodGen); 171 } 172 } 173 } 174 175 // Do not need to call Translet.popParamFrame() if we are 176 // calling a simple named template. 177 if (_calleeTemplate == null && (stylesheet.hasLocalParams() || hasContents())) { 178 // Pop parameter frame 179 final int pop = cpg.addMethodref(TRANSLET_CLASS, 180 POP_PARAM_FRAME, 181 POP_PARAM_FRAME_SIG); 182 il.append(classGen.loadTranslet()); 183 il.append(new INVOKEVIRTUAL(pop)); 184 } 185 } 186 187 /** 188 * Return the simple named template which this CallTemplate calls. 189 * Return false if there is no matched template or the matched 190 * template is not a simple named template. 191 */ 192 public Template getCalleeTemplate() { 193 Template foundTemplate 194 = getXSLTC().getParser().getSymbolTable().lookupTemplate(_name); 195 196 return foundTemplate.isSimpleNamedTemplate() ? foundTemplate : null; 197 } 198 199 /** 200 * Build the list of effective parameters in this CallTemplate. 201 * The parameters of the called template are put into the array first. 202 * Then we visit the WithParam children of this CallTemplate and replace 203 * the Param with a corresponding WithParam having the same name. 204 */ 205 private void buildParameterList() { 206 // Put the parameters from the called template into the array first. 207 // This is to ensure the order of the parameters. 208 List<Param> defaultParams = _calleeTemplate.getParameters(); 209 int numParams = defaultParams.size(); 210 _parameters = new SyntaxTreeNode[numParams]; 211 for (int i = 0; i < numParams; i++) { 212 _parameters[i] = defaultParams.get(i); 213 } 214 215 // Replace a Param with a WithParam if they have the same name. 216 int count = elementCount(); 217 for (int i = 0; i < count; i++) { 218 Object node = elementAt(i); 219 220 // Ignore if not WithParam 221 if (node instanceof WithParam) { 222 WithParam withParam = (WithParam)node; 223 QName name = withParam.getName(); 224 225 // Search for a Param with the same name 226 for (int k = 0; k < numParams; k++) { 227 SyntaxTreeNode parm = _parameters[k]; 228 if (parm instanceof Param 229 && ((Param)parm).getName().equals(name)) { 230 withParam.setDoParameterOptimization(true); 231 _parameters[k] = withParam; 232 break; 233 } 234 else if (parm instanceof WithParam 235 && ((WithParam)parm).getName().equals(name)) { 236 withParam.setDoParameterOptimization(true); 237 _parameters[k] = withParam; 238 break; 239 } 240 } 241 } 242 } 243 } 244 }