/* zweic -- a compiler for Zwei
*
* Stephane Micheloud & LAMP
*
* $Id$
*/
package zweic;
import java.io.PrintWriter;
/**
* This class implements a pretty printer for abstract syntax
* trees in Zwei.
*/
class Printer(out: PrintWriter) {
import Operators._;
/**
* Indentation string.
*/
private val step = " ";
/**
* indentation level.
*/
private var level = 0;
def joinprint(args:List[Tree], sep:String):Printer = args match {
case h :: Nil =>
print(h);
case h :: t =>
print(h).print(sep);
joinprint(t, sep);
case Nil =>
print("");
}
//TODO: do this by passing a function as argument.
def joinprintln(args:List[Tree]):Printer = args match {
case h :: Nil =>
print(h);
case h :: t =>
print(h);
println;
joinprintln(t);
case Nil =>
print("");
}
/**
* Prints a tree node.
*/
def print(tree: Tree): Printer = tree match {
case Program(decls, main) =>
for (val d <- decls) {
print(d).println;
}
print(main).println;
//
// Tree nodes for definitions
//
case ClassDef(name, extend, members) =>
print("class ").print(name);
extend match {
case Some(e) => print(" extends ").print(e);
case _ => null;
}
print(" {").indent.println;
joinprintln(members);
undent.println.print("}").println;
case FieldDecl(formal) =>
print(formal);
case MethodDef(name, args, returntype, expression) =>
print(returntype).print(" ").print(name);
print(" (").joinprint(args, ", ").print(") ");
print(expression);
case Formal(name, typ) =>
print(typ).print(" ").print(name);
//
// Tree nodes for types
//
case IntType() =>
print("Int");
case NullType() =>
print("Null");
case ClassType(name) =>
print(name);
//
// Tree nodes for statements
//
case While(cond, stats) =>
print("while (").print(cond).print(") {");
indent.println.joinprintln(stats).undent.println.print("}");
case Var(varname, vartype, init) =>
print(vartype).print(" ").print(varname).print(" = ").
print(init).print(";");
case Set(name, expr) =>
print(name).print(" = ").print(expr).print(";");
case Do(expr) =>
print(expr).print(";");
case PrintInt(expr) =>
print("printInt(").print(expr).print(")").print(";");
case PrintChar(expr) =>
print("printChar(").print(expr).print(")").print(";");
//
// Tree nodes for expressions
//
case Ident(name) =>
print(name);
case New(name, args) =>
print("new ").print(name).print("(");
joinprint(args, ", ");
print(")");
case Select(prefix, selector) =>
print(prefix).print(".").print(selector);
case Call(obj, funcname, args) =>
print(obj).print(".").print(funcname).print("(");
joinprint(args, ", ")
print(")");
case NullLit() =>
print("null");
case IntLit(value) =>
print(value.toString());
case Unop(op, expr) =>
print(op.toString()).print(expr);
case Binop(op, left, right) =>
print(left).print(" ");
print(op.toString());
print(" ").print(right);
case ReadInt() =>
print("readInt");
case ReadChar() =>
print("readChar");
case If(cond, stata, statb) =>
print("if (").print(cond).print(") ");
indent.print(stata).undent.println;
print("else ").indent;
print(statb).undent;
case Block(stats, expression) =>
print("{").indent.println;
for (val s <- stats) {
print(s).println;
}
print("return ").print(expression);
undent.println.print("}");
case x =>
error("unexpected error in tree");
}
/**
* Print abstract syntax trees separated by commas.
*/
private def print(trees: List[Tree]): Printer = trees match {
case _ => this
}
/**
* Print a string.
*/
private def print(value: String): Printer = {
out.print(value);
this
}
private def print(name: Name): Printer = print(name.name);
private def print(formal: Pair[Name, TypeTree]): Printer =
print(formal._2).print(" ").print(formal._1);
/**
* Print abstract syntax trees separated by commas.
*/
private def printFormals(formals: List[Pair[Name, TypeTree]]): Printer =
formals match {
// ... à compléter ...
case _ => this
}
/**
* Print an end-of-line character and indent the following
* line appropriately.
*/
private def println = {
out.println();
for (val i <- List.range(0, level)) out.print(step);
this
}
/**
* Increment the indentation level.
*/
private def indent = {
level = level + 1;
this
}
/**
* Decrement the indentation level.
*/
private def undent = {
level = level - 1;
this
}
}