summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-09-11 00:25:07 -0700
committerJason Zaugg <jzaugg@gmail.com>2013-09-11 00:25:07 -0700
commit6c78a2800c2cd8fe709a290c3575e578ceb35eb0 (patch)
treec47cf7d5bd816d30349ef1ad9057b79750582262 /src/compiler/scala/tools
parent71dc4c0e162e880048388b2dc82de528d7c9c497 (diff)
parentcdac66f750acb6fbf000215b8534f27f51da00a3 (diff)
downloadscala-6c78a2800c2cd8fe709a290c3575e578ceb35eb0.tar.gz
scala-6c78a2800c2cd8fe709a290c3575e578ceb35eb0.tar.bz2
scala-6c78a2800c2cd8fe709a290c3575e578ceb35eb0.zip
Merge pull request #2910 from densh/topic/quasiquote-improvement-final
Various bugfixes and improvements for the quasiquotes
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala36
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala72
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala9
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala2
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala34
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala27
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala6
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala238
8 files changed, 225 insertions, 199 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index ad1977b9aa..7122e864a4 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -264,42 +264,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
mkNew(Nil, emptyValDef, stats1, NoPosition, NoPosition)
}
- /** Create positioned tree representing an object creation <new parents { stats }
- * @param npos the position of the new
- * @param cpos the position of the anonymous class starting with parents
- */
- def mkNew(parents: List[Tree], self: ValDef, stats: List[Tree],
- npos: Position, cpos: Position): Tree =
- if (parents.isEmpty)
- mkNew(List(scalaAnyRefConstr), self, stats, npos, cpos)
- else if (parents.tail.isEmpty && stats.isEmpty) {
- // `Parsers.template` no longer differentiates tpts and their argss
- // e.g. `C()` will be represented as a single tree Apply(Ident(C), Nil)
- // instead of parents = Ident(C), argss = Nil as before
- // this change works great for things that are actually templates
- // but in this degenerate case we need to perform postprocessing
- val app = treeInfo.dissectApplied(parents.head)
- atPos(npos union cpos) { New(app.callee, app.argss) }
- } else {
- val x = tpnme.ANON_CLASS_NAME
- atPos(npos union cpos) {
- Block(
- List(
- atPos(cpos) {
- ClassDef(
- Modifiers(FINAL), x, Nil,
- mkTemplate(parents, self, NoMods, ListOfNil, stats, cpos.focus))
- }),
- atPos(npos) {
- New(
- Ident(x) setPos npos.focus,
- Nil)
- }
- )
- }
- }
-
def mkSyntheticParam(pname: TermName) =
ValDef(Modifiers(PARAM | SYNTHETIC), pname, TypeTree(), EmptyTree)
-
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 6a09f9f07c..52aa11cb40 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1445,7 +1445,7 @@ self =>
// The case still missed is unparenthesized single argument, like "x: Int => x + 1", which
// may be impossible to distinguish from a self-type and so remains an error. (See #1564)
def lhsIsTypedParamList() = t match {
- case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true
+ case Parens(xs) if xs.forall(isTypedParam) => true
case _ => false
}
if (in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)) {
@@ -1458,6 +1458,8 @@ self =>
parseOther
}
+ def isTypedParam(t: Tree) = t.isInstanceOf[Typed]
+
/** {{{
* Expr ::= implicit Id => Expr
* }}}
@@ -2704,8 +2706,7 @@ self =>
syntaxError("classes are not allowed to be virtual", skipIt = false)
}
val template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss, tstart)
- if (isInterface(mods1, template.body)) mods1 |= Flags.INTERFACE
- val result = ClassDef(mods1, name, tparams, template)
+ val result = gen.mkClassDef(mods1, name, tparams, template)
// Context bounds generate implicit parameters (part of the template) with types
// from tparams: we need to ensure these don't overlap
if (!classContextBounds.isEmpty)
@@ -2796,17 +2797,7 @@ self =>
// @S: pre template body cannot stub like post body can!
val (self, body) = templateBody(isPre = true)
if (in.token == WITH && (self eq emptyValDef)) {
- val earlyDefs: List[Tree] = body flatMap {
- case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred =>
- List(copyValDef(vdef)(mods = mods | Flags.PRESUPER))
- case tdef @ TypeDef(mods, name, tparams, rhs) =>
- deprecationWarning(tdef.pos.point, "early type members are deprecated. Move them to the regular body: the semantics are the same.")
- List(treeCopy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs))
- case stat if !stat.isEmpty =>
- syntaxError(stat.pos, "only concrete field definitions allowed in early object initialization section", skipIt = false)
- List()
- case _ => List()
- }
+ val earlyDefs: List[Tree] = body.map(ensureEarlyDef).filter(_.nonEmpty)
in.nextToken()
val parents = templateParents()
val (self1, body1) = templateBodyOpt(parenMeansSyntaxError = false)
@@ -2821,8 +2812,18 @@ self =>
}
}
- def isInterface(mods: Modifiers, body: List[Tree]): Boolean =
- mods.isTrait && (body forall treeInfo.isInterfaceMember)
+ def ensureEarlyDef(tree: Tree): Tree = tree match {
+ case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred =>
+ copyValDef(vdef)(mods = mods | Flags.PRESUPER)
+ case tdef @ TypeDef(mods, name, tparams, rhs) =>
+ deprecationWarning(tdef.pos.point, "early type members are deprecated. Move them to the regular body: the semantics are the same.")
+ treeCopy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs)
+ case stat if !stat.isEmpty =>
+ syntaxError(stat.pos, "only concrete field definitions allowed in early object initialization section", skipIt = false)
+ EmptyTree
+ case _ =>
+ EmptyTree
+ }
/** {{{
* ClassTemplateOpt ::= `extends' ClassTemplate | [[`extends'] TemplateBody]
@@ -2831,7 +2832,7 @@ self =>
* }}}
*/
def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = {
- val (parents0, self, body) = (
+ val (parents, self, body) = (
if (in.token == EXTENDS || in.token == SUBTYPE && mods.isTrait) {
in.nextToken()
template()
@@ -2842,26 +2843,21 @@ self =>
(List(), self, body)
}
)
- def anyrefParents() = {
- val caseParents = if (mods.isCase) List(productConstr, serializableConstr) else Nil
- parents0 ::: caseParents match {
- case Nil => atInPos(scalaAnyRefConstr) :: Nil
- case ps => ps
- }
- }
def anyvalConstructor() = (
// Not a well-formed constructor, has to be finished later - see note
// regarding AnyVal constructor in AddInterfaces.
DefDef(NoMods, nme.CONSTRUCTOR, Nil, ListOfNil, TypeTree(), Block(Nil, literalUnit))
)
- val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart
+ val parentPos = o2p(in.offset)
+ val tstart1 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart
- atPos(tstart0) {
+ atPos(tstart1) {
// Exclude only the 9 primitives plus AnyVal.
if (inScalaRootPackage && ScalaValueClassNames.contains(name))
- Template(parents0, self, anyvalConstructor :: body)
+ Template(parents, self, anyvalConstructor :: body)
else
- gen.mkTemplate(anyrefParents(), self, constrMods, vparamss, body, o2p(tstart))
+ gen.mkTemplate(gen.mkParents(mods, parents, parentPos),
+ self, constrMods, vparamss, body, o2p(tstart))
}
}
@@ -3012,19 +3008,23 @@ self =>
def refineStatSeq(): List[Tree] = checkNoEscapingPlaceholders {
val stats = new ListBuffer[Tree]
while (!isStatSeqEnd) {
- if (isDclIntro) { // don't IDE hook
- stats ++= joinComment(defOrDcl(in.offset, NoMods))
- } else if (!isStatSep) {
- syntaxErrorOrIncomplete(
- "illegal start of declaration"+
- (if (inFunReturnType) " (possible cause: missing `=' in front of current method body)"
- else ""), skipIt = true)
- }
+ stats ++= refineStat()
if (in.token != RBRACE) acceptStatSep()
}
stats.toList
}
+ def refineStat(): List[Tree] =
+ if (isDclIntro) { // don't IDE hook
+ joinComment(defOrDcl(in.offset, NoMods))
+ } else if (!isStatSep) {
+ syntaxErrorOrIncomplete(
+ "illegal start of declaration"+
+ (if (inFunReturnType) " (possible cause: missing `=' in front of current method body)"
+ else ""), skipIt = true)
+ Nil
+ } else Nil
+
/** overridable IDE hook for local definitions of blockStatSeq
* Here's an idea how to fill in start and end positions.
def localDef : List[Tree] = {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index ed694023d7..28e3217449 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -229,11 +229,7 @@ abstract class TreeBuilder {
}
/** Create block of statements `stats` */
- def makeBlock(stats: List[Tree]): Tree =
- if (stats.isEmpty) Literal(Constant(()))
- else if (!stats.last.isTerm) Block(stats, Literal(Constant(())))
- else if (stats.length == 1) stats.head
- else Block(stats.init, stats.last)
+ def makeBlock(stats: List[Tree]): Tree = gen.mkBlock(stats)
def makeFilter(tree: Tree, condition: Tree, scrutineeName: String): Tree = {
val cases = List(
@@ -520,8 +516,7 @@ abstract class TreeBuilder {
}
/** Create a tree representing the function type (argtpes) => restpe */
- def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
- AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe))
+ def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = gen.mkFunctionTypeTree(argtpes, restpe)
/** Append implicit parameter section if `contextBounds` nonempty */
def addEvidenceParams(owner: Name, vparamss: List[List[ValDef]], contextBounds: List[Tree]): List[List[ValDef]] = {
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index cbe4f69d25..2ec7e97ac5 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -174,7 +174,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
omittables ++= outerCandidatesForElision
val bodyOfOuterAccessor: Map[Symbol, DefDef] =
- defBuf collect { case dd: DefDef if outerCandidatesForElision(dd.symbol) => dd.symbol -> dd } toMap
+ defBuf.collect { case dd: DefDef if outerCandidatesForElision(dd.symbol) => dd.symbol -> dd }.toMap
// no point traversing further once omittables is empty, all candidates ruled out already.
object detectUsages extends Traverser {
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index 18a806e5ff..19888fa8d2 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -50,6 +50,10 @@ trait Parsers { self: Quasiquotes =>
def entryPoint: QuasiquoteParser => Tree
class QuasiquoteParser(source0: SourceFile) extends SourceFileParser(source0) {
+ def isHole: Boolean = isIdent && isHole(in.name)
+
+ def isHole(name: Name): Boolean = holeMap.contains(name)
+
override val treeBuilder = new ParserTreeBuilder {
// q"(..$xs)"
override def makeTupleTerm(trees: List[Tree], flattenUnary: Boolean): Tree =
@@ -61,9 +65,13 @@ trait Parsers { self: Quasiquotes =>
// q"{ $x }"
override def makeBlock(stats: List[Tree]): Tree = stats match {
- case (head @ Ident(name)) :: Nil if holeMap.contains(name) => Block(Nil, head)
+ case (head @ Ident(name)) :: Nil if isHole(name) => Block(Nil, head)
case _ => super.makeBlock(stats)
}
+
+ // tq"$a => $b"
+ override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
+ AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), argtpes :+ restpe)
}
import treeBuilder.{global => _, _}
@@ -79,7 +87,10 @@ trait Parsers { self: Quasiquotes =>
} else
super.caseClause()
- def isHole: Boolean = isIdent && holeMap.contains(in.name)
+ override def caseBlock(): Tree = super.caseBlock() match {
+ case Block(Nil, expr) => expr
+ case other => other
+ }
override def isAnnotation: Boolean = super.isAnnotation || (isHole && lookingAhead { isAnnotation })
@@ -105,13 +116,30 @@ trait Parsers { self: Quasiquotes =>
case AT =>
in.nextToken()
annot :: readAnnots(annot)
- case _ if isHole && lookingAhead { in.token == AT || isModifier || isDefIntro || isIdent} =>
+ case _ if isHole && lookingAhead { isAnnotation || isModifier || isDefIntro || isIdent || isStatSep || in.token == LPAREN } =>
val ann = Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(in.name.toString))))
in.nextToken()
ann :: readAnnots(annot)
case _ =>
Nil
}
+
+ override def refineStat(): List[Tree] =
+ if (isHole && !isDclIntro) {
+ val result = ValDef(NoMods, in.name, Ident(tpnme.QUASIQUOTE_REFINE_STAT), EmptyTree) :: Nil
+ in.nextToken()
+ result
+ } else super.refineStat()
+
+ override def ensureEarlyDef(tree: Tree) = tree match {
+ case Ident(name: TermName) if isHole(name) => ValDef(NoMods | Flag.PRESUPER, name, Ident(tpnme.QUASIQUOTE_EARLY_DEF), EmptyTree)
+ case _ => super.ensureEarlyDef(tree)
+ }
+
+ override def isTypedParam(tree: Tree) = super.isTypedParam(tree) || (tree match {
+ case Ident(name) if isHole(name) => true
+ case _ => false
+ })
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index b3ac1e293a..e20d98c0f1 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -92,10 +92,9 @@ trait Placeholders { self: Quasiquotes =>
}
}
- object AnnotPlaceholder {
- def unapply(tree: Tree): Option[(Tree, Location, Cardinality, List[Tree])] = tree match {
- case Apply(Select(New(Placeholder(tree, loc, card)), nme.CONSTRUCTOR), args) => Some(tree, loc, card, args)
- case _ => None
+ object AnnotPlaceholder extends HolePlaceholder {
+ def matching = {
+ case Apply(Select(New(Ident(name)), nme.CONSTRUCTOR), Nil) => name
}
}
@@ -113,6 +112,13 @@ trait Placeholders { self: Quasiquotes =>
}
}
+ object FunctionTypePlaceholder {
+ 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[Tree] = scrutinee match {
case Placeholder(tree, SymbolLocation, _) => Some(tree)
@@ -127,9 +133,16 @@ trait Placeholders { self: Quasiquotes =>
}
}
- object ClassPlaceholder {
- def unapply(tree: Tree): Option[Tree] = tree match {
- case ClassDef(_, _, _, _) => Some(tree)
+ object RefineStatPlaceholder {
+ def unapply(tree: Tree): Option[(Tree, Location, Cardinality)] = tree match {
+ case ValDef(_, Placeholder(tree, location, card), Ident(tpnme.QUASIQUOTE_REFINE_STAT), _) => Some((tree, location, card))
+ case _ => None
+ }
+ }
+
+ object EarlyDefPlaceholder {
+ def unapply(tree: Tree): Option[(Tree, Location, Cardinality)] = tree match {
+ case ValDef(_, Placeholder(tree, location, card), Ident(tpnme.QUASIQUOTE_EARLY_DEF), _) => Some((tree, location, card))
case _ => None
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
index ee99a5e280..1305e25240 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
@@ -41,11 +41,11 @@ abstract class Quasiquotes extends Parsers
lazy val universeTypes = new definitions.UniverseDependentTypes(universe)
def expandQuasiquote = {
- debug(s"\ncode to parse=\n$code\n")
+ debug(s"\ncode to parse:\n$code\n")
val tree = parse(code)
- debug(s"parsed tree\n=${tree}\n=${showRaw(tree)}\n")
+ debug(s"parsed:\n${showRaw(tree)}\n$tree\n")
val reified = reify(tree)
- debug(s"reified tree\n=${reified}\n=${showRaw(reified)}\n")
+ debug(s"reified tree:\n$reified\n")
reified
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 900237b00d..af4e34536c 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -7,7 +7,10 @@ import scala.reflect.internal.Flags._
trait Reifiers { self: Quasiquotes =>
import global._
- import global.build.SyntacticClassDef
+ import global.build.{SyntacticClassDef, SyntacticTraitDef, SyntacticModuleDef,
+ SyntacticDefDef, SyntacticValDef, SyntacticVarDef,
+ SyntacticBlock, SyntacticApplied, SyntacticTypeApplied,
+ SyntacticFunction, SyntacticNew}
import global.treeInfo._
import global.definitions._
import Cardinality._
@@ -35,13 +38,9 @@ trait Reifiers { self: Quasiquotes =>
reified
}
- override def reifyTree(tree: Tree): Tree = {
- val reified =
- reifyTreePlaceholder(tree) orElse
- reifyTreeSyntactically(tree)
- //println(s"reified ${showRaw(tree)} as $reified")
- reified
- }
+ override def reifyTree(tree: Tree): Tree =
+ reifyTreePlaceholder(tree) orElse
+ reifyTreeSyntactically(tree)
def reifyTreePlaceholder(tree: Tree): Tree = tree match {
case Placeholder(tree, TreeLocation(_), _) if isReifyingExpressions => tree
@@ -49,11 +48,49 @@ trait Reifiers { self: Quasiquotes =>
case Placeholder(tree, _, card @ Dot()) => c.abort(tree.pos, s"Can't $action with $card here")
case TuplePlaceholder(args) => reifyTuple(args)
case TupleTypePlaceholder(args) => reifyTupleType(args)
+ case FunctionTypePlaceholder(argtpes, restpe) => reifyFunctionType(argtpes, restpe)
case CasePlaceholder(tree, location, _) => reifyCase(tree, location)
- case ClassPlaceholder(tree) => reifyClass(tree)
+ case RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree)
+ case EarlyDefPlaceholder(tree, _, _) => reifyEarlyDef(tree)
case _ => EmptyTree
}
+ override def reifyTreeSyntactically(tree: Tree) = tree match {
+ 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) =>
+ reifyBuildCall(nme.SyntacticClassDef, mods, name, tparams, constrmods, vparamss,
+ earlyDefs, parents, selfdef, body)
+ case SyntacticModuleDef(mods, name, earlyDefs, parents, selfdef, body) =>
+ reifyBuildCall(nme.SyntacticModuleDef, 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) =>
+ reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs)
+ case SyntacticValDef(mods, name, tpt, rhs) =>
+ reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs)
+ case SyntacticVarDef(mods, name, tpt, rhs) =>
+ reifyBuildCall(nme.SyntacticVarDef, mods, name, tpt, rhs)
+ case SyntacticApplied(fun, argss) if argss.length > 1 =>
+ reifyBuildCall(nme.SyntacticApplied, fun, argss)
+ case SyntacticApplied(fun, argss @ (_ :+ (_ :+ Placeholder(_, _, DotDotDot)))) =>
+ reifyBuildCall(nme.SyntacticApplied, fun, argss)
+ case SyntacticTypeApplied(fun, targs) if targs.nonEmpty =>
+ reifyBuildCall(nme.SyntacticTypeApplied, fun, targs)
+ case SyntacticFunction(args, body) =>
+ reifyBuildCall(nme.SyntacticFunction, args, body)
+ case Block(stats, last) =>
+ reifyBuildCall(nme.SyntacticBlock, stats :+ last)
+ // 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 _ =>
+ super.reifyTreeSyntactically(tree)
+ }
+
override def reifyName(name: Name): Tree = name match {
case Placeholder(tree, location, _) =>
if (holesHaveTypes && !(location.tpe <:< nameType)) c.abort(tree.pos, s"$nameType expected but ${location.tpe} found")
@@ -70,26 +107,30 @@ trait Reifiers { self: Quasiquotes =>
def reifyTuple(args: List[Tree]) = args match {
case Nil => reify(Literal(Constant(())))
case List(hole @ Placeholder(_, _, NoDot)) => reify(hole)
- case List(Placeholder(_, _, _)) => reifyBuildCall(nme.TupleN, args)
+ case List(Placeholder(_, _, _)) => reifyBuildCall(nme.SyntacticTuple, args)
// in a case we only have one element tuple without
// any cardinality annotations this means that this is
// just an expression wrapped in parentheses
case List(other) => reify(other)
- case _ => reifyBuildCall(nme.TupleN, args)
+ 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(_, _, NoDot)) => reify(hole)
- case List(Placeholder(_, _, _)) => reifyBuildCall(nme.TupleTypeN, args)
+ case List(Placeholder(_, _, _)) => reifyBuildCall(nme.SyntacticTupleType, args)
case List(other) => reify(other)
- case _ => reifyBuildCall(nme.TupleTypeN, args)
+ case _ => reifyBuildCall(nme.SyntacticTupleType, args)
}
- def reifyClass(tree: Tree) = {
- val SyntacticClassDef(mods, name, tparams, constrmods, argss, parents, selfval, body) = tree
- reifyBuildCall(nme.SyntacticClassDef, mods, name, tparams, constrmods, argss, parents, selfval, body)
- }
+ def reifyFunctionType(argtpes: List[Tree], restpe: Tree) =
+ reifyBuildCall(nme.SyntacticFunctionType, argtpes, restpe)
+
+ def reifyRefineStat(tree: Tree) = tree
+
+ def reifyEarlyDef(tree: Tree) = tree
+
+ def reifyAnnotation(tree: Tree) = tree
/** Splits list into a list of groups where subsequent elements are considered
* similar by the corresponding function.
@@ -143,15 +184,33 @@ trait Reifiers { self: Quasiquotes =>
override def reifyList(xs: List[Any]): Tree = reifyMultiCardinalityList(xs) {
case Placeholder(tree, _, DotDot) => tree
case CasePlaceholder(tree, _, DotDot) => tree
+ case RefineStatPlaceholder(tree, _, DotDot) => reifyRefineStat(tree)
+ case EarlyDefPlaceholder(tree, _, DotDot) => reifyEarlyDef(tree)
case List(Placeholder(tree, _, DotDotDot)) => tree
} {
reify(_)
}
- def reifyAnnotList(annots: List[Tree]): Tree
+ def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) {
+ case AnnotPlaceholder(tree, _, DotDot) => reifyAnnotation(tree)
+ } {
+ case AnnotPlaceholder(tree, UnknownLocation | TreeLocation(_), NoDot) => reifyAnnotation(tree)
+ case other => reify(other)
+ }
- def ensureNoExplicitFlags(m: Modifiers, pos: Position) =
- if ((m.flags & ExplicitFlags) != 0L) c.abort(pos, s"Can't $action modifiers together with flags, consider merging flags into modifiers")
+ // 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))
@@ -167,19 +226,10 @@ trait Reifiers { self: Quasiquotes =>
def isReifyingExpressions = true
override def reifyTreeSyntactically(tree: Tree): Tree = tree match {
- case Block(stats, p @ Placeholder(_, _, _)) => reifyBuildCall(nme.Block, stats :+ p)
- case Apply(f, List(Placeholder(argss, _, DotDotDot))) => reifyCallWithArgss(f, argss)
- case RefTree(qual, SymbolPlaceholder(tree)) => mirrorBuildCall(nme.RefTree, reify(qual), tree)
- case _ => super.reifyTreeSyntactically(tree)
- }
-
- def reifyCallWithArgss(f: Tree, argss: Tree) = {
- val f1 = reifyTree(f)
- val foldLeftF1 = Apply(TypeApply(Select(argss, nme.foldLeft), List(Select(u, tpnme.Tree))), List(f1))
- val uDotApply = Function(
- List(gen.mkSyntheticParam(nme.x_1), gen.mkSyntheticParam(nme.x_2)),
- Apply(Select(u, nme.Apply), List(Ident(nme.x_1), Ident(nme.x_2))))
- Apply(foldLeftF1, List(uDotApply))
+ case RefTree(qual, SymbolPlaceholder(tree)) =>
+ mirrorBuildCall(nme.RefTree, reify(qual), tree)
+ case _ =>
+ super.reifyTreeSyntactically(tree)
}
override def reifyMultiCardinalityList[T](xs: List[T])(fill: PartialFunction[T, Tree])(fallback: T => Tree): Tree = xs match {
@@ -193,61 +243,47 @@ trait Reifiers { self: Quasiquotes =>
tail.foldLeft[Tree](reifyGroup(head)) { (tree, lst) => Apply(Select(tree, nme.PLUSPLUS), List(reifyGroup(lst))) }
}
- override def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) {
- case AnnotPlaceholder(tree, _, DotDot, args) =>
- val x: TermName = c.freshName()
- val xToAnnotationCtor = Function(
- List(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree)),
- mirrorBuildCall(nme.mkAnnotationCtor, Ident(x), reify(args)))
- Apply(Select(tree, nme.map), List(xToAnnotationCtor))
- } {
- case AnnotPlaceholder(tree, _: TreeLocation, _, args) =>
- mirrorBuildCall(nme.mkAnnotationCtor, tree, reify(args))
- case other => reify(other)
- }
-
- override def reifyModifiers(m: Modifiers) = {
- val (modsPlaceholders, annots) = m.annotations.partition {
- case ModsPlaceholder(_, _, _) => true
- case _ => false
- }
- val (mods, flags) = modsPlaceholders.map {
- case ModsPlaceholder(tree, location, card) => (tree, location)
- }.partition { case (tree, location) =>
- location match {
- case ModsLocation => true
- case FlagsLocation => false
- case _ => c.abort(tree.pos, s"$flagsType or $modsType expected but ${tree.tpe} found")
+ 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(tree, location, card) => (tree, location)
+ }.partition { case (tree, location) =>
+ location match {
+ case ModsLocation => true
+ case FlagsLocation => false
+ case _ => c.abort(tree.pos, s"$flagsType or $modsType expected but ${tree.tpe} found")
+ }
+ }
+ mods match {
+ case (tree, _) :: Nil =>
+ if (flags.nonEmpty) c.abort(flags(0)._1.pos, "Can't splice flags together with modifiers, consider merging flags into modifiers")
+ if (annots.nonEmpty) c.abort(tree.pos, "Can't splice modifiers together with annotations, consider merging annotations into modifiers")
+ ensureNoExplicitFlags(m, tree.pos)
+ tree
+ case _ :: (second, _) :: Nil =>
+ c.abort(second.pos, "Can't splice multiple modifiers, consider merging them into a single modifiers instance")
+ case _ =>
+ val baseFlags = reifyFlags(m.flags)
+ val reifiedFlags = flags.foldLeft[Tree](baseFlags) { case (flag, (tree, _)) => Apply(Select(flag, nme.OR), List(tree)) }
+ mirrorFactoryCall(nme.Modifiers, reifiedFlags, reify(m.privateWithin), reifyAnnotList(annots))
}
}
- mods match {
- case (tree, _) :: Nil =>
- if (flags.nonEmpty) c.abort(flags(0)._1.pos, "Can't splice flags together with modifiers, consider merging flags into modifiers")
- if (annots.nonEmpty) c.abort(tree.pos, "Can't splice modifiers together with annotations, consider merging annotations into modifiers")
- ensureNoExplicitFlags(m, tree.pos)
- tree
- case _ :: (second, _) :: Nil =>
- c.abort(second.pos, "Can't splice multiple modifiers, consider merging them into a single modifiers instance")
- case _ =>
- val baseFlags = reifyBuildCall(nme.flagsFromBits, m.flags)
- val reifiedFlags = flags.foldLeft[Tree](baseFlags) { case (flag, (tree, _)) => Apply(Select(flag, nme.OR), List(tree)) }
- mirrorFactoryCall(nme.Modifiers, reifiedFlags, reify(m.privateWithin), reifyAnnotList(annots))
- }
- }
+
+ override def reifyRefineStat(tree: Tree) = mirrorBuildCall(nme.mkRefineStat, tree)
+
+ override def reifyEarlyDef(tree: Tree) = mirrorBuildCall(nme.mkEarlyDef, tree)
+
+ override def reifyAnnotation(tree: Tree) = mirrorBuildCall(nme.mkAnnotation, tree)
}
class UnapplyReifier extends Reifier {
def isReifyingExpressions = false
- override def reifyTreeSyntactically(tree: Tree): Tree = tree match {
- case treeInfo.Applied(fun, Nil, argss) if fun != tree && !tree.isInstanceOf[AppliedTypeTree] =>
- reifyBuildCall(nme.Applied, fun, argss)
- case treeInfo.Applied(fun, targs, argss) if fun != tree & !tree.isInstanceOf[AppliedTypeTree] =>
- mirrorBuildCall(nme.Applied, reifyBuildCall(nme.TypeApplied, fun, targs), reifyList(argss))
- case _ =>
- super.reifyTreeSyntactically(tree)
- }
-
override def scalaFactoryCall(name: String, args: Tree*): Tree =
call("scala." + name, args: _*)
@@ -261,30 +297,20 @@ trait Reifiers { self: Quasiquotes =>
mkList(xs.map(fallback))
}
- override def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) {
- case AnnotPlaceholder(tree, _, DotDot, Nil) => tree
- } {
- case AnnotPlaceholder(tree, _, NoDot, Nil) => tree
- case AnnotPlaceholder(tree, _, NoDot, args) =>
- val selectCONSTRUCTOR = Apply(Select(u, nme.Select), List(Apply(Select(u, nme.New), List(tree)), Select(Select(u, nme.nmeNme), nme.nmeCONSTRUCTOR)))
- Apply(Select(u, nme.Apply), List(selectCONSTRUCTOR, reify(args)))
- case other =>
- reify(other)
- }
-
- override def reifyModifiers(m: Modifiers) = {
- val mods = m.annotations.collect { case ModsPlaceholder(tree, _, _) => tree }
- mods match {
- case tree :: Nil =>
- if (m.annotations.length != 1) c.abort(tree.pos, "Can't extract modifiers together with annotations, consider extracting just modifiers")
- ensureNoExplicitFlags(m, tree.pos)
- tree
- case _ :: second :: rest =>
- c.abort(second.pos, "Can't extract multiple modifiers together, consider extracting a single modifiers instance")
- case Nil =>
- mirrorFactoryCall(nme.Modifiers, reifyBuildCall(nme.FlagsAsBits, m.flags),
- reify(m.privateWithin), reifyAnnotList(m.annotations))
+ override def reifyModifiers(m: Modifiers) =
+ if (m == NoMods) super.reifyModifiers(m)
+ else {
+ val mods = m.annotations.collect { case ModsPlaceholder(tree, _, _) => tree }
+ mods match {
+ case tree :: Nil =>
+ if (m.annotations.length != 1) c.abort(tree.pos, "Can't extract modifiers together with annotations, consider extracting just modifiers")
+ ensureNoExplicitFlags(m, tree.pos)
+ tree
+ case _ :: second :: rest =>
+ c.abort(second.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))
+ }
}
- }
}
-} \ No newline at end of file
+}