001/* Abstract base class for tokens that contain a scalar.
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 FIXME: setUnitCategory seems to violate immutability.
028 */
029package ptolemy.data;
030
031import ptolemy.data.type.Type;
032import ptolemy.data.type.TypeLattice;
033import ptolemy.data.unit.UnitUtilities;
034import ptolemy.graph.CPO;
035import ptolemy.kernel.util.IllegalActionException;
036import ptolemy.math.Complex;
037import ptolemy.math.FixPoint;
038
039///////////////////////////////////////////////////////////////////
040//// ScalarToken
041
042/**
043 Abstract base class for tokens that contain a scalar.  This base class
044 extends the Token class to properly implement type conversion and the
045 units portion of the standard operations for scalar tokens.  It also
046 adds methods for querying the natural ordering between scalars.
047
048 <p> This class has a number of protected abstract methods that subclasses
049 must implement.  These methods need only implement the numerical
050 portion of the operation between two tokens of the same type.  This
051 base class will handle the conversion of tokens from different types
052 to the same type before calling the protected method, and the proper
053 computation of the units of the returned token afterwards.
054
055 <p> In general, any instance of a scalar token may be optionally
056 associated with a set of units.  In the arithmetic methods add(),
057 modulo(), and subtract(), the two operands must have the same
058 units. Otherwise, an exception will be thrown. In the methods
059 multiply() and divide(), the units of the resulting token will be
060 computed automatically.  IMPORTANT: The protected methods implemented
061 in derived classes are expected to return a new token in the case of
062 multiply and divide.  This new token will automatically have its units
063 set correctly by this base class implementation.  Certain cases, such
064 as multiplication by one, cannot be optimized to simply return an the
065 input token without performing the multiplication, since the units of
066 the result may be different than the units of either input token.
067
068 @author Yuhong Xiong, Mudit Goel, Steve Neuendorffer
069 @version $Id$
070 @since Ptolemy II 0.2
071 @Pt.ProposedRating Green (neuendor)
072 @Pt.AcceptedRating Green (yuhong)
073 */
074public abstract class ScalarToken extends Token
075        implements BitwiseOperationToken, PartiallyOrderedToken {
076    ///////////////////////////////////////////////////////////////////
077    ////                         public methods                    ////
078
079    /** Return a ScalarToken containing the absolute value of the
080     *  value of this token. If this token contains a non-negative
081     *  number, it is returned directly; otherwise, a new token is
082     *  returned.  Note that it is explicitly allowable to return this
083     *  token, since the units are the same.  This method defers to
084     *  the _absolute() method to perform the operation, and derived
085     *  classes should implement that method to provide type-specific
086     *  behavior.
087     *  @return A ScalarToken with the same units, and likely to be of
088     *  the same type as this token.
089     *  If this token is a nil token, then {@link ptolemy.data.Token#NIL}
090     *  is returned.
091     */
092    public final ScalarToken absolute() {
093        if (isNil()) {
094            return this;
095        }
096        ScalarToken result = _absolute();
097
098        if (_unitCategoryExponents != null && !_isUnitless()) {
099            result._unitCategoryExponents = _copyOfCategoryExponents();
100        }
101        return result;
102    }
103
104    /** Return a new token whose value is the sum of this token and
105     *  the argument. Type conversion also occurs here, so that the
106     *  operation is performed at the least type necessary to ensure
107     *  precision.  The returned type is the same as the type chosen
108     *  for the operation, which is the higher of the type of this
109     *  token and the argument type.  Subclasses should implement the
110     *  protected _add() method to perform the correct type-specific
111     *  operation.
112     *  @param rightArgument The token to add to this token.
113     *  @return A new token containing the result.
114     *  @exception IllegalActionException If the argument token and
115     *  this token are of incomparable types, or have different units,
116     *  or the operation does not make sense for the given types.
117     */
118    @Override
119    public final Token add(Token rightArgument) throws IllegalActionException {
120        int typeInfo = TypeLattice.compare(getType(), rightArgument);
121
122        if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) {
123            return _doAdd(rightArgument);
124        } else if (typeInfo == CPO.HIGHER) {
125            ScalarToken convertedArgument = (ScalarToken) getType()
126                    .convert(rightArgument);
127
128            try {
129                return _doAdd(convertedArgument);
130            } catch (IllegalActionException ex) {
131                // If the type-specific operation fails, then create a
132                // better error message that has the types of the
133                // arguments that were passed in.
134                throw new IllegalActionException(null, ex,
135                        notSupportedMessage("add", this, rightArgument));
136            }
137        } else if (typeInfo == CPO.LOWER
138                || rightArgument instanceof MatrixToken) {
139            // NOTE: If the right argument is an instance of MatrixToken,
140            // then we try reversing the add.
141            return rightArgument.addReverse(this);
142        } else {
143            // Items being added are incomparable.
144            // However, addition may still be possible because
145            // the LUB of the types might support it. E.g., [double]+complex,
146            // where the LUB is [complex].
147            Type lubType = (Type) TypeLattice.lattice()
148                    .leastUpperBound(getType(), rightArgument.getType());
149
150            // If the LUB is a new type, try it.
151            if (!lubType.equals(getType())) {
152                Token lub = lubType.convert(this);
153
154                // Caution: convert() might return this again, e.g.
155                // if lubType is general.  Only proceed if the conversion
156                // returned a new type.
157                if (!lub.getType().equals(getType())) {
158                    return lub.add(rightArgument);
159                }
160            }
161
162            throw new IllegalActionException(notSupportedIncomparableMessage(
163                    "add", this, rightArgument));
164        }
165    }
166
167    /** Return a new token whose value is the sum of this token and
168     *  the argument.  Type conversion also occurs here, so that the
169     *  operation is performed at the least type necessary to ensure
170     *  precision.  The returned type is the same as the type chosen
171     *  for the operation, which is the higher of the type of this
172     *  token and the argument type.  Subclasses should implement the
173     *  protected _add() method to perform the correct type-specific
174     *  operation.
175     *  @param leftArgument The token to add this token to.
176     *  @return A new token containing the result.
177     *  @exception IllegalActionException If the argument token and
178     *  this token are of incomparable types, or have different units,
179     *  or the operation does not make sense for the given types.
180     */
181    @Override
182    public final Token addReverse(ptolemy.data.Token leftArgument)
183            throws IllegalActionException {
184        int typeInfo = TypeLattice.compare(leftArgument, getType());
185
186        // We would normally expect this to be LOWER, since this will almost
187        // always be called by add, so put that case first.
188        if (typeInfo == CPO.LOWER) {
189            ScalarToken convertedArgument = (ScalarToken) getType()
190                    .convert(leftArgument);
191
192            try {
193                return convertedArgument._doAdd(this);
194            } catch (IllegalActionException ex) {
195                // If the type-specific operation fails, then create a
196                // better error message that has the types of the
197                // arguments that were passed in.
198                throw new IllegalActionException(null, ex,
199                        notSupportedMessage("addReverse", this, leftArgument));
200            }
201        } else if (typeInfo == CPO.SAME) {
202            return ((ScalarToken) leftArgument)._doAdd(this);
203        } else if (typeInfo == CPO.HIGHER) {
204            return leftArgument.add(this);
205        } else {
206            throw new IllegalActionException(notSupportedIncomparableMessage(
207                    "addReverse", this, leftArgument));
208        }
209    }
210
211    /** Returns a token representing the bitwise AND of this token and
212     *  the given token.
213     *  @param rightArgument The ScalarToken to bitwise AND with this one.
214     *  @return The bitwise AND.
215     *  @exception IllegalActionException If the given token is not
216     *  compatible for this operation, or the operation does not make
217     *  sense for this type.
218     */
219    @Override
220    public BitwiseOperationToken bitwiseAnd(Token rightArgument)
221            throws IllegalActionException {
222        int typeInfo = TypeLattice.compare(getType(), rightArgument);
223
224        if (typeInfo == CPO.SAME) {
225            return _doBitwiseAnd(rightArgument);
226        } else if (typeInfo == CPO.HIGHER) {
227            ScalarToken convertedArgument = (ScalarToken) getType()
228                    .convert(rightArgument);
229
230            try {
231                return _doBitwiseAnd(convertedArgument);
232            } catch (IllegalActionException ex) {
233                // If the type-specific operation fails, then create a
234                // better error message that has the types of the
235                // arguments that were passed in.
236                throw new IllegalActionException(null, ex,
237                        notSupportedMessage("bitwiseAnd", this, rightArgument));
238            }
239        } else if (typeInfo == CPO.LOWER) {
240            if (!(rightArgument instanceof BitwiseOperationToken)) {
241                throw new IllegalActionException(
242                        notSupportedMessage("bitwiseAnd", this, rightArgument));
243            } else {
244                // This code uses the fact that bitwise AND is always
245                // commutative, there is no need to add a bitwiseAndReverse
246                // method.
247                return ((BitwiseOperationToken) rightArgument).bitwiseAnd(this);
248            }
249        } else {
250            throw new IllegalActionException(notSupportedIncomparableMessage(
251                    "bitwiseAnd", this, rightArgument));
252        }
253    }
254
255    /** Returns a token representing the bitwise NOT of this token.
256     *  @return The bitwise NOT of this token.
257     *  @exception IllegalActionException If the given token is not
258     *  compatible for this operation, or the operation does not make
259     *  sense for this type.
260     */
261    @Override
262    public BitwiseOperationToken bitwiseNot() throws IllegalActionException {
263        ScalarToken result = _bitwiseNot();
264        if (_unitCategoryExponents != null && !_isUnitless()) {
265            result._unitCategoryExponents = _copyOfCategoryExponents();
266        }
267        return result;
268    }
269
270    /** Returns a token representing the bitwise OR of this token and
271     *  the given token.
272     *  @param rightArgument The ScalarToken to bitwise OR with this one.
273     *  @return The bitwise OR.
274     *  @exception IllegalActionException If the given token is not
275     *  compatible for this operation, or the operation does not make
276     *  sense for this type.
277     */
278    @Override
279    public BitwiseOperationToken bitwiseOr(Token rightArgument)
280            throws IllegalActionException {
281        int typeInfo = TypeLattice.compare(getType(), rightArgument);
282
283        if (typeInfo == CPO.SAME) {
284            return _doBitwiseOr(rightArgument);
285        } else if (typeInfo == CPO.HIGHER) {
286            ScalarToken convertedArgument = (ScalarToken) getType()
287                    .convert(rightArgument);
288
289            try {
290                return _doBitwiseOr(convertedArgument);
291            } catch (IllegalActionException ex) {
292                // If the type-specific operation fails, then create a
293                // better error message that has the types of the
294                // arguments that were passed in.
295                throw new IllegalActionException(null, ex,
296                        notSupportedMessage("bitwiseOr", this, rightArgument));
297            }
298        } else if (typeInfo == CPO.LOWER) {
299            if (!(rightArgument instanceof BitwiseOperationToken)) {
300                throw new IllegalActionException(
301                        notSupportedMessage("bitwiseOr", this, rightArgument));
302            } else {
303                // This code uses the fact that bitwise OR is always
304                // commutative, there is no need to add a bitwiseOrReverse
305                // method.
306                return ((BitwiseOperationToken) rightArgument).bitwiseOr(this);
307            }
308        } else {
309            throw new IllegalActionException(notSupportedIncomparableMessage(
310                    "bitwiseOr", this, rightArgument));
311        }
312    }
313
314    /** Returns a token representing the bitwise XOR of this token and
315     *  the given token.
316     *  @param rightArgument The ScalarToken to bitwise XOR with this one.
317     *  @return The bitwise XOR.
318     *  @exception IllegalActionException If the given token is not
319     *  compatible for this operation, or the operation does not make
320     *  sense for this type.
321     */
322    @Override
323    public BitwiseOperationToken bitwiseXor(Token rightArgument)
324            throws IllegalActionException {
325        int typeInfo = TypeLattice.compare(getType(), rightArgument);
326
327        if (typeInfo == CPO.SAME) {
328            return _doBitwiseXor(rightArgument);
329        } else if (typeInfo == CPO.HIGHER) {
330            ScalarToken convertedArgument = (ScalarToken) getType()
331                    .convert(rightArgument);
332
333            try {
334                return _doBitwiseXor(convertedArgument);
335            } catch (IllegalActionException ex) {
336                // If the type-specific operation fails, then create a
337                // better error message that has the types of the
338                // arguments that were passed in.
339                throw new IllegalActionException(null, ex,
340                        notSupportedMessage("bitwiseXor", this, rightArgument));
341            }
342        } else if (typeInfo == CPO.LOWER) {
343            if (!(rightArgument instanceof BitwiseOperationToken)) {
344                throw new IllegalActionException(
345                        notSupportedMessage("bitwiseXor", this, rightArgument));
346            } else {
347                // This code uses the fact that bitwise XOR is always
348                // commutative, there is no need to add a bitwiseXorReverse
349                // method.
350                return ((BitwiseOperationToken) rightArgument).bitwiseXor(this);
351            }
352        } else {
353            throw new IllegalActionException(notSupportedIncomparableMessage(
354                    "bitwiseXor", this, rightArgument));
355        }
356    }
357
358    //     /** If the token is an instance of a subclass of ScalarToken,
359    //      *  then return the token. Otherwise, throw an exception.
360    //      *  @param token The token to be converted to a ScalarToken.
361    //      *  @return An instance of ScalarToken.
362    //      *  @exception IllegalActionException If the argument is not
363    //      *   already an instance of ScalarToken.
364    //      */
365    //     public static ScalarToken convert(Token token)
366    //             throws IllegalActionException {
367    //         if (token instanceof ScalarToken) {
368    //             return (ScalarToken) token;
369    //         }
370    //         throw new IllegalActionException(
371    //                 notSupportedIncomparableConversionMessage(token, "scalar"));
372    //     }
373
374    /** Return the value in the token as a byte.
375     *  In this base class, we just throw an exception.
376     *  @return The byte value contained in this token.
377     *  @exception IllegalActionException Always thrown.
378     */
379    public byte byteValue() throws IllegalActionException {
380        throw new IllegalActionException(
381                notSupportedConversionMessage(this, "byte"));
382    }
383
384    /** Return the value of this token as a Complex.
385     *  In this base class, we just throw an exception.
386     *  @return A Complex
387     *  @exception IllegalActionException Always thrown.
388     */
389    public Complex complexValue() throws IllegalActionException {
390        throw new IllegalActionException(
391                notSupportedConversionMessage(this, "Complex"));
392    }
393
394    /** Return a new token whose value is the value of this token
395     *  divided by the value of the argument token. Type conversion
396     *  also occurs here, so that the operation is performed at the
397     *  least type necessary to ensure precision.  The returned type
398     *  is the same as the type chosen for the operation, which is the
399     *  higher of the type of this token and the argument type.  The
400     *  returned token will also have the correct units.  Subclasses
401     *  should implement the protected _divide() method to perform the
402     *  correct type-specific operation.
403     *  @param rightArgument The token to divide into this token.
404     *  @return A new token containing the result.
405     *  @exception IllegalActionException If the argument token and
406     *  this token are of incomparable types, or the operation does
407     *  not make sense for the given types.
408     */
409    @Override
410    public final Token divide(Token rightArgument)
411            throws IllegalActionException {
412        int typeInfo = TypeLattice.compare(getType(), rightArgument);
413
414        if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) {
415            return _doDivide(rightArgument);
416        } else if (typeInfo == CPO.HIGHER) {
417            ScalarToken convertedArgument = (ScalarToken) getType()
418                    .convert(rightArgument);
419
420            try {
421                return _doDivide(convertedArgument);
422            } catch (IllegalActionException ex) {
423                // If the type-specific operation fails, then create a
424                // better error message that has the types of the
425                // arguments that were passed in.
426                throw new IllegalActionException(null, ex,
427                        notSupportedMessage("divide", this, rightArgument));
428            }
429        } else if (typeInfo == CPO.LOWER) {
430            return rightArgument.divideReverse(this);
431        } else {
432            // Items being divided are incomparable.
433            // However, division may still be possible because
434            // the LUB of the types might support it. E.g., [double]/complex,
435            // where the LUB is [complex].
436            Type lubType = (Type) TypeLattice.lattice()
437                    .leastUpperBound(getType(), rightArgument.getType());
438
439            // If the LUB is a new type, try it.
440            if (lubType != null && !lubType.equals(getType())) {
441                Token lub = lubType.convert(this);
442
443                // Caution: convert() might return this again, e.g.
444                // if lubType is general.  Only proceed if the conversion
445                // returned a new type.
446                if (!lub.getType().equals(getType())) {
447                    return lub.divide(rightArgument);
448                }
449            }
450
451            // LUB does not support it, but it still might be
452            // possible, e.g. with expressions like double / {double}.
453            // Only divideReverse() could support it at this time however.
454            // This will throw an exception if it is not supported.
455            return rightArgument.divideReverse(this);
456        }
457    }
458
459    /** Return a new token whose value is the value of this token
460     *  divided into the value of the argument token.  Type conversion
461     *  also occurs here, so that the operation is performed at the
462     *  least type necessary to ensure precision.  The returned type
463     *  is the same as the type chosen for the operation, which is the
464     *  higher of the type of this token and the argument type.  The
465     *  returned token will also have the correct units.  Subclasses
466     *  should implement the protected _divide() method to perform the
467     *  correct type-specific operation.
468     *  @param leftArgument The token to be divided into the value of
469     *  this token.
470     *  @return A new token containing the result.
471     *  @exception IllegalActionException If the argument token and
472     *  this token are of incomparable types, or the operation does
473     *  not make sense for the given types.
474     */
475    @Override
476    public final Token divideReverse(Token leftArgument)
477            throws IllegalActionException {
478        int typeInfo = TypeLattice.compare(leftArgument, getType());
479
480        // We would normally expect this to be LOWER, since this will almost
481        // always be called by divide, so put that case first.
482        if (typeInfo == CPO.LOWER) {
483            ScalarToken convertedArgument = (ScalarToken) getType()
484                    .convert(leftArgument);
485
486            try {
487                return convertedArgument._doDivide(this);
488            } catch (IllegalActionException ex) {
489                // If the type-specific operation fails, then create a
490                // better error message that has the types of the
491                // arguments that were passed in.
492                throw new IllegalActionException(null, ex, notSupportedMessage(
493                        "divideReverse", this, leftArgument));
494            }
495        } else if (typeInfo == CPO.SAME) {
496            return ((ScalarToken) leftArgument)._doDivide(this);
497        } else if (typeInfo == CPO.HIGHER) {
498            return leftArgument.divide(this);
499        } else {
500            throw new IllegalActionException(notSupportedIncomparableMessage(
501                    "divideReverse", this, leftArgument));
502        }
503    }
504
505    /** Return the value of this token as a double.
506     *  In this base class, we just throw an exception.
507     *  @return A double
508     *  @exception IllegalActionException Always thrown
509     */
510    public double doubleValue() throws IllegalActionException {
511        throw new IllegalActionException(
512                notSupportedConversionMessage(this, "double"));
513    }
514
515    /** Return the value of this token as a FixPoint.
516     *  In this base class, we just throw an exception.
517     *  @return A FixPoint
518     *  @exception IllegalActionException Always thrown.
519     */
520    public FixPoint fixValue() throws IllegalActionException {
521        throw new IllegalActionException(
522                notSupportedConversionMessage(this, "fixedpoint"));
523    }
524
525    /** Return the value of this token as a float
526     *  In this base class, we just throw an exception.
527     *  @return A float
528     *  @exception IllegalActionException Always thrown
529     */
530    public float floatValue() throws IllegalActionException {
531        throw new IllegalActionException(
532                notSupportedConversionMessage(this, "float"));
533    }
534
535    /** Return the type of this token.  Subclasses must implement this method
536     *  to return the correct type.
537     *  @return BaseType.SCALAR
538     */
539    @Override
540    public abstract Type getType();
541
542    /** Return a scalar token that contains the value of this token in the
543     *  units of the argument token. The unit category of the argument token
544     *  must be the same as that of this token, otherwise, an exception will
545     *  be thrown. The returned token is unitless.
546     *  @param units A scalar token that represents a unit.
547     *  @return A scalar token that does not have a unit.
548     *  @exception IllegalActionException If the unit category of the
549     *  argument token is not the same as that of this one.
550     */
551    public ScalarToken inUnitsOf(ScalarToken units)
552            throws IllegalActionException {
553        if (!_areUnitsEqual(units)) {
554            throw new IllegalActionException(
555                    notSupportedMessage("inUnitsOf", this, units)
556                            + " because the units are not the same.");
557        }
558
559        return (ScalarToken) this.divide(units);
560    }
561
562    /** Return the value of this token as an int.
563     *  In this base class, we just throw an exception.
564     *  @return The value of this token as an int.
565     *  @exception IllegalActionException Always thrown.
566     */
567    public int intValue() throws IllegalActionException {
568        throw new IllegalActionException(
569                notSupportedConversionMessage(this, "int"));
570    }
571
572    /** Test whether the value of this Token is close to the argument
573     *  Token.  The argument and this token are converted to
574     *  equivalent types, and then compared.  Generally, this is the
575     *  higher of the type of this token and the argument type.
576     *  Subclasses should implement the protected _isCloseTo() method
577     *  to perform the correct type-specific operation.
578     *  @see #isEqualTo
579     *  @param rightArgument The token to test closeness of this token with.
580     *  @param epsilon The value that we use to determine whether two
581     *   tokens are close.
582     *  @return A boolean token that contains the value true if the
583     *   units of this token and the argument token are the same, and their
584     *   values are close.
585     *  @exception IllegalActionException If the argument token is not
586     *   of a type that can be compared with this token, or the units
587     *   are not the same.
588     */
589    @Override
590    public final BooleanToken isCloseTo(Token rightArgument, double epsilon)
591            throws IllegalActionException {
592        // Note that if we had absolute(), subtraction() and islessThan()
593        // we could perhaps define this method for all tokens.  However,
594        // Precise classes like IntToken not bother doing the absolute(),
595        // subtraction(), and isLessThan() method calls and should go
596        // straight to isEqualTo().  Also, these methods might introduce
597        // exceptions because of type conversion issues.
598        int typeInfo = TypeLattice.compare(getType(), rightArgument);
599
600        if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) {
601            return _doIsCloseTo(rightArgument, epsilon);
602        } else if (typeInfo == CPO.HIGHER) {
603            ScalarToken convertedArgument = (ScalarToken) getType()
604                    .convert(rightArgument);
605
606            try {
607                return _doIsCloseTo(convertedArgument, epsilon);
608            } catch (IllegalActionException ex) {
609                // If the type-specific operation fails, then create a
610                // better error message that has the types of the
611                // arguments that were passed in.
612                throw new IllegalActionException(null, ex,
613                        notSupportedMessage("isCloseTo", this, rightArgument));
614            }
615        } else if (typeInfo == CPO.LOWER) {
616            return rightArgument.isCloseTo(this, epsilon);
617        } else {
618            throw new IllegalActionException(notSupportedIncomparableMessage(
619                    "isCloseTo", this, rightArgument));
620        }
621    }
622
623    /** Test for equality of the values of this Token and the argument
624     *  Token.  The argument and this token are converted to
625     *  equivalent types, and then compared.  Generally, this is the
626     *  higher of the type of this token and the argument type.  This
627     *  method defers to the _isEqualTo() method to perform a
628     *  type-specific equality check.  Derived classes should implement
629     *  that method to provide type specific actions for equality
630     *  testing.
631     *
632     *  @see #isCloseTo
633     *  @param rightArgument The token with which to test equality.
634     *  @exception IllegalActionException If this method is not
635     *  supported by the derived class.
636     *  @return A boolean token that contains the value true if the
637     *  values and units of this token and the argument token are the same.
638     */
639    @Override
640    public final BooleanToken isEqualTo(Token rightArgument)
641            throws IllegalActionException {
642        int typeInfo = TypeLattice.compare(getType(), rightArgument);
643
644        if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) {
645            return _doIsEqualTo(rightArgument);
646        } else if (typeInfo == CPO.HIGHER) {
647            ScalarToken convertedArgument = (ScalarToken) getType()
648                    .convert(rightArgument);
649
650            try {
651                return _doIsEqualTo(convertedArgument);
652            } catch (IllegalActionException ex) {
653                // If the type-specific operation fails, then create a
654                // better error message that has the types of the
655                // arguments that were passed in.
656                throw new IllegalActionException(null, ex,
657                        notSupportedMessage("isEqualTo", this, rightArgument));
658            }
659        } else if (typeInfo == CPO.LOWER) {
660            return rightArgument.isEqualTo(this);
661        } else {
662            throw new IllegalActionException(notSupportedIncomparableMessage(
663                    "isEqualTo", this, rightArgument));
664        }
665    }
666
667    /** Check whether the value of this token is strictly greater than
668     *  that of the argument token.  The argument and this token are
669     *  converted to equivalent types, and then compared.  Generally,
670     *  this is the higher of the type of this token and the argument
671     *  type.  This method defers to the _isLessThan() method to perform
672     *  a type-specific equality check.  Derived classes should
673     *  implement that method to provide type specific actions for
674     *  equality testing.
675     *
676     *  @param rightArgument The token to compare against.
677     *  @return A boolean token with value true if this token has the
678     *  same units as the argument, and is strictly greater than the
679     *  argument.
680     *  @exception IllegalActionException If the argument token and
681     *  this token are of incomparable types, or have different units,
682     *  or the operation does not make sense for the given types.
683     */
684    public final BooleanToken isGreaterThan(ScalarToken rightArgument)
685            throws IllegalActionException {
686        int typeInfo = TypeLattice.compare(getType(), rightArgument);
687
688        if (typeInfo == CPO.SAME) {
689            return rightArgument._doIsLessThan(this);
690        } else if (typeInfo == CPO.HIGHER) {
691            ScalarToken convertedArgument = (ScalarToken) getType()
692                    .convert(rightArgument);
693
694            try {
695                return convertedArgument._doIsLessThan(this);
696            } catch (IllegalActionException ex) {
697                // If the type-specific operation fails, then create a
698                // better error message that has the types of the
699                // arguments that were passed in.
700                throw new IllegalActionException(null, ex, notSupportedMessage(
701                        "isGreaterThan", this, rightArgument));
702            }
703        } else if (typeInfo == CPO.LOWER) {
704            return rightArgument.isLessThan(this);
705        } else {
706            throw new IllegalActionException(notSupportedIncomparableMessage(
707                    "isGreaterThan", this, rightArgument));
708        }
709    }
710
711    /** Check whether the value of this token is strictly less than that of the
712     *  argument token.
713     *
714     *  @param rightArgument The token to compare against.
715     *  @return A boolean token with value true if this token is strictly
716     *  less than the argument.
717     *  @exception IllegalActionException If the argument token and
718     *  this token are of incomparable types, or have different units,
719     *  or the operation does not make sense for the given types.
720     */
721    @Override
722    public final BooleanToken isLessThan(PartiallyOrderedToken rightArgument)
723            throws IllegalActionException {
724        if (!(rightArgument instanceof ScalarToken)) {
725            //// FIXME: Since PartiallyOrderedToken is an interface, we cannot do:
726            //throw new IllegalActionException(null, ex, notSupportedMessage(
727            //        "isLessThan", this, rightArgument))
728            //// and must do this instead:
729            throw new IllegalActionException(
730                    "Cannot compare ScalarToken with " + rightArgument);
731        }
732        return isLessThan((ScalarToken) rightArgument);
733    }
734
735    /** Check whether the value of this token is strictly less than that of the
736     *  argument token.  The argument and this token are converted to
737     *  equivalent types, and then compared.  Generally, this is the
738     *  higher of the type of this token and the argument type.  This
739     *  method defers to the _isLessThan() method to perform a
740     *  type-specific equality check.  Derived classes should implement
741     *  that method to provide type specific actions for equality
742     *  testing.
743     *
744     *  @param rightArgument The token to compare against.
745     *  @return A boolean token with value true if this token has the
746     *  same units as the argument, and is strictly less than the
747     *  argument.
748     *  @exception IllegalActionException If the argument token and
749     *  this token are of incomparable types, or have different units,
750     *  or the operation does not make sense for the given types.
751     */
752    public final BooleanToken isLessThan(ScalarToken rightArgument)
753            throws IllegalActionException {
754        int typeInfo = TypeLattice.compare(getType(), rightArgument);
755
756        if (typeInfo == CPO.SAME) {
757            return _doIsLessThan(rightArgument);
758        } else if (typeInfo == CPO.HIGHER) {
759            ScalarToken convertedArgument = (ScalarToken) getType()
760                    .convert(rightArgument);
761
762            try {
763                return _doIsLessThan(convertedArgument);
764            } catch (IllegalActionException ex) {
765                // If the type-specific operation fails, then create a
766                // better error message that has the types of the
767                // arguments that were passed in.
768                throw new IllegalActionException(null, ex,
769                        notSupportedMessage("isLessThan", this, rightArgument));
770            }
771        } else if (typeInfo == CPO.LOWER) {
772            return rightArgument.isGreaterThan(this);
773        } else {
774            throw new IllegalActionException(notSupportedIncomparableMessage(
775                    "isLessThan", this, rightArgument));
776        }
777    }
778
779    /** Returns a token representing the result of shifting the bits
780     *  of this token towards the most significant bit, filling the
781     *  least significant bits with zeros.
782     *  @param bits The number of bits to shift.
783     *  @return The left shift.
784     *  @exception IllegalActionException If the given token is not
785     *  compatible for this operation, or the operation does not make
786     *  sense for this type.
787     */
788    public ScalarToken leftShift(int bits) throws IllegalActionException {
789        throw new IllegalActionException(
790                notSupportedMessage("leftShift", this, new IntToken(bits)));
791    }
792
793    /** Returns a token representing the result of shifting the bits
794     *  of this token towards the least significant bit, filling the
795     *  most significant bits with zeros.  This treats the value as an
796     *  unsigned number, which may have the effect of destroying the
797     *  sign of the value.
798     *  @param bits The number of bits to shift.
799     *  @return The right shift.
800     *  @exception IllegalActionException If the given token is not
801     *  compatible for this operation, or the operation does not make
802     *  sense for this type.
803     */
804    public ScalarToken logicalRightShift(int bits)
805            throws IllegalActionException {
806        throw new IllegalActionException(notSupportedMessage(
807                "logicalRightShift", this, new IntToken(bits)));
808    }
809
810    /** Return the value of this token as a long integer.
811     *  In this base class, we just throw an exception.
812     *  @return The value of this token as a long.
813     *  @exception IllegalActionException Always thrown.
814     */
815    public long longValue() throws IllegalActionException {
816        throw new IllegalActionException(
817                notSupportedConversionMessage(this, "long"));
818    }
819
820    /** Return a new token whose value is the value of this token
821     *  modulo the value of the argument token.  Type conversion also
822     *  occurs here, so that the operation is performed at the least
823     *  type necessary to ensure precision.  The returned type is the
824     *  same as the type chosen for the operation, which is the higher
825     *  of the type of this token and the argument type.  Subclasses
826     *  should implement the protected _modulo() method to perform the
827     *  correct type-specific operation.
828     *  @param rightArgument The token to modulo with this token.
829     *  @return A new token containing the result.
830     *  @exception IllegalActionException If the argument token and
831     *  this token are of incomparable types, or have different units,
832     *  or the operation does not make sense for the given types.
833     */
834    @Override
835    public final Token modulo(Token rightArgument)
836            throws IllegalActionException {
837        int typeInfo = TypeLattice.compare(getType(), rightArgument);
838
839        if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) {
840            return _doModulo(rightArgument);
841        } else if (typeInfo == CPO.HIGHER) {
842            ScalarToken convertedArgument = (ScalarToken) getType()
843                    .convert(rightArgument);
844
845            try {
846                return _doModulo(convertedArgument);
847            } catch (IllegalActionException ex) {
848                // If the type-specific operation fails, then create a
849                // better error message that has the types of the
850                // arguments that were passed in.
851                throw new IllegalActionException(null, ex,
852                        notSupportedMessage("modulo", this, rightArgument));
853            }
854        } else if (typeInfo == CPO.LOWER) {
855            return rightArgument.moduloReverse(this);
856        } else {
857            // Items being moduloed are incomparable.  However, modulo
858            // may still be possible because the LUB of the types
859            // might support it. E.g., int mod arrayType(int, 2),
860            // where the LUB is arrayType(int).
861            Type lubType = (Type) TypeLattice.lattice()
862                    .leastUpperBound(getType(), rightArgument.getType());
863
864            // If the LUB is a new type, try it.
865            if (lubType != null && !lubType.equals(getType())) {
866                Token lub = lubType.convert(this);
867
868                // Caution: convert() might return this again, e.g.
869                // if lubType is general.  Only proceed if the conversion
870                // returned a new type.
871                if (!lub.getType().equals(getType())) {
872                    return lub.modulo(rightArgument);
873                }
874            }
875
876            // LUB does not support it, but it still might be
877            // possible, e.g. with expressions like double modulo {double}.
878            // Only moduloReverse() could support it at this time however.
879            // This will throw an exception if it is not supported.
880            return rightArgument.moduloReverse(this);
881        }
882    }
883
884    /** Return a new token whose value is the value of this token
885     *  modulo the value of the argument token.  Type conversion also
886     *  occurs here, so that the operation is performed at the least
887     *  type necessary to ensure precision.  The returned type is the
888     *  same as the type chosen for the operation, which is the higher
889     *  of the type of this token and the argument type.  Subclasses
890     *  should implement the protected _modulo() method to perform the
891     *  correct type-specific operation.
892     *  @param leftArgument The token to apply modulo to by the value
893     *  of this token.
894     *  @return A new token containing the result.
895     *  @exception IllegalActionException If the argument token and
896     *  this token are of incomparable types, or have different units,
897     *  or the operation does not make sense for the given types.
898     */
899    @Override
900    public final Token moduloReverse(Token leftArgument)
901            throws IllegalActionException {
902        int typeInfo = TypeLattice.compare(leftArgument, getType());
903
904        // We would normally expect this to be LOWER, since this will almost
905        // always be called by modulo, so put that case first.
906        if (typeInfo == CPO.LOWER) {
907            ScalarToken convertedArgument = (ScalarToken) getType()
908                    .convert(leftArgument);
909
910            try {
911                return convertedArgument._doModulo(this);
912            } catch (IllegalActionException ex) {
913                // If the type-specific operation fails, then create a
914                // better error message that has the types of the
915                // arguments that were passed in.
916                throw new IllegalActionException(null, ex, notSupportedMessage(
917                        "moduloReverse", this, leftArgument));
918            }
919        } else if (typeInfo == CPO.SAME) {
920            return ((ScalarToken) leftArgument)._doModulo(this);
921        } else if (typeInfo == CPO.HIGHER) {
922            return leftArgument.modulo(this);
923        } else {
924            throw new IllegalActionException(notSupportedIncomparableMessage(
925                    "moduloReverse", this, leftArgument));
926        }
927    }
928
929    /** Return a new token whose value is the value of this token
930     *  multiplied by the value of the argument token.  Type
931     *  conversion also occurs here, so that the operation is
932     *  performed at the least type necessary to ensure precision.
933     *  The returned type is the same as the type chosen for the
934     *  operation, which is the higher of the type of this token and
935     *  the argument type.  Subclasses should implement the protected
936     *  _multiply() method to perform the correct type-specific
937     *  operation.
938     *  @param rightArgument The token to multiply this token by.
939     *  @return A new token containing the result.
940     *  @exception IllegalActionException If the argument token and
941     *  this token are of incomparable types, or the operation does
942     *  not make sense for the given types.
943     */
944    @Override
945    public final Token multiply(Token rightArgument)
946            throws IllegalActionException {
947        int typeInfo = TypeLattice.compare(getType(), rightArgument);
948
949        if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) {
950            return _doMultiply(rightArgument);
951        } else if (typeInfo == CPO.HIGHER) {
952            ScalarToken convertedArgument = (ScalarToken) getType()
953                    .convert(rightArgument);
954
955            try {
956                return _doMultiply(convertedArgument);
957            } catch (IllegalActionException ex) {
958                // If the type-specific operation fails, then create a
959                // better error message that has the types of the
960                // arguments that were passed in.
961                throw new IllegalActionException(null, ex,
962                        notSupportedMessage("multiply", this, rightArgument));
963            }
964        } else if (typeInfo == CPO.LOWER
965                || rightArgument instanceof MatrixToken) {
966            // NOTE: If the right argument is an instance of MatrixToken,
967            // then we try reversing the multiply.
968            return rightArgument.multiplyReverse(this);
969        } else {
970            // Items being multiplied are incomparable.
971            // However, multiplication may still be possible because
972            // the LUB of the types might support it. E.g., [double]*complex,
973            // where the LUB is [complex].
974            Type lubType = (Type) TypeLattice.lattice()
975                    .leastUpperBound(getType(), rightArgument.getType());
976
977            // If the LUB is a new type, try it.
978            if (lubType != null && !lubType.equals(getType())) {
979                Token lub = lubType.convert(this);
980
981                // Caution: convert() might return this again, e.g.
982                // if lubType is general.  Only proceed if the conversion
983                // returned a new type.
984                if (!lub.getType().equals(getType())) {
985                    return lub.multiply(rightArgument);
986                }
987            }
988
989            // LUB does not support it, but it still might be
990            // possible, e.g. with expressions like double * {double}.
991            // Only multiplyReverse() could support it at this time however.
992            // This will throw an exception if it is not supported.
993            return rightArgument.multiplyReverse(this);
994        }
995    }
996
997    /** Return a new token whose value is the value of this token
998     *  multiplied by the value of the argument token.  Type
999     *  conversion also occurs here, so that the operation is
1000     *  performed at the least type necessary to ensure precision.
1001     *  The returned type is the same as the type chosen for the
1002     *  operation, which is the higher of the type of this token and
1003     *  the argument type.  Subclasses should implement the protected
1004     *  _multiply() method to perform the correct type-specific
1005     *  operation.
1006     *  @param leftArgument The token to be multiplied by the value of
1007     *  this token.
1008     *  @return A new token containing the result.
1009     *  @exception IllegalActionException If the argument token and
1010     *  this token are of incomparable types, or the operation does
1011     *  not make sense for the given types.
1012     */
1013    @Override
1014    public final Token multiplyReverse(Token leftArgument)
1015            throws IllegalActionException {
1016        int typeInfo = TypeLattice.compare(leftArgument, getType());
1017
1018        // We would normally expect this to be LOWER, since this will almost
1019        // always be called by multiply, so put that case first.
1020        if (typeInfo == CPO.LOWER) {
1021            ScalarToken convertedArgument = (ScalarToken) getType()
1022                    .convert(leftArgument);
1023
1024            try {
1025                return convertedArgument._doMultiply(this);
1026            } catch (IllegalActionException ex) {
1027                // If the type-specific operation fails, then create a
1028                // better error message that has the types of the
1029                // arguments that were passed in.
1030                throw new IllegalActionException(null, ex, notSupportedMessage(
1031                        "multiplyReverse", this, leftArgument));
1032            }
1033        } else if (typeInfo == CPO.SAME) {
1034            return ((ScalarToken) leftArgument)._doMultiply(this);
1035        } else if (typeInfo == CPO.HIGHER
1036                || leftArgument instanceof MatrixToken) {
1037            // NOTE: If the left argument is an instance of MatrixToken,
1038            // then we try reversing the multiply.
1039            return leftArgument.multiply(this);
1040        } else {
1041            // Items being multiplied are incomparable.
1042            // However, multiplication may still be possible because
1043            // the LUB of the types might support it. E.g., [double]*complex,
1044            // where the LUB is [complex].
1045            Type lubType = (Type) TypeLattice.lattice()
1046                    .leastUpperBound(getType(), leftArgument.getType());
1047
1048            // If the LUB is a new type, try it.
1049            if (!lubType.equals(getType())) {
1050                Token lub = lubType.convert(this);
1051
1052                // Caution: convert() might return this again, e.g.
1053                // if lubType is general.  Only proceed if the conversion
1054                // returned a new type.
1055                if (!lub.getType().equals(getType())) {
1056                    return lub.multiplyReverse(leftArgument);
1057                }
1058            }
1059
1060            throw new IllegalActionException(notSupportedIncomparableMessage(
1061                    "multiplyReverse", leftArgument, this));
1062        }
1063    }
1064
1065    /** Returns a token representing the result of shifting the bits
1066     *  of this token towards the least significant bit, filling the
1067     *  most significant bits with the sign of the value.  This preserves
1068     *  the sign of the result.
1069     *  @param bits The number of bits to shift.
1070     *  @return The right shift.
1071     *  @exception IllegalActionException If the given token is not
1072     *  compatible for this operation, or the operation does not make
1073     *  sense for this type.
1074     */
1075    public ScalarToken rightShift(int bits) throws IllegalActionException {
1076        throw new IllegalActionException(
1077                notSupportedMessage("rightShift", this, new IntToken(bits)));
1078    }
1079
1080    /** Set the unit category this token belongs to.  This method is
1081     *  called from within the units system to create tokens
1082     *  representing base units.  This method should not be called by
1083     *  user code.
1084     *  @param index The unit category index.
1085     *  @deprecated We need a better way of manufacturing the tokens
1086     *  for base units, since this method violates the immutability of
1087     *  tokens.
1088     */
1089    @Deprecated
1090    public void setUnitCategory(int index) {
1091        // FIXME: shouldn't this be protected???  it violates the
1092        // immutability of tokens.
1093        _unitCategoryExponents = UnitUtilities.newUnitArrayInCategory(index);
1094    }
1095
1096    /** Return the value of this token as a short.
1097     *  In this base class, we just throw an exception.
1098     *  @return A short
1099     *  @exception IllegalActionException Always thrown
1100     */
1101    public short shortValue() throws IllegalActionException {
1102        throw new IllegalActionException(
1103                notSupportedConversionMessage(this, "short"));
1104    }
1105
1106    /** Return a new token whose value is the value of the argument
1107     *  token subtracted from the value of this token.  Type
1108     *  conversion also occurs here, so that the operation is
1109     *  performed at the least type necessary to ensure precision.
1110     *  The returned type is the same as the type chosen for the
1111     *  operation, which is the higher of the type of this token and
1112     *  the argument type.  Subclasses should implement the protected
1113     *  _subtract() method to perform the correct type-specific
1114     *  operation.
1115     *  @param rightArgument The token to subtract from this token.
1116     *  @return A new token containing the result.
1117     *  @exception IllegalActionException If the argument token and
1118     *  this token are of incomparable types, or have different units,
1119     *  or the operation does not make sense for the given types.
1120     */
1121    @Override
1122    public final Token subtract(Token rightArgument)
1123            throws IllegalActionException {
1124        int typeInfo = TypeLattice.compare(getType(), rightArgument);
1125
1126        if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) {
1127            return _doSubtract(rightArgument);
1128        } else if (typeInfo == CPO.HIGHER) {
1129            ScalarToken convertedArgument = (ScalarToken) getType()
1130                    .convert(rightArgument);
1131
1132            try {
1133                return _doSubtract(convertedArgument);
1134            } catch (IllegalActionException ex) {
1135                // If the type-specific operation fails, then create a
1136                // better error message that has the types of the
1137                // arguments that were passed in.
1138                throw new IllegalActionException(null, ex,
1139                        notSupportedMessage("subtract", this, rightArgument));
1140            }
1141        } else if (typeInfo == CPO.LOWER
1142                || rightArgument instanceof MatrixToken) {
1143            // NOTE: If the right argument is an instance of MatrixToken,
1144            // then we try reversing the subtract.
1145            return rightArgument.subtractReverse(this);
1146        } else {
1147            // Items being subtracted are incomparable.
1148            // However, addition may still be possible because
1149            // the LUB of the types might support it. E.g., [double]-complex,
1150            // where the LUB is [complex].
1151            Type lubType = (Type) TypeLattice.lattice()
1152                    .leastUpperBound(getType(), rightArgument.getType());
1153
1154            // If the LUB is a new type, try it.
1155            if (!lubType.equals(getType())) {
1156                Token lub = lubType.convert(this);
1157
1158                // Caution: convert() might return this again, e.g.
1159                // if lubType is general.  Only proceed if the conversion
1160                // returned a new type.
1161                if (!lub.getType().equals(getType())) {
1162                    return lub.subtract(rightArgument);
1163                }
1164            }
1165
1166            throw new IllegalActionException(notSupportedIncomparableMessage(
1167                    "subtract", this, rightArgument));
1168        }
1169    }
1170
1171    /** Return a new token whose value is the value of the argument
1172     *  token subtracted from the value of this token.  Type
1173     *  conversion also occurs here, so that the operation is
1174     *  performed at the least type necessary to ensure precision.
1175     *  The returned type is the same as the type chosen for the
1176     *  operation, which is the higher of the type of this token and
1177     *  the argument type.  Subclasses should implement the protected
1178     *  _subtract() method to perform the correct type-specific
1179     *  operation.
1180     *  @param leftArgument The token to subtract this token from.
1181     *  @return A new token containing the result.
1182     *  @exception IllegalActionException If the argument token and
1183     *  this token are of incomparable types, or have different units,
1184     *  or the operation does not make sense for the given types.
1185     */
1186    @Override
1187    public final Token subtractReverse(Token leftArgument)
1188            throws IllegalActionException {
1189        int typeInfo = TypeLattice.compare(leftArgument, getType());
1190
1191        // We would normally expect this to be LOWER, since this will almost
1192        // always be called by subtract, so put that case first.
1193        if (typeInfo == CPO.LOWER) {
1194            ScalarToken convertedArgument = (ScalarToken) getType()
1195                    .convert(leftArgument);
1196
1197            try {
1198                return convertedArgument._doSubtract(this);
1199            } catch (IllegalActionException ex) {
1200                // If the type-specific operation fails, then create a
1201                // better error message that has the types of the
1202                // arguments that were passed in.
1203                throw new IllegalActionException(null, ex, notSupportedMessage(
1204                        "subtractReverse", this, leftArgument));
1205            }
1206        } else if (typeInfo == CPO.SAME) {
1207            return ((ScalarToken) leftArgument)._doSubtract(this);
1208        } else if (typeInfo == CPO.HIGHER) {
1209            return leftArgument.subtract(this);
1210        } else {
1211            throw new IllegalActionException(notSupportedIncomparableMessage(
1212                    "subtractReverse", this, leftArgument));
1213        }
1214    }
1215
1216    /** Return the string representation of the units of this token.
1217     *  The general format of the returned string is
1218     *  "(l_1 * l_2 * ... * l_m) / (s_1 * s_2 * ... * s_n)".
1219     *  For example: "(meter * kilogram) / (second * second)".
1220     *  If m or n is 1, then the parenthesis above or below "/" is
1221     *  omitted. For example: "meter / second".
1222     *  If there is no term above "/", the format becomes
1223     *  "1 / (s_1 * s_2 * ... * s_n)". For example: "1 / meter".
1224     *  If this token does not have a unit, return an empty string.
1225     *  @return A string representation of the units of this token.
1226     */
1227    public String unitsString() {
1228        return UnitUtilities.unitsString(_unitCategoryExponents);
1229    }
1230
1231    ///////////////////////////////////////////////////////////////////
1232    ////                         protected methods                 ////
1233
1234    /** Return a ScalarToken containing the absolute value of the
1235     *  value of this token. If this token contains a non-negative
1236     *  number, it is returned directly; otherwise, a new token is
1237     *  returned.  Note that it is explicitly allowable to return this
1238     *  token, since the units are the same.  Derived classes must implement
1239     *  this method in a type-specific fashion.
1240     *  @return A ScalarToken, which is likely, but not required to be
1241     *  the same type as this token.
1242     */
1243    protected abstract ScalarToken _absolute();
1244
1245    /** Return a new token whose value is the value of the argument
1246     *  token added to the value of this token.  It is guaranteed by
1247     *  the caller that the type of the argument is the same as the
1248     *  type of this class.  This method should be overridden in
1249     *  derived classes to provide type-specific operation and return
1250     *  a token of the appropriate subclass.
1251     *  @param rightArgument The token to add to this token.
1252     *  @exception IllegalActionException If this method is not
1253     *  supported by the derived class.
1254     *  @return A new token containing the result.
1255     */
1256    protected abstract ScalarToken _add(ScalarToken rightArgument)
1257            throws IllegalActionException;
1258
1259    /** Add the corresponding unit category exponents.
1260     *  @param token A token whose exponent will be added with the
1261     *   exponents of this token.
1262     *  @return An int array containing the addition result, or null
1263     *   if the result is unitless.
1264     */
1265    protected int[] _addCategoryExponents(ScalarToken token) {
1266        return UnitUtilities.addUnitsArray(_unitCategoryExponents,
1267                token._unitCategoryExponents);
1268    }
1269
1270    /** Return true if the units of this token are the same as that of the
1271     *  argument token. If both tokens do not have units, return true.
1272     *  @param scalarToken A scalar token.
1273     *  @return True if the units of this token is the same as that of the
1274     *   argument token; false otherwise.
1275     */
1276    protected boolean _areUnitsEqual(ScalarToken scalarToken) {
1277        return UnitUtilities.areUnitArraysEqual(_unitCategoryExponents,
1278                scalarToken._unitCategoryExponents);
1279    }
1280
1281    /** Returns a token representing the bitwise AND of this token and
1282     *  the given token.
1283     *  @param rightArgument The ScalarToken to bitwise AND with this one.
1284     *  @return The bitwise AND.
1285     *  @exception IllegalActionException If the given token is not
1286     *  compatible for this operation, or the operation does not make
1287     *  sense for this type.
1288     */
1289    protected abstract ScalarToken _bitwiseAnd(ScalarToken rightArgument)
1290            throws IllegalActionException;
1291
1292    /** Returns a token representing the bitwise NOT of this token.
1293     *  @return The bitwise NOT of this token.
1294     *  @exception IllegalActionException If the given token is not
1295     *  compatible for this operation, or the operation does not make
1296     *  sense for this type.
1297     */
1298    protected abstract ScalarToken _bitwiseNot() throws IllegalActionException;
1299
1300    /** Returns a token representing the bitwise OR of this token and
1301     *  the given token.
1302     *  @param rightArgument The ScalarToken to bitwise OR with this one.
1303     *  @return The bitwise OR.
1304     *  @exception IllegalActionException If the given token is not
1305     *  compatible for this operation, or the operation does not make
1306     *  sense for this type.
1307     */
1308    protected abstract ScalarToken _bitwiseOr(ScalarToken rightArgument)
1309            throws IllegalActionException;
1310
1311    /** Returns a token representing the bitwise XOR of this token and
1312     *  the given token.
1313     *  @param rightArgument The ScalarToken to bitwise XOR with this one.
1314     *  @return The bitwise XOR.
1315     *  @exception IllegalActionException If the given token is not
1316     *  compatible for this operation, or the operation does not make
1317     *  sense for this type.
1318     */
1319    protected abstract ScalarToken _bitwiseXor(ScalarToken rightArgument)
1320            throws IllegalActionException;
1321
1322    /** Return a copy of the unit category exponents array. If this
1323     *  token does not have a unit, return null;
1324     *  @return An int array that is a copy of the unit category
1325     *  exponents of this token.
1326     */
1327    protected int[] _copyOfCategoryExponents() {
1328        return UnitUtilities.copyUnitsArray(_unitCategoryExponents);
1329    }
1330
1331    /** Return a new token whose value is the value of this token
1332     *  divided by the value of the argument token.  It is guaranteed
1333     *  by the caller that the type of the argument is the same as the
1334     *  type of this class.  This method should be overridden in
1335     *  derived classes to provide type-specific operation and return
1336     *  a token of the appropriate subclass.
1337     *  @param rightArgument The token to divide this token by.
1338     *  @exception IllegalActionException If this method is not
1339     *  supported by the derived class.
1340     *  @return A new Token containing the result.
1341     */
1342    protected abstract ScalarToken _divide(ScalarToken rightArgument)
1343            throws IllegalActionException;
1344
1345    /** Test whether the value of this token is close to the first argument,
1346     *  where "close" means that the distance between them is less than
1347     *  or equal to the second argument.  This method only makes sense
1348     *  for tokens where the distance between them is reasonably
1349     *  represented as a double.
1350     *  @param rightArgument The token to compare to this token.
1351     *  @param epsilon The value that we use to determine whether two
1352     *   tokens are close.
1353     *  @return A token containing true if the value of the first
1354     *   argument is close to the value of this token.
1355     *  @exception IllegalActionException If there is a problem processing
1356     *  the rightArgument.
1357     */
1358    protected abstract BooleanToken _isCloseTo(ScalarToken rightArgument,
1359            double epsilon) throws IllegalActionException;
1360
1361    /** Test for equality of the values of this token and the argument.
1362     *  This base class delegates to the equals() method.
1363     *  @param token The token to compare to this token.
1364     *  @return A token containing true if the value element of the first
1365     *   argument is equal to the value of this token.
1366     *  @exception IllegalActionException Not thrown in this base class.
1367     */
1368    protected BooleanToken _isEqualTo(ScalarToken token)
1369            throws IllegalActionException {
1370        return BooleanToken.getInstance(equals(token));
1371    }
1372
1373    /** Test for ordering of the values of this Token and the argument
1374     *  Token.  It is guaranteed by the caller that the type and
1375     *  units of the argument is the same as the type of this class.
1376     *  This method should be overridden in derived classes to provide
1377     *  type-specific operation and return a token of the appropriate
1378     *  subclass.
1379     *  @param rightArgument The token to add to this token.
1380     *  @exception IllegalActionException If this method is not
1381     *  supported by the derived class.
1382     *  @return A new Token containing the result.
1383     */
1384    protected abstract BooleanToken _isLessThan(ScalarToken rightArgument)
1385            throws IllegalActionException;
1386
1387    /** Return true if this token does not have a unit.
1388     *  @return True if this token does not have a unit.
1389     */
1390    protected boolean _isUnitless() {
1391        return UnitUtilities.isUnitless(_unitCategoryExponents);
1392    }
1393
1394    /** Return a new token whose value is the value of this token
1395     *  modulo the value of the argument token.  It is guaranteed by
1396     *  the caller that the type of the argument is the same as the
1397     *  type of this class.  This method should be overridden in
1398     *  derived classes to provide type-specific operation and return
1399     *  a token of the appropriate subclass.
1400     *  @param rightArgument The token to modulo this token by.
1401     *  @exception IllegalActionException If this method is not
1402     *   supported by the derived class.
1403     *  @return A new Token containing the result.
1404     */
1405    protected abstract ScalarToken _modulo(ScalarToken rightArgument)
1406            throws IllegalActionException;
1407
1408    /** Return a new token whose value is the value of this token
1409     *  multiplied by the value of the argument token.  It is
1410     *  guaranteed by the caller that the type of the argument is the
1411     *  same as the type of this class.  This method should be
1412     *  overridden in derived classes to provide type-specific
1413     *  operation and return a token of the appropriate subclass.
1414     *  @param rightArgument The token to multiply this token by.
1415     *  @exception IllegalActionException If this method is not
1416     *  supported by the derived class.
1417     *  @return A new Token containing the result.
1418     */
1419    protected abstract ScalarToken _multiply(ScalarToken rightArgument)
1420            throws IllegalActionException;
1421
1422    /** Return a new token whose value is the value of the argument
1423     *  token subtracted from the value of this token.  It is
1424     *  guaranteed by the caller that the type of the argument is the
1425     *  same as the type of this class.  This method should be
1426     *  overridden in derived classes to provide type-specific
1427     *  operation and return a token of the appropriate subclass.
1428     *  @param rightArgument The token to subtract from this token.
1429     *  @exception IllegalActionException If this method is not
1430     *  supported by the derived class.
1431     *  @return A new Token containing the result.
1432     */
1433    protected abstract ScalarToken _subtract(ScalarToken rightArgument)
1434            throws IllegalActionException;
1435
1436    /** Subtract the corresponding unit category exponents of the
1437     *  argument token from that of this token.
1438     *  @param token A token whose exponent will be subtracted from
1439     *  the exponents of this token.
1440     *  @return An array of int containing the result, or null if the
1441     *  result is unitless.
1442     */
1443    protected int[] _subtractCategoryExponents(ScalarToken token) {
1444        return UnitUtilities.subtractUnitsArray(_unitCategoryExponents,
1445                token._unitCategoryExponents);
1446    }
1447
1448    ///////////////////////////////////////////////////////////////////
1449    ////                         protected variables               ////
1450
1451    /** The unit category exponents.
1452     *  The unit system contains a set of base unit categories and derived
1453     *  categories. The base categories are customizable by the user.
1454     *  For example, the user may choose to use the SI unit system which
1455     *  has 7 base categories: length, mass, time, electric current,
1456     *  thermodynamic temperature, amount of substance, and luminous
1457     *  intensity. The customization is done by defining a MoML file to specify
1458     *  the categories and the units in each category. Each category has an
1459     *  index, assigned by the order the category appears in the MoML file.
1460     *  Derived units are recorded by the exponents of the category. For
1461     *  example, the category speed, which is length/time, is stored by an
1462     *  exponent of 1 for the length category, and an exponent of -1 for the
1463     *  time category.
1464     *  This array records the exponents of the base categories.
1465     */
1466    protected int[] _unitCategoryExponents = null;
1467
1468    ///////////////////////////////////////////////////////////////////
1469    ////                         private methods                   ////
1470
1471    /** Return a new token whose value is the value of the argument
1472     *  Token added to the value of this Token.  It is guaranteed by
1473     *  the caller that the type of the argument is the same as the
1474     *  type of this class and has the same units as this token.  The
1475     *  resulting token will also have the same type and units.  This
1476     *  method defers to the _add() method that takes a ScalarToken.
1477     *  Derived classes should implement that method instead to
1478     *  provide type-specific operation.
1479     *  @param rightArgument The token to add to this token.
1480     *  @return A new Token containing the result.
1481     *  If either this token or the argument token is a nil token, then
1482     *  then {@link ptolemy.data.Token#NIL} is returned.
1483     *  @exception IllegalActionException If this operation is not
1484     *  supported by the derived class.
1485     */
1486    private Token _doAdd(Token rightArgument) throws IllegalActionException {
1487        if (isNil() || rightArgument.isNil()) {
1488            return getType().convert(Token.NIL);
1489        }
1490
1491        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1492        if (!_areUnitsEqual(convertedArgument)) {
1493            throw new IllegalActionException(
1494                    notSupportedMessage("add", this, rightArgument)
1495                            + " because the units are not the same.");
1496        }
1497
1498        ScalarToken result = _add(convertedArgument);
1499        if (_unitCategoryExponents != null && !_isUnitless()) {
1500            result._unitCategoryExponents = _copyOfCategoryExponents();
1501        }
1502        return result;
1503    }
1504
1505    /*  Return a new token whose value is the value of the argument
1506     *  Token bitwise ANDed to the value of this Token.  It is guaranteed
1507     *  by the caller that the type of the argument is the same as the
1508     *  type of this class.  The resulting token will also have the same
1509     *  type. This method checks that the two tokens have the same units
1510     *  and throws an exception if the units are not the same. The resulting
1511     *  token will have the same units as the operands. This method defers
1512     *  to the _bitwiseAnd() method that takes a ScalarToken.
1513     *  @param rightArgument The token to bitwise AND to this token.
1514     *  @return A new Token containing the result.
1515     *  If either this token or the argument token is a nil token, then
1516     *  then {@link ptolemy.data.Token#NIL} is returned.
1517     *  @exception IllegalActionException If this operation is not
1518     *  supported by the derived class.
1519     */
1520    private BitwiseOperationToken _doBitwiseAnd(Token rightArgument)
1521            throws IllegalActionException {
1522        if (isNil() || rightArgument.isNil()) {
1523            return (BitwiseOperationToken) getType().convert(Token.NIL);
1524        }
1525        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1526
1527        if (!_areUnitsEqual(convertedArgument)) {
1528            throw new IllegalActionException(
1529                    notSupportedMessage("bitwiseAnd", this, rightArgument)
1530                            + " because the units of this token: "
1531                            + unitsString()
1532                            + " are not the same as those of the argument: "
1533                            + convertedArgument.unitsString());
1534        }
1535
1536        ScalarToken result = _bitwiseAnd(convertedArgument);
1537        if (_unitCategoryExponents != null && !_isUnitless()) {
1538            result._unitCategoryExponents = _copyOfCategoryExponents();
1539        }
1540        return result;
1541    }
1542
1543    /*  Return a new token whose value is the value of the argument
1544     *  Token bitwise ORed to the value of this Token.  It is guaranteed
1545     *  by the caller that the type of the argument is the same as the
1546     *  type of this class.  The resulting token will also have the same
1547     *  type. This method checks that the two tokens have the same units
1548     *  and throws an exception if the units are not the same. The resulting
1549     *  token will have the same units as the operands. This method defers
1550     *  to the _bitwiseOr() method that takes a ScalarToken.
1551     *  @param rightArgument The token to bitwise OR to this token.
1552     *  @return A new Token containing the result.
1553     *  If either this token or the argument token is a nil token, then
1554     *  then {@link ptolemy.data.Token#NIL} is returned.
1555     *  @exception IllegalActionException If this operation is not
1556     *  supported by the derived class.
1557     */
1558    private BitwiseOperationToken _doBitwiseOr(Token rightArgument)
1559            throws IllegalActionException {
1560        if (isNil() || rightArgument.isNil()) {
1561            return (BitwiseOperationToken) getType().convert(Token.NIL);
1562        }
1563
1564        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1565
1566        if (!_areUnitsEqual(convertedArgument)) {
1567            throw new IllegalActionException(
1568                    notSupportedMessage("bitwiseOr", this, rightArgument)
1569                            + " because the units of this token: "
1570                            + unitsString()
1571                            + " are not the same as those of the argument: "
1572                            + convertedArgument.unitsString());
1573        }
1574
1575        ScalarToken result = _bitwiseOr(convertedArgument);
1576        if (_unitCategoryExponents != null && !_isUnitless()) {
1577            result._unitCategoryExponents = _copyOfCategoryExponents();
1578        }
1579        return result;
1580    }
1581
1582    /*  Return a new token whose value is the value of the argument
1583     *  Token bitwise XORed to the value of this Token.  It is guaranteed
1584     *  by the caller that the type of the argument is the same as the
1585     *  type of this class.  The resulting token will also have the same
1586     *  type. This method checks that the two tokens have the same units
1587     *  and throws an exception if the units are not the same. The resulting
1588     *  token will have the same units as the operands. This method defers
1589     *  to the _bitwiseXOR() method that takes a ScalarToken.
1590     *  @param rightArgument The token to bitwise XOR to this token.
1591     *  @return A new Token containing the result.
1592     *  If either this token or the argument token is a nil token, then
1593     *  then {@link ptolemy.data.Token#NIL} is returned.
1594     *  @exception IllegalActionException If this operation is not
1595     *  supported by the derived class.
1596     */
1597    private BitwiseOperationToken _doBitwiseXor(Token rightArgument)
1598            throws IllegalActionException {
1599        if (isNil() || rightArgument.isNil()) {
1600            return (BitwiseOperationToken) getType().convert(Token.NIL);
1601        }
1602
1603        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1604
1605        if (!_areUnitsEqual(convertedArgument)) {
1606            throw new IllegalActionException(
1607                    notSupportedMessage("bitwiseXor", this, rightArgument)
1608                            + " because the units of this token: "
1609                            + unitsString()
1610                            + " are not the same as those of the argument: "
1611                            + convertedArgument.unitsString());
1612        }
1613
1614        ScalarToken result = _bitwiseXor(convertedArgument);
1615        if (_unitCategoryExponents != null && !_isUnitless()) {
1616            result._unitCategoryExponents = _copyOfCategoryExponents();
1617        }
1618        return result;
1619    }
1620
1621    /** Return a new token whose value is the value of this token
1622     *  divided by the value of the argument token.  It is guaranteed
1623     *  by the caller that the type of the argument is the same as the
1624     *  type of this class.  The resulting token will also have the
1625     *  same type and appropriate units.  This method defers to the
1626     *  _divide method that takes a ScalarToken.  Derived classes
1627     *  should implement that method instead to provide type-specific
1628     *  operation.
1629     *  @param rightArgument The token to divide this token by.
1630     *  @return A new Token containing the result.
1631     *  If either this token or the argument token is a nil token, then
1632     *  then {@link ptolemy.data.Token#NIL} is returned.
1633     *  @exception IllegalActionException If this operation is not
1634     *  supported by the derived class.
1635     */
1636    private Token _doDivide(Token rightArgument) throws IllegalActionException {
1637        if (isNil() || rightArgument.isNil()) {
1638            return getType().convert(Token.NIL);
1639        }
1640
1641        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1642
1643        ScalarToken result = _divide(convertedArgument);
1644
1645        // compute units
1646        if (_unitCategoryExponents != null && !_isUnitless()
1647                || convertedArgument._unitCategoryExponents != null
1648                        && !convertedArgument._isUnitless()) {
1649            result._unitCategoryExponents = _subtractCategoryExponents(
1650                    convertedArgument);
1651        }
1652        return result;
1653    }
1654
1655    /** Test for closeness of the values of this Token and the
1656     *  argument Token.  It is guaranteed by the caller that the type
1657     *  and units of the argument is the same as the type of this
1658     *  class. This method may defer to the _isCloseTo() method that
1659     *  takes a ScalarToken.  Derived classes should implement that
1660     *  method instead to provide type-specific operation.
1661     *  @param rightArgument The token with which to test closeness.
1662     *  @return A BooleanToken which contains the result of the test.
1663     *  If either this token or the argument token is a nil token, then
1664     *  a BooleanToken that contains the value false is returned.
1665     *  @exception IllegalActionException If the units of the argument
1666     *  are not the same as the units of this token, or the method is
1667     *  not supported by the derived class.
1668     */
1669    private BooleanToken _doIsCloseTo(Token rightArgument, double epsilon)
1670            throws IllegalActionException {
1671        if (isNil() || rightArgument.isNil()) {
1672            return BooleanToken.FALSE;
1673        }
1674
1675        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1676
1677        if (!_areUnitsEqual(convertedArgument)) {
1678            throw new IllegalActionException(
1679                    notSupportedMessage("isCloseTo", this, rightArgument)
1680                            + " because the units are not the same.");
1681        }
1682
1683        return _isCloseTo(convertedArgument, epsilon);
1684    }
1685
1686    /** Test for equality of the values of this Token and the argument
1687     *  Token.  It is guaranteed by the caller that the type of the
1688     *  argument is the same as the type of this class.  This method
1689     *  returns BooleanToken.FALSE if the units of this token and the
1690     *  given token are not identical.  This method may defer to the
1691     *  _isEqualTo() method that takes a ScalarToken.  Derived classes
1692     *  should implement that method instead to provide type-specific
1693     *  operation.
1694     *  @param rightArgument The token with which to test equality.
1695     *  @return A BooleanToken which contains the result of the test.
1696     *  If either this token or the argument token is a nil token, then
1697     *  a BooleanToken that contains the value false is returned.
1698     *  @exception IllegalActionException If this method is not
1699     *  supported by the derived class.
1700     */
1701    private BooleanToken _doIsEqualTo(Token rightArgument)
1702            throws IllegalActionException {
1703        if (isNil() || rightArgument.isNil()) {
1704            return BooleanToken.FALSE;
1705        }
1706
1707        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1708
1709        if (!_areUnitsEqual(convertedArgument)) {
1710            return BooleanToken.FALSE;
1711        }
1712
1713        return _isEqualTo(convertedArgument);
1714    }
1715
1716    /** Test for ordering of the values of this Token and the argument
1717     *  Token.  It is guaranteed by the caller that the type and
1718     *  units of the argument is the same as the type of this class.
1719     *  This method may defer to the _isLessThan() method that takes a
1720     *  ScalarToken.  Derived classes should implement that method
1721     *  instead to provide type-specific operation.
1722     *  @param rightArgument The token with which to test ordering.
1723     *  @return A BooleanToken which contains the result of the test.
1724     *  @exception IllegalActionException If the units of the argument
1725     *  are not the same as the units of this token, or the method is
1726     *  not supported by the derived class or if either this token or
1727     *  the argument token is a nil token.
1728     */
1729    private BooleanToken _doIsLessThan(Token rightArgument)
1730            throws IllegalActionException {
1731        if (isNil() || rightArgument.isNil()) {
1732            throw new IllegalActionException(
1733                    notSupportedMessage("isLessThan", this, rightArgument)
1734                            + " because one or the other is nil");
1735        }
1736
1737        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1738
1739        if (!_areUnitsEqual(convertedArgument)) {
1740            throw new IllegalActionException(
1741                    notSupportedMessage("isLessThan", this, rightArgument)
1742                            + " because the units are not the same.");
1743        }
1744
1745        return _isLessThan(convertedArgument);
1746    }
1747
1748    /** Return a new token whose value is the value of this token
1749     *  modulo the value of the argument token.  It is guaranteed by
1750     *  the caller that the type of the argument is the same as the
1751     *  type of this class and has the same units as this token.  The
1752     *  resulting token will also have the same type and units.  This
1753     *  method defers to the _modulo() method that takes a
1754     *  ScalarToken.  Derived classes should implement that method
1755     *  instead to provide type-specific operation.
1756     *  @param rightArgument The token to modulo this token by.
1757     *  @return A new Token containing the result.
1758     *  If either this token or the argument token is a nil token, then
1759     *  then {@link ptolemy.data.Token#NIL} is returned.
1760     *  @exception IllegalActionException If the units are not
1761     *  compatible, or this operation is not supported by the derived
1762     *  class.
1763     */
1764    private Token _doModulo(Token rightArgument) throws IllegalActionException {
1765        if (isNil() || rightArgument.isNil()) {
1766            return getType().convert(Token.NIL);
1767        }
1768        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1769
1770        if (!_areUnitsEqual(convertedArgument)) {
1771            throw new IllegalActionException(
1772                    notSupportedMessage("modulo", this, rightArgument)
1773                            + " because the units are not the same.");
1774        }
1775
1776        ScalarToken result = _modulo(convertedArgument);
1777        if (_unitCategoryExponents != null && !_isUnitless()) {
1778            result._unitCategoryExponents = _copyOfCategoryExponents();
1779        }
1780        return result;
1781    }
1782
1783    /** Return a new token whose value is the value of this token
1784     *  multiplied by the value of the argument token.  It is
1785     *  guaranteed by the caller that the type of the argument is the
1786     *  same as the type of this class.  The resulting token will also
1787     *  have the same type and appropriate units.  This method defers
1788     *  to the _multiply() method that takes a ScalarToken.  Derived
1789     *  classes should implement that method instead to provide
1790     *  type-specific operation.
1791     *  @param rightArgument The token to multiply this token by.
1792     *  @return A new Token containing the result.
1793     *  If either this token or the argument token is a nil token, then
1794     *  then {@link ptolemy.data.Token#NIL} is returned.
1795     *  @exception IllegalActionException If this operation is not
1796     *  supported by the derived class.
1797     */
1798    private Token _doMultiply(Token rightArgument)
1799            throws IllegalActionException {
1800        if (isNil() || rightArgument.isNil()) {
1801            return getType().convert(Token.NIL);
1802        }
1803
1804        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1805        ScalarToken result = _multiply(convertedArgument);
1806
1807        // compute units
1808        if (_unitCategoryExponents != null && !_isUnitless()
1809                || convertedArgument._unitCategoryExponents != null
1810                        && !convertedArgument._isUnitless()) {
1811            result._unitCategoryExponents = _addCategoryExponents(
1812                    convertedArgument);
1813
1814        }
1815        return result;
1816    }
1817
1818    /** Return a new token whose value is the value of the argument
1819     *  token subtracted from the value of this token.  It is
1820     *  guaranteed by the caller that the type of the argument is the
1821     *  same as the type of this class and has the same units as this
1822     *  token.  The resulting token will also have the same type and
1823     *  units.  This method defers to the _subtract method that takes
1824     *  a ScalarToken.  Derived classes should implement that method
1825     *  instead to provide type-specific operation.
1826     *  @param rightArgument The token to subtract from this token.
1827     *  @return A new Token containing the result.
1828     *  If either this token or the argument token is a nil token, then
1829     *  then {@link ptolemy.data.Token#NIL} is returned.
1830     *  @exception IllegalActionException If the units are not
1831     *  compatible, or this operation is not supported by the derived
1832     *  class.
1833     */
1834    private Token _doSubtract(Token rightArgument)
1835            throws IllegalActionException {
1836        if (isNil() || rightArgument.isNil()) {
1837            return getType().convert(Token.NIL);
1838        }
1839        ScalarToken convertedArgument = (ScalarToken) rightArgument;
1840
1841        if (!_areUnitsEqual(convertedArgument)) {
1842            throw new IllegalActionException(
1843                    notSupportedMessage("subtract", this, rightArgument)
1844                            + " because the units are not the same.");
1845        }
1846
1847        ScalarToken result = _subtract(convertedArgument);
1848
1849        if (_unitCategoryExponents != null && !_isUnitless()) {
1850            result._unitCategoryExponents = _copyOfCategoryExponents();
1851        }
1852        return result;
1853    }
1854}