diff options
author | Denys Shabalin <denys.shabalin@typesafe.com> | 2014-02-01 19:25:16 +0100 |
---|---|---|
committer | Denys Shabalin <denys.shabalin@typesafe.com> | 2014-02-02 18:19:47 +0100 |
commit | ffc3203c3688b6fc5f47f4043bf3a0090de9d985 (patch) | |
tree | e64965cedf021c14144c4f51fb055a60ecf66342 /src/compiler/scala/tools/reflect | |
parent | 1a3de955b824aa4d946467c5b207133b6839b17d (diff) | |
download | scala-ffc3203c3688b6fc5f47f4043bf3a0090de9d985.tar.gz scala-ffc3203c3688b6fc5f47f4043bf3a0090de9d985.tar.bz2 scala-ffc3203c3688b6fc5f47f4043bf3a0090de9d985.zip |
SI-8173 add support for patterns like init :+ last to quasiquotes
Adds support for patterns like:
val q"{ ..$init; $last }" = q"{ a; b; c }"
// init == List(q"a", q"b")
// last == q"c"
Which under the hood get compiled as `:+` patterns:
SyntacticBlock(init :+ last)
Diffstat (limited to 'src/compiler/scala/tools/reflect')
-rw-r--r-- | src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala | 36 |
2 files changed, 27 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala index 3e703924e8..396688c437 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala @@ -16,7 +16,7 @@ abstract class Quasiquotes extends Parsers lazy val (universe: Tree, args, parts, parse, reify, method) = c.macroApplication match { case Apply(build.SyntacticTypeApplied(Select(Select(Apply(Select(universe0, _), List(Apply(_, parts0))), interpolator0), method0), _), args0) => - debug(s"\nparse prefix:\nuniverse=$universe0\nparts=$parts0\ninterpolator=$interpolator0\nmethod=$method0\nargs=$args0\n") + debug(s"parse prefix:\nuniverse=$universe0\nparts=$parts0\ninterpolator=$interpolator0\nmethod=$method0\nargs=$args0\n") val parts1 = parts0.map { case lit @ Literal(Constant(s: String)) => s -> lit.pos case part => c.abort(part.pos, "Quasiquotes can only be used with literal strings") @@ -43,8 +43,8 @@ abstract class Quasiquotes extends Parsers lazy val universeTypes = new definitions.UniverseDependentTypes(universe) def expandQuasiquote = { - debug(s"\nmacro application:\n${c.macroApplication}\n") - debug(s"\ncode to parse:\n$code\n") + debug(s"macro application:\n${c.macroApplication}\n") + debug(s"code to parse:\n$code\n") val tree = parse(code) debug(s"parsed:\n${showRaw(tree)}\n$tree\n") val reified = reify(tree) diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 273245f7bd..c2f4a6fdab 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -162,7 +162,7 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticNew, earlyDefs, parents, selfdef, body) case SyntacticDefDef(mods, name, tparams, build.ImplicitParams(vparamss, implparams), tpt, rhs) => if (implparams.nonEmpty) - mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams), + mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams), reifyBuildCall(nme.ImplicitParams, vparamss, implparams), reify(tpt), reify(rhs)) else reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs) @@ -305,7 +305,7 @@ trait Reifiers { self: Quasiquotes => * > reifyMultiCardinalityList(lst) { ... } { ... } * q"List($foo, $bar) ++ ${holeMap(qq$f3948f9s$1).tree}" */ - def reifyMultiCardinalityList[T](xs: List[T])(fill: PartialFunction[T, Tree])(fallback: T => Tree): Tree + def reifyMultiCardinalityList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree /** Reifies arbitrary list filling ..$x and ...$y holeMap when they are put * in the correct position. Fallbacks to regular reification for non-high cardinality @@ -361,10 +361,10 @@ trait Reifiers { self: Quasiquotes => } class ApplyReifier extends Reifier(isReifyingExpressions = true) { - def reifyMultiCardinalityList[T](xs: List[T])(fill: PartialFunction[T, Tree])(fallback: T => Tree): Tree = + def reifyMultiCardinalityList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree = if (xs.isEmpty) mkList(Nil) else { - def reifyGroup(group: List[T]): Tree = group match { + def reifyGroup(group: List[Any]): Tree = group match { case List(elem) if fill.isDefinedAt(elem) => fill(elem) case elems => mkList(elems.map(fallback)) } @@ -403,14 +403,26 @@ trait Reifiers { self: Quasiquotes => } class UnapplyReifier extends Reifier(isReifyingExpressions = false) { - def reifyMultiCardinalityList[T](xs: List[T])(fill: PartialFunction[T, Tree])(fallback: T => Tree): Tree = xs match { - case init :+ last if fill.isDefinedAt(last) => - init.foldRight[Tree](fill(last)) { (el, rest) => - val cons = Select(Select(Select(Ident(nme.scala_), nme.collection), nme.immutable), nme.CONS) - Apply(cons, List(fallback(el), rest)) - } - case _ => - mkList(xs.map(fallback)) + private def collection = ScalaDot(nme.collection) + private def collectionColonPlus = Select(collection, nme.COLONPLUS) + private def collectionCons = Select(Select(collection, nme.immutable), nme.CONS) + private def collectionNil = Select(Select(collection, nme.immutable), nme.Nil) + // pq"$lhs :+ $rhs" + private def append(lhs: Tree, rhs: Tree) = Apply(collectionColonPlus, lhs :: rhs :: Nil) + // pq"$lhs :: $rhs" + private def cons(lhs: Tree, rhs: Tree) = Apply(collectionCons, lhs :: rhs :: Nil) + + def reifyMultiCardinalityList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree = { + val grouped = group(xs) { (a, b) => !fill.isDefinedAt(a) && !fill.isDefinedAt(b) } + def appended(lst: List[Any], init: Tree) = lst.foldLeft(init) { (l, r) => append(l, fallback(r)) } + def prepended(lst: List[Any], init: Tree) = lst.foldRight(init) { (l, r) => cons(fallback(l), r) } + grouped match { + case init :: List(hole) :: last :: Nil if fill.isDefinedAt(hole) => appended(last, prepended(init, fill(hole))) + case init :: List(hole) :: Nil if fill.isDefinedAt(hole) => prepended(init, fill(hole)) + case List(hole) :: last :: Nil if fill.isDefinedAt(hole) => appended(last, fill(hole)) + case List(hole) :: Nil if fill.isDefinedAt(hole) => fill(hole) + case _ => prepended(xs, collectionNil) + } } override def reifyModifiers(m: Modifiers) = |