/* * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.tools.tree; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.util.Map; import org.visage.api.VisageBindStatus; import org.visage.api.tree.ForExpressionInClauseTree; import com.sun.tools.mjavac.code.Symbol; import com.sun.tools.mjavac.code.TypeTags; import com.sun.tools.mjavac.tree.JCTree; import com.sun.tools.mjavac.util.Convert; import com.sun.tools.mjavac.util.List; import com.sun.tools.mjavac.util.Name; import com.sun.tools.mjavac.util.Position; import org.visage.tools.code.VisageFlags; import static com.sun.tools.mjavac.code.Flags.*; /** Prints out a tree as an indented Java source program. * * <p><b>This is NOT part of any API supported by Sun Microsystems. If * you write code tree depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> * * @author Robert Field */ public class VisagePretty implements VisageVisitor { public static final int SCOPE_OUTER = 0; public static final int SCOPE_CLASS = 1; public static final int SCOPE_METHOD = 2; public static final int SCOPE_PARAMS = 3; protected int variableScope = SCOPE_OUTER; /** Set when we are producing source output. If we're not * producing source output, we can sometimes give more detail in * the output even though that detail would not be valid java * soruce. */ protected final boolean sourceOutput; /** The output stream on which trees are printed. */ Writer out; /** Indentation width (can be reassigned from outside). */ public int width = 4; /** The current left margin. */ int lmargin = 0; /** A hashtable mapping trees to their documentation comments * (can be null) */ Map<JCTree, String> docComments = null; CharSequence sourceContent; public VisagePretty(Writer out, boolean sourceOutput, CharSequence content) { this.out = out; this.sourceOutput = sourceOutput; sourceContent = content; } public VisagePretty(Writer out, boolean sourceOutput) { this.out = out; this.sourceOutput = sourceOutput; sourceContent = null; } /** Align code to be indented to left margin. */ public void align() throws IOException { for (int i = 0; i < lmargin; i++) out.write(" "); } /** Increase left margin by indentation width. */ public void indent() { lmargin = lmargin + width; } /** Decrease left margin by indentation width. */ public void undent() { lmargin = lmargin - width; } /** Enter a new precedence level. Emit a `(' if new precedence level * is less than precedence level so far. * @param contextPrec The precedence level in force so far. * @param ownPrec The new precedence level. */ void open(int contextPrec, int ownPrec) throws IOException { if (ownPrec < contextPrec) out.write("("); } /** Leave precedence level. Emit a `(' if inner precedence level * is less than precedence level we revert to. * @param contextPrec The precedence level we revert to. * @param ownPrec The inner precedence level. */ void close(int contextPrec, int ownPrec) throws IOException { if (ownPrec < contextPrec) out.write(")"); } /** Print string, replacing all non-ascii character with unicode escapes. */ public void print(Object s) throws IOException { // s may be null for CATCH in "try {} catch() {}" out.write(Convert.escapeUnicode((s != null) ? s.toString() : "")); } /** Print new line. */ public void println() throws IOException { out.write(lineSep); } String lineSep = System.getProperty("line.separator"); /************************************************************************** * Traversal methods *************************************************************************/ /** Exception to propogate IOException through visitXXX methods */ protected static class UncheckedIOException extends RuntimeException { static final long serialVersionUID = -4032692679158424751L; public UncheckedIOException(IOException e) { super(e.getMessage(), e); } } /** Visitor argument: the current precedence level. */ protected int prec; /** Visitor method: print expression tree. * @param prec The current precedence level. */ public void printExpr(VisageTree tree, int prec) throws IOException { int prevPrec = this.prec; try { // uncomment to debug position information // println(); // print(posAsString(tree.getStartPosition())); this.prec = prec; if (tree == null || tree instanceof VisageErroneous) { print("/*missing*/"); } else { tree.accept(this); } } catch (UncheckedIOException ex) { IOException e = new IOException(ex.getMessage()); e.initCause(ex); throw e; } finally { this.prec = prevPrec; } } /** Derived visitor method: print expression tree at minimum precedence level * for expression. */ public void printExpr(VisageTree tree) throws IOException { printExpr(tree, VisageTreeInfo.noPrec); } /** Derived visitor method: print statement tree. */ public void printStat(VisageTree tree) throws IOException { printExpr(tree, VisageTreeInfo.notExpression); } /** Derived visitor method: print list of expression trees, separated by given string. * @param sep the separator string */ public <T extends VisageTree> void printExprs(List<T> trees, String sep) throws IOException { if (trees.nonEmpty()) { printExpr(trees.head); for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) { print(sep); printExpr(l.head); } } } /** Derived visitor method: print list of expression trees, separated by commas. */ public <T extends VisageTree> void printExprs(List<T> trees) throws IOException { printExprs(trees, ", "); } /** Derived visitor method: print list of statements, each on a separate line. */ public void printStats(List<? extends VisageTree> trees) throws IOException { for (List<? extends VisageTree> l = trees; l.nonEmpty(); l = l.tail) { align(); printStat(l.head); println(); } } /** Print a set of modifiers. */ public void printFlags(long flags) throws IOException { String sf = VisageTreeInfo.flagNames(flags, true); print(sf); if (sf.length() > 0) print(" "); if ((flags & ANNOTATION) != 0) print("@"); } /** Print documentation comment, if it exists * @param tree The tree for which a documentation comment should be printed. */ public void printDocComment(VisageTree tree) throws IOException { if (docComments != null) { String dc = docComments.get(tree); if (dc != null) { int pos = 0; int endpos = lineEndPos(dc, pos); while (pos < dc.length()) { align(); print(dc.substring(pos, endpos)); pos = endpos + 1; if (pos < dc.length()) println(); endpos = lineEndPos(dc, pos); } align(); } } } //where static int lineEndPos(String s, int start) { int pos = s.indexOf('\n', start); if (pos < 0) pos = s.length(); return pos; } /** Print a block. */ public void printBlock(List<? extends VisageTree> stats) throws IOException { print("{"); println(); indent(); printStats(stats); undent(); align(); print("}"); } /** Print unit consisting of package clause and import statements in toplevel, * followed by class definition. if class definition == null, * print all definitions in toplevel. * @param tree The toplevel tree * @param cdef The class definition, which is assumed to be part of the * toplevel tree. */ public void printUnit(VisageScript tree) throws IOException { docComments = tree.docComments; printDocComment(tree); if (tree.pid != null) { print("package "); printExpr(tree.pid); print(";"); println(); } boolean firstImport = true; for (List<VisageTree> l = tree.defs; l.nonEmpty(); l = l.tail) { if (l.head.getVisageTag() == VisageTag.IMPORT) { VisageImport imp = (VisageImport)l.head; if (firstImport) { firstImport = false; println(); } printStat(imp); } else { printStat(l.head); } } } // where boolean isUsed(final Symbol t, VisageTree cdef) { class UsedVisitor extends VisageTreeScanner { @Override public void scan(VisageTree tree) { if (tree!=null && !result) tree.accept(this); } boolean result = false; @Override public void visitIdent(VisageIdent tree) { if (tree.sym == t) result = true; } } UsedVisitor v = new UsedVisitor(); v.scan(cdef); return v.result; } /************************************************************************** * Visitor methods *************************************************************************/ public void visitScript(VisageScript tree) { try { printUnit(tree); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitImport(VisageImport tree) { try { print("import "); printExpr(tree.qualid); print(";"); println(); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitSkip(VisageSkip tree) { try { print(";"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitWhileLoop(VisageWhileLoop tree) { try { print("while "); if (tree.cond.getVisageTag() == VisageTag.PARENS) { printExpr(tree.cond); } else { print("("); printExpr(tree.cond); print(")"); } print(" "); printStat(tree.body); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitTry(VisageTry tree) { try { print("try "); printStat(tree.body); for (List<VisageCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { printStat(l.head); } if (tree.finalizer != null) { print(" finally "); printStat(tree.finalizer); } } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitCatch(VisageCatch tree) { try { print(" catch ("); printExpr(tree.param); print(") "); printStat(tree.body); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitIfExpression(VisageIfExpression tree) { try { print(" if ("); printExpr(tree.cond); print(") "); printExpr(tree.truepart); if (tree.falsepart != null) { print(" else "); printExpr(tree.falsepart); } } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitBreak(VisageBreak tree) { try { print("break"); if (tree.label != null) print(" " + tree.label); print(";"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitContinue(VisageContinue tree) { try { print("continue"); if (tree.label != null) print(" " + tree.label); print(";"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitReturn(VisageReturn tree) { try { print("return"); if (tree.expr != null) { print(" "); printExpr(tree.expr); } print(";"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitThrow(VisageThrow tree) { try { print("throw "); printExpr(tree.expr); print(";"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitFunctionInvocation(VisageFunctionInvocation tree) { try { if (!tree.typeargs.isEmpty()) { if (tree.meth.getVisageTag() == VisageTag.SELECT) { VisageSelect left = (VisageSelect)tree.meth; printExpr(left.selected); print(".<"); printExprs(tree.typeargs); print(">" + left.name); } else { print("<"); printExprs(tree.typeargs); print(">"); printExpr(tree.meth); } } else { printExpr(tree.meth); } print("("); printExprs(tree.args); print(")"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitParens(VisageParens tree) { try { print("("); printExpr(tree.expr); print(")"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitAssign(VisageAssign tree) { try { open(prec, VisageTreeInfo.assignPrec); printExpr(tree.lhs, VisageTreeInfo.assignPrec + 1); print(" = "); printExpr(tree.rhs, VisageTreeInfo.assignPrec); close(prec, VisageTreeInfo.assignPrec); } catch (IOException e) { throw new UncheckedIOException(e); } } public String operatorName(VisageTag tag) { switch(tag) { case NEG: return "-"; case NOT: return "not"; case PREINC: return "++"; case PREDEC: return "--"; case POSTINC: return "++"; case POSTDEC: return "--"; case NULLCHK: return "<*nullchk*>"; case OR: return "or"; case AND: return "and"; case EQ: return "=="; case NE: return "!="; case LT: return "<"; case GT: return ">"; case LE: return "<="; case GE: return ">="; case PLUS: return "+"; case MINUS: return "-"; case MUL: return "*"; case DIV: return "/"; case MOD: return "%"; case PLUS_ASG: return "+="; case MINUS_ASG: return "-="; case MUL_ASG: return "*="; case DIV_ASG: return "/="; case REVERSE: return "reverse"; case INDEXOF: return "indexof"; case SIZEOF: return "sizeof"; default: return "[unexpected operator tag "+tag+"]"; } } public void visitAssignop(VisageAssignOp tree) { try { open(prec, VisageTreeInfo.assignopPrec); printExpr(tree.lhs, VisageTreeInfo.assignopPrec + 1); print(" " + operatorName(tree.getVisageTag())); printExpr(tree.rhs, VisageTreeInfo.assignopPrec); close(prec, VisageTreeInfo.assignopPrec); } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitUnary(VisageUnary tree) { try { if (tree.getVisageTag() == VisageTag.SIZEOF) { print("(sizeof "); printExpr(tree.arg); print(")"); } else { int ownprec = VisageTreeInfo.opPrec(tree.getVisageTag()); String opname = operatorName(tree.getVisageTag()); open(prec, ownprec); if (tree.getVisageTag().ordinal() <= VisageTag.PREDEC.ordinal()) { print(opname); printExpr(tree.arg, ownprec); } else { printExpr(tree.arg, ownprec); print(opname); } close(prec, ownprec); } } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitBinary(VisageBinary tree) { try { int ownprec = VisageTreeInfo.opPrec(tree.getVisageTag()); String opname = operatorName(tree.getVisageTag()); open(prec, ownprec); printExpr(tree.lhs, ownprec); print(" " + opname + " "); printExpr(tree.rhs, ownprec + 1); close(prec, ownprec); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitTypeCast(VisageTypeCast tree) { try { printExpr(tree.expr, VisageTreeInfo.prefixPrec); print(" as "); printExpr(tree.clazz); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitInstanceOf(VisageInstanceOf tree) { try { open(prec, VisageTreeInfo.ordPrec); printExpr(tree.expr, VisageTreeInfo.ordPrec); print(" instanceof "); printExpr(tree.clazz, VisageTreeInfo.ordPrec + 1); close(prec, VisageTreeInfo.ordPrec); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitSelect(VisageSelect tree) { try { printExpr(tree.selected, VisageTreeInfo.postfixPrec); print("." + tree.name); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitIdent(VisageIdent tree) { try { print(tree.getName()); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitLiteral(VisageLiteral tree) { try { switch (tree.typetag) { case TypeTags.BYTE: case TypeTags.SHORT: case TypeTags.INT: print(tree.value.toString()); break; case TypeTags.LONG: print(tree.value + "L"); break; case TypeTags.FLOAT: print(tree.value + "F"); break; case TypeTags.DOUBLE: print(tree.value.toString()); break; case TypeTags.CHAR: print("\'" + Convert.quote( String.valueOf((char)((Number)tree.value).intValue())) + "\'"); break; case TypeTags.BOOLEAN: print(((Number)tree.value).intValue() == 1 ? "true" : "false"); break; case TypeTags.BOT: print("null"); break; default: print("\"" + Convert.quote(tree.value.toString()) + "\""); break; } } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitErroneous(VisageErroneous tree) { try { print("(ERROR)"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitModifiers(VisageModifiers mods) { try { printFlags(mods.flags); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitTree(VisageTree tree) { try { print("(UNKNOWN: " + tree + ")"); println(); } catch (IOException e) { throw new UncheckedIOException(e); } } private String posAsString(int pos) { if (pos == Position.NOPOS || sourceContent == null) { return "%?%"; } int line = 1; int bp = 0; while (bp < sourceContent.length() && bp < pos) { switch (sourceContent.charAt(bp++)) { case 0xD: //CR if (bp < sourceContent.length() && sourceContent.charAt(bp) == 0xA) { bp++; } line++; break; case 0xA: //LF line++; break; } } return " %(" + pos + ")" + line + "% "; } private void printInterpolateValue(VisageInterpolateValue tree) { try { if (tree.getAttribute() != null) { print(tree.getAttribute()); print("=>"); } print(tree.getValue()); printTween(tree); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitClassDeclaration(VisageClassDeclaration tree) { try { int oldScope = variableScope; variableScope = SCOPE_CLASS; println(); align(); printDocComment(tree); printFlags(tree.getModifiers().flags); print("class "); Name n = tree.getName(); print(n == null ? "<anonymous>" : n); if (tree.getSupertypes().nonEmpty()) { print(" extends"); for (VisageExpression sup : tree.getSupertypes()) { print(" "); printExpr(sup); } } print(" {"); println(); indent(); for (VisageTree mem : tree.getMembers()) { align(); printExpr(mem); } undent(); println(); print("}"); println(); align(); variableScope = oldScope; } catch (IOException e) { throw new UncheckedIOException(e); } } public static void visitFunctionValue(VisagePretty pretty, VisageFunctionValue tree) { try { pretty.println(); pretty.align(); pretty.printDocComment(tree); pretty.print("function "); pretty.print("("); pretty.printExprs(tree.getParams()); pretty.print(")"); if (tree.getType() != null) { pretty.printExpr(tree.getType()); } VisageBlock body = tree.getBodyExpression(); if (body != null) { if (body instanceof VisageErroneousBlock) { pretty.print("<erroroneous>"); } else { pretty.printExpr(body); } } pretty.println(); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitFunctionValue(VisageFunctionValue tree) { visitFunctionValue(this, tree); } public static void visitFunctionDefinition(VisagePretty pretty, VisageFunctionDefinition tree) { try { VisagePretty visagepretty = (VisagePretty)pretty; int oldScope = visagepretty.variableScope; pretty.println(); pretty.align(); pretty.printDocComment(tree); pretty.printExpr(tree.mods); pretty.print("function "); pretty.print(tree.name); pretty.print("("); visagepretty.variableScope = SCOPE_PARAMS; pretty.printExprs(tree.getParams()); visagepretty.variableScope = SCOPE_METHOD; pretty.print(")"); if (tree.operation.rettype != null && tree.operation.rettype.getVisageTag() != VisageTag.TYPEUNKNOWN) { pretty.print(" : "); pretty.printExpr(tree.operation.rettype); } VisageBlock body = tree.getBodyExpression(); if (body != null) { pretty.print(" "); pretty.printExpr(body); } pretty.println(); visagepretty.variableScope = oldScope; } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitFunctionDefinition(VisageFunctionDefinition tree) { visitFunctionDefinition(this, tree); } public void visitInitDefinition(VisageInitDefinition tree) { try { println(); align(); printDocComment(tree); print("init "); print(tree.getBody()); println(); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitPostInitDefinition(VisagePostInitDefinition tree) { try { println(); align(); printDocComment(tree); print("postinit "); print(tree.getBody()); println(); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitBlockExpression(VisageBlock tree) { visitBlockExpression(this, tree); } public static void visitBlockExpression(VisagePretty pretty, VisageBlock tree) { try { pretty.printFlags(tree.flags); pretty.print("{"); pretty.println(); pretty.indent(); pretty.printStats(tree.stats); if (tree.value != null) { pretty.align(); pretty.printExpr(tree.value); pretty.println(); } pretty.undent(); pretty.align(); pretty.print("}"); } catch (IOException e) { throw new UncheckedIOException(e); } } void printBind(VisageBindStatus bindStatus) { try { if (bindStatus.isUnidiBind()) { print(" bind "); } if (bindStatus.isBidiBind()) { print(" bind /*bi-directional*/ "); } } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitSequenceEmpty(VisageSequenceEmpty that) { try { print("[]"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitSequenceRange(VisageSequenceRange that) { try { print("["); printExpr(that.getLower()); print(".."); printExpr(that.getUpper()); if (that.getStepOrNull() != null) { print("step "); printExpr(that.getStepOrNull()); } if (that.isExclusive()) { print(" exclusive"); } print("]"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitSequenceExplicit(VisageSequenceExplicit that) { try { boolean first = true; print("["); for (VisageExpression expr : that.getItems()) { if (!first) { print(", "); } first = false; printExpr(expr); } print("]"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitSequenceIndexed(VisageSequenceIndexed that) { try { printExpr(that.getSequence()); print("[ "); printExpr(that.getIndex()); print("]"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitSequenceSlice(VisageSequenceSlice that) { try { printExpr(that.getSequence()); print("[ "); printExpr(that.getFirstIndex()); print(" .. "); printExpr(that.getLastIndex()); print("]"); } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitSequenceInsert(VisageSequenceInsert that) { try { print("insert "); printExpr(that.getElement()); print(" into "); printExpr(that.getSequence()); print("; "); } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitSequenceDelete(VisageSequenceDelete that) { try { print("delete "); printExpr(that.getSequence()); if (that.getElement() != null) { print(" ("); printExpr(that.getElement()); print(")"); } print("; "); } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitInvalidate(VisageInvalidate that) { try { print("invalidate "); printExpr(that.getVariable()); print("; "); } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitStringExpression(VisageStringExpression tree) { try { int i; List<VisageExpression> parts = tree.getParts(); for (i = 0; i < parts.length() - 1; i += 3) { printExpr(parts.get(i)); print("{"); VisageExpression format = parts.get(i + 1); if (format != null) { printExpr(format); } printExpr(parts.get(i + 2)); print("}"); } printExpr(parts.get(i)); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitInstanciate(VisageInstanciate tree) { try { VisageExpression id = tree.getIdentifier(); if (tree.getArgs().nonEmpty()) print("new "); if (id != null) { printExpr(id); } if (tree.getArgs().nonEmpty()) { // Java constructor call print("("); printExprs(tree.getArgs()); print(")"); } { // Visage instantiation print(" {"); if (tree.getParts().nonEmpty()) { indent(); for (VisageObjectLiteralPart mem : tree.getParts()) { println(); align(); printExpr(mem); } //TODO: add defs undent(); println(); align(); } if (tree.getClassBody() != null) { printExpr(tree.getClassBody()); } print("}"); } } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitObjectLiteralPart(VisageObjectLiteralPart tree) { try { print(tree.getName()); print(": "); printBind(tree.getExplicitBindStatus()); printExpr(tree.getExpression()); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitTypeAny(VisageTypeAny tree) { try { print("* "); print(ary(tree)); } catch (IOException e) { throw new UncheckedIOException(e); } } public void printTypeSpecifier(VisageType type) { try { if (type instanceof VisageTypeUnknown) return; print(": "); printExpr(type); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitTypeClass(VisageTypeClass tree) { try { print(tree.getClassName()); print(ary(tree)); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitTypeFunctional(VisageTypeFunctional tree) { try { print("("); List<VisageType> params = tree.getParams(); if (params.nonEmpty()) { printTypeSpecifier(params.head); for (List<VisageType> l = params.tail; l.nonEmpty(); l = l.tail) { print(", "); printTypeSpecifier(l.head); } } print(")"); printTypeSpecifier((VisageType)tree.getReturnType()); print(ary(tree)); } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitTypeArray(VisageTypeArray tree) { try { print("nativearray of "); printTypeSpecifier(tree.getElementType()); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitTypeUnknown(VisageTypeUnknown tree) { try { print(ary(tree)); } catch (IOException e) { throw new UncheckedIOException(e); } } String ary(VisageType tree) { switch (tree.getCardinality()) { case ANY: return "[]"; case SINGLETON: return ""; } return ""; } public void visitVarInit(VisageVarInit tree) { try { print("var-init: "); print(tree.getVar()); } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitVarRef(VisageVarRef tree) { try { print(tree.getVarRefKind() + "(" + tree.getExpression() + ")"); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitVar(VisageVar tree) { try { if (docComments != null && docComments.get(tree) != null) { println(); align(); } printDocComment(tree); printExpr(tree.mods); if (variableScope != SCOPE_PARAMS) { if ((tree.getModifiers().flags & VisageFlags.IS_DEF) != 0) { print("def "); } else { print("var "); } } print(tree.getName()); if (tree.getVisageType() != null && tree.getVisageType().getVisageTag() != VisageTag.TYPEANY) { printTypeSpecifier(tree.getVisageType()); } if (variableScope != SCOPE_PARAMS) { if (tree.getInitializer() != null) { print(" = "); if (tree.isBound()) print("bind "); printExpr(tree.getInitializer()); if (tree.isBidiBind()) print(" with inverse"); } } if (tree.getOnReplace() != null) { printExpr(tree.getOnReplace()); } if (tree.getOnInvalidate() != null) { printExpr(tree.getOnInvalidate()); } print(";"); if (variableScope == SCOPE_OUTER || variableScope == SCOPE_CLASS) { println(); } } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitOverrideClassVar(VisageOverrideClassVar tree) { try { print("override var "); printExpr(tree.getId()); if (tree.getInitializer() != null) { print(" = "); if (tree.isBound()) { print("bind "); } printExpr(tree.getInitializer()); if (tree.isBidiBind()) { print(" with inverse"); } } print(" "); align(); if (tree.getOnReplace() != null) { printExpr(tree.getOnReplace()); } if (tree.getOnInvalidate() != null) { printExpr(tree.getOnInvalidate()); } } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitOnReplace(VisageOnReplace tree) { try { String triggerKind = tree.getTriggerKind() == VisageOnReplace.Kind.ONREPLACE ? "replace" : "invalidate"; print(" on " + triggerKind); if (tree.getOldValue() != null) { print(" "); printExpr(tree.getOldValue()); } if (tree.getFirstIndex() != null) { print("["); printExpr(tree.getFirstIndex()); if (tree.getLastIndex() != null) { print(" .. "); printExpr(tree.getLastIndex()); } print(" ]"); } if (tree.getNewElements() != null) { print("= "); printExpr(tree.getNewElements()); } print(" "); if (tree.getBody() != null) { printExpr(tree.getBody()); } } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitForExpression(VisageForExpression tree) { try { boolean first = true; print("for ("); for (ForExpressionInClauseTree cl : tree.getInClauses()) { // Don't try to examine erroneous in clauses. We don't wish to // place the entire for expression into error nodes, just because // one or more in clauses was in error, so we jsut skip any // erroneous ones. // if (cl == null || cl instanceof VisageErroneousForExpressionInClause) { continue; } VisageForExpressionInClause clause = (VisageForExpressionInClause)cl; if (first) { first = false; } else { print(", "); } VisageVar var = clause.getVar(); // Don't try to examine erroneous loop controls, such as // when a variable was missing. Again, this is because the IDE may // try to attribute a node that is mostly correct, but contains // one or more components that are in error. // if (var == null || var instanceof VisageErroneousVar) { print("<missing>)"); } else { print(var.getName()); } print(" in "); VisageExpression e1 = clause.getSequenceExpression(); if (e1 == null || e1 instanceof VisageErroneous) { print("<error>"); } else { printExpr(e1); } if (clause.getWhereExpression() != null) { print(" where "); printExpr(clause.getWhereExpression()); } } print(") "); VisageExpression body = tree.getBodyExpression(); if (body == null || body instanceof VisageErroneous) { print(" {}\n"); } else { printExpr(body); } } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitIndexof(VisageIndexof that) { try { print("indexof "); print(that.fname); } catch (IOException e) { throw new UncheckedIOException(e); } } //@Override public void visitForExpressionInClause(VisageForExpressionInClause that) { try { if (that.var == null || that.var instanceof VisageErroneousVar) { print("<missing var>"); } else { print(that.var); } print(" in "); if (that.seqExpr == null || that.seqExpr instanceof VisageErroneous) { print("<missing expr>"); } else { print(that.seqExpr); } if (that.getWhereExpression() != null) { print(" where "); if (that.getWhereExpression() instanceof VisageErroneous) { print("<erroreous where>"); } else { print(that.getWhereExpression()); } } } catch (IOException e) { throw new UncheckedIOException(e); } } /** Convert a tree to a pretty-printed string. */ public static String toString(VisageTree tree) { StringWriter s = new StringWriter(); try { new VisagePretty(s, false).printExpr(tree); } catch (IOException e) { // should never happen, because StringWriter is defined // never to throw any IOExceptions throw new AssertionError(e); } return s.toString(); } public void visitTimeLiteral(VisageTimeLiteral tree) { try { Double d = ((Number)tree.value.value).doubleValue(); d /= tree.duration.getMultiplier(); print(d + tree.duration.getSuffix()); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitLengthLiteral(VisageLengthLiteral tree) { try { Double d = ((Number)tree.value.value).doubleValue(); print(d + tree.units.getSuffix()); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitAngleLiteral(VisageAngleLiteral tree) { try { Double d = ((Number)tree.value.value).doubleValue(); print(d + tree.units.getSuffix()); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitColorLiteral(VisageColorLiteral tree) { try { Integer i = ((Number)tree.value.value).intValue(); print("#" + Integer.toHexString(i)); } catch (IOException e) { throw new UncheckedIOException(e); } } public void visitInterpolateValue(VisageInterpolateValue tree) { printInterpolateValue(tree); } private void printTween(VisageInterpolateValue tree) throws IOException { VisageExpression tween = tree.getInterpolation(); if (tween != null) { print(" tween "); print(tween); } } public void visitKeyFrameLiteral(VisageKeyFrameLiteral tree) { try { print("at ("); print(tree.getStartDuration()); print(") {"); println(); indent(); printStats(List.convert(VisageTree.class, tree.getInterpolationValues())); if (tree.getTrigger() != null) { align(); print("trigger "); visitBlockExpression(this, (VisageBlock)tree.getTrigger()); } undent(); println(); align(); print("}"); } catch (IOException e) { throw new UncheckedIOException(e); } } }