1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: VariableBase.java,v 1.23 2004/02/24 02:57:28 zongaro Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import java.util.Vector;
  21. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  22. import com.sun.org.apache.bcel.internal.generic.Instruction;
  23. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  24. import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  25. import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  26. import com.sun.org.apache.bcel.internal.generic.NEW;
  27. import com.sun.org.apache.bcel.internal.generic.PUSH;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
  32. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  33. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  34. import com.sun.org.apache.xml.internal.utils.XMLChar;
  35. /**
  36. * @author Jacek Ambroziak
  37. * @author Santiago Pericas-Geertsen
  38. * @author Morten Jorgensen
  39. * @author Erwin Bolwidt <ejb@klomp.org>
  40. * @author John Howard <JohnH@schemasoft.com>
  41. */
  42. class VariableBase extends TopLevelElement {
  43. protected QName _name; // The name of the variable.
  44. protected String _escapedName; // The escaped qname of the variable.
  45. protected Type _type; // The type of this variable.
  46. protected boolean _isLocal; // True if the variable is local.
  47. protected LocalVariableGen _local; // Reference to JVM variable
  48. protected Instruction _loadInstruction; // Instruction to load JVM variable
  49. protected Instruction _storeInstruction; // Instruction to load JVM variable
  50. protected Expression _select; // Reference to variable expression
  51. protected String select; // Textual repr. of variable expr.
  52. // References to this variable (when local)
  53. protected Vector _refs = new Vector(2);
  54. // Dependencies to other variables/parameters (for globals only)
  55. protected Vector _dependencies = null;
  56. // Used to make sure parameter field is not added twice
  57. protected boolean _ignore = false;
  58. // Used to order top-level variables so that there are no forward references
  59. protected int _weight = 0;
  60. /**
  61. * Disable this variable/parameter
  62. */
  63. public void disable() {
  64. _ignore = true;
  65. }
  66. /**
  67. * Add a reference to this variable. Called by VariableRef when an
  68. * expression contains a reference to this variable.
  69. */
  70. public void addReference(VariableRefBase vref) {
  71. _refs.addElement(vref);
  72. }
  73. /**
  74. * Remove a reference to this variable. Called by VariableRef when this
  75. * variable goes out of scope.
  76. */
  77. public void removeReference(VariableRefBase vref) {
  78. _refs.remove(vref);
  79. }
  80. /**
  81. *
  82. */
  83. public void addDependency(VariableBase other) {
  84. if (_dependencies == null) {
  85. _dependencies = new Vector();
  86. }
  87. if (!_dependencies.contains(other)) {
  88. _dependencies.addElement(other);
  89. }
  90. }
  91. /**
  92. *
  93. */
  94. public Vector getDependencies() {
  95. return _dependencies;
  96. }
  97. /**
  98. * Map this variable to a register
  99. */
  100. public void mapRegister(MethodGenerator methodGen) {
  101. if (_local == null) {
  102. final InstructionList il = methodGen.getInstructionList();
  103. final String name = getEscapedName(); // TODO: namespace ?
  104. final com.sun.org.apache.bcel.internal.generic.Type varType = _type.toJCType();
  105. _local = methodGen.addLocalVariable2(name, varType, il.getEnd());
  106. }
  107. }
  108. /**
  109. * Remove the mapping of this variable to a register.
  110. * Called when we leave the AST scope of the variable's declaration
  111. */
  112. public void unmapRegister(MethodGenerator methodGen) {
  113. if (_refs.isEmpty() && (_local != null)) {
  114. _local.setEnd(methodGen.getInstructionList().getEnd());
  115. methodGen.removeLocalVariable(_local);
  116. _refs = null;
  117. _local = null;
  118. }
  119. }
  120. /**
  121. * Returns an instruction for loading the value of this variable onto
  122. * the JVM stack.
  123. */
  124. public Instruction loadInstruction() {
  125. final Instruction instr = _loadInstruction;
  126. if (_loadInstruction == null) {
  127. _loadInstruction = _type.LOAD(_local.getIndex());
  128. }
  129. return _loadInstruction;
  130. }
  131. /**
  132. * Returns an instruction for storing a value from the JVM stack
  133. * into this variable.
  134. */
  135. public Instruction storeInstruction() {
  136. final Instruction instr = _storeInstruction;
  137. if (_storeInstruction == null) {
  138. _storeInstruction = _type.STORE(_local.getIndex());
  139. }
  140. return _storeInstruction;
  141. }
  142. /**
  143. * Returns the expression from this variable's select attribute (if any)
  144. */
  145. public Expression getExpression() {
  146. return(_select);
  147. }
  148. /**
  149. * Display variable as single string
  150. */
  151. public String toString() {
  152. return("variable("+_name+")");
  153. }
  154. /**
  155. * Display variable in a full AST dump
  156. */
  157. public void display(int indent) {
  158. indent(indent);
  159. System.out.println("Variable " + _name);
  160. if (_select != null) {
  161. indent(indent + IndentIncrement);
  162. System.out.println("select " + _select.toString());
  163. }
  164. displayContents(indent + IndentIncrement);
  165. }
  166. /**
  167. * Returns the type of the variable
  168. */
  169. public Type getType() {
  170. return _type;
  171. }
  172. /**
  173. * Returns the name of the variable or parameter as it will occur in the
  174. * compiled translet.
  175. */
  176. public QName getName() {
  177. return _name;
  178. }
  179. /**
  180. * Returns the escaped qname of the variable or parameter
  181. */
  182. public String getEscapedName() {
  183. return _escapedName;
  184. }
  185. /**
  186. * Set the name of the variable or paremeter. Escape all special chars.
  187. */
  188. public void setName(QName name) {
  189. _name = name;
  190. _escapedName = Util.escape(name.getStringRep());
  191. }
  192. /**
  193. * Returns the true if the variable is local
  194. */
  195. public boolean isLocal() {
  196. return _isLocal;
  197. }
  198. /**
  199. * Parse the contents of the <xsl:decimal-format> element.
  200. */
  201. public void parseContents(Parser parser) {
  202. // Get the 'name attribute
  203. String name = getAttribute("name");
  204. if (name.length() > 0) {
  205. if (!XMLChar.isValidQName(name)) {
  206. ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
  207. parser.reportError(Constants.ERROR, err);
  208. }
  209. setName(parser.getQNameIgnoreDefaultNs(name));
  210. }
  211. else
  212. reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name");
  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. select = getAttribute("select");
  219. if (select.length() > 0) {
  220. _select = getParser().parseExpression(this, "select", null);
  221. if (_select.isDummy()) {
  222. reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "select");
  223. return;
  224. }
  225. }
  226. // Children must be parsed first -> static scoping
  227. parseChildren(parser);
  228. }
  229. /**
  230. * Compile the value of the variable, which is either in an expression in
  231. * a 'select' attribute, or in the variable elements body
  232. */
  233. public void translateValue(ClassGenerator classGen,
  234. MethodGenerator methodGen) {
  235. // Compile expression is 'select' attribute if present
  236. if (_select != null) {
  237. _select.translate(classGen, methodGen);
  238. // Create a CachedNodeListIterator for select expressions
  239. // in a variable or parameter.
  240. if (_select.getType() instanceof NodeSetType) {
  241. final ConstantPoolGen cpg = classGen.getConstantPool();
  242. final InstructionList il = methodGen.getInstructionList();
  243. final int initCNI = cpg.addMethodref(CACHED_NODE_LIST_ITERATOR_CLASS,
  244. "<init>",
  245. "("
  246. +NODE_ITERATOR_SIG
  247. +")V");
  248. il.append(new NEW(cpg.addClass(CACHED_NODE_LIST_ITERATOR_CLASS)));
  249. il.append(DUP_X1);
  250. il.append(SWAP);
  251. il.append(new INVOKESPECIAL(initCNI));
  252. }
  253. _select.startIterator(classGen, methodGen);
  254. }
  255. // If not, compile result tree from parameter body if present.
  256. else if (hasContents()) {
  257. compileResultTree(classGen, methodGen);
  258. }
  259. // If neither are present then store empty string in variable
  260. else {
  261. final ConstantPoolGen cpg = classGen.getConstantPool();
  262. final InstructionList il = methodGen.getInstructionList();
  263. il.append(new PUSH(cpg, Constants.EMPTYSTRING));
  264. }
  265. }
  266. }