From a6fedfabc32bd92669490750535d2614037d6189 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 8 Jan 2021 09:49:13 +0100 Subject: [PATCH] Update metaprogramming docs --- ...2019-01-21-12th-dotty-milestone-release.md | 2 +- .../docs/reference/dropped-features/macros.md | 4 +- .../{tasty-reflect.md => reflection.md} | 53 +++++++++---------- .../docs/reference/metaprogramming/staging.md | 2 +- .../metaprogramming/tasty-inspect.md | 25 ++++----- docs/docs/reference/metaprogramming/toc.md | 4 +- docs/sidebar.yml | 6 +-- 7 files changed, 45 insertions(+), 51 deletions(-) rename docs/docs/reference/metaprogramming/{tasty-reflect.md => reflection.md} (71%) diff --git a/docs/blog/_posts/2019-01-21-12th-dotty-milestone-release.md b/docs/blog/_posts/2019-01-21-12th-dotty-milestone-release.md index e5e9ec8652c0..15d689730b90 100644 --- a/docs/blog/_posts/2019-01-21-12th-dotty-milestone-release.md +++ b/docs/blog/_posts/2019-01-21-12th-dotty-milestone-release.md @@ -92,7 +92,7 @@ We also connect the new lower-level reflection layer to the existing principled - `unseal` that unseals an `Expr[T]` (non traversable code) into a `Term` and - `seal` that seals back a `Term` into an `Expr[T]`. -Read the [relevant documentation](https://dotty.epfl.ch/docs/reference/metaprogramming/tasty-reflect.html) to learn how to go from quotes and splices to TASTys Reflect trees and back . +Read the [relevant documentation](https://dotty.epfl.ch/docs/reference/metaprogramming/reflection.html) to learn how to go from quotes and splices to TASTys Reflect trees and back . ### Alignments with the Scala Improvement Process diff --git a/docs/docs/reference/dropped-features/macros.md b/docs/docs/reference/dropped-features/macros.md index ca8d2adfb345..c8070ffda6db 100644 --- a/docs/docs/reference/dropped-features/macros.md +++ b/docs/docs/reference/dropped-features/macros.md @@ -8,8 +8,8 @@ The previous, experimental macro system has been dropped. Instead, there is a cleaner, more restricted system based on two complementary concepts: `inline` and `'{ ... }`/`${ ... }` code generation. `'{ ... }` delays the compilation of the code and produces an object containing the code, dually `${ ... }` evaluates an expression which produces code and inserts it in the surrounding `${ ... }`. In this setting, a definition marked as inlined containing a `${ ... }` is a macro, the code inside the `${ ... }` is executed at compile-time and produces code in the form of `'{ ... }`. -Additionally, the contents of code can be inspected and created with a more complex reflection API (TASTy Reflect) as an extension of `'{ ... }`/`${ ... }` framework. +Additionally, the contents of code can be inspected and created with a more complex reflection API as an extension of `'{ ... }`/`${ ... }` framework. * `inline` has been [implemented](../metaprogramming/inline.md) in Scala 3. * Quotes `'{ ... }` and splices `${ ... }` has been [implemented](../metaprogramming/macros.md) in Scala 3. -* [TASTy reflect](../metaprogramming/tasty-reflect.md) provides more complex tree based APIs to inspect or create quoted code. +* [TASTy reflect](../metaprogramming/reflection.md) provides more complex tree based APIs to inspect or create quoted code. diff --git a/docs/docs/reference/metaprogramming/tasty-reflect.md b/docs/docs/reference/metaprogramming/reflection.md similarity index 71% rename from docs/docs/reference/metaprogramming/tasty-reflect.md rename to docs/docs/reference/metaprogramming/reflection.md index 2fa6f3e213dc..0855e4230432 100644 --- a/docs/docs/reference/metaprogramming/tasty-reflect.md +++ b/docs/docs/reference/metaprogramming/reflection.md @@ -1,20 +1,20 @@ --- layout: doc-page -title: "TASTy Reflect" +title: "Reflection" --- -TASTy Reflect enables inspection and construction of Typed Abstract Syntax Trees +Reflection enables inspection and construction of Typed Abstract Syntax Trees (Typed-AST). It may be used on quoted expressions (`quoted.Expr`) and quoted types (`quoted.Type`) from [Macros](./macros.md) or on full TASTy files. If you are writing macros, please first read [Macros](./macros.md). -You may find all you need without using TASTy Reflect. +You may find all you need without using quote reflection. ## API: From quotes and splices to TASTy reflect trees and back With `quoted.Expr` and `quoted.Type` we can compute code but also analyze code by inspecting the ASTs. [Macros](./macros.md) provide the guarantee that the -generation of code will be type-correct. Using TASTy Reflect will break these +generation of code will be type-correct. Using quote reflection will break these guarantees and may fail at macro expansion time, hence additional explicit checks must be done. @@ -34,20 +34,20 @@ def natConstImpl(x: Expr[Int])(using Quotes): Expr[Int] = ### Extractors -`import quotes.reflect._` will provide all extractors and methods on TASTy -Reflect trees. For example the `Literal(_)` extractor used below. +`import quotes.reflect._` will provide all extractors and methods on `quotes.reflect.Tree`s. +For example the `Literal(_)` extractor used below. ```scala def natConstImpl(x: Expr[Int])(using Quotes): Expr[Int] = import quotes.reflect._ - val xTree: Term = x.asTerm - xTree match + val tree: Term = x.asTerm + tree match case Inlined(_, _, Literal(IntConstant(n))) => if n <= 0 then report.error("Parameter must be natural number") '{0} else - xTree.asExprOf[Int] + tree.asExprOf[Int] case _ => report.error("Parameter must be a known constant") '{0} @@ -58,9 +58,9 @@ which returns the string representation the structure of the tree. Other printer can also be found in the `Printer` module. ```scala -xTree.show(using Printer.TreeStructure) +tree.show(using Printer.TreeStructure) // or -Printer.TreeStructure.show(xTree) +Printer.TreeStructure.show(tree) ``` The methods `quotes.reflect.Term.{asExpr, asExprOf}` provide a way to go back to @@ -94,40 +94,37 @@ def macroImpl()(quotes: Quotes): Expr[Unit] = ### Tree Utilities -`scala.tasty.reflect` contains three facilities for tree traversal and +`quotes.reflect` contains three facilities for tree traversal and transformation. -`TreeAccumulator` ties the knot of a traversal. By calling `foldOver(x, tree))` +`TreeAccumulator` ties the knot of a traversal. By calling `foldOver(x, tree)(owner)` we can dive into the `tree` node and start accumulating values of type `X` (e.g., of type `List[Symbol]` if we want to collect symbols). The code below, for -example, collects the pattern variables of a tree. +example, collects the `val` definitions in the tree. ```scala def collectPatternVariables(tree: Tree)(using ctx: Context): List[Symbol] = val acc = new TreeAccumulator[List[Symbol]]: - def apply(syms: List[Symbol], tree: Tree)(using ctx: Context): List[Symbol] = tree match - case Bind(_, body) => apply(tree.symbol :: syms, body) - case _ => foldOver(syms, tree) + def foldTree(syms: List[Symbol], tree: Tree)(owner: Symbol): List[Symbol] = tree match + case ValDef(_, _, rhs) => + val newSyms = tree.symbol :: syms + foldTree(newSyms, body)(tree.symbol) + case _ => + foldOverTree(syms, tree)(owner) acc(Nil, tree) ``` A `TreeTraverser` extends a `TreeAccumulator` and performs the same traversal -but without returning any value. Finally a `TreeMap` performs a transformation. +but without returning any value. Finally, a `TreeMap` performs a transformation. -#### Let +#### ValDef.let -`scala.tasty.Reflection` also offers a method `let` that allows us to bind the -`rhs` (right-hand side) to a `val` and use it in `body`. Additionally, `lets` -binds the given `terms` to names and allows to use them in the `body`. Their type -definitions are shown below: +`quotes.reflect.ValDef` also offers a method `let` that allows us to bind the `rhs` (right-hand side) to a `val` and use it in `body`. +Additionally, `lets` binds the given `terms` to names and allows to use them in the `body`. +Their type definitions are shown below: ```scala def let(rhs: Term)(body: Ident => Term): Term = ... def lets(terms: List[Term])(body: List[Term] => Term): Term = ... ``` - -## More Examples - -* Start experimenting with TASTy Reflect ([link](https://github.com/nicolasstucki/tasty-reflection-exercise)) - (outdated, need update) diff --git a/docs/docs/reference/metaprogramming/staging.md b/docs/docs/reference/metaprogramming/staging.md index af657f7e0e7a..bb71c7a2550a 100644 --- a/docs/docs/reference/metaprogramming/staging.md +++ b/docs/docs/reference/metaprogramming/staging.md @@ -1,6 +1,6 @@ --- layout: doc-page -title: "Multi-Stage Programming" +title: "Runtime Multi-Stage Programming" --- The framework expresses at the same time compile-time metaprogramming and diff --git a/docs/docs/reference/metaprogramming/tasty-inspect.md b/docs/docs/reference/metaprogramming/tasty-inspect.md index 72c85f784186..9b86a8650475 100644 --- a/docs/docs/reference/metaprogramming/tasty-inspect.md +++ b/docs/docs/reference/metaprogramming/tasty-inspect.md @@ -15,30 +15,27 @@ through the TASTy reflect API. ## Inspecting TASTy files -To inspect the TASTy Reflect trees of a TASTy file a consumer can be defined in -the following way. +To inspect the trees of a TASTy file a consumer can be defined in the following way. ```scala -import scala.tasty.Reflection -import scala.tasty.file._ +import scala.quoted._ +import scala.tasty.inspector._ -class Consumer extends TastyInspector: - final def apply(reflect: Reflection)(root: reflect.Tree): Unit = - import reflect._ - // Do something with the tree +class MyInspector extends TastyInspector: + protected def processCompilationUnit(using Quotes)(tree: quotes.reflect.Tree): Unit = + import quotes.reflect._ + // Do something with the tree ``` -Then the consumer can be instantiated with the following code to get the tree of -the class `foo.Bar` for a foo in the classpath. +Then the consumer can be instantiated with the following code to get the tree of the `foo/Bar.tasty` file. ```scala object Test: - def main(args: Array[String]): Unit = - InspectTasty("", List("foo.Bar"), new Consumer) + def main(args: Array[String]): Unit = + new MyInspector().inspectTastyFiles("foo/Bar.tasty") ``` -Note that if we need to run the main (in the example below defined in an object called `Test`) after -compilation we need to make the compiler available to the runtime: +Note that if we need to run the main (in the example below defined in an object called `Test`) after compilation we need to make the compiler available to the runtime: ```shell scalac -d out Test.scala diff --git a/docs/docs/reference/metaprogramming/toc.md b/docs/docs/reference/metaprogramming/toc.md index 81722aa96b79..9d1e0b2a0405 100644 --- a/docs/docs/reference/metaprogramming/toc.md +++ b/docs/docs/reference/metaprogramming/toc.md @@ -25,13 +25,13 @@ introduce the following fundamental facilities: to program code. Together with `inline`, these two abstractions allow to construct program code programmatically. -3. [Staging](./staging.md) Where macros construct code at _compile-time_, +3. [Runtime Staging](./staging.md) Where macros construct code at _compile-time_, staging lets programs construct new code at _runtime_. That way, code generation can depend not only on static data but also on data available at runtime. This splits the evaluation of the program in two or more phases or ... stages. Consequently, this method of generative programming is called "Multi-Stage Programming". Staging is built on the same foundations as macros. It uses quotes and splices, but leaves out `inline`. -4. [TASTy Reflection](./tasty-reflect.md) Quotations are a "black-box" +4. [Reflection](./reflection.md) Quotations are a "black-box" representation of code. They can be parameterized and composed using splices, but their structure cannot be analyzed from the outside. TASTy reflection gives a way to analyze code structure by partly revealing the representation type of a piece of code in a standard API. The representation diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 4cde10a1b4ed..eac1368cfdd4 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -81,10 +81,10 @@ sidebar: url: docs/reference/metaprogramming/inline.html - title: Macros url: docs/reference/metaprogramming/macros.html - - title: Staging + - title: Runtime Staging url: docs/reference/metaprogramming/staging.html - - title: TASTy Reflection - url: docs/reference/metaprogramming/tasty-reflect.html + - title: Reflection + url: docs/reference/metaprogramming/reflection.html - title: TASTy Inspection url: docs/reference/metaprogramming/tasty-inspect.html - title: Other New Features