001/* A table of named constants that are recognized by the expression parser.
002
003 Copyright (c) 2001-2016 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.expr;
030
031import java.util.Hashtable;
032import java.util.Iterator;
033import java.util.TreeMap;
034
035import ptolemy.data.ActorToken;
036import ptolemy.data.BooleanToken;
037import ptolemy.data.ComplexToken;
038import ptolemy.data.DateToken;
039import ptolemy.data.DoubleToken;
040import ptolemy.data.FloatToken;
041import ptolemy.data.IntToken;
042import ptolemy.data.LongToken;
043import ptolemy.data.ObjectToken;
044import ptolemy.data.RecordToken;
045import ptolemy.data.ShortToken;
046import ptolemy.data.StringToken;
047import ptolemy.data.UnsignedByteToken;
048import ptolemy.data.UnsizedFixToken;
049import ptolemy.data.XMLToken;
050import ptolemy.data.type.Type;
051import ptolemy.kernel.util.IllegalActionException;
052import ptolemy.kernel.util.InternalErrorException;
053import ptolemy.math.Complex;
054import ptolemy.util.StringUtilities;
055
056///////////////////////////////////////////////////////////////////
057//// Constants
058
059/**
060 A table of named constants that are recognized by the expression parser.
061 <p>
062 A named constant in an expression is substituted by its associated value
063 when the expression is evaluated. The constants are stored in a hash table,
064 using their names as key. The value of each constant is wrapped in a data
065 token.
066
067 @author Xiaojun Liu
068 @version $Id$
069 @since Ptolemy II 2.0
070 @Pt.ProposedRating Red (liuxj)
071 @Pt.AcceptedRating Red (liuxj)
072 @see ptolemy.data.expr.PtParser
073 */
074public class Constants {
075    // There is no need to create an instance of this class.
076    private Constants() {
077    }
078
079    ///////////////////////////////////////////////////////////////////
080    ////                         public methods                    ////
081
082    /** Add a constant with the given name and value to the table.
083     *  If a constant with this same name had been previously added,
084     *  then that value is replaced with the new one.
085     *  Neither the name nor the value can be null, otherwise a
086     *  NullPointerException will be thrown.
087     *  @param name The name of the constant.
088     *  @param value The value of the constant, wrapped in a data token.
089     */
090    public static void add(String name, ptolemy.data.Token value) {
091        _table.put(name, value);
092    }
093
094    /** Return a record representation of the constants.
095     *  @return A record with the constants and their values.
096     *  @since Ptolemy II 2.1
097     */
098    public static RecordToken constants() {
099        // This should be called toString(), but we cannot have a static
100        // toString() because Object.toString() is not static.
101        // NOTE: Construct these arrays rather than using keySet()
102        // and values() because we have no assurance that those will
103        // return the contents in the same order.
104        int size = _table.size();
105        String[] names = new String[size];
106        ptolemy.data.Token[] values = new ptolemy.data.Token[size];
107        Iterator keys = _table.keySet().iterator();
108        int i = 0;
109
110        while (keys.hasNext()) {
111            String key = (String) keys.next();
112            names[i] = key;
113            values[i] = (ptolemy.data.Token) _table.get(key);
114            i++;
115        }
116
117        try {
118            return new RecordToken(names, values);
119        } catch (IllegalActionException ex) {
120            throw new InternalErrorException("Cannot construct a record!");
121        }
122    }
123
124    /** Look up the value of the constant with the given name.
125     *  @param name The name of the constant.
126     *  @return The value of the constant, wrapped in a data token, or null
127     *   if there is no constant with the given name in the table.
128     */
129    public static ptolemy.data.Token get(String name) {
130        return (ptolemy.data.Token) _table.get(name);
131    }
132
133    /** Given a name defining a type, return the type, or null if
134     *  there is no such type.
135     *  @param name The type name.
136     */
137    public static Type nameToType(String name) {
138        ptolemy.data.Token token = _types.get(name);
139        if (token != null) {
140            return token.getType();
141        }
142        return null;
143    }
144
145    /** Remove the constant with the given name from the table.
146     *  If there is no constant with the given name in the table,
147     *  the table is not changed.
148     *  @param name The name of the constant to be removed from the table.
149     */
150    public static void remove(String name) {
151        _table.remove(name);
152    }
153
154    /** Return a map from names to types, with the names sorted alphabetically.
155     *  @return A copy of the table of named types.
156     */
157    public static TreeMap types() {
158        // We use a separate map of types so that we can list the
159        // types in the port configurer dialog
160        // We return a TreeMap here because we do not need the
161        // synchronization in a Hashtable, but we do want it sorted.
162        return _types;
163    }
164
165    ///////////////////////////////////////////////////////////////////
166    ////                         private variables                 ////
167    // The hash table containing the named constants.
168    private static Hashtable _table = new Hashtable();
169
170    /** The treemap containing the named constants.
171     *  We use a treemap so that we get sorting in natural order.
172     */
173    private static TreeMap<String, ptolemy.data.Token> _types = new TreeMap<String, ptolemy.data.Token>();
174
175    ///////////////////////////////////////////////////////////////////
176    ////                         static initializer                ////
177    // Add the default set of named constants to the table.
178    static {
179        DoubleToken token = new DoubleToken(java.lang.Math.PI);
180        _table.put("PI", token);
181        _table.put("pi", token);
182        token = new DoubleToken(java.lang.Math.E);
183        _table.put("E", token);
184        _table.put("e", token);
185
186        ComplexToken i = new ComplexToken(new Complex(0.0, 1.0));
187        _table.put("i", i);
188        _table.put("j", i);
189        _table.put("true", BooleanToken.TRUE);
190        _table.put("false", BooleanToken.FALSE);
191
192        // This variable is used as a tag by the FileParameter
193        // class to represent a search in the classpath.  This is a hack,
194        // but it deals with the fact that Java is not symmetric in how it
195        // deals with getting files from the classpath (using getResource)
196        // and getting files from the file system.
197        _table.put("CLASSPATH", new StringToken("xxxxxxCLASSPATHxxxxxx"));
198
199        try {
200            // StringToken.getProperty() specially handles user.dir.
201            _putProperty("CWD", "user.dir");
202
203            _putProperty("HOME", "user.home");
204
205            // When Vergil is started up, java is called with
206            // -Dptolemy.ptII.dir=${PTII} and
207            // StringUtilities.getProperty() does some special munging
208            // for ptolemy.ptII.dir
209            _putProperty("PTII", "ptolemy.ptII.dir");
210
211            // See also the ptolemy.ptII.dirAsURL property in StringUtilities.
212            // Note that TMPDIR almost always ends with a \ or /
213            // so usually we refer to it as ${TMPDIR}.
214            _putProperty("TMPDIR", "java.io.tmpdir");
215
216            _putProperty("USERNAME", "user.name");
217        } catch (Exception ex) {
218            throw new RuntimeException(ex);
219        }
220
221        // Infinities and NaN
222        _table.put("NaN", new DoubleToken(Double.NaN));
223        _table.put("Infinity", new DoubleToken(Double.POSITIVE_INFINITY));
224
225        // numerical bounds
226        _table.put("MaxUnsignedByte", new UnsignedByteToken(255));
227        _table.put("MinUnsignedByte", new UnsignedByteToken(0));
228        _table.put("MaxShort", new ShortToken(Short.MAX_VALUE));
229        _table.put("MinShort", new ShortToken(Short.MIN_VALUE));
230        _table.put("MaxInt", new IntToken(Integer.MAX_VALUE));
231        _table.put("MinInt", new IntToken(Integer.MIN_VALUE));
232        _table.put("MaxLong", new LongToken(Long.MAX_VALUE));
233        _table.put("MinLong", new LongToken(Long.MIN_VALUE));
234        _table.put("MaxFloat", new DoubleToken(Float.MAX_VALUE));
235        _table.put("MinFloat", new DoubleToken(Float.MIN_VALUE));
236        _table.put("MaxDouble", new DoubleToken(Double.MAX_VALUE));
237        _table.put("MinDouble", new DoubleToken(Double.MIN_VALUE));
238        _table.put("PositiveInfinity",
239                new DoubleToken(Double.POSITIVE_INFINITY));
240        _table.put("NegativeInfinity",
241                new DoubleToken(Double.NEGATIVE_INFINITY));
242
243        // Type constants.
244        // We use a separate map of types so that we can list the
245        // types in the port configurer dialog
246        _types.put("boolean", BooleanToken.FALSE);
247        _types.put("complex", new ComplexToken(new Complex(0.0, 0.0)));
248        _types.put("float", new FloatToken(0.0f));
249        _types.put("double", new DoubleToken(0.0));
250        _types.put("date", new DateToken());
251        _types.put("fixedpoint", new UnsizedFixToken());
252        _types.put("general", new GeneralToken());
253        _types.put("short", new ShortToken(0));
254        _types.put("int", new IntToken(0));
255        _types.put("long", new LongToken(0));
256        _types.put("matrix", new ConcreteMatrixToken());
257        _types.put("object", ObjectToken.NULL);
258        _types.put("actor", ActorToken.EMPTY);
259        // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5545
260        // "Also, why is "xmltoken" an option in the list? For double you enter "double", not DoubleToken, etc."
261        XMLToken xmltoken = new XMLToken();
262        _types.put("xml", xmltoken);
263        _types.put("scalar", new ConcreteScalarToken());
264        _types.put("string", new StringToken(""));
265        _types.put("unknown", new UnknownToken());
266        _types.put("unsignedByte", new UnsignedByteToken(0));
267        _types.put("record", RecordToken.EMPTY_RECORD);
268
269        ptolemy.data.Token nil = ptolemy.data.Token.NIL;
270        _types.put("niltype", nil);
271
272        _table.putAll(_types);
273
274        _table.put("nil", nil);
275
276        _table.put("null", ObjectToken.NULL);
277
278        // add "xmltoken" since that's returned by BaseType.XmlTokenType.toString()
279        _table.put("xmltoken", xmltoken);
280
281    }
282
283    ///////////////////////////////////////////////////////////////////
284    ////                         private methods                   ////
285    // Look up a property and add it to the _table.
286    // If the property is not available because of a securityException,
287    // then ignore the securityException and do nothing.
288    private static void _putProperty(String variableName, String property) {
289        try {
290            _table.put(variableName,
291                    new StringToken(StringUtilities.getProperty(property)));
292        } catch (SecurityException ex) {
293            System.out.println("Warning: While trying to set '" + variableName
294                    + "', failed to read '" + property + "' property "
295                    + "(-sandbox always causes this)");
296        }
297    }
298}