001: /* ====================================================================
002: * Tea - Copyright (c) 1997-2000 Walt Disney Internet Group
003: * ====================================================================
004: * The Tea Software License, Version 1.1
005: *
006: * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Walt Disney Internet Group (http://opensource.go.com/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact opensource@dig.com.
031: *
032: * 5. Products derived from this software may not be called "Tea",
033: * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
034: * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
035: * written permission of the Walt Disney Internet Group.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
041: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
042: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
043: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
044: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
045: * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
046: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
047: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
048: * ====================================================================
049: *
050: * For more information about Tea, please see http://opensource.go.com/.
051: */
052:
053: package com.go.tea.compiler;
054:
055: import java.io.*;
056: import com.go.tea.parsetree.*;
057:
058: /******************************************************************************
059: * A class that prints a parse tree. To print, call the writeTo method.
060: *
061: * @author Brian S O'Neill
062: * @version
063: * <!--$$Revision:--> 35 <!-- $-->, <!--$$JustDate:--> 5/31/01 <!-- $-->
064: */
065: public class TreePrinter extends CodeGenerator {
066: private String mIndentStr;
067: private boolean mExtraParens;
068:
069: public TreePrinter(Template tree) {
070: this (tree, " ", false);
071: }
072:
073: public TreePrinter(Template tree, String indentStr) {
074: this (tree, indentStr, false);
075: }
076:
077: public TreePrinter(Template tree, boolean extraParens) {
078: this (tree, " ", extraParens);
079: }
080:
081: public TreePrinter(Template tree, String indentStr,
082: boolean extraParens) {
083: super (tree);
084: mIndentStr = indentStr;
085: mExtraParens = extraParens;
086: }
087:
088: public void writeTo(OutputStream out) throws IOException {
089: BufferedWriter w = new BufferedWriter(new OutputStreamWriter(
090: out));
091:
092: Visitor v = new Visitor(w, mIndentStr, mExtraParens);
093:
094: try {
095: getParseTree().accept(v);
096: } catch (IOError e) {
097: e.rethrow();
098: }
099:
100: w.flush();
101: }
102:
103: /**
104: * Converts any node to a String.
105: */
106: public static String toString(Node node) {
107: return toString(node, " ");
108: }
109:
110: /**
111: * Converts any node to a String.
112: */
113: public static String toString(Node node, String indentStr) {
114: StringWriter sw = new StringWriter();
115: BufferedWriter w = new BufferedWriter(sw);
116: Visitor v = new Visitor(w, indentStr, false);
117: node.accept(v);
118: try {
119: w.flush();
120: } catch (IOException e) {
121: throw new IOError(e);
122: }
123: return sw.toString();
124: }
125:
126: private static class IOError extends RuntimeException {
127: private IOException mException;
128:
129: public IOError(IOException e) {
130: mException = e;
131: }
132:
133: public void rethrow() throws IOException {
134: throw mException;
135: }
136: }
137:
138: private static class Visitor implements NodeVisitor {
139: private BufferedWriter mWriter;
140: private String mIndentStr;
141: private boolean mExtraParens;
142: private int mIndent;
143: private boolean mNeedIndent = true;
144:
145: public Visitor(BufferedWriter writer, String indentStr,
146: boolean extraParens) {
147: mWriter = writer;
148: mIndentStr = indentStr;
149: mExtraParens = extraParens;
150: }
151:
152: public void indent(int amount) {
153: mIndent += amount;
154: if (mIndent < 0) {
155: mIndent = 0;
156: }
157: }
158:
159: private void print(String str) throws IOError {
160: doIndent();
161:
162: try {
163: mWriter.write(str);
164: } catch (IOException e) {
165: throw new IOError(e);
166: }
167: }
168:
169: private void println() throws IOError {
170: mNeedIndent = true;
171:
172: try {
173: mWriter.newLine();
174: } catch (IOException e) {
175: throw new IOError(e);
176: }
177: }
178:
179: private void doIndent() throws IOError {
180: if (mNeedIndent) {
181: mNeedIndent = false;
182:
183: try {
184: for (int i = mIndent; i > 0; --i) {
185: mWriter.write(mIndentStr);
186: }
187: } catch (IOException e) {
188: throw new IOError(e);
189: }
190: }
191: }
192:
193: public Object visit(Template node) {
194: print("template ");
195: print(node.getName().getName());
196:
197: Variable[] params = node.getParams();
198: print(" (");
199: if (params != null) {
200: for (int i = 0; i < params.length; i++) {
201: if (i > 0) {
202: print(", ");
203: }
204: params[i].accept(this );
205: }
206: }
207: print(") ");
208:
209: if (node.hasSubstitutionParam()) {
210: print("{...} ");
211: }
212:
213: Statement stmt = node.getStatement();
214: if (stmt != null) {
215: stmt.accept(this );
216: }
217:
218: return null;
219: }
220:
221: public Object visit(Name node) {
222: print(node.getName());
223: return null;
224: }
225:
226: public Object visit(TypeName node) {
227: print(node.getName());
228: int dim = node.getDimensions();
229: for (int i = 0; i < dim; i++) {
230: print("[]");
231: }
232: return null;
233: }
234:
235: public Object visit(Variable node) {
236: TypeName typeName = node.getTypeName();
237: if (typeName != null) {
238: typeName.accept(this );
239: print(" ");
240: }
241: print(node.getName());
242: return null;
243: }
244:
245: public Object visit(ExpressionList node) {
246: Expression[] exprs = node.getExpressions();
247: for (int i = 0; i < exprs.length; i++) {
248: if (i > 0) {
249: print(", ");
250: }
251: exprs[i].accept(this );
252: }
253:
254: return null;
255: }
256:
257: public Object visit(Statement node) {
258: return null;
259: }
260:
261: public Object visit(StatementList node) {
262: Statement[] stmts = node.getStatements();
263: if (stmts != null) {
264: for (int i = 0; i < stmts.length; i++) {
265: println();
266: stmts[i].accept(this );
267: }
268: println();
269: }
270:
271: return null;
272: }
273:
274: public Object visit(Block node) {
275: print("{ ");
276: indent(1);
277: visit((StatementList) node);
278: indent(-1);
279: print("} ");
280:
281: return null;
282: }
283:
284: public Object visit(AssignmentStatement node) {
285: node.getLValue().accept(this );
286: print(" = ");
287: node.getRValue().accept(this );
288: print(" ");
289:
290: return null;
291: }
292:
293: public Object visit(BreakStatement node) {
294: print("break");
295: return null;
296: }
297:
298: public Object visit(ForeachStatement node) {
299: print("foreach (");
300: node.getLoopVariable().accept(this );
301: print(" in ");
302: node.getRange().accept(this );
303: if (node.getEndRange() != null) {
304: print("..");
305: node.getEndRange().accept(this );
306: }
307: print(") ");
308: Statement body = node.getBody();
309: if (body != null) {
310: body.accept(this );
311: }
312:
313: return null;
314: }
315:
316: public Object visit(IfStatement node) {
317: print("if ");
318:
319: node.getCondition().accept(this );
320:
321: Statement stmt = node.getThenPart();
322: if (stmt != null) {
323: print(" ");
324: stmt.accept(this );
325: } else {
326: print(" {");
327: println();
328: print("} ");
329: }
330:
331: stmt = node.getElsePart();
332: if (stmt != null) {
333: println();
334: print("else ");
335: stmt.accept(this );
336: }
337:
338: return null;
339: }
340:
341: public Object visit(SubstitutionStatement node) {
342: print("...");
343: return null;
344: }
345:
346: public Object visit(ExpressionStatement node) {
347: node.getExpression().accept(this );
348: return null;
349: }
350:
351: public Object visit(ReturnStatement node) {
352: Expression expr = node.getExpression();
353: if (expr != null) {
354: print("/* return */ ");
355: expr.accept(this );
356: } else {
357: print("/* return void */ ");
358: }
359: return null;
360: }
361:
362: public Object visit(ExceptionGuardStatement node) {
363: print("/* try { */");
364: if (node.getGuarded() != null) {
365: indent(1);
366: node.getGuarded().accept(this );
367: indent(-1);
368: }
369: print("/* } catch (java.lang.Exception e) { */");
370: if (node.getReplacement() != null) {
371: indent(1);
372: node.getReplacement().accept(this );
373: indent(-1);
374: }
375: print("/* } */");
376:
377: return null;
378: }
379:
380: public Object visit(Expression node) {
381: print(String.valueOf(node));
382: return null;
383: }
384:
385: public Object visit(ParenExpression node) {
386: print("(");
387: node.getExpression().accept(this );
388: print(")");
389:
390: return null;
391: }
392:
393: public Object visit(NewArrayExpression node) {
394: if (node.isAssociative()) {
395: print("##(");
396: } else {
397: print("#(");
398: }
399: node.getExpressionList().accept(this );
400: print(")");
401:
402: return null;
403: }
404:
405: public Object visit(FunctionCallExpression node) {
406: return visit((CallExpression) node);
407: }
408:
409: public Object visit(TemplateCallExpression node) {
410: print("call ");
411: return visit((CallExpression) node);
412: }
413:
414: private Object visit(CallExpression node) {
415: node.getTarget().accept(this );
416: print("(");
417: node.getParams().accept(this );
418: print(")");
419:
420: Statement subParam = node.getSubstitutionParam();
421: if (subParam != null) {
422: print(" ");
423: subParam.accept(this );
424: }
425:
426: return null;
427: }
428:
429: public Object visit(VariableRef node) {
430: print(node.getName());
431: return null;
432: }
433:
434: public Object visit(Lookup node) {
435: if (mExtraParens) {
436: print("(");
437: node.getExpression().accept(this );
438: print(").");
439: } else {
440: node.getExpression().accept(this );
441: print(".");
442: }
443: print(node.getLookupName().getName());
444:
445: return null;
446: }
447:
448: public Object visit(ArrayLookup node) {
449: if (mExtraParens) {
450: print("(");
451: node.getExpression().accept(this );
452: print(")[");
453: } else {
454: node.getExpression().accept(this );
455: print("[");
456: }
457: node.getLookupIndex().accept(this );
458: print("]");
459:
460: return null;
461: }
462:
463: public Object visit(NegateExpression node) {
464: if (mExtraParens) {
465: print("-(");
466: node.getExpression().accept(this );
467: print(")");
468: } else {
469: print("-");
470: node.getExpression().accept(this );
471: }
472:
473: return null;
474: }
475:
476: public Object visit(NotExpression node) {
477: if (mExtraParens) {
478: print("not (");
479: node.getExpression().accept(this );
480: print(")");
481: } else {
482: print("not ");
483: node.getExpression().accept(this );
484: }
485:
486: return null;
487: }
488:
489: public Object visit(BinaryExpression node) {
490: if (mExtraParens)
491: print("(");
492: node.getLeftExpression().accept(this );
493: print(" ");
494: print(node.getOperator().getImage());
495: print(" ");
496: node.getRightExpression().accept(this );
497: if (mExtraParens)
498: print(")");
499:
500: return null;
501: }
502:
503: public Object visit(ConcatenateExpression node) {
504: return visit((BinaryExpression) node);
505: }
506:
507: public Object visit(ArithmeticExpression node) {
508: return visit((BinaryExpression) node);
509: }
510:
511: public Object visit(RelationalExpression node) {
512: if (node.getOperator().getID() != Token.ISA) {
513: return visit((BinaryExpression) node);
514: } else {
515: if (mExtraParens)
516: print("(");
517: node.getLeftExpression().accept(this );
518: print(" ");
519: print(node.getOperator().getImage());
520: print(" ");
521: node.getIsaTypeName().accept(this );
522: if (mExtraParens)
523: print(")");
524:
525: return null;
526: }
527: }
528:
529: public Object visit(AndExpression node) {
530: return visit((BinaryExpression) node);
531: }
532:
533: public Object visit(OrExpression node) {
534: return visit((BinaryExpression) node);
535: }
536:
537: public Object visit(NullLiteral node) {
538: print(String.valueOf(node.getValue()));
539: return null;
540: }
541:
542: public Object visit(BooleanLiteral node) {
543: print(String.valueOf(node.getValue()));
544: return null;
545: }
546:
547: public Object visit(StringLiteral node) {
548: String str = node.getValue().toString();
549: int length = str.length();
550: StringBuffer buf = new StringBuffer(length);
551:
552: for (int i = 0; i < length; i++) {
553: char c = str.charAt(i);
554:
555: if (c > '\"' && c < 128) {
556: buf.append(c);
557: } else {
558: switch (c) {
559: case ' ':
560: case '!':
561: buf.append(c);
562: break;
563: case '\"':
564: buf.append("\\\"");
565: break;
566: case '\0':
567: buf.append("\\0");
568: break;
569: case '\b':
570: buf.append("\\b");
571: break;
572: case '\t':
573: buf.append("\\t");
574: break;
575: case '\n':
576: buf.append("\\n");
577: break;
578: case '\f':
579: buf.append("\\f");
580: break;
581: case '\r':
582: buf.append("\\r");
583: break;
584: default:
585: buf.append("\\u");
586: String hex = "0000" + Integer.toHexString(c);
587: buf.append(hex.substring(hex.length() - 4));
588: break;
589: }
590: }
591: }
592:
593: print("\"");
594: print(buf.toString());
595: print("\"");
596: return null;
597: }
598:
599: public Object visit(NumberLiteral node) {
600: Number value = (Number) node.getValue();
601: print(value.toString());
602:
603: if (value instanceof Long) {
604: print("L");
605: } else if (value instanceof Float) {
606: print("f");
607: } else if (value instanceof Double) {
608: print("d");
609: }
610:
611: return null;
612: }
613: }
614: }
|