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 }