diff options
author | Den Shabalin <den.shabalin@gmail.com> | 2012-12-08 13:47:14 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-12-25 01:58:28 +0100 |
commit | e5ed594a89f4e468f3a9e754eb75687885908ba3 (patch) | |
tree | d969ec4655a0d2766c1749eb01c0385cd5b184ac | |
parent | d2a7aa4ba1c048e52affb0eb2b9167a18dc29c83 (diff) | |
download | scala-e5ed594a89f4e468f3a9e754eb75687885908ba3.tar.gz scala-e5ed594a89f4e468f3a9e754eb75687885908ba3.tar.bz2 scala-e5ed594a89f4e468f3a9e754eb75687885908ba3.zip |
Adds extractors for TypeName, TermName and Modifiers
This change allows to pattern match over type names, term names and
modifiers. Otherwise it can be quite painful to match over complex trees
as each name or modifiers requires a guard.
This pull request also changes the name of default constructor for term
and type names i.e. TypeName(s) instead of newTermName(s). This is
shorter to type, more consistent with the rest of reflection api and
consistent with the way it will be pattern matched later on.
-rw-r--r-- | src/reflect/scala/reflect/api/Names.scala | 30 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Trees.scala | 8 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Names.scala | 10 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Trees.scala | 2 | ||||
-rw-r--r-- | test/files/scalacheck/ReflectionExtractors.scala | 52 |
5 files changed, 98 insertions, 4 deletions
diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index 7c12f180a8..8add98d815 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -58,7 +58,7 @@ trait Names { * Can be used for pattern matching, instance tests, serialization and likes. * @group Tags */ -implicit val TypeNameTag: ClassTag[TypeName] + implicit val TypeNameTag: ClassTag[TypeName] /** The abstract type of names representing types. * @group Names @@ -109,10 +109,38 @@ implicit val TypeNameTag: ClassTag[TypeName] /** Create a new term name. * @group Names */ + @deprecated("Use TermName instead", "2.11.0") def newTermName(s: String): TermName /** Creates a new type name. * @group Names */ + @deprecated("Use TypeName instead", "2.11.0") def newTypeName(s: String): TypeName + + /** The constructor/extractor for `TermName` instances. + * @group Extractors + */ + val TermName: TermNameExtractor + + /** An extractor class to create and pattern match with syntax `TermName(s)`. + * @group Extractors + */ + abstract class TermNameExtractor { + def apply(s: String): TermName + def unapply(name: TermName): Option[String] + } + + /** The constructor/extractor for `TypeName` instances. + * @group Extractors + */ + val TypeName: TypeNameExtractor + + /** An extractor class to create and pattern match with syntax `TypeName(s)`. + * @group Extractors + */ + abstract class TypeNameExtractor { + def apply(s: String): TypeName + def unapply(name: TypeName): Option[String] + } } diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index cfa6315797..34be977905 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -3018,15 +3018,19 @@ trait Trees { self: Universe => /** The constructor/extractor for `Modifiers` instances. * @group Traversal */ - val Modifiers: ModifiersCreator + val Modifiers: ModifiersExtractor + + @deprecated("Use ModifiersExtractor instead", "2.11.0") + type ModifiersCreator = ModifiersExtractor /** An extractor class to create and pattern match with syntax `Modifiers(flags, privateWithin, annotations)`. * Modifiers encapsulate flags, visibility annotations and Scala annotations for member definitions. * @group Traversal */ - abstract class ModifiersCreator { + abstract class ModifiersExtractor { def apply(): Modifiers = Modifiers(NoFlags, tpnme.EMPTY, List()) def apply(flags: FlagSet, privateWithin: Name, annotations: List[Tree]): Modifiers + def unapply(mods: Modifiers): Option[(FlagSet, Name, List[Tree])] } /** The factory for `Modifiers` instances. diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index cea9215ae2..b60d1e619f 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -463,6 +463,11 @@ trait Names extends api.Names { implicit val TermNameTag = ClassTag[TermName](classOf[TermName]) + object TermName extends TermNameExtractor { + def apply(s: String) = newTermName(s) + def unapply(name: TermName): Option[String] = Some(name.toString) + } + sealed abstract class TypeName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) { type ThisNameType = TypeName protected[this] def thisName: TypeName = this @@ -492,4 +497,9 @@ trait Names extends api.Names { } implicit val TypeNameTag = ClassTag[TypeName](classOf[TypeName]) + + object TypeName extends TypeNameExtractor { + def apply(s: String) = newTypeName(s) + def unapply(name: TypeName): Option[String] = Some(name.toString) + } } diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 9e737528d2..9795299342 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -932,7 +932,7 @@ trait Trees extends api.Trees { self: SymbolTable => override def toString = "Modifiers(%s, %s, %s)".format(flagString, annotations mkString ", ", positions) } - object Modifiers extends ModifiersCreator + object Modifiers extends ModifiersExtractor implicit val ModifiersTag = ClassTag[Modifiers](classOf[Modifiers]) diff --git a/test/files/scalacheck/ReflectionExtractors.scala b/test/files/scalacheck/ReflectionExtractors.scala new file mode 100644 index 0000000000..a2615feb3e --- /dev/null +++ b/test/files/scalacheck/ReflectionExtractors.scala @@ -0,0 +1,52 @@ +import org.scalacheck._ +import Prop._ +import Gen._ +import Arbitrary._ + +import scala.reflect.runtime.universe._ +import Flag._ + +object Test extends Properties("reflection extractors") { + + val genFlag = oneOf( + TRAIT, INTERFACE, MUTABLE, MACRO, DEFERRED, ABSTRACT, FINAL, SEALED, + IMPLICIT, LAZY, OVERRIDE, PRIVATE, PROTECTED, LOCAL, CASE, ABSOVERRIDE, + BYNAMEPARAM, PARAM, COVARIANT, CONTRAVARIANT, DEFAULTPARAM, PRESUPER, + DEFAULTINIT + ) + val genModifiers = + for(flag <- genFlag; privateWithin <- genName) + yield Modifiers(flag, privateWithin, Nil) + val genTermName = for(name <- arbitrary[String]) yield TermName(name) + val genTypeName = for(name <- arbitrary[String]) yield TypeName(name) + val genName = oneOf(genTermName, genTypeName) + + implicit val arbTermName: Arbitrary[TermName] = Arbitrary(genTermName) + implicit val arbTypeName: Arbitrary[TypeName] = Arbitrary(genTypeName) + implicit val arbName: Arbitrary[Name] = Arbitrary(genName) + implicit val arbMods: Arbitrary[Modifiers] = Arbitrary(genModifiers) + + property("extract term name") = forAll { (name: TermName) => + val TermName(s) = name + s == name.toString + } + + property("extract type name") = forAll { (name: TypeName) => + val TypeName(s) = name + s == name.toString + } + + property("extract term or type name") = forAll { (name: Name) => + name match { + case TermName(s) => s == name.toString + case TypeName(s) => s == name.toString + } + } + + property("extract modifiers") = forAll { (mods: Modifiers) => + val Modifiers(flags, priv, annots) = mods + flags == mods.flags && + priv == mods.privateWithin && + annots == mods.annotations + } +}
\ No newline at end of file |