summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/reflect
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-09-11 11:27:49 +0200
committerEugene Burmako <xeno.by@gmail.com>2014-09-11 11:27:49 +0200
commit9ba986e61151cb370ba519f568042776c9f303df (patch)
tree282dbe114f6f26882c16a5421710c73c930bf1ba /src/compiler/scala/tools/reflect
parent7c8eaef41cacaa34cd691fb81e58d2d80428c661 (diff)
downloadscala-9ba986e61151cb370ba519f568042776c9f303df.tar.gz
scala-9ba986e61151cb370ba519f568042776c9f303df.tar.bz2
scala-9ba986e61151cb370ba519f568042776c9f303df.zip
moves the impl of quasiquotes to scala.reflect
This brings consistency with scala.reflect.reify and scala.reflect.macros already existing in scala-compiler. To the contrast, scala.tools.reflect, the previous home of quasiquotes, is a grab bag of various stuff without any central theme.
Diffstat (limited to 'src/compiler/scala/tools/reflect')
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala2
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Holes.scala245
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala228
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala201
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala60
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala487
6 files changed, 1 insertions, 1222 deletions
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
index 64cf3d0847..8fed53c89f 100644
--- a/src/compiler/scala/tools/reflect/FastTrack.scala
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -5,7 +5,7 @@ import scala.reflect.reify.Taggers
import scala.tools.nsc.typechecker.{ Analyzer, Macros }
import scala.reflect.runtime.Macros.currentMirror
import scala.reflect.api.Universe
-import scala.tools.reflect.quasiquotes.{ Quasiquotes => QuasiquoteImpls }
+import scala.reflect.quasiquotes.{ Quasiquotes => QuasiquoteImpls }
/** Optimizes system macro expansions by hardwiring them directly to their implementations
* bypassing standard reflective load and invoke to avoid the overhead of Java/Scala reflection.
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
deleted file mode 100644
index 68cc728eb3..0000000000
--- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala
+++ /dev/null
@@ -1,245 +0,0 @@
-package scala.tools.reflect
-package quasiquotes
-
-import scala.collection.{immutable, mutable}
-import scala.reflect.internal.Flags._
-import scala.reflect.macros.TypecheckException
-
-class Rank private[Rank](val value: Int) extends AnyVal {
- def pred = { assert(value - 1 >= 0); new Rank(value - 1) }
- def succ = new Rank(value + 1)
- override def toString = if (value == 0) "no dots" else "." * (value + 1)
-}
-
-object Rank {
- val NoDot = new Rank(0)
- val DotDot = new Rank(1)
- val DotDotDot = new Rank(2)
- object Dot { def unapply(rank: Rank) = rank != NoDot }
- def parseDots(part: String) = {
- if (part.endsWith("...")) (part.stripSuffix("..."), DotDotDot)
- else if (part.endsWith("..")) (part.stripSuffix(".."), DotDot)
- else (part, NoDot)
- }
-}
-
-/** Defines abstractions that provide support for splicing into Scala syntax.
- */
-trait Holes { self: Quasiquotes =>
- import global._
- import Rank._
- import definitions._
- import universeTypes._
-
- private lazy val IterableTParam = IterableClass.typeParams(0).asType.toType
- private def inferParamImplicit(tfun: Type, targ: Type) = c.inferImplicitValue(appliedType(tfun, List(targ)), silent = true)
- private def inferLiftable(tpe: Type): Tree = inferParamImplicit(liftableType, tpe)
- private def inferUnliftable(tpe: Type): Tree = inferParamImplicit(unliftableType, tpe)
- private def isLiftableType(tpe: Type) = inferLiftable(tpe) != EmptyTree
- private def isNativeType(tpe: Type) =
- (tpe <:< treeType) || (tpe <:< nameType) || (tpe <:< modsType) ||
- (tpe <:< flagsType) || (tpe <:< symbolType)
- private def isBottomType(tpe: Type) =
- tpe <:< NothingClass.tpe || tpe <:< NullClass.tpe
- private def extractIterableTParam(tpe: Type) =
- IterableTParam.asSeenFrom(tpe, IterableClass)
- private def stripIterable(tpe: Type, limit: Rank = DotDotDot): (Rank, Type) =
- if (limit == NoDot) (NoDot, tpe)
- else if (tpe != null && !isIterableType(tpe)) (NoDot, tpe)
- else if (isBottomType(tpe)) (NoDot, tpe)
- else {
- val targ = extractIterableTParam(tpe)
- val (rank, innerTpe) = stripIterable(targ, limit.pred)
- (rank.succ, innerTpe)
- }
- private def iterableTypeFromRank(n: Rank, tpe: Type): Type = {
- if (n == NoDot) tpe
- else appliedType(IterableClass.toType, List(iterableTypeFromRank(n.pred, tpe)))
- }
-
- /** Hole encapsulates information about unquotees in quasiquotes.
- * It packs together a rank, pre-reified tree representation
- * (possibly preprocessed) and position.
- */
- abstract class Hole {
- val tree: Tree
- val pos: Position
- val rank: Rank
- }
-
- object Hole {
- def apply(rank: Rank, tree: Tree): Hole =
- if (method != nme.unapply) new ApplyHole(rank, tree)
- else new UnapplyHole(rank, tree)
- def unapply(hole: Hole): Some[(Tree, Rank)] = Some((hole.tree, hole.rank))
- }
-
- class ApplyHole(annotatedRank: Rank, unquotee: Tree) extends Hole {
- val (strippedTpe, tpe): (Type, Type) = {
- val (strippedRank, strippedTpe) = stripIterable(unquotee.tpe, limit = annotatedRank)
- if (isBottomType(strippedTpe)) cantSplice()
- else if (isNativeType(strippedTpe)) {
- if (strippedRank != NoDot && !(strippedTpe <:< treeType) && !isLiftableType(strippedTpe)) cantSplice()
- else (strippedTpe, iterableTypeFromRank(annotatedRank, strippedTpe))
- } else if (isLiftableType(strippedTpe)) (strippedTpe, iterableTypeFromRank(annotatedRank, treeType))
- else cantSplice()
- }
-
- val tree = {
- def inner(itpe: Type)(tree: Tree) =
- if (isNativeType(itpe)) tree
- else if (isLiftableType(itpe)) lifted(itpe)(tree)
- else global.abort("unreachable")
- if (annotatedRank == NoDot) inner(strippedTpe)(unquotee)
- else iterated(annotatedRank, unquotee, unquotee.tpe)
- }
-
- val pos = unquotee.pos
-
- val rank = stripIterable(tpe)._1
-
- private def cantSplice(): Nothing = {
- val (iterableRank, iterableType) = stripIterable(unquotee.tpe)
- val holeRankMsg = if (annotatedRank != NoDot) s" with $annotatedRank" else ""
- val action = "unquote " + unquotee.tpe + holeRankMsg
- val suggestRank = annotatedRank != iterableRank || annotatedRank != NoDot
- val unquoteeRankMsg = if (annotatedRank != iterableRank && iterableRank != NoDot) s"using $iterableRank" else "omitting the dots"
- val rankSuggestion = if (suggestRank) unquoteeRankMsg else ""
- val suggestLifting = (annotatedRank == NoDot || iterableRank != NoDot) && !(iterableType <:< treeType) && !isLiftableType(iterableType)
- val liftedTpe = if (annotatedRank != NoDot) iterableType else unquotee.tpe
- val liftSuggestion = if (suggestLifting) s"providing an implicit instance of Liftable[$liftedTpe]" else ""
- val advice =
- if (isBottomType(iterableType)) "bottom type values often indicate programmer mistake"
- else "consider " + List(rankSuggestion, liftSuggestion).filter(_ != "").mkString(" or ")
- c.abort(unquotee.pos, s"Can't $action, $advice")
- }
-
- private def lifted(tpe: Type)(tree: Tree): Tree = {
- val lifter = inferLiftable(tpe)
- assert(lifter != EmptyTree, s"couldnt find a liftable for $tpe")
- val lifted = Apply(lifter, List(tree))
- atPos(tree.pos)(lifted)
- }
-
- private def toStats(tree: Tree): Tree =
- // q"$u.internal.reificationSupport.toStats($tree)"
- Apply(Select(Select(Select(u, nme.internal), nme.reificationSupport), nme.toStats), tree :: Nil)
-
- private def toList(tree: Tree, tpe: Type): Tree =
- if (isListType(tpe)) tree
- else Select(tree, nme.toList)
-
- private def mapF(tree: Tree, f: Tree => Tree): Tree =
- if (f(Ident(TermName("x"))) equalsStructure Ident(TermName("x"))) tree
- else {
- val x: TermName = c.freshName()
- // q"$tree.map { $x => ${f(Ident(x))} }"
- Apply(Select(tree, nme.map),
- Function(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree) :: Nil,
- f(Ident(x))) :: Nil)
- }
-
- private object IterableType {
- def unapply(tpe: Type): Option[Type] =
- if (isIterableType(tpe)) Some(extractIterableTParam(tpe)) else None
- }
-
- private object LiftedType {
- def unapply(tpe: Type): Option[Tree => Tree] =
- if (tpe <:< treeType) Some(t => t)
- else if (isLiftableType(tpe)) Some(lifted(tpe)(_))
- else None
- }
-
- /** Map high-rank unquotee onto an expression that eveluates as a list of given rank.
- *
- * All possible combinations of representations are given in the table below:
- *
- * input output for T <: Tree output for T: Liftable
- *
- * ..${x: Iterable[T]} x.toList x.toList.map(lift)
- * ..${x: T} toStats(x) toStats(lift(x))
- *
- * ...${x: Iterable[Iterable[T]]} x.toList { _.toList } x.toList.map { _.toList.map(lift) }
- * ...${x: Iterable[T]} x.toList.map { toStats(_) } x.toList.map { toStats(lift(_)) }
- * ...${x: T} toStats(x).map { toStats(_) } toStats(lift(x)).map { toStats(_) }
- *
- * For optimization purposes `x.toList` is represented as just `x` if it is statically known that
- * x is not just an Iterable[T] but a List[T]. Similarly no mapping is performed if mapping function is
- * known to be an identity.
- */
- private def iterated(rank: Rank, tree: Tree, tpe: Type): Tree = (rank, tpe) match {
- case (DotDot, tpe @ IterableType(LiftedType(lift))) => mapF(toList(tree, tpe), lift)
- case (DotDot, LiftedType(lift)) => toStats(lift(tree))
- case (DotDotDot, tpe @ IterableType(inner)) => mapF(toList(tree, tpe), t => iterated(DotDot, t, inner))
- case (DotDotDot, LiftedType(lift)) => mapF(toStats(lift(tree)), toStats)
- case _ => global.abort("unreachable")
- }
- }
-
- class UnapplyHole(val rank: Rank, pat: Tree) extends Hole {
- val (placeholderName, pos, tptopt) = pat match {
- case Bind(pname, inner @ Bind(_, Typed(Ident(nme.WILDCARD), tpt))) => (pname, inner.pos, Some(tpt))
- case Bind(pname, inner @ Typed(Ident(nme.WILDCARD), tpt)) => (pname, inner.pos, Some(tpt))
- case Bind(pname, inner) => (pname, inner.pos, None)
- }
- val treeNoUnlift = Bind(placeholderName, Ident(nme.WILDCARD))
- lazy val tree =
- tptopt.map { tpt =>
- val TypeDef(_, _, _, typedTpt) =
- try c.typeCheck(TypeDef(NoMods, TypeName("T"), Nil, tpt))
- catch { case TypecheckException(pos, msg) => c.abort(pos.asInstanceOf[c.Position], msg) }
- val tpe = typedTpt.tpe
- val (iterableRank, _) = stripIterable(tpe)
- if (iterableRank.value < rank.value)
- c.abort(pat.pos, s"Can't extract $tpe with $rank, consider using $iterableRank")
- val (_, strippedTpe) = stripIterable(tpe, limit = rank)
- if (strippedTpe <:< treeType) treeNoUnlift
- else
- unlifters.spawn(strippedTpe, rank).map {
- Apply(_, treeNoUnlift :: Nil)
- }.getOrElse {
- c.abort(pat.pos, s"Can't find $unliftableType[$strippedTpe], consider providing it")
- }
- }.getOrElse { treeNoUnlift }
- }
-
- /** Full support for unliftable implies that it's possible to interleave
- * deconstruction with higher rank and unlifting of the values.
- * In particular extraction of List[Tree] as List[T: Unliftable] requires
- * helper extractors that would do the job: UnliftListElementwise[T]. Similarly
- * List[List[Tree]] needs UnliftListOfListsElementwise[T].
- *
- * See also "unlift list" tests in UnapplyProps.scala
- */
- object unlifters {
- private var records = List.empty[(Type, Rank)]
- // Materialize unlift helper that does elementwise
- // unlifting for corresponding rank and type.
- def spawn(tpe: Type, rank: Rank): Option[Tree] = {
- val unlifter = inferUnliftable(tpe)
- if (unlifter == EmptyTree) None
- else if (rank == NoDot) Some(unlifter)
- else {
- val idx = records.indexWhere { p => p._1 =:= tpe && p._2 == rank }
- val resIdx = if (idx != -1) idx else { records +:= (tpe, rank); records.length - 1}
- Some(Ident(TermName(nme.QUASIQUOTE_UNLIFT_HELPER + resIdx)))
- }
- }
- // Returns a list of vals that will defined required unlifters
- def preamble(): List[Tree] =
- records.zipWithIndex.map { case ((tpe, rank), idx) =>
- val name = TermName(nme.QUASIQUOTE_UNLIFT_HELPER + idx)
- val helperName = rank match {
- case DotDot => nme.UnliftListElementwise
- case DotDotDot => nme.UnliftListOfListsElementwise
- }
- val lifter = inferUnliftable(tpe)
- assert(helperName.isTermName)
- // q"val $name: $u.internal.reificationSupport.${helperName.toTypeName} = $u.internal.reificationSupport.$helperName($lifter)"
- ValDef(NoMods, name,
- AppliedTypeTree(Select(Select(Select(u, nme.internal), nme.reificationSupport), helperName.toTypeName), List(TypeTree(tpe))),
- Apply(Select(Select(Select(u, nme.internal), nme.reificationSupport), helperName), lifter :: Nil))
- }
- }
-}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
deleted file mode 100644
index 392b7fc881..0000000000
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ /dev/null
@@ -1,228 +0,0 @@
-package scala.tools.reflect
-package quasiquotes
-
-import scala.tools.nsc.ast.parser.{Parsers => ScalaParser}
-import scala.tools.nsc.ast.parser.Tokens._
-import scala.compat.Platform.EOL
-import scala.reflect.internal.util.{BatchSourceFile, SourceFile, FreshNameCreator}
-import scala.collection.mutable.ListBuffer
-import scala.util.Try
-
-/** Builds upon the vanilla Scala parser and teams up together with Placeholders.scala to emulate holes.
- * A principled solution to splicing into Scala syntax would be a parser that natively supports holes.
- * Unfortunately, that's outside of our reach in Scala 2.11, so we have to emulate.
- */
-trait Parsers { self: Quasiquotes =>
- import global.{Try => _, _}
- import build.implodePatDefs
-
- abstract class Parser extends {
- val global: self.global.type = self.global
- } with ScalaParser {
- def parse(code: String): Tree = {
- try {
- val file = new BatchSourceFile(nme.QUASIQUOTE_FILE, code)
- val parser = new QuasiquoteParser(file)
- parser.checkNoEscapingPlaceholders { parser.parseRule(entryPoint) }
- } catch {
- case mi: MalformedInput => c.abort(correspondingPosition(mi.offset), mi.msg)
- }
- }
-
- def correspondingPosition(offset: Int): Position = {
- val posMapList = posMap.toList
- def containsOffset(start: Int, end: Int) = start <= offset && offset < end
- def fallbackPosition = posMapList match {
- case (pos1, (start1, end1)) :: _ if start1 > offset => pos1
- case _ :+ ((pos2, (start2, end2))) if end2 <= offset => pos2.withPoint(pos2.point + (end2 - start2))
- }
- posMapList.sliding(2).collect {
- case (pos1, (start1, end1)) :: _ if containsOffset(start1, end1) => (pos1, offset - start1)
- case (pos1, (start1, end1)) :: (pos2, (start2, _)) :: _ if containsOffset(end1, start2) => (pos1, end1 - start1)
- case _ :: (pos2, (start2, end2)) :: _ if containsOffset(start2, end2) => (pos2, offset - start2)
- }.map { case (pos, offset) =>
- pos.withPoint(pos.point + offset)
- }.toList.headOption.getOrElse(fallbackPosition)
- }
-
- override def token2string(token: Int): String = token match {
- case EOF => "end of quote"
- case _ => super.token2string(token)
- }
-
- def entryPoint: QuasiquoteParser => Tree
-
- class QuasiquoteParser(source0: SourceFile) extends SourceFileParser(source0) { parser =>
- def isHole: Boolean = isIdent && isHole(in.name)
-
- def isHole(name: Name): Boolean = holeMap.contains(name)
-
- override implicit lazy val fresh: FreshNameCreator = new FreshNameCreator(nme.QUASIQUOTE_PREFIX)
-
- override val treeBuilder = new ParserTreeBuilder {
- override implicit def fresh: FreshNameCreator = parser.fresh
-
- // q"(..$xs)"
- override def makeTupleTerm(trees: List[Tree]): Tree = TuplePlaceholder(trees)
-
- // tq"(..$xs)"
- override def makeTupleType(trees: List[Tree]): Tree = TupleTypePlaceholder(trees)
-
- // q"{ $x }"
- override def makeBlock(stats: List[Tree]): Tree = method match {
- case nme.apply =>
- stats match {
- // we don't want to eagerly flatten trees with placeholders as they
- // might have to be wrapped into a block depending on their value
- case (head @ Ident(name)) :: Nil if isHole(name) => Block(Nil, head)
- case _ => gen.mkBlock(stats, doFlatten = true)
- }
- case nme.unapply => gen.mkBlock(stats, doFlatten = false)
- case other => global.abort("unreachable")
- }
-
- // tq"$a => $b"
- override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = FunctionTypePlaceholder(argtpes, restpe)
-
- // make q"val (x: T) = rhs" be equivalent to q"val x: T = rhs" for sake of bug compatibility (SI-8211)
- override def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree) = pat match {
- case TuplePlaceholder(inParensPat :: Nil) => super.makePatDef(mods, inParensPat, rhs)
- case _ => super.makePatDef(mods, pat, rhs)
- }
- }
- import treeBuilder.{global => _, unit => _, _}
-
- // q"def foo($x)"
- override def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef =
- if (isHole && lookingAhead { in.token == COMMA || in.token == RPAREN }) {
- ParamPlaceholder(implicitmod, ident())
- } else super.param(owner, implicitmod, caseParam)
-
- // q"($x) => ..." && q"class X { selfie => }
- override def convertToParam(tree: Tree): ValDef = tree match {
- case Ident(name) if isHole(name) => ParamPlaceholder(NoFlags, name)
- case _ => super.convertToParam(tree)
- }
-
- // q"foo match { case $x }"
- override def caseClause(): CaseDef =
- if (isHole && lookingAhead { in.token == CASE || in.token == RBRACE || in.token == SEMI }) {
- val c = CasePlaceholder(ident())
- while (in.token == SEMI) in.nextToken()
- c
- } else
- super.caseClause()
-
- override def caseBlock(): Tree = super.caseBlock() match {
- case Block(Nil, expr) => expr
- case other => other
- }
-
- override def isAnnotation: Boolean = super.isAnnotation || (isHole && lookingAhead { isAnnotation })
-
- override def isModifier: Boolean = super.isModifier || (isHole && lookingAhead { isModifier })
-
- override def isLocalModifier: Boolean = super.isLocalModifier || (isHole && lookingAhead { isLocalModifier })
-
- override def isTemplateIntro: Boolean = super.isTemplateIntro || (isHole && lookingAhead { isTemplateIntro })
-
- override def isDefIntro: Boolean = super.isDefIntro || (isHole && lookingAhead { isDefIntro })
-
- override def isDclIntro: Boolean = super.isDclIntro || (isHole && lookingAhead { isDclIntro })
-
- override def isStatSep(token: Int) = token == EOF || super.isStatSep(token)
-
- override def expectedMsg(token: Int): String =
- if (isHole) expectedMsgTemplate(token2string(token), "unquotee")
- else super.expectedMsg(token)
-
- // $mods def foo
- // $mods T
- override def readAnnots(annot: => Tree): List[Tree] = in.token match {
- case AT =>
- in.nextToken()
- annot :: readAnnots(annot)
- case _ if isHole && lookingAhead { isAnnotation || isModifier || isDefIntro || isIdent || isStatSep || in.token == LPAREN } =>
- val ann = ModsPlaceholder(in.name)
- in.nextToken()
- ann :: readAnnots(annot)
- case _ =>
- Nil
- }
-
- override def refineStat(): List[Tree] =
- if (isHole && !isDclIntro) {
- val result = RefineStatPlaceholder(in.name) :: Nil
- in.nextToken()
- result
- } else super.refineStat()
-
- override def ensureEarlyDef(tree: Tree) = tree match {
- case Ident(name: TermName) if isHole(name) => EarlyDefPlaceholder(name)
- case _ => super.ensureEarlyDef(tree)
- }
-
- override def isTypedParam(tree: Tree) = super.isTypedParam(tree) || (tree match {
- case Ident(name) if isHole(name) => true
- case _ => false
- })
-
- override def topStat = super.topStat.orElse {
- case _ if isHole =>
- val stats = PackageStatPlaceholder(in.name) :: Nil
- in.nextToken()
- stats
- }
-
- override def enumerator(isFirst: Boolean, allowNestedIf: Boolean = true) =
- if (isHole && lookingAhead { in.token == EOF || in.token == RPAREN || isStatSep }) {
- val res = ForEnumPlaceholder(in.name) :: Nil
- in.nextToken()
- res
- } else super.enumerator(isFirst, allowNestedIf)
- }
- }
-
- /** Wrapper around tree parsed in q"..." quote. Needed to support ..$ splicing on top-level. */
- object Q {
- def apply(tree: Tree): Block = Block(Nil, tree).updateAttachment(Q)
- def unapply(tree: Tree): Option[Tree] = tree match {
- case Block(Nil, contents) if tree.hasAttachment[Q.type] => Some(contents)
- case _ => None
- }
- }
-
- object TermParser extends Parser {
- def entryPoint = parser => Q(implodePatDefs(gen.mkTreeOrBlock(parser.templateOrTopStatSeq())))
- }
-
- object TypeParser extends Parser {
- def entryPoint = { parser =>
- if (parser.in.token == EOF)
- TypeTree()
- else
- parser.typ()
- }
- }
-
- object CaseParser extends Parser {
- def entryPoint = parser => implodePatDefs(parser.caseClause())
- }
-
- object PatternParser extends Parser {
- def entryPoint = { parser =>
- val pat = parser.noSeq.pattern()
- gen.patvarTransformer.transform(pat)
- }
- }
-
- object ForEnumeratorParser extends Parser {
- def entryPoint = { parser =>
- val enums = parser.enumerator(isFirst = false, allowNestedIf = false)
- assert(enums.length == 1)
- implodePatDefs(enums.head)
- }
- }
-
- object FreshName extends FreshNameExtractor(nme.QUASIQUOTE_PREFIX)
-}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
deleted file mode 100644
index b287971815..0000000000
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ /dev/null
@@ -1,201 +0,0 @@
-package scala.tools.reflect
-package quasiquotes
-
-import java.util.UUID.randomUUID
-import scala.collection.{immutable, mutable}
-
-/** Emulates hole support (see Holes.scala) in the quasiquote parser (see Parsers.scala).
- * A principled solution to splicing into Scala syntax would be a parser that natively supports holes.
- * Unfortunately, that's outside of our reach in Scala 2.11, so we have to emulate.
- * This trait stores knowledge of how to represent the holes as something understandable by the parser
- * and how to recover holes from the results of parsing the produced representation.
- */
-trait Placeholders { self: Quasiquotes =>
- import global._
- import Rank._
- import universeTypes._
-
- // Step 1: Transform Scala source with holes into vanilla Scala source
-
- lazy val posMap = mutable.LinkedHashMap[Position, (Int, Int)]()
- lazy val code = {
- val sb = new StringBuilder()
- val sessionSuffix = randomUUID().toString.replace("-", "").substring(0, 8) + "$"
-
- def appendPart(value: String, pos: Position) = {
- val start = sb.length
- sb.append(value)
- val end = sb.length
- posMap += pos -> ((start, end))
- }
-
- def appendHole(tree: Tree, rank: Rank) = {
- val placeholderName = c.freshName(TermName(nme.QUASIQUOTE_PREFIX + sessionSuffix))
- sb.append(placeholderName)
- val holeTree =
- if (method != nme.unapply) tree
- else Bind(placeholderName, tree)
- holeMap(placeholderName) = Hole(rank, holeTree)
- }
-
- val iargs = method match {
- case nme.apply => args
- case nme.unapply => internal.subpatterns(args.head).get
- case _ => global.abort("unreachable")
- }
-
- foreach2(iargs, parts.init) { case (tree, (p, pos)) =>
- val (part, rank) = parseDots(p)
- appendPart(part, pos)
- appendHole(tree, rank)
- }
- val (p, pos) = parts.last
- appendPart(p, pos)
-
- sb.toString
- }
-
- object holeMap {
- private val underlying = mutable.LinkedHashMap.empty[String, Hole]
- private val accessed = mutable.Set.empty[String]
- def unused: Set[Name] = (underlying.keys.toSet -- accessed).map(TermName(_))
- def contains(key: Name): Boolean = underlying.contains(key.toString)
- def apply(key: Name): Hole = {
- val skey = key.toString
- val value = underlying(skey)
- accessed += skey
- value
- }
- def update(key: Name, hole: Hole) =
- underlying += key.toString -> hole
- def get(key: Name): Option[Hole] = {
- val skey = key.toString
- underlying.get(skey).map { v =>
- accessed += skey
- v
- }
- }
- def keysIterator: Iterator[TermName] = underlying.keysIterator.map(TermName(_))
- }
-
- // Step 2: Transform vanilla Scala AST into an AST with holes
-
- trait HolePlaceholder {
- def matching: PartialFunction[Any, Name]
- def unapply(scrutinee: Any): Option[Hole] = {
- val name = matching.lift(scrutinee)
- name.flatMap { holeMap.get(_) }
- }
- }
-
- object Placeholder extends HolePlaceholder {
- def matching = {
- case name: Name => name
- case Ident(name) => name
- case Bind(name, Ident(nme.WILDCARD)) => name
- case TypeDef(_, name, List(), TypeBoundsTree(EmptyTree, EmptyTree)) => name
- }
- }
-
- object ModsPlaceholder extends HolePlaceholder {
- def apply(name: Name) =
- Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(name.toString))))
- def matching = {
- case Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(s: String)))) => TermName(s)
- }
- }
-
- object AnnotPlaceholder extends HolePlaceholder {
- def matching = {
- case Apply(Select(New(Ident(name)), nme.CONSTRUCTOR), Nil) => name
- }
- }
-
- object ParamPlaceholder extends HolePlaceholder {
- def apply(flags: FlagSet, name: Name) =
- ValDef(Modifiers(flags), nme.QUASIQUOTE_PARAM, Ident(name), EmptyTree)
- def matching = {
- case ValDef(_, nme.QUASIQUOTE_PARAM, Ident(name), EmptyTree) => name
- }
- }
-
- object TuplePlaceholder {
- def apply(args: List[Tree]) =
- Apply(Ident(nme.QUASIQUOTE_TUPLE), args)
- def unapply(tree: Tree): Option[List[Tree]] = tree match {
- case Apply(Ident(nme.QUASIQUOTE_TUPLE), args) => Some(args)
- case _ => None
- }
- }
-
- object TupleTypePlaceholder {
- def apply(args: List[Tree]) =
- AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), args)
- def unapply(tree: Tree): Option[List[Tree]] = tree match {
- case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), args) => Some(args)
- case _ => None
- }
- }
-
- object FunctionTypePlaceholder {
- def apply(args: List[Tree], res: Tree) =
- AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res)
- def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
- case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res) => Some((args, res))
- case _ => None
- }
- }
-
- object SymbolPlaceholder {
- def unapply(scrutinee: Any): Option[Hole] = scrutinee match {
- case Placeholder(hole: ApplyHole) if hole.tpe <:< symbolType => Some(hole)
- case _ => None
- }
- }
-
- object CasePlaceholder {
- def apply(name: Name) =
- CaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), Ident(name) :: Nil), EmptyTree, EmptyTree)
- def unapply(tree: Tree): Option[Hole] = tree match {
- case CaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), List(Placeholder(hole))), EmptyTree, EmptyTree) => Some(hole)
- case _ => None
- }
- }
-
- object RefineStatPlaceholder {
- def apply(name: Name) =
- ValDef(NoMods, nme.QUASIQUOTE_REFINE_STAT, Ident(name), EmptyTree)
- def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(_, nme.QUASIQUOTE_REFINE_STAT, Ident(Placeholder(hole)), _) => Some(hole)
- case _ => None
- }
- }
-
- object EarlyDefPlaceholder {
- def apply(name: Name) =
- ValDef(Modifiers(Flag.PRESUPER), nme.QUASIQUOTE_EARLY_DEF, Ident(name), EmptyTree)
- def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(_, nme.QUASIQUOTE_EARLY_DEF, Ident(Placeholder(hole)), _) => Some(hole)
- case _ => None
- }
- }
-
- object PackageStatPlaceholder {
- def apply(name: Name) =
- ValDef(NoMods, nme.QUASIQUOTE_PACKAGE_STAT, Ident(name), EmptyTree)
- def unapply(tree: Tree): Option[Hole] = tree match {
- case ValDef(NoMods, nme.QUASIQUOTE_PACKAGE_STAT, Ident(Placeholder(hole)), EmptyTree) => Some(hole)
- case _ => None
- }
- }
-
- object ForEnumPlaceholder {
- def apply(name: Name) =
- build.SyntacticValFrom(Bind(name, Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM))
- def unapply(tree: Tree): Option[Hole] = tree match {
- case build.SyntacticValFrom(Bind(Placeholder(hole), Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM)) =>
- Some(hole)
- case _ => None
- }
- }
-}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
deleted file mode 100644
index b33069181c..0000000000
--- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
+++ /dev/null
@@ -1,60 +0,0 @@
-package scala.tools.reflect
-package quasiquotes
-
-import scala.reflect.macros.runtime.Context
-
-abstract class Quasiquotes extends Parsers
- with Holes
- with Placeholders
- with Reifiers {
- val c: Context
- val global: c.universe.type = c.universe
- import c.universe._
-
- def debug(msg: => String): Unit =
- if (settings.Yquasiquotedebug.value) println(msg)
-
- 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"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")
- }
- val reify0 = method0 match {
- case nme.apply => new ApplyReifier().reifyFillingHoles(_)
- case nme.unapply => new UnapplyReifier().reifyFillingHoles(_)
- case other => global.abort(s"Unknown quasiquote api method: $other")
- }
- val parse0 = interpolator0 match {
- case nme.q => TermParser.parse(_)
- case nme.tq => TypeParser.parse(_)
- case nme.cq => CaseParser.parse(_)
- case nme.pq => PatternParser.parse(_)
- case nme.fq => ForEnumeratorParser.parse(_)
- case other => global.abort(s"Unknown quasiquote flavor: $other")
- }
- (universe0, args0, parts1, parse0, reify0, method0)
- case _ =>
- global.abort(s"Couldn't parse call prefix tree ${c.macroApplication}.")
- }
-
- lazy val u = universe // shortcut
- lazy val universeTypes = new definitions.UniverseDependentTypes(universe)
-
- def expandQuasiquote = {
- 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)
- def sreified =
- reified
- .toString
- .replace("scala.reflect.runtime.`package`.universe.internal.reificationSupport.", "")
- .replace("scala.reflect.runtime.`package`.universe.", "")
- .replace("scala.collection.immutable.", "")
- debug(s"reified tree:\n$sreified\n")
- reified
- }
-}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
deleted file mode 100644
index 95113d5b00..0000000000
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ /dev/null
@@ -1,487 +0,0 @@
-package scala.tools.reflect
-package quasiquotes
-
-import java.lang.UnsupportedOperationException
-import scala.reflect.reify.{Reifier => ReflectReifier}
-import scala.reflect.internal.Flags._
-
-trait Reifiers { self: Quasiquotes =>
- import global._
- import global.build._
- import global.treeInfo._
- import global.definitions._
- import Rank._
- import universeTypes._
-
- abstract class Reifier(val isReifyingExpressions: Boolean) extends {
- val global: self.global.type = self.global
- val universe = self.universe
- val reifee = EmptyTree
- val mirror = EmptyTree
- val concrete = false
- } with ReflectReifier {
- lazy val typer = throw new UnsupportedOperationException
-
- def isReifyingPatterns: Boolean = !isReifyingExpressions
- def action = if (isReifyingExpressions) "unquote" else "extract"
- def holesHaveTypes = isReifyingExpressions
-
- /** Map that stores freshly generated names linked to the corresponding names in the reified tree.
- * This information is used to reify names created by calls to freshTermName and freshTypeName.
- */
- val nameMap = collection.mutable.HashMap.empty[Name, Set[TermName]].withDefault { _ => Set() }
-
- /** Wraps expressions into:
- * a block which starts with a sequence of vals that correspond
- * to fresh names that has to be created at evaluation of the quasiquote
- * and ends with reified tree:
- *
- * {
- * val name$1: universe.TermName = universe.build.freshTermName(prefix1)
- * ...
- * val name$N: universe.TermName = universe.build.freshTermName(prefixN)
- * tree
- * }
- *
- * Wraps patterns into:
- * a call into anonymous class' unapply method required by unapply macro expansion:
- *
- * new {
- * def unapply(tree) = tree match {
- * case pattern if guard => Some(result)
- * case _ => None
- * }
- * }.unapply(<unapply-selector>)
- *
- * where pattern corresponds to reified tree and guard represents conjunction of equalities
- * which check that pairs of names in nameMap.values are equal between each other.
- */
- def wrap(tree: Tree) =
- if (isReifyingExpressions) {
- val freshdefs = nameMap.iterator.map {
- case (origname, names) =>
- assert(names.size == 1)
- val FreshName(prefix) = origname
- val nameTypeName = if (origname.isTermName) tpnme.TermName else tpnme.TypeName
- val freshName = if (origname.isTermName) nme.freshTermName else nme.freshTypeName
- // q"val ${names.head}: $u.$nameTypeName = $u.internal.reificationSupport.$freshName($prefix)"
- ValDef(NoMods, names.head, Select(u, nameTypeName),
- Apply(Select(Select(Select(u, nme.internal), nme.reificationSupport), freshName), Literal(Constant(prefix)) :: Nil))
- }.toList
- // q"..$freshdefs; $tree"
- SyntacticBlock(freshdefs :+ tree)
- } else {
- val freevars = holeMap.keysIterator.map(Ident(_)).toList
- val isVarPattern = tree match { case Bind(name, Ident(nme.WILDCARD)) => true case _ => false }
- val cases =
- if(isVarPattern) {
- val Ident(name) :: Nil = freevars
- // cq"$name: $treeType => $SomeModule($name)" :: Nil
- CaseDef(Bind(name, Typed(Ident(nme.WILDCARD), TypeTree(treeType))),
- EmptyTree, Apply(Ident(SomeModule), List(Ident(name)))) :: Nil
- } else {
- val (succ, fail) = freevars match {
- case Nil =>
- // (q"true", q"false")
- (Literal(Constant(true)), Literal(Constant(false)))
- case head :: Nil =>
- // (q"$SomeModule($head)", q"$NoneModule")
- (Apply(Ident(SomeModule), List(head)), Ident(NoneModule))
- case vars =>
- // (q"$SomeModule((..$vars))", q"$NoneModule")
- (Apply(Ident(SomeModule), List(SyntacticTuple(vars))), Ident(NoneModule))
- }
- val guard =
- nameMap.collect { case (_, nameset) if nameset.size >= 2 =>
- nameset.toList.sliding(2).map { case List(n1, n2) =>
- // q"$n1 == $n2"
- Apply(Select(Ident(n1), nme.EQ), List(Ident(n2)))
- }
- }.flatten.reduceOption[Tree] { (l, r) =>
- // q"$l && $r"
- Apply(Select(l, nme.ZAND), List(r))
- }.getOrElse { EmptyTree }
- // cq"$tree if $guard => $succ" :: cq"_ => $fail" :: Nil
- CaseDef(tree, guard, succ) :: CaseDef(Ident(nme.WILDCARD), EmptyTree, fail) :: Nil
- }
- // q"new { def unapply(tree: $AnyClass) = { ..${unlifters.preamble()}; tree match { case ..$cases } } }.unapply(..$args)"
- Apply(
- Select(
- SyntacticNew(Nil, Nil, noSelfType, List(
- DefDef(NoMods, nme.unapply, Nil, List(List(ValDef(NoMods, nme.tree, TypeTree(AnyClass.toType), EmptyTree))), TypeTree(),
- SyntacticBlock(unlifters.preamble() :+ Match(Ident(nme.tree), cases))))),
- nme.unapply),
- args)
- }
-
- def reifyFillingHoles(tree: Tree): Tree = {
- val reified = reifyTree(tree)
- holeMap.unused.foreach { hole =>
- c.abort(holeMap(hole).pos, s"Don't know how to $action here")
- }
- wrap(reified)
- }
-
- override def reifyTree(tree: Tree): Tree =
- reifyTreePlaceholder(tree) orElse
- reifyTreeSyntactically(tree)
-
- def reifyTreePlaceholder(tree: Tree): Tree = tree match {
- case Placeholder(hole: ApplyHole) if hole.tpe <:< treeType => hole.tree
- case Placeholder(Hole(tree, NoDot)) if isReifyingPatterns => tree
- case Placeholder(hole @ Hole(_, rank @ Dot())) => c.abort(hole.pos, s"Can't $action with $rank here")
- case TuplePlaceholder(args) => reifyTuple(args)
- // Due to greediness of syntactic applied we need to pre-emptively peek inside.
- // `rest` will always be non-empty due to the rule on top of this one.
- case SyntacticApplied(id @ Ident(nme.QUASIQUOTE_TUPLE), first :: rest) =>
- mirrorBuildCall(nme.SyntacticApplied, reifyTreePlaceholder(Apply(id, first)), reify(rest))
- case TupleTypePlaceholder(args) => reifyTupleType(args)
- case FunctionTypePlaceholder(argtpes, restpe) => reifyFunctionType(argtpes, restpe)
- case CasePlaceholder(hole) => hole.tree
- case RefineStatPlaceholder(hole) => reifyRefineStat(hole)
- case EarlyDefPlaceholder(hole) => reifyEarlyDef(hole)
- case PackageStatPlaceholder(hole) => reifyPackageStat(hole)
- case ParamPlaceholder(hole) => hole.tree
- // for enumerators are checked not during splicing but during
- // desugaring of the for loop in SyntacticFor & SyntacticForYield
- case ForEnumPlaceholder(hole) => hole.tree
- case _ => EmptyTree
- }
-
- override def reifyTreeSyntactically(tree: Tree) = tree match {
- case RefTree(qual, SymbolPlaceholder(Hole(tree, _))) if isReifyingExpressions =>
- mirrorBuildCall(nme.mkRefTree, reify(qual), tree)
- case This(SymbolPlaceholder(Hole(tree, _))) if isReifyingExpressions =>
- mirrorCall(nme.This, tree)
- case SyntacticTraitDef(mods, name, tparams, earlyDefs, parents, selfdef, body) =>
- reifyBuildCall(nme.SyntacticTraitDef, mods, name, tparams, earlyDefs, parents, selfdef, body)
- case SyntacticClassDef(mods, name, tparams, constrmods, vparamss,
- earlyDefs, parents, selfdef, body) =>
- mirrorBuildCall(nme.SyntacticClassDef, reify(mods), reify(name), reify(tparams), reify(constrmods),
- reifyVparamss(vparamss), reify(earlyDefs), reify(parents),
- reify(selfdef), reify(body))
- case SyntacticPackageObjectDef(name, earlyDefs, parents, selfdef, body) =>
- reifyBuildCall(nme.SyntacticPackageObjectDef, name, earlyDefs, parents, selfdef, body)
- case SyntacticObjectDef(mods, name, earlyDefs, parents, selfdef, body) =>
- reifyBuildCall(nme.SyntacticObjectDef, mods, name, earlyDefs, parents, selfdef, body)
- case SyntacticNew(earlyDefs, parents, selfdef, body) =>
- reifyBuildCall(nme.SyntacticNew, earlyDefs, parents, selfdef, body)
- case SyntacticDefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams),
- reifyVparamss(vparamss), reify(tpt), reify(rhs))
- case SyntacticValDef(mods, name, tpt, rhs) if tree != noSelfType =>
- reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs)
- case SyntacticVarDef(mods, name, tpt, rhs) =>
- reifyBuildCall(nme.SyntacticVarDef, mods, name, tpt, rhs)
- case SyntacticValFrom(pat, rhs) =>
- reifyBuildCall(nme.SyntacticValFrom, pat, rhs)
- case SyntacticValEq(pat, rhs) =>
- reifyBuildCall(nme.SyntacticValEq, pat, rhs)
- case SyntacticFilter(cond) =>
- reifyBuildCall(nme.SyntacticFilter, cond)
- case SyntacticFor(enums, body) =>
- reifyBuildCall(nme.SyntacticFor, enums, body)
- case SyntacticForYield(enums, body) =>
- reifyBuildCall(nme.SyntacticForYield, enums, body)
- case SyntacticAssign(lhs, rhs) =>
- reifyBuildCall(nme.SyntacticAssign, lhs, rhs)
- case SyntacticApplied(fun, argss) if argss.nonEmpty =>
- reifyBuildCall(nme.SyntacticApplied, fun, argss)
- case SyntacticTypeApplied(fun, targs) if targs.nonEmpty =>
- reifyBuildCall(nme.SyntacticTypeApplied, fun, targs)
- case SyntacticAppliedType(tpt, targs) if targs.nonEmpty =>
- reifyBuildCall(nme.SyntacticAppliedType, tpt, targs)
- case SyntacticFunction(args, body) =>
- reifyBuildCall(nme.SyntacticFunction, args, body)
- case SyntacticEmptyTypeTree() =>
- reifyBuildCall(nme.SyntacticEmptyTypeTree)
- case SyntacticImport(expr, selectors) =>
- reifyBuildCall(nme.SyntacticImport, expr, selectors)
- case SyntacticPartialFunction(cases) =>
- reifyBuildCall(nme.SyntacticPartialFunction, cases)
- case SyntacticMatch(scrutinee, cases) =>
- reifyBuildCall(nme.SyntacticMatch, scrutinee, cases)
- case SyntacticTermIdent(name, isBackquoted) =>
- reifyBuildCall(nme.SyntacticTermIdent, name, isBackquoted)
- case SyntacticTypeIdent(name) =>
- reifyBuildCall(nme.SyntacticTypeIdent, name)
- case SyntacticCompoundType(parents, defns) =>
- reifyBuildCall(nme.SyntacticCompoundType, parents, defns)
- case SyntacticSingletonType(ref) =>
- reifyBuildCall(nme.SyntacticSingletonType, ref)
- case SyntacticTypeProjection(qual, name) =>
- reifyBuildCall(nme.SyntacticTypeProjection, qual, name)
- case SyntacticAnnotatedType(tpt, annot) =>
- reifyBuildCall(nme.SyntacticAnnotatedType, tpt, annot)
- case SyntacticExistentialType(tpt, where) =>
- reifyBuildCall(nme.SyntacticExistentialType, tpt, where)
- case Q(tree) if fillListHole.isDefinedAt(tree) =>
- mirrorBuildCall(nme.SyntacticBlock, fillListHole(tree))
- case Q(other) =>
- reifyTree(other)
- // Syntactic block always matches so we have to be careful
- // not to cause infinite recursion.
- case block @ SyntacticBlock(stats) if block.isInstanceOf[Block] =>
- reifyBuildCall(nme.SyntacticBlock, stats)
- case SyntheticUnit() =>
- reifyBuildCall(nme.SyntacticBlock, Nil)
- case Try(block, catches, finalizer) =>
- reifyBuildCall(nme.SyntacticTry, block, catches, finalizer)
- case CaseDef(pat, guard, body) if fillListHole.isDefinedAt(body) =>
- mirrorCall(nme.CaseDef, reify(pat), reify(guard), mirrorBuildCall(nme.SyntacticBlock, fillListHole(body)))
- // parser emits trees with scala package symbol to ensure
- // that some names hygienically point to various scala package
- // members; we need to preserve this symbol to preserve
- // correctness of the trees produced by quasiquotes
- case Select(id @ Ident(nme.scala_), name) if id.symbol == ScalaPackage =>
- reifyBuildCall(nme.ScalaDot, name)
- case Select(qual, name) =>
- val ctor = if (name.isTypeName) nme.SyntacticSelectType else nme.SyntacticSelectTerm
- reifyBuildCall(ctor, qual, name)
- case _ =>
- super.reifyTreeSyntactically(tree)
- }
-
- override def reifyName(name: Name): Tree = name match {
- case Placeholder(hole: ApplyHole) =>
- if (!(hole.tpe <:< nameType)) c.abort(hole.pos, s"$nameType expected but ${hole.tpe} found")
- hole.tree
- case Placeholder(hole: UnapplyHole) => hole.treeNoUnlift
- case FreshName(prefix) if prefix != nme.QUASIQUOTE_NAME_PREFIX =>
- def fresh() = c.freshName[TermName](nme.QUASIQUOTE_NAME_PREFIX)
- def introduceName() = { val n = fresh(); nameMap(name) += n; n}
- def result(n: Name) = if (isReifyingExpressions) Ident(n) else Bind(n, Ident(nme.WILDCARD))
- if (isReifyingPatterns) result(introduceName())
- else result(nameMap.get(name).map { _.head }.getOrElse { introduceName() })
- case _ =>
- super.reifyName(name)
- }
-
- def reifyTuple(args: List[Tree]) = args match {
- case Nil => reify(Literal(Constant(())))
- case List(hole @ Placeholder(Hole(_, NoDot))) => reify(hole)
- case List(Placeholder(_)) => reifyBuildCall(nme.SyntacticTuple, args)
- // in a case we only have one element tuple without
- // any rank annotations this means that this is
- // just an expression wrapped in parentheses
- case List(other) => reify(other)
- case _ => reifyBuildCall(nme.SyntacticTuple, args)
- }
-
- def reifyTupleType(args: List[Tree]) = args match {
- case Nil => reify(Select(Ident(nme.scala_), tpnme.Unit))
- case List(hole @ Placeholder(Hole(_, NoDot))) => reify(hole)
- case List(Placeholder(_)) => reifyBuildCall(nme.SyntacticTupleType, args)
- case List(other) => reify(other)
- case _ => reifyBuildCall(nme.SyntacticTupleType, args)
- }
-
- def reifyFunctionType(argtpes: List[Tree], restpe: Tree) =
- reifyBuildCall(nme.SyntacticFunctionType, argtpes, restpe)
-
- def reifyConstructionCheck(name: TermName, hole: Hole) = hole match {
- case _: UnapplyHole => hole.tree
- case _: ApplyHole => mirrorBuildCall(name, hole.tree)
- }
-
- def reifyRefineStat(hole: Hole) = reifyConstructionCheck(nme.mkRefineStat, hole)
-
- def reifyEarlyDef(hole: Hole) = reifyConstructionCheck(nme.mkEarlyDef, hole)
-
- def reifyAnnotation(hole: Hole) = reifyConstructionCheck(nme.mkAnnotation, hole)
-
- def reifyPackageStat(hole: Hole) = reifyConstructionCheck(nme.mkPackageStat, hole)
-
- def reifyVparamss(vparamss: List[List[ValDef]]) = {
- val build.ImplicitParams(paramss, implparams) = vparamss
- if (implparams.isEmpty) reify(paramss)
- else reifyBuildCall(nme.ImplicitParams, paramss, implparams)
- }
-
- /** Splits list into a list of groups where subsequent elements are considered
- * similar by the corresponding function.
- *
- * Example:
- *
- * > group(List(1, 1, 0, 0, 1, 0)) { _ == _ }
- * List(List(1, 1), List(0, 0), List(1), List(0))
- *
- */
- def group[T](lst: List[T])(similar: (T, T) => Boolean) = lst.foldLeft[List[List[T]]](List()) {
- case (Nil, el) => List(List(el))
- case (ll :+ (last @ (lastinit :+ lastel)), el) if similar(lastel, el) => ll :+ (last :+ el)
- case (ll, el) => ll :+ List(el)
- }
-
- /** Reifies list filling all the valid holeMap.
- *
- * Reification of non-trivial list is done in two steps:
- *
- * 1. split the list into groups where every placeholder is always
- * put in a group of it's own and all subsquent non-holeMap are
- * grouped together; element is considered to be a placeholder if it's
- * in the domain of the fill function;
- *
- * 2. fold the groups into a sequence of lists added together with ++ using
- * fill reification for holeMapĀ and fallback reification for non-holeMap.
- *
- * Example:
- *
- * reifyHighRankList(lst) {
- * // first we define patterns that extract high-rank holeMap (currently ..)
- * case Placeholder(IterableType(_, _)) => tree
- * } {
- * // in the end we define how single elements are reified, typically with default reify call
- * reify(_)
- * }
- *
- * Sample execution of previous concrete list reifier:
- *
- * > val lst = List(foo, bar, qq$f3948f9s$1)
- * > reifyHighRankList(lst) { ... } { ... }
- * q"List($foo, $bar) ++ ${holeMap(qq$f3948f9s$1).tree}"
- */
- def reifyHighRankList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree
-
- val fillListHole: PartialFunction[Any, Tree] = {
- case Placeholder(Hole(tree, DotDot)) => tree
- case CasePlaceholder(Hole(tree, DotDot)) => tree
- case RefineStatPlaceholder(h @ Hole(_, DotDot)) => reifyRefineStat(h)
- case EarlyDefPlaceholder(h @ Hole(_, DotDot)) => reifyEarlyDef(h)
- case PackageStatPlaceholder(h @ Hole(_, DotDot)) => reifyPackageStat(h)
- case ForEnumPlaceholder(Hole(tree, DotDot)) => tree
- case ParamPlaceholder(Hole(tree, DotDot)) => tree
- case SyntacticPatDef(mods, pat, tpt, rhs) =>
- reifyBuildCall(nme.SyntacticPatDef, mods, pat, tpt, rhs)
- case SyntacticValDef(mods, p @ Placeholder(h: ApplyHole), tpt, rhs) if h.tpe <:< treeType =>
- mirrorBuildCall(nme.SyntacticPatDef, reify(mods), h.tree, reify(tpt), reify(rhs))
- }
-
- val fillListOfListsHole: PartialFunction[Any, Tree] = {
- case List(ParamPlaceholder(Hole(tree, DotDotDot))) => tree
- case List(Placeholder(Hole(tree, DotDotDot))) => tree
- }
-
- /** Reifies arbitrary list filling ..$x and ...$y holeMap when they are put
- * in the correct position. Fallbacks to regular reification for zero rank
- * elements.
- */
- override def reifyList(xs: List[Any]): Tree = reifyHighRankList(xs)(fillListHole.orElse(fillListOfListsHole))(reify)
-
- def reifyAnnotList(annots: List[Tree]): Tree = reifyHighRankList(annots) {
- case AnnotPlaceholder(h @ Hole(_, DotDot)) => reifyAnnotation(h)
- } {
- case AnnotPlaceholder(h: ApplyHole) if h.tpe <:< treeType => reifyAnnotation(h)
- case AnnotPlaceholder(h: UnapplyHole) if h.rank == NoDot => reifyAnnotation(h)
- case other => reify(other)
- }
-
- // These are explicit flags except those that are used
- // to overload the same tree for two different concepts:
- // - MUTABLE that is used to override ValDef for vars
- // - TRAIT that is used to override ClassDef for traits
- val nonOverloadedExplicitFlags = ExplicitFlags & ~MUTABLE & ~TRAIT
-
- def ensureNoExplicitFlags(m: Modifiers, pos: Position) = {
- // Traits automatically have ABSTRACT flag assigned to
- // them so in that case it's not an explicit flag
- val flags = if (m.isTrait) m.flags & ~ABSTRACT else m.flags
- if ((flags & nonOverloadedExplicitFlags) != 0L)
- c.abort(pos, s"Can't $action modifiers together with flags, consider merging flags into modifiers")
- }
-
- override def mirrorSelect(name: String): Tree =
- Select(universe, TermName(name))
-
- override def mirrorCall(name: TermName, args: Tree*): Tree =
- Apply(Select(universe, name), args.toList)
-
- override def mirrorBuildCall(name: TermName, args: Tree*): Tree =
- Apply(Select(Select(Select(universe, nme.internal), nme.reificationSupport), name), args.toList)
-
- override def scalaFactoryCall(name: String, args: Tree*): Tree =
- call("scala." + name, args: _*)
- }
-
- class ApplyReifier extends Reifier(isReifyingExpressions = true) {
- def reifyHighRankList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree =
- if (xs.isEmpty) mkList(Nil)
- else {
- def reifyGroup(group: List[Any]): Tree = group match {
- case List(elem) if fill.isDefinedAt(elem) => fill(elem)
- case elems => mkList(elems.map(fallback))
- }
- val head :: tail = group(xs) { (a, b) => !fill.isDefinedAt(a) && !fill.isDefinedAt(b) }
- tail.foldLeft[Tree](reifyGroup(head)) { (tree, lst) => Apply(Select(tree, nme.PLUSPLUS), List(reifyGroup(lst))) }
- }
-
- override def reifyModifiers(m: Modifiers) =
- if (m == NoMods) super.reifyModifiers(m)
- else {
- val (modsPlaceholders, annots) = m.annotations.partition {
- case ModsPlaceholder(_) => true
- case _ => false
- }
- val (mods, flags) = modsPlaceholders.map {
- case ModsPlaceholder(hole: ApplyHole) => hole
- }.partition { hole =>
- if (hole.tpe <:< modsType) true
- else if (hole.tpe <:< flagsType) false
- else c.abort(hole.pos, s"$flagsType or $modsType expected but ${hole.tpe} found")
- }
- mods match {
- case hole :: Nil =>
- if (flags.nonEmpty) c.abort(flags(0).pos, "Can't unquote flags together with modifiers, consider merging flags into modifiers")
- if (annots.nonEmpty) c.abort(hole.pos, "Can't unquote modifiers together with annotations, consider merging annotations into modifiers")
- ensureNoExplicitFlags(m, hole.pos)
- hole.tree
- case _ :: hole :: Nil =>
- c.abort(hole.pos, "Can't unquote multiple modifiers, consider merging them into a single modifiers instance")
- case _ =>
- val baseFlags = reifyFlags(m.flags)
- val reifiedFlags = flags.foldLeft[Tree](baseFlags) { case (flag, hole) => Apply(Select(flag, nme.OR), List(hole.tree)) }
- mirrorFactoryCall(nme.Modifiers, reifiedFlags, reify(m.privateWithin), reifyAnnotList(annots))
- }
- }
-
- }
- class UnapplyReifier extends Reifier(isReifyingExpressions = false) {
- 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 reifyHighRankList(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) =
- if (m == NoMods) super.reifyModifiers(m)
- else {
- val mods = m.annotations.collect { case ModsPlaceholder(hole: UnapplyHole) => hole }
- mods match {
- case hole :: Nil =>
- if (m.annotations.length != 1) c.abort(hole.pos, "Can't extract modifiers together with annotations, consider extracting just modifiers")
- ensureNoExplicitFlags(m, hole.pos)
- hole.treeNoUnlift
- case _ :: hole :: _ =>
- c.abort(hole.pos, "Can't extract multiple modifiers together, consider extracting a single modifiers instance")
- case Nil =>
- mirrorFactoryCall(nme.Modifiers, reifyFlags(m.flags), reify(m.privateWithin), reifyAnnotList(m.annotations))
- }
- }
- }
-}