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