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}