View Javadoc
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 }