Skip to content

Commit f04dae7

Browse files
committed
Add deconstructor for quotes containing constants
1 parent b8116bb commit f04dae7

File tree

11 files changed

+78
-37
lines changed

11 files changed

+78
-37
lines changed
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package dotty.tools.dotc.quoted
22

3-
import java.io.PrintStream
4-
3+
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.core.Contexts.Context
55
import dotty.tools.dotc.core.Phases.Phase
66

7-
/** Compiler that takes the contents of a quoted expression `expr` and produces outputs
8-
* the pretty printed code.
9-
*/
10-
class ExprDecompiler(out: PrintStream) extends ExprCompiler(null) {
7+
/** Compiler that takes the contents of a quoted expression `expr` and outputs it's tree. */
8+
class ExprDecompiler(output: tpd.Tree => Context => Unit) extends ExprCompiler(null) {
119
override def phases: List[List[Phase]] = List(
1210
List(new ExprFrontend(putInClass = false)), // Create class from Expr
13-
List(new QuotePrinter(out)) // Print all loaded classes
11+
List(new QuoteTreeOutput(output))
1412
)
1513
}

compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
package dotty.tools.dotc.quoted
22

3+
import dotty.tools.dotc.ast.tpd
34
import dotty.tools.dotc.Driver
45
import dotty.tools.dotc.core.Contexts.Context
56
import dotty.tools.dotc.core.StdNames._
67
import dotty.tools.io.VirtualDirectory
7-
88
import dotty.tools.repl.AbstractFileClassLoader
99

1010
import scala.quoted.Expr
1111

12-
import java.io.ByteArrayOutputStream
13-
import java.io.PrintStream
14-
import java.nio.charset.StandardCharsets
15-
1612
class QuoteDriver extends Driver {
13+
import tpd._
1714

1815
def run[T](expr: Expr[T]): T = {
1916
val ctx: Context = initCtx.fresh
@@ -33,19 +30,16 @@ class QuoteDriver extends Driver {
3330
method.invoke(instance).asInstanceOf[T]
3431
}
3532

36-
def show(expr: Expr[_]): String = {
33+
def toTreeWithContext(expr: Expr[_]): (Tree, Context) = {
3734
val ctx: Context = initCtx.fresh
3835
ctx.settings.color.update("never")(ctx) // TODO support colored show
39-
val baos = new ByteArrayOutputStream
40-
var ps: PrintStream = null
41-
try {
42-
ps = new PrintStream(baos, true, "utf-8")
43-
44-
new ExprDecompiler(ps).newRun(ctx).compileExpr(expr)
45-
46-
new String(baos.toByteArray, StandardCharsets.UTF_8)
36+
var output: (tpd.Tree, Context) = null
37+
def registerTree(tree: tpd.Tree)(ctx: Context): Unit = {
38+
assert(output eq null)
39+
output = (tree, ctx)
4740
}
48-
finally if (ps != null) ps.close()
41+
new ExprDecompiler(registerTree).newRun(ctx).compileExpr(expr)
42+
output
4943
}
5044

5145
override def initCtx: Context = {
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
package dotty.tools.dotc.quoted
22

3-
import java.io.PrintStream
4-
3+
import dotty.tools.dotc.ast.tpd
54
import dotty.tools.dotc.core.Contexts._
65
import dotty.tools.dotc.core.Phases.Phase
76

87
/** Pretty prints the compilation unit to an output stream */
9-
class QuotePrinter(out: PrintStream) extends Phase {
10-
8+
class QuoteTreeOutput(output: tpd.Tree => Context => Unit) extends Phase {
119
override def phaseName: String = "quotePrinter"
12-
13-
override def run(implicit ctx: Context): Unit = {
14-
val unit = ctx.compilationUnit
15-
out.print(unit.tpdTree.show)
16-
}
10+
override def run(implicit ctx: Context): Unit = output(ctx.compilationUnit.tpdTree)(ctx)
1711
}
Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
11
package dotty.tools.dotc.quoted
22

3+
import dotty.tools.dotc.ast.Trees._
4+
import dotty.tools.dotc.ast.tpd
5+
import dotty.tools.dotc.core.Constants._
6+
import dotty.tools.dotc.core.Contexts._
7+
import dotty.tools.dotc.interpreter.RawExpr
8+
39
import scala.quoted.Expr
410
import scala.quoted.Liftable.PrimitiveExpr
511
import scala.runtime.quoted._
612

713
/** Default runners for quoted expressions */
814
object Runners {
15+
import tpd._
916

1017
implicit def runner[T]: Runner[T] = new Runner[T] {
1118

12-
def run(expr: Expr[T]): T = expr match {
19+
override def run(expr: Expr[T]): T = expr match {
1320
case expr: PrimitiveExpr[T] => expr.value
1421
case _ => new QuoteDriver().run(expr)
1522
}
1623

17-
def show(expr: Expr[T]): String = expr match {
24+
override def show(expr: Expr[T]): String = expr match {
1825
case expr: PrimitiveExpr[T] => expr.value.toString
19-
case _ => new QuoteDriver().show(expr)
26+
case _ =>
27+
val (tree, ctx) = toTreeWithContext(expr)
28+
tree.show(ctx)
29+
}
30+
31+
override def toConstantOpt(expr: Expr[T]): Option[T] = {
32+
def toConstantOpt(tree: Tree): Option[T] = tree match {
33+
case Literal(Constant(c)) => Some(c.asInstanceOf[T])
34+
case Block(Nil, e) => toConstantOpt(e)
35+
case Inlined(_, Nil, e) => toConstantOpt(e)
36+
case _ => None
37+
}
38+
expr match {
39+
case expr: PrimitiveExpr[T] => Some(expr.value)
40+
case _ => toConstantOpt(toTreeWithContext(expr)._1)
41+
}
2042
}
43+
44+
private def toTreeWithContext(expr: Expr[T]): (Tree, Context) =
45+
new QuoteDriver().toTreeWithContext(expr)
46+
2147
}
2248
}

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ class CompilationTests extends ParallelTesting {
197197
compileFilesInDir("../tests/run-no-optimise", defaultOptions) +
198198
compileFile("../tests/run-special/quote-run.scala", defaultRunWithCompilerOptions) +
199199
compileFile("../tests/run-special/quote-run-2.scala", defaultRunWithCompilerOptions) +
200-
compileFile("../tests/run-special/quote-run-staged-interpreter.scala", defaultRunWithCompilerOptions)
200+
compileFile("../tests/run-special/quote-run-staged-interpreter.scala", defaultRunWithCompilerOptions) +
201+
compileFile("../tests/run-special/quote-run-constants.scala", defaultRunWithCompilerOptions)
201202
}.checkRuns()
202203

203204
// Generic java signatures tests ---------------------------------------------
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package scala.quoted
2+
3+
import scala.runtime.quoted.Runner
4+
5+
object Constant {
6+
def unapply[T](expr: Expr[T])(implicit runner: Runner[T]): Option[T] = runner.toConstantOpt(expr)
7+
}

library/src/scala/quoted/TastyExpr.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ package scala.quoted
33
import scala.runtime.quoted.Unpickler.Pickled
44

55
/** An Expr backed by a pickled TASTY tree */
6-
final case class TastyExpr[T](tasty: Pickled, args: Seq[Any]) extends Expr[T] with TastyQuoted
6+
final class TastyExpr[T](val tasty: Pickled, val args: Seq[Any]) extends Expr[T] with TastyQuoted

library/src/scala/quoted/TastyType.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ package scala.quoted
33
import scala.runtime.quoted.Unpickler.Pickled
44

55
/** A Type backed by a pickled TASTY tree */
6-
final case class TastyType[T](tasty: Pickled, args: Seq[Any]) extends Type[T] with TastyQuoted
6+
final class TastyType[T](val tasty: Pickled, val args: Seq[Any]) extends Type[T] with TastyQuoted

library/src/scala/runtime/quoted/Runner.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ import scala.quoted.Expr
77
trait Runner[T] {
88
def run(expr: Expr[T]): T
99
def show(expr: Expr[T]): String
10+
def toConstantOpt(expr: Expr[T]): Option[T]
1011
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
3
2+
4
3+
abc
4+
null
5+
OK
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.quoted._
2+
3+
import dotty.tools.dotc.quoted.Runners._
4+
5+
object Test {
6+
7+
def main(args: Array[String]): Unit = {
8+
(3: Expr[Int]) match { case Constant(n) => println(n) }
9+
'(4) match { case Constant(n) => println(n) }
10+
'("abc") match { case Constant(n) => println(n) }
11+
'(null) match { case Constant(n) => println(n) }
12+
13+
'(new Object) match { case Constant(n) => println(n); case _ => println("OK") }
14+
}
15+
}

0 commit comments

Comments
 (0)