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 }