001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: CallTemplate.java 1225842 2011-12-30 15:14:35Z mrglavas $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import java.util.Vector; 025 026 import org.apache.bcel.generic.ConstantPoolGen; 027 import org.apache.bcel.generic.INVOKEVIRTUAL; 028 import org.apache.bcel.generic.InstructionList; 029 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 030 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 031 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 032 import org.apache.xalan.xsltc.compiler.util.Type; 033 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 034 import org.apache.xalan.xsltc.compiler.util.Util; 035 import org.apache.xml.utils.XML11Char; 036 037 /** 038 * @author Jacek Ambroziak 039 * @author Santiago Pericas-Geertsen 040 * @author Erwin Bolwidt <ejb@klomp.org> 041 */ 042 final class CallTemplate extends Instruction { 043 044 /** 045 * Name of template to call. 046 */ 047 private QName _name; 048 049 /** 050 * The array of effective parameters in this CallTemplate. An object in 051 * this array can be either a WithParam or a Param if no WithParam 052 * exists for a particular parameter. 053 */ 054 private Object[] _parameters = null; 055 056 /** 057 * The corresponding template which this CallTemplate calls. 058 */ 059 private Template _calleeTemplate = null; 060 061 public void display(int indent) { 062 indent(indent); 063 System.out.print("CallTemplate"); 064 Util.println(" name " + _name); 065 displayContents(indent + IndentIncrement); 066 } 067 068 public boolean hasWithParams() { 069 return elementCount() > 0; 070 } 071 072 public void parseContents(Parser parser) { 073 final String name = getAttribute("name"); 074 if (name.length() > 0) { 075 if (!XML11Char.isXML11ValidQName(name)) { 076 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this); 077 parser.reportError(Constants.ERROR, err); 078 } 079 _name = parser.getQNameIgnoreDefaultNs(name); 080 } 081 else { 082 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name"); 083 } 084 parseChildren(parser); 085 } 086 087 /** 088 * Verify that a template with this name exists. 089 */ 090 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 091 final Template template = stable.lookupTemplate(_name); 092 if (template != null) { 093 typeCheckContents(stable); 094 } 095 else { 096 ErrorMsg err = new ErrorMsg(ErrorMsg.TEMPLATE_UNDEF_ERR,_name,this); 097 throw new TypeCheckError(err); 098 } 099 return Type.Void; 100 } 101 102 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 103 final Stylesheet stylesheet = classGen.getStylesheet(); 104 final ConstantPoolGen cpg = classGen.getConstantPool(); 105 final InstructionList il = methodGen.getInstructionList(); 106 107 // If there are Params in the stylesheet or WithParams in this call? 108 if (stylesheet.hasLocalParams() || hasContents()) { 109 _calleeTemplate = getCalleeTemplate(); 110 111 // Build the parameter list if the called template is simple named 112 if (_calleeTemplate != null) { 113 buildParameterList(); 114 } 115 // This is only needed when the called template is not 116 // a simple named template. 117 else { 118 // Push parameter frame 119 final int push = cpg.addMethodref(TRANSLET_CLASS, 120 PUSH_PARAM_FRAME, 121 PUSH_PARAM_FRAME_SIG); 122 il.append(classGen.loadTranslet()); 123 il.append(new INVOKEVIRTUAL(push)); 124 translateContents(classGen, methodGen); 125 } 126 } 127 128 // Generate a valid Java method name 129 final String className = stylesheet.getClassName(); 130 String methodName = Util.escape(_name.toString()); 131 132 // Load standard arguments 133 il.append(classGen.loadTranslet()); 134 il.append(methodGen.loadDOM()); 135 il.append(methodGen.loadIterator()); 136 il.append(methodGen.loadHandler()); 137 il.append(methodGen.loadCurrentNode()); 138 139 // Initialize prefix of method signature 140 StringBuffer methodSig = new StringBuffer("(" + DOM_INTF_SIG 141 + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + NODE_SIG); 142 143 // If calling a simply named template, push actual arguments 144 if (_calleeTemplate != null) { 145 Vector calleeParams = _calleeTemplate.getParameters(); 146 int numParams = _parameters.length; 147 148 for (int i = 0; i < numParams; i++) { 149 SyntaxTreeNode node = (SyntaxTreeNode)_parameters[i]; 150 methodSig.append(OBJECT_SIG); // append Object to signature 151 152 // Push 'null' if Param to indicate no actual parameter specified 153 if (node instanceof Param) { 154 il.append(ACONST_NULL); 155 } 156 else { // translate WithParam 157 node.translate(classGen, methodGen); 158 } 159 } 160 } 161 162 // Complete signature and generate invokevirtual call 163 methodSig.append(")V"); 164 il.append(new INVOKEVIRTUAL(cpg.addMethodref(className, 165 methodName, 166 methodSig.toString()))); 167 168 // Do not need to call Translet.popParamFrame() if we are 169 // calling a simple named template. 170 if (_calleeTemplate == null && (stylesheet.hasLocalParams() || hasContents())) { 171 // Pop parameter frame 172 final int pop = cpg.addMethodref(TRANSLET_CLASS, 173 POP_PARAM_FRAME, 174 POP_PARAM_FRAME_SIG); 175 il.append(classGen.loadTranslet()); 176 il.append(new INVOKEVIRTUAL(pop)); 177 } 178 } 179 180 /** 181 * Return the simple named template which this CallTemplate calls. 182 * Return false if there is no matched template or the matched 183 * template is not a simple named template. 184 */ 185 public Template getCalleeTemplate() { 186 Template foundTemplate 187 = getXSLTC().getParser().getSymbolTable().lookupTemplate(_name); 188 189 return foundTemplate.isSimpleNamedTemplate() ? foundTemplate : null; 190 } 191 192 /** 193 * Build the list of effective parameters in this CallTemplate. 194 * The parameters of the called template are put into the array first. 195 * Then we visit the WithParam children of this CallTemplate and replace 196 * the Param with a corresponding WithParam having the same name. 197 */ 198 private void buildParameterList() { 199 // Put the parameters from the called template into the array first. 200 // This is to ensure the order of the parameters. 201 Vector defaultParams = _calleeTemplate.getParameters(); 202 int numParams = defaultParams.size(); 203 _parameters = new Object[numParams]; 204 for (int i = 0; i < numParams; i++) { 205 _parameters[i] = defaultParams.elementAt(i); 206 } 207 208 // Replace a Param with a WithParam if they have the same name. 209 int count = elementCount(); 210 for (int i = 0; i < count; i++) { 211 Object node = elementAt(i); 212 213 // Ignore if not WithParam 214 if (node instanceof WithParam) { 215 WithParam withParam = (WithParam)node; 216 QName name = withParam.getName(); 217 218 // Search for a Param with the same name 219 for (int k = 0; k < numParams; k++) { 220 Object object = _parameters[k]; 221 if (object instanceof Param 222 && ((Param)object).getName().equals(name)) { 223 withParam.setDoParameterOptimization(true); 224 _parameters[k] = withParam; 225 break; 226 } 227 else if (object instanceof WithParam 228 && ((WithParam)object).getName().equals(name)) { 229 withParam.setDoParameterOptimization(true); 230 _parameters[k] = withParam; 231 break; 232 } 233 } 234 } 235 } 236 } 237 } 238