summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
blob: f9ee9755d04923fea31ea6b6e38c3fd18437a89d (plain) (tree)
1
2
3
4
5
6
7
8
9
                            
                                

                          
       



                                              




                                                  

                  





                                                                                 
                             
 

                                           
 
                 

                                                  
                                    



                                                





                                                                                     

     
                                                                              



                                                                           
                                                                           


                                                               
                                                                           
 
                                            


                                                                     
     
 
                                            





                                                                    








                                                        

     






                                                


                                                 
                                                           



                                                                                         
                                              
                                                       
     
 
                                                     








                                                                              

                                                                        



                                                                 



                                                        
            


                                                                  


       

                                                    
 
                              



                          
                                                   
                                


                                                                                       
                                         

                                           
                                


                                                                                
                                



                                                                            
                                









                                                              
                                




                                                                     







                                                                            




                                                                                      
                                                         


                                                                     




                                                             



                                                    
                                                                                    



                                         
                                                                                              

                                          
                                             
                                     



                                                                                     


                                                              


                                           
























































                                                                                       
                                                                     






                                                     

                                                                                           

                                            









                                                                                        
                                                                        














                                                                  

                                                                                           



                                 

                                                                                                     



                                           
                                                                                                

                                            

                                                                    












                                                                      

                                                    
 

                                                      
                                                            
 


                                                            
                                                                      



                                                                                              
                           

                                                               
                                                                                 
                      


                                                                                  
                                                                                        
                                                                               




                          
                                      







                                                               









                                                                                 
                                                            
 
                                                        









                                            
/* NSC -- new Scala compiler
 * Copyright 2005-2007 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$

package scala.tools.nsc.ast

import compat.Platform.{EOL => LINE_SEPARATOR}
import java.io.{OutputStream, PrintWriter, Writer}
import symtab.Flags._

abstract class TreePrinters {

  val trees: Trees
  import trees._

  class TreePrinter(out: PrintWriter) {
    protected var indentMargin = 0
    protected val indentStep = 2
    protected var indentString = "                                        " // 40

    def flush() = out.flush()

    def indent = indentMargin += indentStep
    def undent = indentMargin -= indentStep

    def println {
      out.println()
      while (indentMargin > indentString.length())
        indentString += indentString
      if (indentMargin > 0)
        out.write(indentString, 0, indentMargin)
    }

    def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) {
      ls match {
        case List() =>
        case List(x) => printelem(x)
        case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep)
      }
    }

    def printColumn(ts: List[Tree], start: String, sep: String, end: String) {
      print(start); indent; println
      printSeq(ts){print}{print(sep); println}; undent; println; print(end)
    }

    def printRow(ts: List[Tree], start: String, sep: String, end: String) {
      print(start); printSeq(ts){print}{print(sep)}; print(end)
    }

    def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") }

    def printTypeParams(ts: List[TypeDef]) {
      if (!ts.isEmpty) {
        print("["); printSeq(ts){printParam}{print(", ")}; print("]")
      }
    }

    def printValueParams(ts: List[ValDef]) {
      print("(")
      if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "")
      printSeq(ts){printParam}{print(", ")}
      print(")")
    }

    def printParam(tree: Tree) {
      tree match {
        case ValDef(mods, name, tp, rhs) =>
          printAnnotations(tree)
          print(symName(tree, name)); printOpt(": ", tp)
        case TypeDef(mods, name, tparams, rhs) =>
          print(symName(tree, name))
          printTypeParams(tparams); print(rhs)
      }
    }

    def printBlock(tree: Tree) {
      tree match {
        case Block(_, _) =>
          print(tree)
        case _ =>
          printColumn(List(tree), "{", ";", "}")
      }
    }

    def symName(tree: Tree, name: Name): String =
      if (tree.symbol != null && tree.symbol != NoSymbol) {
        ((if (tree.symbol.isMixinConstructor) "/*"+tree.symbol.owner.name+"*/" else "") +
         tree.symbol.nameString)
      } else name.toString();

    def printOpt(prefix: String, tree: Tree) {
      if (!tree.isEmpty) { print(prefix); print(tree) }
    }

    def printModifiers(tree: Tree, mods: Modifiers) {
      if (tree.symbol == NoSymbol)
        printFlags(mods.flags, mods.privateWithin.toString)
      else if (tree.symbol.privateWithin == NoSymbol ||
               tree.symbol.privateWithin == tree.symbol.owner)
        printFlags(tree.symbol.flags, "")
      else
        printFlags(tree.symbol.flags, tree.symbol.privateWithin.name.toString)
    }

    def printFlags(flags: Long, privateWithin: String) {
      var mask: Long = if (settings.debug.value) -1L else PrintableFlags
      val s = flagsToString(flags & mask, privateWithin.toString)
      if (s.length() != 0) print(s + " ")
    }

    def printAnnotations(tree: Tree) {
      val annots = tree.symbol.attributes
      if (!annots.isEmpty)
        annots foreach { annot => print("@"+annot+" ") }
      else {
        val annots = tree.asInstanceOf[MemberDef].mods.annotations
        if (!annots.isEmpty)
          annots foreach { annot => print("@"+annot+" ") }
      }
    }

    def print(str: String) { out.print(str) }
    def print(name: Name) { print(name.toString()) }

    def printRaw(tree: Tree) {
      tree match {
        case EmptyTree =>
          print("<empty>")

        case ClassDef(mods, name, tparams, impl) =>
          printAnnotations(tree)
          printModifiers(tree, mods)
          print((if (mods hasFlag TRAIT) "trait " else "class ") + symName(tree, name))
          printTypeParams(tparams)
          print(" extends "); print(impl)

        case PackageDef(packaged, stats) =>
          printAnnotations(tree)
          print("package "); print(packaged); printColumn(stats, " {", ";", "}")

        case ModuleDef(mods, name, impl) =>
          printAnnotations(tree)
          printModifiers(tree, mods); print("object " + symName(tree, name))
          print(" extends "); print(impl)

        case ValDef(mods, name, tp, rhs) =>
          printAnnotations(tree)
          printModifiers(tree, mods)
          print(if (mods.hasFlag(MUTABLE)) "var " else "val ")
          print(symName(tree, name))
          printOpt(": ", tp)
          if (!mods.hasFlag(DEFERRED)) {
            print(" = ")
            if (rhs.isEmpty) print("_") else print(rhs)
          }

        case DefDef(mods, name, tparams, vparamss, tp, rhs) =>
          printAnnotations(tree)
          printModifiers(tree, mods)
          print("def " + symName(tree, name))
          printTypeParams(tparams); vparamss foreach printValueParams
          printOpt(": ", tp); printOpt(" = ", rhs)

        case TypeDef(mods, name, tparams, rhs) =>
          if (mods hasFlag (PARAM | DEFERRED)) {
            printModifiers(tree, mods); print("type "); printParam(tree)
          } else {
            printAnnotations(tree)
            printModifiers(tree, mods); print("type " + symName(tree, name))
            printTypeParams(tparams); printOpt(" = ", rhs)
          }

        case LabelDef(name, params, rhs) =>
          print(symName(tree, name)); printRow(params, "(", ",", ")"); printBlock(rhs)

        case Import(expr, selectors) =>
          def selectorToString(s: (Name, Name)): String =
            if (s._1 == nme.WILDCARD || s._1 == s._2) s._1.toString()
            else s._1.toString() + "=>" + s._2.toString()
          print("import "); print(expr)
	  print(".")
          selectors.map(selectorToString) match {
            case List(one) => print(one)
            case many => print(many.mkString("{", ", ", "}"))
          }

        case DocDef(comment, definition) =>
          print(comment); println; print(definition)

        case Annotation(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), elements) =>
          print(tpt)
          if (!args.isEmpty)
            printRow(args, "(", ",", ")")
          if (!elements.isEmpty)
            print((for (Assign(name, value) <- elements) yield "val " + name + " = " + value).
                  mkString("{", ",", "}"))

        case Template(parents, self, body) =>
          printRow(parents, " with ")
          if (!body.isEmpty) {
            if (self.name != nme.WILDCARD) {
              print(" { "); print(self.name); printOpt(": ", self.tpt); print(" => ")
            } else if (!self.tpt.isEmpty) {
              print(" { _ : "); print(self.tpt); print(" => ")
            } else {
              print(" {")
            }
            printColumn(body, "", ";", "}")
          }

        case Block(stats, expr) =>
          printColumn(stats ::: List(expr), "{", ";", "}")

        case Match(selector, cases) =>
          print(selector); printColumn(cases, " match {", "", "}")

        case CaseDef(pat, guard, body) =>
          print("case "); print(pat); printOpt(" if ", guard)
          print(" => "); print(body)

        case Sequence(trees) =>
          printRow(trees, "[", ", ", "]")

        case Alternative(trees) =>
          printRow(trees, "(", "| ", ")")

        case Star(elem) =>
          print("("); print(elem); print(")*")

        case Bind(name, t) =>
          print("("); print(symName(tree, name)); print(" @ "); print(t); print(")")

        case UnApply(fun, args) =>
          print(fun); print(" <unapply> "); printRow(args, "(", ", ", ")")

        case ArrayValue(elemtpt, trees) =>
          print("Array["); print(elemtpt); printRow(trees, "]{", ", ", "}")

        case Function(vparams, body) =>
          print("("); printValueParams(vparams); print(" => "); print(body); print(")")

        case Assign(lhs, rhs) =>
          print(lhs); print(" = "); print(rhs)

        case If(cond, thenp, elsep) =>
          print("if ("); print(cond); print(")"); indent; println
          print(thenp); undent
          if (!elsep.isEmpty) {
            println; print("else"); indent; println; print(elsep); undent
          }

        case Return(expr) =>
          print("return "); print(expr)

        case Try(block, catches, finalizer) =>
          print("try "); printBlock(block)
          if (!catches.isEmpty) printColumn(catches, " catch {", "", "}")
          printOpt(" finally ", finalizer)

        case Throw(expr) =>
          print("throw "); print(expr)

        case New(tpe) =>
          print("new "); print(tpe)

        case Typed(expr, tp) =>
          print("("); print(expr); print(": "); print(tp); print(")")

        case TypeApply(fun, targs) =>
          print(fun); printRow(targs, "[", ", ", "]")

        case Apply(fun, vargs) =>
          print(fun); printRow(vargs, "(", ", ", ")")

        case ApplyDynamic(qual, vargs) =>
          print("<apply-dynamic>("); print(qual); print("#"); print(tree.symbol.nameString)
          printRow(vargs, ", (", ", ", "))")

        case Super(qual, mix) =>
          if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".")
          print("super")
          if (!mix.isEmpty)
            print("[" + mix + "]")

        case This(qual) =>
          if (!qual.isEmpty) print(symName(tree, qual) + ".")
          print("this")

        case Select(qual @ New(tpe), name) if (!settings.debug.value) =>
          print(qual)

        case Select(qualifier, name) =>
          print(qualifier); print("."); print(symName(tree, name))

        case Ident(name) =>
          print(symName(tree, name))

        case Literal(x) =>
          print(x.escapedStringValue)

        case TypeTree() =>
          print(
            if (tree.tpe eq null)
              "<type ?>"
            else if ((tree.tpe.typeSymbol ne null) && tree.tpe.typeSymbol.isAnonymousClass)
              tree.tpe.typeSymbol.toString()
            else
              tree.tpe.toString()
          )

        case Annotated(Annotation(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), elements), tree) =>
          def printAnnot() {
            print("@"); print(tpt)
            if (!args.isEmpty)
              printRow(args, "(", ",", ")")
            if (!elements.isEmpty)
              print((for (Assign(name, value) <- elements) yield "val " + name + " = " + value).
                    mkString("{", ",", "}"))
          }
          if (tree.isType) { printAnnot(); print(" "); print(tree) }
          else { print(tree); print(": "); printAnnot() }

        case SingletonTypeTree(ref) =>
          print(ref); print(".type")

        case SelectFromTypeTree(qualifier, selector) =>
          print(qualifier); print("#"); print(symName(tree, selector))

        case CompoundTypeTree(templ) =>
          print(templ)

        case AppliedTypeTree(tp, args) =>
          print(tp); printRow(args, "[", ", ", "]")

        case TypeBoundsTree(lo, hi) =>
          printOpt(" >: ", lo); printOpt(" <: ", hi)

        case ExistentialTypeTree(tpt, whereClauses) =>
          print(tpt);
          printColumn(whereClauses, " forSome { ", ";", "}")

        case tree =>
          print("<unknown tree of class "+tree.getClass+">")
      }
      if (settings.printtypes.value && tree.isTerm && !tree.isEmpty) {
        print("{"); print(if (tree.tpe eq null) "<null>" else tree.tpe.toString()); print("}")
      }
    }

    def print(tree: Tree) {
      if (settings.Xprintpos.value) print("[" + tree.pos + "]")
      printRaw(
        if (tree.isDef && tree.symbol != NoSymbol && tree.symbol.isInitialized) {
          tree match {
            case ClassDef(_, _, _, impl)           => ClassDef(tree.symbol, impl)
            case ModuleDef(_, _, impl)             => ModuleDef(tree.symbol, impl)
            case ValDef(_, _, _, rhs)              => ValDef(tree.symbol, rhs)
            case DefDef(_, _, _, vparamss, _, rhs) => DefDef(tree.symbol, vparamss, rhs)
            case TypeDef(_, _, _, rhs)             => TypeDef(tree.symbol, rhs)
            case _ => tree
          }
        } else tree)
    }

    def print(unit: CompilationUnit) {
      print("// Scala source: " + unit.source + LINE_SEPARATOR)
      if (unit.body ne null) {
        print(unit.body); println
      } else {
        print("<null>")
      }
      println; flush
    }
  }

  def create(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
  def create(stream: OutputStream): TreePrinter = create(new PrintWriter(stream))
  def create(): TreePrinter = {
    /** A writer that writes to the current Console and
      * is sensitive to replacement of the Console's
      * output stream.
      */
    object ConsoleWriter extends Writer {
      override def write(str: String) { Console.print(str) }

      def write(cbuf: Array[Char], off: Int, len: Int) {
        val str = new String(cbuf, off, len)
        write(str)
      }

      def close = { /* do nothing */ }
      def flush = { /* do nothing */ }
    }
    create(new PrintWriter(ConsoleWriter))
  }
}