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: Param.java,v 1.2.4.1 2005/09/02 11:03:42 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  25 
  26 import com.sun.org.apache.bcel.internal.classfile.Field;
  27 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  28 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
  29 import com.sun.org.apache.bcel.internal.generic.IFNONNULL;
  30 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  31 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  32 import com.sun.org.apache.bcel.internal.generic.Instruction;
  33 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  34 import com.sun.org.apache.bcel.internal.generic.PUSH;
  35 import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType;
  42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  43 import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
  44 
  45 /**
  46  * @author Jacek Ambroziak
  47  * @author Santiago Pericas-Geertsen
  48  * @author Morten Jorgensen
  49  * @author Erwin Bolwidt <ejb@klomp.org>
  50  * @author John Howard <JohnH@schemasoft.com>
  51  */
  52 final class Param extends VariableBase {
  53 
  54     /**
  55      * True if this Param is declared in a simple named template.
  56      * This is used to optimize codegen for parameter passing
  57      * in named templates.
  58      */
  59     private boolean _isInSimpleNamedTemplate = false;
  60 
  61     /**
  62      * Display variable as single string
  63      */
  64     public String toString() {
  65         return "param(" + _name + ")";
  66     }
  67 
  68     /**
  69      * Set the instruction for loading the value of this variable onto the
  70      * JVM stack and returns the old instruction.
  71      */
  72     public Instruction setLoadInstruction(Instruction instruction) {
  73         Instruction tmp = _loadInstruction;
  74         _loadInstruction = instruction;
  75         return tmp;
  76     }
  77 
  78     /**
  79      * Set the instruction for storing a value from the stack into this
  80      * variable and returns the old instruction.
  81      */
  82     public Instruction setStoreInstruction(Instruction instruction) {
  83         Instruction tmp = _storeInstruction;
  84         _storeInstruction = instruction;
  85         return tmp;
  86     }
  87 
  88     /**
  89      * Display variable in a full AST dump
  90      */
  91     public void display(int indent) {
  92         indent(indent);
  93         System.out.println("param " + _name);
  94         if (_select != null) {
  95             indent(indent + IndentIncrement);
  96             System.out.println("select " + _select.toString());
  97         }
  98         displayContents(indent + IndentIncrement);
  99     }
 100 
 101     /**
 102      * Parse the contents of the <xsl:param> element. This method must read
 103      * the 'name' (required) and 'select' (optional) attributes.
 104      */
 105     public void parseContents(Parser parser) {
 106 
 107         // Parse 'name' and 'select' attributes plus parameter contents
 108         super.parseContents(parser);
 109 
 110         // Add a ref to this param to its enclosing construct
 111         final SyntaxTreeNode parent = getParent();
 112         if (parent instanceof Stylesheet) {
 113             // Mark this as a global parameter
 114             _isLocal = false;
 115             // Check if a global variable with this name already exists...
 116             Param param = parser.getSymbolTable().lookupParam(_name);
 117             // ...and if it does we need to check import precedence
 118             if (param != null) {
 119                 final int us = this.getImportPrecedence();
 120                 final int them = param.getImportPrecedence();
 121                 // It is an error if the two have the same import precedence
 122                 if (us == them) {
 123                     final String name = _name.toString();
 124                     reportError(this, parser, ErrorMsg.VARIABLE_REDEF_ERR,name);
 125                 }
 126                 // Ignore this if previous definition has higher precedence
 127                 else if (them > us) {
 128                     _ignore = true;
 129                     copyReferences(param);
 130                     return;
 131                 }
 132                 else {
 133                     param.copyReferences(this);
 134                     param.disable();
 135                 }
 136             }
 137             // Add this variable if we have higher precedence
 138             ((Stylesheet)parent).addParam(this);
 139             parser.getSymbolTable().addParam(this);
 140         }
 141         else if (parent instanceof Template) {
 142             Template template = (Template) parent;
 143             _isLocal = true;
 144             template.addParameter(this);
 145             if (template.isSimpleNamedTemplate()) {
 146                 _isInSimpleNamedTemplate = true;
 147             }
 148         }
 149     }
 150 
 151     /**
 152      * Type-checks the parameter. The parameter type is determined by the
 153      * 'select' expression (if present) or is a result tree if the parameter
 154      * element has a body and no 'select' expression.
 155      */
 156     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
 157         if (_select != null) {
 158             _type = _select.typeCheck(stable);
 159             if (_type instanceof ReferenceType == false && !(_type instanceof ObjectType)) {
 160                 _select = new CastExpr(_select, Type.Reference);
 161             }
 162         }
 163         else if (hasContents()) {
 164             typeCheckContents(stable);
 165         }
 166         _type = Type.Reference;
 167 
 168         // This element has no type (the parameter does, but the parameter
 169         // element itself does not).
 170         return Type.Void;
 171     }
 172 
 173     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 174         final ConstantPoolGen cpg = classGen.getConstantPool();
 175         final InstructionList il = methodGen.getInstructionList();
 176 
 177         if (_ignore) return;
 178         _ignore = true;
 179 
 180         /*
 181          * To fix bug 24518 related to setting parameters of the form
 182          * {namespaceuri}localName which will get mapped to an instance
 183          * variable in the class.
 184          */
 185         final String name = BasisLibrary.mapQNameToJavaName(_name.toString());
 186         final String signature = _type.toSignature();
 187         final String className = _type.getClassName();
 188 
 189         if (isLocal()) {
 190             /*
 191               * If simple named template then generate a conditional init of the
 192               * param using its default value:
 193               *       if (param == null) param = <default-value>
 194               */
 195             if (_isInSimpleNamedTemplate) {
 196                 il.append(loadInstruction());
 197                 BranchHandle ifBlock = il.append(new IFNONNULL(null));
 198                 translateValue(classGen, methodGen);
 199                 il.append(storeInstruction());
 200                 ifBlock.setTarget(il.append(NOP));
 201                 return;
 202             }
 203 
 204             il.append(classGen.loadTranslet());
 205             il.append(new PUSH(cpg, name));
 206             translateValue(classGen, methodGen);
 207             il.append(new PUSH(cpg, true));
 208 
 209             // Call addParameter() from this class
 210             il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
 211                                                          ADD_PARAMETER,
 212                                                          ADD_PARAMETER_SIG)));
 213             if (className != EMPTYSTRING) {
 214                 il.append(new CHECKCAST(cpg.addClass(className)));
 215             }
 216 
 217             _type.translateUnBox(classGen, methodGen);
 218 
 219             if (_refs.isEmpty()) { // nobody uses the value
 220                 il.append(_type.POP());
 221                 _local = null;
 222             }
 223             else {              // normal case
 224                 _local = methodGen.addLocalVariable2(name,
 225                                                      _type.toJCType(),
 226                                                      il.getEnd());
 227                 // Cache the result of addParameter() in a local variable
 228                 il.append(_type.STORE(_local.getIndex()));
 229             }
 230         }
 231         else {
 232             if (classGen.containsField(name) == null) {
 233                 classGen.addField(new Field(ACC_PUBLIC, cpg.addUtf8(name),
 234                                             cpg.addUtf8(signature),
 235                                             null, cpg.getConstantPool()));
 236                 il.append(classGen.loadTranslet());
 237                 il.append(DUP);
 238                 il.append(new PUSH(cpg, name));
 239                 translateValue(classGen, methodGen);
 240                 il.append(new PUSH(cpg, true));
 241 
 242                 // Call addParameter() from this class
 243                 il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
 244                                                      ADD_PARAMETER,
 245                                                      ADD_PARAMETER_SIG)));
 246 
 247                 _type.translateUnBox(classGen, methodGen);
 248 
 249                 // Cache the result of addParameter() in a field
 250                 if (className != EMPTYSTRING) {
 251                     il.append(new CHECKCAST(cpg.addClass(className)));
 252                 }
 253                 il.append(new PUTFIELD(cpg.addFieldref(classGen.getClassName(),
 254                                                        name, signature)));
 255             }
 256         }
 257     }
 258 }