@@ -8,70 +8,88 @@ import scala.quoted.Toolbox.Default._
8
8
object Macro {
9
9
10
10
class StringContextOps (strCtx : => StringContext ) {
11
- inline def foo (args : Any * ): String = ~ SIntepolator ('(strCtx), ' (args))
11
+ inline def s2 (args : Any * ): String = ~ SIntepolator ('(strCtx), ' (args))
12
+ inline def raw2 (args : Any * ): String = ~ RawIntepolator ('(strCtx), ' (args))
13
+ inline def foo (args : Any * ): String = ~ FooIntepolator ('(strCtx), ' (args))
12
14
}
13
15
implicit inline def SCOps (strCtx : => StringContext ): StringContextOps = new StringContextOps (strCtx)
14
-
15
16
}
16
17
17
18
object SIntepolator extends MacroStringInterpolator [String ] {
19
+ protected def interpolate (strCtx : StringContext , args : List [Expr [Any ]])(implicit reflect : Reflection ): Expr [String ] =
20
+ '((~strCtx.toExpr).s(~args.toExprOfList: _*))
21
+ }
18
22
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: _*))
23
+ object RawIntepolator extends MacroStringInterpolator [String ] {
24
+ protected def interpolate (strCtx : StringContext , args : List [Expr [Any ]])(implicit reflect : Reflection ): Expr [String ] =
25
+ '((~strCtx.toExpr).raw(~args.toExprOfList: _*))
26
+ }
26
27
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
- }
28
+ object FooIntepolator extends MacroStringInterpolator [String ] {
29
+ protected def interpolate (strCtx : StringContext , args : List [Expr [Any ]])(implicit reflect : Reflection ): Expr [String ] =
30
+ '((~strCtx.toExpr).s(~args.map(_ => ' (" foo" )).toExprOfList: _* ))
34
31
}
35
32
33
+ // TODO put this class in the stdlib or separate project?
36
34
abstract class MacroStringInterpolator [T ] {
37
35
38
- /* final*/ def apply (strCtxExpr : Expr [StringContext ], argsExpr : Expr [Seq [Any ]])(implicit reflect : Reflection ): Expr [T ] = {
39
- interpolate(strCtxExpr, argsExpr)
36
+ final def apply (strCtxExpr : Expr [StringContext ], argsExpr : Expr [Seq [Any ]])(implicit reflect : Reflection ): Expr [T ] = {
37
+ try interpolate(strCtxExpr, argsExpr)
38
+ catch {
39
+ case ex : NotStaticlyKnownError =>
40
+ // TODO use ex.expr to recover the position
41
+ throw new QuoteError (ex.getMessage)
42
+ case ex : StringContextError =>
43
+ // TODO use ex.idx to recover the position
44
+ throw new QuoteError (ex.getMessage)
45
+ case ex : ArgumentError =>
46
+ // TODO use ex.idx to recover the position
47
+ throw new QuoteError (ex.getMessage)
48
+ }
40
49
}
41
50
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
- }
51
+ protected def interpolate (strCtxExpr : Expr [StringContext ], argsExpr : Expr [Seq [Any ]])(implicit reflect : Reflection ): Expr [T ] =
52
+ interpolate(getStaticStringContext(strCtxExpr), getArgsList(argsExpr))
47
53
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
- }
54
+ protected def interpolate (strCtx : StringContext , argExprs : List [Expr [Any ]])(implicit reflect : Reflection ): Expr [T ]
53
55
54
- protected def getStaticStringContext (strCtxExpr : Expr [StringContext ])(implicit reflect : Reflection ): Option [ StringContext ] = {
56
+ protected def getStaticStringContext (strCtxExpr : Expr [StringContext ])(implicit reflect : Reflection ): StringContext = {
55
57
import reflect ._
56
58
strCtxExpr.unseal.underlyingArgument match {
57
59
case Term .Select (Term .Typed (Term .Apply (_, List (Term .Apply (_, List (Term .Typed (Term .Repeated (strCtxArgTrees), TypeTree .Inferred ()))))), _), _) =>
58
60
val strCtxArgs = strCtxArgTrees.map {
59
61
case Term .Literal (Constant .String (str)) => str
60
- case _ => return None
62
+ case tree => throw new NotStaticlyKnownError ( " Expected statically known StringContext " , tree.seal[ Any ])
61
63
}
62
- Some ( StringContext (strCtxArgs : _* ) )
63
- case _ =>
64
- None
64
+ StringContext (strCtxArgs : _* )
65
+ case tree =>
66
+ throw new NotStaticlyKnownError ( " Expected statically known StringContext " , tree.seal[ Any ])
65
67
}
66
68
}
67
69
68
- protected def getArgsList (argsExpr : Expr [Seq [Any ]])(implicit reflect : Reflection ): Option [ List [Expr [Any ] ]] = {
70
+ protected def getArgsList (argsExpr : Expr [Seq [Any ]])(implicit reflect : Reflection ): List [Expr [Any ]] = {
69
71
import reflect ._
70
72
argsExpr.unseal.underlyingArgument match {
71
- case Term .Typed (Term .Repeated (args), _) => Some (args.map(_.seal[Any ]))
72
- case _ => None
73
+ case Term .Typed (Term .Repeated (args), _) => args.map(_.seal[Any ])
74
+ case tree => throw new NotStaticlyKnownError (" Expected statically known argument list" , tree.seal[Any ])
75
+ }
76
+ }
77
+
78
+ protected implicit def StringContextIsLiftable : Liftable [StringContext ] = new Liftable [StringContext ] {
79
+ def toExpr (strCtx : StringContext ): Expr [StringContext ] = {
80
+ // TODO define in stdlib?
81
+ implicit def ListIsLiftable : Liftable [List [String ]] = new Liftable [List [String ]] {
82
+ override def toExpr (list : List [String ]): Expr [List [String ]] = list match {
83
+ case x :: xs => '(~x.toExpr :: ~toExpr(xs))
84
+ case Nil => '(Nil)
85
+ }
86
+ }
87
+ '(StringContext(~strCtx.parts.toList.toExpr: _*))
73
88
}
74
89
}
75
90
91
+ protected class NotStaticlyKnownError (msg : String , expr : Expr [Any ]) extends Exception (msg)
92
+ protected class StringContextError (msg : String , idx : Int , start : Int = - 1 , end : Int = - 1 ) extends Exception (msg)
93
+ protected class ArgumentError (msg : String , idx : Int ) extends Exception (msg)
76
94
77
95
}
0 commit comments