/src/library/scala/reflect/generic/Constants.scala

https://github.com/heathermiller/parcolls-extended · Scala · 238 lines · 202 code · 23 blank · 13 comment · 56 complexity · 5d2bd893149b5a9d01219f8b9739688c MD5 · raw file

  1. /* NSC -- new Scala compiler
  2. * Copyright 2005-2011 LAMP/EPFL
  3. * @author Martin Odersky
  4. */
  5. package scala.reflect
  6. package generic
  7. import java.lang.Integer.toOctalString
  8. import annotation.switch
  9. trait Constants {
  10. self: Universe =>
  11. import definitions._
  12. final val NoTag = 0
  13. final val UnitTag = 1
  14. final val BooleanTag = 2
  15. final val ByteTag = 3
  16. final val ShortTag = 4
  17. final val CharTag = 5
  18. final val IntTag = 6
  19. final val LongTag = 7
  20. final val FloatTag = 8
  21. final val DoubleTag = 9
  22. final val StringTag = 10
  23. final val NullTag = 11
  24. final val ClassTag = 12
  25. // For supporting java enumerations inside java annotations (see ClassfileParser)
  26. final val EnumTag = 13
  27. case class Constant(value: Any) {
  28. val tag: Int = value match {
  29. case null => NullTag
  30. case x: Unit => UnitTag
  31. case x: Boolean => BooleanTag
  32. case x: Byte => ByteTag
  33. case x: Short => ShortTag
  34. case x: Int => IntTag
  35. case x: Long => LongTag
  36. case x: Float => FloatTag
  37. case x: Double => DoubleTag
  38. case x: String => StringTag
  39. case x: Char => CharTag
  40. case x: AbsType => ClassTag
  41. case x: AbsSymbol => EnumTag
  42. case _ => throw new Error("bad constant value: " + value)
  43. }
  44. def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue
  45. def isShortRange: Boolean = isIntRange && Short.MinValue <= intValue && intValue <= Short.MaxValue
  46. def isCharRange: Boolean = isIntRange && Char.MinValue <= intValue && intValue <= Char.MaxValue
  47. def isIntRange: Boolean = ByteTag <= tag && tag <= IntTag
  48. def isLongRange: Boolean = ByteTag <= tag && tag <= LongTag
  49. def isFloatRange: Boolean = ByteTag <= tag && tag <= FloatTag
  50. def isNumeric: Boolean = ByteTag <= tag && tag <= DoubleTag
  51. def tpe: Type = tag match {
  52. case UnitTag => UnitClass.tpe
  53. case BooleanTag => BooleanClass.tpe
  54. case ByteTag => ByteClass.tpe
  55. case ShortTag => ShortClass.tpe
  56. case CharTag => CharClass.tpe
  57. case IntTag => IntClass.tpe
  58. case LongTag => LongClass.tpe
  59. case FloatTag => FloatClass.tpe
  60. case DoubleTag => DoubleClass.tpe
  61. case StringTag => StringClass.tpe
  62. case NullTag => NullClass.tpe
  63. case ClassTag => ClassType(value.asInstanceOf[Type])
  64. case EnumTag =>
  65. // given (in java): "class A { enum E { VAL1 } }"
  66. // - symbolValue: the symbol of the actual enumeration value (VAL1)
  67. // - .owner: the ModuleClasSymbol of the enumeration (object E)
  68. // - .linkedClassOfClass: the ClassSymbol of the enumeration (class E)
  69. symbolValue.owner.linkedClassOfClass.tpe
  70. }
  71. /** We need the equals method to take account of tags as well as values.
  72. */
  73. override def equals(other: Any): Boolean = other match {
  74. case that: Constant =>
  75. this.tag == that.tag &&
  76. (this.value == that.value || this.isNaN && that.isNaN)
  77. case _ => false
  78. }
  79. def isNaN = value match {
  80. case f: Float => f.isNaN
  81. case d: Double => d.isNaN
  82. case _ => false
  83. }
  84. def booleanValue: Boolean =
  85. if (tag == BooleanTag) value.asInstanceOf[Boolean]
  86. else throw new Error("value " + value + " is not a boolean");
  87. def byteValue: Byte = tag match {
  88. case ByteTag => value.asInstanceOf[Byte]
  89. case ShortTag => value.asInstanceOf[Short].toByte
  90. case CharTag => value.asInstanceOf[Char].toByte
  91. case IntTag => value.asInstanceOf[Int].toByte
  92. case LongTag => value.asInstanceOf[Long].toByte
  93. case FloatTag => value.asInstanceOf[Float].toByte
  94. case DoubleTag => value.asInstanceOf[Double].toByte
  95. case _ => throw new Error("value " + value + " is not a Byte")
  96. }
  97. def shortValue: Short = tag match {
  98. case ByteTag => value.asInstanceOf[Byte].toShort
  99. case ShortTag => value.asInstanceOf[Short]
  100. case CharTag => value.asInstanceOf[Char].toShort
  101. case IntTag => value.asInstanceOf[Int].toShort
  102. case LongTag => value.asInstanceOf[Long].toShort
  103. case FloatTag => value.asInstanceOf[Float].toShort
  104. case DoubleTag => value.asInstanceOf[Double].toShort
  105. case _ => throw new Error("value " + value + " is not a Short")
  106. }
  107. def charValue: Char = tag match {
  108. case ByteTag => value.asInstanceOf[Byte].toChar
  109. case ShortTag => value.asInstanceOf[Short].toChar
  110. case CharTag => value.asInstanceOf[Char]
  111. case IntTag => value.asInstanceOf[Int].toChar
  112. case LongTag => value.asInstanceOf[Long].toChar
  113. case FloatTag => value.asInstanceOf[Float].toChar
  114. case DoubleTag => value.asInstanceOf[Double].toChar
  115. case _ => throw new Error("value " + value + " is not a Char")
  116. }
  117. def intValue: Int = tag match {
  118. case ByteTag => value.asInstanceOf[Byte].toInt
  119. case ShortTag => value.asInstanceOf[Short].toInt
  120. case CharTag => value.asInstanceOf[Char].toInt
  121. case IntTag => value.asInstanceOf[Int]
  122. case LongTag => value.asInstanceOf[Long].toInt
  123. case FloatTag => value.asInstanceOf[Float].toInt
  124. case DoubleTag => value.asInstanceOf[Double].toInt
  125. case _ => throw new Error("value " + value + " is not an Int")
  126. }
  127. def longValue: Long = tag match {
  128. case ByteTag => value.asInstanceOf[Byte].toLong
  129. case ShortTag => value.asInstanceOf[Short].toLong
  130. case CharTag => value.asInstanceOf[Char].toLong
  131. case IntTag => value.asInstanceOf[Int].toLong
  132. case LongTag => value.asInstanceOf[Long]
  133. case FloatTag => value.asInstanceOf[Float].toLong
  134. case DoubleTag => value.asInstanceOf[Double].toLong
  135. case _ => throw new Error("value " + value + " is not a Long")
  136. }
  137. def floatValue: Float = tag match {
  138. case ByteTag => value.asInstanceOf[Byte].toFloat
  139. case ShortTag => value.asInstanceOf[Short].toFloat
  140. case CharTag => value.asInstanceOf[Char].toFloat
  141. case IntTag => value.asInstanceOf[Int].toFloat
  142. case LongTag => value.asInstanceOf[Long].toFloat
  143. case FloatTag => value.asInstanceOf[Float]
  144. case DoubleTag => value.asInstanceOf[Double].toFloat
  145. case _ => throw new Error("value " + value + " is not a Float")
  146. }
  147. def doubleValue: Double = tag match {
  148. case ByteTag => value.asInstanceOf[Byte].toDouble
  149. case ShortTag => value.asInstanceOf[Short].toDouble
  150. case CharTag => value.asInstanceOf[Char].toDouble
  151. case IntTag => value.asInstanceOf[Int].toDouble
  152. case LongTag => value.asInstanceOf[Long].toDouble
  153. case FloatTag => value.asInstanceOf[Float].toDouble
  154. case DoubleTag => value.asInstanceOf[Double]
  155. case _ => throw new Error("value " + value + " is not a Double")
  156. }
  157. /** Convert constant value to conform to given type.
  158. */
  159. def convertTo(pt: Type): Constant = {
  160. val target = pt.typeSymbol
  161. if (target == tpe.typeSymbol)
  162. this
  163. else if (target == ByteClass && isByteRange)
  164. Constant(byteValue)
  165. else if (target == ShortClass && isShortRange)
  166. Constant(shortValue)
  167. else if (target == CharClass && isCharRange)
  168. Constant(charValue)
  169. else if (target == IntClass && isIntRange)
  170. Constant(intValue)
  171. else if (target == LongClass && isLongRange)
  172. Constant(longValue)
  173. else if (target == FloatClass && isFloatRange)
  174. Constant(floatValue)
  175. else if (target == DoubleClass && isNumeric)
  176. Constant(doubleValue)
  177. else
  178. null
  179. }
  180. def stringValue: String =
  181. if (value == null) "null"
  182. else if (tag == ClassTag) signature(typeValue)
  183. else value.toString()
  184. @switch def escapedChar(ch: Char): String = ch match {
  185. case '\b' => "\\b"
  186. case '\t' => "\\t"
  187. case '\n' => "\\n"
  188. case '\f' => "\\f"
  189. case '\r' => "\\r"
  190. case '"' => "\\\""
  191. case '\'' => "\\\'"
  192. case '\\' => "\\\\"
  193. case _ => String.valueOf(ch)
  194. }
  195. def escapedStringValue: String = {
  196. def escape(text: String): String = {
  197. text map { ch =>
  198. if (ch.isControl) "\\0" + toOctalString(ch)
  199. else escapedChar(ch)
  200. } mkString ""
  201. }
  202. tag match {
  203. case NullTag => "null"
  204. case StringTag => "\"" + escape(stringValue) + "\""
  205. case ClassTag => "classOf[" + signature(typeValue) + "]"
  206. case CharTag => escape("'" + escapedChar(charValue) + "'")
  207. case LongTag => longValue.toString() + "L"
  208. case _ => String.valueOf(value)
  209. }
  210. }
  211. def typeValue: Type = value.asInstanceOf[Type]
  212. def symbolValue: Symbol = value.asInstanceOf[Symbol]
  213. override def hashCode: Int = value.## * 41 + 17
  214. }
  215. }