Skip to content

Commit

Permalink
Use indentation syntax in Staging/Inspector internals
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Mar 13, 2020
1 parent b64b8a9 commit 34fb2fa
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 76 deletions.
40 changes: 20 additions & 20 deletions staging/src/scala/quoted/staging/QuoteCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import scala.quoted.{Expr, QuoteContext, Type}
/** Compiler that takes the contents of a quoted expression `expr` and produces
* a class file with `class ' { def apply: Object = expr }`.
*/
private class QuoteCompiler extends Compiler {
private class QuoteCompiler extends Compiler:

/** Either `Left` with name of the classfile generated or `Right` with the value contained in the expression */
private[this] var result: Either[String, Any] = null
Expand All @@ -40,15 +40,14 @@ private class QuoteCompiler extends Compiler {
override protected def picklerPhases: List[List[Phase]] =
List(List(new ReifyQuotes))

override def newRun(implicit ctx: Context): ExprRun = {
override def newRun(implicit ctx: Context): ExprRun =
reset()
new ExprRun(this, ctx.addMode(Mode.ReadPositions))
}

def outputClassName: TypeName = "Generated$Code$From$Quoted".toTypeName

/** Frontend that receives a scala.quoted.Expr or scala.quoted.Type as input */
class QuotedFrontend extends Phase {
class QuotedFrontend extends Phase:
import tpd._

def phaseName: String = "quotedFrontend"
Expand All @@ -68,14 +67,14 @@ private class QuoteCompiler extends Compiler {
cls.enter(unitCtx.newDefaultConstructor(cls), EmptyScope)
val meth = unitCtx.newSymbol(cls, nme.apply, Method, ExprType(defn.AnyType), coord = pos).entered

val quoted = {
val quoted =
given Context = unitCtx.withOwner(meth)
val qctx = dotty.tools.dotc.quoted.QuoteContext()
val quoted = PickledQuotes.quotedExprToTree(exprUnit.exprBuilder.apply(qctx))
checkEscapedVariables(quoted, meth)
}
end quoted

getLiteral(quoted) match {
getLiteral(quoted) match
case Some(value) =>
result = Right(value)
None // Stop copilation here we already have the result
Expand All @@ -86,28 +85,29 @@ private class QuoteCompiler extends Compiler {
val source = SourceFile.virtual("<quoted.Expr>", "")
result = Left(outputClassName.toString)
Some(CompilationUnit(source, tree, forceTrees = true))
}
}

/** Get the literal value if this tree only contains a literal tree */
@tailrec private def getLiteral(tree: Tree): Option[Any] = tree match {
case Literal(lit) => Some(lit.value)
case Block(Nil, expr) => getLiteral(expr)
case Inlined(_, Nil, expr) => getLiteral(expr)
case _ => None
}
@tailrec private def getLiteral(tree: Tree): Option[Any] =
tree match
case Literal(lit) => Some(lit.value)
case Block(Nil, expr) => getLiteral(expr)
case Inlined(_, Nil, expr) => getLiteral(expr)
case _ => None

def run(implicit ctx: Context): Unit = unsupported("run")
}

class ExprRun(comp: QuoteCompiler, ictx: Context) extends Run(comp, ictx) {
end QuotedFrontend

class ExprRun(comp: QuoteCompiler, ictx: Context) extends Run(comp, ictx):
/** Unpickle and optionally compile the expression.
* Returns either `Left` with name of the classfile generated or `Right` with the value contained in the expression.
*/
def compileExpr(exprBuilder: QuoteContext => Expr[_]): Either[String, Any] = {
def compileExpr(exprBuilder: QuoteContext => Expr[_]): Either[String, Any] =
val units = new ExprCompilationUnit(exprBuilder) :: Nil
compileUnits(units)
result
}
}
}

end ExprRun

end QuoteCompiler
37 changes: 18 additions & 19 deletions staging/src/scala/quoted/staging/QuoteDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,26 @@ import scala.annotation.tailrec
*
* @param appClassloader classloader of the application that generated the quotes
*/
private class QuoteDriver(appClassloader: ClassLoader) extends Driver {
private class QuoteDriver(appClassloader: ClassLoader) extends Driver:
import tpd._

private[this] val contextBase: ContextBase = new ContextBase

def run[T](exprBuilder: QuoteContext => Expr[T], settings: Toolbox.Settings): T = {
val outDir: AbstractFile = settings.outDir match {
case Some(out) =>
val dir = Directory(out)
dir.createDirectory()
new PlainDirectory(Directory(out))
case None =>
new VirtualDirectory("<quote compilation output>")
}
def run[T](exprBuilder: QuoteContext => Expr[T], settings: Toolbox.Settings): T =
val outDir: AbstractFile =
settings.outDir match
case Some(out) =>
val dir = Directory(out)
dir.createDirectory()
new PlainDirectory(Directory(out))
case None =>
new VirtualDirectory("<quote compilation output>")
end outDir

val (_, ctx0: Context) = setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh)
val ctx = setToolboxSettings(ctx0.fresh.setSetting(ctx0.settings.outputDir, outDir), settings)

new QuoteCompiler().newRun(ctx).compileExpr(exprBuilder) match {
new QuoteCompiler().newRun(ctx).compileExpr(exprBuilder) match
case Right(value) =>
value.asInstanceOf[T]

Expand All @@ -50,21 +51,19 @@ private class QuoteDriver(appClassloader: ClassLoader) extends Driver {
val inst = clazz.getConstructor().newInstance()

method.invoke(inst).asInstanceOf[T]
}
}
end match

override def initCtx: Context = {
end run

override def initCtx: Context =
val ictx = contextBase.initialCtx
ictx.settings.classpath.update(ClasspathFromClassloader(appClassloader))(ictx)
ictx
}

private def setToolboxSettings(ctx: FreshContext, settings: Toolbox.Settings): ctx.type = {
private def setToolboxSettings(ctx: FreshContext, settings: Toolbox.Settings): ctx.type =
ctx.setSetting(ctx.settings.YshowRawQuoteTrees, settings.showRawTree)
// An error in the generated code is a bug in the compiler
// Setting the throwing reporter however will report any exception
ctx.setReporter(new ThrowingReporter(ctx.reporter))
}

}

end QuoteDriver
40 changes: 21 additions & 19 deletions staging/src/scala/quoted/staging/Toolbox.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ package staging
import scala.annotation.implicitNotFound

@implicitNotFound("Could not find implicit scala.quoted.staging.Toolbox.\n\nDefault toolbox can be instantiated with:\n `given scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader)`\n\n")
trait Toolbox {
trait Toolbox:
def run[T](expr: QuoteContext => Expr[T]): T
}

object Toolbox {
object Toolbox:

/** Create a new instance of the toolbox using the the classloader of the application.
*
Expand All @@ -22,28 +21,30 @@ object Toolbox {
* @param settings toolbox settings
* @return A new instance of the toolbox
*/
def make(appClassloader: ClassLoader)(implicit settings: Settings): Toolbox = new Toolbox {
def make(appClassloader: ClassLoader)(implicit settings: Settings): Toolbox =
new Toolbox:

private[this] val driver: QuoteDriver = new QuoteDriver(appClassloader)
private[this] val driver: QuoteDriver = new QuoteDriver(appClassloader)

private[this] var running = false
private[this] var running = false

def run[T](exprBuilder: QuoteContext => Expr[T]): T = synchronized {
try {
if (running) // detected nested run
throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`")
running = true
driver.run(exprBuilder, settings)
} finally {
running = false
def run[T](exprBuilder: QuoteContext => Expr[T]): T = synchronized {
try
if (running) // detected nested run
throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`")
running = true
driver.run(exprBuilder, settings)
finally
running = false
end try
}
}
}

end new

/** Setting of the Toolbox instance. */
case class Settings private (outDir: Option[String], showRawTree: Boolean, compilerArgs: List[String])

object Settings {
object Settings:

implicit def default: Settings = make()

Expand All @@ -58,6 +59,7 @@ object Toolbox {
compilerArgs: List[String] = Nil
): Settings =
new Settings(outDir, showRawTree, compilerArgs)
}

}
end Settings

end Toolbox
8 changes: 4 additions & 4 deletions staging/src/scala/quoted/staging/staging.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package scala.quoted

package object staging {
package object staging:

/** Evaluate the contents of this expression and return the result.
* It provides a new QuoteContext that is only valid within the scope the argument.
Expand Down Expand Up @@ -32,7 +32,7 @@ package object staging {
* This method should not be called in a context where there is already has a `QuoteContext`
* such as within a `run` or a `withQuoteContext`.
*/
def withQuoteContext[T](thunk: QuoteContext ?=> T)(using toolbox: Toolbox): T = {
def withQuoteContext[T](thunk: QuoteContext ?=> T)(using toolbox: Toolbox): T =
val noResult = new Object
var result: T = noResult.asInstanceOf[T]
def dummyRun(using QuoteContext): Expr[Unit] = {
Expand All @@ -42,6 +42,6 @@ package object staging {
toolbox.run(dummyRun(using _))
assert(result != noResult) // toolbox.run should have thrown an exception
result
}
end withQuoteContext

}
end staging
32 changes: 18 additions & 14 deletions tasty-inspector/src/scala/tasty/inspector/TastyInspector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import dotty.tools.dotc.util.ClasspathFromClassloader

import java.io.File.pathSeparator

trait TastyInspector { self =>
trait TastyInspector:
self =>

/** Process a TASTy file using TASTy reflect */
protected def processCompilationUnit(reflect: Reflection)(root: reflect.Tree): Unit
Expand All @@ -24,44 +25,47 @@ trait TastyInspector { self =>
* @param classpath Classpath where the classes are located
* @param classes classes to be inspected
*/
def inspect(classpath: String, classes: List[String]): Unit = {
def inspect(classpath: String, classes: List[String]): Unit =
if (classes.isEmpty)
throw new IllegalArgumentException("Parameter classes should no be empty")

class InspectorDriver extends Driver {
class InspectorDriver extends Driver:
override protected def newCompiler(implicit ctx: Context): Compiler = new TastyFromClass
}

class TastyFromClass extends TASTYCompiler {
class TastyFromClass extends TASTYCompiler:

override protected def frontendPhases: List[List[Phase]] =
List(new ReadTasty) :: // Load classes from tasty
Nil

override protected def picklerPhases: List[List[Phase]] = Nil

override protected def transformPhases: List[List[Phase]] = Nil

override protected def backendPhases: List[List[Phase]] =
List(new TastyInspectorPhase) :: // Print all loaded classes
Nil

override def newRun(implicit ctx: Context): Run = {
override def newRun(implicit ctx: Context): Run =
reset()
new TASTYRun(this, ctx.fresh.addMode(Mode.ReadPositions).addMode(Mode.ReadComments))
}
}

class TastyInspectorPhase extends Phase {
end TastyFromClass

class TastyInspectorPhase extends Phase:

override def phaseName: String = "tastyInspector"

override def run(implicit ctx: Context): Unit = {
override def run(implicit ctx: Context): Unit =
val reflect = ReflectionImpl(ctx)
self.processCompilationUnit(reflect)(ctx.compilationUnit.tpdTree.asInstanceOf[reflect.Tree])
}
}

end TastyInspectorPhase

val currentClasspath = ClasspathFromClassloader(getClass.getClassLoader)
val args = "-from-tasty" :: "-Yretain-trees" :: "-classpath" :: s"$classpath$pathSeparator$currentClasspath" :: classes
(new InspectorDriver).process(args.toArray)
}
end inspect


}
end TastyInspector

0 comments on commit 34fb2fa

Please sign in to comment.