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