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    }