scala.reflect.api.Printers.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-reflect Show documentation
Show all versions of scala-reflect Show documentation
Reflection Library for the Scala Programming Language
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala
package reflect
package api
import java.io.{ PrintWriter, StringWriter }
/**
* EXPERIMENTAL
*
* Utilities for nicely printing [[scala.reflect.api.Trees]] and [[scala.reflect.api.Types]].
*
* === Printing Trees ===
* The method `show` displays the "prettified" representation of reflection artifacts.
* This representation provides one with the desugared Java representation of Scala code.
* For example:
*
* {{{
* scala> import scala.reflect.runtime.universe._
* import scala.reflect.runtime.universe._
*
* scala> def tree = reify{ final class C { def x = 2 } }.tree
* tree: reflect.runtime.universe.Tree
*
* scala> show(tree)
* res0: String =
* {
* final class C extends AnyRef {
* def () = {
* super.();
* ()
* };
* def x = 2
* };
* ()
* }
* }}}
*
* The method `showRaw` displays internal structure of a given reflection object
* as a Scala abstract syntax tree (AST), the representation that the Scala typechecker
* operates on.
*
* Note, that while this representation appears to generate correct trees that one
* might think would be possible to use in a macro implementation, this is not usually
* the case. Symbols aren't fully represented (only their names are). Thus, this method
* is best-suited for use simply inspecting ASTs given some valid Scala code.
* {{{
* scala> showRaw(tree)
* res1: String = Block(List(
* ClassDef(Modifiers(FINAL), TypeName("C"), List(), Template(
* List(Ident(TypeName("AnyRef"))),
* noSelfType,
* List(
* DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(),
* Block(List(
* Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())),
* Literal(Constant(())))),
* DefDef(Modifiers(), TermName("x"), List(), List(), TypeTree(),
* Literal(Constant(2))))))),
* Literal(Constant(())))
* }}}
*
* The method `showRaw` can also print [[scala.reflect.api.Types]] next to the artifacts
* being inspected
* {{{
* scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar
* import scala.tools.reflect.ToolBox
*
* scala> import scala.reflect.runtime.{currentMirror => cm}
* import scala.reflect.runtime.{currentMirror=>cm}
*
* scala> showRaw(cm.mkToolBox().typecheck(tree), printTypes = true)
* res2: String = Block[1](List(
* ClassDef[2](Modifiers(FINAL), TypeName("C"), List(), Template[3](
* List(Ident[4](TypeName("AnyRef"))),
* noSelfType,
* List(
* DefDef[2](Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree[3](),
* Block[1](List(
* Apply[4](Select[5](Super[6](This[3](TypeName("C")), tpnme.EMPTY), ...))),
* Literal[1](Constant(())))),
* DefDef[2](Modifiers(), TermName("x"), List(), List(), TypeTree[7](),
* Literal[8](Constant(2))))))),
* Literal[1](Constant(())))
* [1] TypeRef(ThisType(scala), scala.Unit, List())
* [2] NoType
* [3] TypeRef(NoPrefix, TypeName("C"), List())
* [4] TypeRef(ThisType(java.lang), java.lang.Object, List())
* [5] MethodType(List(), TypeRef(ThisType(java.lang), java.lang.Object, List()))
* [6] SuperType(ThisType(TypeName("C")), TypeRef(... java.lang.Object ...))
* [7] TypeRef(ThisType(scala), scala.Int, List())
* [8] ConstantType(Constant(2))
* }}}
*
* === Printing Types ===
*
* The method `show`
* {{{
* scala> import scala.reflect.runtime.universe._
* import scala.reflect.runtime.universe._
*
* scala> def tpe = typeOf[{ def x: Int; val y: List[Int] }]
* tpe: reflect.runtime.universe.Type
*
* scala> show(tpe)
* res0: String = scala.AnyRef{def x: Int; val y: scala.List[Int]}
* }}}
*
* Like the method `showRaw` for [[scala.reflect.api.Trees]], `showRaw`
* for [[scala.reflect.api.Types]] provides a visualization of the Scala
* AST operated on by the Scala typechecker.
* {{{
* // showRaw has already been discussed above
* scala> showRaw(tpe)
* res1: String = RefinedType(
* List(TypeRef(ThisType(scala), TypeName("AnyRef"), List())),
* Scope(
* TermName("x"),
* TermName("y")))
* }}}
*
* `printIds` and/or `printKinds` can additionally be supplied as arguments in a call to
* `showRaw` which additionally shows the unique identifiers of symbols.
*
* {{{
* scala> showRaw(tpe, printIds = true, printKinds = true)
* res2: String = RefinedType(
* List(TypeRef(ThisType(scala#2043#PK), TypeName("AnyRef")#691#TPE, List())),
* Scope(
* TermName("x")#2540#METH,
* TermName("y")#2541#GET))
* }}}
*
* For more details about `Printer`s and other aspects of Scala reflection, see the
* [[https://docs.scala-lang.org/overviews/reflection/overview.html Reflection Guide]]
*
* @group ReflectionAPI
*/
trait Printers { self: Universe =>
/** @group Printers */
protected trait TreePrinter {
def print(args: Any*): Unit
protected var printTypes = false
protected var printIds = false
protected var printOwners = false
protected var printKinds = false
protected var printMirrors = false
protected var printPositions = false
def withTypes: this.type = { printTypes = true; this }
def withoutTypes: this.type = { printTypes = false; this }
def withIds: this.type = { printIds = true; this }
def withoutIds: this.type = { printIds = false; this }
def withOwners: this.type = { printOwners = true; this }
def withoutOwners: this.type = { printOwners = false; this }
def withKinds: this.type = { printKinds = true; this }
def withoutKinds: this.type = { printKinds = false; this }
def withMirrors: this.type = { printMirrors = true; this }
def withoutMirrors: this.type = { printMirrors = false; this }
def withPositions: this.type = { printPositions = true; this }
def withoutPositions: this.type = { printPositions = false; this }
}
/** @group Printers */
case class BooleanFlag(value: Option[Boolean])
/** @group Printers */
object BooleanFlag {
import scala.language.implicitConversions
implicit def booleanToBooleanFlag(value: Boolean): BooleanFlag = BooleanFlag(Some(value))
implicit def optionToBooleanFlag(value: Option[Boolean]): BooleanFlag = BooleanFlag(value)
import scala.reflect.internal.settings.MutableSettings
implicit def settingToBooleanFlag(setting: MutableSettings#BooleanSetting): BooleanFlag = BooleanFlag(Some(setting.value))
}
/** @group Printers */
protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = {
val buffer = new StringWriter()
val writer = new PrintWriter(buffer)
val printer = mkPrinter(writer)
printTypes.value.foreach(if (_) printer.withTypes else printer.withoutTypes)
printIds.value.foreach(if (_) printer.withIds else printer.withoutIds)
printOwners.value.foreach(if (_) printer.withOwners else printer.withoutOwners)
printKinds.value.foreach(if (_) printer.withKinds else printer.withoutKinds)
printMirrors.value.foreach(if (_) printer.withMirrors else printer.withoutMirrors)
printPositions.value.foreach(if (_) printer.withPositions else printer.withoutPositions)
printer.print(what)
writer.flush()
buffer.toString
}
/** By default trees are printed with `show`
* @group Printers
*/
override protected def treeToString(tree: Tree) = show(tree)
/** Renders a representation of a reflection artifact
* as desugared Scala code.
*
* @group Printers
*/
def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String =
render(any, newTreePrinter(_), printTypes, printIds, printOwners, printKinds, printMirrors, printPositions)
/** Hook to define what `show(...)` means.
* @group Printers
*/
protected def newTreePrinter(out: PrintWriter): TreePrinter
/**
* Renders the code of the passed tree, so that:
* 1) it can be later compiled by scalac retaining the same meaning,
* 2) it looks pretty.
* #1 is available for unattributed trees and attributed trees
* #2 is more or less okay indentation-wise, but at the moment there's a lot of desugaring
* left in place, and that's what we plan to improve in the future.
* printTypes, printIds, printPositions options have the same meaning as for TreePrinter
* printRootPkg option is available only for attributed trees.
*
* @group Printers
*/
def showCode(tree: Tree, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printPositions: BooleanFlag = None, printRootPkg: Boolean = false) =
render(tree, newCodePrinter(_, tree, printRootPkg), printTypes, printIds, printOwners, printKinds = None, printMirrors = None, printPositions)
/**
* Hook to define what `showCode(...)` means.
* @group Printers
*/
protected def newCodePrinter(out: PrintWriter, tree: Tree, printRootPkg: Boolean): TreePrinter
/** Renders internal structure of a reflection artifact as the
* visualization of a Scala syntax tree.
*
* @group Printers
*/
def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String =
render(any, newRawTreePrinter, printTypes, printIds, printOwners, printKinds, printMirrors, printPositions)
/** Hook to define what `showRaw(...)` means.
* @group Printers
*/
protected def newRawTreePrinter(out: PrintWriter): TreePrinter
/** Renders a prettified representation of a name.
* @group Printers
*/
def show(name: Name): String
/** Renders internal structure of a name.
* @group Printers
*/
def showRaw(name: Name): String = name.toString
/** Renders a prettified representation of a flag set.
* @group Printers
*/
def show(flags: FlagSet): String
/** Renders a prettified representation of a position.
* @group Printers
*/
def show(position: Position): String
/** Renders internal structure of a flag set.
* @group Printers
*/
def showRaw(flags: FlagSet): String = flags.toString
/** Renders internal structure of a position.
* @group Printers
*/
def showRaw(position: Position): String = position.toString
/** Renders a string that represents a declaration of this symbol written in Scala.
* @group Printers
*/
def showDecl(sym: Symbol): String
}