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