Skip to content

Commit

Permalink
Add an interface for Tasty loaded in the inspector
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Jan 21, 2021
1 parent 854d5ef commit e190f91
Show file tree
Hide file tree
Showing 16 changed files with 69 additions and 45 deletions.
14 changes: 9 additions & 5 deletions docs/docs/reference/metaprogramming/tasty-inspect.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ libraryDependencies += "org.scala-lang" %% "scala3-tasty-inspector" % scalaVersi
TASTy files contain the full typed tree of a class including source positions
and documentation. This is ideal for tools that analyze or extract semantic
information from the code. To avoid the hassle of working directly with the TASTy
file we provide the `TastyInspector` which loads the contents and exposes it
file we provide the `Inspector` which loads the contents and exposes it
through the TASTy reflect API.

## Inspecting TASTy files
Expand All @@ -21,18 +21,22 @@ To inspect the trees of a TASTy file a consumer can be defined in the following
import scala.quoted._
import scala.tasty.inspector._

class MyInspector extends TastyInspector with
protected def processCompilationUnit(using Quotes)(tree: quotes.reflect.Tree): Unit =
class MyInspector extends Inspector with
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit =
import quotes.reflect._
// Do something with the tree
for tasty <- tastys do
val tree = tasty.ast
// Do something with the tree
```

Then the consumer can be instantiated with the following code to get the tree of the `foo/Bar.tasty` file.

```scala
object Test with
def main(args: Array[String]): Unit =
new MyInspector().inspectTastyFiles("foo/Bar.tasty")
val tastyFiles = List("foo/Bar.tasty")
TastyInspector.inspectTastyFiles(tastyFiles)(new MyInspector)

```

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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import java.nio.file.{Path, Files, Paths, FileSystems}
object Main extends App {

val inspector = new Inspector {
def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit = {
for (_, tree) <- tastys do
val tastyStr = tree.show
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
for tasty <- tastys do
val tastyStr = tasty.ast.show
println(tastyStr)

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ object BootstrappedStdLibTASYyTest with

def loadWithTastyInspector(blacklisted: Set[String]): Unit =
val inspector = new scala.tasty.inspector.Inspector {
def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit =
for (_, tree) <- tastys do
tree.show(using quotes.reflect.Printer.TreeStructure) // Check that we can traverse the full tree
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit =
for tasty <- tastys do
tasty.ast.show(using quotes.reflect.Printer.TreeStructure) // Check that we can traverse the full tree
()
}
val tastyFiles = scalaLibTastyPaths.filterNot(blacklisted)
Expand Down
4 changes: 2 additions & 2 deletions tasty-inspector/src/scala/tasty/inspector/Inspector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ trait Inspector:
*
* Note: Within this method `quotes.reflect.SourceFile.current` will not work, hence the explicit source paths.
*
* @param tastys List of tuples containing the path of the `.tasty` and the AST within the file.
* @param tastys List of `Tasty` containing `.tasty`file path and AST
*/
def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit

end Inspector
17 changes: 17 additions & 0 deletions tasty-inspector/src/scala/tasty/inspector/Tasty.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package scala.tasty.inspector

import scala.quoted._

/** `.tasty` file representation containing file path and the AST */
trait Tasty[Q <: Quotes & Singleton]:

/** Instance of `Quotes` used to load the AST */
val quotes: Q

/** Path to the `.tasty` file */
def path: String

/** Abstract Syntax Tree contained in the `.tasty` file */
def ast: quotes.reflect.Tree

end Tasty
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ object TastyInspector:

override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
val quotesImpl = QuotesImpl()
val tastys = units.map(unit => (unit.source.path , unit.tpdTree.asInstanceOf[quotesImpl.reflect.Tree]))
class TastyImpl(val path: String, val ast: quotesImpl.reflect.Tree) extends Tasty[quotesImpl.type] {
val quotes = quotesImpl
}
val tastys = units.map(unit => new TastyImpl(unit.source.path , unit.tpdTree.asInstanceOf[quotesImpl.reflect.Tree]))
inspector.inspect(using quotesImpl)(tastys)
units

Expand Down
8 changes: 4 additions & 4 deletions tests/run-custom-args/tasty-inspector/i10359.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ object Test {

class TestInspector() extends Inspector with

def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit =
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit =
import quotes.reflect._

for (_, root) <- tastys do
val code = root.show
for tasty <- tastys do
val code = tasty.ast.show
assert(code.contains("import Foo.this.g.{given}"), code)
assert(code.contains("import Foo.this.g.{given scala.Int}"), code)

val extractors = root.show(using Printer.TreeStructure)
val extractors = tasty.ast.show(using Printer.TreeStructure)
assert(extractors.contains("GivenSelector"), extractors)
6 changes: 3 additions & 3 deletions tests/run-custom-args/tasty-inspector/i8163.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ object Test {

class TestInspector() extends Inspector with

def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit =
for (_, tree) <- tastys do
inspectClass(tree)
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit =
for tasty <- tastys do
inspectClass(tasty.ast)

private def inspectClass(using Quotes)(tree: quotes.reflect.Tree): Unit =
import quotes.reflect._
Expand Down
6 changes: 3 additions & 3 deletions tests/run-custom-args/tasty-inspector/i8364.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import scala.tasty.inspector._

@main def Test = {
val inspector = new Inspector {
def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit = {
for (_, tree) <- tastys do
tree.show(using quotes.reflect.Printer.TreeStructure) // Make sure that tree is loaded and can be traveresed
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
for tasty <- tastys do
tasty.ast.show(using quotes.reflect.Printer.TreeStructure) // Make sure that tree is loaded and can be traveresed
}
}

Expand Down
6 changes: 3 additions & 3 deletions tests/run-custom-args/tasty-inspector/i8389.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import scala.tasty.inspector._

// in dotty-example-project
val inspector = new Inspector {
def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit = {
for (_, tree) <- tastys do
println(tree.show)
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
for tasty <- tastys do
println(tasty.ast.show)
}
}
TastyInspector.inspectTastyFiles(tastyFiles)(inspector)
Expand Down
6 changes: 3 additions & 3 deletions tests/run-custom-args/tasty-inspector/i8460.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ class TestInspector_Children() extends Inspector with

var kids: List[String] = Nil

def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit = {
for (_, tree) <- tastys do
inspectClass(tree)
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
for tasty <- tastys do
inspectClass(tasty.ast)
}

private def inspectClass(using Quotes)(tree: quotes.reflect.Tree): Unit =
Expand Down
6 changes: 3 additions & 3 deletions tests/run-custom-args/tasty-inspector/i9970.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ object Test {

class TestInspector() extends Inspector with

def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit =
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit =
var foundIOApp: Boolean = false
var foundSimple: Boolean = false

Expand Down Expand Up @@ -80,10 +80,10 @@ class TestInspector() extends Inspector with

case _ =>

for (_, tree) <- tastys do
for tasty <- tastys do
foundIOApp = false
foundSimple = false
inspectClass(tree)
inspectClass(tasty.ast)
// Sanity check to make sure that our pattern matches are not simply glossing over the things we want to test
assert(foundIOApp, "the inspector did not encounter IOApp")
assert(foundSimple, "the inspect did not encounter IOApp.Simple")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object Test {

class DocumentationInspector extends Inspector {

def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit = {
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {

import quotes.reflect._
object Traverser extends TreeTraverser {
Expand All @@ -32,8 +32,8 @@ class DocumentationInspector extends Inspector {
}

}
for (_, tree) <- tastys do
Traverser.traverseTree(tree)
for tasty <- tastys do
Traverser.traverseTree(tasty.ast)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object Test {

class DBInspector extends Inspector {

def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit = {
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
import quotes.reflect._
object Traverser extends TreeTraverser {

Expand All @@ -28,8 +28,8 @@ class DBInspector extends Inspector {
}

}
for (_, tree) <- tastys do
Traverser.traverseTree(tree)
for tasty <- tastys do
Traverser.traverseTree(tasty.ast)
}

}
4 changes: 2 additions & 2 deletions tests/run-custom-args/tasty-inspector/tastyPaths.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ object Test {

class TestInspector() extends Inspector:

def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit =
println(tastys.map(_._1.split("/tasty-inspector/").last))
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit =
println(tastys.map(_.path.split("/tasty-inspector/").last))
try
quotes.reflect.SourceFile.current
assert(false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package scala.tasty.interpreter

import scala.quoted._
import scala.tasty.inspector.Inspector
import scala.tasty.inspector._

class TastyInterpreter extends Inspector {

def inspect(using Quotes)(tastys: List[(String, quotes.reflect.Tree)]): Unit = {
def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
import quotes.reflect._

object Traverser extends TreeTraverser {
Expand All @@ -21,8 +21,8 @@ class TastyInterpreter extends Inspector {
}
}

for (_, tree) <- tastys do
Traverser.traverseTree(tree)(Symbol.spliceOwner)
for tasty <- tastys do
Traverser.traverseTree(tasty.ast)(Symbol.spliceOwner)
}

}

0 comments on commit e190f91

Please sign in to comment.