summaryrefslogblamecommitdiff
path: root/sources/scalac/atree/ATreePrinter.java
blob: fb0a108a996616fef3c470ef32245ef5d2c07759 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                                          
                     
                    
                              



                                        
                                        


























































































































































































































                                                                              

                                      
                            
                                                             

                                                                            



                                                                   
                           
                                                         



                                                   


























































































                                                                         




                                               



                                                               


















                                                                             
                                                                  






                                                                               
                                                              







                                                                              
                                                             

































                                                                            




                                                    















                                                                            
                                                        


         


                                                           
                                                           
                                                            
                                                                     
                                                                              

                                                                              
                                       
                                                                     
                                         
                                                                              


                                             

                                                                       




                                                        
                                

                                                              











                                                                             

                                                      

                                                    






                                                         


                                                                     

     
                                                         
                                                                               
                                        

                                                                         


                    





















                                                           
                                                                                     

                                                                                                     








                                                        
                                                                              








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

// $Id$

package scalac.atree;

import ch.epfl.lamp.util.CodePrinter;

import scalac.Global;
import scalac.Phase;
import scalac.CompilationUnit;
import scalac.symtab.Type;
import scalac.symtab.Symbol;
import scalac.symtab.SymbolTablePrinter;
import scalac.util.Debug;
import scalac.util.SourceRepresentation;

/** This class provides methods to print attributed trees. */
public class ATreePrinter {

    //########################################################################
    // Private Fields

    /** The global environment */
    private final Global global;

    /** The underlying code printer */
    private final CodePrinter printer;

    /** The underlying symbol table printer */
    private final SymbolTablePrinter symtab;

    //########################################################################
    // Public Constructors

    /** Initalizes this instance */
    public ATreePrinter() {
        this(new CodePrinter());
    }

    /** Initalizes this instance */
    public ATreePrinter(String step) {
        this(Global.instance, new CodePrinter(step));
    }

    /** Initalizes this instance */
    public ATreePrinter(CodePrinter printer) {
        this(Global.instance, printer);
    }

    /** Initalizes this instance */
    public ATreePrinter(Global global, CodePrinter printer) {
        this.global = global;
        this.printer = printer;
        this.symtab = new SymbolTablePrinter(global, printer);
    }

    //########################################################################
    // Public Methods - Getting & Setting

    /** Returns the underlying code printer. */
    public CodePrinter getCodePrinter() {
        return printer;
    }

    //########################################################################
    // Public Methods - Formatting

    /** Increases the indentation level by one. */
    public ATreePrinter indent() {
        printer.indent();
        return this;
    }

    /** Decreases the indentation level by one. */
    public ATreePrinter undent() {
        printer.undent();
        return this;
    }

    /** Inserts a new line. */
    public ATreePrinter line() {
        printer.line();
        return this;
    }

    /** Inserts a white space. */
    public ATreePrinter space() {
        printer.space();
        return this;
    }

    /** Prints an opening brace followed by a new line. */
    public ATreePrinter lbrace() {
        return space().println('{').indent();
    }

    /** Prints a closing brace followed by a new line. */
    public ATreePrinter rbrace() {
        return undent().space().println('}');
    }

    //########################################################################
    // Public Methods - Printing simple values

    /** Prints a new line. */
    public ATreePrinter println() {
        printer.println();
        return this;
    }

    /** Prints the boolean value followed by a new line. */
    public ATreePrinter println(boolean value) {
        printer.println(value);
        return this;
    }

    /** Prints the byte value followed by a new line. */
    public ATreePrinter println(byte value) {
        printer.println(value);
        return this;
    }

    /** Prints the short value followed by a new line. */
    public ATreePrinter println(short value) {
        printer.println(value);
        return this;
    }

    /** Prints the char value followed by a new line. */
    public ATreePrinter println(char value) {
        printer.println(value);
        return this;
    }

    /** Prints the int value followed by a new line. */
    public ATreePrinter println(int value) {
        printer.println(value);
        return this;
    }

    /** Prints the long value followed by a new line. */
    public ATreePrinter println(long value) {
        printer.println(value);
        return this;
    }

    /** Prints the float value followed by a new line. */
    public ATreePrinter println(float value) {
        printer.println(value);
        return this;
    }

    /** Prints the double value followed by a new line. */
    public ATreePrinter println(double value) {
        printer.println(value);
        return this;
    }

    /** Prints the string followed by a new line. */
    public ATreePrinter println(String value) {
        printer.println(value);
        return this;
    }

    /** Prints the boolean value. */
    public ATreePrinter print(boolean value) {
        printer.print(value);
        return this;
    }

    /** Prints the byte value. */
    public ATreePrinter print(byte value) {
        printer.print(value);
        return this;
    }

    /** Prints the short value. */
    public ATreePrinter print(short value) {
        printer.print(value);
        return this;
    }

    /** Prints the char value. */
    public ATreePrinter print(char value) {
        printer.print(value);
        return this;
    }

    /** Prints the int value. */
    public ATreePrinter print(int value) {
        printer.print(value);
        return this;
    }

    /** Prints the long value. */
    public ATreePrinter print(long value) {
        printer.print(value);
        return this;
    }

    /** Prints the float value. */
    public ATreePrinter print(float value) {
        printer.print(value);
        return this;
    }

    /** Prints the long value. */
    public ATreePrinter print(double value) {
        printer.print(value);
        return this;
    }

    /** Prints the string. */
    public ATreePrinter print(String value) {
        printer.print(value);
        return this;
    }

    //########################################################################
    // Public Methods - Printing types and symbols

    /** Prints the symbol. */
    public ATreePrinter printSymbol(Symbol symbol) {
        symtab.printSymbolName(symbol);
        return this;
    }

    /** Prints the type. */
    public ATreePrinter printType(Type type) {
        symtab.printType(type);
        return this;
    }

    //########################################################################
    // Public Methods - Printing trees

    /** Prints the units. */
    public ATreePrinter printUnits(CompilationUnit[] units) {
        Phase phase = global.currentPhase;
        println("[[attributed trees at "+phase+" (after "+phase.prev+")]]");
        for (int i = 0; i < units.length; i++) printUnit(units[i]);
        return this;
    }

    /** Prints the unit. */
    public ATreePrinter printUnit(CompilationUnit unit) {
        println("// Scala source: " + unit.source);
        return printRepository(unit.repository);
    }

    /** Prints the repository. */
    public ATreePrinter printRepository(ARepository repository) {
        AClass[] classes = repository.classes();
        for (int i = 0; i < classes.length; i++) printClass(classes[i]);
        return this;
    }

    /** Prints the class. */
    public ATreePrinter printClass(AClass clasz) {
        printClassModifiers(clasz);
        print(clasz.isInterface() ? "interface" : "class").space();
        printSymbol(clasz.symbol());
        Symbol[] tparams = clasz.tparams();
        if (tparams.length != 0) symtab.printTypeParams(tparams);
        Symbol[] vparams = clasz.vparams();
        if (vparams.length != 0) symtab.printValueParams(vparams);
        if (clasz.symbol().typeOfThis() != clasz.symbol().thisType())
            space().print(':').printType(clasz.symbol().typeOfThis());
        space().print("extends").space();
        symtab.printTypes(clasz.parents()," with ");
        lbrace();
        printRepository(clasz);
        AField[] fields = clasz.fields();
        for (int i = 0; i < fields.length; i++) printField(fields[i]);
        AMethod[] methods = clasz.methods();
        for (int i = 0; i < methods.length; i++) printMethod(methods[i]);
        return rbrace();
    }

    /** Prints the class modifiers. */
    public ATreePrinter printClassModifiers(AClass clasz) {
        if (clasz.isDeprecated()) print("deprecated").space();
        if (clasz.isSynthetic()) print("synthetic").space();
        if (clasz.isPublic()) print("public").space();
        if (clasz.isPrivate()) print("private").space();
        if (clasz.isProtected()) print("protected").space();
        if (clasz.isFinal()) print("final").space();
        if (clasz.isAbstract()) print("abstract").space();
        return this;
    }

    /** Prints the member modifiers. */
    public ATreePrinter printMemberModifiers(AMember member) {
        if (member.isDeprecated()) print("deprecated").space();
        if (member.isSynthetic()) print("synthetic").space();
        if (member.isPublic()) print("public").space();
        if (member.isPrivate()) print("private").space();
        if (member.isProtected()) print("protected").space();
        if (member.isStatic()) print("static").space();
        return this;
    }

    /** Prints the member code. */
    public ATreePrinter printMemberCode(AMember member) {
        if (member.code() == ACode.Void) return this;
        return print('=').space().printCode(member.code());
    }

    /** Prints the field. */
    public ATreePrinter printField(AField field) {
        printFieldModifiers(field);
        symtab.printSignature(field.symbol()).space();
        return printMemberCode(field).line();
    }

    /** Prints the field modifiers. */
    public ATreePrinter printFieldModifiers(AField field) {
        printMemberModifiers(field);
        if (field.isFinal()) print("final").space();
        if (field.isVolatile()) print("volatile").space();
        if (field.isTransient()) print("transient").space();
        return this;
    }

    /** Prints the method. */
    public ATreePrinter printMethod(AMethod method) {
        printMethodModifiers(method);
        symtab.printSignature(method.symbol()).space();
        return printMemberCode(method).line();
    }

    /** Prints the method modifiers. */
    public ATreePrinter printMethodModifiers(AMethod method) {
        printMemberModifiers(method);
        if (method.isFinal()) print("final").space();
        if (method.isSynchronized()) print("synchronized").space();
        if (method.isNative()) print("native").space();
        if (method.isAbstract()) print("abstract").space();
        return this;
    }

    /** Prints the code. */
    public ATreePrinter printCode(ACode code) {
        switch (code) {
        case Void:
            return print("<void>");
        case This(Symbol clasz):
            return printSymbol(clasz).print('.').print("this");
        case Constant(AConstant constant):
            return printConstant(constant);
        case Load(ALocation location):
            return printLocation(location);
        case Store(ALocation location, ACode value):
            printLocation(location).space().print('=').space();
            return printCode(value);
        case Apply(AFunction function, Type[] targs, ACode[] vargs):
            printFunction(function);
            if (targs.length > 0){
                print('[');
                for (int i = 0; i < targs.length; i++)
                    (i == 0 ? this : print(',').space()).printType(targs[i]);
                print(']');
            }
            print('(');
            for (int i = 0; i < vargs.length; i++)
                (i == 0 ? this : print(',').space()).printCode(vargs[i]);
            print(')');
            return this;
        case IsAs(ACode value, Type type, boolean cast):
            printCode(value).print('.').print(cast ? "as" : "is");
            return print('[').printType(type).print(']');
        case If(ACode test, ACode success, ACode failure):
            print("if").space().print('(').printCode(test).print(')').lbrace();
            printCode(success).line();
            rbrace().space().print("else").space().lbrace();
            printCode(failure).line();
            return rbrace();
        case Switch(ACode test, int[][] tags, ACode[] bodies):
            print("switch").space().print('(').printCode(test).print(')');
            lbrace();
            for (int i = 0; i < tags.length; i++) {
                for (int j = 0; j < tags[i].length; j++)
                    print("case").space().print(tags[i][j]).print(':').line();
                indent().printCode(bodies[i]).undent().line();
            }
            print("case").space().print('_').print(':').line();
            indent().printCode(bodies[tags.length]).undent();
            return rbrace();
        case Synchronized(ACode lock, ACode value):
            print("synchronized").space();
            print('(').printCode(lock).print(')');
            return lbrace().printCode(value).rbrace();
        case Block(Symbol[] locals, ACode[] statements, ACode value):
            lbrace();
            for (int i = 0; i < locals.length; i++) {
                print("var").space().printSymbol(locals[i]);
                print(":").space().printType(locals[i].type());
                println(";");
            }
            for (int i = 0; i < statements.length; i++)
                printCode(statements[i]).println(';');
            return printCode(value).line().rbrace();
        case Label(Symbol label, Symbol[] locals, ACode value):
            print("label").space().printSymbol(label).print('(');
            for (int i = 0; i < locals.length; i++)
                (i == 0 ? this : print(',').space()).printSymbol(locals[i]);
            print(')').space().print('=').lbrace();
            return printCode(value).rbrace();
        case Goto(Symbol label, ACode[] vargs):
            print("goto").space().printSymbol(label).print('(');
            for (int i = 0; i < vargs.length; i++)
                (i == 0 ? this : print(',').space()).printCode(vargs[i]);
            return print(')');
        case Return(Symbol function, ACode value):
            print("return").symtab.printSymbolUniqueId(function).space();
            return printCode(value);
        case Throw(ACode value):
            return print("throw").space().printCode(value);
        case Drop(ACode value, Type type):
            print("drop").print('[').printType(type).print(']').space();
            return printCode(value);
        default:
            throw Debug.abort("unknown case", code);
        }
    }

    /** Prints the location. */
    public ATreePrinter printLocation(ALocation location) {
        switch (location) {
        case Module(Symbol module):
            return printSymbol(module);
        case Field(Void, Symbol field, true):
            return printSymbol(field.owner()).print('.').printSymbol(field);
        case Field(ACode object, Symbol field, boolean isStatic):
            printCode(object).print('.');
            if (isStatic) print("<static>").space();
            return printSymbol(field);
        case Local(Symbol local, _):
            return printSymbol(local);
        case ArrayItem(ACode array, ACode index):
            return printCode(array).print('(').printCode(index).print(')');
        default:
            throw Debug.abort("unknown case", location);
        }
    }

    /** Prints the function. */
    public ATreePrinter printFunction(AFunction function) {
        switch (function) {
        case Method(Void, Symbol method, AInvokeStyle.New):
            return print("new").space().printSymbol(method);
        case Method(Void, Symbol method, AInvokeStyle.Static(false)):
            return printSymbol(method.owner()).print('.').printSymbol(method);
        case Method(This(Symbol c), Symbol method, AInvokeStyle.Static(true)):
            printSymbol(c).print('.').print("super").print('.');
            return printSymbol(method);
        case Method(ACode object, Symbol method, AInvokeStyle style):
            printCode(object).print('.');
            if (style != AInvokeStyle.Dynamic) print("<" +style+ ">").space();
            return printSymbol(method);
        case Primitive(APrimitive primitive):
            return printPrimitive(primitive);
        case NewArray(Type element):
            return print("new").space().printType(element).print("[]");
        default:
            throw Debug.abort("unknown case", function);
        }
    }

    /** Prints the primitive. */
    public ATreePrinter printPrimitive(APrimitive primitive) {
        switch (primitive) {
        case Negation(ATypeKind kind):
            return printPrimitiveOp("NEG", kind);
        case Test(ATestOp op, ATypeKind kind, boolean zero):
            return printPrimitiveOp(op.toString() + (zero ? "Z" : ""), kind);
        case Comparison(AComparisonOp op, ATypeKind kind):
            return printPrimitiveOp(op.toString(), kind);
        case Arithmetic(AArithmeticOp op, ATypeKind kind):
            return printPrimitiveOp(op.toString(), kind);
        case Logical(ALogicalOp op, ATypeKind kind):
            return printPrimitiveOp(op.toString(), kind);
        case Shift(AShiftOp op, ATypeKind kind):
            return printPrimitiveOp(op.toString(), kind);
        case Conversion(ATypeKind src, ATypeKind dst):
            return printPrimitiveOp("CONV", src, dst);
        case ArrayLength(ATypeKind kind):
            return printPrimitiveOp("LENGTH", kind);
        case StringConcat(ATypeKind lf, ATypeKind rg):
            return printPrimitiveOp("CONCAT", lf, rg);
        default:
            throw Debug.abort("unknown case", primitive);
        }
    }

    /** Prints the primitive operation of given type kind. */
    public ATreePrinter printPrimitiveOp(String op, ATypeKind kind) {
        return printPrimitiveOp(op, kind, null);
    }

    /** Prints the primitive operation of given types. */
    public ATreePrinter printPrimitiveOp(String op, ATypeKind k1,ATypeKind k2){
        print('<').print(op).print('>');
        if (k1 != null && global.uniqid) print('#').print(k1.toString());
        if (k2 != null && global.uniqid) print(',').print(k2.toString());
        return this;
    }

    /** Prints the constant. */
    public ATreePrinter printConstant(AConstant constant) {
        switch (constant) {
        case UNIT:
            return print("()");
        case BOOLEAN(boolean value):
            return print(value);
        case BYTE(byte value):
            return print(value);
        case SHORT(short value):
            return print(value);
        case CHAR(char value):
            return print('\'').print(value).print('\'');
        case INT(int value):
            return print(value);
        case LONG(long value):
            return print(value);
        case FLOAT(float value):
            return print(value);
        case DOUBLE(double value):
            return print(value);
        case STRING(String value):
            return print('\"').print(SourceRepresentation.escape(value)).print('\"');
        case SYMBOL_NAME(Symbol value):
            return print('\"').print(SourceRepresentation.escape(value.name.toString())).print('\"');
        case NULL:
            return print("null");
        case ZERO:
            return print("<zero>");
        default:
            throw Debug.abort("unknown case", constant);
        }
    }

    //########################################################################
    // Public Methods - Converting

    /** Returns the string representation of this printer. */
    public String toString() {
        return printer.toString();
    }

    //########################################################################
}