001/* A visitor for parse trees of the expression language that collects the set of free variables.
002
003 Copyright (c) 2006-2016 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024
025 */
026package ptolemy.data.expr;
027
028import java.util.Collection;
029import java.util.HashSet;
030import java.util.Iterator;
031import java.util.Set;
032
033import ptolemy.kernel.util.IllegalActionException;
034
035///////////////////////////////////////////////////////////////////
036//// ParseTreeFreeVariableRenamer
037
038/**
039 This class visits parse trees and renames the free variables
040 that match a specified variable. Use this class prior to changing
041 the name of a variable to update references to the variable.
042
043 @author Edward A. Lee
044 @version $Id$
045 @since Ptolemy II 5.2
046 @Pt.ProposedRating Yellow (eal)
047 @Pt.AcceptedRating Red (cxh)
048 @see ptolemy.data.expr.ASTPtRootNode
049 */
050public class ParseTreeFreeVariableRenamer extends AbstractParseTreeVisitor {
051    ///////////////////////////////////////////////////////////////////
052    ////                         public methods                    ////
053
054    /** Rename the variables, if any, in the dependentVariable
055     *  that refer to the specified variableToRename.
056     *  @param node The root node of the parse tree.
057     *  @param dependentVariable The dependent variable.
058     *  @param variableToRename The variable to rename.
059     *  @param name The new name.
060     *  @exception IllegalActionException If thrown while visiting the
061     *  node.
062     */
063    public void renameVariables(ASTPtRootNode node, Variable dependentVariable,
064            Variable variableToRename, String name)
065            throws IllegalActionException {
066        _scope = dependentVariable.getParserScope();
067        _dependentVariable = dependentVariable;
068        _variableToRename = variableToRename;
069        // If the variable containing a reference to the variable to be
070        // renamed is in string mode, prepend a $ to the name.
071        if (_dependentVariable.isStringMode()
072                && !_dependentVariable.isSuppressVariableSubstitution()) {
073            _name = "$" + name;
074        } else {
075            _name = name;
076        }
077        node.visit(this);
078        _scope = null;
079        _variableToRename = null;
080        _name = null;
081    }
082
083    @Override
084    public void visitArrayConstructNode(ASTPtArrayConstructNode node)
085            throws IllegalActionException {
086        _visitAllChildren(node);
087    }
088
089    @Override
090    public void visitBitwiseNode(ASTPtBitwiseNode node)
091            throws IllegalActionException {
092        _visitAllChildren(node);
093    }
094
095    @Override
096    public void visitFunctionApplicationNode(ASTPtFunctionApplicationNode node)
097            throws IllegalActionException {
098        _visitAllChildren(node);
099    }
100
101    @Override
102    public void visitFunctionDefinitionNode(ASTPtFunctionDefinitionNode node)
103            throws IllegalActionException {
104        Collection arguments = node.getArgumentNameList();
105        // Make sure that parameters that are already formal
106        // formal parameters remain so after.
107        Collection alreadyFormal = _intersection(_formalParameters, arguments);
108        _formalParameters.addAll(arguments);
109        node.getExpressionTree().visit(this);
110        _formalParameters.removeAll(arguments);
111        _formalParameters.addAll(alreadyFormal);
112    }
113
114    @Override
115    public void visitFunctionalIfNode(ASTPtFunctionalIfNode node)
116            throws IllegalActionException {
117        _visitAllChildren(node);
118    }
119
120    @Override
121    public void visitLeafNode(ASTPtLeafNode node)
122            throws IllegalActionException {
123        if (node.isConstant() && node.isEvaluated()) {
124            return;
125        }
126        String name = node.getName();
127        if (name != null && !_formalParameters.contains(name)
128                && ModelScope.getScopedVariable(null, _dependentVariable,
129                        name) == _variableToRename) {
130            node._name = _name;
131        }
132    }
133
134    @Override
135    public void visitLogicalNode(ASTPtLogicalNode node)
136            throws IllegalActionException {
137        _visitAllChildren(node);
138    }
139
140    @Override
141    public void visitMatrixConstructNode(ASTPtMatrixConstructNode node)
142            throws IllegalActionException {
143        _visitAllChildren(node);
144    }
145
146    @Override
147    public void visitMethodCallNode(ASTPtMethodCallNode node)
148            throws IllegalActionException {
149        _visitAllChildren(node);
150    }
151
152    @Override
153    public void visitPowerNode(ASTPtPowerNode node)
154            throws IllegalActionException {
155        _visitAllChildren(node);
156    }
157
158    @Override
159    public void visitProductNode(ASTPtProductNode node)
160            throws IllegalActionException {
161        _visitAllChildren(node);
162    }
163
164    @Override
165    public void visitRecordConstructNode(ASTPtRecordConstructNode node)
166            throws IllegalActionException {
167        _visitAllChildren(node);
168    }
169
170    @Override
171    public void visitRelationalNode(ASTPtRelationalNode node)
172            throws IllegalActionException {
173        _visitAllChildren(node);
174    }
175
176    @Override
177    public void visitShiftNode(ASTPtShiftNode node)
178            throws IllegalActionException {
179        _visitAllChildren(node);
180    }
181
182    @Override
183    public void visitSumNode(ASTPtSumNode node) throws IllegalActionException {
184        _visitAllChildren(node);
185    }
186
187    @Override
188    public void visitUnaryNode(ASTPtUnaryNode node)
189            throws IllegalActionException {
190        _visitAllChildren(node);
191    }
192
193    ///////////////////////////////////////////////////////////////////
194    ////                         protected methods                 ////
195
196    /** Return the intersection of two collections.
197     *  @param collection1 The first collection.
198     *  @param collection2 The second collection.
199     *  @return The intersection of two collections.
200     */
201    protected Collection _intersection(Collection collection1,
202            Collection collection2) {
203        Set result = new HashSet();
204        Iterator items = collection1.iterator();
205        while (items.hasNext()) {
206            Object item = items.next();
207            if (collection2.contains(item)) {
208                result.add(items);
209            }
210        }
211        return result;
212    }
213
214    /** Loop through all of the children of this node,
215     *  visiting each one of them, which will cause their token
216     *  value to be determined.
217     */
218    @Override
219    protected void _visitAllChildren(ASTPtRootNode node)
220            throws IllegalActionException {
221        int numChildren = node.jjtGetNumChildren();
222
223        for (int i = 0; i < numChildren; i++) {
224            _visitChild(node, i);
225        }
226    }
227
228    /** Visit the child with the given index of the given node.
229     *  This is usually called while visiting the given node.
230     */
231    @Override
232    protected void _visitChild(ASTPtRootNode node, int i)
233            throws IllegalActionException {
234        ASTPtRootNode child = (ASTPtRootNode) node.jjtGetChild(i);
235        child.visit(this);
236    }
237
238    ///////////////////////////////////////////////////////////////////
239    ////                         protected variables               ////
240
241    /** The variable to which the parse tree belongs. */
242    protected Variable _dependentVariable;
243
244    /** Formal parameters within a function definition. */
245    protected Set _formalParameters = new HashSet();
246
247    /** The new name. */
248    protected String _name;
249
250    /** The scope. */
251    protected ParserScope _scope;
252
253    /** The variable to be renamed. */
254    protected Variable _variableToRename;
255}