|
| 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 | +} |
0 commit comments