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: VariableBase.java 528589 2007-04-13 18:50:56Z zongaro $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import java.util.Vector; 025 026 import org.apache.bcel.generic.ConstantPoolGen; 027 import org.apache.bcel.generic.Instruction; 028 import org.apache.bcel.generic.InstructionList; 029 import org.apache.bcel.generic.INVOKESPECIAL; 030 import org.apache.bcel.generic.LocalVariableGen; 031 import org.apache.bcel.generic.NEW; 032 import org.apache.bcel.generic.PUSH; 033 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 034 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 035 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 036 import org.apache.xalan.xsltc.compiler.util.NodeSetType; 037 import org.apache.xalan.xsltc.compiler.util.Type; 038 import org.apache.xalan.xsltc.compiler.util.Util; 039 import org.apache.xml.utils.XML11Char; 040 041 /** 042 * @author Jacek Ambroziak 043 * @author Santiago Pericas-Geertsen 044 * @author Morten Jorgensen 045 * @author Erwin Bolwidt <ejb@klomp.org> 046 * @author John Howard <JohnH@schemasoft.com> 047 */ 048 class VariableBase extends TopLevelElement { 049 050 protected QName _name; // The name of the variable. 051 protected String _escapedName; // The escaped qname of the variable. 052 protected Type _type; // The type of this variable. 053 protected boolean _isLocal; // True if the variable is local. 054 protected LocalVariableGen _local; // Reference to JVM variable 055 protected Instruction _loadInstruction; // Instruction to load JVM variable 056 protected Instruction _storeInstruction; // Instruction to load JVM variable 057 protected Expression _select; // Reference to variable expression 058 protected String select; // Textual repr. of variable expr. 059 060 // References to this variable (when local) 061 protected Vector _refs = new Vector(2); 062 063 // Dependencies to other variables/parameters (for globals only) 064 protected Vector _dependencies = null; 065 066 // Used to make sure parameter field is not added twice 067 protected boolean _ignore = false; 068 069 /** 070 * Disable this variable/parameter 071 */ 072 public void disable() { 073 _ignore = true; 074 } 075 076 /** 077 * Add a reference to this variable. Called by VariableRef when an 078 * expression contains a reference to this variable. 079 */ 080 public void addReference(VariableRefBase vref) { 081 _refs.addElement(vref); 082 } 083 084 /** 085 * Map this variable to a register 086 */ 087 public void mapRegister(MethodGenerator methodGen) { 088 if (_local == null) { 089 final String name = getEscapedName(); // TODO: namespace ? 090 final org.apache.bcel.generic.Type varType = _type.toJCType(); 091 _local = methodGen.addLocalVariable2(name, varType, null); 092 } 093 } 094 095 /** 096 * Remove the mapping of this variable to a register. 097 * Called when we leave the AST scope of the variable's declaration 098 */ 099 public void unmapRegister(MethodGenerator methodGen) { 100 if (_local != null) { 101 _local.setEnd(methodGen.getInstructionList().getEnd()); 102 methodGen.removeLocalVariable(_local); 103 _refs = null; 104 _local = null; 105 } 106 } 107 108 /** 109 * Returns an instruction for loading the value of this variable onto 110 * the JVM stack. 111 */ 112 public Instruction loadInstruction() { 113 final Instruction instr = _loadInstruction; 114 if (_loadInstruction == null) { 115 _loadInstruction = _type.LOAD(_local.getIndex()); 116 } 117 return _loadInstruction; 118 } 119 120 /** 121 * Returns an instruction for storing a value from the JVM stack 122 * into this variable. 123 */ 124 public Instruction storeInstruction() { 125 final Instruction instr = _storeInstruction; 126 if (_storeInstruction == null) { 127 _storeInstruction = _type.STORE(_local.getIndex()); 128 } 129 return _storeInstruction; 130 } 131 132 /** 133 * Returns the expression from this variable's select attribute (if any) 134 */ 135 public Expression getExpression() { 136 return(_select); 137 } 138 139 /** 140 * Display variable as single string 141 */ 142 public String toString() { 143 return("variable("+_name+")"); 144 } 145 146 /** 147 * Display variable in a full AST dump 148 */ 149 public void display(int indent) { 150 indent(indent); 151 System.out.println("Variable " + _name); 152 if (_select != null) { 153 indent(indent + IndentIncrement); 154 System.out.println("select " + _select.toString()); 155 } 156 displayContents(indent + IndentIncrement); 157 } 158 159 /** 160 * Returns the type of the variable 161 */ 162 public Type getType() { 163 return _type; 164 } 165 166 /** 167 * Returns the name of the variable or parameter as it will occur in the 168 * compiled translet. 169 */ 170 public QName getName() { 171 return _name; 172 } 173 174 /** 175 * Returns the escaped qname of the variable or parameter 176 */ 177 public String getEscapedName() { 178 return _escapedName; 179 } 180 181 /** 182 * Set the name of the variable or paremeter. Escape all special chars. 183 */ 184 public void setName(QName name) { 185 _name = name; 186 _escapedName = Util.escape(name.getStringRep()); 187 } 188 189 /** 190 * Returns the true if the variable is local 191 */ 192 public boolean isLocal() { 193 return _isLocal; 194 } 195 196 /** 197 * Parse the contents of the <xsl:decimal-format> element. 198 */ 199 public void parseContents(Parser parser) { 200 // Get the 'name attribute 201 String name = getAttribute("name"); 202 203 if (name.length() > 0) { 204 if (!XML11Char.isXML11ValidQName(name)) { 205 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this); 206 parser.reportError(Constants.ERROR, err); 207 } 208 setName(parser.getQNameIgnoreDefaultNs(name)); 209 } 210 else 211 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name"); 212 213 // Check whether variable/param of the same name is already in scope 214 VariableBase other = parser.lookupVariable(_name); 215 if ((other != null) && (other.getParent() == getParent())) { 216 reportError(this, parser, ErrorMsg.VARIABLE_REDEF_ERR, name); 217 } 218 219 select = getAttribute("select"); 220 if (select.length() > 0) { 221 _select = getParser().parseExpression(this, "select", null); 222 if (_select.isDummy()) { 223 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "select"); 224 return; 225 } 226 } 227 228 // Children must be parsed first -> static scoping 229 parseChildren(parser); 230 } 231 232 /** 233 * Compile the value of the variable, which is either in an expression in 234 * a 'select' attribute, or in the variable elements body 235 */ 236 public void translateValue(ClassGenerator classGen, 237 MethodGenerator methodGen) { 238 // Compile expression is 'select' attribute if present 239 if (_select != null) { 240 _select.translate(classGen, methodGen); 241 // Create a CachedNodeListIterator for select expressions 242 // in a variable or parameter. 243 if (_select.getType() instanceof NodeSetType) { 244 final ConstantPoolGen cpg = classGen.getConstantPool(); 245 final InstructionList il = methodGen.getInstructionList(); 246 247 final int initCNI = cpg.addMethodref(CACHED_NODE_LIST_ITERATOR_CLASS, 248 "<init>", 249 "(" 250 +NODE_ITERATOR_SIG 251 +")V"); 252 il.append(new NEW(cpg.addClass(CACHED_NODE_LIST_ITERATOR_CLASS))); 253 il.append(DUP_X1); 254 il.append(SWAP); 255 256 il.append(new INVOKESPECIAL(initCNI)); 257 } 258 _select.startIterator(classGen, methodGen); 259 } 260 // If not, compile result tree from parameter body if present. 261 else if (hasContents()) { 262 compileResultTree(classGen, methodGen); 263 } 264 // If neither are present then store empty string in variable 265 else { 266 final ConstantPoolGen cpg = classGen.getConstantPool(); 267 final InstructionList il = methodGen.getInstructionList(); 268 il.append(new PUSH(cpg, Constants.EMPTYSTRING)); 269 } 270 } 271 272 }