1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
package scala.annotation
import java.util.logging.Level
/** An annotation for methods whose bodies may be excluded
* from compiler-generated bytecode.
*
* Behavior is influenced by passing `-Xelide-below <arg>` to `scalac`.
* Calls to methods marked elidable (as well as the method body) will
* be omitted from generated code if the priority given the annotation
* is lower than that given on the command line.
*
* {{{
* @elidable(123) // annotation priority
* scalac -Xelide-below 456 // command line priority
* }}}
*
* The method call will be replaced with an expression which depends on
* the type of the elided expression. In decreasing order of precedence:
*
* {{{
* Unit ()
* Boolean false
* T <: AnyVal 0
* T >: Null null
* T >: Nothing Predef.???
* }}}
*
* Complete example:
{{{
import annotation._, elidable._
object Test extends App {
def expensiveComputation(): Int = { Thread.sleep(1000) ; 172 }
@elidable(WARNING) def warning(msg: String) = println(msg)
@elidable(FINE) def debug(msg: String) = println(msg)
@elidable(FINE) def computedValue = expensiveComputation()
warning("Warning! Danger! Warning!")
debug("Debug! Danger! Debug!")
println("I computed a value: " + computedValue)
}
% scalac example.scala && scala Test
Warning! Danger! Warning!
Debug! Danger! Debug!
I computed a value: 172
// INFO lies between WARNING and FINE
% scalac -Xelide-below INFO example.scala && scala Test
Warning! Danger! Warning!
I computed a value: 0
}}}
*
* @author Paul Phillips
* @since 2.8
*/
final class elidable(final val level: Int) extends annotation.StaticAnnotation {}
/** This useless appearing code was necessary to allow people to use
* named constants for the elidable annotation. This is what it takes
* to convince the compiler to fold the constants: otherwise when it's
* time to check an elision level it's staring at a tree like
* {{{
* (Select(Level, Select(FINEST, Apply(intValue, Nil))))
* }}}
* instead of the number `300`.
*
* @since 2.8
*/
object elidable {
/** The levels `ALL` and `OFF` are confusing in this context because
* the sentiment being expressed when using the annotation is at cross
* purposes with the one being expressed via `-Xelide-below`. This
* confusion reaches its zenith at level `OFF`, where the annotation means
* ''never elide this method'' but `-Xelide-below OFF` is how you would
* say ''elide everything possible''.
*
* With no simple remedy at hand, the issue is now at least documented,
* and aliases `MAXIMUM` and `MINIMUM` are offered.
*/
final val ALL = Int.MinValue // Level.ALL.intValue()
final val FINEST = 300 // Level.FINEST.intValue()
final val FINER = 400 // Level.FINER.intValue()
final val FINE = 500 // Level.FINE.intValue()
final val CONFIG = 700 // Level.CONFIG.intValue()
final val INFO = 800 // Level.INFO.intValue()
final val WARNING = 900 // Level.WARNING.intValue()
final val SEVERE = 1000 // Level.SEVERE.intValue()
final val OFF = Int.MaxValue // Level.OFF.intValue()
// a couple aliases for the confusing ALL and OFF
final val MAXIMUM = OFF
final val MINIMUM = ALL
// and we can add a few of our own
final val ASSERTION = 2000 // we should make this more granular
// for command line parsing so we can use names or ints
val byName: Map[String, Int] = Map(
"FINEST" -> FINEST,
"FINER" -> FINER,
"FINE" -> FINE,
"CONFIG" -> CONFIG,
"INFO" -> INFO,
"WARNING" -> WARNING,
"SEVERE" -> SEVERE,
"ASSERTION" -> ASSERTION,
"ALL" -> ALL,
"OFF" -> OFF,
"MAXIMUM" -> MAXIMUM,
"MINIMUM" -> MINIMUM
)
}
|