001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: WithParam.java 468650 2006-10-28 07:03:30Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import org.apache.bcel.generic.ConstantPoolGen;
025 import org.apache.bcel.generic.INVOKEVIRTUAL;
026 import org.apache.bcel.generic.InstructionList;
027 import org.apache.bcel.generic.PUSH;
028 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
029 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
030 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
031 import org.apache.xalan.xsltc.compiler.util.ReferenceType;
032 import org.apache.xalan.xsltc.compiler.util.Type;
033 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
034 import org.apache.xalan.xsltc.compiler.util.Util;
035 import org.apache.xml.utils.XML11Char;
036
037 /**
038 * @author Jacek Ambroziak
039 * @author Santiago Pericas-Geertsen
040 * @author Morten Jorgensen
041 * @author John Howard <JohnH@schemasoft.com>
042 */
043 final class WithParam extends Instruction {
044
045 /**
046 * Parameter's name.
047 */
048 private QName _name;
049
050 /**
051 * The escaped qname of the with-param.
052 */
053 protected String _escapedName;
054
055 /**
056 * Parameter's default value.
057 */
058 private Expression _select;
059
060 /**
061 * %OPT% This is set to true when the WithParam is used in a CallTemplate
062 * for a simple named template. If this is true, the parameters are
063 * passed to the named template through method arguments rather than
064 * using the expensive Translet.addParameter() call.
065 */
066 private boolean _doParameterOptimization = false;
067
068 /**
069 * Displays the contents of this element
070 */
071 public void display(int indent) {
072 indent(indent);
073 Util.println("with-param " + _name);
074 if (_select != null) {
075 indent(indent + IndentIncrement);
076 Util.println("select " + _select.toString());
077 }
078 displayContents(indent + IndentIncrement);
079 }
080
081 /**
082 * Returns the escaped qname of the parameter
083 */
084 public String getEscapedName() {
085 return _escapedName;
086 }
087
088 /**
089 * Return the name of this WithParam.
090 */
091 public QName getName() {
092 return _name;
093 }
094
095 /**
096 * Set the name of the variable or paremeter. Escape all special chars.
097 */
098 public void setName(QName name) {
099 _name = name;
100 _escapedName = Util.escape(name.getStringRep());
101 }
102
103 /**
104 * Set the do parameter optimization flag
105 */
106 public void setDoParameterOptimization(boolean flag) {
107 _doParameterOptimization = flag;
108 }
109
110 /**
111 * The contents of a <xsl:with-param> elements are either in the element's
112 * 'select' attribute (this has precedence) or in the element body.
113 */
114 public void parseContents(Parser parser) {
115 final String name = getAttribute("name");
116 if (name.length() > 0) {
117 if (!XML11Char.isXML11ValidQName(name)) {
118 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name,
119 this);
120 parser.reportError(Constants.ERROR, err);
121 }
122 setName(parser.getQNameIgnoreDefaultNs(name));
123 }
124 else {
125 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name");
126 }
127
128 final String select = getAttribute("select");
129 if (select.length() > 0) {
130 _select = parser.parseExpression(this, "select", null);
131 }
132
133 parseChildren(parser);
134 }
135
136 /**
137 * Type-check either the select attribute or the element body, depending
138 * on which is in use.
139 */
140 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
141 if (_select != null) {
142 final Type tselect = _select.typeCheck(stable);
143 if (tselect instanceof ReferenceType == false) {
144 _select = new CastExpr(_select, Type.Reference);
145 }
146 }
147 else {
148 typeCheckContents(stable);
149 }
150 return Type.Void;
151 }
152
153 /**
154 * Compile the value of the parameter, which is either in an expression in
155 * a 'select' attribute, or in the with-param element's body
156 */
157 public void translateValue(ClassGenerator classGen,
158 MethodGenerator methodGen) {
159 // Compile expression is 'select' attribute if present
160 if (_select != null) {
161 _select.translate(classGen, methodGen);
162 _select.startIterator(classGen, methodGen);
163 }
164 // If not, compile result tree from parameter body if present.
165 else if (hasContents()) {
166 compileResultTree(classGen, methodGen);
167 }
168 // If neither are present then store empty string in parameter slot
169 else {
170 final ConstantPoolGen cpg = classGen.getConstantPool();
171 final InstructionList il = methodGen.getInstructionList();
172 il.append(new PUSH(cpg, Constants.EMPTYSTRING));
173 }
174 }
175
176 /**
177 * This code generates a sequence of bytecodes that call the
178 * addParameter() method in AbstractTranslet. The method call will add
179 * (or update) the parameter frame with the new parameter value.
180 */
181 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
182 final ConstantPoolGen cpg = classGen.getConstantPool();
183 final InstructionList il = methodGen.getInstructionList();
184
185 // Translate the value and put it on the stack
186 if (_doParameterOptimization) {
187 translateValue(classGen, methodGen);
188 return;
189 }
190
191 // Make name acceptable for use as field name in class
192 String name = Util.escape(getEscapedName());
193
194 // Load reference to the translet (method is in AbstractTranslet)
195 il.append(classGen.loadTranslet());
196
197 // Load the name of the parameter
198 il.append(new PUSH(cpg, name)); // TODO: namespace ?
199 // Generete the value of the parameter (use value in 'select' by def.)
200 translateValue(classGen, methodGen);
201 // Mark this parameter value is not being the default value
202 il.append(new PUSH(cpg, false));
203 // Pass the parameter to the template
204 il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
205 ADD_PARAMETER,
206 ADD_PARAMETER_SIG)));
207 il.append(POP); // cleanup stack
208 }
209 }