001/* PtRootNode is the root node of the parse tree. It is also the base 002 class for all Ptolemy II nodes as each node is a root node for the 003 tree below it. 004 005 Copyright (c) 1998-2015 The Regents of the University of California. 006 All rights reserved. 007 Permission is hereby granted, without written agreement and without 008 license or royalty fees, to use, copy, modify, and distribute this 009 software and its documentation for any purpose, provided that the above 010 copyright notice and the following two paragraphs appear in all copies 011 of this software. 012 013 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 014 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 015 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 016 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 017 SUCH DAMAGE. 018 019 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 020 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 021 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 022 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 023 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 024 ENHANCEMENTS, OR MODIFICATIONS. 025 026 PT_COPYRIGHT_VERSION_2 027 COPYRIGHTENDKEY 028 029 030 Created : May 1998 031 032 */ 033package ptolemy.data.expr; 034 035import java.util.ArrayList; 036import java.util.Iterator; 037import java.util.Map; 038 039import ptolemy.kernel.util.IllegalActionException; 040 041/////////////////////////////////////////////////////////////////// 042//// ASTPtRootNode 043 044/** 045 The parse tree created from the expression string consists of a 046 hierarchy of node objects, each of which is an instance of a class 047 derived from this class. This is because each node is a root node for 048 the portion of the parse tree below it. 049 <p> 050 Each node in the parse tree stores its type and state information 051 in a ptolemy.data.Token variable. A parent node uses the type and value of 052 the ptolemy.data.Tokens contained in its child nodes to evaluate the type 053 and value of the ptolemy.data.Token it should contain. 054 <P> 055 When a node has more than one child nodes, the lexical tokens relating 056 the child nodes are stored in the parent node. Thus if we parsed a string 057 such as "2+4-9", the child nodes would be leaf nodes containing 058 ptolemy.data.Token's with values 2, 4 and 9, and the parent node would 059 store the lexical tokens representing the "+" and the "-". 060 <p> 061 The tree is evaluated in a top down manner, calling evaluateParseTree() on the 062 children of each node before resolving the type of the current node. 063 064 @author Neil Smyth 065 @version $Id$ 066 @since Ptolemy II 0.2 067 @Pt.ProposedRating Yellow (nsmyth) 068 @Pt.AcceptedRating Red (cxh) 069 @see ptolemy.data.expr.PtParser 070 @see ptolemy.data.Token 071 */ 072public class ASTPtRootNode implements Node, Cloneable { 073 public ASTPtRootNode(int i) { 074 _id = i; 075 } 076 077 public ASTPtRootNode(PtParser p, int i) { 078 this(i); 079 } 080 081 /////////////////////////////////////////////////////////////////// 082 //// public methods //// 083 084 /** Clone the parse tree node by invoking the clone() method of 085 * the base class (java.lang.Object). 086 * @return A new parse tree node. 087 * @exception CloneNotSupportedException If the superclass clone() 088 * method throws it. 089 */ 090 @Override 091 public Object clone() throws CloneNotSupportedException { 092 ASTPtRootNode node = (ASTPtRootNode) super.clone(); 093 094 if (_children != null) { 095 node._children = new ArrayList(_children.size()); 096 097 // Deeply clone all the children. 098 for (Iterator i = _children.iterator(); i.hasNext();) { 099 ASTPtRootNode child = (ASTPtRootNode) i.next(); 100 ASTPtRootNode clone = (ASTPtRootNode) child.clone(); 101 node._children.add(clone); 102 clone._parent = node; 103 } 104 } 105 106 return node; 107 } 108 109 /** Override this method if you want to customize how the node dumps 110 * out its children. 111 * @param prefix The prefix, which is processed by 112 * {@link #toString(String)}. 113 */ 114 public void displayParseTree(String prefix) { 115 if (_ptToken != null) { 116 String str = toString(prefix) + ", Token type: "; 117 str = str + _ptToken.getClass().getName() + ", Value: "; 118 System.out.println(str + _ptToken.toString()); 119 } else { 120 System.out.println(toString(prefix) + " _ptToken is null"); 121 } 122 123 if (_children != null) { 124 for (int i = 0; i < _children.size(); ++i) { 125 ASTPtRootNode n = (ASTPtRootNode) _children.get(i); 126 127 if (n != null) { 128 n.displayParseTree(prefix + " "); 129 } 130 } 131 } 132 } 133 134 /** Evaluate the parse tree. 135 * @exception IllegalActionException If an error occurs 136 * trying to evaluate the PtToken type and/or value to be stored in 137 * node in the tree. 138 * @return The token contained by the root node for the parse tree. 139 * @deprecated Use a ParseTreeEvaluator instead. 140 */ 141 @Deprecated 142 public ptolemy.data.Token evaluateParseTree() 143 throws IllegalActionException { 144 ParseTreeEvaluator evaluator = new ParseTreeEvaluator(); 145 return evaluator.evaluateParseTree(this); 146 } 147 148 /** Return the evaluated token value of this node. This value may be 149 * set during parsing, if this represents a constant value, or may be 150 * set during parse tree evaluation. 151 * @return The evaluated token. 152 */ 153 public ptolemy.data.Token getToken() { 154 return _ptToken; 155 } 156 157 /** Return the type of this node. This value may be set during 158 * parsing, if this represents a constant value, or may be set 159 * during parse tree evaluation. 160 * @return The type of this node. 161 */ 162 public ptolemy.data.type.Type getType() { 163 return _ptType; 164 } 165 166 /** Return true if this node is (hierarchically) congruent to the 167 * given node, under the given renaming of bound identifiers. 168 * Derived classes should extend this method to add additional 169 * necessary congruency checks. 170 * @param node The node to compare to. 171 * @param renaming A map from String to String that gives a 172 * renaming from identifiers in this node to identifiers in the 173 * given node. 174 * @return True if the node is congruent. 175 */ 176 public boolean isCongruent(ASTPtRootNode node, Map renaming) { 177 // Check to see that they are the same kind of node. 178 if (node._id != _id) { 179 return false; 180 } 181 182 // Empty children are allowed 183 if (node._children == null && _children == null) { 184 return true; 185 } 186 187 // But both must be empty 188 if (node._children == null || _children == null) { 189 return false; 190 } 191 192 // Check that they have the same number of children. 193 if (node._children.size() != _children.size()) { 194 return false; 195 } 196 197 // Check that their children are congruent. 198 Iterator children = _children.iterator(); 199 Iterator nodeChildren = node._children.iterator(); 200 201 while (children.hasNext()) { 202 ASTPtRootNode child = (ASTPtRootNode) children.next(); 203 ASTPtRootNode nodeChild = (ASTPtRootNode) nodeChildren.next(); 204 205 if (!child.isCongruent(nodeChild, renaming)) { 206 return false; 207 } 208 } 209 210 return true; 211 } 212 213 /** Return true if this node represents a constant value. This will 214 * be set to true if the node is a constant leaf node (either it is a 215 * constant leaf node, or a pure function with constant children.) 216 * @return True if the node represents a constant value. 217 */ 218 public boolean isConstant() { 219 return _isConstant; 220 } 221 222 /** Return true if this node has had its token value set to something 223 * other than null. 224 * @return True if this node has had its token value set to something 225 * other than null. 226 */ 227 public boolean isEvaluated() { 228 return _ptToken != null; 229 } 230 231 @Override 232 public void jjtAddChild(Node n, int i) { 233 if (_children == null) { 234 _children = new ArrayList(); 235 } 236 237 if (i >= _children.size()) { 238 while (_children.size() <= i) { 239 _children.add(null); 240 } 241 } 242 243 _children.set(i, n); 244 } 245 246 @Override 247 public void jjtClose() { 248 if (_children != null) { 249 // Trim the list of children, to reduce memory usage. 250 _children.trimToSize(); 251 252 // Check to see if this node is constant, i.e. it has 253 // only constant children. 254 _isConstant = true; 255 256 for (int i = 0; i < _children.size(); ++i) { 257 ASTPtRootNode ch = (ASTPtRootNode) jjtGetChild(i); 258 259 if (!ch._isConstant) { 260 _isConstant = false; 261 break; 262 } 263 } 264 } 265 } 266 267 @Override 268 public Node jjtGetChild(int i) { 269 return (Node) _children.get(i); 270 } 271 272 @Override 273 public int jjtGetNumChildren() { 274 return _children == null ? 0 : _children.size(); 275 } 276 277 @Override 278 public Node jjtGetParent() { 279 return _parent; 280 } 281 282 @Override 283 public void jjtOpen() { 284 } 285 286 @Override 287 public void jjtSetParent(Node n) { 288 _parent = n; 289 } 290 291 /** Set whether this node is a constant. In almost all cases this 292 * is statically determined when the parse tree is first parsed, 293 * and this method is not normally called. However, it can be 294 * useful to transform a parse tree, which can make parts of the 295 * parse tree constant which were not before. This method is 296 * provided for those transformations. 297 * @param flag If true, then this node is a constant. 298 */ 299 public void setConstant(boolean flag) { 300 _isConstant = flag; 301 } 302 303 /** Set the value of this node. This may be set during parsing, 304 * if the node is a constant node, or during evaluation of the 305 * expression. 306 * @param token The value of this node. 307 */ 308 public void setToken(ptolemy.data.Token token) { 309 _ptToken = token; 310 } 311 312 /** Set the type of this node. This may be set during parsing, 313 * if the node is a constant node, or during evaluation of the 314 * expression. 315 * @param type The type of this node. 316 */ 317 public void setType(ptolemy.data.type.Type type) { 318 _ptType = type; 319 } 320 321 /** Return the string value of this node. 322 * You can override these two methods in subclasses of RootNode 323 * to customize the way the node appears when the tree is dumped. 324 * If your output uses more than one line you should override 325 * toString(String), otherwise overriding toString() is probably 326 * all you need to do. 327 * @return The string value of this node. 328 */ 329 @Override 330 public String toString() { 331 return PtParserTreeConstants.jjtNodeName[_id] + ":" + _isConstant + ":" 332 + _ptType + ":" + _ptToken; 333 } 334 335 /** Return the prefix, followed by the string value of this node. 336 * @param prefix The prefix 337 * @return The prefix followed by the string value of this node. 338 */ 339 public String toString(String prefix) { 340 return prefix + toString(); 341 } 342 343 /** Traverse this node with the given visitor. 344 * Subclasses should override this method to invoke the appropriate 345 * method in the visitor. 346 * @param visitor The visitor. 347 * @exception IllegalActionException Always thrown in this base 348 * class the visit() method is not implemented here. 349 */ 350 public void visit(ParseTreeVisitor visitor) throws IllegalActionException { 351 throw new IllegalActionException( 352 "The visit() method is not " + " implemented for nodes of type " 353 + getClass().getName() + "."); 354 } 355 356 /////////////////////////////////////////////////////////////////// 357 //// protected variables //// 358 359 /** The parent node. */ 360 protected Node _parent; 361 362 /** The children. */ 363 protected ArrayList _children; 364 365 /** The id. */ 366 protected int _id; 367 368 /** Each node stores its type and state information in this variable. 369 */ 370 protected ptolemy.data.Token _ptToken; 371 372 /** The type of this node. 373 */ 374 protected ptolemy.data.type.Type _ptType; 375 376 /** Flags whether the parse tree under this root evaluates to a constant. 377 */ 378 protected boolean _isConstant = false; 379}