summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorChristopher Vogt <christopher.vogt@epfl.ch>2012-10-08 19:14:52 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-10-11 20:06:26 +0200
commit69693d90ac043feb1bff7adb26db0b2fd73a0640 (patch)
treecdb45ae0c202f4a05b9e6d20100d1cb90a362243 /src/reflect
parent0c619f18ec275c25af65f4c7bdba4b73cb60855d (diff)
downloadscala-69693d90ac043feb1bff7adb26db0b2fd73a0640.tar.gz
scala-69693d90ac043feb1bff7adb26db0b2fd73a0640.tar.bz2
scala-69693d90ac043feb1bff7adb26db0b2fd73a0640.zip
simplified reflection docs for trees
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/api/Trees.scala244
1 files changed, 28 insertions, 216 deletions
diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala
index 9d574adf69..03d62c3bb9 100644
--- a/src/reflect/scala/reflect/api/Trees.scala
+++ b/src/reflect/scala/reflect/api/Trees.scala
@@ -5,222 +5,28 @@
package scala.reflect
package api
-/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines trees and operations on them.
- * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern.
+/** This trait defines the node types used in Scala abstract syntax trees (AST) and operations on them.
+ *
+ * All tree node types are sub types of [[scala.reflect.api#Tree Tree]].
+ *
+ * Trees are immutable, except for three fields
+ * [[Trees#TreeApi.pos pos]], [[Trees#TreeApi.symbol symbol]], and [[Trees#TreeApi.tpe tpe]], which are assigned when a tree is typechecked
+ * to attribute it with the information gathered by the typechecker.
+ *
+ * [[scala.reflect.api.Universe#reify reify]] can be used to get the tree for a given Scala expression.
+ *
+ * [[scala.reflect.api.Universe#showRaw showRaw]] can be used to get a readable representation of a tree.
*
- * Tree is the basis for scala's abstract syntax. The nodes are
- * implemented as case classes, and the parameters which initialize
- * a given tree are immutable: however trees have several mutable
- * fields which are manipulated in the course of typechecking,
- * including `pos`, `symbol`, and `tpe`.
+ * === Examples ===
+ * `Literal(Constant(5))` creates an AST representing a literal 5 in Scala source code.
+ *
+ * `Apply(Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("print")), List(Literal(Constant("Hello World"))))`
+ * creates an AST representing `print("Hello World")`.
+ *
+ * `import scala.reflect.runtime.universe.{reify,showRaw}`
+ * `print( showRaw( reify{5}.tree ) )` // prints Literal(Constant(5))
*
- * Newly instantiated trees have `tpe` set to null (though it
- * may be set immediately thereafter depending on how it is
- * constructed.) When a tree is passed to the typechecker
- * (via toolboxes in runtime reflection or using
- * [[scala.reflect.macros.Context#typeCheck]] in comple-time reflection)
- * under normal circumstances the `tpe` must be
- * `null` or the typechecker will ignore it. Furthermore, the typechecker is not
- * required to return the same tree it was passed.
- *
- * Trees can be easily traversed with e.g. `foreach` on the root node;
- * for a more nuanced traversal, subclass `Traverser`. Transformations
- * are done by subclassing `Transformer`.
- *
- * Copying Trees should be done with care depending on whether
- * it needs be done lazily or strictly (see [[scala.reflect.api.Trees#newLazyTreeCopier]] and
- * [[scala.reflect.api.Trees#newStrictTreeCopier]]) and on whether the contents of the mutable
- * fields should be copied. The tree copiers will copy the mutable
- * attributes to the new tree. A shortcut way of copying trees is [[scala.reflect.api.Trees#Tree#duplicate]]
- * which uses a strict copier.
- *
- * Trees can be coarsely divided into four mutually exclusive categories:
- *
- * - Subclasses of `TermTree`, representing terms
- * - Subclasses of `TypTree`, representing types. Note that is `TypTree`, not `TypeTree`.
- * - Subclasses of `SymTree`, which either define or reference symbols.
- * - Other trees, which have none of those as superclasses.
- *
- * `SymTrees` include important nodes `Ident` (which represent references to identifiers)
- * and `Select` (which represent member selection). These nodes can be used as both terms and types;
- * they are distinguishable based on whether their underlying [[scala.reflect.api.Names#Name]]
- * is a `TermName` or `TypeName`. The correct way to test any Tree for a type or a term are the `isTerm`/`isType`
- * methods on Tree.
- *
- * "Others" are mostly syntactic or short-lived constructs. Take, for example,
- * `CaseDef`, which wraps individual match cases: such nodes are neither terms nor types,
- * nor do they carry a symbol.
- *
- * === How to get a tree that corresponds to a snippet of Scala code? ===
- *
- * With the introduction of compile-time metaprogramming and runtime compilation in Scala 2.10.0,
- * quite often it becomes necessary to convert Scala code into corresponding trees.
- *
- * The simplest was to do that is to use [[scala.reflect.api.Universe#reify]].
- * The `reify` method takes an valid Scala expression (i.e. it has to be well-formed
- * with respect to syntax and has to typecheck, which means no unresolved free variables).
- * and produces a tree that represents the input.
- *
- * {{{
- * scala> import scala.reflect.runtime.universe._
- * import scala.reflect.runtime.universe._
- *
- * // trying to reify a snippet that doesn't typecheck
- * // leads to a compilation error
- * scala> reify(x + 2)
- * <console>:31: error: not found: value x
- * reify(x + 2)
- * ^
- *
- * scala> val x = 2
- * x: Int = 2
- *
- * // now when the variable x is in the scope
- * // we can successfully reify the expression `x + 2`
- * scala> val expr = reify(x + 2)
- * expr: reflect.runtime.universe.Expr[Int] = Expr[Int](x.$plus(2))
- *
- * // the result of reification is of type Expr
- * // exprs are thin wrappers over trees
- * scala> expr.tree
- * res2: reflect.runtime.universe.Tree = x.$plus(2)
- *
- * // we can see that the expression `x + 2`
- * // is internally represented as an instance of the `Apply` case class
- * scala> res2.getClass.toString
- * res3: String = class scala.reflect.internal.Trees$Apply
- *
- * // when it comes to inspecting the structure of the trees,
- * // the default implementation of `toString` doesn't help much
- * // the solution is discussed in one of the next sections
- * }}}
- *
- * The alternative way of getting an AST of a snippet of Scala code
- * is having it parsed by a toolbox (see [[scala.reflect.api.package the overview page]]
- * for more information about toolboxes):
- * {{{
- * scala> import scala.reflect.runtime.universe._
- * import scala.reflect.runtime.universe._
- *
- * scala> import scala.reflect.runtime.{currentMirror => cm}
- * import scala.reflect.runtime.{currentMirror=>cm}
- *
- * scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar
- * import scala.tools.reflect.ToolBox
- *
- * scala> val tb = cm.mkToolBox()
- * tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = ...
- *
- * scala> tb.parse("x + 2")
- * res0: tb.u.Tree = x.$plus(2)
- * }}}
- *
- * === How to evaluate a tree? ===
- *
- * Once there's a way to get a tree that represents Scala code, the next question
- * is how to evaluate it. The answer to this question depends on what flavor of reflection is used:
- * runtime reflection or compile-time reflection (macros).
- *
- * Within runtime reflection, evaluation can be carried out using toolboxes.
- * To create a toolbox one wraps a classloader in a mirror and then uses the mirror
- * to instantiate a toolbox. Later on the underlying classloader will be used to map
- * symbolic names (such as `List`) to underlying classes of the platform
- * (see [[scala.reflect.api.package the overview page]] for more information about universes,
- * mirrors and toolboxes):
- *
- * {{{
- * scala> import scala.reflect.runtime.universe._
- * import scala.reflect.runtime.universe._
- *
- * scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar
- * import scala.tools.reflect.ToolBox
- *
- * scala> val mirror = runtimeMirror(getClass.getClassLoader)
- * mirror: reflect.runtime.universe.Mirror = JavaMirror with ...
- *
- * scala> val tb = mirror.mkToolBox()
- * tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = ...
- *
- * scala> tb.eval(tb.parse("2 + 2"))
- * res0: Int = 4
- * }}}
- *
- * At compile-time, [[scala.reflect.macros.Context]] provides the [[scala.reflect.macros.Evals#eval]] method,
- * which doesn't require manual instantiation of mirrors and toolboxes and potentially will have better performance
- * (at the moment it still creates toolboxes under the cover, but in later releases it might be optimized
- * to reuse the infrastructure of already running compiler).
- *
- * Behind the scenes tree evaluation launches the entire compilation pipeline and creates an in-memory virtual directory
- * that holds the resulting class files (that's why it requires scala-compiler.jar when used with runtime reflection).
- * This means that the tree being evaluated should be valid Scala code (e.g. it shouldn't contain type errors).
- *
- * Quite often though there is a need to evaluate code in some predefined context. For example, one might want to use a dictionary
- * that maps names to values as an environment for the code being evaluated. This isn't supported out of the box,
- * but nevertheless this scenario is possible to implement. See a [[http://stackoverflow.com/questions/12122939 Stack Overflow topic]]
- * for more details.
- *
- * === How to get an internal representation of a tree? ===
- *
- * The `toString` method on trees is designed to print a close-to-Scala representation
- * of the code that a given tree represents. This is usually convenient, but sometimes
- * one would like to look under the covers and see what exactly are the AST nodes that
- * constitute a certain tree.
- *
- * Scala reflection provides a way to dig deeper through [[scala.reflect.api.Printers]]
- * and their `showRaw` method. Refer to the page linked above for a series of detailed
- * examples.
- *
- * {{{
- * 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
- *
- * // show displays prettified representation of reflection artifacts
- * // which is typically close to Scala code, but sometimes not quite
- * // (e.g. here the constructor is shown in a desugared way)
- * scala> show(tree)
- * res0: String =
- * {
- * final class C extends AnyRef {
- * def <init>() = {
- * super.<init>();
- * ()
- * };
- * def x = 2
- * };
- * ()
- * }
- *
- * // showRaw displays internal structure of a given reflection object
- * // trees and types (type examples are shown below) are case classes
- * // so they are shown in a form that's almost copy/pasteable
- * //
- * // almost copy/pasteable, but not completely - that's because of symbols
- * // there's no good way to get a roundtrip-surviving representation of symbols
- * // in general case, therefore only symbol names are shown (e.g. take a look at AnyRef)
- * //
- * // in such a representation, it's impossible to distinguish Idents/Selects
- * // that have underlying symbols vs ones that don't have symbols, because in both cases
- * // only names will be printed
- * //
- * // to overcome this limitation, use `printIds` and `printKinds` - optional parameters
- * // of the `showRaw` method (example is shown on the scala.reflect.api.Printers doc page)
- * scala> showRaw(tree)
- * res1: String = Block(List(
- * ClassDef(Modifiers(FINAL), newTypeName("C"), List(), Template(
- * List(Ident(newTypeName("AnyRef"))),
- * emptyValDef,
- * 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(), newTermName("x"), List(), List(), TypeTree(),
- * Literal(Constant(2))))))),
- * Literal(Constant(())))
- * }}}
+ * @see [[http://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html#trees]].
*/
trait Trees { self: Universe =>
@@ -260,6 +66,11 @@ trait Trees { self: Universe =>
*
* Upon creation most trees have their `tpe` set to `null`.
* Types are typically assigned to trees during typechecking.
+ * Some node factory methods set `tpe` immediately after creation.
+ *
+ * When the typechecker encounters a tree with a non-null tpe,
+ * it will assume it to be correct and not check it again. This means one has
+ * to be careful not to erase the `tpe` field of subtrees.
*/
def tpe: Type
@@ -1725,7 +1536,7 @@ trait Trees { self: Universe =>
val qual: TypeName
}
- /** Designator <qualifier> . <name> */
+ /** A member selection <qualifier> . <name> */
type Select >: Null <: RefTree with SelectApi
/** A tag that preserves the identity of the `Select` abstract type from erasure.
@@ -1755,7 +1566,8 @@ trait Trees { self: Universe =>
val name: Name
}
- /** Identifier <name> */
+ /** A reference to identifier `name`.
+ */
type Ident >: Null <: RefTree with IdentApi
/** A tag that preserves the identity of the `Ident` abstract type from erasure.