Newer
Older
zweic / sources / zweic / Printer.scala
@ajaggi ajaggi on 27 Dec 2005 4 KB Changes:
/*  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: => Printer):Printer = args match {
    case h :: Nil =>
      print(h);
    case h :: t =>
      print(h);
      sep;
      joinprint(t, sep);
    case Nil =>
      print("");
  }

  def joinprint(args:List[Tree], sep:String):Printer = {
    joinprint(args, print(sep));
  }

  /**
   * Prints a tree node.
   */
  def print(tree: Tree): Printer = {
    if (tree.isInstanceOf[Expr] && tree.asInstanceOf[Expr].brackets)
      print("(");

    tree match {
    case Program(decls, main) =>
      joinprint(decls, println).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;
      joinprint(members, println.println);
      undent.println.print("}").println;

    case FieldDecl(formal) =>
      print(formal).print(";");

    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.joinprint(stats, println).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");
    };

    if (tree.isInstanceOf[Expr] && tree.asInstanceOf[Expr].brackets)
      print(")");

    print("");
  }

  /**
   * 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 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
  }
}