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 }