summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDen Shabalin <den.shabalin@gmail.com>2013-09-20 13:32:38 +0200
committerDen Shabalin <den.shabalin@gmail.com>2013-10-14 13:30:49 +0200
commit3a148cd0cd404751095cd1c5aca09ad8923c51ab (patch)
tree2ad3cbc115fe0ca270d476171b41519c483ba201
parentd7aae49f8ff7ccc6c1a588fc116e8c37fdb9e849 (diff)
downloadscala-3a148cd0cd404751095cd1c5aca09ad8923c51ab.tar.gz
scala-3a148cd0cd404751095cd1c5aca09ad8923c51ab.tar.bz2
scala-3a148cd0cd404751095cd1c5aca09ad8923c51ab.zip
SI-6841 SI-6657 add support for packages into quasiquotes and toolbox
In order to implement this a new parser entry point `parseStatsOrPackages` that augments current parseStats with ability to parse "package name { ... }" syntax.
-rw-r--r--src/compiler/scala/reflect/macros/contexts/Parsers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala12
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala2
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala9
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala7
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala19
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala16
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala29
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala17
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala6
-rw-r--r--test/files/neg/quasiquotes-syntax-error-position.check4
-rw-r--r--test/files/run/toolbox_parse_package.check8
-rw-r--r--test/files/run/toolbox_parse_package.scala9
-rw-r--r--test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala50
-rw-r--r--test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala24
15 files changed, 187 insertions, 27 deletions
diff --git a/src/compiler/scala/reflect/macros/contexts/Parsers.scala b/src/compiler/scala/reflect/macros/contexts/Parsers.scala
index ae6488b5a8..88cfea8157 100644
--- a/src/compiler/scala/reflect/macros/contexts/Parsers.scala
+++ b/src/compiler/scala/reflect/macros/contexts/Parsers.scala
@@ -11,7 +11,7 @@ trait Parsers {
val sreporter = new StoreReporter()
val unit = new CompilationUnit(newSourceFile(code, "<macro>")) { override def reporter = sreporter }
val parser = newUnitParser(unit)
- val tree = gen.mkTreeOrBlock(parser.parseStats())
+ val tree = gen.mkTreeOrBlock(parser.parseStatsOrPackages())
sreporter.infos.foreach {
case sreporter.Info(pos, msg, sreporter.ERROR) => throw ParseException(pos, msg)
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index b1fcb67a9f..508453d5b2 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -346,9 +346,10 @@ self =>
*/
def parse(): Tree = parseRule(_.parseStartRule())
- /** This is alternative entry point for repl, script runner, toolbox and quasiquotes.
+ /** These are alternative entry points for repl, script runner, toolbox and parsing in macros.
*/
def parseStats(): List[Tree] = parseRule(_.templateStats())
+ def parseStatsOrPackages(): List[Tree] = parseRule(_.templateOrTopStatSeq())
/** This is the parse entry point for code which is not self-contained, e.g.
* a script which is a series of template statements. They will be
@@ -2743,10 +2744,9 @@ self =>
*/
def packageObjectDef(start: Offset): PackageDef = {
val defn = objectDef(in.offset, NoMods)
- val module = copyModuleDef(defn)(name = nme.PACKAGEkw)
- val pid = atPos(o2p(defn.pos.start))(Ident(defn.name))
-
- makePackaging(start, pid, module :: Nil)
+ val pidPos = o2p(defn.pos.startOrPoint)
+ val pkgPos = r2p(start, pidPos.point)
+ gen.mkPackageObject(defn, pidPos, pkgPos)
}
def packageOrPackageObject(start: Offset): Tree = (
if (in.token == OBJECT)
@@ -2989,6 +2989,8 @@ self =>
statement(InTemplate) :: Nil
}
+ def templateOrTopStatSeq(): List[Tree] = statSeq(templateStat.orElse(topStat))
+
/** {{{
* RefineStatSeq ::= RefineStat {semi RefineStat}
* RefineStat ::= Dcl
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index fdc2613810..9e5a97270d 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -280,7 +280,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
def parse(code: String): Tree = {
reporter.reset()
- val tree = gen.mkTreeOrBlock(newUnitParser(code, "<toolbox>").parseStats())
+ val tree = gen.mkTreeOrBlock(newUnitParser(code, "<toolbox>").parseStatsOrPackages())
throwIfErrors()
tree
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index 5a1a25cfa1..7abf8b9964 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -140,11 +140,18 @@ trait Parsers { self: Quasiquotes =>
case Ident(name) if isHole(name) => true
case _ => false
})
+
+ override def topStat = super.topStat.orElse {
+ case _ if isHole =>
+ val stats = ValDef(NoMods, in.name, Ident(tpnme.QUASIQUOTE_PACKAGE_STAT), EmptyTree) :: Nil
+ in.nextToken()
+ stats
+ }
}
}
object TermParser extends Parser {
- def entryPoint = { parser => gen.mkTreeOrBlock(parser.templateStats()) }
+ def entryPoint = { parser => gen.mkTreeOrBlock(parser.templateOrTopStatSeq()) }
}
object TypeParser extends Parser {
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index c2b219ee31..d74350cad8 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -146,4 +146,11 @@ trait Placeholders { self: Quasiquotes =>
case _ => None
}
}
+
+ object PackageStatPlaceholder {
+ def unapply(tree: Tree): Option[(Tree, Location, Cardinality)] = tree match {
+ case ValDef(NoMods, Placeholder(tree, location, card), Ident(tpnme.QUASIQUOTE_PACKAGE_STAT), EmptyTree) => Some((tree, location, card))
+ case _ => None
+ }
+ }
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 18999e8267..6f5bf88549 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -7,10 +7,8 @@ import scala.reflect.internal.Flags._
trait Reifiers { self: Quasiquotes =>
import global._
- import global.build.{SyntacticClassDef, SyntacticTraitDef, SyntacticModuleDef,
- SyntacticDefDef, SyntacticValDef, SyntacticVarDef,
- SyntacticBlock, SyntacticApplied, SyntacticTypeApplied,
- SyntacticFunction, SyntacticNew, SyntacticAssign}
+ import global.build.{Select => _, Ident => _, _}
+ import global.treeInfo._
import global.definitions._
import Cardinality._
import universeTypes._
@@ -51,6 +49,7 @@ trait Reifiers { self: Quasiquotes =>
case CasePlaceholder(tree, location, _) => reifyCase(tree, location)
case RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree)
case EarlyDefPlaceholder(tree, _, _) => reifyEarlyDef(tree)
+ case PackageStatPlaceholder(tree, _, _) => reifyPackageStat(tree)
case _ => EmptyTree
}
@@ -60,8 +59,10 @@ trait Reifiers { self: Quasiquotes =>
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 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) =>
@@ -131,6 +132,8 @@ trait Reifiers { self: Quasiquotes =>
def reifyAnnotation(tree: Tree) = tree
+ def reifyPackageStat(tree: Tree) = tree
+
/** Splits list into a list of groups where subsequent elements are considered
* similar by the corresponding function.
*
@@ -185,6 +188,8 @@ trait Reifiers { self: Quasiquotes =>
case CasePlaceholder(tree, _, DotDot) => tree
case RefineStatPlaceholder(tree, _, DotDot) => reifyRefineStat(tree)
case EarlyDefPlaceholder(tree, _, DotDot) => reifyEarlyDef(tree)
+ case PackageStatPlaceholder(tree, _, DotDot) => reifyPackageStat(tree)
+
case List(Placeholder(tree, _, DotDotDot)) => tree
} {
reify(_)
@@ -280,6 +285,8 @@ trait Reifiers { self: Quasiquotes =>
override def reifyEarlyDef(tree: Tree) = mirrorBuildCall(nme.mkEarlyDef, tree)
override def reifyAnnotation(tree: Tree) = mirrorBuildCall(nme.mkAnnotation, tree)
+
+ override def reifyPackageStat(tree: Tree) = mirrorBuildCall(nme.mkPackageStat, tree)
}
class UnapplyReifier extends Reifier {
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index 551c27bf9c..df126bed45 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -80,6 +80,10 @@ private[reflect] trait BuildUtils { self: Universe =>
def mkRefineStat(stats: List[Tree]): List[Tree]
+ def mkPackageStat(stat: Tree): Tree
+
+ def mkPackageStat(stats: List[Tree]): List[Tree]
+
def mkEarlyDef(defn: Tree): Tree
def mkEarlyDef(defns: List[Tree]): List[Tree]
@@ -133,14 +137,22 @@ private[reflect] trait BuildUtils { self: Universe =>
List[Tree], List[Tree], ValDef, List[Tree])]
}
- val SyntacticModuleDef: SyntacticModuleDefExtractor
+ val SyntacticObjectDef: SyntacticObjectDefExtractor
- trait SyntacticModuleDefExtractor {
+ trait SyntacticObjectDefExtractor {
def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree],
parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree
def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])]
}
+ val SyntacticPackageObjectDef: SyntacticPackageObjectDefExtractor
+
+ trait SyntacticPackageObjectDefExtractor {
+ def apply(name: TermName, earlyDefs: List[Tree],
+ parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree
+ def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])]
+ }
+
val SyntacticTuple: SyntacticTupleExtractor
val SyntacticTupleType: SyntacticTupleExtractor
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index 951efd90ed..a09715ec7c 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -98,6 +98,18 @@ trait BuildUtils { self: SymbolTable =>
def mkRefineStat(stats: List[Tree]): List[Tree] = stats.map(mkRefineStat)
+ def mkPackageStat(stat: Tree): Tree = {
+ stat match {
+ case cd: ClassDef =>
+ case md: ModuleDef =>
+ case pd: PackageDef =>
+ case _ => throw new IllegalArgumentException(s"not legal package stat: $stat")
+ }
+ stat
+ }
+
+ def mkPackageStat(stats: List[Tree]): List[Tree] = stats.map(mkPackageStat)
+
object ScalaDot extends ScalaDotExtractor {
def apply(name: Name): Tree = gen.scalaDot(name)
def unapply(tree: Tree): Option[Name] = tree match {
@@ -110,7 +122,7 @@ trait BuildUtils { self: SymbolTable =>
case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred =>
copyValDef(vdef)(mods = mods | PRESUPER)
case tdef @ TypeDef(mods, _, _, _) =>
- copyTypeDef(tdef)(mods = mods | PRESUPER)
+ copyTypeDef(tdef)(mods = mods | PRESUPER)
case _ =>
throw new IllegalArgumentException(s"not legal early def: $defn")
}
@@ -244,7 +256,7 @@ trait BuildUtils { self: SymbolTable =>
}
}
- object SyntacticModuleDef extends SyntacticModuleDefExtractor {
+ object SyntacticObjectDef extends SyntacticObjectDefExtractor {
def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree],
parents: List[Tree], selfdef: ValDef, body: List[Tree]) =
ModuleDef(mods, name, gen.mkTemplate(parents, selfdef, NoMods, Nil, earlyDefs ::: body))
@@ -257,6 +269,19 @@ trait BuildUtils { self: SymbolTable =>
}
}
+ object SyntacticPackageObjectDef extends SyntacticPackageObjectDefExtractor {
+ def apply(name: TermName, earlyDefs: List[Tree],
+ parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree =
+ gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfdef, body))
+
+ def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match {
+ case PackageDef(Ident(name: TermName), List(SyntacticObjectDef(NoMods, nme.PACKAGEkw, earlyDefs, parents, selfdef, body))) =>
+ Some((name, earlyDefs, parents, selfdef, body))
+ case _ =>
+ None
+ }
+ }
+
private trait ScalaMemberRef {
val symbols: Seq[Symbol]
def result(name: Name): Option[Symbol] =
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index af26253802..7cfe194fd1 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -247,11 +247,12 @@ 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_FUNCTION: NameType = "$quasiquote$function$"
- final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
- final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$"
+ final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$"
+ final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
+ final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$"
+ final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
+ final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$"
+ final val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$"
// Annotation simple names, used in Namer
final val BeanPropertyAnnot: NameType = "BeanProperty"
@@ -587,8 +588,9 @@ trait StdNames {
val SyntacticClassDef: NameType = "SyntacticClassDef"
val SyntacticDefDef: NameType = "SyntacticDefDef"
val SyntacticFunction: NameType = "SyntacticFunction"
- val SyntacticFunctionType: NameType= "SyntacticFunctionType"
- val SyntacticModuleDef: NameType = "SyntacticModuleDef"
+ val SyntacticFunctionType: NameType = "SyntacticFunctionType"
+ val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef"
+ val SyntacticObjectDef: NameType = "SyntacticObjectDef"
val SyntacticNew: NameType = "SyntacticNew"
val SyntacticTraitDef: NameType = "SyntacticTraitDef"
val SyntacticTuple: NameType = "SyntacticTuple"
@@ -683,6 +685,7 @@ trait StdNames {
val mkAnnotation: NameType = "mkAnnotation"
val mkRefineStat: NameType = "mkRefineStat"
val mkEarlyDef: NameType = "mkEarlyDef"
+ val mkPackageStat: NameType = "mkPackageStat"
val ne: NameType = "ne"
val newArray: NameType = "newArray"
val newFreeTerm: NameType = "newFreeTerm"
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index 720d8bfe4a..cf7c729a6a 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -448,4 +448,10 @@ abstract class TreeGen extends macros.TreeBuilder {
case _ =>
Assign(lhs, rhs)
}
+
+ def mkPackageObject(defn: ModuleDef, pidPos: Position = NoPosition, pkgPos: Position = NoPosition) = {
+ val module = copyModuleDef(defn)(name = nme.PACKAGEkw)
+ val pid = atPos(pidPos)(Ident(defn.name))
+ atPos(pkgPos)(PackageDef(pid, module :: Nil))
+ }
}
diff --git a/test/files/neg/quasiquotes-syntax-error-position.check b/test/files/neg/quasiquotes-syntax-error-position.check
index 3bd813b1bb..25e5b8d75a 100644
--- a/test/files/neg/quasiquotes-syntax-error-position.check
+++ b/test/files/neg/quasiquotes-syntax-error-position.check
@@ -10,9 +10,9 @@ quasiquotes-syntax-error-position.scala:7: error: '}' expected but end of quote
quasiquotes-syntax-error-position.scala:8: error: '.' expected but splicee found.
q"import $t $t"
^
-quasiquotes-syntax-error-position.scala:9: error: illegal start of definition
+quasiquotes-syntax-error-position.scala:9: error: '{' expected but end of quote found.
q"package p"
- ^
+ ^
quasiquotes-syntax-error-position.scala:10: error: ';' expected but '@' found.
q"foo@$a"
^
diff --git a/test/files/run/toolbox_parse_package.check b/test/files/run/toolbox_parse_package.check
new file mode 100644
index 0000000000..46465980a0
--- /dev/null
+++ b/test/files/run/toolbox_parse_package.check
@@ -0,0 +1,8 @@
+package foo {
+ object bar extends scala.AnyRef {
+ def <init>() = {
+ super.<init>();
+ ()
+ }
+ }
+}
diff --git a/test/files/run/toolbox_parse_package.scala b/test/files/run/toolbox_parse_package.scala
new file mode 100644
index 0000000000..62412a50d7
--- /dev/null
+++ b/test/files/run/toolbox_parse_package.scala
@@ -0,0 +1,9 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.{universe => ru}
+import scala.reflect.runtime.{currentMirror => cm}
+import scala.tools.reflect.ToolBox
+
+object Test extends App {
+ val toolbox = cm.mkToolBox()
+ println(toolbox.parse("package foo { object bar }"))
+} \ No newline at end of file
diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
index ced479aef5..e8ddb4b72a 100644
--- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
@@ -13,6 +13,7 @@ object DefinitionConstructionProps
with TraitConstruction
with TypeDefConstruction
with ValDefConstruction
+ with PackageConstruction
trait ClassConstruction { self: QuasiquoteProperties =>
val anyRef = ScalaDot(TypeName("AnyRef"))
@@ -292,4 +293,53 @@ trait MethodConstruction { self: QuasiquoteProperties =>
val a = q"new Foo(a)(b)"
assertEqAst(q"@$a def foo", "@Foo(a)(b) def foo")
}
+}
+
+trait PackageConstruction { self: QuasiquoteProperties =>
+ property("splice select into package name") = test {
+ val name = q"foo.bar"
+ assertEqAst(q"package $name { }", "package foo.bar { }")
+ }
+
+ property("splce name into package name") = test{
+ val name = TermName("bippy")
+ assertEqAst(q"package $name { }", "package bippy { }")
+ }
+
+ property("splice members into package body") = test {
+ val members = q"class C" :: q"object O" :: Nil
+ assertEqAst(q"package foo { ..$members }", "package foo { class C; object O }")
+ }
+
+ property("splice illegal members into package body") = test {
+ val f = q"def f"
+ assertThrows[IllegalArgumentException] { q"package foo { $f }" }
+ val v = q"val v = 0"
+ assertThrows[IllegalArgumentException] { q"package foo { $v }" }
+ val expr = q"x + 1"
+ assertThrows[IllegalArgumentException] { q"package foo { $expr }" }
+ }
+
+ property("splice name into package object") = test {
+ val foo = TermName("foo")
+ assertEqAst(q"package object $foo", "package object foo")
+ }
+
+ property("splice parents into package object") = test {
+ val parents = tq"a" :: tq"b" :: Nil
+ assertEqAst(q"package object foo extends ..$parents",
+ "package object foo extends a with b")
+ }
+
+ property("splice members into package object") = test {
+ val members = q"def foo" :: q"val x = 1" :: Nil
+ assertEqAst(q"package object foo { ..$members }",
+ "package object foo { def foo; val x = 1 }")
+ }
+
+ property("splice early def into package object") = test {
+ val edefs = q"val x = 1" :: q"type I = Int" :: Nil
+ assertEqAst(q"package object foo extends { ..$edefs } with Any",
+ "package object foo extends { val x = 1; type I = Int } with Any")
+ }
} \ No newline at end of file
diff --git a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
index fdfbfe871c..993ef899b0 100644
--- a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
@@ -13,6 +13,7 @@ object DefinitionDeconstructionProps
with ObjectDeconstruction
with ModsDeconstruction
with ValVarDeconstruction
+ with PackageDeconstruction
trait TraitDeconstruction { self: QuasiquoteProperties =>
property("exhaustive trait matcher") = test {
@@ -144,4 +145,27 @@ trait ValVarDeconstruction { self: QuasiquoteProperties =>
matches("var x = 1")
assertThrows[MatchError] { matches("val x = 1") }
}
+}
+
+trait PackageDeconstruction { self: QuasiquoteProperties =>
+ property("exhaustive package matcher") = test {
+ def matches(line: String) { val q"package $name { ..$body }" = parse(line) }
+ matches("package foo { }")
+ matches("package foo { class C }")
+ matches("package foo.bar { }")
+ matches("package bippy.bongo { object A; object B }")
+ matches("package bippy { package bongo { object O } }")
+ }
+
+ property("exhaustive package object matcher") = test {
+ def matches(line: String) {
+ val q"package object $name extends { ..$early } with ..$parents { $self => ..$body }" = parse(line)
+ }
+ matches("package object foo")
+ matches("package object foo { def baz }")
+ matches("package object foo { self => }")
+ matches("package object foo extends mammy with daddy { def baz }")
+ matches("package object foo extends { val early = 1 } with daddy")
+ assertThrows[MatchError] { matches("object foo") }
+ }
} \ No newline at end of file