|
| 1 | +import scala.quoted._ |
| 2 | +import scala.quoted.autolift._ |
| 3 | +import scala.quoted.matching._ |
| 4 | +import scala.tasty.Reflection |
| 5 | + |
| 6 | +import scala.language.implicitConversions |
| 7 | + |
| 8 | +object Foo { |
| 9 | + implicit object StringContextOps { |
| 10 | + inline def (ctx: => StringContext) foo (args: => Any*): String = ${ Macro.foo('ctx, 'args) } |
| 11 | + } |
| 12 | +} |
| 13 | + |
| 14 | + |
| 15 | +object TestFooErrors { // Defined in tests |
| 16 | + implicit object StringContextOps { |
| 17 | + inline def (ctx: => StringContext) foo (args: => Any*): List[(Int, Int, Int, String)] = ${ Macro.fooErrors('ctx, 'args) } |
| 18 | + } |
| 19 | +} |
| 20 | + |
| 21 | +object Macro { |
| 22 | + |
| 23 | + def foo(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]]) given (reflect: Reflection): Expr[String] = { |
| 24 | + (sc, argsExpr) match { |
| 25 | + case ('{ StringContext(${ExprSeq(parts)}: _*) }, ExprSeq(args)) => |
| 26 | + val reporter = new Reporter { |
| 27 | + def errorOnPart(msg: String, partIdx: Int): Unit = { |
| 28 | + import reflect._ |
| 29 | + error(msg, parts(partIdx).unseal.pos) |
| 30 | + } |
| 31 | + } |
| 32 | + fooCore(parts, args, reporter) |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + def fooErrors(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]]) given (reflect: Reflection): Expr[List[(Int, Int, Int, String)]] = { |
| 37 | + (sc, argsExpr) match { |
| 38 | + case ('{ StringContext(${ExprSeq(parts)}: _*) }, ExprSeq(args)) => |
| 39 | + val errors = List.newBuilder[Expr[(Int, Int, Int, String)]] |
| 40 | + val reporter = new Reporter { |
| 41 | + def errorOnPart(msg: String, partIdx: Int): Unit = { |
| 42 | + import reflect._ |
| 43 | + val pos = parts(partIdx).unseal.pos |
| 44 | + errors += '{ Tuple4($partIdx, ${pos.start}, ${pos.end}, $msg) } |
| 45 | + } |
| 46 | + } |
| 47 | + fooCore(parts, args, reporter) // Discard result |
| 48 | + errors.result().toExprOfList |
| 49 | + } |
| 50 | + |
| 51 | + |
| 52 | + } |
| 53 | + |
| 54 | + |
| 55 | + private def fooCore(parts: Seq[Expr[String]], args: Seq[Expr[Any]], reporter: Reporter) given Reflection: Expr[String] = { |
| 56 | + for ((part, idx) <- parts.zipWithIndex) { |
| 57 | + val Const(v: String) = part |
| 58 | + if (v.contains("#")) |
| 59 | + reporter.errorOnPart("Cannot use #", idx) |
| 60 | + } |
| 61 | + |
| 62 | + '{ StringContext(${parts.toList.toExprOfList}: _*).s(${args.toList.toExprOfList}: _*) } |
| 63 | + } |
| 64 | + |
| 65 | + |
| 66 | + trait Reporter { |
| 67 | + def errorOnPart(msg: String, partIdx: Int): Unit |
| 68 | + } |
| 69 | + |
| 70 | + |
| 71 | +} |
0 commit comments