001/** A class representing the type of an ArrayToken. 002 003 Copyright (c) 1997-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 */ 028package ptolemy.data.type; 029 030import ptolemy.data.ArrayToken; 031import ptolemy.data.Token; 032import ptolemy.graph.InequalityTerm; 033import ptolemy.kernel.util.IllegalActionException; 034import ptolemy.kernel.util.InternalErrorException; 035 036/** 037 038 A class representing the type of an ArrayToken. 039 040 @author Steve Neuendorffer, Yuhong Xiong 041 @version $Id$ 042 @since Ptolemy II 4.0 043 @Pt.ProposedRating Red (cxh) 044 @Pt.AcceptedRating Red (cxh) 045 */ 046public class ArrayType extends StructuredType implements Cloneable { 047 /** Construct a new ArrayType with the specified type for the array 048 * elements. To leave the element type undeclared, use BaseType.UNKNOWN. 049 * @param elementType The type of the array elements. 050 * @exception IllegalArgumentException If the argument is null. 051 */ 052 public ArrayType(Type elementType) { 053 if (elementType == null) { 054 throw new IllegalArgumentException( 055 "Cannot create ArrayType " + " with null elementType"); 056 } 057 058 try { 059 _declaredElementType = (Type) elementType.clone(); 060 } catch (CloneNotSupportedException cnse) { 061 throw new InternalErrorException( 062 "The specified type " + elementType + " cannot be cloned."); 063 } 064 065 _elementType = _declaredElementType; 066 _length = -1; 067 } 068 069 /** Construct a new ArrayType with the specified type for the array 070 * elements. To leave the element type undeclared, use BaseType.UNKNOWN. 071 * @param elementType The type of the array elements. 072 * @param length Then length of the array. 073 * @exception IllegalArgumentException If the argument is null. 074 */ 075 public ArrayType(Type elementType, int length) { 076 this(elementType); 077 if (length < 0) { 078 throw new IllegalArgumentException( 079 "Cannot create ArrayType " + "with negative length."); 080 } 081 _length = length; 082 } 083 084 /////////////////////////////////////////////////////////////////// 085 //// public methods //// 086 087 /** Return a type constraint that can be used to constrain 088 * another typeable object to have a type related to an 089 * array whose element type is the type of the specified 090 * typeable. A typical usage of this is as follows: 091 * <pre> 092 * output.setTypeAtLeast(ArrayType.arrayOf(input)); 093 * </pre> 094 * where input and output are ports (this is the type 095 * constraint of SequenceToArray, for example). 096 * @param typeable A typeable. 097 * @return An InequalityTerm that can be passed to methods 098 * like setTypeAtLeast() of the Typeable interface. 099 * @exception IllegalActionException If the specified typeable 100 * cannot be set to an array type. 101 */ 102 public static InequalityTerm arrayOf(Typeable typeable) 103 throws IllegalActionException { 104 return new TypeableArrayTypeTerm(typeable); 105 } 106 107 /** Return a type constraint that can be used to constrain 108 * another typeable object to have a type related to an 109 * array whose element type is the type of the specified 110 * typeable. A typical usage of this is as follows: 111 * <pre> 112 * output.setTypeAtLeast(ArrayType.arrayOf(input, length)); 113 * </pre> 114 * where input and output are ports (this is the type 115 * constraint of SequenceToArray, for example). 116 * @param typeable A typeable. 117 * @param length The length of array. 118 * @return An InequalityTerm that can be passed to methods 119 * like setTypeAtLeast() of the Typeable interface. 120 * @exception IllegalActionException If the specified typeable 121 * cannot be set to an array type. 122 */ 123 public static InequalityTerm arrayOf(Typeable typeable, int length) 124 throws IllegalActionException { 125 return new TypeableSizedArrayTypeTerm(typeable, length); 126 } 127 128 /** Return a deep copy of this ArrayType if it is a variable, or 129 * itself if it is a constant. 130 * @return An ArrayType. 131 */ 132 @Override 133 public Object clone() { 134 ArrayType newObj = new ArrayType(_declaredElementType); 135 newObj._length = _length; 136 137 try { 138 newObj.updateType(this); 139 } catch (IllegalActionException ex) { 140 throw new InternalErrorException("ArrayType.clone: " 141 + "Cannot update new instance. " + ex.getMessage()); 142 } 143 return newObj; 144 } 145 146 /** Convert the argument token into an ArrayToken having this 147 * type, if lossless conversion can be done. If the argument 148 * is not an ArrayToken, then the result is an array token with 149 * one entry, the argument. 150 * @param token A token. 151 * @return An ArrayToken. 152 * @exception IllegalActionException If lossless conversion 153 * cannot be done. 154 */ 155 @Override 156 public Token convert(Token token) throws IllegalActionException { 157 Type myElementType = getElementType(); 158 // Cannot convert to unknown element type. 159 if (myElementType.equals(BaseType.UNKNOWN)) { 160 if (token instanceof ArrayToken) { 161 // Following the logic implemented in BaseType for UNKNOWN, 162 // since every array token is a substitution instance for 163 // {unknown}, just return the token. 164 return token; 165 } 166 // If it's not an ArrayToken, then something is wrong. 167 throw new IllegalActionException( 168 "Cannot convert " + token + " to type {unknown}"); 169 } 170 if (!(token instanceof ArrayToken)) { 171 if (hasKnownLength() && length() != 1) { 172 throw new IllegalActionException(null, 173 Token.notSupportedConversionMessage(token, toString())); 174 } 175 // NOTE: Added 7/17/06 by EAL to support type -> {type} conversion. 176 Token[] contents = new Token[1]; 177 contents[0] = token; 178 return new ArrayToken(myElementType, contents); 179 } 180 181 ArrayToken argumentArrayToken = (ArrayToken) token; 182 if (hasKnownLength() && argumentArrayToken.length() != length()) { 183 throw new IllegalActionException(null, 184 Token.notSupportedConversionMessage(token, toString())); 185 } 186 187 if (myElementType.equals(argumentArrayToken.getElementType())) { 188 return token; 189 } 190 191 Token[] argumentArray = argumentArrayToken.arrayValue(); 192 Token[] resultArray = new Token[argumentArray.length]; 193 194 try { 195 for (int i = 0; i < argumentArray.length; i++) { 196 resultArray[i] = myElementType.convert(argumentArray[i]); 197 } 198 } catch (IllegalActionException ex) { 199 throw new IllegalActionException(null, ex, 200 Token.notSupportedConversionMessage(token, "int")); 201 } 202 203 if (resultArray.length < 1) { 204 // Support your local zero length array. 205 // actor/lib/test/auto/NilTokenTypeTest.xml requires this. 206 Type argumentArrayElementType = argumentArrayToken.getElementType(); 207 try { 208 return new ArrayToken(argumentArrayElementType); 209 } catch (Exception ex) { 210 throw new IllegalActionException(null, ex, 211 "Failed to construct an array of type " 212 + argumentArrayElementType); 213 } 214 } 215 return new ArrayToken(myElementType, resultArray); 216 } 217 218 /** Return the depth of an array type. The depth of an 219 * array type is the number of times it 220 * contains other structured types. For example, an array 221 * of arrays has depth 2, and an array of arrays of records 222 * has depth 3. 223 * @return the depth of a structured type. 224 */ 225 @Override 226 public int depth() { 227 int depth = 1; 228 if (_elementType instanceof StructuredType) { 229 depth += ((StructuredType) _elementType).depth(); 230 } 231 return depth; 232 } 233 234 /** Determine if the argument represents the same ArrayType as this 235 * object. 236 * @param object Another object. 237 * @return True if the argument represents the same ArrayType as 238 * this object; false otherwise. 239 */ 240 @Override 241 public boolean equals(Object object) { 242 if (!(object instanceof ArrayType)) { 243 return false; 244 } 245 246 ArrayType argumentType = (ArrayType) object; 247 return _elementType.equals(argumentType.getElementType()) 248 && _length == argumentType._length; 249 } 250 251 /** Return a type constraint that can be used to constrain 252 * another typeable object to have a type related to the 253 * element type of the specified typeable. As a side 254 * effect, the specified typeable is constrained to have an array 255 * type. A typical usage of this is as follows: 256 * <pre> 257 * output.setTypeAtLeast(ArrayType.elementType(input)); 258 * </pre> 259 * where input and output are ports. This forces the input 260 * port to have an array type and the output port to have 261 * a type at least that of the elements of input arrays. 262 * @param typeable An array-valued typeable. 263 * @return An InequalityTerm that can be passed to methods 264 * like setTypeAtLeast() of the Typeable interface. 265 * @exception IllegalActionException If the specified typeable 266 * cannot be set to an array type. 267 */ 268 public static InequalityTerm elementType(Typeable typeable) 269 throws IllegalActionException { 270 typeable.setTypeAtLeast(ArrayType.ARRAY_BOTTOM); 271 return new TypeableElementTypeTerm(typeable); 272 } 273 274 /** Return the declared type of the array elements. 275 * @return a Type. 276 */ 277 public Type getDeclaredElementType() { 278 return _declaredElementType; 279 } 280 281 /** Return the type of the array elements. 282 * @return a Type. 283 */ 284 public Type getElementType() { 285 return _elementType; 286 } 287 288 /** Return the InequalityTerm representing the element type. 289 * @return An InequalityTerm. 290 * @see ptolemy.graph.InequalityTerm 291 */ 292 public InequalityTerm getElementTypeTerm() { 293 // This should be public because of copernicus.java.TypeSpecializer 294 return _elemTypeTerm; 295 } 296 297 /** Return the class for tokens that this type represents. 298 * @return The class for tokens that this type represents. 299 */ 300 @Override 301 public Class getTokenClass() { 302 return ArrayToken.class; 303 } 304 305 /** Return a hash code value for this object. 306 */ 307 @Override 308 public int hashCode() { 309 return _elementType.hashCode() + 2917; 310 } 311 312 /** Return true if the length of this array type has been determined. 313 * @return true if the length has been determined. 314 */ 315 public boolean hasKnownLength() { 316 return _length >= 0; 317 } 318 319 /** Return true if this type does not correspond to a single token 320 * class. This occurs if the type is not instantiable, or it 321 * represents either an abstract base class or an interface. 322 * @return true if the element type is abstract. 323 */ 324 @Override 325 public boolean isAbstract() { 326 return _elementType.isAbstract() || !hasKnownLength(); 327 } 328 329 /** Set the elements that have declared type BaseType.UNKNOWN (the leaf 330 * type variable) to the specified type. 331 * @param t the type to set the leaf type variable to. 332 */ 333 @Override 334 public void initialize(Type t) { 335 try { 336 if (!isConstant()) { 337 _elemTypeTerm.initialize(t); 338 } 339 } catch (IllegalActionException iae) { 340 throw new InternalErrorException("ArrayType.initialize: Cannot " 341 + "initialize the element type to " + t + ". " 342 + iae.getMessage()); 343 } 344 } 345 346 /** Test if the argument type is compatible with this type. 347 * If this type is a constant, the argument is compatible if it is less 348 * than or equal to this type in the type lattice; If this type is a 349 * variable, the argument is compatible if it is a substitution 350 * instance of this type. 351 * @param type A Type. 352 * @return True if the argument is compatible with this type. 353 * @see ptolemy.data.type.ArrayType#convert 354 */ 355 @Override 356 public boolean isCompatible(Type type) { 357 ArrayType arrayType; 358 359 if (type instanceof ArrayType) { 360 arrayType = (ArrayType) type; 361 if (hasKnownLength() && arrayType.hasKnownLength() 362 && length() != arrayType.length()) { 363 return false; 364 } 365 // If the length of this type is unknown, then the 366 // argument length is compatible. 367 } else { 368 if (type.equals(BaseType.GENERAL)) { 369 // If we have a Const {1,2,3} -> Display, then 370 // this method needs to return true because Display 371 // has an input port of type General. 372 return true; 373 } 374 return false; 375 } 376 377 Type elementType = arrayType.getElementType(); 378 return _elementType.isCompatible(elementType); 379 } 380 381 /** Test if this ArrayType is a constant. An ArrayType is a constant if 382 * it does not contain BaseType.UNKNOWN in any level. 383 * @return True if this type is a constant. 384 */ 385 @Override 386 public boolean isConstant() { 387 return _declaredElementType.isConstant(); 388 } 389 390 /** Determine if this type corresponds to an instantiable token 391 * class. An ArrayType is instantiable if its element type is 392 * instantiable. 393 * @return True if this type is instantiable. 394 */ 395 @Override 396 public boolean isInstantiable() { 397 return _elementType.isInstantiable(); 398 } 399 400 /** Return true if the specified type is a substitution instance of this 401 * type. 402 * @param type A Type. 403 * @return True if the argument is a substitution instance of this type. 404 * @see Type#isSubstitutionInstance 405 */ 406 @Override 407 public boolean isSubstitutionInstance(Type type) { 408 ArrayType arrayType; 409 if (type instanceof ArrayType) { 410 arrayType = (ArrayType) type; 411 if (hasKnownLength() && arrayType.hasKnownLength() 412 && length() != arrayType.length()) { 413 return false; 414 } 415 } else { 416 return false; 417 } 418 419 Type argElemType = ((ArrayType) type).getElementType(); 420 return _declaredElementType.isSubstitutionInstance(argElemType); 421 } 422 423 /** Return the length of this array type. 424 * @return The length of this type. 425 * @exception RuntimeException If the length is not known. 426 */ 427 public int length() { 428 if (!hasKnownLength()) { 429 throw new RuntimeException("Length is not known."); 430 } 431 return _length; 432 } 433 434 /** Set the type to the specified type, which is required to be 435 * an array type. 436 * @param type The new type. 437 * @exception IllegalActionException If the specified type is not 438 * an instance of ArrayType. 439 */ 440 public void setType(Type type) throws IllegalActionException { 441 if (!(type instanceof ArrayType)) { 442 throw new IllegalActionException( 443 "Cannot change an array type to a non-array type."); 444 } 445 try { 446 Type clone = (Type) ((ArrayType) type).getElementType().clone(); 447 _elementType = clone; 448 _declaredElementType = clone; 449 _length = ((ArrayType) type).length(); 450 } catch (CloneNotSupportedException e) { 451 throw new InternalErrorException(e); 452 } 453 } 454 455 /** Return the string representation of this type. The format is 456 * {<i>type</i>}, where <i>type</i> is the element type. 457 * @return A String. 458 */ 459 @Override 460 public String toString() { 461 if (hasKnownLength()) { 462 return "arrayType(" + getElementType().toString() + "," + _length 463 + ")"; 464 } else { 465 return "arrayType(" + getElementType().toString() + ")"; 466 } 467 } 468 469 /** Update this Type to the specified ArrayType. 470 * The specified type must be an ArrayType with the same structure as 471 * this type, and have depth less than the MAXDEPTHBOUND. 472 * This method will only update the component whose declared type is 473 * BaseType.UNKNOWN, and leave the constant part of this type intact. 474 * @param newType A StructuredType. 475 * @exception IllegalActionException If the specified type is not an 476 * ArrayType or it does not have the same structure as this one. 477 */ 478 @Override 479 public void updateType(StructuredType newType) 480 throws IllegalActionException { 481 super.updateType(newType); 482 483 // This type is a variable. 484 if (!this.isSubstitutionInstance(newType)) { 485 throw new IllegalActionException( 486 "ArrayType.updateType: " + "The type " + this 487 + " cannot be updated to " + newType + "."); 488 } 489 490 ArrayType arrayType = (ArrayType) newType; 491 if (!arrayType.hasKnownLength() || arrayType._length != _length) { 492 _length = -1; // Other length cases should be guarded by 493 // the isSubstituionInstance method 494 } 495 496 Type newElemType = ((ArrayType) newType).getElementType(); 497 498 if (_declaredElementType.equals(BaseType.UNKNOWN)) { 499 try { 500 _elementType = (Type) newElemType.clone(); 501 } catch (CloneNotSupportedException cnse) { 502 throw new InternalErrorException("ArrayType.updateType: " 503 + "The specified element type cannot be cloned: " 504 + _elementType); 505 } 506 } else if (!_declaredElementType.equals(newElemType)) { 507 // _declaredElementType is a StructuredType. _elementType 508 // must also be. 509 ((StructuredType) _elementType) 510 .updateType((StructuredType) newElemType); 511 } 512 } 513 514 /////////////////////////////////////////////////////////////////// 515 //// public variables //// 516 517 /** A term to use when declaring the type of some parameter or port 518 * to be an array. The way to use this is to declare: 519 * <pre> 520 * param.setTypeAtLeast(ArrayType.ARRAY_BOTTOM); 521 * </pre> 522 * for a parameter "param". 523 */ 524 public static final InequalityTerm ARRAY_BOTTOM = new ArrayBottomTypeTerm( 525 BaseType.ARRAY_BOTTOM); 526 527 /** A term to use when declaring the type of some parameter or port 528 * to be an array, with unknown length. The way to use this is to declare: 529 * <pre> 530 * param.setTypeAtLeast(ArrayType.ARRAY_UNSIZED_BOTTOM); 531 * </pre> 532 * for a parameter "param". 533 */ 534 public static final InequalityTerm ARRAY_UNSIZED_BOTTOM = new ArrayBottomTypeTerm( 535 new ArrayType(BaseType.UNKNOWN)); 536 537 // (new ArrayType(BaseType.UNKNOWN) { 538 // // This particular inequality term always has an acceptable type 539 // // because it has no visible array that will ever be evaluated. 540 // // It is essential that isValueAcceptable() return true, or the 541 // // idiom above will result in reported type errors. 542 // public InequalityTerm getElementTypeTerm() { 543 // return _replacementElementTerm; 544 // } 545 546 // private InequalityTerm _replacementElementTerm = new ElementTypeTerm() { 547 // public boolean isValueAcceptable() { 548 // return true; 549 // } 550 // }; 551 // }).getElementTypeTerm(); 552 553 /////////////////////////////////////////////////////////////////// 554 //// protected methods //// 555 556 /** Compare this type with the specified type. The specified type 557 * must be an ArrayType, otherwise an exception will be thrown. 558 * This method returns one of ptolemy.graph.CPO.LOWER, 559 * ptolemy.graph.CPO.SAME, ptolemy.graph.CPO.HIGHER, 560 * ptolemy.graph.CPO.INCOMPARABLE, indicating this type is lower 561 * than, equal to, higher than, or incomparable with the 562 * specified type in the type hierarchy, respectively. 563 * @param type an ArrayType. 564 * @return An integer. 565 * @exception IllegalArgumentException If the specified type is 566 * not an ArrayType. 567 */ 568 @Override 569 protected int _compare(StructuredType type) { 570 if (!(type instanceof ArrayType)) { 571 throw new IllegalArgumentException("ArrayType.compare: " 572 + "The argument " + type + " is not an ArrayType."); 573 } 574 575 int retval = TypeLattice.compare(_elementType, 576 ((ArrayType) type).getElementType()); 577 578 ArrayType arrayArgType = (ArrayType) type; 579 if (hasKnownLength() && arrayArgType.hasKnownLength()) { 580 if (length() != arrayArgType.length()) { 581 retval = ptolemy.graph.CPO.INCOMPARABLE; 582 } 583 } else if (hasKnownLength()) { 584 if (retval == ptolemy.graph.CPO.HIGHER) { 585 retval = ptolemy.graph.CPO.INCOMPARABLE; 586 } else if (retval == ptolemy.graph.CPO.SAME) { 587 // same element type but arrayArgType has no length [a, n] <= [a] 588 retval = ptolemy.graph.CPO.LOWER; 589 } 590 } else if (arrayArgType.hasKnownLength()) { 591 if (retval == ptolemy.graph.CPO.LOWER) { 592 retval = ptolemy.graph.CPO.INCOMPARABLE; 593 } else if (retval == ptolemy.graph.CPO.SAME) { 594 // same element type but this type has no length [a] >= [a, n] 595 retval = ptolemy.graph.CPO.HIGHER; 596 } 597 } 598 599 //System.out.println("comparing " + this + " and " + arrayArgType + " = " + retval); 600 return retval; 601 } 602 603 /** Return a static instance of ArrayType. 604 * @return an ArrayType. 605 */ 606 @Override 607 protected StructuredType _getRepresentative() { 608 return _representative; 609 } 610 611 /** Return the greatest lower bound of this type with the specified 612 * type. The specified type must be an ArrayType, otherwise an 613 * exception will be thrown. 614 * @param type an ArrayType. 615 * @return an ArrayType. 616 * @exception IllegalArgumentException If the specified type is 617 * not an ArrayType. 618 */ 619 @Override 620 protected StructuredType _greatestLowerBound(StructuredType type) { 621 if (!(type instanceof ArrayType)) { 622 throw new IllegalArgumentException("ArrayType.greatestLowerBound: " 623 + "The argument " + type + " is not an ArrayType."); 624 } 625 626 Type elementGLB = (Type) TypeLattice.lattice().greatestLowerBound( 627 _elementType, ((ArrayType) type).getElementType()); 628 629 ArrayType arrayArgType = (ArrayType) type; 630 if (!hasKnownLength() && !arrayArgType.hasKnownLength()) { 631 return new ArrayType(elementGLB); 632 } else if (hasKnownLength() && arrayArgType.hasKnownLength()) { 633 if (length() != arrayArgType.length()) { 634 // FIXME: 635 // return BaseType.ARRAY_BOTTOM; 636 } 637 } 638 if (hasKnownLength()) { 639 return new ArrayType(elementGLB, length()); 640 } else { 641 return new ArrayType(elementGLB, arrayArgType.length()); 642 } 643 } 644 645 /** Return the least Upper bound of this type with the specified 646 * type. The specified type must be an ArrayType, otherwise an 647 * exception will be thrown. 648 * @param type an ArrayType. 649 * @return an ArrayType. 650 * @exception IllegalArgumentException If the specified type is 651 * not an ArrayType. 652 */ 653 @Override 654 protected StructuredType _leastUpperBound(StructuredType type) { 655 if (!(type instanceof ArrayType)) { 656 throw new IllegalArgumentException("ArrayType.leastUpperBound: " 657 + "The argument " + type + " is not an ArrayType."); 658 } 659 660 Type elementLUB = (Type) TypeLattice.lattice().leastUpperBound( 661 _elementType, ((ArrayType) type).getElementType()); 662 663 ArrayType arrayArgType = (ArrayType) type; 664 if (hasKnownLength() && arrayArgType.hasKnownLength()) { 665 if (length() == arrayArgType.length()) { 666 return new ArrayType(elementLUB, length()); 667 } 668 } 669 670 // System.out.println("least upper bound of " + this + " and " + type + " = " + new ArrayType(elementLUB)); 671 672 return new ArrayType(elementLUB); 673 } 674 675 /////////////////////////////////////////////////////////////////// 676 //// private variables //// 677 // the type of array elements. 678 private Type _declaredElementType; 679 680 private Type _elementType; 681 682 private int _length; 683 684 private ElementTypeTerm _elemTypeTerm = new ElementTypeTerm(); 685 686 private static ArrayType _representative = new ArrayType(BaseType.UNKNOWN); 687 688 /////////////////////////////////////////////////////////////////// 689 //// inner classes //// 690 691 /** An InequalityTerm representing an arbitrary array type. 692 */ 693 private static class ArrayBottomTypeTerm implements InequalityTerm { 694 695 /** Construct a term. 696 */ 697 public ArrayBottomTypeTerm(Type type) { 698 _arrayType = type; 699 } 700 701 /////////////////////////////////////////////////////////////// 702 //// public inner methods //// 703 704 /** Return an array type with element types given by the 705 * associated typeable. 706 * @return An ArrayType. 707 */ 708 @Override 709 public Object getAssociatedObject() { 710 return _arrayType; 711 } 712 713 /** Return an array type with element types given by the 714 * associated typeable. 715 * @return An ArrayType. 716 * @exception IllegalActionException If the type of the 717 * associated typeable cannot be determined. 718 */ 719 @Override 720 public Object getValue() throws IllegalActionException { 721 return _arrayType; 722 } 723 724 /** Return an array of size zero. 725 * @return An array of InequalityTerm. 726 */ 727 @Override 728 public InequalityTerm[] getVariables() { 729 return new InequalityTerm[0]; 730 } 731 732 /** Throw an exception. This term cannot be set. 733 * @param e A Type. 734 * @exception IllegalActionException If this type is a constant, 735 * or the argument is not a Type. 736 */ 737 @Override 738 public void initialize(Object e) throws IllegalActionException { 739 throw new IllegalActionException( 740 "ArrayType$ArraybottomTypeTerm.setValue: " 741 + "Is not settable."); 742 } 743 744 /** Return false. 745 * @return False. 746 */ 747 @Override 748 public boolean isSettable() { 749 return false; 750 } 751 752 /** Delegate to an array type with elements given by the 753 * type of the associated typeable. 754 * @return True if the element type is acceptable. 755 */ 756 @Override 757 public boolean isValueAcceptable() { 758 return true; 759 } 760 761 /** Throw an exception. 762 * @param type a Type. 763 * @exception IllegalActionException Always 764 */ 765 @Override 766 public void setValue(Object type) throws IllegalActionException { 767 throw new IllegalActionException( 768 "ArrayType$ArrayBottomTypeTerm.setValue: " 769 + "Is not settable."); 770 } 771 772 /** Delegate to an array type with elements given by the 773 * type of the associated typeable. 774 * @return A String. 775 */ 776 @Override 777 public String toString() { 778 return _arrayType.toString(); 779 } 780 781 /////////////////////////////////////////////////////////////// 782 //// private members //// 783 784 /** The array type with element types matching the typeable. */ 785 private Type _arrayType; 786 } 787 788 /** An InequalityTerm associated with an instance of ArrayType. */ 789 private class ElementTypeTerm implements InequalityTerm { 790 /////////////////////////////////////////////////////////////// 791 //// public inner methods //// 792 793 /** Return this ArrayType. 794 * @return an ArrayType. 795 */ 796 @Override 797 public Object getAssociatedObject() { 798 return ArrayType.this; 799 } 800 801 /** Return the element type. 802 * @return a Type. 803 */ 804 @Override 805 public Object getValue() { 806 return _elementType; 807 } 808 809 /** Return this ElementTypeTerm in an array if this term 810 * represents a type variable. Otherwise, return an array of 811 * size zero. 812 * @return An array of InequalityTerm. 813 */ 814 @Override 815 public InequalityTerm[] getVariables() { 816 if (isSettable()) { 817 InequalityTerm[] variable = new InequalityTerm[1]; 818 variable[0] = this; 819 return variable; 820 } 821 822 return new InequalityTerm[0]; 823 } 824 825 /** Reset the variable part of the element type to the specified 826 * type. 827 * @param e A Type. 828 * @exception IllegalActionException If this type is a constant, 829 * or the argument is not a Type. 830 */ 831 @Override 832 public void initialize(Object e) throws IllegalActionException { 833 if (isConstant()) { 834 throw new IllegalActionException( 835 "ArrayType$ElementTypeTerm.initialize: " + "This type " 836 + this + " is not settable."); 837 } 838 839 if (!(e instanceof Type)) { 840 throw new IllegalActionException( 841 "ArrayType$ElementTypeTerm.initialize: " 842 + "The argument " + this + " is not a Type."); 843 } 844 845 if (_declaredElementType.equals(BaseType.UNKNOWN)) { 846 _elementType = (Type) e; 847 } else { 848 // element type is a structured type. 849 ((StructuredType) _elementType).initialize((Type) e); 850 } 851 } 852 853 /** Test if the element type is a type variable. 854 * @return True if the element type is a type variable. 855 */ 856 @Override 857 public boolean isSettable() { 858 return !_declaredElementType.isConstant(); 859 } 860 861 /** Check whether the current element type is acceptable. 862 * The element type is acceptable if it represents an 863 * instantiable object. 864 * @return True if the element type is acceptable. 865 */ 866 @Override 867 public boolean isValueAcceptable() { 868 return _elementType.isInstantiable(); 869 } 870 871 /** Set the element type to the specified type. 872 * @param e a Type. 873 * @exception IllegalActionException If the specified type violates 874 * the declared type of the element. 875 */ 876 @Override 877 public void setValue(Object e) throws IllegalActionException { 878 if (!isSettable()) { 879 throw new IllegalActionException( 880 "ArrayType$ElementTypeTerm.setValue: This type " + e 881 + " is not settable."); 882 } 883 884 if (!_declaredElementType.isSubstitutionInstance((Type) e)) { 885 // The LUB of the _elementType and another type is General, 886 // this is a type conflict. 887 throw new IllegalActionException( 888 "ArrayType$ElementTypeTerm.setValue: " 889 + "Cannot update the element type of this array to " 890 + "the new type." + " Element type: " 891 + _declaredElementType.toString() 892 + ", New type: " + e.toString()); 893 } 894 895 if (_declaredElementType.equals(BaseType.UNKNOWN)) { 896 try { 897 _elementType = (Type) ((Type) e).clone(); 898 } catch (CloneNotSupportedException cnse) { 899 throw new InternalErrorException( 900 "ArrayType$ElementTypeTerm.setValue: " 901 + "The specified type " + e 902 + " cannot be cloned."); 903 } 904 } else { 905 ((StructuredType) _elementType).updateType((StructuredType) e); 906 } 907 } 908 909 /** Return a string representation of this term. 910 * @return A String. 911 */ 912 @Override 913 public String toString() { 914 return "(ArrayElementType(" + getAssociatedObject() + "), " 915 + getValue() + ")"; 916 } 917 } 918 919 /** An InequalityTerm representing an array type whose elements 920 * have the type of the specified typeable. The purpose of this class 921 * is to defer to as late as possible actually accessing 922 * the type of the typeable, since it may change dynamically. 923 * This term is not variable and cannot be set. 924 */ 925 private static class TypeableArrayTypeTerm implements InequalityTerm { 926 927 /** Construct a term that will defer to the type of the 928 * specified typeable. 929 * @param typeable The object to defer requests to. 930 */ 931 public TypeableArrayTypeTerm(Typeable typeable) { 932 _typeable = typeable; 933 } 934 935 /////////////////////////////////////////////////////////////// 936 //// public inner methods //// 937 938 /** Return the associated typeable. 939 * @return A Typeable. 940 */ 941 @Override 942 public Object getAssociatedObject() { 943 return _typeable; 944 } 945 946 /** Return an array type with element types given by the associated typeable. 947 * @return An ArrayType. 948 * @exception IllegalActionException If the type of the associated typeable 949 * cannot be determined. 950 */ 951 @Override 952 public Object getValue() throws IllegalActionException { 953 return _getArrayTypeRaw(); 954 } 955 956 /** Return an array of size zero. 957 * @return An array of InequalityTerm. 958 */ 959 @Override 960 public InequalityTerm[] getVariables() { 961 return new InequalityTerm[0]; 962 } 963 964 /** Throw an exception. This term cannot be set. 965 * @param e A Type. 966 * @exception IllegalActionException If this type is a constant, 967 * or the argument is not a Type. 968 */ 969 @Override 970 public void initialize(Object e) throws IllegalActionException { 971 throw new IllegalActionException( 972 "ArrayType$TypeableArrayTypeTerm.initialize: " 973 + "This array type given with elements given by " 974 + _typeable + " is not settable."); 975 } 976 977 /** Return false. 978 * @return False. 979 */ 980 @Override 981 public boolean isSettable() { 982 return false; 983 } 984 985 /** Delegate to an array type with elements given by the 986 * type of the associated typeable. 987 * @return True if the element type is acceptable. 988 */ 989 @Override 990 public boolean isValueAcceptable() { 991 ArrayType type = _getArrayType(); 992 return type.getElementTypeTerm().isValueAcceptable(); 993 } 994 995 /** Throw an exception. 996 * @param type a Type. 997 * @exception IllegalActionException Always 998 */ 999 @Override 1000 public void setValue(Object type) throws IllegalActionException { 1001 throw new IllegalActionException( 1002 "ArrayType$TypeableArrayTypeTerm.setValue: " 1003 + "The array type with element type given by " 1004 + _typeable + " is not settable."); 1005 } 1006 1007 /** Delegate to an array type with elements given by the 1008 * type of the associated typeable. 1009 * @return A String. 1010 */ 1011 @Override 1012 public String toString() { 1013 try { 1014 return "(TypeableArrayType(" + getAssociatedObject() + "), " 1015 + getValue() + ")"; 1016 } catch (IllegalActionException e) { 1017 throw new InternalErrorException(e); 1018 } 1019 } 1020 1021 /////////////////////////////////////////////////////////////// 1022 //// private methods //// 1023 1024 /** Get an array type with element type matching the type 1025 * of the associated typeable. 1026 * @return An array type for the associated typeable. 1027 */ 1028 private ArrayType _getArrayType() { 1029 try { 1030 return _getArrayTypeRaw(); 1031 } catch (IllegalActionException e) { 1032 throw new InternalErrorException(e); 1033 } 1034 } 1035 1036 /** Get an array type with element type matching the type 1037 * of the associated typeable. 1038 * @return An array type for the associated typeable. 1039 * @exception IllegalActionException If the type of the typeable 1040 * cannot be determined. 1041 */ 1042 private ArrayType _getArrayTypeRaw() throws IllegalActionException { 1043 Type type = _typeable.getType(); 1044 if (_arrayType == null 1045 || !_arrayType.getElementType().equals(type)) { 1046 _arrayType = new ArrayType(type); 1047 } 1048 return _arrayType; 1049 } 1050 1051 /////////////////////////////////////////////////////////////// 1052 //// private members //// 1053 1054 /** The associated typeable. */ 1055 private Typeable _typeable; 1056 1057 /** The array type with element types matching the typeable. */ 1058 private ArrayType _arrayType; 1059 } 1060 1061 /** An InequalityTerm representing the element types 1062 * of an instance of Typeable. The purpose of this class 1063 * is to defer to as late as possible actually accessing 1064 * the type of the typeable, since it may change dynamically. 1065 */ 1066 private static class TypeableElementTypeTerm implements InequalityTerm { 1067 1068 /** Construct a term that will defer to the type of the 1069 * specified typeable. 1070 * @param typeable The object to defer requests to. 1071 */ 1072 public TypeableElementTypeTerm(Typeable typeable) { 1073 _typeable = typeable; 1074 } 1075 1076 /////////////////////////////////////////////////////////////// 1077 //// public inner methods //// 1078 1079 /** Delegate to the element type term of the associated typeable. 1080 * @return an ArrayType. 1081 */ 1082 @Override 1083 public Object getAssociatedObject() { 1084 return _typeable; 1085 } 1086 1087 /** Delegate to the element type term of the associated typeable. 1088 * @return a Type. 1089 * @exception IllegalActionException If the delegate throws it. 1090 */ 1091 @Override 1092 public Object getValue() throws IllegalActionException { 1093 InequalityTerm term = _getElementTypeTerm(); 1094 if (term == null) { 1095 return BaseType.UNKNOWN; 1096 } else { 1097 return term.getValue(); 1098 } 1099 } 1100 1101 /** Delegate to the element type term of the associated typeable. 1102 * @return An array of InequalityTerm. 1103 */ 1104 @Override 1105 public InequalityTerm[] getVariables() { 1106 if (isSettable()) { 1107 InequalityTerm[] variable = new InequalityTerm[1]; 1108 variable[0] = this; 1109 return variable; 1110 } 1111 1112 return new InequalityTerm[0]; 1113 } 1114 1115 /** Delegate to the element type term of the associated typeable. 1116 * @param type A Type. 1117 * @exception IllegalActionException If the delegate throws it. 1118 */ 1119 @Override 1120 public void initialize(Object type) throws IllegalActionException { 1121 InequalityTerm term = _getElementTypeTerm(); 1122 if (term == null) { 1123 return; 1124 } else { 1125 term.initialize(type); 1126 } 1127 } 1128 1129 /** Delegate to the element type term of the associated typeable. 1130 * @return True if the element type is a type variable. 1131 */ 1132 @Override 1133 public boolean isSettable() { 1134 InequalityTerm term = _getElementTypeTerm(); 1135 if (term == null) { 1136 return true; 1137 } else { 1138 return term.isSettable(); 1139 } 1140 } 1141 1142 /** Delegate to the element type term of the associated typeable. 1143 * @return True if the element type is acceptable. 1144 */ 1145 @Override 1146 public boolean isValueAcceptable() { 1147 InequalityTerm term = _getElementTypeTerm(); 1148 if (term == null) { 1149 // Array has no element type. 1150 // If the type of the associated typable is 1151 // unknown and if this is acceptable, then it 1152 // is OK for the element types to be unknown. 1153 try { 1154 Type arrayType = _typeable.getType(); 1155 if (BaseType.UNKNOWN.equals(arrayType) 1156 && _typeable.isTypeAcceptable()) { 1157 return true; 1158 } 1159 } catch (IllegalActionException e) { 1160 // Ignore and return false. 1161 } 1162 return false; 1163 } else { 1164 return term.isValueAcceptable(); 1165 } 1166 } 1167 1168 /** Delegate to the element type term of the associated typeable. 1169 * @param type a Type. 1170 * @exception IllegalActionException If the specified type violates 1171 * the declared type of the element. 1172 */ 1173 @Override 1174 public void setValue(Object type) throws IllegalActionException { 1175 InequalityTerm term = _getElementTypeTerm(); 1176 if (term == null) { 1177 return; 1178 } else { 1179 term.setValue(type); 1180 } 1181 } 1182 1183 /** Delegate to the element type term of the associated typeable. 1184 * @return A String. 1185 */ 1186 @Override 1187 public String toString() { 1188 try { 1189 return "(ArrayElementType(" + getAssociatedObject() + "), " 1190 + getValue() + ")"; 1191 } catch (IllegalActionException e) { 1192 throw new InternalErrorException(e); 1193 } 1194 1195 } 1196 1197 /////////////////////////////////////////////////////////////// 1198 //// private methods //// 1199 1200 /** Get an inequality term for elements of the associated 1201 * typeable. If the associated typeable does not already have 1202 * an array type, then return null, indicating that the type 1203 * of the typeable hasn't yet resolved to an array type. 1204 * @return An array type for the associated typeable. 1205 */ 1206 private InequalityTerm _getElementTypeTerm() { 1207 try { 1208 Type type = _typeable.getType(); 1209 if (!(type instanceof ArrayType)) { 1210 return null; 1211 } 1212 return ((ArrayType) type).getElementTypeTerm(); 1213 } catch (IllegalActionException e) { 1214 throw new InternalErrorException(e); 1215 } 1216 } 1217 1218 /////////////////////////////////////////////////////////////// 1219 //// private members //// 1220 1221 /** The associated typeable. */ 1222 private Typeable _typeable; 1223 } 1224 1225 /** An InequalityTerm representing an array types whose elements 1226 * have the type of the specified typeable. The purpose of this class 1227 * is to defer to as late as possible actually accessing 1228 * the type of the typeable, since it may change dynamically. 1229 * This term is not variable and cannot be set. 1230 */ 1231 private static class TypeableSizedArrayTypeTerm implements InequalityTerm { 1232 1233 /** Construct a term that will defer to the type of the 1234 * specified typeable. 1235 * @param typeable The object to defer requests to. 1236 */ 1237 public TypeableSizedArrayTypeTerm(Typeable typeable, int length) { 1238 _typeable = typeable; 1239 _length = length; 1240 } 1241 1242 /////////////////////////////////////////////////////////////// 1243 //// public inner methods //// 1244 1245 /** Return an array type with element types given by the associated typeable. 1246 * @return An ArrayType. 1247 */ 1248 @Override 1249 public Object getAssociatedObject() { 1250 return _getArrayType(); 1251 } 1252 1253 /** Return an array type with element types given by the associated typeable. 1254 * @return An ArrayType. 1255 * @exception IllegalActionException If the type of the associated typeable 1256 * cannot be determined. 1257 */ 1258 @Override 1259 public Object getValue() throws IllegalActionException { 1260 return _getArrayTypeRaw(); 1261 } 1262 1263 /** Return an array of size zero. 1264 * @return An array of InequalityTerm. 1265 */ 1266 @Override 1267 public InequalityTerm[] getVariables() { 1268 return new InequalityTerm[0]; 1269 } 1270 1271 /** Throw an exception. This term cannot be set. 1272 * @param e A Type. 1273 * @exception IllegalActionException If this type is a constant, 1274 * or the argument is not a Type. 1275 */ 1276 @Override 1277 public void initialize(Object e) throws IllegalActionException { 1278 throw new IllegalActionException( 1279 "ArrayType$TypeableArrayTypeTerm.initialize: " 1280 + "This array type given with elements given by " 1281 + _typeable + " is not settable."); 1282 } 1283 1284 /** Return false. 1285 * @return False. 1286 */ 1287 @Override 1288 public boolean isSettable() { 1289 return false; 1290 } 1291 1292 /** Delegate to an array type with elements given by the 1293 * type of the associated typeable. 1294 * @return True if the element type is acceptable. 1295 */ 1296 @Override 1297 public boolean isValueAcceptable() { 1298 ArrayType type = _getArrayType(); 1299 return type.getElementTypeTerm().isValueAcceptable(); 1300 } 1301 1302 /** Throw an exception. 1303 * @param type a Type. 1304 * @exception IllegalActionException Always 1305 */ 1306 @Override 1307 public void setValue(Object type) throws IllegalActionException { 1308 throw new IllegalActionException( 1309 "ArrayType$TypeableArrayTypeTerm.setValue: " 1310 + "The array type with element type given by " 1311 + _typeable + " is not settable."); 1312 } 1313 1314 /** Delegate to an array type with elements given by the 1315 * type of the associated typeable. 1316 * @return A String. 1317 */ 1318 @Override 1319 public String toString() { 1320 return _getArrayType().toString(); 1321 } 1322 1323 /////////////////////////////////////////////////////////////// 1324 //// private methods //// 1325 1326 /** Get an array type with element type matching the type 1327 * of the associated typeable. 1328 * @return An array type for the associated typeable. 1329 */ 1330 private ArrayType _getArrayType() { 1331 try { 1332 return _getArrayTypeRaw(); 1333 } catch (IllegalActionException e) { 1334 throw new InternalErrorException(e); 1335 } 1336 } 1337 1338 /** Get an array type with element type matching the type 1339 * of the associated typeable. 1340 * @return An array type for the associated typeable. 1341 * @exception IllegalActionException If the type of the typeable 1342 * cannot be determined. 1343 */ 1344 private ArrayType _getArrayTypeRaw() throws IllegalActionException { 1345 Type type = _typeable.getType(); 1346 if (_arrayType == null 1347 || !_arrayType.getElementType().equals(type)) { 1348 _arrayType = new ArrayType(type, _length); 1349 } 1350 return _arrayType; 1351 } 1352 1353 /////////////////////////////////////////////////////////////// 1354 //// private members //// 1355 1356 /** The associated typeable. */ 1357 private Typeable _typeable; 1358 1359 /** The array type with element types matching the typeable. */ 1360 private ArrayType _arrayType; 1361 1362 private int _length; 1363 } 1364}