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