/*
* Copyright 1999-2006 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* 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 com.sun.tools.javac.tree;
import static com.sun.tools.javac.code.Flags.ANNOTATION;
import static com.sun.tools.javac.code.Flags.ARRAYCONSTR;
import static com.sun.tools.javac.code.Flags.DPJStandardFlags;
import static com.sun.tools.javac.code.Flags.ENUM;
import static com.sun.tools.javac.code.Flags.INTERFACE;
import static com.sun.tools.javac.code.Flags.SYNTHETIC;
import static com.sun.tools.javac.code.Flags.VARARGS;
import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.code.TypeTags;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.tree.JCTree.DPJAtomic;
import com.sun.tools.javac.tree.JCTree.DPJCobegin;
import com.sun.tools.javac.tree.JCTree.DPJFinish;
import com.sun.tools.javac.tree.JCTree.DPJForLoop;
import com.sun.tools.javac.tree.JCTree.DPJNegationExpression;
import com.sun.tools.javac.tree.JCTree.DPJNonint;
import com.sun.tools.javac.tree.JCTree.DPJParamInfo;
import com.sun.tools.javac.tree.JCTree.DPJRegionDecl;
import com.sun.tools.javac.tree.JCTree.DPJRegionParameter;
import com.sun.tools.javac.tree.JCTree.DPJRegionPathList;
import com.sun.tools.javac.tree.JCTree.DPJRegionPathListElt;
import com.sun.tools.javac.tree.JCTree.DPJSpawn;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
import com.sun.tools.javac.tree.JCTree.JCAssert;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCAssignOp;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCatch;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCConditional;
import com.sun.tools.javac.tree.JCTree.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
import com.sun.tools.javac.tree.JCTree.JCErroneous;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCForLoop;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCIf;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCParens;
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCSkip;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCSwitch;
import com.sun.tools.javac.tree.JCTree.JCSynchronized;
import com.sun.tools.javac.tree.JCTree.JCThrow;
import com.sun.tools.javac.tree.JCTree.JCTry;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.JCTree.LetExpr;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
import com.sun.tools.javac.util.Convert;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Pair;
/** 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 that 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>
*/
public class Pretty extends JCTree.Visitor {
/**
* No code gen, just pretty print the AST
*/
public static final int NONE = 0;
/**
* Sequential code gen
*/
public static final int SEQ = 1;
/**
* Sequential code gen with instrumentation
*/
public static final int SEQ_INST = 2;
/**
* Parallel code gen
*/
public static final int PAR = 3;
/**
* Code generation mode. We are using the Pretty printer as a code generator,
* so we have to keep track of what kind of code generation we are doing.
*/
public int codeGenMode = NONE;
/**
* Set if we need to compile to sequential code.
*/
public boolean sequential = false;
private Log log;
public Pretty(Writer out, boolean sourceOutput,
int codeGenMode) {
this.out = out;
this.sourceOutput = sourceOutput;
this.codeGenMode = codeGenMode;
switch (codeGenMode) {
case SEQ_INST:
case SEQ:
this.sequential = true;
default:
break;
}
}
// Note: The following two methods are a HACK to work around
// the fact that the javac implementation of enums is broken! Without
// these flags, we get strange output that is not legal
// Java code.
//
/** Set if we are in an enum block
*/
public boolean inEnumBlock = false;
/** Set if we are in an enum variable declaration
*/
public boolean inEnumVarDecl = false;
/**
* Set if we need to DPJplicate this
*/
private boolean thisIsBogus = false;
/** 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
* source.
*/
private 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;
/** The enclosing class name.
*/
Name enclClassName;
/** A hashtable mapping trees to their documentation comments
* (can be null)
*/
Map<JCTree, String> docComments = null;
/** Align code to be indented to left margin.
*/
void align() throws IOException {
for (int i = 0; i < lmargin; i++) out.write(" ");
}
/** Increase left margin by indentation width.
*/
void indent() {
lmargin = lmargin + width;
}
/** Decrease left margin by indentation width.
*/
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 {
out.write(Convert.escapeUnicode(s.toString()));
}
public void printAligned(Object s) throws IOException {
align();
print(s);
}
/** 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 Error {
static final long serialVersionUID = -4032692679158424751L;
UncheckedIOException(IOException e) {
super(e.getMessage(), e);
}
}
/** Visitor argument: the current precedence level.
*/
int prec;
/** Visitor method: print expression tree.
* @param prec The current precedence level.
*/
public void printExpr(JCTree tree, int prec) throws IOException {
int prevPrec = this.prec;
try {
this.prec = prec;
if (tree == null) 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(JCTree tree) throws IOException {
printExpr(tree, TreeInfo.noPrec);
}
/** Derived visitor method: print statement tree.
*/
public void printStat(JCTree tree) throws IOException {
printExpr(tree, TreeInfo.notExpression);
}
/** Derived visitor method: print list of expression trees, separated by given string.
* @param sep the separator string
*/
public <T extends JCTree> 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 JCTree> 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 JCTree> trees) throws IOException {
for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
if ((codeGenMode == NONE) || !(l.head instanceof DPJRegionDecl)) {
align();
printStat(l.head);
println();
}
}
}
public void printCobeginStats(List<? extends JCTree> trees) throws IOException {
int count = 0;
for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
if ((codeGenMode == NONE) || !(l.head instanceof DPJRegionDecl)) {
align();
printStat(l.head);
println();
if (++count < l.size()) {
align();
if (codeGenMode == SEQ_INST) print("DPJRuntime.Instrument.cobeginSeparator();");
println();
}
}
}
}
/** Print a set of modifiers.
*/
public void printFlags(long flags) throws IOException {
if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ ");
print(TreeInfo.flagNames(flags));
if ((flags & DPJStandardFlags) != 0) print(" ");
if ((flags & ANNOTATION) != 0) print("@");
}
public void printAnnotations(List<JCAnnotation> trees) throws IOException {
for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
printStat(l.head);
println();
align();
}
}
/** Print documentation comment, if it exists
* @param tree The tree for which a documentation comment should be printed.
*/
public void printDocComment(JCTree tree) throws IOException {
if (docComments != null) {
String dc = docComments.get(tree);
if (dc != null) {
print("/**"); println();
int pos = 0;
int endpos = lineEndPos(dc, pos);
while (pos < dc.length()) {
align();
print(" *");
if (pos < dc.length() && dc.charAt(pos) > ' ') print(" ");
print(dc.substring(pos, endpos)); println();
pos = endpos + 1;
endpos = lineEndPos(dc, pos);
}
align(); print(" */"); println();
align();
}
}
}
//where
static int lineEndPos(String s, int start) {
int pos = s.indexOf('\n', start);
if (pos < 0) pos = s.length();
return pos;
}
/** Print region parameter constraints
*/
public void printConstraints(List<Pair<DPJRegionPathList,DPJRegionPathList>> constraints)
throws IOException {
if (constraints.nonEmpty()) {
print(" | ");
int count = 0;
for (Pair<DPJRegionPathList,DPJRegionPathList> pair : constraints) {
if (count++ > 0) print(", ");
print(pair.fst);
print(" # ");
print(pair.snd);
}
}
}
/** If parameter list is non-empty, print it enclosed in "<...>" brackets.
*/
public void printTypeRegionEffectParams(List<JCTypeParameter> typeParams,
DPJParamInfo paramInfo) throws IOException {
if (typeParams.nonEmpty()) {
print("<");
printExprs(typeParams);
print(">");
}
}
/** If there are type or region parameters, print both
*/
public void printParams(List<JCTypeParameter> typarams, DPJParamInfo rgnparaminfo)
throws IOException {
boolean printRegionParams = ((codeGenMode == NONE) && rgnparaminfo != null &&
rgnparaminfo.rplParams.nonEmpty());
if (typarams.nonEmpty() || printRegionParams) {
print("<");
printExprs(typarams);
if (printRegionParams) {
if (typarams.nonEmpty()) print(", ");
print("region ");
printExprs(rgnparaminfo.rplParams);
printConstraints(rgnparaminfo.rplConstraints);
}
print(">");
}
}
/** Print a block.
*/
public void printBlock(List<? extends JCTree> stats) throws IOException {
print("{");
println();
indent();
printStats(stats);
undent();
align();
print("}");
}
public void printCobeginBlock(List<? extends JCTree> stats) throws IOException {
print("{");
println();
indent();
printCobeginStats(stats);
undent();
align();
print("}");
}
/** Print a block.
*/
public void printEnumBody(List<JCTree> stats) throws IOException {
print("{");
println();
indent();
boolean first = true;
for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
if (isEnumerator(l.head)) {
if (!first) {
print(",");
println();
}
align();
printStat(l.head);
first = false;
}
}
print(";");
println();
inEnumBlock = true;
for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
if (!isEnumerator(l.head)) {
align();
printStat(l.head);
println();
}
}
inEnumBlock = false;
undent();
align();
print("}");
}
/** Is the given tree an enumerator definition? */
boolean isEnumerator(JCTree t) {
return t.getTag() == JCTree.VARDEF && (((JCVariableDecl) t).mods.flags & ENUM) != 0;
}
/** 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(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
docComments = tree.docComments;
printDocComment(tree);
if (tree.pid != null) {
print("package ");
printExpr(tree.pid);
print(";");
println();
}
boolean firstImport = true;
for (List<JCTree> l = tree.defs;
l.nonEmpty() && (cdef == null || l.head.getTag() == JCTree.IMPORT);
l = l.tail) {
if (l.head.getTag() == JCTree.IMPORT) {
JCImport imp = (JCImport)l.head;
Name name = TreeInfo.name(imp.qualid);
if (name == name.table.asterisk ||
cdef == null ||
isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
if (firstImport) {
firstImport = false;
println();
}
printStat(imp);
}
} else {
printStat(l.head);
}
}
if (cdef != null) {
printStat(cdef);
println();
}
}
// where
boolean isUsed(final Symbol t, JCTree cdef) {
class UsedVisitor extends TreeScanner {
public void scan(JCTree tree) {
if (tree!=null && !result) tree.accept(this);
}
boolean result = false;
public void visitIdent(JCIdent tree) {
if (tree.sym == t) result = true;
}
}
UsedVisitor v = new UsedVisitor();
v.scan(cdef);
return v.result;
}
/**************************************************************************
* Visitor methods
*************************************************************************/
public void visitTopLevel(JCCompilationUnit tree) {
try {
printUnit(tree, null);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
boolean inImport = false;
public void visitImport(JCImport tree) {
try {
inImport = true;
print("import ");
if (tree.staticImport) print("static ");
printExpr(tree.qualid);
print(";");
println();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
finally {
inImport = false;
}
}
public void visitClassDef(JCClassDecl tree) {
try {
println(); align();
printDocComment(tree);
printAnnotations(tree.mods.annotations);
printFlags(tree.mods.flags & ~INTERFACE);
Name enclClassNamePrev = enclClassName;
enclClassName = tree.name;
if ((tree.mods.flags & INTERFACE) != 0) {
print("interface " + tree.name);
printParams(tree.typarams, tree.paramInfo);
if (tree.implementing.nonEmpty()) {
print(" extends ");
printExprs(tree.implementing);
}
} else {
if ((tree.mods.flags & ENUM) != 0)
print("enum " + tree.name);
else
print("class " + tree.name);
printParams(tree.typarams, tree.paramInfo);
if (tree.extending != null) {
print(" extends ");
printExpr(tree.extending);
}
if (tree.implementing.nonEmpty()) {
print(" implements ");
printExprs(tree.implementing);
}
}
print(" ");
if ((tree.mods.flags & ENUM) != 0) {
printEnumBody(tree.defs);
} else {
printBlock(tree.defs);
}
enclClassName = enclClassNamePrev;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitMethodDef(JCMethodDecl tree) {
try {
// when producing source output, omit anonymous constructors
if (tree.name == tree.name.table.init &&
(enclClassName == null ||
enclClassName.toString().equals("")) &&
sourceOutput) return;
println(); align();
printDocComment(tree);
printExpr(tree.mods);
printParams(tree.typarams, tree.paramInfo);
if (tree.name == tree.name.table.init) {
print(enclClassName != null ? enclClassName : tree.name);
} else {
printExpr(tree.restype);
print(" " + tree.name);
}
print("(");
printExprs(tree.params);
print(")");
if (tree.effects != null && (codeGenMode == NONE)) {
if (tree.effects.isPure) {
print(" pure");
} else {
if (tree.effects.readEffects.nonEmpty()) {
print(" reads ");
printExprs(tree.effects.readEffects);
}
if (tree.effects.writeEffects.nonEmpty()) {
print(" writes ");
printExprs(tree.effects.writeEffects);
}
}
}
if (tree.thrown.nonEmpty()) {
print(" throws ");
printExprs(tree.thrown);
}
if (tree.body != null) {
print(" ");
printStat(tree.body);
} else {
print(";");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitVarDef(JCVariableDecl tree) {
try {
if (docComments != null && docComments.get(tree) != null) {
println(); align();
}
printDocComment(tree);
if ((tree.mods.flags & ENUM) != 0) {
//print("/*public static final*/ ");
print(tree.name);
if (tree.init != null) {
//print(" /* = ");
inEnumVarDecl = true;
printExpr(tree.init);
inEnumVarDecl = false;
//print(" */");
}
} else {
printExpr(tree.mods);
if ((tree.mods.flags & VARARGS) != 0) {
printExpr(((JCArrayTypeTree) tree.vartype).elemtype);
print("... " + tree.name);
} else {
printExpr(tree.vartype);
print(" " + tree.name);
}
// DPJ BEGIN
if ((codeGenMode == NONE) && tree.rpl != null && !tree.rpl.elts.isEmpty()) {
print(" in ");
print(tree.rpl);
}
// DPJ END
if (tree.init != null) {
print(" = ");
printExpr(tree.init);
}
if (prec == TreeInfo.notExpression) print(";");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitRegionDecl(DPJRegionDecl tree) { // DPJ -- based on visitVarDef
try {
if (docComments != null && docComments.get(tree) != null) {
println(); align();
}
printDocComment(tree);
printExpr(tree.mods);
print("region ");
if (tree.isAtomic)
print("atomic ");
print(tree.name);
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitRPLElt(DPJRegionPathListElt tree) { // DPJ
try {
switch (tree.type) {
case DPJRegionPathListElt.STAR:
print("*");
break;
case DPJRegionPathListElt.NAME:
// case DPJRegionPathListElt.FIELD_REGION:
print(tree.exp);
break;
case DPJRegionPathListElt.ARRAY_INDEX:
print("[");
print(tree.exp);
print("]");
break;
case DPJRegionPathListElt.ARRAY_UNKNOWN:
print("[?]");
break;
default:
print("Unknown RPL element");
break;
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitRPL(DPJRegionPathList tree) { // DPJ
try {
int size = tree.elts.size();
int idx = 0;
for (Iterator<DPJRegionPathListElt> I = tree.elts.iterator();
I.hasNext(); ) {
visitRPLElt(I.next());
if (++idx < size) print(":");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitSkip(JCSkip tree) {
try {
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitBlock(JCBlock tree) {
try {
printFlags(tree.flags);
printBlock(tree.stats);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitDoLoop(JCDoWhileLoop tree) {
try {
print("do ");
printStat(tree.body);
align();
print(" while ");
if (tree.cond.getTag() == JCTree.PARENS) {
printExpr(tree.cond);
} else {
print("(");
printExpr(tree.cond);
print(")");
}
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitWhileLoop(JCWhileLoop tree) {
try {
print("while ");
if (tree.cond.getTag() == JCTree.PARENS) {
printExpr(tree.cond);
} else {
print("(");
printExpr(tree.cond);
print(")");
}
print(" ");
printStat(tree.body);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitForLoop(JCForLoop tree) {
try {
print("for (");
if (tree.init.nonEmpty()) {
if (tree.init.head.getTag() == JCTree.VARDEF) {
printExpr(tree.init.head);
for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) {
JCVariableDecl vdef = (JCVariableDecl)l.head;
print(", " + vdef.name + " = ");
printExpr(vdef.init);
}
} else {
printExprs(tree.init);
}
}
print("; ");
if (tree.cond != null) printExpr(tree.cond);
print("; ");
printExprs(tree.step);
print(") ");
printStat(tree.body);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitForeachLoop(JCEnhancedForLoop tree) {
try {
print("for (");
printExpr(tree.var);
print(" : ");
printExpr(tree.expr);
print(") ");
printStat(tree.body);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void seqDPJForLoop(DPJForLoop tree) {
try {
if (codeGenMode == SEQ_INST) {
print("DPJRuntime.Instrument.enterForeach(");
if (tree.length != null)
print(tree.length);
else
print(tree.start + ".size()");
print(");");
println();
align();
}
int depth = lmargin / width;
if (tree.length == null) {
// Iterator form of foreach
print("{\n");
indent();
align();
printType(tree.start.type);
print(" ");
print("i_"); print(depth); print(" = ");
printExpr(tree.start);
print(";\n");
align();
print("DPJIterator.Status<"+tree.var.type+
"> status_"+depth+"=null;\n");
align();
print ("while ((status_"+depth+"=i_"+depth+
".next()).hasElement()) {\n");
} else {
// Indexed form of foreach
print("for (");
long flags = tree.var.mods.flags;
tree.var.mods.flags &= ~Flags.FINAL;
printExpr(tree.var);
tree.var.mods.flags = flags;
print(" = ");
printExpr(tree.start);
print(", ");
print("i_"); print(depth); print(" = ");
print("0");
print("; i_"); print(depth);
print(" < ");
printExpr(tree.length);
print("; ");
print(tree.var.name);
if (tree.stride != null) {
print(" += ");
printExpr(tree.stride);
} else {
print("++");
}
print(", ++i_"); print(depth);
print(") {\n");
}
indent();
align();
if (codeGenMode == SEQ_INST) {
print("DPJRuntime.Instrument.enterForeachIter();\n");
align();
}
if (tree.length == null) {
printExpr(tree.var);
print(" = ");
print("status_"); print(depth);
print(".getElement();\n");
align();
}
printStat(tree.body);
println();
if(codeGenMode == SEQ_INST) {
align();
print("DPJRuntime.Instrument.exitForeachIter();\n");
}
undent();
align();
print("}\n");
if (tree.length == null) {
undent();
align();
print("}\n");
}
align();
if(codeGenMode == SEQ_INST) print("DPJRuntime.Instrument.exitForeach();");
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
Types.printDPJ = true;
}
}
private void parDPJForLoop(DPJForLoop tree) {
try {
Types.printDPJ = false;
List<String> toCoInvoke = List.<String>nil();
List<String> copyOutAssign = List.<String>nil();
println();
String stName = "__dpj_S"+dpj_tname++;
printAligned("class " + stName + " extends RecursiveAction {\n");
indent();
printAligned("int __dpj_begin;\n");
printAligned("int __dpj_length;\n");
printAligned("int __dpj_stride;\n");
align();
Set<VarSymbol> copyIn = new HashSet(tree.usedVars);
copyIn.removeAll(tree.declaredVars);
Set<VarSymbol> copyOut = new HashSet(tree.definedVars);
copyOut.removeAll(tree.declaredVars);
if(copyOut.size()>0 && !tree.isNondet)
// In real life this should have been caught by the type checker.
print("Error: Assignment inside foreach to local variable declared prior to foreach\n");
// Don't copy field values in/out, which would interfere with the STM system.
// TODO Is this the best way to handle this issue?
if (tree.isNondet) {
Set<VarSymbol> dontInclude = new HashSet<VarSymbol>();
for (VarSymbol var : copyIn)
if (var.owner.kind != Kinds.MTH && !var.toString().equals("this"))
dontInclude.add(var);
for (VarSymbol var : copyOut)
if (var.owner.kind != Kinds.MTH && !var.toString().equals("this"))
dontInclude.add(var);
copyIn.removeAll(dontInclude);
copyOut.removeAll(dontInclude);
}
Set<VarSymbol> copyAll = new HashSet(copyIn);
copyAll.addAll(copyOut);
// Declare local vars necessary for copyin/copyout
for(VarSymbol var : copyAll) {
printType(var.type);
print(" ");
print(varString(var)+";\n");
align();
}
//Generate constructor for class
print(stName+"(int __dpj_begin, int __dpj_length, int __dpj_stride");
for(VarSymbol var : copyIn) {
print(", ");
printType(var.type);
print(" "+varString(var));
}
print(") {\n");
indent(); align();
print("this.__dpj_begin = __dpj_begin;\n"); align();
print("this.__dpj_length = __dpj_length;\n"); align();
print("this.__dpj_stride = __dpj_stride;\n");
for(VarSymbol var : copyIn) {
align();
print("this."+varString(var)+"="+varString(var)+";\n");
}
undent();
align();
print("}\n");
//Generate run method
printAligned("protected void compute() {\n");
indent();
printAligned("if((__dpj_length / __dpj_stride) > DPJRuntime.RuntimeState.dpjForeachCutoff) {\n");
indent();
printAligned("RecursiveAction[] __dpj_splits = new RecursiveAction[DPJRuntime.RuntimeState.dpjForeachSplit];\n");
printAligned("for(int i=0; i<DPJRuntime.RuntimeState.dpjForeachSplit; i++)\n");
indent();
printAligned("__dpj_splits[i] = new "+stName+"(__dpj_begin + (__dpj_length/DPJRuntime.RuntimeState.dpjForeachSplit)*i, (i+1==DPJRuntime.RuntimeState.dpjForeachSplit) ? (__dpj_length - __dpj_length/DPJRuntime.RuntimeState.dpjForeachSplit*i) : (__dpj_length/DPJRuntime.RuntimeState.dpjForeachSplit), __dpj_stride");
for(VarSymbol var : copyIn)
print(", "+varString(var));
print(");\n");
undent();
printAligned("RecursiveAction.forkJoin(__dpj_splits);\n");
undent();
printAligned("}\n");
printAligned("else {\n");
indent();
long flags = tree.var.mods.flags;
tree.var.mods.flags &= ~Flags.FINAL;
printAligned("for("+tree.var.toString()+" = __dpj_begin; "+tree.var.sym.toString()+" < __dpj_begin + __dpj_length * __dpj_stride; "+tree.var.sym.toString()+"+=__dpj_stride)\n");
tree.var.mods.flags = flags;
indent();
align();
boolean wasBogus = thisIsBogus;
thisIsBogus=true;
printStat(tree.body);
thisIsBogus=wasBogus;
undent();
printAligned("}\n"); //end else
undent();
printAligned("}\n"); //end run
undent();
printAligned("};\n"); //close class block
//Okay, now generate the actual invocation
align();
print("if(!DPJRuntime.RuntimeState.insideParallelTask) {\n");
indent();
printAligned("DPJRuntime.RuntimeState.insideParallelTask = true;\n");
printAligned("DPJRuntime.RuntimeState.pool.invoke(new "+stName+"("+tree.start.toString()+", "+(tree.length==null ? tree.start.toString()+".size()" : tree.length.toString())+", "+(tree.stride==null ? "1" : tree.stride.toString()));
for(VarSymbol var : copyIn)
{
align();
if(var.toString().equals("this") && !thisIsBogus)
print(", this");
else
print(", "+varString(var));
}
print("));\n");
align();
print("DPJRuntime.RuntimeState.insideParallelTask = false;\n");
undent();
align();
print("}\n");
align();
print("else\n");
indent();
printAligned("(new "+stName+"("+tree.start.toString()+", "+
(tree.length==null ?
tree.start.toString()+".size()" :
tree.length.toString()) +
", "+(tree.stride==null ? "1" : tree.stride.toString()));
for(VarSymbol var : copyIn)
{
align();
if(var.toString().equals("this") && !thisIsBogus)
print(", this");
else
print(", "+varString(var));
}
print(")).forkJoin();\n");
undent();
}
catch(IOException e) {
throw new UncheckedIOException(e);
}
finally {
Types.printDPJ = true;
}
}
private String varString(VarSymbol maybeThis) {
if(maybeThis.toString().equals("this"))
return "__dpj_this";
else
return maybeThis.toString();
}
public void visitDPJForLoop(DPJForLoop tree) {
if (codeGenMode == NONE) {
try {
if (tree.isNondet) {
print("foreach_nd (");
} else {
print("foreach (");
}
long flags = tree.var.mods.flags;
tree.var.mods.flags &= ~Flags.FINAL;
printExpr(tree.var);
tree.var.mods.flags = flags;
print(" in ");
printExpr(tree.start);
if (tree.length != null) {
print(", ");
printExpr(tree.length);
}
if (tree.stride != null) {
print(", ");
printExpr(tree.stride);
}
print(") ");
printStat(tree.body);
}
catch(IOException e) {
throw new UncheckedIOException(e);
}
} else if(sequential || tree.length==null) {
seqDPJForLoop(tree);
} else {
parDPJForLoop(tree);
}
}
public void visitLabelled(JCLabeledStatement tree) {
try {
print(tree.label + ": ");
printStat(tree.body);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitSwitch(JCSwitch tree) {
try {
print("switch ");
if (tree.selector.getTag() == JCTree.PARENS) {
printExpr(tree.selector);
} else {
print("(");
printExpr(tree.selector);
print(")");
}
print(" {");
println();
printStats(tree.cases);
align();
print("}");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitCase(JCCase tree) {
try {
if (tree.pat == null) {
print("default");
} else {
print("case ");
printExpr(tree.pat);
}
print(": ");
println();
indent();
printStats(tree.stats);
undent();
align();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitSynchronized(JCSynchronized tree) {
try {
print("synchronized ");
if (tree.lock.getTag() == JCTree.PARENS) {
printExpr(tree.lock);
} else {
print("(");
printExpr(tree.lock);
print(")");
}
print(" ");
printStat(tree.body);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitTry(JCTry tree) {
try {
print("try ");
printStat(tree.body);
for (List<JCCatch> 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(JCCatch tree) {
try {
print(" catch (");
printExpr(tree.param);
print(") ");
printStat(tree.body);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitConditional(JCConditional tree) {
try {
open(prec, TreeInfo.condPrec);
printExpr(tree.cond, TreeInfo.condPrec);
print(" ? ");
printExpr(tree.truepart, TreeInfo.condPrec);
print(" : ");
printExpr(tree.falsepart, TreeInfo.condPrec);
close(prec, TreeInfo.condPrec);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitIf(JCIf tree) {
try {
print("if ");
if (tree.cond.getTag() == JCTree.PARENS) {
printExpr(tree.cond);
} else {
print("(");
printExpr(tree.cond);
print(")");
}
print(" ");
printStat(tree.thenpart);
if (tree.elsepart != null) {
print(" else ");
printStat(tree.elsepart);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitExec(JCExpressionStatement tree) {
// Get rid of bogus super() invocation in enum constructor
if (inEnumBlock && tree.expr instanceof JCMethodInvocation) {
JCMethodInvocation mi = (JCMethodInvocation) tree.expr;
if (mi.meth instanceof JCIdent) {
JCIdent id = (JCIdent) mi.meth;
if (id.name.toString().equals("super"))
return;
}
}
try {
printExpr(tree.expr);
if (prec == TreeInfo.notExpression) print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitBreak(JCBreak tree) {
try {
print("break");
if (tree.label != null) print(" " + tree.label);
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitNegationExpression(DPJNegationExpression tree) {
try {
print("~ ");
print(tree.negatedExpr);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitContinue(JCContinue tree) {
try {
print("continue");
if (tree.label != null) print(" " + tree.label);
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitReturn(JCReturn tree) {
try {
print("return");
if (tree.expr != null) {
print(" ");
printExpr(tree.expr);
}
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitThrow(JCThrow tree) {
try {
print("throw ");
printExpr(tree.expr);
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitAssert(JCAssert tree) {
try {
print("assert ");
printExpr(tree.cond);
if (tree.detail != null) {
print(" : ");
printExpr(tree.detail);
}
print(";");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void printArgs(List<JCExpression> typeargs, List<DPJRegionPathList> rplargs,
boolean printKeyword) throws IOException {
boolean rplsToPrint = ((codeGenMode == NONE) && rplargs.nonEmpty());
if (!typeargs.isEmpty() || rplsToPrint) {
print("<");
printExprs(typeargs);
if (typeargs.nonEmpty() && rplsToPrint)
print(", ");
if (rplsToPrint && printKeyword) print("region ");
printExprs(rplargs);
print(">");
}
}
public void visitApply(JCMethodInvocation tree) {
try {
if (!tree.typeargs.isEmpty() ||
!tree.regionArgs.isEmpty()) {
if (tree.meth.getTag() == JCTree.SELECT) {
JCFieldAccess left = (JCFieldAccess)tree.meth;
printExpr(left.selected);
print(".");
printArgs(tree.typeargs, tree.regionArgs, true);
print(left.name);
} else {
printArgs(tree.typeargs, tree.regionArgs, true);
printExpr(tree.meth);
}
} else {
printExpr(tree.meth);
}
print("(");
printExprs(tree.args);
print(")");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void printArrayConstructor(Type cellType, List<JCExpression> args)
throws IOException {
if (cellType instanceof ClassType) {
ClassType ct = (ClassType) cellType;
if (ct.cellType != null) {
printArrayConstructor(ct.cellType, args);
print("[]");
return;
}
}
print("new ");
printType(cellType);
print("[");
printExprs(args);
print("]");
}
public void visitNewClass(JCNewClass tree) {
try {
if (tree.encl != null) {
printExpr(tree.encl);
print(".");
}
if ((tree.constructor.flags() & ARRAYCONSTR) != 0) {
// Convert array constructor call to regular Java array
ClassType ct = (ClassType) tree.clazz.type;
printArrayConstructor(ct.cellType, tree.args);
return;
}
if (!inEnumVarDecl) {
print("new ");
boolean rplsToPrint = ((codeGenMode == NONE) &&
tree.regionArgs.nonEmpty());
if (rplsToPrint || !tree.typeargs.isEmpty()) {
print("<");
printExprs(tree.typeargs);
if (rplsToPrint) {
if (tree.typeargs.nonEmpty()) print(", ");
printExprs(tree.regionArgs);
}
print(">");
}
printExpr(tree.clazz);
}
print("(");
printExprs(tree.args);
print(")");
if (tree.def != null) {
Name enclClassNamePrev = enclClassName;
enclClassName =
tree.def.name != null ? tree.def.name :
tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.empty ? tree.type.tsym.name :
null;
//if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/");
printBlock(tree.def.defs);
enclClassName = enclClassNamePrev;
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitNewArray(JCNewArray tree) {
try {
if (tree.elemtype != null) {
print("new ");
JCTree elem = tree.elemtype;
if (elem instanceof JCArrayTypeTree)
printBaseElementType((JCArrayTypeTree) elem);
else
printExpr(elem);
List<DPJRegionPathList> rl = tree.rpls;
List<JCIdent> indexVars = tree.indexVars;
for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
print("[");
printExpr(l.head);
print("]");
if ((codeGenMode == NONE) && rl.head != null) {
print("<");
printExpr(rl.head);
print(">");
}
if ((codeGenMode == NONE) && indexVars.head != null) {
print("#");
printExpr(indexVars.head);
}
rl = rl.tail;
indexVars = indexVars.tail;
}
if (elem instanceof JCArrayTypeTree)
printBrackets((JCArrayTypeTree) elem);
}
if (tree.elems != null) {
if (tree.elemtype != null) print("[]");
print("{");
printExprs(tree.elems);
print("}");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitParens(JCParens tree) {
try {
print("(");
printExpr(tree.expr);
print(")");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitSpawn(DPJSpawn tree) {
try {
if (codeGenMode == NONE) {
print("spawn ");
} else {
print("{\n");
indent();
align();
if(codeGenMode == SEQ_INST) print("DPJRuntime.Instrument.enterSpawn();");
println();
align();
}
printStat(tree.body);
if (codeGenMode != NONE) {
println();
align();
if(codeGenMode == SEQ_INST) print("DPJRuntime.Instrument.exitSpawn();\n");
undent();
align();
print("}");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitFinish(DPJFinish tree) {
try {
if (codeGenMode == NONE) {
print("dpjfinish ");
} else {
if(codeGenMode == SEQ_INST) print("DPJRuntime.Instrument.enterFinish();\n");
align();
}
printStat(tree.body);
if (codeGenMode != NONE) {
println();
align();
if(codeGenMode == SEQ_INST) print("DPJRuntime.Instrument.exitFinish();");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private int dpj_tname = 0;
public void visitCobegin(DPJCobegin tree) {
if (codeGenMode == NONE) {
try {
if (tree.isNondet) {
print("cobegin_nd ");
} else {
print("cobegin ");
}
printStat(tree.body);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
} else if(sequential || !(tree.body instanceof JCBlock)) {
seqCobegin(tree);
} else {
parCobegin(tree);
}
}
public void visitAtomic(DPJAtomic tree) {
try {
if (codeGenMode == NONE) {
print("atomic ");
} else if (codeGenMode == PAR) {
//TODO Use javac's normal error logging
throw new Error("Nondeterministic constructs are not supported");
}
printStat(tree.body);
} catch(IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitNonint(DPJNonint tree) {
try {
if (codeGenMode == NONE) {
print("nonint ");
}
printStat(tree.body);
} catch(IOException e) {
throw new UncheckedIOException(e);
}
}
public void seqCobegin(DPJCobegin tree) {
try {
if(codeGenMode == SEQ_INST) print("DPJRuntime.Instrument.enterCobegin();\n");
align();
if (tree.body instanceof JCBlock) {
JCBlock block = (JCBlock) tree.body;
try {
printFlags(block.flags);
printCobeginBlock(block.stats);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
} else {
printStat(tree.body);
}
println();
align();
if(codeGenMode == SEQ_INST) print("DPJRuntime.Instrument.exitCobegin();");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void parCobegin(DPJCobegin tree) {
boolean savedPrintDPJ = Types.printDPJ;
Types.printDPJ = false;
try {
JCBlock body = (JCBlock)(tree.body);
List<String> toCoInvoke = List.<String>nil();
List<String> copyOutAssign = List.<String>nil();
String arr = "__dpj_s"+dpj_tname++;
int orig_dpj_tname = dpj_tname;
println();
int i=0;
for(JCStatement statement : body.stats)
{
align();
String stName = "__dpj_S"+dpj_tname++;
print("class " + stName + " extends RecursiveAction {\n");
indent();
Set<VarSymbol> copyIn = new HashSet(tree.usedVars[i]);
copyIn.removeAll(tree.declaredVars[i]);
Set<VarSymbol> copyOut = new HashSet(tree.definedVars[i]);
copyOut.removeAll(tree.declaredVars[i]);
// TODO: Don't put 'this' in in the first place!
for (VarSymbol vs : copyIn) {
if (vs.name.toString().equals("this")) {
copyIn.remove(vs);
copyOut.remove(vs);
break;
}
}
Set<VarSymbol> copyAll = new HashSet(copyIn);
copyAll.addAll(copyOut);
//Declare local vars necessary for copyin/copyout
for(VarSymbol var : copyAll)
{
align();
printType(var.type);
print(" ");
print(var.toString()+";\n");
}
//Generate constructor for class
align();
print(stName+"(");
boolean needsComma = false;
for(VarSymbol var : copyIn) {
if (needsComma)
print(",");
else
needsComma=true;
printType(var.type);
print(" ");
print(var.toString());
}
print(") {\n");
indent();
for(VarSymbol var : copyIn)
{
align();
print("this."+var.toString()+"="+var.toString()+";\n");
}
undent();
align();
print("}\n");
//Generate run method
align();
print("protected void compute() {\n");
indent();
align();
printOwner = true;
printStat(statement);
printOwner = false;
println();
undent();
align();
print("}\n");
//close class block
undent();
align();
print("};\n");
//generate code for FJTask object, for use later
String varList="";
needsComma=false;
for(VarSymbol var : copyIn)
{
if (needsComma)
varList+=",";
else
needsComma=true;
varList+=var.toString();
}
toCoInvoke = toCoInvoke.append("new "+stName+"("+varList+")");
//generate code for copy out assignment, for use later
for(VarSymbol var : copyOut)
{
String stmt=var.toString()+" = (("+stName+")("+arr+
"["+(dpj_tname - 1 - orig_dpj_tname)+"]))."+
var.toString()+";\n";
copyOutAssign = copyOutAssign.append(stmt);
}
i++;
}
//Okay, now generate the actual array and coInvoke call
align();
print("RecursiveAction[] "+arr+" = {");
boolean needsComma=false;
for(String toPrint : toCoInvoke)
{
if (needsComma)
print(",");
else
needsComma=true;
print(toPrint);
}
print("};\n");
align();
int cobegin_wrapper = dpj_tname++;
print("class __dpj_S"+cobegin_wrapper+" extends RecursiveAction {\n");
indent();
align();
print("RecursiveAction[] __dpj_toforkjoin;\n");
align();
print("__dpj_S"+cobegin_wrapper+"(RecursiveAction[] __dpj_toforkjoin_) {\n");
indent();
align();
print("__dpj_toforkjoin = __dpj_toforkjoin_;\n");
undent();
align();
print("}\n");
align();
print("protected void compute() {\n");
indent();
align();
print("RecursiveAction.forkJoin(__dpj_toforkjoin);\n");
undent();
align();
print("}\n"); //end compute
undent();
align();
print("};\n"); //end cobegin_wrapper class
align();
print("if(!DPJRuntime.RuntimeState.insideParallelTask) {\n");
indent();
align();
print("DPJRuntime.RuntimeState.insideParallelTask = true;\n");
align();
print("DPJRuntime.RuntimeState.pool.invoke(new __dpj_S"+cobegin_wrapper+"("+arr+"));\n");
undent();
align();
print("DPJRuntime.RuntimeState.insideParallelTask = false;\n");
align();
print("}\n");
align();
print("else\n");
indent();
align();
print("RecursiveAction.forkJoin("+arr+");\n");
undent();
//Generate copy out assignments
for(String assign : copyOutAssign)
{
align();
print(assign);
}
}
catch(IOException e) {
throw new UncheckedIOException(e);
}
finally {
Types.printDPJ = savedPrintDPJ;
}
}
public void visitAssign(JCAssign tree) {
try {
open(prec, TreeInfo.assignPrec);
printExpr(tree.lhs, TreeInfo.assignPrec + 1);
print(" = ");
printExpr(tree.rhs, TreeInfo.assignPrec);
close(prec, TreeInfo.assignPrec);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public String operatorName(int tag) {
switch(tag) {
case JCTree.POS: return "+";
case JCTree.NEG: return "-";
case JCTree.NOT: return "!";
case JCTree.COMPL: return "~";
case JCTree.PREINC: return "++";
case JCTree.PREDEC: return "--";
case JCTree.POSTINC: return "++";
case JCTree.POSTDEC: return "--";
case JCTree.NULLCHK: return "<*nullchk*>";
case JCTree.OR: return "||";
case JCTree.AND: return "&&";
case JCTree.EQ: return "==";
case JCTree.NE: return "!=";
case JCTree.LT: return "<";
case JCTree.GT: return ">";
case JCTree.LE: return "<=";
case JCTree.GE: return ">=";
case JCTree.BITOR: return "|";
case JCTree.BITXOR: return "^";
case JCTree.BITAND: return "&";
case JCTree.SL: return "<<";
case JCTree.SR: return ">>";
case JCTree.USR: return ">>>";
case JCTree.PLUS: return "+";
case JCTree.MINUS: return "-";
case JCTree.MUL: return "*";
case JCTree.DIV: return "/";
case JCTree.MOD: return "%";
default: throw new Error();
}
}
public void visitAssignop(JCAssignOp tree) {
try {
open(prec, TreeInfo.assignopPrec);
printExpr(tree.lhs, TreeInfo.assignopPrec + 1);
print(" " + operatorName(tree.getTag() - JCTree.ASGOffset) + "= ");
printExpr(tree.rhs, TreeInfo.assignopPrec);
close(prec, TreeInfo.assignopPrec);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitUnary(JCUnary tree) {
try {
int ownprec = TreeInfo.opPrec(tree.getTag());
String opname = operatorName(tree.getTag());
open(prec, ownprec);
if (tree.getTag() <= JCTree.PREDEC) {
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(JCBinary tree) {
try {
int ownprec = TreeInfo.opPrec(tree.getTag());
String opname = operatorName(tree.getTag());
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(JCTypeCast tree) {
try {
open(prec, TreeInfo.prefixPrec);
print("(");
printExpr(tree.clazz);
print(")");
printExpr(tree.expr, TreeInfo.prefixPrec);
close(prec, TreeInfo.prefixPrec);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitTypeTest(JCInstanceOf tree) {
try {
open(prec, TreeInfo.ordPrec);
printExpr(tree.expr, TreeInfo.ordPrec);
print(" instanceof ");
printExpr(tree.clazz, TreeInfo.ordPrec + 1);
close(prec, TreeInfo.ordPrec);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitIndexed(JCArrayAccess tree) {
try {
printExpr(tree.indexed, TreeInfo.postfixPrec);
print("[");
printExpr(tree.index);
print("]");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitSelect(JCFieldAccess tree) {
try {
if (tree.selected instanceof JCIdent &&
((JCIdent)(tree.selected)).name.length() == 0) {
// Hack to work around generation of types starting with "." during barrier insertion
// TODO Fix the root cause of this (in TreeMaker, I think).
print(tree.name);
} else {
if (tree.sym instanceof ClassSymbol &&
isArrayClass(tree.sym.type)) {
printType(tree.sym.type);
}
else {
printExpr(tree.selected, TreeInfo.postfixPrec);
print(".");
print(tree.name);
}
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public boolean printOwner = false;
/**
* Recursively print a type. If the type is an array class type,
* then print it out as a regular Java array. Otherwise, print out
* the regular Java type.
*/
private void printType(Type type) throws IOException {
// Don't print out DPJ type annotations if we are generating code
boolean oldPrintDPJ = Types.printDPJ;
Types.printDPJ = (codeGenMode == NONE);
boolean printed = false;
if (type instanceof ClassType) {
ClassType ct = (ClassType) type;
if (ct.cellType != null && !inImport) {
printType(ct.cellType);
print("[]");
printed = true;
}
}
if (!printed) {
print(type);
}
Types.printDPJ = oldPrintDPJ;
}
private boolean isArrayClass(Type type) {
if (type instanceof ClassType) {
ClassType ct = (ClassType) type;
return ct.cellType != null;
}
return false;
}
public void visitIdent(JCIdent tree) {
try {
if (thisIsBogus && tree.toString().equals("this"))
print("__dpj_this");
else if (printOwner && tree.toString().equals("this")) {
print (tree.sym.owner.type + "." + "this");
}
else if (tree.sym instanceof ClassSymbol) {
if (isArrayClass(tree.sym.type)) {
printType(tree.sym.type);
}
else print(tree.name);
}
else {
print(tree.name);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitLiteral(JCLiteral tree) {
try {
switch (tree.typetag) {
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 visitTypeIdent(JCPrimitiveTypeTree tree) {
try {
switch(tree.typetag) {
case TypeTags.BYTE:
print("byte");
break;
case TypeTags.CHAR:
print("char");
break;
case TypeTags.SHORT:
print("short");
break;
case TypeTags.INT:
print("int");
break;
case TypeTags.LONG:
print("long");
break;
case TypeTags.FLOAT:
print("float");
break;
case TypeTags.DOUBLE:
print("double");
break;
case TypeTags.BOOLEAN:
print("boolean");
break;
case TypeTags.VOID:
print("void");
break;
default:
print("error");
break;
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitTypeArray(JCArrayTypeTree tree) {
try {
printBaseElementType(tree);
printBrackets(tree);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
// Prints the inner element type of a nested array
private void printBaseElementType(JCArrayTypeTree tree) throws IOException {
JCTree elem = tree.elemtype;
while (elem instanceof JCWildcard)
elem = ((JCWildcard) elem).inner;
if (elem instanceof JCArrayTypeTree)
printBaseElementType((JCArrayTypeTree) elem);
else
printExpr(elem);
}
// prints the brackets of a nested array in reverse order
private void printBrackets(JCArrayTypeTree tree) throws IOException {
JCTree elem;
while (true) {
elem = tree.elemtype;
print("[]");
if ((codeGenMode == NONE) && tree.rpl != null) {
print("<");
printExpr(tree.rpl);
print(">");
if (tree.indexParam != null) {
print("#");
printExpr(tree.indexParam);
}
}
if (!(elem instanceof JCArrayTypeTree)) break;
tree = (JCArrayTypeTree) elem;
}
}
public void visitTypeApply(JCTypeApply tree) {
try {
printExpr(tree.functor);
Symbol functorSymbol = tree.functor.getSymbol();
if (functorSymbol != null &&
isArrayClass(functorSymbol.type))
return;
boolean rplsToPrint = (codeGenMode == NONE) && tree.rplArgs != null &&
tree.rplArgs.nonEmpty();
boolean effectsToPrint = (codeGenMode == NONE) && tree.effectArgs != null &&
tree.effectArgs.nonEmpty();
if (tree.typeArgs.nonEmpty() || rplsToPrint || effectsToPrint) {
print("<");
printExprs(tree.typeArgs);
if (rplsToPrint) {
if (tree.typeArgs.nonEmpty()) {
print(", ");
}
printExprs(tree.rplArgs);
}
if (effectsToPrint) {
if (tree.typeArgs.nonEmpty() || rplsToPrint) {
print(", ");
}
// printExprs(tree.effectArgs);
// TODO: WHY DOES THIS CAUSE STACK OVERFLOW???
}
print(">");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitTypeParameter(JCTypeParameter tree) {
try {
print(tree.name);
if (tree.bounds.nonEmpty()) {
print(" extends ");
printExprs(tree.bounds, " & ");
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitRegionParameter(DPJRegionParameter tree) {
try {
if (tree.isAtomic)
print("atomic ");
print(tree.name);
if (tree.bound != null) {
print(" under ");
printExpr(tree.bound);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public void visitWildcard(JCWildcard tree) {
try {
print(tree.kind);
if (tree.kind.kind != BoundKind.UNBOUND)
printExpr(tree.inner);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public void visitTypeBoundKind(TypeBoundKind tree) {
try {
print(String.valueOf(tree.kind));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitErroneous(JCErroneous tree) {
try {
print("(ERROR)");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitLetExpr(LetExpr tree) {
try {
print("(let " + tree.defs + " in " + tree.expr + ")");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitModifiers(JCModifiers mods) {
try {
printAnnotations(mods.annotations);
if (codeGenMode == NONE)
printFlags(mods.flags);
else
printFlags(mods.flags & ~Flags.ISCOMMUTATIVE);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitAnnotation(JCAnnotation tree) {
try {
print("@");
printExpr(tree.annotationType);
print("(");
printExprs(tree.args);
print(")");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitTree(JCTree tree) {
try {
print("(UNKNOWN: " + tree + ")");
println();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}