Skip to content

Commit e158370

Browse files
committed
Add MacroStringInterpolator framework
1 parent 909f10a commit e158370

File tree

3 files changed

+86
-0
lines changed

3 files changed

+86
-0
lines changed

tests/run-separate-compilation/tasty-interpolation-1.check

Whitespace-only changes.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
import scala.quoted._
3+
import scala.tasty.Reflection
4+
import scala.language.implicitConversions
5+
import scala.quoted.Exprs.LiftedExpr
6+
import scala.quoted.Toolbox.Default._
7+
8+
object Macro {
9+
10+
class StringContextOps(strCtx: => StringContext) {
11+
inline def foo(args: Any*): String = ~SIntepolator('(strCtx), '(args))
12+
}
13+
implicit inline def SCOps(strCtx: => StringContext): StringContextOps = new StringContextOps(strCtx)
14+
15+
}
16+
17+
object SIntepolator extends MacroStringInterpolator[String] {
18+
19+
// TODO remove this
20+
override def apply(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(implicit reflect: Reflection): Expr[String] = {
21+
super.apply(strCtxExpr, argsExpr)
22+
}
23+
24+
override def interpolate(strCtx: StringContext, args: List[Expr[Any]])(implicit reflect: Reflection): Expr[String] =
25+
'(StringContext(~strCtx.parts.toList.toExpr: _*).s(~args.toExprOfList: _*))
26+
27+
// TODO use stdlib
28+
implicit def l: Liftable[List[String]] = new Liftable[List[String]] {
29+
override def toExpr(list: List[String]): Expr[List[String]] = list match {
30+
case x :: xs => '(~x.toExpr :: ~toExpr(xs))
31+
case Nil => '(Nil)
32+
}
33+
}
34+
}
35+
36+
abstract class MacroStringInterpolator[T] {
37+
38+
/*final*/ def apply(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(implicit reflect: Reflection): Expr[T] = {
39+
interpolate(strCtxExpr, argsExpr)
40+
}
41+
42+
def interpolate(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(implicit reflect: Reflection): Expr[T] = {
43+
val strCtx = getStaticStringContext(strCtxExpr).getOrElse(throw new QuoteError("Expected statically known StringContext"))
44+
val argExprs = getArgsList(argsExpr).getOrElse(throw new QuoteError("Expected statically known argument list"))
45+
interpolate(strCtx, argExprs)
46+
}
47+
48+
def interpolate(strCtx: StringContext, argExprs: List[Expr[Any]])(implicit reflect: Reflection): Expr[T] = {
49+
// argExprs.toExprOfList
50+
// '(StringContext(~strCtx.parts.toList.toExpr: _*).s(~args: _*))
51+
???
52+
}
53+
54+
protected def getStaticStringContext(strCtxExpr: Expr[StringContext])(implicit reflect: Reflection): Option[StringContext] = {
55+
import reflect._
56+
strCtxExpr.unseal.underlyingArgument match {
57+
case Term.Select(Term.Typed(Term.Apply(_, List(Term.Apply(_, List(Term.Typed(Term.Repeated(strCtxArgTrees), TypeTree.Inferred()))))), _), _) =>
58+
val strCtxArgs = strCtxArgTrees.map {
59+
case Term.Literal(Constant.String(str)) => str
60+
case _ => return None
61+
}
62+
Some(StringContext(strCtxArgs: _*))
63+
case _ =>
64+
None
65+
}
66+
}
67+
68+
protected def getArgsList(argsExpr: Expr[Seq[Any]])(implicit reflect: Reflection): Option[List[Expr[Any]]] = {
69+
import reflect._
70+
argsExpr.unseal.underlyingArgument match {
71+
case Term.Typed(Term.Repeated(args), _) => Some(args.map(_.seal[Any]))
72+
case _ => None
73+
}
74+
}
75+
76+
77+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Macro._
2+
3+
object Test {
4+
def main(args: Array[String]): Unit = {
5+
6+
println(foo"Hello ${"world"}!")
7+
8+
}
9+
}

0 commit comments

Comments
 (0)