001/* A token that contains a label/token pairs in a union. 002 003 Copyright (c) 2006-2014 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 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 028 */ 029package ptolemy.data; 030 031import ptolemy.data.expr.ASTPtRootNode; 032import ptolemy.data.expr.ParseTreeEvaluator; 033import ptolemy.data.expr.PtParser; 034import ptolemy.data.type.Type; 035import ptolemy.data.type.UnionType; 036import ptolemy.kernel.util.IllegalActionException; 037 038/////////////////////////////////////////////////////////////////// 039//// UnionToken 040 041/** 042 A token that contains a label/token pairs. This pair is one of the 043 choices in a union type, but the exact type is not stored in this 044 class. Operations on union tokens may require that they have the 045 same field in among the possible choices. 046 047 @author Yuhong Xiong, Steve Neuendorffer, Elaine Cheong, Edward Lee 048 @version $Id$ 049 @since Ptolemy II 5.2 050 @Pt.ProposedRating Red (yuhong) 051 @Pt.AcceptedRating Red (cxh) 052 */ 053public class UnionToken extends AbstractNotConvertibleToken { 054 /** Construct a UnionToken with the specified label and value. 055 * @param label The label. 056 * @param value The value of this token. 057 * @exception IllegalActionException If the label or the value is null. 058 */ 059 public UnionToken(String label, Token value) throws IllegalActionException { 060 if (label == null || value == null) { 061 throw new IllegalActionException( 062 "UnionToken: The label or the " + "value is null."); 063 } 064 065 _label = label; 066 _value = value; 067 } 068 069 /** Construct a UnionToken from the specified string. 070 * @param init A string expression of a record. 071 * @exception IllegalActionException If the string does not 072 * contain a parsable record. 073 */ 074 public UnionToken(String init) throws IllegalActionException { 075 PtParser parser = new PtParser(); 076 ASTPtRootNode tree = parser.generateParseTree(init); 077 078 ParseTreeEvaluator evaluator = new ParseTreeEvaluator(); 079 Token token = evaluator.evaluateParseTree(tree); 080 081 if (token instanceof UnionToken) { 082 UnionToken unionToken = (UnionToken) token; 083 _label = unionToken.label(); 084 _value = unionToken.value(); 085 086 if (_label == null || _value == null) { 087 throw new IllegalActionException( 088 "UnionToken: The label " + "or the value is null."); 089 } 090 } else { 091 throw new IllegalActionException("An union token cannot be" 092 + " created from the expression '" + init + "'"); 093 } 094 } 095 096 /////////////////////////////////////////////////////////////////// 097 //// public methods //// 098 099 /** Return true if the argument is an UnionToken with the same 100 * label and value. 101 * @param object An instance of Object. 102 * @return True if the argument is equal to this token. 103 * @see #hashCode() 104 */ 105 @Override 106 public boolean equals(Object object) { 107 if (object == null) { 108 return false; 109 } 110 // This test rules out instances of a subclass. 111 if (object.getClass() != getClass()) { 112 return false; 113 } 114 115 UnionToken unionToken = (UnionToken) object; 116 117 return _label.equals(unionToken.label()) 118 && _value.equals(unionToken.value()); 119 } 120 121 /** Return the type of this token. 122 * @return An instance of UnionType containing one field. The label 123 * of that field is the label of this token, and the type of that 124 * field is the type of the value of this token. 125 */ 126 @Override 127 public Type getType() { 128 String[] labels = new String[1]; 129 labels[0] = _label; 130 131 Type[] types = new Type[1]; 132 types[0] = _value.getType(); 133 return new UnionType(labels, types); 134 } 135 136 /** Return a hash code value for this token. This method returns the 137 * hash codes of the value token. 138 * @return A hash code value for this token. 139 */ 140 @Override 141 public int hashCode() { 142 return _value.hashCode(); 143 } 144 145 /** Return the label of this token. 146 * @return The label of this token. 147 */ 148 public String label() { 149 return _label; 150 } 151 152 /** Returns a new UnionToken representing the multiplicative identity. 153 * The returned token has the same label as this one, and contains 154 * the multiplicative identity of the value of this token. 155 * @return A UnionToken. 156 * @exception IllegalActionException If multiplicative identity is not 157 * supported by any value token. 158 */ 159 @Override 160 public Token one() throws IllegalActionException { 161 return new UnionToken(_label, _value.one()); 162 } 163 164 /** Return the value of this token as a string. 165 * The syntax is <code>{|<i>label</i> = <i>value</i>|}</code> 166 * @return A String beginning with "{|" that contains a label and value 167 * pair, ending with "|}". 168 */ 169 @Override 170 public String toString() { 171 return "{|" + _label + " = " + _value.toString() + "|}"; 172 } 173 174 /** Return the value of this token. 175 * @return The value of this token. 176 */ 177 public Token value() { 178 return _value; 179 } 180 181 /** Returns a new UnionToken representing the additive identity. 182 * The returned token has the same label as this one, and 183 * contains the additive identity of the value token. 184 * @return A UnionToken. 185 * @exception IllegalActionException If additive identity is not 186 * supported by any value token. 187 */ 188 @Override 189 public Token zero() throws IllegalActionException { 190 return new UnionToken(_label, _value.zero()); 191 } 192 193 /////////////////////////////////////////////////////////////////// 194 //// protected methods //// 195 196 /** Return a new token whose value is the sum of this token and 197 * the argument. It is assumed that the class of the argument 198 * is UnionToken. 199 * @param rightArgument The token to add to this token. 200 * @return A new UnionToken. 201 * @exception IllegalActionException If the label of the argument 202 * and this token are different, or calling the add method on 203 * the value token throws it. 204 */ 205 @Override 206 protected Token _add(Token rightArgument) throws IllegalActionException { 207 UnionToken unionToken = (UnionToken) rightArgument; 208 209 if (!_label.equals(unionToken.label())) { 210 throw new IllegalActionException("UnionToken._add: The label " 211 + "of the argument token (" + unionToken.label() 212 + ") is different from that of this token (" + _label 213 + "."); 214 } 215 216 Token value = _value.add(unionToken.value()); 217 return new UnionToken(_label, value); 218 } 219 220 /** Return a new token whose value is the division of 221 * this token and the argument. It is assumed that the class of 222 * the argument is UnionToken. 223 * @param rightArgument The token to divide this token by. 224 * @return A new UnionToken. 225 * @exception IllegalActionException If the label of the argument 226 * and this token are different, or calling the divide method on 227 * the value token throws it. 228 */ 229 @Override 230 protected Token _divide(Token rightArgument) throws IllegalActionException { 231 UnionToken unionToken = (UnionToken) rightArgument; 232 233 if (!_label.equals(unionToken.label())) { 234 throw new IllegalActionException("UnionToken._divide: The label " 235 + "of the argument token (" + unionToken.label() 236 + ") is different from that of this token (" + _label 237 + "."); 238 } 239 240 Token value = _value.divide(unionToken.value()); 241 return new UnionToken(_label, value); 242 } 243 244 /** Test whether the value of this token is close to the first 245 * argument, where "close" means that the distance between them 246 * is less than or equal to the second argument. This method 247 * only makes sense for tokens where the distance between them is 248 * reasonably represented as a double. It is assumed that the 249 * argument is an UnionToken, and the isCloseTo() method of the 250 * fields is used. If the fields do not match, then the 251 * return value is false. 252 * @param rightArgument The token to compare to this token. 253 * @param epsilon The value that we use to determine whether two 254 * tokens are close. 255 * @return A token containing true if the value of the first 256 * argument is close to the value of this token. 257 * @exception IllegalActionException If thrown by calling isCloseTo() 258 * on the value of this Token. 259 */ 260 @Override 261 protected BooleanToken _isCloseTo(Token rightArgument, double epsilon) 262 throws IllegalActionException { 263 UnionToken unionToken = (UnionToken) rightArgument; 264 265 if (!_label.equals(unionToken.label())) { 266 return new BooleanToken(false); 267 } 268 269 return _value.isCloseTo(unionToken.value(), epsilon); 270 } 271 272 /** Return true if the specified token is equal to this one. 273 * Equal means that both tokens have the same label with the 274 * same value. This method is different from equals() in that 275 * _isEqualTo() looks for equalities of values irrespective of 276 * their types. It is assumed that the type of the argument is 277 * UnionToken. 278 * @param rightArgument The token to compare to this token. 279 * @exception IllegalActionException If this method is not 280 * supported by the derived class. 281 * @return True if the argument is equal to this. 282 */ 283 @Override 284 protected BooleanToken _isEqualTo(Token rightArgument) 285 throws IllegalActionException { 286 UnionToken unionToken = (UnionToken) rightArgument; 287 288 if (!_label.equals(unionToken.label())) { 289 return new BooleanToken(false); 290 } 291 292 return _value.isEqualTo(unionToken.value()); 293 } 294 295 /** Return a new token whose value is the modulo of this token and 296 * the argument. It is assumed that the class of the argument is 297 * UnionToken. 298 * @param rightArgument The token to modulo this token by. 299 * @return A new UnionToken. 300 * @exception IllegalActionException If the label of the argument 301 * and this token are different, or calling the modulo method on 302 * the value token throws it. 303 */ 304 @Override 305 protected Token _modulo(Token rightArgument) throws IllegalActionException { 306 UnionToken unionToken = (UnionToken) rightArgument; 307 308 if (!_label.equals(unionToken.label())) { 309 throw new IllegalActionException("UnionToken._modulo: The label " 310 + "of the argument token (" + unionToken.label() 311 + ") is different from that of this token (" + _label 312 + "."); 313 } 314 315 Token value = _value.modulo(unionToken.value()); 316 return new UnionToken(_label, value); 317 } 318 319 /** Return a new token whose value is the multiplication of this token 320 * and the argument. It is assumed that the class of the argument is 321 * UnionToken. 322 * @param rightArgument The token to multiply this token by. 323 * @return A new UnionToken. 324 * @exception IllegalActionException If the label of the argument 325 * and this token are different, or calling the multiply method on 326 * the value token throws it. 327 */ 328 @Override 329 protected Token _multiply(Token rightArgument) 330 throws IllegalActionException { 331 UnionToken unionToken = (UnionToken) rightArgument; 332 333 if (!_label.equals(unionToken.label())) { 334 throw new IllegalActionException("UnionToken._multiply: The label " 335 + "of the argument token (" + unionToken.label() 336 + ") is different from that of this token (" + _label 337 + "."); 338 } 339 340 Token value = _value.multiply(unionToken.value()); 341 return new UnionToken(_label, value); 342 } 343 344 /** Return a new token whose value is the subtraction of this token 345 * and the argument. It is assumed that the class of the argument 346 * is UnionToken. 347 * @param rightArgument The token to subtract from this token. 348 * @return A new UnionToken. 349 * @exception IllegalActionException If the label of the argument 350 * and this token are different, or calling the subtract method on 351 * the value token throws it. 352 */ 353 @Override 354 protected Token _subtract(Token rightArgument) 355 throws IllegalActionException { 356 UnionToken unionToken = (UnionToken) rightArgument; 357 358 if (!_label.equals(unionToken.label())) { 359 throw new IllegalActionException("UnionToken._subtract: The label " 360 + "of the argument token (" + unionToken.label() 361 + ") is different from that of this token (" + _label 362 + "."); 363 } 364 365 Token value = _value.subtract(unionToken.value()); 366 return new UnionToken(_label, value); 367 } 368 369 /////////////////////////////////////////////////////////////////// 370 //// private variables //// 371 private String _label; 372 373 private Token _value; 374}