001/* A visitor that writes parse trees.
002
003 Copyright (c) 2002-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 OR RESEARCH IN MOTION
012 LIMITED BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
013 INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
014 SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA
015 OR RESEARCH IN MOTION LIMITED HAVE BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION LIMITED
019 SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
021 PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
022 BASIS, AND THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION
023 LIMITED HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
024 ENHANCEMENTS, OR MODIFICATIONS.
025
026
027 */
028package ptolemy.data.expr;
029
030import java.io.PrintWriter;
031import java.io.StringWriter;
032import java.util.Iterator;
033import java.util.List;
034
035import ptolemy.data.StringToken;
036import ptolemy.kernel.util.IllegalActionException;
037
038///////////////////////////////////////////////////////////////////
039//// ParseTreeWriter
040
041/**
042 This class implements a visitor that writes parse trees in the
043 expression language.
044
045 @author Steve Neuendorffer
046 @version $Id$
047 @since Ptolemy II 2.1
048 @Pt.ProposedRating Red (neuendor)
049 @Pt.AcceptedRating Red (cxh)
050 @see ptolemy.data.expr.ASTPtRootNode
051 */
052public class ParseTreeWriter extends AbstractParseTreeVisitor {
053    public void displayParseTree(ASTPtRootNode root) {
054        _writer = new PrintWriter(System.out);
055
056        try {
057            root.visit(this);
058        } catch (IllegalActionException ex) {
059            _writer.println(ex);
060            ex.printStackTrace(_writer);
061        }
062    }
063
064    /** Produce an expression for this parse tree.
065     *  @param root The root of the parse tree.
066     *  @return The expression.
067     *  @exception IllegalActionException If the parse tree has an error.
068     */
069    public String parseTreeToExpression(ASTPtRootNode root)
070            throws IllegalActionException {
071        StringWriter writer = new StringWriter();
072        _writer = new PrintWriter(writer);
073        root.visit(this);
074        return writer.toString();
075    }
076
077    /** Return an expression for this parse tree, or a description
078     *  of the exception if an exception occurs.
079     *  @param root The root of the parse tree.
080     *  @return The expression.
081     */
082    public String printParseTree(ASTPtRootNode root) {
083        StringWriter writer = new StringWriter();
084        _writer = new PrintWriter(writer);
085
086        try {
087            root.visit(this);
088        } catch (IllegalActionException ex) {
089            _writer.println(ex);
090            ex.printStackTrace(_writer);
091        }
092
093        return writer.toString();
094    }
095
096    /** Specify whether the expression to write is in string mode.
097     *  FIXME string mode has only been implemented for leaf and sum nodes.
098     *  @param stringMode True to put the expression to write in string mode.
099     */
100    public void setStringMode(boolean stringMode) {
101        _isStringMode = stringMode;
102    }
103
104    ///////////////////////////////////////////////////////////////////
105    ////                         public methods                    ////
106    @Override
107    public void visitArrayConstructNode(ASTPtArrayConstructNode node)
108            throws IllegalActionException {
109        _writer.print("{");
110        _printChildrenSeparated(node, ", ");
111        _writer.print("}");
112    }
113
114    @Override
115    public void visitBitwiseNode(ASTPtBitwiseNode node)
116            throws IllegalActionException {
117        _writer.print("(");
118        _printChildrenSeparated(node, node.getOperator().image);
119        _writer.print(")");
120    }
121
122    @Override
123    public void visitFunctionApplicationNode(ASTPtFunctionApplicationNode node)
124            throws IllegalActionException {
125        _printChild(node, 0);
126        _writer.print("(");
127
128        int n = node.jjtGetNumChildren();
129
130        for (int i = 1; i < n - 1; ++i) {
131            _printChild(node, i);
132            _writer.print(", ");
133        }
134
135        if (n > 1) {
136            _printChild(node, n - 1);
137        }
138
139        _writer.print(")");
140    }
141
142    @Override
143    public void visitFunctionDefinitionNode(ASTPtFunctionDefinitionNode node)
144            throws IllegalActionException {
145        // This code is duplicated with the FunctionToken.
146        _writer.print("(function(");
147
148        List args = node.getArgumentNameList();
149        ptolemy.data.type.Type[] argTypes = node.getArgumentTypes();
150        int n = args.size();
151
152        for (int i = 0; i < n; i++) {
153            if (i > 0) {
154                _writer.print(", ");
155            }
156
157            _writer.print((String) args.get(i));
158
159            ptolemy.data.type.Type type = argTypes[i];
160
161            if (type != ptolemy.data.type.BaseType.GENERAL) {
162                _writer.print(":");
163                _writer.print(type.toString());
164            }
165        }
166
167        _writer.print(") ");
168        node.getExpressionTree().visit(this);
169        _writer.print(")");
170    }
171
172    @Override
173    public void visitFunctionalIfNode(ASTPtFunctionalIfNode node)
174            throws IllegalActionException {
175        _writer.print("(");
176        _printChild(node, 0);
177        _writer.print("?");
178        _printChild(node, 1);
179        _writer.print(":");
180        _printChild(node, 2);
181        _writer.print(")");
182    }
183
184    @Override
185    public void visitLeafNode(ASTPtLeafNode node)
186            throws IllegalActionException {
187        if (node.isConstant() && node.isEvaluated()) {
188            ptolemy.data.Token token = node.getToken();
189            if (_isStringMode && (token instanceof StringToken)) {
190                _writer.print(((StringToken) token).stringValue());
191            } else {
192                _writer.print(token.toString());
193            }
194        } else {
195            _writer.print(node.getName());
196        }
197    }
198
199    @Override
200    public void visitLogicalNode(ASTPtLogicalNode node)
201            throws IllegalActionException {
202        _writer.print("(");
203        _printChildrenSeparated(node, node.getOperator().image);
204        _writer.print(")");
205    }
206
207    @Override
208    public void visitMatrixConstructNode(ASTPtMatrixConstructNode node)
209            throws IllegalActionException {
210        _writer.print("[");
211
212        int n = 0;
213        int rowCount = node.getRowCount();
214        int columnCount = node.getColumnCount();
215
216        for (int i = 0; i < rowCount; i++) {
217            for (int j = 0; j < columnCount; j++) {
218                _printChild(node, n++);
219
220                if (j < columnCount - 1) {
221                    _writer.print(", ");
222                }
223            }
224
225            if (i < rowCount - 1) {
226                _writer.print("; ");
227            }
228        }
229
230        _writer.print("]");
231    }
232
233    @Override
234    public void visitMethodCallNode(ASTPtMethodCallNode node)
235            throws IllegalActionException {
236        _printChild(node, 0);
237        _writer.print(".");
238        _writer.print(node.getMethodName());
239        _writer.print("(");
240
241        if (node.jjtGetNumChildren() > 1) {
242            _printChild(node, 1);
243
244            for (int i = 2; i < node.jjtGetNumChildren(); i++) {
245                _writer.print(", ");
246                _printChild(node, i);
247            }
248        }
249
250        _writer.print(")");
251    }
252
253    @Override
254    public void visitPowerNode(ASTPtPowerNode node)
255            throws IllegalActionException {
256        _printChildrenSeparated(node, "^");
257    }
258
259    @Override
260    public void visitProductNode(ASTPtProductNode node)
261            throws IllegalActionException {
262        _writer.print("(");
263        _printChildrenSeparated(node, node.getLexicalTokenList());
264        _writer.print(")");
265    }
266
267    @Override
268    public void visitRecordConstructNode(ASTPtRecordConstructNode node)
269            throws IllegalActionException {
270        Iterator names = node.getFieldNames().iterator();
271        if (node instanceof ASTPtOrderedRecordConstructNode) {
272            _writer.print("[");
273        } else {
274            _writer.print("{");
275        }
276
277        if (node.jjtGetNumChildren() > 0) {
278            _writer.print(names.next());
279            _writer.print("=");
280            _printChild(node, 0);
281
282            for (int i = 1; i < node.jjtGetNumChildren(); i++) {
283                _writer.print(", ");
284                _writer.print(names.next());
285                _writer.print("=");
286                _printChild(node, i);
287            }
288        }
289
290        if (node instanceof ASTPtOrderedRecordConstructNode) {
291            _writer.print("]");
292        } else {
293            _writer.print("}");
294        }
295    }
296
297    @Override
298    public void visitRelationalNode(ASTPtRelationalNode node)
299            throws IllegalActionException {
300        _writer.print("(");
301        _printChildrenSeparated(node, node.getOperator().image);
302        _writer.print(")");
303    }
304
305    @Override
306    public void visitShiftNode(ASTPtShiftNode node)
307            throws IllegalActionException {
308        _writer.print("(");
309        _printChildrenSeparated(node, node.getOperator().image);
310        _writer.print(")");
311    }
312
313    @Override
314    public void visitSumNode(ASTPtSumNode node) throws IllegalActionException {
315        if (!_isStringMode) {
316            _writer.print("(");
317        }
318        _printChildrenSeparated(node, node.getLexicalTokenList());
319        if (!_isStringMode) {
320            _writer.print(")");
321        }
322    }
323
324    @Override
325    public void visitUnaryNode(ASTPtUnaryNode node)
326            throws IllegalActionException {
327        if (node.isMinus()) {
328            _writer.print("-");
329        } else if (node.isNot()) {
330            _writer.print("!");
331        } else {
332            _writer.print("~");
333        }
334
335        _printChild(node, 0);
336    }
337
338    protected PrintWriter _writer = new PrintWriter(System.out);
339
340    private void _printChild(ASTPtRootNode node, int index)
341            throws IllegalActionException {
342        ASTPtRootNode child = (ASTPtRootNode) node.jjtGetChild(index);
343        child.visit(this);
344    }
345
346    private void _printChildrenSeparated(ASTPtRootNode node, List separatorList)
347            throws IllegalActionException {
348        Iterator separators = separatorList.iterator();
349
350        if (node.jjtGetNumChildren() > 0) {
351            _printChild(node, 0);
352
353            for (int i = 1; i < node.jjtGetNumChildren(); i++) {
354                Token separator = (Token) separators.next();
355                if (!_isStringMode || separator.image != null) {
356                    _writer.print(separator.image);
357                }
358                _printChild(node, i);
359            }
360        }
361    }
362
363    private void _printChildrenSeparated(ASTPtRootNode node, String string)
364            throws IllegalActionException {
365        if (node.jjtGetNumChildren() > 0) {
366            _printChild(node, 0);
367
368            for (int i = 1; i < node.jjtGetNumChildren(); i++) {
369                _writer.print(string);
370                _printChild(node, i);
371            }
372        }
373    }
374
375    /** Indicates if string mode is on. */
376    private boolean _isStringMode = false;
377
378}