Skip to content

Commit 7a42360

Browse files
Merge pull request #5096 from dotty-staging/xml-interpolation
Stub implementation of xml interpolator
2 parents f9c6010 + 92ab218 commit 7a42360

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

compiler/test/dotc/run-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,4 @@ typelevel-patmat.scala
8383
typelevel.scala
8484
typelevel1.scala
8585
typelevel3.scala
86+
xml-interpolation
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import XmlQuote._
2+
3+
object Test {
4+
def main(args: Array[String]): Unit = {
5+
// TODO: enable once #5119 is fixed
6+
// assert(xml"Hello Allan!" == Xml("Hello Allan!", Nil)
7+
8+
val name = new Object{}
9+
assert(xml"Hello $name!" == Xml("Hello ??!", List(name)))
10+
}
11+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import scala.quoted._
2+
import scala.tasty.Tasty
3+
4+
import scala.language.implicitConversions
5+
6+
case class Xml(parts: String, args: List[Any])
7+
8+
// Ideally should be an implicit class but the implicit conversion
9+
// has to be a rewrite method
10+
class XmlQuote(ctx: => StringContext) {
11+
rewrite def xml(args: => Any*): Xml = ~XmlQuote.impl('(ctx), '(args))
12+
}
13+
14+
object XmlQuote {
15+
implicit rewrite def XmlQuote(ctx: => StringContext): XmlQuote = new XmlQuote(ctx)
16+
17+
def impl(ctx: Expr[StringContext], args: Expr[Seq[Any]])
18+
(implicit tasty: Tasty): Expr[Xml] = {
19+
import tasty._
20+
import Term._
21+
22+
def abort(msg: String): Nothing =
23+
throw new QuoteError(msg)
24+
25+
// for debugging purpose
26+
def pp(tree: Tree): Unit = {
27+
println(tree.show)
28+
println(tasty.showSourceCode.showTree(tree))
29+
}
30+
31+
def liftListOfAny(lst: List[Term]): Expr[List[Any]] = lst match {
32+
case x :: xs =>
33+
val head = x.toExpr[Any]
34+
val tail = liftListOfAny(xs)
35+
'{ ~head :: ~tail }
36+
case Nil => '(Nil)
37+
}
38+
39+
def isStringConstant(tree: Term) = tree match {
40+
case Literal(_) => true
41+
case _ => false
42+
}
43+
44+
// _root_.scala.StringContext.apply([p0, ...]: String*)
45+
val parts = ctx.toTasty match {
46+
case Inlined(_, _,
47+
Apply(
48+
Select(Select(Select(Ident("_root_"), "scala", _), "StringContext", _), "apply", _),
49+
List(Typed(Repeated(values), _)))) if values.forall(isStringConstant) =>
50+
values.collect { case Literal(Constant.String(value)) => value }
51+
case tree =>
52+
abort("String literal expected")
53+
}
54+
55+
// [a0, ...]: Any*
56+
val Inlined(_, _, Typed(Repeated(args0), _)) = args.toTasty
57+
58+
val string = parts.mkString("??")
59+
'(new Xml(~string.toExpr, ~liftListOfAny(args0)))
60+
}
61+
}

0 commit comments

Comments
 (0)