From e8525254314627bd145d2093f0a1a0f3ca6a8067 Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 10 Oct 2012 09:59:12 +0200 Subject: scala.reflect.api.Constants documentation --- src/reflect/scala/reflect/api/Constants.scala | 193 +++++++++++++++----------- src/reflect/scala/reflect/api/package.scala | 13 ++ 2 files changed, 124 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala index 1f303877de..8c532bd4dd 100644 --- a/src/reflect/scala/reflect/api/Constants.scala +++ b/src/reflect/scala/reflect/api/Constants.scala @@ -6,114 +6,143 @@ package scala.reflect package api -/** A slice of [[scala.reflect.api.Universe the Scala reflection cake]] that defines compile-time constants and operations on them. - * See [[scala.reflect.api.Universe]] for a description of how the reflection API is encoded with the cake pattern. - * - * According to the section 6.24 "Constant Expressions" of the Scala language specification, - * certain expressions (dubbed ''constant expressions'') can be evaluated by the Scala compiler at compile-time. - * - * [[scala.reflect.api.Constants#Constant]] instances represent certain kinds of these expressions - * (with values stored in the `value` field and its strongly-typed views named `booleanValue`, `intValue` etc.), namely: - * 1. Literals of primitive value classes (bytes, shorts, ints, longs, floats, doubles, chars, booleans and voids). - * 1. String literals. - * 1. References to classes (typically constructed with [[scala.Predef#classOf]]). - * 1. References to enumeration values. - * - * Such constants are used to represent literals in abstract syntax trees (the [[scala.reflect.api.Trees#Literal]] node) - * and literal arguments for Java class file annotations (the [[scala.reflect.api.Annotations#LiteralArgument]] class). - * - * === Example === - * - * The `value` field deserves some explanation. Primitive and string values are represented as themselves, whereas - * references to classes and enums are a bit roundabout. - * - * Class references are represented as instances of [[scala.reflect.api.Types#Type]] - * (because when the Scala compiler processes a class reference, the underlying runtime class might not yet have been compiled). - * To convert such a reference to a runtime class, one should use the `runtimeClass` method of a mirror such as [[scala.reflect.api.Mirrors#RuntimeMirror]] - * (the simplest way to get such a mirror is using [[scala.reflect.runtime.package#currentMirror]]). - * - * Enumeration value references are represented as instances of [[scala.reflect.api.Symbols#Symbol]], which on JVM point to methods - * that return underlying enum values. To inspect an underlying enumeration or to get runtime value of a reference to an enum, - * one should use a [[scala.reflect.api.Mirrors#RuntimeMirror]] (the simplest way to get such a mirror is again [[scala.reflect.runtime.package#currentMirror]]). - - * {{{ - * enum JavaSimpleEnumeration { FOO, BAR } - * - * import java.lang.annotation.*; - * @Retention(RetentionPolicy.RUNTIME) - * @Target({ElementType.TYPE}) - * public @interface JavaSimpleAnnotation { - * Class classRef(); - * JavaSimpleEnumeration enumRef(); - * } - * - * @JavaSimpleAnnotation( - * classRef = JavaAnnottee.class, - * enumRef = JavaSimpleEnumeration.BAR - * ) - * public class JavaAnnottee {} - * }}} - * {{{ - * import scala.reflect.runtime.universe._ - * import scala.reflect.runtime.{currentMirror => cm} - * - * object Test extends App { - * val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs - * def jarg(name: String) = jann(newTermName(name)).asInstanceOf[LiteralArgument].value - * - * val classRef = jarg("classRef").typeValue - * println(showRaw(classRef)) // TypeRef(ThisType(), JavaAnnottee, List()) - * println(cm.runtimeClass(classRef)) // class JavaAnnottee - * - * val enumRef = jarg("enumRef").symbolValue - * println(enumRef) // value BAR - * - * val siblings = enumRef.owner.typeSignature.declarations - * val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic) - * println(enumValues) // Scope{ - * // final val FOO: JavaSimpleEnumeration; - * // final val BAR: JavaSimpleEnumeration - * // } - * - * // doesn't work because of https://issues.scala-lang.org/browse/SI-6459 - * // val enumValue = mirror.reflectField(enumRef.asTerm).get - * val enumClass = cm.runtimeClass(enumRef.owner.asClass) - * val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null) - * println(enumValue) // BAR - * } - * }}} +/** + * This trait is the [[scala.reflect.api.Universe reflection API]] component that mirrors constant irreducible expressions + * such as `true`, `0` and `classOf[List]`. Constant values appear in the program abstract syntax tree and in annotation parameters + * wrapped in [[Constant `Constant`]] case classes. */ trait Constants { self: Universe => - /** The type of compile-time constants. + /** + * This "virtual" case class represents the reflection interface for literal expressions which can not be further + * broken down or evaluated, such as "true", "0", "classOf[List]". Such values become parts of the Scala abstract + * syntax tree representing the program. The constants + * correspond to section 6.24 "Constant Expressions" of the + * [[http://www.scala-lang.org/docu/files/ScalaReference.pdf Scala language specification]]. + * + * Such constants are used to represent literals in abstract syntax trees (the [[scala.reflect.api.Trees#Literal]] node) + * and literal arguments for Java class file annotations (the [[scala.reflect.api.Annotations#LiteralArgument]] class). + * + * Constants can be matched against and can be constructed directly, as if they were case classes: + * {{{ + * assert(Constant(true).value == true) + * Constant(true) match { + * case Constant(s: String) => println("A string: " + s) + * case Constant(b: Boolean) => println("A boolean value: " + b) + * case Constant(x) => println("Something else: " + x) + * } + * }}} + * + * `Constant` instances can wrap certain kinds of these expressions: + * 1. Literals of primitive value classes ([[scala.Byte `Byte`]], [[scala.Short `Short`]], [[scala.Int `Int`]], [[scala.Long `Long`]], [[scala.Float `Float`]], [[scala.Double `Double`]], [[scala.Char `Char`]], [[scala.Boolean `Boolean`]] and [[scala.Unit `Unit`]]) - represented directly as the corresponding type + * 1. String literals - represented as instances of the `String`. + * 1. References to classes, typically constructed with [[scala.Predef#classOf]] - represented as [[scala.reflect.api.Types#Type types]]. + * 1. References to enumeration values - represented as [[scala.reflect.api.Symbols#Symbol symbols]]. + * + * Class references are represented as instances of [[scala.reflect.api.Types#Type]] + * (because when the Scala compiler processes a class reference, the underlying runtime class might not yet have + * been compiled). To convert such a reference to a runtime class, one should use the [[scala.reflect.api.Mirrors#RuntimeMirror#runtimeClass `runtimeClass`]] method of a + * mirror such as [[scala.reflect.api.Mirrors#RuntimeMirror `RuntimeMirror`]] (the simplest way to get such a mirror is using + * [[scala.reflect.runtime#currentMirror `scala.reflect.runtime.currentMirror`]]). + * + * Enumeration value references are represented as instances of [[scala.reflect.api.Symbols#Symbol]], which on JVM point to methods + * that return underlying enum values. To inspect an underlying enumeration or to get runtime value of a reference to an enum, + * one should use a [[scala.reflect.api.Mirrors#RuntimeMirror]] (the simplest way to get such a mirror is again [[scala.reflect.runtime.package#currentMirror]]). + * + * Usage example: + * {{{ + * enum JavaSimpleEnumeration { FOO, BAR } + * + * import java.lang.annotation.*; + * @Retention(RetentionPolicy.RUNTIME) + * @Target({ElementType.TYPE}) + * public @interface JavaSimpleAnnotation { + * Class classRef(); + * JavaSimpleEnumeration enumRef(); + * } + * + * @JavaSimpleAnnotation( + * classRef = JavaAnnottee.class, + * enumRef = JavaSimpleEnumeration.BAR + * ) + * public class JavaAnnottee {} + * }}} + * {{{ + * import scala.reflect.runtime.universe._ + * import scala.reflect.runtime.{currentMirror => cm} + * + * object Test extends App { + * val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs + * def jarg(name: String) = jann(newTermName(name)) match { + * // Constant is always wrapped into a Literal or LiteralArgument tree node + * case LiteralArgument(ct: Constant) => value + * case _ => sys.error("Not a constant") + * } + * + * val classRef = jarg("classRef").value.asInstanceOf[Type] + * // ideally one should match instead of casting + * println(showRaw(classRef)) // TypeRef(ThisType(), JavaAnnottee, List()) + * println(cm.runtimeClass(classRef)) // class JavaAnnottee + * + * val enumRef = jarg("enumRef").value.asInstanceOf[Symbol] + * // ideally one should match instead of casting + * println(enumRef) // value BAR + * + * val siblings = enumRef.owner.typeSignature.declarations + * val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic) + * println(enumValues) // Scope{ + * // final val FOO: JavaSimpleEnumeration; + * // final val BAR: JavaSimpleEnumeration + * // } + * + * // doesn't work because of https://issues.scala-lang.org/browse/SI-6459 + * // val enumValue = mirror.reflectField(enumRef.asTerm).get + * val enumClass = cm.runtimeClass(enumRef.owner.asClass) + * val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null) + * println(enumValue) // BAR + * } + * }}} + * @template + * @group Constants */ type Constant >: Null <: AnyRef with ConstantApi /** A tag that preserves the identity of the `Constant` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags */ implicit val ConstantTag: ClassTag[Constant] - /** The constructor/deconstructor for `Constant` instances. */ + /** The constructor/deconstructor for `Constant` instances. + * @group Extractors + */ val Constant: ConstantExtractor /** An extractor class to create and pattern match with syntax `Constant(value)` * where `value` is the Scala value of the constant. + * @group Extractors */ abstract class ConstantExtractor { + /** A factory method that produces [[Constant `Constant`]] instances. + * + * Notice that not any value can be passed to a constant: it must be either a primitive, a `String`, a + * [[scala.reflect.api.Types#Type type]] or a [[scala.reflect.api.Symbols#Symbol symbol]]. + * See [[Constant the `Constant` class]] for more information. + */ def apply(value: Any): Constant + /** An extractor that enables writing pattern matches against the [[Constant `Constant`]] class. */ def unapply(arg: Constant): Option[Any] } - /** The API of `Constant` instances. - * The main source of information about constants is the [[scala.reflect.api.Constants]] page. + /** The API of [[Constant]] instances. + * @group API */ abstract class ConstantApi { - /** Payload of the constant. */ + /** Payload of the constant, that can be accessed directly or pattern matched against. */ val value: Any - /** Scala type that describes the constant. */ + /** Scala type that describes the constant. It is generated automatically based on the type of the value. */ def tpe: Type } } diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala index a11a269523..ba098cb3d5 100644 --- a/src/reflect/scala/reflect/api/package.scala +++ b/src/reflect/scala/reflect/api/package.scala @@ -9,6 +9,19 @@ import scala.reflect.api.{Universe => ApiUniverse} * * In Scala 2.10.0, reflection API and its implementation have experimental status. This means that the API and the docs are not complete and can be changed * in binary- and source-incompatible manner in 2.10.1. This also means that the implementation has known issues + * + * @groupprio API 9 + * @groupprio Extractors 10 + * @groupprio Tags 11 + * @groupdesc API The methods available for each reflection entity, without the implementation. Since the + * reflection entities are abstract types that are later overridden, their API counterparts + * guarantee a minimum set of methods implemented in both runtime reflection and macros. + * @groupdesc Extractors Extractors provide the machinery necessary to allow pattern matching and construction of + * reflection entities that is similar to case classes, although the entities are only abstract + * types that are later overridden. + * @groupdesc Tags Implicit values that provide [[scala.reflect.ClassTag `ClassTags`]] for the reflection + * classes. These are abstract in the interface but are later filled in to provide ClassTags + * for the either the runtime reflection or macros entities, depending on the use. */ package object api { -- cgit v1.2.3