ohair | 6c32066 | 2012-03-04 11:55:34 -0800 | [diff] [blame^] | 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 | } |