001/* A tableau for evaluating expressions interactively.
002
003 Copyright (c) 2003-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 */
027package ptolemy.actor.gui;
028
029import java.util.Set;
030
031import ptolemy.data.Token;
032import ptolemy.data.expr.ASTPtAssignmentNode;
033import ptolemy.data.expr.ASTPtRootNode;
034import ptolemy.data.expr.ModelScope;
035import ptolemy.data.expr.Parameter;
036import ptolemy.data.expr.ParseTreeEvaluator;
037import ptolemy.data.expr.ParserScope;
038import ptolemy.data.expr.PtParser;
039import ptolemy.data.expr.Variable;
040import ptolemy.graph.InequalityTerm;
041import ptolemy.gui.ShellInterpreter;
042import ptolemy.gui.ShellTextArea;
043import ptolemy.kernel.util.Attribute;
044import ptolemy.kernel.util.IllegalActionException;
045import ptolemy.kernel.util.NameDuplicationException;
046import ptolemy.kernel.util.NamedObj;
047
048///////////////////////////////////////////////////////////////////
049//// ExpressionShellTableau
050
051/**
052 A tableau that provides an interactive shell for evaluating expressions.
053
054 @author Christopher Hylands and Edward A. Lee
055 @version $Id$
056 @since Ptolemy II 3.0
057 @Pt.ProposedRating Red (cxh)
058 @Pt.AcceptedRating Red (cxh)
059 @see ShellTextArea
060 @see ExpressionShellEffigy
061 */
062public class ExpressionShellTableau extends Tableau
063        implements ShellInterpreter {
064    /** Create a new tableau.
065     *  The tableau is itself an entity contained by the effigy
066     *  and having the specified name.  The frame is not made visible
067     *  automatically.  You must call show() to make it visible.
068     *  @param container The containing effigy.
069     *  @param name The name of this tableau within the specified effigy.
070     *  @exception IllegalActionException If the tableau is not acceptable
071     *   to the specified container.
072     *  @exception NameDuplicationException If the container already contains
073     *   an entity with the specified name.
074     */
075    public ExpressionShellTableau(ExpressionShellEffigy container, String name)
076            throws IllegalActionException, NameDuplicationException {
077        super(container, name);
078        frame = new ExpressionShellFrame(this);
079        setFrame(frame);
080        frame.setTableau(this);
081        _evaluator = new ParseTreeEvaluator();
082    }
083
084    ///////////////////////////////////////////////////////////////////
085    ////                         public methods                    ////
086
087    /** Evaluate the specified command.
088     *  @param command The command.
089     *  @return The return value of the command, or null if there is none.
090     *  @exception Exception If something goes wrong processing the command.
091     */
092    @Override
093    public String evaluateCommand(String command) throws Exception {
094        if (command.trim().equals("")) {
095            return "";
096        }
097
098        PtParser parser = new PtParser();
099        ASTPtRootNode node = parser.generateSimpleAssignmentParseTree(command);
100        String targetName = null;
101
102        // Figure out if we got an assignment... if so, then get the
103        // identifier name and only evaluated the expression part.
104        if (node instanceof ASTPtAssignmentNode) {
105            ASTPtAssignmentNode assignmentNode = (ASTPtAssignmentNode) node;
106            targetName = assignmentNode.getIdentifier();
107            node = assignmentNode.getExpressionTree();
108        }
109
110        final NamedObj model = ((ExpressionShellEffigy) getContainer())
111                .getModel();
112        ParserScope scope = new ModelScope() {
113            @Override
114            public ptolemy.data.Token get(String name)
115                    throws IllegalActionException {
116                Variable result = getScopedVariable(null, model, name);
117
118                if (result != null) {
119                    return result.getToken();
120                } else {
121                    return null;
122                }
123            }
124
125            @Override
126            public ptolemy.data.type.Type getType(String name)
127                    throws IllegalActionException {
128                Variable result = getScopedVariable(null, model, name);
129
130                if (result != null) {
131                    return result.getType();
132                } else {
133                    return null;
134                }
135            }
136
137            @Override
138            public InequalityTerm getTypeTerm(String name)
139                    throws IllegalActionException {
140                Variable result = getScopedVariable(null, model, name);
141
142                if (result != null) {
143                    return result.getTypeTerm();
144                } else {
145                    return null;
146                }
147            }
148
149            @Override
150            public Set identifierSet() {
151                return getAllScopedVariableNames(null, model);
152            }
153        };
154
155        Token result = _evaluator.evaluateParseTree(node, scope);
156
157        // If a target was specified, instantiate a new token.
158        if (targetName != null) {
159            Attribute attribute = model.getAttribute(targetName);
160
161            if (attribute != null && !(attribute instanceof Parameter)) {
162                attribute.setContainer(null);
163                attribute = null;
164            }
165
166            if (attribute == null) {
167                attribute = new Parameter(model, targetName);
168            }
169
170            ((Parameter) attribute).setToken(result);
171        }
172
173        if (result == null) {
174            return "";
175        } else {
176            return result.toString();
177        }
178    }
179
180    /** Return true if the specified command is complete (ready
181     *  to be interpreted).
182     *  @param command The command.
183     *  @return True.
184     */
185    @Override
186    public boolean isCommandComplete(String command) {
187        return true;
188    }
189
190    ///////////////////////////////////////////////////////////////////
191    ////                         public variables                  ////
192
193    /** The associated frame. */
194    public ExpressionShellFrame frame;
195
196    /** The contained shell. */
197    public ShellTextArea shell;
198
199    ///////////////////////////////////////////////////////////////////
200    ////                         private variables                 ////
201
202    /** The parameter used for evaluation. */
203    private ParseTreeEvaluator _evaluator;
204
205    ///////////////////////////////////////////////////////////////////
206    ////                         inner classes                     ////
207
208    /** A factory that creates a control panel to display an Expression Shell.
209     */
210    public static class Factory extends TableauFactory {
211        /** Create a factory with the given name and container.
212         *  @param container The container.
213         *  @param name The name.
214         *  @exception IllegalActionException If the container is incompatible
215         *   with this attribute.
216         *  @exception NameDuplicationException If the name coincides with
217         *   an attribute already in the container.
218         */
219        public Factory(NamedObj container, String name)
220                throws IllegalActionException, NameDuplicationException {
221            super(container, name);
222        }
223
224        ///////////////////////////////////////////////////////////////////
225        ////                         public methods                    ////
226
227        /** Create a new instance of ExpressionShellTableau in the specified
228         *  effigy. It is the responsibility of callers of
229         *  this method to check the return value and call show().
230         *  @param effigy The model effigy.
231         *  @return A new control panel tableau if the effigy is
232         *    a PtolemyEffigy, or null otherwise.
233         *  @exception Exception If the factory should be able to create a
234         *   tableau for the effigy, but something goes wrong.
235         */
236        @Override
237        public Tableau createTableau(Effigy effigy) throws Exception {
238            // NOTE: Can create any number of tableaux within the same
239            // effigy.  Is this what we want?
240            if (effigy instanceof ExpressionShellEffigy) {
241                return new ExpressionShellTableau(
242                        (ExpressionShellEffigy) effigy,
243                        "ExpressionShellTableau");
244            } else {
245                return null;
246            }
247        }
248    }
249}