/* NSC -- new Scala compiler * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ // $Id: Constants.scala 18387 2009-07-24 15:28:37Z odersky $ package scala.tools.nsc package symtab import java.lang.Integer.toOctalString import classfile.PickleFormat._ trait Constants { self: SymbolTable => import definitions._ final val NoTag = LITERAL - LITERAL final val UnitTag = LITERALunit - LITERAL final val BooleanTag = LITERALboolean - LITERAL final val ByteTag = LITERALbyte - LITERAL final val ShortTag = LITERALshort - LITERAL final val CharTag = LITERALchar - LITERAL final val IntTag = LITERALint - LITERAL final val LongTag = LITERALlong - LITERAL final val FloatTag = LITERALfloat - LITERAL final val DoubleTag = LITERALdouble - LITERAL final val StringTag = LITERALstring - LITERAL final val NullTag = LITERALnull - LITERAL final val ClassTag = LITERALclass - LITERAL // For supporting java enumerations inside java annotations (see ClassfileParser) final val EnumTag = LITERALenum - LITERAL def isNumeric(tag: Int) = ByteTag <= tag && tag <= DoubleTag case class Constant(value: Any) { val tag: Int = if (value.isInstanceOf[Unit]) UnitTag else if (value.isInstanceOf[Boolean]) BooleanTag else if (value.isInstanceOf[Byte]) ByteTag else if (value.isInstanceOf[Short]) ShortTag else if (value.isInstanceOf[Char]) CharTag else if (value.isInstanceOf[Int]) IntTag else if (value.isInstanceOf[Long]) LongTag else if (value.isInstanceOf[Float]) FloatTag else if (value.isInstanceOf[Double]) DoubleTag else if (value.isInstanceOf[String]) StringTag else if (value.isInstanceOf[Type]) ClassTag else if (value.isInstanceOf[Symbol]) EnumTag else if (value == null) NullTag else throw new Error("bad constant value: " + value) def tpe: Type = tag match { case UnitTag => UnitClass.tpe case BooleanTag => BooleanClass.tpe case ByteTag => ByteClass.tpe case ShortTag => ShortClass.tpe case CharTag => CharClass.tpe case IntTag => IntClass.tpe case LongTag => LongClass.tpe case FloatTag => FloatClass.tpe case DoubleTag => DoubleClass.tpe case StringTag => StringClass.tpe case NullTag => NullClass.tpe case ClassTag => Predef_classOfType(value.asInstanceOf[Type]) case EnumTag => symbolValue.owner.linkedClassOfClass.tpe } /** We need the equals method to take account of tags as well as values. * * @param other ... * @return ... */ override def equals(other: Any): Boolean = other match { case that: Constant => this.tag == that.tag && this.value == that.value case _ => false } def booleanValue: Boolean = if (tag == BooleanTag) value.asInstanceOf[Boolean] else throw new Error("value " + value + " is not a boolean"); def byteValue: Byte = tag match { case ByteTag => value.asInstanceOf[Byte] case ShortTag => value.asInstanceOf[Short].asInstanceOf[Byte] case CharTag => value.asInstanceOf[Char].asInstanceOf[Byte] case IntTag => value.asInstanceOf[Int].asInstanceOf[Byte] case LongTag => value.asInstanceOf[Long].asInstanceOf[Byte] case FloatTag => value.asInstanceOf[Float].asInstanceOf[Byte] case DoubleTag => value.asInstanceOf[Double].asInstanceOf[Byte] case _ => throw new Error("value " + value + " is not a Byte") } def shortValue: Short = tag match { case ByteTag => value.asInstanceOf[Byte].asInstanceOf[Short] case ShortTag => value.asInstanceOf[Short] case CharTag => value.asInstanceOf[Char].asInstanceOf[Short] case IntTag => value.asInstanceOf[Int].asInstanceOf[Short] case LongTag => value.asInstanceOf[Long].asInstanceOf[Short] case FloatTag => value.asInstanceOf[Float].asInstanceOf[Short] case DoubleTag => value.asInstanceOf[Double].asInstanceOf[Short] case _ => throw new Error("value " + value + " is not a Short") } def charValue: Char = tag match { case ByteTag => value.asInstanceOf[Byte].asInstanceOf[Char] case ShortTag => value.asInstanceOf[Short].asInstanceOf[Char] case CharTag => value.asInstanceOf[Char] case IntTag => value.asInstanceOf[Int].asInstanceOf[Char] case LongTag => value.asInstanceOf[Long].asInstanceOf[Char] case FloatTag => value.asInstanceOf[Float].asInstanceOf[Char] case DoubleTag => value.asInstanceOf[Double].asInstanceOf[Char] case _ => throw new Error("value " + value + " is not a Char") } def intValue: Int = tag match { case ByteTag => value.asInstanceOf[Byte].asInstanceOf[Int] case ShortTag => value.asInstanceOf[Short].asInstanceOf[Int] case CharTag => value.asInstanceOf[Char].asInstanceOf[Int] case IntTag => value.asInstanceOf[Int] case LongTag => value.asInstanceOf[Long].asInstanceOf[Int] case FloatTag => value.asInstanceOf[Float].asInstanceOf[Int] case DoubleTag => value.asInstanceOf[Double].asInstanceOf[Int] case _ => throw new Error("value " + value + " is not an Int") } def longValue: Long = tag match { case ByteTag => value.asInstanceOf[Byte].asInstanceOf[Long] case ShortTag => value.asInstanceOf[Short].asInstanceOf[Long] case CharTag => value.asInstanceOf[Char].asInstanceOf[Long] case IntTag => value.asInstanceOf[Int].asInstanceOf[Long] case LongTag => value.asInstanceOf[Long] case FloatTag => value.asInstanceOf[Float].asInstanceOf[Long] case DoubleTag => value.asInstanceOf[Double].asInstanceOf[Long] case _ => throw new Error("value " + value + " is not a Long") } def floatValue: Float = tag match { case ByteTag => value.asInstanceOf[Byte].asInstanceOf[Float] case ShortTag => value.asInstanceOf[Short].asInstanceOf[Float] case CharTag => value.asInstanceOf[Char].asInstanceOf[Float] case IntTag => value.asInstanceOf[Int].asInstanceOf[Float] case LongTag => value.asInstanceOf[Long].asInstanceOf[Float] case FloatTag => value.asInstanceOf[Float] case DoubleTag => value.asInstanceOf[Double].asInstanceOf[Float] case _ => throw new Error("value " + value + " is not a Float") } def doubleValue: Double = tag match { case ByteTag => value.asInstanceOf[Byte].asInstanceOf[Double] case ShortTag => value.asInstanceOf[Short].asInstanceOf[Double] case CharTag => value.asInstanceOf[Char].asInstanceOf[Double] case IntTag => value.asInstanceOf[Int].asInstanceOf[Double] case LongTag => value.asInstanceOf[Long].asInstanceOf[Double] case FloatTag => value.asInstanceOf[Float].asInstanceOf[Double] case DoubleTag => value.asInstanceOf[Double] case _ => throw new Error("value " + value + " is not a Double") } /** Convert constant value to conform to given type. * * @param pt ... * @return ... */ def convertTo(pt: Type): Constant = { val target = pt.typeSymbol if (target == tpe.typeSymbol) this else if (target == ByteClass && ByteTag <= tag && tag <= IntTag && -128 <= intValue && intValue <= 127) Constant(byteValue) else if (target == ShortClass && ByteTag <= tag && tag <= IntTag && -32768 <= intValue && intValue <= 32767) Constant(shortValue) else if (target == CharClass && ByteTag <= tag && tag <= IntTag && 0 <= intValue && intValue <= 65635) Constant(charValue) else if (target == IntClass && ByteTag <= tag && tag <= IntTag) Constant(intValue) else if (target == LongClass && ByteTag <= tag && tag <= LongTag) Constant(longValue) else if (target == FloatClass && ByteTag <= tag && tag <= FloatTag) Constant(floatValue) else if (target == DoubleClass && ByteTag <= tag && tag <= DoubleTag) Constant(doubleValue) else { null } } def stringValue: String = if (value == null) "null" else if (tag == ClassTag) signature(typeValue) else value.toString() def escapedStringValue: String = { def escape(text: String): String = { val buf = new StringBuilder for (c <- text.iterator) if (c.isControl) buf.append("\\0" + toOctalString(c.asInstanceOf[Int])) else buf.append(c) buf.toString } tag match { case NullTag => "null" case StringTag => "\"" + escape(stringValue) + "\"" case ClassTag => "classOf[" + signature(typeValue) + "]" case CharTag => escape("\'" + charValue + "\'") case LongTag => longValue.toString() + "L" case _ => value.toString() } } def typeValue: Type = value.asInstanceOf[Type] def symbolValue: Symbol = value.asInstanceOf[Symbol] override def hashCode(): Int = if (value == null) 0 else value.hashCode() * 41 + 17 } }