View Javadoc
1   /*
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  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import com.sun.org.apache.bcel.internal.generic.ALOAD;
27  import com.sun.org.apache.bcel.internal.generic.ASTORE;
28  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
29  import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
30  import com.sun.org.apache.bcel.internal.generic.InstructionList;
31  import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
32  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
33  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
34  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
35  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
36  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
37  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
38  import com.sun.org.apache.xml.internal.utils.XML11Char;
39  
40  import java.util.Vector;
41  
42  /**
43   * @author Jacek Ambroziak
44   * @author Santiago Pericas-Geertsen
45   * @author Erwin Bolwidt <ejb@klomp.org>
46   */
47  final 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 }