View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: VariableRefBase.java,v 1.5 2005/09/28 13:48:18 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
27  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
28  import java.util.Objects;
29  
30  /**
31   * @author Morten Jorgensen
32   * @author Santiago Pericas-Geertsen
33   */
34  class VariableRefBase extends Expression {
35  
36      /**
37       * A reference to the associated variable.
38       */
39      protected VariableBase _variable;
40  
41      /**
42       * A reference to the enclosing expression/instruction for which a
43       * closure is needed (Predicate, Number or Sort).
44       */
45      protected Closure _closure = null;
46  
47      public VariableRefBase(VariableBase variable) {
48          _variable = variable;
49          variable.addReference(this);
50      }
51  
52      public VariableRefBase() {
53          _variable = null;
54      }
55  
56      /**
57       * Returns a reference to the associated variable
58       */
59      public VariableBase getVariable() {
60          return _variable;
61      }
62  
63      /**
64       * If this variable reference is in a top-level element like
65       * another variable, param or key, add a dependency between
66       * that top-level element and the referenced variable. For
67       * example,
68       *
69       *   <xsl:variable name="x" .../>
70       *   <xsl:variable name="y" select="$x + 1"/>
71       *
72       * and assuming this class represents "$x", add a reference
73       * between variable y and variable x.
74       */
75      public void addParentDependency() {
76          SyntaxTreeNode node = this;
77          while (node != null && node instanceof TopLevelElement == false) {
78              node = node.getParent();
79          }
80  
81          TopLevelElement parent = (TopLevelElement) node;
82          if (parent != null) {
83              VariableBase var = _variable;
84              if (_variable._ignore) {
85                  if (_variable instanceof Variable) {
86                      var = parent.getSymbolTable()
87                                  .lookupVariable(_variable._name);
88                  } else if (_variable instanceof Param) {
89                      var = parent.getSymbolTable().lookupParam(_variable._name);
90                  }
91              }
92  
93              parent.addDependency(var);
94          }
95      }
96  
97      /**
98       * Two variable references are deemed equal if they refer to the
99       * same variable.
100      */
101     @Override
102     public boolean equals(Object obj) {
103         return obj == this || (obj instanceof VariableRefBase)
104             && (_variable == ((VariableRefBase) obj)._variable);
105     }
106 
107     @Override
108     public int hashCode() {
109         return Objects.hashCode(this._variable);
110     }
111 
112     /**
113      * Returns a string representation of this variable reference on the
114      * format 'variable-ref(<var-name>)'.
115      * @return Variable reference description
116      */
117     @Override
118     public String toString() {
119         return "variable-ref("+_variable.getName()+'/'+_variable.getType()+')';
120     }
121 
122     @Override
123     public Type typeCheck(SymbolTable stable)
124         throws TypeCheckError
125     {
126         // Returned cached type if available
127         if (_type != null) return _type;
128 
129         // Find nearest closure to add a variable reference
130         if (_variable.isLocal()) {
131             SyntaxTreeNode node = getParent();
132             do {
133                 if (node instanceof Closure) {
134                     _closure = (Closure) node;
135                     break;
136                 }
137                 if (node instanceof TopLevelElement) {
138                     break;      // way up in the tree
139                 }
140                 node = node.getParent();
141             } while (node != null);
142 
143             if (_closure != null) {
144                 _closure.addVariable(this);
145             }
146         }
147 
148         // Attempt to get the cached variable type
149         _type = _variable.getType();
150 
151         // If that does not work we must force a type-check (this is normally
152         // only needed for globals in included/imported stylesheets
153         if (_type == null) {
154             _variable.typeCheck(stable);
155             _type = _variable.getType();
156         }
157 
158         // If in a top-level element, create dependency to the referenced var
159         addParentDependency();
160 
161         // Return the type of the referenced variable
162         return _type;
163     }
164 
165 }