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