Skip to content

Commit 22d7429

Browse files
committed
Add Quotable type class
Quotable is a way to lift expressions from T to Expr[T] without having to go through quotes. This makes writing staged interpreters more pleasant.
1 parent b466e0a commit 22d7429

File tree

5 files changed

+80
-0
lines changed

5 files changed

+80
-0
lines changed

library/src/scala/quoted/Expr.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@ class Expr[T] extends Quoted {
44
def unary_~ : T = ???
55
def run: T = ???
66
}
7+
8+
object Expr {
9+
implicit def toExpr[T](x: T)(implicit ev: Quotable[T]): Expr[T] =
10+
ev.toExpr(x)
11+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package scala.quoted
2+
import scala.math
3+
4+
/** A typeclass for types that can be turned to `quoted.Expr[T]`
5+
* without going through an explicit `'(...)` operation.
6+
*/
7+
abstract class Quotable[T] {
8+
implicit def toExpr(x: T): Expr[T]
9+
}
10+
11+
/** Some base quotable types. To be completed with at least all types
12+
* that are valid Scala literals. The actual implementation of these
13+
* typed could be in terms of `ast.tpd.Literal`; the test `quotable.scala`
14+
* gives an alternative implementation using just the basic staging system.
15+
*/
16+
object Quotable {
17+
18+
implicit def IntIsQuotable: Quotable[Int] = ???
19+
implicit def BooleanIsQuotable: Quotable[Boolean] = ???
20+
}

library/src/scala/quoted/Type.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@ class Type[T] extends Quoted {
44
type unary_~ = T
55
}
66

7+
/** Some basic type tags, currently incomplete */
8+
object Type {
9+
implicit def IntTag: Type[Int] = new Type[Int]
10+
implicit def BooleanTag: Type[Boolean] = new Type[Boolean]
11+
}

tests/pos/quotable.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import scala.quoted._
2+
3+
object Test {
4+
5+
implicit def IntIsQuotable: Quotable[Int] = new {
6+
def toExpr(n: Int): Expr[Int] = n match {
7+
case Int.MinValue => '(Int.MinValue)
8+
case _ if n < 0 => '(-(~toExpr(n)))
9+
case 0 => '(0)
10+
case _ if n % 2 == 0 => '( ~toExpr(n / 2) * 2)
11+
case _ => '( ~toExpr(n / 2) * 2 + 1)
12+
}
13+
}
14+
15+
implicit def BooleanIsQuotable: Quotable[Boolean] = new {
16+
implicit def toExpr(b: Boolean) =
17+
if (b) '(true) else '(false)
18+
}
19+
20+
implicit def ListIsQuotable[T: Type: Quotable]: Quotable[List[T]] = new {
21+
def toExpr(xs: List[T]): Expr[List[T]] = xs match {
22+
case x :: xs1 => '{ ~implicitly[Quotable[T]].toExpr(x) :: ~toExpr(xs1) }
23+
case Nil => '(Nil: List[T])
24+
}
25+
}
26+
27+
val xs: Expr[List[Int]] = 1 :: 2 :: 3 :: Nil
28+
}

tests/pos/stagedInterpreter.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import scala.quoted._
2+
3+
enum Exp {
4+
case Num(n: Int)
5+
case Plus(e1: Exp, e2: Exp)
6+
case Var(x: String)
7+
}
8+
9+
object Test {
10+
import Exp._
11+
12+
val exp = Plus(Plus(Num(2), Var("x")), Num(4))
13+
14+
def compile(e: Exp, env: Map[String, Expr[Int]]): Expr[Int] = e match {
15+
case Num(n) => n
16+
case Plus(e1, e2) => '(~compile(e1, env) + ~compile(e2, env))
17+
case Var(x) => env(x)
18+
}
19+
20+
val res = (x: Int) => ~compile(exp, Map("x" -> '(x)))
21+
22+
}

0 commit comments

Comments
 (0)