diff options
Diffstat (limited to 'javalanglib/src/main/scala')
34 files changed, 2710 insertions, 0 deletions
diff --git a/javalanglib/src/main/scala/java/lang/Appendable.scala b/javalanglib/src/main/scala/java/lang/Appendable.scala new file mode 100644 index 0000000..9cd74ad --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Appendable.scala @@ -0,0 +1,7 @@ +package java.lang + +trait Appendable { + def append(c: Char): Appendable + def append(csq: CharSequence): Appendable + def append(csq: CharSequence, start: Int, end: Int): Appendable +} diff --git a/javalanglib/src/main/scala/java/lang/AutoCloseable.scala b/javalanglib/src/main/scala/java/lang/AutoCloseable.scala new file mode 100644 index 0000000..21a3d0f --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/AutoCloseable.scala @@ -0,0 +1,5 @@ +package java.lang + +trait AutoCloseable { + def close(): Unit +} diff --git a/javalanglib/src/main/scala/java/lang/Boolean.scala b/javalanglib/src/main/scala/java/lang/Boolean.scala new file mode 100644 index 0000000..94a9967 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Boolean.scala @@ -0,0 +1,61 @@ +package java.lang + +import scala.scalajs.js + +/* This is a hijacked class. Its instances are primitive booleans. + * Constructors are not emitted. + */ +final class Boolean private () extends Comparable[Boolean] { + + def this(value: scala.Boolean) = this() + def this(v: String) = this() + + @inline def booleanValue(): scala.Boolean = + this.asInstanceOf[scala.Boolean] + + @inline override def equals(that: Any): scala.Boolean = + this eq that.asInstanceOf[AnyRef] + + @inline override def hashCode(): Int = + if (booleanValue) 1231 else 1237 + + @inline override def compareTo(that: Boolean): Int = + Boolean.compare(booleanValue, that.booleanValue) + + @inline override def toString(): String = + Boolean.toString(booleanValue) + +} + +object Boolean { + final val TYPE = classOf[scala.Boolean] + + /* TRUE and FALSE are supposed to be vals. However, they are better + * optimized as defs, because they end up being just the constant true and + * false (since `new Boolean(x)` is a no-op). + * Since vals and defs are binary-compatible (although they're not strictly + * speaking source-compatible, because of stability), we implement them as + * defs. Source-compatibility is not an issue because user code is compiled + * against the JDK .class files anyway. + * Moreover, preserving the identity of TRUE and FALSE is not an issue + * either, since they are primitive booleans in the end. + */ + def TRUE: Boolean = new Boolean(true) + def FALSE: Boolean = new Boolean(false) + + @inline def valueOf(booleanValue: scala.Boolean): Boolean = { + // We don't care about identity, since they end up as primitive booleans + new Boolean(booleanValue) + } + + @inline def valueOf(s: String): Boolean = valueOf(parseBoolean(s)) + + @inline def parseBoolean(s: String): scala.Boolean = + (s != null) && s.equalsIgnoreCase("true") + + @inline def toString(b: scala.Boolean): String = + "" + b + + @inline def compare(x: scala.Boolean, y: scala.Boolean): scala.Int = + if (x == y) 0 else if (x) 1 else -1 +} diff --git a/javalanglib/src/main/scala/java/lang/Byte.scala b/javalanglib/src/main/scala/java/lang/Byte.scala new file mode 100644 index 0000000..dc0c82f --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Byte.scala @@ -0,0 +1,71 @@ +package java.lang + +import scala.scalajs.js + +/* This is a hijacked class. Its instances are primitive numbers. + * Constructors are not emitted. + */ +final class Byte private () extends Number with Comparable[Byte] { + + def this(value: scala.Byte) = this() + def this(s: String) = this() + + @inline override def byteValue(): scala.Byte = + this.asInstanceOf[scala.Byte] + + @inline override def shortValue(): scala.Short = byteValue.toShort + @inline def intValue(): scala.Int = byteValue.toInt + @inline def longValue(): scala.Long = byteValue.toLong + @inline def floatValue(): scala.Float = byteValue.toFloat + @inline def doubleValue(): scala.Double = byteValue.toDouble + + @inline override def equals(that: Any): scala.Boolean = + this eq that.asInstanceOf[AnyRef] + + @inline override def hashCode(): Int = + byteValue + + @inline override def compareTo(that: Byte): Int = + Byte.compare(byteValue, that.byteValue) + + @inline override def toString(): String = + Byte.toString(byteValue) +} + +object Byte { + final val TYPE = classOf[scala.Byte] + final val SIZE = 8 + + /* MIN_VALUE and MAX_VALUE should be 'final val's. But it is impossible to + * write a proper Byte literal in Scala, that would both considered a Byte + * and a constant expression (optimized as final val). + * Since vals and defs are binary-compatible (although they're not strictly + * speaking source-compatible, because of stability), we implement them as + * defs. Source-compatibility is not an issue because user code is compiled + * against the JDK .class files anyway. + */ + def MIN_VALUE: scala.Byte = -128 + def MAX_VALUE: scala.Byte = 127 + + @inline def valueOf(byteValue: scala.Byte): Byte = new Byte(byteValue) + @inline def valueOf(s: String): Byte = valueOf(parseByte(s)) + + @inline def valueOf(s: String, radix: Int): Byte = + valueOf(parseByte(s, radix)) + + @inline def parseByte(s: String): scala.Byte = parseByte(s, 10) + + def parseByte(s: String, radix: Int): scala.Byte = { + val r = Integer.parseInt(s, radix) + if (r < MIN_VALUE || r > MAX_VALUE) + throw new NumberFormatException(s"""For input string: "$s"""") + else + r.toByte + } + + @inline def toString(b: scala.Byte): String = + "" + b + + @inline def compare(x: scala.Byte, y: scala.Byte): scala.Int = + x - y +} diff --git a/javalanglib/src/main/scala/java/lang/CharSequence.scala b/javalanglib/src/main/scala/java/lang/CharSequence.scala new file mode 100644 index 0000000..5875a2d --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/CharSequence.scala @@ -0,0 +1,8 @@ +package java.lang + +trait CharSequence { + def length(): scala.Int + def charAt(index: scala.Int): scala.Char + def subSequence(start: scala.Int, end: scala.Int): CharSequence + def toString(): String +} diff --git a/javalanglib/src/main/scala/java/lang/Character.scala b/javalanglib/src/main/scala/java/lang/Character.scala new file mode 100644 index 0000000..1b2b565 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Character.scala @@ -0,0 +1,289 @@ +package java.lang + +import scala.scalajs.js + +class Character(private val value: scala.Char) extends Comparable[Character] { + + def charValue(): scala.Char = value + + override def equals(that: Any) = + that.isInstanceOf[Character] && (value == that.asInstanceOf[Character].charValue) + + override def compareTo(that: Character): Int = + Character.compare(charValue, that.charValue) + + override def toString(): String = + Character.toString(value) + + override def hashCode(): Int = value.## + + /* + * Methods on scala.Char + * The following methods are only here to properly support reflective calls + * on boxed primitive values. YOU WILL NOT BE ABLE TO USE THESE METHODS, since + * we use the true javalib to lookup symbols, this file contains only + * implementations. + */ + protected def toByte: scala.Byte = value.toByte + protected def toShort: scala.Short = value.toShort + protected def toChar: scala.Char = value.toChar + protected def toInt: scala.Int = value + protected def toLong: scala.Long = value.toLong + protected def toFloat: scala.Float = value.toFloat + protected def toDouble: scala.Double = value.toDouble + + protected def unary_~ : scala.Int = ~value + protected def unary_+ : scala.Int = value + protected def unary_- : scala.Int = -value + + protected def +(x: String): String = value + x + + protected def <<(x: scala.Int): scala.Int = value << x + protected def <<(x: scala.Long): scala.Int = value << x + protected def >>>(x: scala.Int): scala.Int = value >>> x + protected def >>>(x: scala.Long): scala.Int = value >>> x + protected def >>(x: scala.Int): scala.Int = value >> x + protected def >>(x: scala.Long): scala.Int = value >> x + + protected def ==(x: scala.Byte): scala.Boolean = value == x + protected def ==(x: scala.Short): scala.Boolean = value == x + protected def ==(x: scala.Char): scala.Boolean = value == x + protected def ==(x: scala.Int): scala.Boolean = value == x + protected def ==(x: scala.Long): scala.Boolean = value == x + protected def ==(x: scala.Float): scala.Boolean = value == x + protected def ==(x: scala.Double): scala.Boolean = value == x + + protected def !=(x: scala.Byte): scala.Boolean = value != x + protected def !=(x: scala.Short): scala.Boolean = value != x + protected def !=(x: scala.Char): scala.Boolean = value != x + protected def !=(x: scala.Int): scala.Boolean = value != x + protected def !=(x: scala.Long): scala.Boolean = value != x + protected def !=(x: scala.Float): scala.Boolean = value != x + protected def !=(x: scala.Double): scala.Boolean = value != x + + protected def <(x: scala.Byte): scala.Boolean = value < x + protected def <(x: scala.Short): scala.Boolean = value < x + protected def <(x: scala.Char): scala.Boolean = value < x + protected def <(x: scala.Int): scala.Boolean = value < x + protected def <(x: scala.Long): scala.Boolean = value < x + protected def <(x: scala.Float): scala.Boolean = value < x + protected def <(x: scala.Double): scala.Boolean = value < x + + protected def <=(x: scala.Byte): scala.Boolean = value <= x + protected def <=(x: scala.Short): scala.Boolean = value <= x + protected def <=(x: scala.Char): scala.Boolean = value <= x + protected def <=(x: scala.Int): scala.Boolean = value <= x + protected def <=(x: scala.Long): scala.Boolean = value <= x + protected def <=(x: scala.Float): scala.Boolean = value <= x + protected def <=(x: scala.Double): scala.Boolean = value <= x + + protected def >(x: scala.Byte): scala.Boolean = value > x + protected def >(x: scala.Short): scala.Boolean = value > x + protected def >(x: scala.Char): scala.Boolean = value > x + protected def >(x: scala.Int): scala.Boolean = value > x + protected def >(x: scala.Long): scala.Boolean = value > x + protected def >(x: scala.Float): scala.Boolean = value > x + protected def >(x: scala.Double): scala.Boolean = value > x + + protected def >=(x: scala.Byte): scala.Boolean = value >= x + protected def >=(x: scala.Short): scala.Boolean = value >= x + protected def >=(x: scala.Char): scala.Boolean = value >= x + protected def >=(x: scala.Int): scala.Boolean = value >= x + protected def >=(x: scala.Long): scala.Boolean = value >= x + protected def >=(x: scala.Float): scala.Boolean = value >= x + protected def >=(x: scala.Double): scala.Boolean = value >= x + + protected def |(x: scala.Byte): scala.Int = value | x + protected def |(x: scala.Short): scala.Int = value | x + protected def |(x: scala.Char): scala.Int = value | x + protected def |(x: scala.Int): scala.Int = value | x + protected def |(x: scala.Long): scala.Long = value | x + + protected def &(x: scala.Byte): scala.Int = value & x + protected def &(x: scala.Short): scala.Int = value & x + protected def &(x: scala.Char): scala.Int = value & x + protected def &(x: scala.Int): scala.Int = value & x + protected def &(x: scala.Long): scala.Long = value & x + + protected def ^(x: scala.Byte): scala.Int = value ^ x + protected def ^(x: scala.Short): scala.Int = value ^ x + protected def ^(x: scala.Char): scala.Int = value ^ x + protected def ^(x: scala.Int): scala.Int = value ^ x + protected def ^(x: scala.Long): scala.Long = value ^ x + + protected def +(x: scala.Byte): scala.Int = value + x + protected def +(x: scala.Short): scala.Int = value + x + protected def +(x: scala.Char): scala.Int = value + x + protected def +(x: scala.Int): scala.Int = value + x + protected def +(x: scala.Long): scala.Long = value + x + protected def +(x: scala.Float): scala.Float = value + x + protected def +(x: scala.Double): scala.Double = value + x + + protected def -(x: scala.Byte): scala.Int = value - x + protected def -(x: scala.Short): scala.Int = value - x + protected def -(x: scala.Char): scala.Int = value - x + protected def -(x: scala.Int): scala.Int = value - x + protected def -(x: scala.Long): scala.Long = value - x + protected def -(x: scala.Float): scala.Float = value - x + protected def -(x: scala.Double): scala.Double = value - x + + protected def *(x: scala.Byte): scala.Int = value * x + protected def *(x: scala.Short): scala.Int = value * x + protected def *(x: scala.Char): scala.Int = value * x + protected def *(x: scala.Int): scala.Int = value * x + protected def *(x: scala.Long): scala.Long = value * x + protected def *(x: scala.Float): scala.Float = value * x + protected def *(x: scala.Double): scala.Double = value * x + + protected def /(x: scala.Byte): scala.Int = value / x + protected def /(x: scala.Short): scala.Int = value / x + protected def /(x: scala.Char): scala.Int = value / x + protected def /(x: scala.Int): scala.Int = value / x + protected def /(x: scala.Long): scala.Long = value / x + protected def /(x: scala.Float): scala.Float = value / x + protected def /(x: scala.Double): scala.Double = value / x + + protected def %(x: scala.Byte): scala.Int = value % x + protected def %(x: scala.Short): scala.Int = value % x + protected def %(x: scala.Char): scala.Int = value % x + protected def %(x: scala.Int): scala.Int = value % x + protected def %(x: scala.Long): scala.Long = value % x + protected def %(x: scala.Float): scala.Float = value % x + protected def %(x: scala.Double): scala.Double = value % x + +} + +object Character { + final val TYPE = classOf[scala.Char] + final val MIN_VALUE = '\u0000' + final val MAX_VALUE = '\uffff' + final val SIZE = 16 + + def valueOf(charValue: scala.Char) = new Character(charValue) + + /* These are supposed to be final vals of type Byte, but that's not possible. + * So we implement them as def's, which are binary compatible with final vals. + */ + def UPPERCASE_LETTER: scala.Byte = 1 + def LOWERCASE_LETTER: scala.Byte = 2 + def TITLECASE_LETTER: scala.Byte = 3 + def MODIFIER_LETTER: scala.Byte = 4 + def OTHER_LETTER: scala.Byte = 5 + def NON_SPACING_MARK: scala.Byte = 6 + def ENCLOSING_MARK: scala.Byte = 7 + def COMBINING_SPACING_MARK: scala.Byte = 8 + def DECIMAL_DIGIT_NUMBER: scala.Byte = 9 + def LETTER_NUMBER: scala.Byte = 10 + def SURROGATE: scala.Byte = 19 + + final val MIN_RADIX = 2 + final val MAX_RADIX = 36 + + final val MIN_HIGH_SURROGATE = '\uD800' + final val MAX_HIGH_SURROGATE = '\uDBFF' + final val MIN_LOW_SURROGATE = '\uDC00' + final val MAX_LOW_SURROGATE = '\uDFFF' + final val MIN_SURROGATE = MIN_HIGH_SURROGATE + final val MAX_SURROGATE = MAX_LOW_SURROGATE + + final val MIN_CODE_POINT = 0 + final val MAX_CODE_POINT = 0x10ffff + final val MIN_SUPPLEMENTARY_CODE_POINT = 0x10000 + + // Not implemented: + //def getType(ch: scala.Char): scala.Int + //def getType(codePoint: scala.Int): scala.Int + + def digit(c: scala.Char, radix: scala.Int): scala.Int = { + if (radix > MAX_RADIX || radix < MIN_RADIX) + -1 + else if (c >= '0' && c <= '9' && c - '0' < radix) + c - '0' + else if (c >= 'A' && c <= 'Z' && c - 'A' < radix - 10) + c - 'A' + 10 + else if (c >= 'a' && c <= 'z' && c - 'a' < radix - 10) + c - 'a' + 10 + else if (c >= '\uFF21' && c <= '\uFF3A' && + c - '\uFF21' < radix - 10) + c - '\uFF21' + 10 + else if (c >= '\uFF41' && c <= '\uFF5A' && + c - '\uFF41' < radix - 10) + c - '\uFF21' + 10 + else -1 + } + + def isISOControl(c: scala.Char): scala.Boolean = isISOControl(c.toInt) + def isISOControl(codePoint: scala.Int): scala.Boolean = { + (0x00 <= codePoint && codePoint <= 0x1F) || (0x7F <= codePoint && codePoint <= 0x9F) + } + + def isDigit(c: scala.Char): scala.Boolean = c >= '0' && c <= '9' + //def isLetter(c: scala.Char): scala.Boolean + //def isLetterOrDigit(c: scala.Char): scala.Boolean + def isWhitespace(c: scala.Char): scala.Boolean = js.RegExp("^\\s$").test(c.toString) + //def isSpaceChar(c: scala.Char): scala.Boolean + + // --- UTF-16 surrogate pairs handling --- + // See http://en.wikipedia.org/wiki/UTF-16 + + private final val HighSurrogateMask = 0xfc00 // 111111 00 00000000 + private final val HighSurrogateID = 0xd800 // 110110 00 00000000 + private final val LowSurrogateMask = 0xfc00 // 111111 00 00000000 + private final val LowSurrogateID = 0xdc00 // 110111 00 00000000 + private final val SurrogateUsefulPartMask = 0x03ff // 000000 11 11111111 + + @inline def isHighSurrogate(c: scala.Char): scala.Boolean = + (c & HighSurrogateMask) == HighSurrogateID + @inline def isLowSurrogate(c: scala.Char): scala.Boolean = + (c & LowSurrogateMask) == LowSurrogateID + @inline def isSurrogatePair(high: scala.Char, low: scala.Char): scala.Boolean = + isHighSurrogate(high) && isLowSurrogate(low) + + @inline def toCodePoint(high: scala.Char, low: scala.Char): scala.Int = + ((high & SurrogateUsefulPartMask) << 10) + (low & SurrogateUsefulPartMask) + 0x10000 + + // --- End of UTF-16 surrogate pairs handling --- + + def isUnicodeIdentifierStart(c: scala.Char): scala.Boolean = + reUnicodeIdentStart.test(c.toString) + + def isUnicodeIdentifierPart(c: scala.Char): scala.Boolean = + isUnicodeIdentifierStart(c) || isIdentifierIgnorable(c) || + reUnicodeIdentPartExcl.test(c.toString) + + def isIdentifierIgnorable(c: scala.Char): scala.Boolean = + reIdentIgnorable.test(c.toString) + + //def isMirrored(c: scala.Char): scala.Boolean + def isLowerCase(c: scala.Char): scala.Boolean = toLowerCase(c) == c + def isUpperCase(c: scala.Char): scala.Boolean = toUpperCase(c) == c + //def isTitleCase(c: scala.Char): scala.Boolean + //def isJavaIdentifierPart(c: scala.Char): scala.Boolean + + //def getDirectionality(c: scala.Char): scala.Byte + + /* Conversions */ + def toUpperCase(c: scala.Char): scala.Char = c.toString.toUpperCase()(0) + def toLowerCase(c: scala.Char): scala.Char = c.toString.toLowerCase()(0) + //def toTitleCase(c: scala.Char): scala.Char + //def getNumericValue(c: scala.Char): scala.Int + + /* Misc */ + //def reverseBytes(ch: scala.Char): scala.Char + + @inline def toString(c: scala.Char) = js.String.fromCharCode(c.toInt) + + @inline def compare(x: scala.Char, y: scala.Char): scala.Int = + x - y + + // Based on Unicode 7.0.0 + private[this] lazy val reUnicodeIdentStart = + new js.RegExp("""[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]""") + + private[this] lazy val reUnicodeIdentPartExcl = + new js.RegExp("""[0-9\x5F\u0300-\u036F\u0483-\u0487\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u0669\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u06F0-\u06F9\u0711\u0730-\u074A\u07A6-\u07B0\u07C0-\u07C9\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08E4-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0966-\u096F\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09E6-\u09EF\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A66-\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B66-\u0B6F\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0CE6-\u0CEF\u0D01-\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D66-\u0D6F\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0E50-\u0E59\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0ED0-\u0ED9\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1040-\u1049\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u18A9\u1920-\u192B\u1930-\u193B\u1946-\u194F\u19B0-\u19C0\u19C8\u19C9\u19D0-\u19D9\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AB0-\u1ABD\u1B00-\u1B04\u1B34-\u1B44\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BB0-\u1BB9\u1BE6-\u1BF3\u1C24-\u1C37\u1C40-\u1C49\u1C50-\u1C59\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF8\u1CF9\u1DC0-\u1DF5\u1DFC-\u1DFF\u203F\u2040\u2054\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA620-\uA629\uA66F\uA674-\uA67D\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F1\uA900-\uA909\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9D0-\uA9D9\uA9E5\uA9F0-\uA9F9\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA50-\uAA59\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uABF0-\uABF9\uFB1E\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFF10-\uFF19\uFF3F]""") + + private[this] lazy val reIdentIgnorable = + new js.RegExp("""[\0-\x08\x0E-\x1B\x7F-\x9F\xAD\u0600-\u0605\u061C\u06DD\u070F\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]""") + +} diff --git a/javalanglib/src/main/scala/java/lang/Class.scala b/javalanglib/src/main/scala/java/lang/Class.scala new file mode 100644 index 0000000..e8ff46f --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Class.scala @@ -0,0 +1,83 @@ +package java.lang + +import scala.scalajs.js + +private trait ScalaJSClassData[A] extends js.Object { + val name: String = js.native + val isPrimitive: scala.Boolean = js.native + val isInterface: scala.Boolean = js.native + val isArrayClass: scala.Boolean = js.native + + def isInstance(obj: Object): scala.Boolean = js.native + def getFakeInstance(): Object = js.native + + def getSuperclass(): Class[_ >: A] = js.native + def getComponentType(): Class[_] = js.native + + def newArrayOfThisClass(dimensions: js.Array[Int]): AnyRef = js.native +} + +final class Class[A] private (data: ScalaJSClassData[A]) extends Object { + + override def toString(): String = { + (if (isInterface()) "interface " else + if (isPrimitive()) "" else "class ")+getName() + } + + def isInstance(obj: Object): scala.Boolean = + data.isInstance(obj) + + def isAssignableFrom(that: Class[_]): scala.Boolean = + if (this.isPrimitive || that.isPrimitive) { + /* This differs from the JVM specification to mimic the behavior of + * runtime type tests of primitive numeric types. + */ + (this eq that) || { + if (this eq classOf[scala.Short]) + (that eq classOf[scala.Byte]) + else if (this eq classOf[scala.Int]) + (that eq classOf[scala.Byte]) || (that eq classOf[scala.Short]) + else if (this eq classOf[scala.Float]) + (that eq classOf[scala.Byte]) || (that eq classOf[scala.Short]) || + (that eq classOf[scala.Int]) + else if (this eq classOf[scala.Double]) + (that eq classOf[scala.Byte]) || (that eq classOf[scala.Short]) || + (that eq classOf[scala.Int]) || (that eq classOf[scala.Float]) + else + false + } + } else { + this.isInstance(that.getFakeInstance()) + } + + private def getFakeInstance(): Object = + data.getFakeInstance() + + def isInterface(): scala.Boolean = + data.isInterface + + def isArray(): scala.Boolean = + data.isArrayClass + + def isPrimitive(): scala.Boolean = + data.isPrimitive + + def getName(): String = + data.name + + def getSimpleName(): String = + data.name.split('.').last.split('$').last + + def getSuperclass(): Class[_ >: A] = + data.getSuperclass() + + def getComponentType(): Class[_] = + data.getComponentType() + + def getEnclosingClass(): Class[_] = null + + // java.lang.reflect.Array support + + private[lang] def newArrayOfThisClass(dimensions: js.Array[Int]): AnyRef = + data.newArrayOfThisClass(dimensions) +} diff --git a/javalanglib/src/main/scala/java/lang/Cloneable.scala b/javalanglib/src/main/scala/java/lang/Cloneable.scala new file mode 100644 index 0000000..4183bf5 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Cloneable.scala @@ -0,0 +1,3 @@ +package java.lang + +trait Cloneable diff --git a/javalanglib/src/main/scala/java/lang/Comparable.scala b/javalanglib/src/main/scala/java/lang/Comparable.scala new file mode 100644 index 0000000..8d17c6f --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Comparable.scala @@ -0,0 +1,5 @@ +package java.lang + +trait Comparable[A] { + def compareTo(o: A): scala.Int +} diff --git a/javalanglib/src/main/scala/java/lang/Double.scala b/javalanglib/src/main/scala/java/lang/Double.scala new file mode 100644 index 0000000..25987ac --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Double.scala @@ -0,0 +1,110 @@ +package java.lang + +import scala.scalajs.js + +/* This is a hijacked class. Its instances are primitive numbers. + * Constructors are not emitted. + */ +final class Double private () extends Number with Comparable[Double] { + + def this(value: scala.Double) = this() + def this(s: String) = this() + + @inline def doubleValue(): scala.Double = + this.asInstanceOf[scala.Double] + + @inline override def byteValue(): scala.Byte = doubleValue.toByte + @inline override def shortValue(): scala.Short = doubleValue.toShort + @inline def intValue(): scala.Int = doubleValue.toInt + @inline def longValue(): scala.Long = doubleValue.toLong + @inline def floatValue(): scala.Float = doubleValue.toFloat + + override def equals(that: Any): scala.Boolean = that match { + case that: Double => + val a = doubleValue + val b = that.doubleValue + (a == b) || (Double.isNaN(a) && Double.isNaN(b)) + case _ => + false + } + + @inline override def hashCode(): Int = + scala.scalajs.runtime.Bits.numberHashCode(doubleValue) + + @inline override def compareTo(that: Double): Int = + Double.compare(doubleValue, that.doubleValue) + + @inline override def toString(): String = + Double.toString(doubleValue) + + @inline def isNaN(): scala.Boolean = + Double.isNaN(doubleValue) + + @inline def isInfinite(): scala.Boolean = + Double.isInfinite(doubleValue) + +} + +object Double { + final val TYPE = classOf[scala.Double] + final val POSITIVE_INFINITY = 1.0 / 0.0 + final val NEGATIVE_INFINITY = 1.0 / -0.0 + final val NaN = 0.0 / 0.0 + final val MAX_VALUE = scala.Double.MaxValue + final val MIN_VALUE = scala.Double.MinPositiveValue + final val MAX_EXPONENT = 1023 + final val MIN_EXPONENT = -1022 + final val SIZE = 64 + + @inline def valueOf(doubleValue: scala.Double): Double = + new Double(doubleValue) + + @inline def valueOf(s: String): Double = valueOf(parseDouble(s)) + + private[this] lazy val doubleStrPat = new js.RegExp("^" + + "[\\x00-\\x20]*" + // optional whitespace + "[+-]?" + // optional sign + "(NaN|Infinity|" + // special cases + "(\\d+\\.?\\d*|" + // literal w/ leading digit + "\\.\\d+)" + // literal w/o leading digit + "([eE][+-]?\\d+)?"+ // optional exponent + ")[fFdD]?" + // optional float / double specifier (ignored) + "[\\x00-\\x20]*" + // optional whitespace + "$") + + def parseDouble(s: String): scala.Double = { + if (doubleStrPat.test(s)) + js.parseFloat(s) + else + throw new NumberFormatException(s"""For input string: "$s"""") + } + + @inline def toString(d: scala.Double): String = + "" + d + + def compare(a: scala.Double, b: scala.Double): scala.Int = { + // NaN must equal itself, and be greater than anything else + if (isNaN(a)) { + if (isNaN(b)) 0 + else 1 + } else if (isNaN(b)) { + -1 + } else { + if (a == b) 0 + else if (a < b) -1 + else 1 + } + } + + @inline def isNaN(v: scala.Double): scala.Boolean = + v != v + + @inline def isInfinite(v: scala.Double): scala.Boolean = + v == POSITIVE_INFINITY || v == NEGATIVE_INFINITY + + @inline def longBitsToDouble(bits: scala.Long): scala.Double = + scala.scalajs.runtime.Bits.longBitsToDouble(bits) + + @inline def doubleToLongBits(value: scala.Double): scala.Long = + scala.scalajs.runtime.Bits.doubleToLongBits(value) +} diff --git a/javalanglib/src/main/scala/java/lang/Float.scala b/javalanglib/src/main/scala/java/lang/Float.scala new file mode 100644 index 0000000..70cb33e --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Float.scala @@ -0,0 +1,96 @@ +package java.lang + +/* This is a hijacked class. Its instances are primitive numbers. + * Constructors are not emitted. + */ +final class Float private () extends Number with Comparable[Float] { + + def this(value: scala.Float) = this() + def this(s: String) = this() + + @inline def floatValue(): scala.Float = + this.asInstanceOf[scala.Float] + + @inline override def byteValue(): scala.Byte = floatValue.toByte + @inline override def shortValue(): scala.Short = floatValue.toShort + @inline def intValue(): scala.Int = floatValue.toInt + @inline def longValue(): scala.Long = floatValue.toLong + @inline def doubleValue(): scala.Double = floatValue.toDouble + + override def equals(that: Any): scala.Boolean = that match { + case that: Double => // yes, Double + val a = doubleValue + val b = that.doubleValue + (a == b) || (Double.isNaN(a) && Double.isNaN(b)) + case _ => + false + } + + // Uses the hashCode of Doubles. See Bits.numberHashCode for the rationale. + @inline override def hashCode(): Int = + scala.scalajs.runtime.Bits.numberHashCode(doubleValue) + + @inline override def compareTo(that: Float): Int = + Float.compare(floatValue, that.floatValue) + + @inline override def toString(): String = + Float.toString(floatValue) + + @inline def isNaN(): scala.Boolean = + Float.isNaN(floatValue) + + @inline def isInfinite(): scala.Boolean = + Float.isInfinite(floatValue) + +} + +object Float { + final val TYPE = classOf[scala.Float] + final val POSITIVE_INFINITY = 1.0f / 0.0f + final val NEGATIVE_INFINITY = 1.0f / -0.0f + final val NaN = 0.0f / 0.0f + final val MAX_VALUE = scala.Float.MaxValue + final val MIN_VALUE = scala.Float.MinPositiveValue + final val MAX_EXPONENT = 127 + final val MIN_EXPONENT = -126 + final val SIZE = 32 + + @inline def valueOf(floatValue: scala.Float): Float = new Float(floatValue) + + @inline def valueOf(s: String): Float = valueOf(parseFloat(s)) + + @inline def parseFloat(s: String): scala.Float = + Double.parseDouble(s).toFloat + + @inline def toString(f: scala.Float): String = + "" + f + + def compare(a: scala.Float, b: scala.Float): scala.Int = { + // NaN must equal itself, and be greater than anything else + if (isNaN(a)) { + if (isNaN(b)) 0 + else 1 + } else if (isNaN(b)) { + -1 + } else { + if (a == b) 0 + else if (a < b) -1 + else 1 + } + } + + @inline protected def equals(a: scala.Float, b: scala.Float): scala.Boolean = + a == b || (isNaN(a) && isNaN(b)) + + @inline def isNaN(v: scala.Float): scala.Boolean = + v != v + + @inline def isInfinite(v: scala.Float): scala.Boolean = + v == POSITIVE_INFINITY || v == NEGATIVE_INFINITY + + @inline def intBitsToFloat(bits: scala.Int): scala.Float = + scala.scalajs.runtime.Bits.intBitsToFloat(bits) + + @inline def floatToIntBits(value: scala.Float): scala.Int = + scala.scalajs.runtime.Bits.floatToIntBits(value) +} diff --git a/javalanglib/src/main/scala/java/lang/InheritableThreadLocal.scala b/javalanglib/src/main/scala/java/lang/InheritableThreadLocal.scala new file mode 100644 index 0000000..92ef07c --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/InheritableThreadLocal.scala @@ -0,0 +1,5 @@ +package java.lang + +class InheritableThreadLocal[T] extends ThreadLocal[T] { + protected def childValue(parentValue: T): T = parentValue +} diff --git a/javalanglib/src/main/scala/java/lang/Integer.scala b/javalanglib/src/main/scala/java/lang/Integer.scala new file mode 100644 index 0000000..a002fb7 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Integer.scala @@ -0,0 +1,129 @@ +package java.lang + +import scala.scalajs.js + +/* This is a hijacked class. Its instances are primitive numbers. + * Constructors are not emitted. + */ +final class Integer private () extends Number with Comparable[Integer] { + + def this(value: scala.Int) = this() + def this(s: String) = this() + + @inline def intValue(): scala.Int = + this.asInstanceOf[scala.Int] + + @inline override def byteValue(): scala.Byte = intValue.toByte + @inline override def shortValue(): scala.Short = intValue.toShort + @inline def longValue(): scala.Long = intValue.toLong + @inline def floatValue(): scala.Float = intValue.toFloat + @inline def doubleValue(): scala.Double = intValue.toDouble + + @inline override def equals(that: Any): scala.Boolean = + this eq that.asInstanceOf[AnyRef] + + @inline override def hashCode(): Int = + intValue + + @inline override def compareTo(that: Integer): Int = + Integer.compare(intValue, that.intValue) + + @inline override def toString(): String = + Integer.toString(intValue) + +} + +object Integer { + final val TYPE = classOf[scala.Int] + final val MIN_VALUE = -2147483648 + final val MAX_VALUE = 2147483647 + final val SIZE = 32 + + @inline def valueOf(intValue: scala.Int): Integer = new Integer(intValue) + @inline def valueOf(s: String): Integer = valueOf(parseInt(s)) + + @inline def valueOf(s: String, radix: Int): Integer = + valueOf(parseInt(s, radix)) + + @inline def parseInt(s: String): scala.Int = parseInt(s, 10) + + def parseInt(s: String, radix: scala.Int): scala.Int = { + def fail = throw new NumberFormatException(s"""For input string: "$s"""") + + if (s == null || s.size == 0 || + radix < Character.MIN_RADIX || + radix > Character.MAX_RADIX) + fail + else { + var i = if (s(0) == '-' || s(0) == '+') 1 else 0 + // JavaDoc says: We need at least one digit + if (s.size <= i) fail + else { + // Check each character for validity + while (i < s.size) { + if (Character.digit(s(i), radix) < 0) fail + i += 1 + } + val res = js.parseInt(s, radix) + + if (js.isNaN(res) || res > MAX_VALUE || res < MIN_VALUE) + fail + else + res.toInt + } + } + } + + @inline def toString(i: scala.Int): String = + "" + i + + @inline def compare(x: scala.Int, y: scala.Int): scala.Int = + if (x == y) 0 else if (x < y) -1 else 1 + + def bitCount(i: scala.Int): scala.Int = { + // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + // The implicit casts to 32-bit ints due to binary ops make this work in JS too + val t1 = i - ((i >> 1) & 0x55555555) + val t2 = (t1 & 0x33333333) + ((t1 >> 2) & 0x33333333) + ((t2 + (t2 >> 4) & 0xF0F0F0F) * 0x1010101) >> 24 + } + + def reverseBytes(i: scala.Int): scala.Int = { + val byte3 = i >>> 24 + val byte2 = (i >>> 8) & 0xFF00 + val byte1 = (i << 8) & 0xFF0000 + val byte0 = (i << 24) + byte0 | byte1 | byte2 | byte3 + } + + def rotateLeft(i: scala.Int, distance: scala.Int): scala.Int = + (i << distance) | (i >>> -distance) + + def rotateRight(i: scala.Int, distance: scala.Int): scala.Int = + (i >>> distance) | (i << -distance) + + @inline def signum(i: scala.Int): scala.Int = + if (i == 0) 0 else if (i < 0) -1 else 1 + + def numberOfLeadingZeros(i: scala.Int): scala.Int = { + // See http://aggregate.org/MAGIC/#Leading%20Zero%20Count + var x = i + x |= (x >>> 1) + x |= (x >>> 2) + x |= (x >>> 4) + x |= (x >>> 8) + x |= (x >>> 16) + 32 - bitCount(x) + } + + def numberOfTrailingZeros(i: scala.Int): scala.Int = + // See http://aggregate.org/MAGIC/#Trailing%20Zero%20Count + bitCount((i & -i) - 1) + + def toBinaryString(i: scala.Int): String = toStringBase(i, 2) + def toHexString(i: scala.Int): String = toStringBase(i, 16) + def toOctalString(i: scala.Int): String = toStringBase(i, 8) + + @inline private[this] def toStringBase(i: scala.Int, base: scala.Int): String = + ((i: js.prim.Number) >>> 0).toString(base) +} diff --git a/javalanglib/src/main/scala/java/lang/Long.scala b/javalanglib/src/main/scala/java/lang/Long.scala new file mode 100644 index 0000000..beeef32 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Long.scala @@ -0,0 +1,196 @@ +package java.lang + +import scala.annotation.tailrec + +import scala.scalajs.js + +/* This is a hijacked class. Its instances are the representation of scala.Longs. + * Constructors are not emitted. + */ +final class Long private () extends Number with Comparable[Long] { + def this(value: scala.Long) = this() + def this(s: String) = this() + + @inline def longValue(): scala.Long = + this.asInstanceOf[scala.Long] + + @inline override def byteValue(): scala.Byte = longValue.toByte + @inline override def shortValue(): scala.Short = longValue.toShort + @inline def intValue(): scala.Int = longValue.toInt + @inline def floatValue(): scala.Float = longValue.toFloat + @inline def doubleValue(): scala.Double = longValue.toDouble + + @inline override def equals(that: Any): scala.Boolean = that match { + case that: Long => longValue == that.longValue + case _ => false + } + + @inline override def hashCode(): Int = + (longValue ^ (longValue >>> 32)).toInt + + @inline override def compareTo(that: Long): Int = + Long.compare(longValue, that.longValue) + + @inline override def toString(): String = + Long.toString(longValue) + +} + +object Long { + import scala.scalajs.runtime.RuntimeLong + + final val TYPE = classOf[scala.Long] + final val MIN_VALUE = -9223372036854775808L + final val MAX_VALUE = 9223372036854775807L + final val SIZE = 64 + + @inline def valueOf(longValue: scala.Long): Long = new Long(longValue) + @inline def valueOf(s: String): Long = valueOf(parseLong(s)) + + @inline def valueOf(s: String, radix: Int): Long = + valueOf(parseLong(s, radix)) + + @inline def parseLong(s: String): scala.Long = + parseLong(s, 10) + + def parseLong(s: String, radix: Int): scala.Long = { + def fail() = throw new NumberFormatException(s"""For input string: "$s"""") + + if (s.isEmpty) { + fail() + } else if (s.charAt(0) == '-') { + -parseLong(s.substring(1), radix) + } else { + @inline + @tailrec + def fastPow(base: Int, exp: Int, acc: Int = 1): Int = + if (exp == 0) acc + else if (exp % 2 == 0) fastPow(base*base, exp/2, acc) + else fastPow(base, exp-1, acc*base) + + @inline + @tailrec + def loop(str0: String, acc: scala.Long): scala.Long = if (str0.length > 0) { + val MaxLen = 9 + val cur = (str0: js.prim.String).substring(0, MaxLen): String + val macc = acc * fastPow(radix, cur.length) + val ival = js.parseInt(cur, radix): scala.Double + if (ival.isNaN) + fail() + val cval = ival.toInt.toLong // faster than ival.toLong + loop((str0: js.prim.String).substring(MaxLen), macc + cval) + } else acc + + loop(s, 0L) + } + } + + def toString(l: scala.Long): String = { + if (l == 0L) "0" + // Check for MinValue, because it is not negatable + else if (l == MIN_VALUE) "-9223372036854775808" + else if (l < 0L) "-" + toString(-l) + else { + @tailrec + @inline + def toString0(v: scala.Long, acc: String): String = { + val quot = v / 1000000000L // 9 zeros + val rem = v % 1000000000L + + val digits = rem.toInt.toString + + if (quot == 0L) { + digits + acc + } else { + val padding = "000000000".substring(digits.length) // (9 - digits.length) zeros + toString0(quot, padding + digits + acc) + } + } + + toString0(l, "") + } + } + + @inline def compare(x: scala.Long, y: scala.Long): scala.Int = + if (x == y) 0 else if (x < y) -1 else 1 + + def bitCount(i: scala.Long): scala.Int = { + val lo = i.toInt + val hi = (i >>> 32).toInt + Integer.bitCount(lo) + Integer.bitCount(hi) + } + + def reverseBytes(i: scala.Long): scala.Long = { + val hiReversed = Integer.reverseBytes((i >>> 32).toInt) + val loReversed = Integer.reverseBytes(i.toInt) + (loReversed.toLong << 32) | (hiReversed.toLong & 0xffffffffL) + } + + def rotateLeft(i: scala.Long, distance: scala.Int): scala.Long = + (i << distance) | (i >>> -distance) + + def rotateRight(i: scala.Long, distance: scala.Int): scala.Long = + (i >>> distance) | (i << -distance) + + def signum(i: scala.Long): scala.Long = + if (i < 0L) -1L else if (i == 0L) 0L else 1L + + def numberOfLeadingZeros(l: scala.Long): Int = { + val hi = (l >>> 32).toInt + if (hi != 0) Integer.numberOfLeadingZeros(hi) + else Integer.numberOfLeadingZeros(l.toInt) + 32 + } + + def numberOfTrailingZeros(l: scala.Long): Int = { + val lo = l.toInt + if (lo != 0) Integer.numberOfTrailingZeros(lo) + else Integer.numberOfTrailingZeros((l >>> 32).toInt) + 32 + } + + def toBinaryString(l: scala.Long): String = { + val zeros = "00000000000000000000000000000000" // 32 zeros + @inline def padBinary32(i: Int) = { + val s = Integer.toBinaryString(i) + zeros.substring(s.length) + s + } + + val lo = l.toInt + val hi = (l >>> 32).toInt + + if (hi != 0) Integer.toBinaryString(hi) + padBinary32(lo) + else Integer.toBinaryString(lo) + } + + def toHexString(l: scala.Long): String = { + val zeros = "00000000" // 8 zeros + @inline def padBinary8(i: Int) = { + val s = Integer.toHexString(i) + zeros.substring(s.length) + s + } + + val lo = l.toInt + val hi = (l >>> 32).toInt + + if (hi != 0) Integer.toHexString(hi) + padBinary8(lo) + else Integer.toHexString(lo) + } + + def toOctalString(l: scala.Long): String = { + val zeros = "0000000000" // 10 zeros + @inline def padOctal10(i: Int) = { + val s = Integer.toOctalString(i) + zeros.substring(s.length) + s + } + + val lo = l.toInt + val hi = (l >>> 32).toInt + + val lp = lo & 0x3fffffff + val mp = ((lo >>> 30) + (hi << 2)) & 0x3fffffff + val hp = hi >>> 28 + + if (hp != 0) Integer.toOctalString(hp) + padOctal10(mp) + padOctal10(lp) + else if (mp != 0) Integer.toOctalString(mp) + padOctal10(lp) + else Integer.toOctalString(lp) + } +} diff --git a/javalanglib/src/main/scala/java/lang/Math.scala b/javalanglib/src/main/scala/java/lang/Math.scala new file mode 100644 index 0000000..c8cd7aa --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Math.scala @@ -0,0 +1,211 @@ +package java +package lang + +import scala.scalajs.js + +object Math { + private lazy val internalRandom = new java.util.Random() + + final val E = 2.718281828459045 + final val PI = 3.141592653589793 + + @inline def abs(a: scala.Int): scala.Int = if (a < 0) -a else a + @inline def abs(a: scala.Long): scala.Long = if (a < 0) -a else a + @inline def abs(a: scala.Float): scala.Float = if (a < 0) -a else a + @inline def abs(a: scala.Double): scala.Double = if (a < 0) -a else a + + @inline def max(a: scala.Int, b: scala.Int): scala.Int = if (a > b) a else b + @inline def max(a: scala.Long, b: scala.Long): scala.Long = if (a > b) a else b + @inline def max(a: scala.Float, b: scala.Float): scala.Float = if (a > b) a else b + @inline def max(a: scala.Double, b: scala.Double): scala.Double = if (a > b) a else b + + @inline def min(a: scala.Int, b: scala.Int): scala.Int = if (a < b) a else b + @inline def min(a: scala.Long, b: scala.Long): scala.Long = if (a < b) a else b + @inline def min(a: scala.Float, b: scala.Float): scala.Float = if (a < b) a else b + @inline def min(a: scala.Double, b: scala.Double): scala.Double = if (a < b) a else b + + @inline def ceil(a: scala.Double): scala.Double = js.Math.ceil(a) + @inline def floor(a: scala.Double): scala.Double = js.Math.floor(a) + + @inline def round(a: scala.Float): scala.Int = js.Math.round(a).toInt + @inline def round(a: scala.Double): scala.Long = js.Math.round(a).toLong + + @inline def sqrt(a: scala.Double): scala.Double = js.Math.sqrt(a) + @inline def pow(a: scala.Double, b: scala.Double): scala.Double = js.Math.pow(a, b) + + @inline def exp(a: scala.Double): scala.Double = js.Math.exp(a) + @inline def log(a: scala.Double): scala.Double = js.Math.log(a) + @inline def log10(a: scala.Double): scala.Double = log(a) / 2.302585092994046 + @inline def log1p(a: scala.Double): scala.Double = log(a + 1) + + @inline def sin(a: scala.Double): scala.Double = js.Math.sin(a) + @inline def cos(a: scala.Double): scala.Double = js.Math.cos(a) + @inline def tan(a: scala.Double): scala.Double = js.Math.tan(a) + @inline def asin(a: scala.Double): scala.Double = js.Math.asin(a) + @inline def acos(a: scala.Double): scala.Double = js.Math.acos(a) + @inline def atan(a: scala.Double): scala.Double = js.Math.atan(a) + @inline def atan2(y: scala.Double, x: scala.Double): scala.Double = js.Math.atan2(y, x) + + def random(): scala.Double = internalRandom.nextDouble() + + @inline def toDegrees(a: scala.Double): scala.Double = a * 180.0 / PI + @inline def toRadians(a: scala.Double): scala.Double = a / 180.0 * PI + + @inline def signum(a: scala.Double): scala.Double = { + if (a > 0) 1.0 + else if (a < 0) -1.0 + else a + } + + @inline def signum(a: scala.Float): scala.Float = { + if (a > 0) 1.0f + else if (a < 0) -1.0f + else a + } + + def cbrt(a: scala.Double): scala.Double = { + if (a == 0 || a.isNaN) + return a + + val sign = if (a < 0.0) -1.0 else 1.0 + val value = sign * a + + //Initial Approximation + var x = 0.0 + var xi = pow(value, 0.3333333333333333) + + //Halley's Method (http://metamerist.com/cbrt/cbrt.htm) + while (abs(x - xi) >= 1E-16) { + x = xi + val x3 = js.Math.pow(x, 3) + val x3Plusa = x3 + value + xi = x * (x3Plusa + value) / (x3Plusa + x3) + } + return sign * xi + } + + def nextUp(a: scala.Double): scala.Double = { + // js implementation of nextUp https://gist.github.com/Yaffle/4654250 + import scala.Double._ + if (a != a || a == PositiveInfinity) + a + else if (a == NegativeInfinity) + -MaxValue + else if (a == MaxValue) + PositiveInfinity + else if (a == 0) + MinValue + else { + def iter(x: scala.Double, xi: scala.Double, n: scala.Double): scala.Double = { + if (Math.abs(xi - x) >= 1E-16) { + val c0 = (xi + x) / 2 + val c = + if (c0 == NegativeInfinity || c0 == PositiveInfinity) + x + (xi - x) / 2 + else + c0 + if (n == c) xi + else if (a < c) iter(x = x, xi = c, n = c) + else iter(x = c, xi = xi, n = c) + } + else xi + } + val d = Math.max(Math.abs(a) * 2E-16, MinValue) + val ad = a + d + val xi0 = + if (ad == PositiveInfinity) MaxValue + else ad + iter(x = a, xi = xi0, n = a) + } + } + + def nextAfter(a: scala.Double, b: scala.Double): scala.Double = { + if (b < a) + -nextUp(-a) + else if (a < b) + nextUp(a) + else if (a != a || b != b) + scala.Double.NaN + else + b + } + + def ulp(a: scala.Double): scala.Double = { + if (abs(a) == scala.Double.PositiveInfinity) + scala.Double.PositiveInfinity + else if (abs(a) == scala.Double.MaxValue) + pow(2, 971) + else + nextAfter(abs(a), scala.Double.MaxValue) - a + } + + def hypot(a: scala.Double, b: scala.Double): scala.Double = { + // http://en.wikipedia.org/wiki/Hypot#Implementation + if (abs(a) == scala.Double.PositiveInfinity || abs(b) == scala.Double.PositiveInfinity) + scala.Double.PositiveInfinity + else if (a.isNaN || b.isNaN) + scala.Double.NaN + else if (a == 0 && b == 0) + 0.0 + else { + //To Avoid Overflow and UnderFlow + // calculate |x| * sqrt(1 - (y/x)^2) instead of sqrt(x^2 + y^2) + val x = abs(a) + val y = abs(b) + val m = max(x, y) + val t = min(x, y) / m + m * sqrt(1 + t * t) + } + } + + def expm1(a: scala.Double): scala.Double = { + // https://github.com/ghewgill/picomath/blob/master/javascript/expm1.js + if (a == 0 || a.isNaN) + a + // Power Series http://en.wikipedia.org/wiki/Power_series + // for small values of a, exp(a) = 1 + a + (a*a)/2 + else if (abs(a) < 1E-5) + a + 0.5 * a * a + else + exp(a) - 1.0 + } + + def sinh(a: scala.Double): scala.Double = { + if (a.isNaN || a == 0.0 || abs(a) == scala.Double.PositiveInfinity) + a + else + (exp(a) - exp(-a)) / 2.0 + } + + def cosh(a: scala.Double): scala.Double = { + if (a.isNaN) + a + else if (a == 0.0) + 1.0 + else if (abs(a) == scala.Double.PositiveInfinity) + scala.Double.PositiveInfinity + else + (exp(a) + exp(-a)) / 2.0 + } + + def tanh(a: scala.Double): scala.Double = { + if (a.isNaN || a == 0.0) + a + else if (abs(a) == scala.Double.PositiveInfinity) + signum(a) + else { + // sinh(a) / cosh(a) = + // 1 - 2 * (exp(-a)/ (exp(-a) + exp (a))) + val expma = exp(-a) + if (expma == scala.Double.PositiveInfinity) //Infinity / Infinity + -1.0 + else { + val expa = exp(a) + val ret = expma / (expa + expma) + 1.0 - (2.0 * ret) + } + } + } + + // TODO The methods not available in the JavaScript Math object +} diff --git a/javalanglib/src/main/scala/java/lang/Number.scala b/javalanglib/src/main/scala/java/lang/Number.scala new file mode 100644 index 0000000..05ffc7a --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Number.scala @@ -0,0 +1,12 @@ +package java.lang + +import scala.scalajs.js + +abstract class Number extends Object { + def byteValue(): scala.Byte = intValue.toByte + def shortValue(): scala.Short = intValue.toShort + def intValue(): scala.Int + def longValue(): scala.Long + def floatValue(): scala.Float + def doubleValue(): scala.Double +} diff --git a/javalanglib/src/main/scala/java/lang/Readable.scala b/javalanglib/src/main/scala/java/lang/Readable.scala new file mode 100644 index 0000000..53e5689 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Readable.scala @@ -0,0 +1,7 @@ +package java.lang + +import java.nio.CharBuffer + +trait Readable { + def read(cb: CharBuffer): Int +} diff --git a/javalanglib/src/main/scala/java/lang/Runnable.scala b/javalanglib/src/main/scala/java/lang/Runnable.scala new file mode 100644 index 0000000..c98cb41 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Runnable.scala @@ -0,0 +1,5 @@ +package java.lang + +trait Runnable { + def run(): Unit +} diff --git a/javalanglib/src/main/scala/java/lang/Runtime.scala b/javalanglib/src/main/scala/java/lang/Runtime.scala new file mode 100644 index 0000000..25aaa9f --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Runtime.scala @@ -0,0 +1,47 @@ +package java.lang + +import scala.scalajs.js + +class Runtime private { + def exit(status: Int): Unit = + halt(status) + + //def addShutdownHook(hook: Thread): Unit + //def removeShutdownHook(hook: Thread): Unit + + def halt(status: Int): Unit = { + val envInfo = scala.scalajs.runtime.environmentInfo + + if (js.typeOf(envInfo.exitFunction) == "function") { + envInfo.exitFunction(status) + throw new IllegalStateException("__ScalaJSEnv.exitFunction returned") + } else { + // We don't have an exit function. Fail + throw new SecurityException("Cannot terminate a JavaScript program. " + + "Define a JavaScript function `__ScalaJSEnv.exitFunction` to " + + "be called on exit.") + } + } + + def availableProcessors(): Int = 1 + //def freeMemory(): scala.Long + //def totalMemory(): scala.Long + //def maxMemory(): scala.Long + + def gc(): Unit = { + // Ignore + } + + //def runFinalization(): Unit + //def traceInstructions(on: scala.Boolean): Unit + //def traceMethodCalls(on: scala.Boolean): Unit + + //def load(filename: String): Unit + //def loadLibrary(filename: String): Unit +} + +object Runtime { + private val currentRuntime = new Runtime + + def getRuntime() = currentRuntime +} diff --git a/javalanglib/src/main/scala/java/lang/Short.scala b/javalanglib/src/main/scala/java/lang/Short.scala new file mode 100644 index 0000000..135fe12 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Short.scala @@ -0,0 +1,73 @@ +package java.lang + +/* This is a hijacked class. Its instances are primitive numbers. + * Constructors are not emitted. + */ +final class Short private () extends Number with Comparable[Short] { + + def this(value: scala.Short) = this() + def this(s: String) = this() + + @inline override def shortValue(): scala.Short = + this.asInstanceOf[scala.Short] + + @inline override def byteValue(): scala.Byte = shortValue.toByte + @inline def intValue(): scala.Int = shortValue.toInt + @inline def longValue(): scala.Long = shortValue.toLong + @inline def floatValue(): scala.Float = shortValue.toFloat + @inline def doubleValue(): scala.Double = shortValue.toDouble + + @inline override def equals(that: Any): scala.Boolean = + this eq that.asInstanceOf[AnyRef] + + @inline override def hashCode(): Int = + shortValue + + @inline override def compareTo(that: Short): Int = + Short.compare(shortValue, that.shortValue) + + @inline override def toString(): String = + Short.toString(shortValue) + +} + +object Short { + final val TYPE = classOf[scala.Short] + final val SIZE = 16 + + /* MIN_VALUE and MAX_VALUE should be 'final val's. But it is impossible to + * write a proper Short literal in Scala, that would both considered a Short + * and a constant expression (optimized as final val). + * Since vals and defs are binary-compatible (although they're not strictly + * speaking source-compatible, because of stability), we implement them as + * defs. Source-compatibility is not an issue because user code is compiled + * against the JDK .class files anyway. + */ + def MIN_VALUE: scala.Short = -32768 + def MAX_VALUE: scala.Short = 32767 + + @inline def valueOf(shortValue: scala.Short): Short = new Short(shortValue) + @inline def valueOf(s: String): Short = valueOf(parseShort(s)) + + @inline def valueOf(s: String, radix: Int): Short = + valueOf(parseShort(s, radix)) + + @inline def parseShort(s: String): scala.Short = parseShort(s, 10) + + def parseShort(s: String, radix: Int): scala.Short = { + val r = Integer.parseInt(s, radix) + if (r < MIN_VALUE || r > MAX_VALUE) + throw new NumberFormatException(s"""For input string: "$s"""") + else + r.toShort + } + + @inline def toString(s: scala.Short): String = + "" + s + + @inline def compare(x: scala.Short, y: scala.Short): scala.Int = + x - y + + def reverseBytes(i: scala.Short): scala.Short = + (((i >>> 8) & 0xff) + ((i & 0xff) << 8)).toShort +} diff --git a/javalanglib/src/main/scala/java/lang/StackTraceElement.scala b/javalanglib/src/main/scala/java/lang/StackTraceElement.scala new file mode 100644 index 0000000..cc87aec --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/StackTraceElement.scala @@ -0,0 +1,55 @@ +package java.lang + +import scala.scalajs.js + +final class StackTraceElement(declaringClass: String, methodName: String, + fileName: String, lineNumber: Int) extends AnyRef with java.io.Serializable { + + def getFileName(): String = fileName + def getLineNumber(): Int = lineNumber + def getClassName(): String = declaringClass + def getMethodName(): String = methodName + def isNativeMethod(): scala.Boolean = false + + override def equals(that: Any): scala.Boolean = that match { + case that: StackTraceElement => + (getFileName == that.getFileName) && + (getLineNumber == that.getLineNumber) && + (getClassName == that.getClassName) && + (getMethodName == that.getMethodName) + case _ => + false + } + + override def toString(): String = { + var result = "" + if (declaringClass != "<jscode>") + result += declaringClass + "." + result += methodName + if (fileName eq null) { + if (isNativeMethod) + result += "(Native Method)" + else + result += "(Unknown Source)" + } else { + result += s"($fileName" + if (lineNumber >= 0) { + result += s":$lineNumber" + if (columnNumber >= 0) + result += s":$columnNumber" + } + result += ")" + } + result + } + + override def hashCode(): Int = { + declaringClass.hashCode() ^ methodName.hashCode() + } + + private def columnNumber: Int = { + val rawNum = this.asInstanceOf[js.Dynamic].columnNumber + if (!(!rawNum)) rawNum.asInstanceOf[Int] + else -1 + } +} diff --git a/javalanglib/src/main/scala/java/lang/StringBuffer.scala b/javalanglib/src/main/scala/java/lang/StringBuffer.scala new file mode 100644 index 0000000..31ee89a --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/StringBuffer.scala @@ -0,0 +1,159 @@ +package java.lang + +class StringBuffer(private var content: String) extends CharSequence + with Appendable + with java.io.Serializable { + def this() = this("") + def this(initialCapacity: Int) = this("") + def this(csq: CharSequence) = this(csq.toString) + + def append(s: String): StringBuffer = { + content += { if (s == null) "null" else s } + this + } + + def append(b: scala.Boolean): StringBuffer = append(b.toString()) + def append(c: scala.Char): StringBuffer = append(c.toString()) + + def append(str: Array[scala.Char]): StringBuffer = + append(str, 0, str.length) + + def append(str: Array[scala.Char], offset: Int, len: Int): StringBuffer = { + var i = 0 + while (i < len) { + content += str(i + offset) + i += 1 + } + this + } + + def append(b: scala.Byte): StringBuffer = append(b.toString()) + def append(s: scala.Short): StringBuffer = append(s.toString()) + def append(i: scala.Int): StringBuffer = append(i.toString()) + def append(lng: scala.Long): StringBuffer = append(lng.toString()) + def append(f: scala.Float): StringBuffer = append(f.toString()) + def append(d: scala.Double): StringBuffer = append(d.toString()) + + def append(obj: AnyRef): StringBuffer = { + if (obj == null) append(null: String) + else append(obj.toString()) + } + + def append(csq: CharSequence): StringBuffer = append(csq: AnyRef) + def append(csq: CharSequence, start: Int, end: Int): StringBuffer = { + if (csq == null) append("null", start, end) + else append(csq.subSequence(start, end).toString()) + } + + override def toString() = content + + def length() = content.length() + + def charAt(index: Int) = content.charAt(index) + def codePointAt(index: Int) = content.codePointAt(index) + + def indexOf(str: String) = content.indexOf(str) + def indexOf(str: String, fromIndex: Int) = content.indexOf(str, fromIndex) + + def lastIndexOf(str: String) = content.lastIndexOf(str) + def lastIndexOf(str: String, fromIndex: Int) = content.lastIndexOf(str, fromIndex) + + def subSequence(start: Int, end: Int): CharSequence = substring(start, end) + def substring(start: Int): String = content.substring(start) + def substring(start: Int, end: Int): String = content.substring(start, end) + + def reverse(): StringBuffer = { + content = new StringBuilder(content).reverse().toString() + this + } + + def deleteCharAt(index: Int): StringBuffer = { + if (index < 0 || index >= content.length) + throw new StringIndexOutOfBoundsException("String index out of range: " + index) + content = content.substring(0, index) + content.substring(index+1) + this + } + + /** + * @param start The beginning index, inclusive. + * @param end The ending index, exclusive. + * @param str String that will replace previous contents. + * @return This StringBuilder. + */ + def replace(start: Int, end: Int, str: String): StringBuffer = { + val length = content.length + if (start < 0 || start > end || start >= length) + throw new StringIndexOutOfBoundsException(s"Illegal to replace substring at [$start - $end] in string of length $length") + val realEnd = if (end > length) length else end // java api convention + content = content.substring(0, start) + str + content.substring(realEnd) + this + } + + def setCharAt(index: Int, ch: scala.Char): Unit = { + if (index < 0 || index >= content.length) + throw new IndexOutOfBoundsException("String index out of range: " + index) + content = content.substring(0, index) + ch + content.substring(index + 1) + } + + def setLength(newLength: Int): Unit = { + if (newLength < 0) + throw new IndexOutOfBoundsException("String index out of range: " + newLength) + + val len = length() + if (len == newLength) { + } else if (len < newLength) { + var index = len + while (index < newLength) { + append("\u0000") + index += 1 + } + } else { + content = substring(0, newLength) + } + } + + def insert(index: Int, b: scala.Boolean): StringBuffer = insert(index, b.toString) + def insert(index: Int, b: scala.Byte): StringBuffer = insert(index, b.toString) + def insert(index: Int, s: scala.Short): StringBuffer = insert(index, s.toString) + def insert(index: Int, i: scala.Int): StringBuffer = insert(index, i.toString) + def insert(index: Int, l: scala.Long): StringBuffer = insert(index, l.toString) + def insert(index: Int, f: scala.Float): StringBuffer = insert(index, f.toString) + def insert(index: Int, d: scala.Double): StringBuffer = insert(index, d.toString) + def insert(index: Int, c: scala.Char): StringBuffer = insert(index, c.toString) + def insert(index: Int, csq: CharSequence): StringBuffer = insert(index: Int, csq: AnyRef) + def insert(index: Int, arr: Array[scala.Char]): StringBuffer = insert(index, arr, 0, arr.length) + + def insert(index: Int, ref: AnyRef): StringBuffer = + if (ref == null) + insert(index, null: String) + else + insert(index, ref.toString) + + def insert(index: Int, csq: CharSequence, start: Int, end: Int): StringBuffer = + if (csq == null) + insert(index, "null", start, end) + else + insert(index, csq.subSequence(start, end).toString) + + + def insert(index: Int, arr: Array[scala.Char], offset: Int, len: Int): StringBuffer = { + var str = "" + var i = 0 + while (i < len) { + str += arr(i + offset) + i += 1 + } + insert(index, str) + } + + def insert(index: Int, str: String): StringBuffer = { + val thisLength = length() + if (index < 0 || index > thisLength) + throw new StringIndexOutOfBoundsException(index) + else if (index == thisLength) + append(str) + else + content = content.substring(0, index) + Option(str).getOrElse("null") + content.substring(index) + this + } +} diff --git a/javalanglib/src/main/scala/java/lang/StringBuilder.scala b/javalanglib/src/main/scala/java/lang/StringBuilder.scala new file mode 100644 index 0000000..e8bd2b7 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/StringBuilder.scala @@ -0,0 +1,178 @@ +package java.lang + +class StringBuilder(private var content: String) extends CharSequence + with Appendable + with java.io.Serializable { + def this() = this("") + def this(initialCapacity: Int) = this("") + def this(csq: CharSequence) = this(csq.toString) + + def append(s: String): StringBuilder = { + content += { if (s == null) "null" else s } + this + } + + def append(b: scala.Boolean): StringBuilder = append(b.toString()) + def append(c: scala.Char): StringBuilder = append(c.toString()) + + def append(str: Array[scala.Char]): StringBuilder = + append(str, 0, str.length) + + def append(str: Array[scala.Char], offset: Int, len: Int): StringBuilder = { + var i = 0 + while (i < len) { + content += str(i + offset) + i += 1 + } + this + } + + def append(b: scala.Byte): StringBuilder = append(b.toString()) + def append(s: scala.Short): StringBuilder = append(s.toString()) + def append(i: scala.Int): StringBuilder = append(i.toString()) + def append(lng: scala.Long): StringBuilder = append(lng.toString()) + def append(f: scala.Float): StringBuilder = append(f.toString()) + def append(d: scala.Double): StringBuilder = append(d.toString()) + + def append(obj: AnyRef): StringBuilder = { + if (obj == null) append(null: String) + else append(obj.toString()) + } + + def append(csq: CharSequence): StringBuilder = append(csq: AnyRef) + def append(csq: CharSequence, start: Int, end: Int): StringBuilder = { + if (csq == null) append("null", start, end) + else append(csq.subSequence(start, end).toString()) + } + + override def toString() = content + + def length() = content.length() + + def charAt(index: Int) = content.charAt(index) + def codePointAt(index: Int) = content.codePointAt(index) + + def indexOf(str: String) = content.indexOf(str) + def indexOf(str: String, fromIndex: Int) = content.indexOf(str, fromIndex) + + def lastIndexOf(str: String) = content.lastIndexOf(str) + def lastIndexOf(str: String, fromIndex: Int) = content.lastIndexOf(str, fromIndex) + + def subSequence(start: Int, end: Int): CharSequence = substring(start, end) + def substring(start: Int): String = content.substring(start) + def substring(start: Int, end: Int): String = content.substring(start, end) + + def reverse(): StringBuilder = { + val original = content + var result = "" + var i = 0 + while (i < original.length) { + val c = original.charAt(i) + if (Character.isHighSurrogate(c) && (i+1 < original.length)) { + val c2 = original.charAt(i+1) + if (Character.isLowSurrogate(c2)) { + result = c.toString + c2.toString + result + i += 2 + } else { + result = c.toString + result + i += 1 + } + } else { + result = c.toString + result + i += 1 + } + } + content = result + this + } + + def deleteCharAt(index: Int): StringBuilder = { + if (index < 0 || index >= content.length) + throw new StringIndexOutOfBoundsException("String index out of range: " + index) + content = content.substring(0, index) + content.substring(index+1) + this + } + + /** + * @param start The beginning index, inclusive. + * @param end The ending index, exclusive. + * @param str String that will replace previous contents. + * @return This StringBuilder. + */ + def replace(start: Int, end: Int, str: String): StringBuilder = { + val length = content.length + if (start < 0 || start > end || start >= length) + throw new StringIndexOutOfBoundsException(s"Illegal to replace substring at [$start - $end] in string of length $length") + val realEnd = if (end > length) length else end // java api convention + content = content.substring(0, start) + str + content.substring(realEnd) + this + } + + def setCharAt(index: Int, ch: scala.Char): Unit = { + if (index < 0 || index >= content.length) + throw new IndexOutOfBoundsException("String index out of range: " + index) + content = content.substring(0, index) + ch + content.substring(index + 1) + } + + def setLength(newLength: Int): Unit = { + if (newLength < 0) + throw new IndexOutOfBoundsException("String index out of range: " + newLength) + + val len = length() + if (len == newLength) { + } else if (len < newLength) { + var index = len + while (index < newLength) { + append("\u0000") + index += 1 + } + } else { + content = substring(0, newLength) + } + } + + def insert(index: Int, b: scala.Boolean): StringBuilder = insert(index, b.toString) + def insert(index: Int, b: scala.Byte): StringBuilder = insert(index, b.toString) + def insert(index: Int, s: scala.Short): StringBuilder = insert(index, s.toString) + def insert(index: Int, i: scala.Int): StringBuilder = insert(index, i.toString) + def insert(index: Int, l: scala.Long): StringBuilder = insert(index, l.toString) + def insert(index: Int, f: scala.Float): StringBuilder = insert(index, f.toString) + def insert(index: Int, d: scala.Double): StringBuilder = insert(index, d.toString) + def insert(index: Int, c: scala.Char): StringBuilder = insert(index, c.toString) + def insert(index: Int, csq: CharSequence): StringBuilder = insert(index: Int, csq: AnyRef) + def insert(index: Int, arr: Array[scala.Char]): StringBuilder = insert(index, arr, 0, arr.length) + + def insert(index: Int, ref: AnyRef): StringBuilder = + if (ref == null) + insert(index, null: String) + else + insert(index, ref.toString) + + def insert(index: Int, csq: CharSequence, start: Int, end: Int): StringBuilder = + if (csq == null) + insert(index, "null", start, end) + else + insert(index, csq.subSequence(start, end).toString) + + + def insert(index: Int, arr: Array[scala.Char], offset: Int, len: Int): StringBuilder = { + var str = "" + var i = 0 + while (i < len) { + str += arr(i + offset) + i += 1 + } + insert(index, str) + } + + def insert(index: Int, str: String): StringBuilder = { + val thisLength = length() + if (index < 0 || index > thisLength) + throw new StringIndexOutOfBoundsException(index) + else if (index == thisLength) + append(str) + else + content = content.substring(0, index) + Option(str).getOrElse("null") + content.substring(index) + this + } +} diff --git a/javalanglib/src/main/scala/java/lang/System.scala b/javalanglib/src/main/scala/java/lang/System.scala new file mode 100644 index 0000000..6d80eaf --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/System.scala @@ -0,0 +1,275 @@ +package java.lang + +import java.io._ + +import scala.scalajs.js +import js.Dynamic.global + +object System { + var out: PrintStream = new JSConsoleBasedPrintStream(isErr = false) + var err: PrintStream = new JSConsoleBasedPrintStream(isErr = true) + var in: InputStream = null + + def currentTimeMillis(): scala.Long = { + (new js.Date).getTime().toLong + } + + private[this] val getHighPrecisionTime: js.Function0[scala.Double] = { + if (!(!global.performance)) { + if (!(!global.performance.now)) { + () => global.performance.now().asInstanceOf[scala.Double] + } else if (!(!(global.performance.webkitNow))) { + () => global.performance.webkitNow().asInstanceOf[scala.Double] + } else { + () => new js.Date().getTime() + } + } else { + () => new js.Date().getTime() + } + } + + def nanoTime(): scala.Long = + (getHighPrecisionTime() * 1000000).toLong + + def arraycopy(src: Object, srcPos: scala.Int, dest: Object, + destPos: scala.Int, length: scala.Int): Unit = { + + import scala.{Boolean, Char, Byte, Short, Int, Long, Float, Double} + + @inline def checkIndices(srcLen: Int, destLen: Int): Unit = { + if (srcPos < 0 || destPos < 0 || length < 0 || + srcPos + length > srcLen || destPos + length > destLen) + throw new ArrayIndexOutOfBoundsException("Array index out of bounds") + } + + def mismatch(): Nothing = + throw new ArrayStoreException("Incompatible array types") + + val forward = (src ne dest) || destPos < srcPos || srcPos + length < destPos + + def copyPrim[@specialized T](src: Array[T], dest: Array[T]): Unit = { + checkIndices(src.length, dest.length) + if (forward) { + var i = 0 + while (i < length) { + dest(i+destPos) = src(i+srcPos) + i += 1 + } + } else { + var i = length-1 + while (i >= 0) { + dest(i+destPos) = src(i+srcPos) + i -= 1 + } + } + } + + def copyRef(src: Array[AnyRef], dest: Array[AnyRef]): Unit = { + checkIndices(src.length, dest.length) + if (forward) { + var i = 0 + while (i < length) { + dest(i+destPos) = src(i+srcPos) + i += 1 + } + } else { + var i = length-1 + while (i >= 0) { + dest(i+destPos) = src(i+srcPos) + i -= 1 + } + } + } + + if (src == null || dest == null) { + throw new NullPointerException() + } else (src match { + case src: Array[AnyRef] => + dest match { + case dest: Array[AnyRef] => copyRef(src, dest) + case _ => mismatch() + } + case src: Array[Boolean] => + dest match { + case dest: Array[Boolean] => copyPrim(src, dest) + case _ => mismatch() + } + case src: Array[Char] => + dest match { + case dest: Array[Char] => copyPrim(src, dest) + case _ => mismatch() + } + case src: Array[Byte] => + dest match { + case dest: Array[Byte] => copyPrim(src, dest) + case _ => mismatch() + } + case src: Array[Short] => + dest match { + case dest: Array[Short] => copyPrim(src, dest) + case _ => mismatch() + } + case src: Array[Int] => + dest match { + case dest: Array[Int] => copyPrim(src, dest) + case _ => mismatch() + } + case src: Array[Long] => + dest match { + case dest: Array[Long] => copyPrim(src, dest) + case _ => mismatch() + } + case src: Array[Float] => + dest match { + case dest: Array[Float] => copyPrim(src, dest) + case _ => mismatch() + } + case src: Array[Double] => + dest match { + case dest: Array[Double] => copyPrim(src, dest) + case _ => mismatch() + } + case _ => + mismatch() + }) + } + + def identityHashCode(x: Object): scala.Int = { + import js.prim + x match { + case null => 0 + case _:prim.Boolean | _:prim.Number | _:prim.String | _:prim.Undefined => + x.hashCode() + case _ => + if (x.getClass == null) { + // This is not a Scala.js object + 42 + } else { + val hash = x.asInstanceOf[js.Dynamic].selectDynamic("$idHashCode$0") + if (!js.isUndefined(hash)) { + hash.asInstanceOf[Int] + } else { + val newHash = IDHashCode.nextIDHashCode() + x.asInstanceOf[js.Dynamic].updateDynamic("$idHashCode$0")(newHash) + newHash + } + } + } + } + + private object IDHashCode { + private var lastIDHashCode: Int = 0 + + def nextIDHashCode(): Int = { + val r = lastIDHashCode + 1 + lastIDHashCode = r + r + } + } + + //def getProperties(): java.util.Properties + //def getProperty(key: String): String + //def getProperty(key: String, default: String): String + //def clearProperty(key: String): String + //def setProperty(key: String, value: String): String + + //def getenv(): java.util.Map[String,String] + //def getenv(name: String): String + + def exit(status: scala.Int) = Runtime.getRuntime().exit(status) + def gc() = Runtime.getRuntime().gc() +} + +private[lang] final class JSConsoleBasedPrintStream(isErr: Boolean) + extends PrintStream(new JSConsoleBasedPrintStream.DummyOutputStream) { + + import JSConsoleBasedPrintStream._ + + /** Whether the buffer is flushed. + * This can be true even if buffer != "" because of line continuations. + * However, the converse is never true, i.e., !flushed => buffer != "". + */ + private var flushed: scala.Boolean = true + private var buffer: String = "" + + override def write(b: Int): Unit = + write(Array(b.toByte), 0, 1) + + override def write(buf: Array[scala.Byte], off: Int, len: Int): Unit = { + /* This does *not* decode buf as a sequence of UTF-8 code units. + * This is not really useful, and would uselessly pull in the UTF-8 decoder + * in all applications that use OutputStreams (not just PrintStreams). + * Instead, we use a trivial ISO-8859-1 decoder in here. + */ + if (off < 0 || len < 0 || len > buf.length - off) + throw new IndexOutOfBoundsException + + var i = 0 + while (i < len) { + print((buf(i + off) & 0xff).toChar) + i += 1 + } + } + + override def print(b: scala.Boolean): Unit = printString(String.valueOf(b)) + override def print(c: scala.Char): Unit = printString(String.valueOf(c)) + override def print(i: scala.Int): Unit = printString(String.valueOf(i)) + override def print(l: scala.Long): Unit = printString(String.valueOf(l)) + override def print(f: scala.Float): Unit = printString(String.valueOf(f)) + override def print(d: scala.Double): Unit = printString(String.valueOf(d)) + override def print(s: Array[scala.Char]): Unit = printString(String.valueOf(s)) + override def print(s: String): Unit = printString(if (s == null) "null" else s) + override def print(obj: AnyRef): Unit = printString(String.valueOf(obj)) + + override def println(): Unit = printString("\n") + + private def printString(s: String): Unit = { + var rest: String = s + while (rest != "") { + val nlPos = rest.indexOf("\n") + if (nlPos < 0) { + buffer += rest + flushed = false + rest = "" + } else { + doWriteLine(buffer + rest.substring(0, nlPos)) + buffer = "" + flushed = true + rest = rest.substring(nlPos+1) + } + } + } + + /** + * Since we cannot write a partial line in JavaScript, we write a whole + * line with continuation symbol at the end and schedule a line continuation + * symbol for the new line if the buffer is flushed. + */ + override def flush(): Unit = if (!flushed) { + doWriteLine(buffer + LineContEnd) + buffer = LineContStart + flushed = true + } + + override def close(): Unit = () + + private def doWriteLine(line: String): Unit = { + if (!(!global.console)) { + if (isErr && !(!global.console.error)) + global.console.error(line) + else + global.console.log(line) + } + } +} + +private[lang] object JSConsoleBasedPrintStream { + private final val LineContEnd: String = "\u21A9" + private final val LineContStart: String = "\u21AA" + + class DummyOutputStream extends OutputStream { + def write(c: Int): Unit = + throw new AssertionError( + "Should not get in JSConsoleBasedPrintStream.DummyOutputStream") + } +} diff --git a/javalanglib/src/main/scala/java/lang/Thread.scala b/javalanglib/src/main/scala/java/lang/Thread.scala new file mode 100644 index 0000000..e52d7f6 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Thread.scala @@ -0,0 +1,16 @@ +package java.lang + +/* We need a constructor to create SingleThread in the companion object, but + * we don't want user code doing a 'new Thread()' to link, because that could + * be confusing. + * So we use a binary signature that no Java source file can ever produce. + */ +class Thread private (dummy: Unit) extends Runnable { + def run(): Unit = () +} + +object Thread { + private[this] val SingleThread = new Thread(()) + + def currentThread(): Thread = SingleThread +} diff --git a/javalanglib/src/main/scala/java/lang/ThreadLocal.scala b/javalanglib/src/main/scala/java/lang/ThreadLocal.scala new file mode 100644 index 0000000..a36a40c --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/ThreadLocal.scala @@ -0,0 +1,24 @@ +package java.lang + +class ThreadLocal[T] { + private var hasValue: Boolean = false + private var v: T = _ + + protected def initialValue(): T = null.asInstanceOf[T] + + def get(): T = { + if (!hasValue) + set(initialValue) + v + } + + def set(o: T): Unit = { + v = o + hasValue = true + } + + def remove(): Unit = { + hasValue = false + v = null.asInstanceOf[T] // for gc + } +} diff --git a/javalanglib/src/main/scala/java/lang/Throwables.scala b/javalanglib/src/main/scala/java/lang/Throwables.scala new file mode 100644 index 0000000..a38fee9 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Throwables.scala @@ -0,0 +1,363 @@ +package java.lang + +import scala.scalajs.js + +class Throwable(s: String, private var e: Throwable) extends Object with java.io.Serializable { + def this() = this(null, null) + def this(s: String) = this(s, null) + def this(e: Throwable) = this(null, e) + + private[this] var stackTrace: Array[StackTraceElement] = _ + + fillInStackTrace() + + def initCause(cause: Throwable): Throwable = { + e = cause + this + } + + def getMessage(): String = s + def getCause(): Throwable = e + def getLocalizedMessage(): String = getMessage() + + def fillInStackTrace(): Throwable = { + scala.scalajs.runtime.StackTrace.captureState(this) + this + } + + def getStackTrace(): Array[StackTraceElement] = { + if (stackTrace eq null) + stackTrace = scala.scalajs.runtime.StackTrace.extract(this) + stackTrace + } + + def setStackTrace(stackTrace: Array[StackTraceElement]): Unit = { + var i = 0 + while (i < stackTrace.length) { + if (stackTrace(i) eq null) + throw new NullPointerException() + i += 1 + } + + this.stackTrace = stackTrace.clone() + } + + def printStackTrace(): Unit = printStackTrace(System.err) + + def printStackTrace(s: java.io.PrintStream): Unit = + printStackTraceImpl(s.println(_)) + + def printStackTrace(s: java.io.PrintWriter): Unit = + printStackTraceImpl(s.println(_)) + + private[this] def printStackTraceImpl(sprintln: String => Unit): Unit = { + getStackTrace() // will init it if still null + + // Message + sprintln(toString) + + // Trace + if (stackTrace.length != 0) { + var i = 0 + while (i < stackTrace.length) { + sprintln(" at "+stackTrace(i)) + i += 1 + } + } else { + sprintln(" <no stack trace available>") + } + + // Causes + var wCause: Throwable = this + while ((wCause ne wCause.getCause) && (wCause.getCause ne null)) { + val parentTrace = wCause.getStackTrace + wCause = wCause.getCause + val thisTrace = wCause.getStackTrace + + val thisLength = thisTrace.length + val parentLength = parentTrace.length + + sprintln("Caused by: " + wCause.toString) + + if (thisLength != 0) { + /* Count how many frames are shared between this stack trace and the + * parent stack trace, so that we can omit them when printing. + */ + var sameFrameCount: Int = 0 + while (sameFrameCount < thisLength && sameFrameCount < parentLength && + thisTrace(thisLength-sameFrameCount-1) == parentTrace(parentLength-sameFrameCount-1)) { + sameFrameCount += 1 + } + + /* If at least one, decrement so that the first common frame is still + * printed. According to Harmony this is spec'ed and common practice. + */ + if (sameFrameCount > 0) + sameFrameCount -= 1 + + // Print the non-common frames + val lengthToPrint = thisLength - sameFrameCount + var i = 0 + while (i < lengthToPrint) { + sprintln(" at "+thisTrace(i)) + i += 1 + } + + if (sameFrameCount > 0) + sprintln(" ... " + sameFrameCount + " more") + } else { + sprintln(" <no stack trace available>") + } + } + } + + override def toString() = { + val className = getClass.getName + val message = getMessage() + if (message eq null) className + else className + ": " + message + } +} + +class ThreadDeath() extends Error() + + +/* java.lang.*Error.java */ + +class AbstractMethodError(s: String) extends IncompatibleClassChangeError(s) { + def this() = this(null) +} + +class AssertionError private (s: String) extends Error(s) { + def this() = this(null) + def this(o: Object) = this(o.toString) + def this(b: scala.Boolean) = this(b.toString) + def this(c: scala.Char) = this(c.toString) + def this(i: scala.Int) = this(i.toString) + def this(l: scala.Long) = this(l.toString) + def this(f: scala.Float) = this(f.toString) + def this(d: scala.Double) = this(d.toString) +} + +class BootstrapMethodError(s: String, e: Throwable) extends LinkageError(s) { + def this(e: Throwable) = this(null, e) + def this(s: String) = this(s, null) + def this() = this(null, null) +} + +class ClassCircularityError(s: String) extends LinkageError(s) { + def this() = this(null) +} + +class ClassFormatError(s: String) extends LinkageError(s) { + def this() = this(null) +} + +class Error(s: String, e: Throwable) extends Throwable(s, e) { + def this() = this(null, null) + def this(s: String) = this(s, null) + def this(e: Throwable) = this(null, e) +} + +class ExceptionInInitializerError private (s: String, private val e: Throwable) extends LinkageError(s) { + def this(thrown: Throwable) = this(null, thrown) + def this(s: String) = this(s, null) + def this() = this(null, null) + def getException(): Throwable = e + override def getCause(): Throwable = e +} + +class IllegalAccessError(s: String) extends IncompatibleClassChangeError(s) { + def this() = this(null) +} + +class IncompatibleClassChangeError(s: String) extends LinkageError(s) { + def this() = this(null) +} + +class InstantiationError(s: String) extends IncompatibleClassChangeError(s) { + def this() = this(null) +} + +class InternalError(s: String) extends VirtualMachineError(s) { + def this() = this(null) +} + +class LinkageError(s: String) extends Error(s) { + def this() = this(null) +} + +class NoClassDefFoundError(s: String) extends LinkageError(s) { + def this() = this(null) +} + +class NoSuchFieldError(s: String) extends IncompatibleClassChangeError(s) { + def this() = this(null) +} + +class NoSuchMethodError(s: String) extends IncompatibleClassChangeError(s) { + def this() = this(null) +} + +class OutOfMemoryError(s: String) extends VirtualMachineError(s) { + def this() = this(null) +} + +class StackOverflowError(s: String) extends VirtualMachineError(s) { + def this() = this(null) +} + +class UnknownError(s: String) extends VirtualMachineError(s) { + def this() = this(null) +} + +class UnsatisfiedLinkError(s: String) extends LinkageError(s) { + def this() = this(null) +} + +class UnsupportedClassVersionError(s: String) extends ClassFormatError(s) { + def this() = this(null) +} + +class VerifyError(s: String) extends LinkageError(s) { + def this() = this(null) +} + +abstract class VirtualMachineError(s: String) extends Error(s) { + def this() = this(null) +} + + +/* java.lang.*Exception.java */ + +class ArithmeticException(s: String) extends RuntimeException(s) { + def this() = this(null) +} + +class ArrayIndexOutOfBoundsException(s: String) extends IndexOutOfBoundsException(s) { + def this(index: Int) = this("Array index out of range: " + index) + def this() = this(null) +} + +class ArrayStoreException(s: String) extends RuntimeException(s) { + def this() = this(null) +} + +class ClassCastException(s: String) extends RuntimeException(s) { + def this() = this(null) +} + +class ClassNotFoundException(s: String, e: Throwable) extends ReflectiveOperationException(s) { + def this(s: String) = this(s, null) + def this() = this(null, null) + def getException(): Throwable = e + override def getCause(): Throwable = e +} + +class CloneNotSupportedException(s: String) extends Exception(s) { + def this() = this(null) +} + +import scala.language.existentials +class EnumConstantNotPresentException( + e: Class[_ <: Enum[T] forSome { type T <: Enum[T] }], c: String) + extends RuntimeException(e.getName() + "." + c) { + def enumType() = e + def constantName() = c +} + +class Exception(s: String, e: Throwable) extends Throwable(s, e) { + def this(e: Throwable) = this(null, e) + def this(s: String) = this(s, null) + def this() = this(null, null) +} + +class IllegalAccessException(s: String) extends ReflectiveOperationException(s) { + def this() = this(null) +} + +class IllegalArgumentException(s: String, e: Throwable) extends RuntimeException(s, e) { + def this(e: Throwable) = this(null, e) + def this(s: String) = this(s, null) + def this() = this(null, null) +} + +class IllegalMonitorStateException(s: String) extends RuntimeException(s) { + def this() = this(null) +} + +class IllegalStateException(s: String, e: Throwable) extends RuntimeException(s, e) { + def this(e: Throwable) = this(null, e) + def this(s: String) = this(s, null) + def this() = this(null, null) +} + +class IllegalThreadStateException(s: String) extends IllegalArgumentException(s) { + def this() = this(null) +} + +class IndexOutOfBoundsException(s: String) extends RuntimeException(s) { + def this() = this(null) +} + +class InstantiationException(s: String) extends ReflectiveOperationException(s) { + def this() = this(null) +} + +class InterruptedException(s: String) extends Exception(s) { + def this() = this(null) +} + +class NegativeArraySizeException(s: String) extends RuntimeException(s) { + def this() = this(null) +} + +class NoSuchFieldException(s: String) extends ReflectiveOperationException(s) { + def this() = this(null) +} + +class NoSuchMethodException(s: String) extends ReflectiveOperationException(s) { + def this() = this(null) +} + +class NullPointerException(s: String) extends RuntimeException(s) { + def this() = this(null) +} + +class NumberFormatException(s: String) extends IllegalArgumentException(s) { + def this() = this(null) +} + +class ReflectiveOperationException(s: String, e: Throwable) extends Exception(s, e) { + def this(e: Throwable) = this(null, e) + def this(s: String) = this(s, null) + def this() = this(null, null) +} + +class RuntimeException(s: String, e: Throwable) extends Exception(s, e) { + def this(e: Throwable) = this(null, e) + def this(s: String) = this(s, null) + def this() = this(null, null) +} + +class SecurityException(s: String, e: Throwable) extends RuntimeException(s, e) { + def this(e: Throwable) = this(null, e) + def this(s: String) = this(s, null) + def this() = this(null, null) +} + +class StringIndexOutOfBoundsException(s: String) extends IndexOutOfBoundsException(s) { + def this(index: Int) = this("String index out of range: " + index) + def this() = this(null) +} + +class TypeNotPresentException(t: String, e: Throwable) + extends RuntimeException("Type " + t + " not present", e) { + def typeName(): String = t +} + +class UnsupportedOperationException(s: String, e: Throwable) extends RuntimeException(s, e) { + def this() = this(null, null) + def this(s: String) = this(s, null) + def this(e: Throwable) = this(null, e) +} diff --git a/javalanglib/src/main/scala/java/lang/Void.scala b/javalanglib/src/main/scala/java/lang/Void.scala new file mode 100644 index 0000000..fbe68fb --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/Void.scala @@ -0,0 +1,7 @@ +package java.lang + +final class Void private {} + +object Void { + final val TYPE = classOf[scala.Unit] +} diff --git a/javalanglib/src/main/scala/java/lang/ref/PhantomReference.scala b/javalanglib/src/main/scala/java/lang/ref/PhantomReference.scala new file mode 100644 index 0000000..ecace8a --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/ref/PhantomReference.scala @@ -0,0 +1,7 @@ +package java.lang.ref + +class PhantomReference[T >: Null <: AnyRef](referent: T, + queue: ReferenceQueue[_ >: T]) extends Reference[T](null) { + + override def get(): T = null +} diff --git a/javalanglib/src/main/scala/java/lang/ref/Reference.scala b/javalanglib/src/main/scala/java/lang/ref/Reference.scala new file mode 100644 index 0000000..76909cf --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/ref/Reference.scala @@ -0,0 +1,8 @@ +package java.lang.ref + +abstract class Reference[T >: Null <: AnyRef](private[this] var referent: T) { + def get(): T = referent + def clear(): Unit = referent = null + def isEnqueued(): Boolean = false + def enqueue(): Boolean = false +} diff --git a/javalanglib/src/main/scala/java/lang/ref/ReferenceQueue.scala b/javalanglib/src/main/scala/java/lang/ref/ReferenceQueue.scala new file mode 100644 index 0000000..e9c5110 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/ref/ReferenceQueue.scala @@ -0,0 +1,3 @@ +package java.lang.ref + +class ReferenceQueue[T >: Null <: AnyRef] diff --git a/javalanglib/src/main/scala/java/lang/ref/SoftReference.scala b/javalanglib/src/main/scala/java/lang/ref/SoftReference.scala new file mode 100644 index 0000000..eb0fdf7 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/ref/SoftReference.scala @@ -0,0 +1,9 @@ +package java.lang.ref + +class SoftReference[T >: Null <: AnyRef](referent: T, + queue: ReferenceQueue[_ >: T]) extends Reference[T](referent) { + + def this(referent: T) = this(referent, null) + + override def get(): T = super.get() +} diff --git a/javalanglib/src/main/scala/java/lang/ref/WeakReference.scala b/javalanglib/src/main/scala/java/lang/ref/WeakReference.scala new file mode 100644 index 0000000..2a74aa1 --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/ref/WeakReference.scala @@ -0,0 +1,7 @@ +package java.lang.ref + +class WeakReference[T >: Null <: AnyRef](referent: T, + queue: ReferenceQueue[_ >: T]) extends Reference[T](referent) { + + def this(referent: T) = this(referent, null) +} diff --git a/javalanglib/src/main/scala/java/lang/reflect/Array.scala b/javalanglib/src/main/scala/java/lang/reflect/Array.scala new file mode 100644 index 0000000..bc3696e --- /dev/null +++ b/javalanglib/src/main/scala/java/lang/reflect/Array.scala @@ -0,0 +1,176 @@ +package java.lang.reflect + +import scala.scalajs.js + +import js.JSConverters._ + +import java.lang.Class + +object Array { + def newInstance(componentType: Class[_], length: Int): AnyRef = + componentType.newArrayOfThisClass(js.Array(length)) + + def newInstance(componentType: Class[_], dimensions: scala.Array[Int]): AnyRef = + componentType.newArrayOfThisClass(dimensions.toJSArray) + + def getLength(array: AnyRef): Int = array match { + // yes, this is kind of stupid, but that's how it is + case array: Array[Object] => array.length + case array: Array[Boolean] => array.length + case array: Array[Char] => array.length + case array: Array[Byte] => array.length + case array: Array[Short] => array.length + case array: Array[Int] => array.length + case array: Array[Long] => array.length + case array: Array[Float] => array.length + case array: Array[Double] => array.length + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def get(array: AnyRef, index: Int): AnyRef = array match { + case array: Array[Object] => array(index) + case array: Array[Boolean] => new java.lang.Boolean(array(index)) + case array: Array[Char] => new java.lang.Character(array(index)) + case array: Array[Byte] => new java.lang.Byte(array(index)) + case array: Array[Short] => new java.lang.Short(array(index)) + case array: Array[Int] => new java.lang.Integer(array(index)) + case array: Array[Long] => new java.lang.Long(array(index)) + case array: Array[Float] => new java.lang.Float(array(index)) + case array: Array[Double] => new java.lang.Double(array(index)) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def getBoolean(array: AnyRef, index: Int): Boolean = array match { + case array: Array[Boolean] => array(index) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def getChar(array: AnyRef, index: Int): Char = array match { + case array: Array[Char] => array(index) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def getByte(array: AnyRef, index: Int): Byte = array match { + case array: Array[Byte] => array(index) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def getShort(array: AnyRef, index: Int): Short = array match { + case array: Array[Short] => array(index) + case array: Array[Byte] => array(index) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def getInt(array: AnyRef, index: Int): Int = array match { + case array: Array[Int] => array(index) + case array: Array[Char] => array(index) + case array: Array[Byte] => array(index) + case array: Array[Short] => array(index) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def getLong(array: AnyRef, index: Int): Long = array match { + case array: Array[Long] => array(index) + case array: Array[Char] => array(index) + case array: Array[Byte] => array(index) + case array: Array[Short] => array(index) + case array: Array[Int] => array(index) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def getFloat(array: AnyRef, index: Int): Float = array match { + case array: Array[Float] => array(index) + case array: Array[Char] => array(index) + case array: Array[Byte] => array(index) + case array: Array[Short] => array(index) + case array: Array[Int] => array(index) + case array: Array[Long] => array(index) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def getDouble(array: AnyRef, index: Int): Double = array match { + case array: Array[Double] => array(index) + case array: Array[Char] => array(index) + case array: Array[Byte] => array(index) + case array: Array[Short] => array(index) + case array: Array[Int] => array(index) + case array: Array[Long] => array(index) + case array: Array[Float] => array(index) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def set(array: AnyRef, index: Int, value: AnyRef): Unit = array match { + case array: Array[Object] => array(index) = value + case _ => + (value: Any) match { + case value: Boolean => setBoolean(array, index, value) + case value: Char => setChar(array, index, value) + case value: Byte => setByte(array, index, value) + case value: Short => setShort(array, index, value) + case value: Int => setInt(array, index, value) + case value: Long => setLong(array, index, value) + case value: Float => setFloat(array, index, value) + case value: Double => setDouble(array, index, value) + case _ => throw new IllegalArgumentException("argument type mismatch") + } + } + + def setBoolean(array: AnyRef, index: Int, value: Boolean): Unit = array match { + case array: Array[Boolean] => array(index) = value + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def setChar(array: AnyRef, index: Int, value: Char): Unit = array match { + case array: Array[Char] => array(index) = value + case array: Array[Int] => array(index) = value + case array: Array[Long] => array(index) = value + case array: Array[Float] => array(index) = value + case array: Array[Double] => array(index) = value + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def setByte(array: AnyRef, index: Int, value: Byte): Unit = array match { + case array: Array[Byte] => array(index) = value + case array: Array[Short] => array(index) = value + case array: Array[Int] => array(index) = value + case array: Array[Long] => array(index) = value + case array: Array[Float] => array(index) = value + case array: Array[Double] => array(index) = value + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def setShort(array: AnyRef, index: Int, value: Short): Unit = array match { + case array: Array[Short] => array(index) = value + case array: Array[Int] => array(index) = value + case array: Array[Long] => array(index) = value + case array: Array[Float] => array(index) = value + case array: Array[Double] => array(index) = value + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def setInt(array: AnyRef, index: Int, value: Int): Unit = array match { + case array: Array[Int] => array(index) = value + case array: Array[Long] => array(index) = value + case array: Array[Float] => array(index) = value + case array: Array[Double] => array(index) = value + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def setLong(array: AnyRef, index: Int, value: Long): Unit = array match { + case array: Array[Long] => array(index) = value + case array: Array[Float] => array(index) = value + case array: Array[Double] => array(index) = value + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def setFloat(array: AnyRef, index: Int, value: Float): Unit = array match { + case array: Array[Float] => array(index) = value + case array: Array[Double] => array(index) = value + case _ => throw new IllegalArgumentException("argument type mismatch") + } + + def setDouble(array: AnyRef, index: Int, value: Double): Unit = array match { + case array: Array[Double] => array(index) = value + case _ => throw new IllegalArgumentException("argument type mismatch") + } +} |