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: VariableRefBase.java 476471 2006-11-18 08:36:27Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import org.apache.xalan.xsltc.compiler.util.Type;
025 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
026
027 /**
028 * @author Morten Jorgensen
029 * @author Santiago Pericas-Geertsen
030 */
031 class VariableRefBase extends Expression {
032
033 /**
034 * A reference to the associated variable.
035 */
036 protected VariableBase _variable;
037
038 /**
039 * A reference to the enclosing expression/instruction for which a
040 * closure is needed (Predicate, Number or Sort).
041 */
042 protected Closure _closure = null;
043
044 public VariableRefBase(VariableBase variable) {
045 _variable = variable;
046 variable.addReference(this);
047 }
048
049 public VariableRefBase() {
050 _variable = null;
051 }
052
053 /**
054 * Returns a reference to the associated variable
055 */
056 public VariableBase getVariable() {
057 return _variable;
058 }
059
060 /**
061 * If this variable reference is in a top-level element like
062 * another variable, param or key, add a dependency between
063 * that top-level element and the referenced variable. For
064 * example,
065 *
066 * <xsl:variable name="x" .../>
067 * <xsl:variable name="y" select="$x + 1"/>
068 *
069 * and assuming this class represents "$x", add a reference
070 * between variable y and variable x.
071 */
072 public void addParentDependency() {
073 SyntaxTreeNode node = this;
074 while (node != null && node instanceof TopLevelElement == false) {
075 node = node.getParent();
076 }
077
078 TopLevelElement parent = (TopLevelElement) node;
079 if (parent != null) {
080 VariableBase var = _variable;
081 if (_variable._ignore) {
082 if (_variable instanceof Variable) {
083 var = parent.getSymbolTable()
084 .lookupVariable(_variable._name);
085 } else if (_variable instanceof Param) {
086 var = parent.getSymbolTable().lookupParam(_variable._name);
087 }
088 }
089
090 parent.addDependency(var);
091 }
092 }
093
094 /**
095 * Two variable references are deemed equal if they refer to the
096 * same variable.
097 */
098 public boolean equals(Object obj) {
099 try {
100 return (_variable == ((VariableRefBase) obj)._variable);
101 }
102 catch (ClassCastException e) {
103 return false;
104 }
105 }
106
107 /**
108 * Returns a string representation of this variable reference on the
109 * format 'variable-ref(<var-name>)'.
110 * @return Variable reference description
111 */
112 public String toString() {
113 return "variable-ref("+_variable.getName()+'/'+_variable.getType()+')';
114 }
115
116 public Type typeCheck(SymbolTable stable)
117 throws TypeCheckError
118 {
119 // Returned cached type if available
120 if (_type != null) return _type;
121
122 // Find nearest closure to add a variable reference
123 if (_variable.isLocal()) {
124 SyntaxTreeNode node = getParent();
125 do {
126 if (node instanceof Closure) {
127 _closure = (Closure) node;
128 break;
129 }
130 if (node instanceof TopLevelElement) {
131 break; // way up in the tree
132 }
133 node = node.getParent();
134 } while (node != null);
135
136 if (_closure != null) {
137 _closure.addVariable(this);
138 }
139 }
140
141 // Attempt to get the cached variable type
142 _type = _variable.getType();
143
144 // If that does not work we must force a type-check (this is normally
145 // only needed for globals in included/imported stylesheets
146 if (_type == null) {
147 _variable.typeCheck(stable);
148 _type = _variable.getType();
149 }
150
151 // If in a top-level element, create dependency to the referenced var
152 addParentDependency();
153
154 // Return the type of the referenced variable
155 return _type;
156 }
157
158 }