001/* An actor that reads expressions and parses them into tokens. 002 003 @Copyright (c) 1998-2014 The Regents of the University of California. 004 All rights reserved. 005 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the 009 above copyright notice and the following two paragraphs appear in all 010 copies of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION 2 026 COPYRIGHTENDKEY 027 */ 028package ptolemy.actor.lib.conversions; 029 030import java.util.Set; 031 032import ptolemy.data.StringToken; 033import ptolemy.data.Token; 034import ptolemy.data.expr.ASTPtRootNode; 035import ptolemy.data.expr.ModelScope; 036import ptolemy.data.expr.ParseTreeEvaluator; 037import ptolemy.data.expr.ParserScope; 038import ptolemy.data.expr.PtParser; 039import ptolemy.data.expr.Variable; 040import ptolemy.data.type.BaseType; 041import ptolemy.data.type.Type; 042import ptolemy.kernel.CompositeEntity; 043import ptolemy.kernel.util.IllegalActionException; 044import ptolemy.kernel.util.NameDuplicationException; 045 046/////////////////////////////////////////////////////////////////// 047//// ExpressionToToken 048 049/** 050 This actor reads a string expression from the input port and outputs 051 the token resulting from the evaluation. The type of the output port 052 is by default undeclared. To use this actor, you may need to declare 053 the output type. Depending on how the output is used, if 054 backward type resolution is enabled in the model 055 (the default, see the parameters of the top-level model), then 056 the type will resolve to the most general type acceptable to 057 the downstream actors. If the downstream actors all propagate 058 type constraints backwards, then it might be possible for 059 the output type to be inferred. If backward type resolution is not enabled, 060 then you will always need to set the type of the output 061 port to the type of the expression that is expected. 062 If the input string parses to something that does not match 063 the specified output data type, then a run-time type check error 064 will occur when this actor tries to produce its output. 065 <p> 066 The expression input can refer to any variable that is in scope 067 for this actor. 068 069 @author Steve Neuendorffer 070 @version $Id$ 071 @since Ptolemy II 2.1 072 @Pt.ProposedRating Yellow (neuendor) 073 @Pt.AcceptedRating Red (liuj) 074 */ 075public class ExpressionToToken extends Converter { 076 /** Construct an actor with the given container and name. 077 * @param container The container. 078 * @param name The name of this actor. 079 * @exception IllegalActionException If the actor cannot be contained 080 * by the proposed container. 081 * @exception NameDuplicationException If the container already has an 082 * actor with this name. 083 */ 084 public ExpressionToToken(CompositeEntity container, String name) 085 throws IllegalActionException, NameDuplicationException { 086 super(container, name); 087 input.setTypeEquals(BaseType.STRING); 088 // With backward type resolution, the following is not appropriate. 089 // output.setTypeEquals(BaseType.GENERAL); 090 } 091 092 /////////////////////////////////////////////////////////////////// 093 //// public methods //// 094 095 /** Output a token that results from evaluating the expression given 096 * by the input string token. 097 * @exception IllegalActionException If there is no director, or 098 * if the expression read from the input cannot be parsed. 099 */ 100 @Override 101 public void fire() throws IllegalActionException { 102 super.fire(); 103 String string = ((StringToken) input.get(0)).stringValue(); 104 Token result; 105 106 try { 107 if (_parser == null) { 108 _parser = new PtParser(); 109 } 110 111 ASTPtRootNode parseTree = _parser.generateParseTree(string); 112 113 if (_parseTreeEvaluator == null) { 114 _parseTreeEvaluator = new ParseTreeEvaluator(); 115 } 116 117 if (_scope == null) { 118 _scope = new ExpressionScope(); 119 } 120 121 result = _parseTreeEvaluator.evaluateParseTree(parseTree, _scope); 122 } catch (IllegalActionException ex) { 123 // Chain exceptions to get the actor that threw the exception. 124 throw new IllegalActionException(this, ex, "Expression invalid."); 125 } 126 127 if (result == null) { 128 throw new IllegalActionException(this, 129 "Expression yields a null result: " + string); 130 } 131 132 output.broadcast(result); 133 } 134 135 /** Return true if and only if an input is present. 136 * @exception IllegalActionException If there is no director, or 137 * if no connection has been made to the input. 138 */ 139 @Override 140 public boolean prefire() throws IllegalActionException { 141 if (input.hasToken(0)) { 142 return super.prefire(); 143 } else { 144 return false; 145 } 146 } 147 148 /** Wrapup execution of this actor. This method overrides the 149 * base class to discard the internal parser to save memory. 150 */ 151 @Override 152 public void wrapup() { 153 _parser = null; 154 } 155 156 /////////////////////////////////////////////////////////////////// 157 //// inner classes //// 158 private class ExpressionScope extends ModelScope { 159 /** Look up and return the attribute with the specified name in the 160 * scope. Return null if such an attribute does not exist. 161 * @return The attribute with the specified name in the scope. 162 */ 163 @Override 164 public Token get(String name) throws IllegalActionException { 165 Variable result = getScopedVariable(null, ExpressionToToken.this, 166 name); 167 168 if (result != null) { 169 return result.getToken(); 170 } 171 172 return null; 173 } 174 175 /** Look up and return the type of the attribute with the 176 * specified name in the scope. Return null if such an 177 * attribute does not exist. 178 * @return The attribute with the specified name in the scope. 179 */ 180 @Override 181 public Type getType(String name) throws IllegalActionException { 182 Variable result = getScopedVariable(null, ExpressionToToken.this, 183 name); 184 185 if (result != null) { 186 return (Type) result.getTypeTerm().getValue(); 187 } 188 189 return null; 190 } 191 192 /** Look up and return the type term for the specified name 193 * in the scope. Return null if the name is not defined in this 194 * scope, or is a constant type. 195 * @return The InequalityTerm associated with the given name in 196 * the scope. 197 * @exception IllegalActionException If a value in the scope 198 * exists with the given name, but cannot be evaluated. 199 */ 200 @Override 201 public ptolemy.graph.InequalityTerm getTypeTerm(String name) 202 throws IllegalActionException { 203 Variable result = getScopedVariable(null, ExpressionToToken.this, 204 name); 205 206 if (result != null) { 207 return result.getTypeTerm(); 208 } 209 210 return null; 211 } 212 213 /** Return the list of identifiers within the scope. 214 * @return The list of identifiers within the scope. 215 */ 216 @Override 217 public Set identifierSet() { 218 return getAllScopedVariableNames(null, ExpressionToToken.this); 219 } 220 } 221 222 /////////////////////////////////////////////////////////////////// 223 //// private members //// 224 225 /** The parser to use. */ 226 private PtParser _parser = null; 227 228 /** The parse tree evaluator to use. */ 229 private ParseTreeEvaluator _parseTreeEvaluator = null; 230 231 /** The scope for the parser. */ 232 private ParserScope _scope = null; 233}