summaryrefslogblamecommitdiff
path: root/sources/scalac/ast/printer/TextTreePrinter.java
blob: 0d4ff6022f4ed0c598fe22c228a19180a6e3bea1 (plain) (tree)




























                                                                          
                                      


                                        

                                                   


                                                            





                                                                    








                              
                







                                          
                               




                                  
                               




                                                       
                











                                                    
                               



                                   


                                                          

                                                
                               





















































                                                                              
                                                                      



















                                                                         

                                                                         









                                                                      








                                                                      























                                                                     
                









































                                                                     







                                               
                             









                                                               
                                                                             




                                                       




                                                                       



























                                                                          




                                                       
                                                                                                       






                                                 
                           


























































































                                                                                 
























































                                                                                 



                                        


















                                                                               
                                                                                  

                  
























                                                   
                                              

                      




























































                                                                              
                                                     

















































                                                                         



                                                                                  




























                                                          
                                                      

                                                       
                                               












                                                               
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
**                                                                      **
\*                                                                      */

// $Id$

package scalac.ast.printer;

import scalac.ast.*;
import scalac.symtab.*;
import scalac.util.Debug;
import scalac.Global;
import scalac.Unit;
import scalac.util.Name;

import java.io.*;
import java.util.*;

/**
 * Text pretty printer for Scala abstract syntax trees.
 *
 * @author Michel Schinz, Matthias Zenger
 * @version 1.0
 */
public class TextTreePrinter implements TreePrinter {
    protected PrintWriter out;
    protected final boolean autoFlush;

    protected int indent = 0;
    protected final int INDENT_STEP = 2;
    protected String INDENT_STRING =
        "                                        ";
    protected final int MAX_INDENT = INDENT_STRING.length();

    public TextTreePrinter(OutputStream stream) {
        this(stream, false);
    }

    public TextTreePrinter(OutputStream stream, boolean autoFlush) {
        this.autoFlush = autoFlush;
        this.out = new PrintWriter(stream);
    }

    public TextTreePrinter() {
        this(System.out);
    }

    public void begin() { }

    public void end() {
        flush();
    }

    public void flush() {
	out.flush();
    }

    public TreePrinter print(String str) {
	out.print(str);
        if (autoFlush) flush();
	return this;
    }

    public TreePrinter println() {
	out.println();
        if (autoFlush) flush();
	return this;
    }

    public void beginSection(int level, String title) {
        out.println("[[" + title + "]]");
        flush();
    }

    protected void indent() {
        indent += Math.min(MAX_INDENT, INDENT_STEP);
    }

    protected void undent() {
        indent -= Math.max(0, INDENT_STEP);
    }

    protected void printString(String str) {
        out.print(str);
        if (autoFlush) flush();
    }

    protected void printNewLine() {
        out.println();
	while (indent > INDENT_STRING.length()) {
	    INDENT_STRING = INDENT_STRING + INDENT_STRING;
	}
        if (indent > 0)
            out.write(INDENT_STRING, 0, indent);
        if (autoFlush) flush();
    }

    public static class SymbolUsage {
        public case Definition;
        public case Use;
    }

    public static class Text {
        public case None;
        public case Space;
        public case Newline;
        public case Simple(String str);
        public case Literal(String str);
        public case Keyword(String name);
        public case Identifier(Symbol symbol, String name, SymbolUsage usage);
        public case Sequence(Text[] elements);
    }

    protected void print(Text text) {
        switch (text) {
        case None : break;
        case Space : printString(" "); break;
        case Newline : printNewLine(); break;
        case Simple(String str) : printString(str); break;
        case Literal(String str) : printString(str); break;
        case Keyword(String name) : printString(name); break;
        case Identifier(Symbol sym, String name, _) :
            printString(name);
            if (sym != null && Global.instance.uniqid)
                printString("#" + Global.instance.uniqueID.id(sym));
            break;
        case Sequence(Text[] elements) : print(elements); break;
        }
    }

    protected void print(Text[] texts) {
        for (int i = 0; i < texts.length; ++i)
            print(texts[i]);
    }

    protected static final Text KW_ABSTRACT  = Text.Keyword("abstract");
    protected static final Text KW_CASE      = Text.Keyword("case");
    protected static final Text KW_CLASS     = Text.Keyword("class");
    protected static final Text KW_CONSTR    = Text.Keyword("constr");
    protected static final Text KW_DEF       = Text.Keyword("def");
    protected static final Text KW_DO        = Text.Keyword("do");
    protected static final Text KW_ELSE      = Text.Keyword("else");
    protected static final Text KW_EXTENDS   = Text.Keyword("extends");
    protected static final Text KW_FINAL     = Text.Keyword("final");
    protected static final Text KW_FOR       = Text.Keyword("for");
    protected static final Text KW_IF        = Text.Keyword("if");
    protected static final Text KW_IMPORT    = Text.Keyword("import");
    protected static final Text KW_INTERFACE = Text.Keyword("interface");
    protected static final Text KW_LET       = Text.Keyword("let");
    protected static final Text KW_OBJECT    = Text.Keyword("object");
    protected static final Text KW_NEW       = Text.Keyword("new");
    protected static final Text KW_NULL      = Text.Keyword("null");
    protected static final Text KW_OUTER     = Text.Keyword("outer");
    protected static final Text KW_OVERRIDE  = Text.Keyword("override");
    protected static final Text KW_PACKAGE   = Text.Keyword("package");
    protected static final Text KW_PRIVATE   = Text.Keyword("private");
    protected static final Text KW_PROTECTED = Text.Keyword("protected");
    protected static final Text KW_QUALIFIED = Text.Keyword("qualified");
    protected static final Text KW_STATIC    = Text.Keyword("static");
    protected static final Text KW_SUPER     = Text.Keyword("super");
    protected static final Text KW_THIS      = Text.Keyword("this");
    protected static final Text KW_TYPE      = Text.Keyword("type");
    protected static final Text KW_VAL       = Text.Keyword("val");
    protected static final Text KW_VAR       = Text.Keyword("var");
    protected static final Text KW_WITH      = Text.Keyword("with");
    protected static final Text KW_YIELD     = Text.Keyword("yield");

    protected static final Text TXT_ERROR   = Text.Simple("<error>");
    protected static final Text TXT_UNKNOWN = Text.Simple("<unknown>");
    protected static final Text TXT_NULL    = Text.Simple("<null>");
    protected static final Text TXT_OBJECT_COMMENT
                                            = Text.Simple("/*object*/ ");
    protected static final Text TXT_EMPTY   = Text.Simple("<empty>");

    protected static final Text TXT_QUOTE         = Text.Simple("\"");
    protected static final Text TXT_PLUS          = Text.Simple("+");
    protected static final Text TXT_COLON         = Text.Simple(":");
    protected static final Text TXT_SEMICOLON     = Text.Simple(";");
    protected static final Text TXT_DOT           = Text.Simple(".");
    protected static final Text TXT_COMMA         = Text.Simple(",");
    protected static final Text TXT_EQUAL         = Text.Simple("=");
    protected static final Text TXT_SUBTYPE       = Text.Simple("<:");
    protected static final Text TXT_HASH          = Text.Simple("#");
    protected static final Text TXT_RIGHT_ARROW   = Text.Simple("=>");
    protected static final Text TXT_LEFT_PAREN    = Text.Simple("(");
    protected static final Text TXT_RIGHT_PAREN   = Text.Simple(")");
    protected static final Text TXT_LEFT_BRACE    = Text.Simple("{");
    protected static final Text TXT_RIGHT_BRACE   = Text.Simple("}");
    protected static final Text TXT_LEFT_BRACKET  = Text.Simple("[");
    protected static final Text TXT_RIGHT_BRACKET = Text.Simple("]");

    protected static final Text TXT_WITH_SP =
        Text.Sequence(new Text[]{ Text.Space, KW_WITH, Text.Space });
    protected static final Text TXT_BLOCK_BEGIN =
        Text.Sequence(new Text[]{ TXT_LEFT_BRACE, Text.Newline });
    protected static final Text TXT_BLOCK_END =
        Text.Sequence(new Text[]{ Text.Newline, TXT_RIGHT_BRACE });
    protected static final Text TXT_BLOCK_SEP =
        Text.Sequence(new Text[]{ TXT_SEMICOLON, Text.Newline });
    protected static final Text TXT_COMMA_SP =
        Text.Sequence(new Text[]{ TXT_COMMA, Text.Space });
    protected static final Text TXT_ELSE_NL =
        Text.Sequence(new Text[]{ KW_ELSE, Text.Newline });

    public void print(Unit unit) {
        printUnitHeader(unit);
        if (unit.body != null) {
            for (int i = 0; i < unit.body.length; ++i) {
                print(unit.body[i]);
                print(TXT_BLOCK_SEP);
            }
        } else
            print(TXT_NULL);
        printUnitFooter(unit);

        flush();
    }

    protected void printUnitHeader(Unit unit) {
        print(Text.Simple("// Scala source: " + unit.source + "\n"));
    }

    protected void printUnitFooter(Unit unit) {
        print(Text.Newline);
    }

    public TreePrinter print(Tree tree) {
        switch (tree) {
        case Bad():
            print(TXT_ERROR);
            break;

        case Empty:
            print(TXT_EMPTY);
            break;

        case ClassDef(int mods, // :
                      Name name,
                      Tree.TypeDef[] tparams,
                      Tree.ValDef[][] vparams,
		      Tree tpe,
                      Tree.Template impl):
            printModifiers(mods);
            print((mods & Modifiers.INTERFACE) != 0
                  ? KW_INTERFACE
                  : KW_CLASS);
            print(Text.Space);
            printSymbolDefinition(tree.symbol(), name);
            printParams(tparams);
            printParams(vparams);
            printOpt(TXT_COLON, tpe, false);
            printTemplate(KW_EXTENDS, impl, true);
            break;

        case PackageDef(Tree packaged, Tree.Template impl):
            print(KW_PACKAGE);
            print(Text.Space);
            print(packaged);
            printTemplate(KW_WITH, impl, true);
            break;

        case ModuleDef(int mods, // :
                       Name name,
                       Tree tpe,
                       Tree.Template impl):
            printModifiers(mods);
            print(KW_OBJECT);
            print(Text.Space);
            printSymbolDefinition(tree.symbol(), name);
            printOpt(TXT_COLON, tpe, false);
            printTemplate(KW_EXTENDS, impl, true);
            break;

        case ValDef(int mods, Name name, Tree tpe, Tree rhs):
            printModifiers(mods);
	    if ((mods & Modifiers.MUTABLE) != 0) print(KW_VAR);
	    else {
		if ((mods & Modifiers.MODUL) != 0) print(TXT_OBJECT_COMMENT);
		print(KW_VAL);
	    }
            print(Text.Space);
            printSymbolDefinition(tree.symbol(), name);
            printOpt(TXT_COLON, tpe, false);
	    if ((mods & Modifiers.DEFERRED) == 0) {
		print(Text.Space); print(TXT_EQUAL); print(Text.Space);
		if (rhs == Tree.Empty) print("_");
		else print(rhs);
	    }
            break;

        case PatDef(int mods, Tree pat, Tree rhs):
            printModifiers(mods);
            print(KW_VAL);
            print(Text.Space);
            print(pat);
            printOpt(TXT_EQUAL, rhs, true);
            break;

        case DefDef(int mods,
                    Name name,
                    Tree.TypeDef[] tparams,
                    Tree.ValDef[][] vparams,
                    Tree tpe,
                    Tree rhs):
            printModifiers(mods);
            if (name.isConstrName()) print(KW_CONSTR); else print(KW_DEF);
            print(Text.Space);
            printSymbolDefinition(tree.symbol(), name);
            printParams(tparams);
            printParams(vparams);
            printOpt(TXT_COLON, tpe, false);
            printOpt(TXT_EQUAL, rhs, true);
            break;

        case TypeDef(int mods,
                     Name name,
                     Tree rhs):
            printModifiers(mods);
            print(KW_TYPE);
            print(Text.Space);
            printSymbolDefinition(tree.symbol(), name);
	    if ((mods & (Modifiers.DEFERRED | Modifiers.PARAM)) != 0) printOpt(TXT_SUBTYPE, rhs, true);
            else printOpt(TXT_EQUAL, rhs, true);
            break;

        case Import(Tree expr, Name[] selectors):
            print(KW_IMPORT);
            print(Text.Space);
            print(expr);
	    print(TXT_DOT);
	    print(TXT_LEFT_BRACE);
	    for (int i = 0; i < selectors.length; i = i + 2) {
		if (i > 0) print(TXT_COMMA_SP);
		print(selectors[i].toString());
		if (i + 1 < selectors.length && selectors[i] != selectors[i+1]) {
		    print(TXT_RIGHT_ARROW);
		    print(selectors[i+1].toString());
		}
	    }
	    print(TXT_RIGHT_BRACE);
            break;

        case CaseDef(Tree pat, Tree guard, Tree body):
            print(KW_CASE);
            print(Text.Space);
            print(pat);
            printOpt(KW_IF, guard, true);
            print(Text.Space);
            print(TXT_RIGHT_ARROW);
            print(Text.Space);
            print(body);
            break;

        case LabelDef(Tree[] params, Tree rhs):
            assert tree.symbol() != null;
            printSymbolDefinition(tree.symbol(), null);
            printArray(params, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP);
            print(rhs);
            break;

        case Block(Tree[] stats):
            printArray(stats, TXT_BLOCK_BEGIN, TXT_BLOCK_END, TXT_BLOCK_SEP);
            break;

        case Tuple(Tree[] trees):
            printArray(trees, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP);
            break;

        case Visitor(Tree.CaseDef[] cases):
            printArray(cases, TXT_BLOCK_BEGIN, TXT_BLOCK_END, Text.Newline);
            break;

        case Function(Tree.ValDef[] vparams, Tree body):
            print(TXT_LEFT_BRACE);
	    printParams(vparams);
	    print(Text.Space);
            print(TXT_RIGHT_ARROW);
            print(Text.Space);
	    print(body);
            print(TXT_RIGHT_BRACE);
            break;

        case Assign(Tree lhs, Tree rhs):
            print(lhs);
            print(Text.Space);
            print(TXT_EQUAL);
            print(Text.Space);
            print(rhs);
            break;

        case If(Tree cond, Tree thenp, Tree elsep):
            print(KW_IF);
            print(Text.Space);
            print(TXT_LEFT_PAREN);
            print(cond);
            print(TXT_RIGHT_PAREN);
            indent(); print(Text.Newline);
            print(thenp);
            undent(); print(Text.Newline);
            indent(); printOpt(TXT_ELSE_NL, elsep, false); undent();
            printType(tree);
            break;

        case New(Tree.Template templ):
            printTemplate(KW_NEW, templ, false);
            printType(tree);
            break;

        case Typed(Tree expr, Tree tpe):
            print(TXT_LEFT_PAREN);
            print(expr);
            print(TXT_RIGHT_PAREN);
            print(Text.Space);
            print(TXT_COLON);
            print(Text.Space);
            print(tpe);
            printType(tree);
            break;

        case TypeApply(Tree fun, Tree[] targs):
            print(fun);
            printArray(targs, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP);
            printType(tree);
            break;

        case Apply(Tree fun, Tree[] vargs):
            print(fun);
            printArray(vargs, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP);
            printType(tree);
            break;

        case Super(Tree tpe):
            if (tpe != Tree.Empty)
                print(TXT_LEFT_PAREN);

            print(KW_SUPER);

            if (tpe != Tree.Empty) {
                print(Text.Space);
                print(TXT_COLON);
                print(Text.Space);
                print(tpe);
                print(TXT_RIGHT_PAREN);
            }
            printType(tree);
            break;

	case This(Tree qualifier):
	    if (qualifier != Tree.Empty) {
		print(qualifier);
		print(TXT_DOT);
	    }
	    print(KW_THIS);
            printType(tree);
	    break;

        case Select(Tree qualifier, Name name):
            print(qualifier);
            print(TXT_DOT);
            printSymbolUse(tree.symbol(), name);
            printType(tree);
            break;

        case Ident(Name name):
            printSymbolUse(tree.symbol(), name);
            printType(tree);
            break;

        case Literal(Object obj):
            String str;
            if (obj instanceof String)
                str = "\"" + obj + "\"";
            else
                str = String.valueOf(obj);
            print(Text.Literal(str));
            printType(tree);
            break;

	case TypeTerm():
	    print(tree.type.toString());
	    break;

	case SingletonType(Tree ref):
	    print(ref);
	    print(TXT_DOT); print(KW_TYPE);
	    break;

	case SelectFromType(Tree qualifier, Name selector):
	    print(qualifier);
	    print(Text.Space); print(TXT_HASH); print(Text.Space);
	    printSymbolUse(tree.symbol(), selector);
	    break;

        case FunType(Tree[] argtpes, Tree restpe):
            printArray(argtpes, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP);
	    print(TXT_RIGHT_ARROW);
            print(restpe);
            break;

        case CompoundType(Tree[] baseTypes, Tree[] refinements):
            printArray(baseTypes, Text.None, Text.None, TXT_WITH_SP);
            printArray(refinements, TXT_BLOCK_BEGIN, TXT_BLOCK_END, Text.Newline);
            break;

        case AppliedType(Tree tpe, Tree[] args):
            print(tpe);
	    indent();
	    print(TXT_LEFT_BRACKET);
	    for (int i = 0; i < args.length; ++i) {
		if (i > 0) print(TXT_COMMA_SP);
		print(args[i]);
	    }
	    undent();
	    print(TXT_RIGHT_BRACKET);
            break;

        case CovariantType(Tree tpe):
	    print(TXT_PLUS);
	    print(tpe);
            break;

        case Template(Tree[] parents, Tree[] body):
            Debug.abort("unexpected case", tree);
            break;

        default:
            print(TXT_UNKNOWN);
            break;
        }
	//print("{" + tree.type + "}");//DEBUG
        if (autoFlush)
            flush();
	return this;
    }

    // Printing helpers

    protected void printArray(Tree[] trees, Text open, Text close, Text sep) {
        indent();
        print(open);
        for (int i = 0; i < trees.length; ++i) {
            if (i > 0) print(sep);
            print(trees[i]);
        }
        undent();
        print(close);
    }

    protected void printOpt(Text prefix, Tree tree, boolean spaceBefore) {
        if (tree != Tree.Empty) {
            if (spaceBefore)
                print(Text.Space);
            print(prefix);
            print(Text.Space);
            print(tree);
        }
    }

    // Printing of symbols

    protected String symbolString(Symbol symbol, Name name) {
        if (symbol != null)
            return symbol.name.toString();
        else
            return name.toString();
    }

    protected void printSymbolDefinition(Symbol symbol, Name name) {
        print(Text.Identifier(symbol,
                              symbolString(symbol, name),
                              SymbolUsage.Definition));
    }

    protected void printSymbolUse(Symbol symbol, Name name) {
        print(Text.Identifier(symbol,
                              symbolString(symbol, name),
                              SymbolUsage.Use));
    }

    // Printing of trees

    protected void printType(Tree tree) {
        if (Global.instance.printtypes) {
	    print(TXT_LEFT_BRACE);
            if (tree.type != null)
                print(Text.Simple(tree.type.toString()));
            else
                print(TXT_NULL);
            print(TXT_RIGHT_BRACE);
	}
    }

    protected void printModifiers(int flags) {
        if ((flags & Modifiers.ABSTRACTCLASS) != 0) {
            print(KW_ABSTRACT);
            print(Text.Space);
        }
        if ((flags & Modifiers.FINAL) != 0) {
            print(KW_FINAL);
            print(Text.Space);
        }
        if ((flags & Modifiers.PRIVATE) != 0) {
            print(KW_PRIVATE);
            print(Text.Space);
        }
        if ((flags & Modifiers.PROTECTED) != 0) {
            print(KW_PROTECTED);
            print(Text.Space);
        }
        if ((flags & Modifiers.QUALIFIED) != 0) {
            print(KW_QUALIFIED);
            print(Text.Space);
        }
        if ((flags & Modifiers.OVERRIDE) != 0) {
            print(KW_OVERRIDE);
            print(Text.Space);
        }
        if ((flags & Modifiers.CASE) != 0) {
            print(KW_CASE);
            print(Text.Space);
        }
        if ((flags & Modifiers.DEF) != 0) {
            print(KW_DEF);
            print(Text.Space);
        }
        if ((flags & Modifiers.STATIC) != 0) {
            print(KW_STATIC);
            print(Text.Space);
        }
    }

    protected void printTemplate(Text prefix,
                                 Tree.Template templ,
                                 boolean spaceBefore) {
        if (! (templ.parents.length == 0
               || (templ.parents.length == 1
                   && templ.parents[0] == Tree.Empty))) {
            if (spaceBefore)
                print(Text.Space);
            print(prefix);
            print(Text.Space);
            printArray(templ.parents, Text.None, Text.None, TXT_WITH_SP);
        }

        if (templ.body.length > 0) {
	    print(Text.Space);
            printArray(templ.body, TXT_BLOCK_BEGIN, TXT_BLOCK_END, TXT_BLOCK_SEP);
	}
    }

    protected void printParams(Tree.TypeDef[] tparams) {
        if (tparams.length > 0) {
	    print(TXT_LEFT_BRACKET);
	    for (int i = 0; i < tparams.length; i++) {
		if (i > 0) print(TXT_COMMA_SP);
		printParam(tparams[i]);
	    }
	    print(TXT_RIGHT_BRACKET);
	}
    }

    protected void printParams(Tree.ValDef[][] vparamss) {
        for (int i = 0; i < vparamss.length; ++i)
            printParams(vparamss[i]);
    }

    protected void printParams(Tree.ValDef[] vparams) {
	print(TXT_LEFT_PAREN);
        for (int i = 0; i < vparams.length; ++i) {
	    if (i > 0) print(TXT_COMMA_SP);
            printParam(vparams[i]);
	}
	print(TXT_RIGHT_PAREN);
    }

    protected void printParam(Tree tree) {
	switch (tree) {
	case TypeDef(int mods, Name name, Tree bound):
            printModifiers(mods);
            printSymbolDefinition(tree.symbol(), name);
            printOpt(TXT_SUBTYPE, bound, true);
            break;

        case ValDef(int mods, Name name, Tree tpe, Tree.Empty):
            printModifiers(mods);
            printSymbolDefinition(tree.symbol(), name);
            printOpt(TXT_COLON, tpe, false);
            break;

	default:
	    Debug.abort("bad parameter: " + tree);
	}
    }
}