diff options
author | Den Shabalin <den.shabalin@gmail.com> | 2013-08-29 17:52:02 +0200 |
---|---|---|
committer | Den Shabalin <den.shabalin@gmail.com> | 2013-09-05 14:39:07 +0200 |
commit | f9d5e3d4e8cca61ee75072ab13c2935061a1850e (patch) | |
tree | c96fe138c69a5d49f9485a1424b9b72b41282c65 | |
parent | c637cfc01cb8258d47094fc79313a76bfdd5d268 (diff) | |
download | scala-f9d5e3d4e8cca61ee75072ab13c2935061a1850e.tar.gz scala-f9d5e3d4e8cca61ee75072ab13c2935061a1850e.tar.bz2 scala-f9d5e3d4e8cca61ee75072ab13c2935061a1850e.zip |
SI-7196 add support for refineStat splicing and extraction
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 |