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}