forked from scala/scala3
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement run/show for quoted expressions
- Loading branch information
1 parent
db47f14
commit 385a87f
Showing
27 changed files
with
401 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
compiler/src/dotty/tools/dotc/quoted/ExprCompilationUnit.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package dotty.tools.dotc.quoted | ||
|
||
import dotty.tools.dotc.CompilationUnit | ||
import dotty.tools.dotc.util.NoSource | ||
|
||
import scala.quoted.Expr | ||
|
||
/* Compilation unit containing the contents of a quoted expression */ | ||
class ExprCompilationUnit(val expr: Expr[_]) extends CompilationUnit(NoSource) { | ||
override def toString = s"Expr($expr)" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package dotty.tools.dotc | ||
package quoted | ||
|
||
import dotty.tools.backend.jvm.GenBCode | ||
import dotty.tools.dotc.core.Contexts.Context | ||
import dotty.tools.dotc.core.{Mode, Phases} | ||
import dotty.tools.dotc.core.Phases.Phase | ||
import dotty.tools.dotc.transform.Pickler | ||
import dotty.tools.io.VirtualDirectory | ||
|
||
/** Compiler that takes the contents of a quoted expression `expr` and produces | ||
* a class file with `class ' { def apply: Object = expr }`. | ||
*/ | ||
class ExprCompiler(directory: VirtualDirectory) extends Compiler { | ||
|
||
/** A GenBCode phase that outputs to a virtual directory */ | ||
private class ExprGenBCode extends GenBCode { | ||
override def phaseName = "genBCode" | ||
override def outputDir(implicit ctx: Context) = directory | ||
} | ||
|
||
override def phases: List[List[Phase]] = { | ||
val backendPhases = super.phases.dropWhile { | ||
case List(_: Pickler) => false | ||
case _ => true | ||
}.tail | ||
|
||
List(new ExprFrontend(putInClass = true)) :: | ||
Phases.replace(classOf[GenBCode], _ => new ExprGenBCode :: Nil, backendPhases) | ||
} | ||
|
||
override def newRun(implicit ctx: Context): ExprRun = { | ||
reset() | ||
new ExprRun(this, ctx.addMode(Mode.ReadPositions)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package dotty.tools.dotc.quoted | ||
|
||
import java.io.PrintStream | ||
|
||
import dotty.tools.dotc.core.Phases.Phase | ||
|
||
/** Compiler that takes the contents of a quoted expression `expr` and produces outputs | ||
* the pretty printed code. | ||
*/ | ||
class ExprDecompiler(out: PrintStream) extends ExprCompiler(null) { | ||
override def phases: List[List[Phase]] = List( | ||
List(new ExprFrontend(putInClass = false)), // Create class from Expr | ||
List(new QuotePrinter(out)) // Print all loaded classes | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package dotty.tools.dotc.quoted | ||
|
||
import dotty.tools.dotc.CompilationUnit | ||
import dotty.tools.dotc.ast.tpd | ||
import dotty.tools.dotc.core.Contexts.Context | ||
import dotty.tools.dotc.core.Flags._ | ||
import dotty.tools.dotc.core.Scopes._ | ||
import dotty.tools.dotc.core.StdNames._ | ||
import dotty.tools.dotc.core.Symbols._ | ||
import dotty.tools.dotc.core.Types._ | ||
import dotty.tools.dotc.core.quoted.PickledQuotes | ||
import dotty.tools.dotc.typer.FrontEnd | ||
import dotty.tools.dotc.util.Positions._ | ||
import dotty.tools.dotc.util.SourceFile | ||
import dotty.tools.io._ | ||
|
||
import scala.quoted.Expr | ||
|
||
/** Frontend that receives scala.quoted.Expr as input */ | ||
class ExprFrontend(putInClass: Boolean) extends FrontEnd { | ||
import tpd._ | ||
|
||
override def isTyper = false | ||
|
||
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { | ||
units.map { | ||
case exprUnit: ExprCompilationUnit => | ||
val tree = | ||
if (putInClass) inClass(exprUnit.expr) | ||
else PickledQuotes.quotedToTree(exprUnit.expr) | ||
val source = new SourceFile("", Seq()) | ||
CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true) | ||
} | ||
} | ||
|
||
/** Places the contents of expr in a compilable tree for a class | ||
* with the following format. | ||
* `package __root__ { class ' { def apply: Any = <expr> } }` | ||
*/ | ||
private def inClass(expr: Expr[_])(implicit ctx: Context): Tree = { | ||
val pos = Position(0) | ||
val assocFile = new PlainFile(Path("<quote>")) | ||
|
||
val cls = ctx.newCompleteClassSymbol(defn.RootClass, nme.QUOTE.toTypeName, EmptyFlags, | ||
defn.ObjectType :: Nil, newScope, coord = pos, assocFile = assocFile).entered.asClass | ||
cls.enter(ctx.newDefaultConstructor(cls), EmptyScope) | ||
val meth = ctx.newSymbol(cls, nme.apply, Method, ExprType(defn.AnyType), coord = pos).entered | ||
|
||
val quoted = PickledQuotes.quotedToTree(expr)(ctx.withOwner(meth)) | ||
|
||
val run = DefDef(meth, quoted) | ||
val classTree = ClassDef(cls, DefDef(cls.primaryConstructor.asTerm), run :: Nil) | ||
PackageDef(ref(defn.RootPackage).asInstanceOf[Ident], classTree :: Nil).withPos(pos) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package dotty.tools.dotc | ||
package quoted | ||
|
||
import dotty.tools.dotc.core.Contexts._ | ||
|
||
import scala.quoted._ | ||
|
||
class ExprRun(comp: Compiler, ictx: Context) extends Run(comp, ictx) { | ||
def compileExpr(expr: Expr[_]): Unit = { | ||
val units = new ExprCompilationUnit(expr) :: Nil | ||
compileUnits(units) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package dotty.tools.dotc.quoted | ||
|
||
import dotty.tools.dotc.Driver | ||
import dotty.tools.dotc.core.Contexts.Context | ||
import dotty.tools.dotc.core.StdNames._ | ||
import dotty.tools.io.VirtualDirectory | ||
|
||
import dotty.tools.repl.AbstractFileClassLoader | ||
|
||
import scala.quoted.Expr | ||
|
||
import java.io.ByteArrayOutputStream | ||
import java.io.PrintStream | ||
import java.nio.charset.StandardCharsets | ||
|
||
class QuoteDriver extends Driver { | ||
|
||
def run[T](expr: Expr[T]): T = { | ||
val ctx: Context = initCtx.fresh | ||
// TODO enable optimisation? | ||
// ctx.settings.optimise.update(true)(ctx) | ||
|
||
val outDir = new VirtualDirectory("(memory)", None) | ||
|
||
new ExprCompiler(outDir).newRun(ctx).compileExpr(expr) | ||
|
||
val classLoader = new AbstractFileClassLoader(outDir, this.getClass.getClassLoader) | ||
|
||
val clazz = classLoader.loadClass(nme.QUOTE.toString) | ||
val method = clazz.getMethod("apply") | ||
val instance = clazz.newInstance() | ||
|
||
method.invoke(instance).asInstanceOf[T] | ||
} | ||
|
||
def show(expr: Expr[_]): String = { | ||
val ctx: Context = initCtx.fresh | ||
ctx.settings.color.update("never")(ctx) // TODO support colored show | ||
val baos = new ByteArrayOutputStream | ||
var ps: PrintStream = null | ||
try { | ||
ps = new PrintStream(baos, true, "utf-8") | ||
|
||
new ExprDecompiler(ps).newRun(ctx).compileExpr(expr) | ||
|
||
new String(baos.toByteArray, StandardCharsets.UTF_8) | ||
} | ||
finally if (ps != null) ps.close() | ||
} | ||
|
||
override def initCtx: Context = { | ||
val ictx = super.initCtx.fresh | ||
val compilerClasspath = System.getProperty("dotty.tools.dotc.classpath") | ||
assert(compilerClasspath ne null, "System property `dotty.tools.dotc.classpath` is not set.") | ||
val classpath = System.getProperty("java.class.path") | ||
val scalaLib = classpath.split(":").filter(_.contains("scala-library")).mkString(":") | ||
ictx.settings.classpath.update(compilerClasspath + ":" + scalaLib)(ictx) | ||
ictx | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package dotty.tools.dotc.quoted | ||
|
||
import java.io.PrintStream | ||
|
||
import dotty.tools.dotc.core.Contexts._ | ||
import dotty.tools.dotc.core.Phases.Phase | ||
|
||
/** Pretty prints the compilation unit to an output stream */ | ||
class QuotePrinter(out: PrintStream) extends Phase { | ||
|
||
override def phaseName: String = "quotePrinter" | ||
|
||
override def run(implicit ctx: Context): Unit = { | ||
val unit = ctx.compilationUnit | ||
out.print(unit.tpdTree.show) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package dotty.tools.dotc.quoted | ||
|
||
import scala.quoted.Expr | ||
import scala.runtime.quoted._ | ||
|
||
/** Default runners for quoted expressions */ | ||
object Runners { | ||
implicit def runner[T]: Runner[T] = (expr: Expr[T]) => new QuoteDriver().run(expr) | ||
implicit def show[T]: Show[T] = (expr: Expr[T]) => new QuoteDriver().show(expr) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package scala.runtime.quoted | ||
|
||
import scala.annotation.implicitNotFound | ||
import scala.quoted.Expr | ||
|
||
@implicitNotFound("Could not find implicit Runner. Default runner can must be imported with `import dotty.tools.dotc.quoted.Runners._`") | ||
trait Runner[T] { | ||
def run(expr: Expr[T]): T | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package scala.runtime.quoted | ||
|
||
import scala.annotation.implicitNotFound | ||
import scala.quoted.Expr | ||
|
||
@implicitNotFound("Could not find implicit Show. Default runner can must be imported with `import dotty.tools.dotc.quoted.Runners._`") | ||
trait Show[T] { | ||
def run(expr: Expr[T]): String | ||
} |
Oops, something went wrong.