package com.google.code.joto.ast.beanstmt.impl;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.List;
import com.google.code.joto.ast.beanstmt.BeanASTVisitor;
import com.google.code.joto.ast.beanstmt.BeanAST.AssignExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.BeanExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.BeanStmt;
import com.google.code.joto.ast.beanstmt.BeanAST.BlockStmt;
import com.google.code.joto.ast.beanstmt.BeanAST.ClassExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.ExprStmt;
import com.google.code.joto.ast.beanstmt.BeanAST.FieldExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.IndexedArrayExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.LiteralExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.MethodApplyExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.NewArrayExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.NewObjectExpr;
import com.google.code.joto.ast.beanstmt.BeanAST.VarDeclStmt;
import com.google.code.joto.ast.beanstmt.BeanAST.SimpleNameExpr;
/**
*
*/
public class BeanASTPrettyPrinter implements BeanASTVisitor {
private PrintStream out;
private int indent;
// ------------------------------------------------------------------------
public BeanASTPrettyPrinter(PrintStream out) {
this.out = out;
}
// implements BeanInitVisitor Statements
// ------------------------------------------------------------------------
public void caseBlock(BlockStmt p) {
indentPrintln("{");
incrIndent();
for(BeanStmt stmt : p.getStmts()) {
stmt.visit(this);
}
decrIndent();
indentPrintln("}");
}
public void caseVarDecl(VarDeclStmt stmt) {
Class<?> declType = stmt.getDeclaredType();
String simpleClassName = classToSimpleName(declType);
indentPrint(simpleClassName + " " + stmt.getVarName());
if (stmt.getInitExpr() != null) {
print(" = ");
stmt.getInitExpr().visit(this);
}
println(";");
}
public void caseExprStmt(ExprStmt p) {
printIndent();
p.getExpr().visit(this);
println(";");
}
// implements BeanInitVisitor Expressions
// ------------------------------------------------------------------------
public void caseAssign(AssignExpr p) {
p.getLhs().visit(this);
print(" = ");
p.getRhs().visit(this);
}
public void caseMethodApplyExpr(MethodApplyExpr p) {
if (p.getLhsExpr() != null) {
p.getLhsExpr().visit(this);
print(".");
}
print(p.getMethodName());
print("(");
visitExprList(p.getArgs());
print(")");
}
public void caseNewObject(NewObjectExpr p) {
print("new ");
print(classToSimpleName(p.getNewClss()));
print("(");
visitExprList(p.getArgs());
print(")");
}
public void caseNewArray(NewArrayExpr p) {
print("new ");
print(classToSimpleName(p.getNewArrayClass()));
print("[");
BeanExpr[] initExprs = p.getInitExprs();
if (initExprs == null || p.getLength() != p.getInitExprs().length) {
print(Integer.toString(p.getLength()));
}
print("]");
if (initExprs != null) {
print(" { ");
visitExprs(initExprs);
print(" }");
}
}
public void caseIndexedArray(IndexedArrayExpr p) {
p.getLhs().visit(this);
print("[");
p.getIndex().visit(this);
print("]");
}
public void caseLitteralExpr(LiteralExpr p) {
String javaValue;
Object value = p.getValue();
javaValue = litteralToJava(value);
print(javaValue);
}
public static String litteralToJava(Object value) {
String javaValue;
if (value == null) {
javaValue = "null";
} else if (value instanceof String) {
String str = (String) value;
javaValue = litteralStringToJavaCode(str);
} else if (value instanceof Character) {
// if ()
char ch = ((Character) value).charValue();
javaValue = litteralCharToJavaCode(ch);
} else {
javaValue = value.toString(); // TODO format...
}
return javaValue;
}
public static String litteralStringToJavaCode(String str) {
String javaValue;
str = str.replace("\\", "\\\\"); // replace '\' by '\\'
str = str.replace("\"", "\\\""); // replace '"' by '\"'
str = str.replace("\n", "\\n"); // replace <newline> by '\n'
// TODO add more escape..
javaValue = "\"" + str + "\"";
return javaValue;
}
public static String litteralCharToJavaCode(char ch) {
String javaValue;
String str = Character.toString(ch);
if (ch == '\\') { str = "\\\\"; }
else if (ch == '\'') { str = "\\\'"; }
else if (ch == '\0') { str = "\\0"; }
else if (ch == '\n') { str = "\\n"; }
// TODO add more escape..
javaValue = "'" + str + "'";
return javaValue;
}
public void caseClassExpr(ClassExpr p) {
print(p.getLhsClassName());
print(".class");
}
public void caseFieldExpr(FieldExpr p) {
p.getLhs().visit(this);
print(".");
print(p.getFieldName());
}
public void caseSimpleName(SimpleNameExpr p) {
print(p.getName());
}
// ------------------------------------------------------------------------
public void visitStmtList(List<BeanStmt> stmts) {
for(BeanStmt stmt : stmts) {
stmt.visit(this);
}
}
protected void visitExprList(List<BeanExpr> args) {
if (args != null && !args.isEmpty()) {
for (Iterator<BeanExpr> iter = args.iterator(); iter.hasNext();) {
BeanExpr arg = iter.next();
arg.visit(this);
if (iter.hasNext()) {
print(", ");
}
}
}
}
protected void visitExprs(BeanExpr[] args) {
if (args != null && args.length != 0) {
for (int i = 0, len = args.length; i < len; i++) {
BeanExpr arg = args[i];
if (arg != null) {
arg.visit(this);
}
if (i + 1 < len) {
print(", ");
}
}
}
}
protected String classToSimpleName(Class<?> p) {
if (p == null) {
p = Object.class; // should not occur!
}
String res = p.getSimpleName();
// TODO add import..
if (-1 != res.indexOf('$')) {
res = res.replace('$', '.'); // TODO add static inner class import?
}
return res;
}
// -------------------------------------------------------------------------
public void incrIndent() {
indent++;
}
public void decrIndent() {
indent--;
}
public void printIndent() {
for (int i = 0; i < indent; i++) {
out.print(' ');
}
}
private void print(String text) {
out.print(text);
}
private void println() {
out.print('\n');
}
private void println(String text) {
print(text);
println();
}
private void indentPrint(String text) {
printIndent();
print(text);
}
private void indentPrintln(String text) {
printIndent();
print(text);
println();
}
}