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