summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDen Shabalin <den.shabalin@gmail.com>2013-08-29 17:52:02 +0200
committerDen Shabalin <den.shabalin@gmail.com>2013-09-05 14:39:07 +0200
commitf9d5e3d4e8cca61ee75072ab13c2935061a1850e (patch)
treec96fe138c69a5d49f9485a1424b9b72b41282c65
parentc637cfc01cb8258d47094fc79313a76bfdd5d268 (diff)
downloadscala-f9d5e3d4e8cca61ee75072ab13c2935061a1850e.tar.gz
scala-f9d5e3d4e8cca61ee75072ab13c2935061a1850e.tar.bz2
scala-f9d5e3d4e8cca61ee75072ab13c2935061a1850e.zip
SI-7196 add support for refineStat splicing and extraction
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala20
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala7
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala6
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala28
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala3
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala12
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala6
-rw-r--r--test/files/scalacheck/quasiquotes/TypeConstructionProps.scala5
-rw-r--r--test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala5
9 files changed, 67 insertions, 25 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index e5101a27a8..158fa147b6 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -3012,19 +3012,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/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index 18a806e5ff..d04b65545d 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -112,6 +112,13 @@ trait Parsers { self: Quasiquotes =>
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()
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index b3ac1e293a..5d7edcd75e 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -127,9 +127,9 @@ 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
}
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index e9c56f1191..d4bc2d67c6 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -35,13 +35,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
@@ -50,10 +46,18 @@ trait Reifiers { self: Quasiquotes =>
case TuplePlaceholder(args) => reifyTuple(args)
case TupleTypePlaceholder(args) => reifyTupleType(args)
case CasePlaceholder(tree, location, _) => reifyCase(tree, location)
- case ClassPlaceholder(tree) => reifyClass(tree)
+ case RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree)
case _ => EmptyTree
}
+ override def reifyTreeSyntactically(tree: Tree) = tree match {
+ case SyntacticClassDef(mods, name, tparams, constrmods, vparamss, parents, selfdef, body) =>
+ reifyBuildCall(nme.SyntacticClassDef, mods, name, tparams, constrmods, vparamss,
+ parents, selfdef, body)
+ 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")
@@ -86,10 +90,7 @@ trait Reifiers { self: Quasiquotes =>
case _ => reifyBuildCall(nme.TupleTypeN, 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 reifyRefineStat(tree: Tree) = tree
/** Splits list into a list of groups where subsequent elements are considered
* similar by the corresponding function.
@@ -143,6 +144,7 @@ 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 List(Placeholder(tree, _, DotDotDot)) => tree
} {
reify(_)
@@ -236,6 +238,8 @@ trait Reifiers { self: Quasiquotes =>
mirrorFactoryCall(nme.Modifiers, reifiedFlags, reify(m.privateWithin), reifyAnnotList(annots))
}
}
+
+ override def reifyRefineStat(tree: Tree) = mirrorBuildCall(nme.mkRefineStat, tree)
}
class UnapplyReifier extends Reifier {
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index 394cbf55c5..03980f5f0a 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -76,6 +76,9 @@ private[reflect] trait BuildUtils { self: Universe =>
def mkAnnotation(tree: Tree, args: List[Tree]): Tree
+ def mkRefineStat(stat: Tree): Tree
+
+ def mkRefineStat(stats: List[Tree]): List[Tree]
val FlagsRepr: FlagsReprExtractor
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index 73b7b79fdb..208a61d9d3 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -76,6 +76,18 @@ trait BuildUtils { self: SymbolTable =>
case _ => throw new IllegalArgumentException(s"Tree ${showRaw(tree)} isn't a correct representation of annotation, consider passing Ident as a first argument")
}
+ def mkRefineStat(stat: Tree): Tree = {
+ stat match {
+ case dd: DefDef => require(dd.rhs.isEmpty, "can't use DefDef with non-empty body as refine stat")
+ case vd: ValDef => require(vd.rhs.isEmpty, "can't use ValDef with non-empty rhs as refine stat")
+ case td: TypeDef =>
+ case _ => throw new IllegalArgumentException(s"not legal refine stat: $stat")
+ }
+ stat
+ }
+
+ def mkRefineStat(stats: List[Tree]): List[Tree] = stats.map(mkRefineStat)
+
object FlagsRepr extends FlagsReprExtractor {
def apply(bits: Long): FlagSet = bits
def unapply(flags: Long): Some[Long] = Some(flags)
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 4811010815..eb24706f29 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -247,8 +247,9 @@ trait StdNames {
final val Quasiquote: NameType = "Quasiquote"
// quasiquote-specific names
- final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$"
- final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
+ final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$"
+ final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
+ final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
// Annotation simple names, used in Namer
final val BeanPropertyAnnot: NameType = "BeanProperty"
@@ -682,6 +683,7 @@ trait StdNames {
val materializeTypeTag: NameType = "materializeTypeTag"
val moduleClass : NameType = "moduleClass"
val mkAnnotation: NameType = "mkAnnotation"
+ val mkRefineStat: NameType = "mkRefineStat"
val ne: NameType = "ne"
val newArray: NameType = "newArray"
val newFreeTerm: NameType = "newFreeTerm"
diff --git a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala
index 535ed8ecbf..459d733733 100644
--- a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala
@@ -22,4 +22,9 @@ object TypeConstructionProps extends QuasiquoteProperties("type construction")
assert(tq"(..$ts)" ≈ tq"Tuple2[t1, t2]")
assert(tq"(t0, ..$ts)" ≈ tq"Tuple3[t0, t1, t2]")
}
+
+ property("refined type") = test {
+ val stats = q"def foo" :: q"val x: Int" :: q"type Y = String" :: Nil
+ assert(tq"T { ..$stats }" ≈ tq"T { def foo; val x: Int; type Y = String }")
+ }
} \ No newline at end of file
diff --git a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala
index 6ab699d4f0..5c919e55cb 100644
--- a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala
@@ -26,4 +26,9 @@ object TypeDeconstructionProps extends QuasiquoteProperties("type deconstruction
val tq"($head, ..$tail)" = tq"(t0, t1, t2)"
assert(head ≈ tq"t0" && tail ≈ List(tq"t1", tq"t2"))
}
+
+ property("refined type") = test {
+ val tq"T { ..$stats }" = tq"T { def foo; val x: Int; type Y = String }"
+ assert(stats ≈ (q"def foo" :: q"val x: Int" :: q"type Y = String" :: Nil))
+ }
} \ No newline at end of file