From 92ab21822dcffe07ae382cfbcd9794bc9757be99 Mon Sep 17 00:00:00 2001 From: Allan Renucci Date: Wed, 12 Sep 2018 14:40:22 +0200 Subject: [PATCH] Stub implementation of xml interpolator --- .../test/dotc/run-test-pickling.blacklist | 1 + tests/run/xml-interpolation/Test_2.scala | 11 ++++ tests/run/xml-interpolation/XmlQuote_1.scala | 61 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 tests/run/xml-interpolation/Test_2.scala create mode 100644 tests/run/xml-interpolation/XmlQuote_1.scala diff --git a/compiler/test/dotc/run-test-pickling.blacklist b/compiler/test/dotc/run-test-pickling.blacklist index 021e69c2eaca..cec951285d9b 100644 --- a/compiler/test/dotc/run-test-pickling.blacklist +++ b/compiler/test/dotc/run-test-pickling.blacklist @@ -83,3 +83,4 @@ typelevel-patmat.scala typelevel.scala typelevel1.scala typelevel3.scala +xml-interpolation diff --git a/tests/run/xml-interpolation/Test_2.scala b/tests/run/xml-interpolation/Test_2.scala new file mode 100644 index 000000000000..f0e6e795cca2 --- /dev/null +++ b/tests/run/xml-interpolation/Test_2.scala @@ -0,0 +1,11 @@ +import XmlQuote._ + +object Test { + def main(args: Array[String]): Unit = { + // TODO: enable once #5119 is fixed + // assert(xml"Hello Allan!" == Xml("Hello Allan!", Nil) + + val name = new Object{} + assert(xml"Hello $name!" == Xml("Hello ??!", List(name))) + } +} diff --git a/tests/run/xml-interpolation/XmlQuote_1.scala b/tests/run/xml-interpolation/XmlQuote_1.scala new file mode 100644 index 000000000000..eddc86886052 --- /dev/null +++ b/tests/run/xml-interpolation/XmlQuote_1.scala @@ -0,0 +1,61 @@ +import scala.quoted._ +import scala.tasty.Tasty + +import scala.language.implicitConversions + +case class Xml(parts: String, args: List[Any]) + +// Ideally should be an implicit class but the implicit conversion +// has to be a rewrite method +class XmlQuote(ctx: => StringContext) { + rewrite def xml(args: => Any*): Xml = ~XmlQuote.impl('(ctx), '(args)) +} + +object XmlQuote { + implicit rewrite def XmlQuote(ctx: => StringContext): XmlQuote = new XmlQuote(ctx) + + def impl(ctx: Expr[StringContext], args: Expr[Seq[Any]]) + (implicit tasty: Tasty): Expr[Xml] = { + import tasty._ + import Term._ + + def abort(msg: String): Nothing = + throw new QuoteError(msg) + + // for debugging purpose + def pp(tree: Tree): Unit = { + println(tree.show) + println(tasty.showSourceCode.showTree(tree)) + } + + def liftListOfAny(lst: List[Term]): Expr[List[Any]] = lst match { + case x :: xs => + val head = x.toExpr[Any] + val tail = liftListOfAny(xs) + '{ ~head :: ~tail } + case Nil => '(Nil) + } + + def isStringConstant(tree: Term) = tree match { + case Literal(_) => true + case _ => false + } + + // _root_.scala.StringContext.apply([p0, ...]: String*) + val parts = ctx.toTasty match { + case Inlined(_, _, + Apply( + Select(Select(Select(Ident("_root_"), "scala", _), "StringContext", _), "apply", _), + List(Typed(Repeated(values), _)))) if values.forall(isStringConstant) => + values.collect { case Literal(Constant.String(value)) => value } + case tree => + abort("String literal expected") + } + + // [a0, ...]: Any* + val Inlined(_, _, Typed(Repeated(args0), _)) = args.toTasty + + val string = parts.mkString("??") + '(new Xml(~string.toExpr, ~liftListOfAny(args0))) + } +}