added optimizations for immutable numbers
This commit is contained in:
parent
3f235878c0
commit
7e8f1406b5
@ -1235,12 +1235,12 @@ class Compiler(
|
||||
return when (t.type) {
|
||||
Token.Type.INT, Token.Type.HEX -> {
|
||||
val n = t.value.replace("_", "").toLong(if (t.type == Token.Type.HEX) 16 else 10)
|
||||
if (isPlus) ObjInt(n) else ObjInt(-n)
|
||||
if (isPlus) ObjInt.of(n) else ObjInt.of(-n)
|
||||
}
|
||||
|
||||
Token.Type.REAL -> {
|
||||
val d = t.value.toDouble()
|
||||
if (isPlus) ObjReal(d) else ObjReal(-d)
|
||||
if (isPlus) ObjReal.of(d) else ObjReal.of(-d)
|
||||
}
|
||||
|
||||
else -> {
|
||||
@ -2940,22 +2940,22 @@ class Compiler(
|
||||
|
||||
// Arithmetic for ints only (keep semantics simple at compile time)
|
||||
BinOp.PLUS -> when {
|
||||
a is ObjInt && b is ObjInt -> ObjInt(a.value + b.value)
|
||||
a is ObjInt && b is ObjInt -> ObjInt.of(a.value + b.value)
|
||||
a is ObjString && b is ObjString -> ObjString(a.value + b.value)
|
||||
else -> null
|
||||
}
|
||||
|
||||
BinOp.MINUS -> if (a is ObjInt && b is ObjInt) ObjInt(a.value - b.value) else null
|
||||
BinOp.STAR -> if (a is ObjInt && b is ObjInt) ObjInt(a.value * b.value) else null
|
||||
BinOp.SLASH -> if (a is ObjInt && b is ObjInt && b.value != 0L) ObjInt(a.value / b.value) else null
|
||||
BinOp.PERCENT -> if (a is ObjInt && b is ObjInt && b.value != 0L) ObjInt(a.value % b.value) else null
|
||||
BinOp.MINUS -> if (a is ObjInt && b is ObjInt) ObjInt.of(a.value - b.value) else null
|
||||
BinOp.STAR -> if (a is ObjInt && b is ObjInt) ObjInt.of(a.value * b.value) else null
|
||||
BinOp.SLASH -> if (a is ObjInt && b is ObjInt && b.value != 0L) ObjInt.of(a.value / b.value) else null
|
||||
BinOp.PERCENT -> if (a is ObjInt && b is ObjInt && b.value != 0L) ObjInt.of(a.value % b.value) else null
|
||||
|
||||
// Bitwise for ints
|
||||
BinOp.BAND -> if (a is ObjInt && b is ObjInt) ObjInt(a.value and b.value) else null
|
||||
BinOp.BXOR -> if (a is ObjInt && b is ObjInt) ObjInt(a.value xor b.value) else null
|
||||
BinOp.BOR -> if (a is ObjInt && b is ObjInt) ObjInt(a.value or b.value) else null
|
||||
BinOp.SHL -> if (a is ObjInt && b is ObjInt) ObjInt(a.value shl (b.value.toInt() and 63)) else null
|
||||
BinOp.SHR -> if (a is ObjInt && b is ObjInt) ObjInt(a.value shr (b.value.toInt() and 63)) else null
|
||||
BinOp.BAND -> if (a is ObjInt && b is ObjInt) ObjInt.of(a.value and b.value) else null
|
||||
BinOp.BXOR -> if (a is ObjInt && b is ObjInt) ObjInt.of(a.value xor b.value) else null
|
||||
BinOp.BOR -> if (a is ObjInt && b is ObjInt) ObjInt.of(a.value or b.value) else null
|
||||
BinOp.SHL -> if (a is ObjInt && b is ObjInt) ObjInt.of(a.value shl (b.value.toInt() and 63)) else null
|
||||
BinOp.SHR -> if (a is ObjInt && b is ObjInt) ObjInt.of(a.value shr (b.value.toInt() and 63)) else null
|
||||
|
||||
// Non-folded / side-effecting or type-dependent ops
|
||||
BinOp.EQARROW, BinOp.REF_EQ, BinOp.REF_NEQ, BinOp.MATCH, BinOp.NOTMATCH,
|
||||
@ -2968,12 +2968,12 @@ class Compiler(
|
||||
return when (op) {
|
||||
UnaryOp.NOT -> if (a is ObjBool) if (!a.value) ObjTrue else ObjFalse else null
|
||||
UnaryOp.NEGATE -> when (a) {
|
||||
is ObjInt -> ObjInt(-a.value)
|
||||
is ObjReal -> ObjReal(-a.value)
|
||||
is ObjInt -> ObjInt.of(-a.value)
|
||||
is ObjReal -> ObjReal.of(-a.value)
|
||||
else -> null
|
||||
}
|
||||
|
||||
UnaryOp.BITNOT -> if (a is ObjInt) ObjInt(a.value.inv()) else null
|
||||
UnaryOp.BITNOT -> if (a is ObjInt) ObjInt.of(a.value.inv()) else null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
override val longValue get() = value
|
||||
override val doubleValue get() = value.toDouble()
|
||||
override val toObjInt get() = this
|
||||
override val toObjReal = ObjReal(doubleValue)
|
||||
override val toObjReal = ObjReal.of(doubleValue)
|
||||
|
||||
override fun byValueCopy(): Obj = this
|
||||
|
||||
@ -65,28 +65,28 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
if (other is ObjInt)
|
||||
of(this.value + other.value)
|
||||
else
|
||||
ObjReal(this.doubleValue + other.toDouble())
|
||||
ObjReal.of(this.doubleValue + other.toDouble())
|
||||
|
||||
override suspend fun minus(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt)
|
||||
of(this.value - other.value)
|
||||
else
|
||||
ObjReal(this.doubleValue - other.toDouble())
|
||||
ObjReal.of(this.doubleValue - other.toDouble())
|
||||
|
||||
override suspend fun mul(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt) {
|
||||
of(this.value * other.value)
|
||||
} else ObjReal(this.value * other.toDouble())
|
||||
} else ObjReal.of(this.value * other.toDouble())
|
||||
|
||||
override suspend fun div(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt)
|
||||
of(this.value / other.value)
|
||||
else ObjReal(this.value / other.toDouble())
|
||||
else ObjReal.of(this.value / other.toDouble())
|
||||
|
||||
override suspend fun mod(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt)
|
||||
of(this.value % other.value)
|
||||
else ObjReal(this.value.toDouble() % other.toDouble())
|
||||
else ObjReal.of(this.value.toDouble() % other.toDouble())
|
||||
|
||||
/**
|
||||
* Numbers are now immutable, so we can't do in-place assignment.
|
||||
@ -107,31 +107,31 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
}
|
||||
|
||||
override suspend fun negate(scope: Scope): Obj {
|
||||
return ObjInt(-value)
|
||||
return of(-value)
|
||||
}
|
||||
|
||||
// Bitwise operations
|
||||
override suspend fun bitAnd(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt) ObjInt(this.value and other.value)
|
||||
if (other is ObjInt) of(this.value and other.value)
|
||||
else scope.raiseIllegalArgument("bitwise and '&' requires Int, got ${other.objClass.className}")
|
||||
|
||||
override suspend fun bitOr(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt) ObjInt(this.value or other.value)
|
||||
if (other is ObjInt) of(this.value or other.value)
|
||||
else scope.raiseIllegalArgument("bitwise or '|' requires Int, got ${other.objClass.className}")
|
||||
|
||||
override suspend fun bitXor(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt) ObjInt(this.value xor other.value)
|
||||
if (other is ObjInt) of(this.value xor other.value)
|
||||
else scope.raiseIllegalArgument("bitwise xor '^' requires Int, got ${other.objClass.className}")
|
||||
|
||||
override suspend fun shl(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt) ObjInt(this.value shl (other.value.toInt() and 63))
|
||||
if (other is ObjInt) of(this.value shl (other.value.toInt() and 63))
|
||||
else scope.raiseIllegalArgument("shift left '<<' requires Int, got ${other.objClass.className}")
|
||||
|
||||
override suspend fun shr(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt) ObjInt(this.value shr (other.value.toInt() and 63))
|
||||
if (other is ObjInt) of(this.value shr (other.value.toInt() and 63))
|
||||
else scope.raiseIllegalArgument("shift right '>>' requires Int, got ${other.objClass.className}")
|
||||
|
||||
override suspend fun bitNot(scope: Scope): Obj = ObjInt(this.value.inv())
|
||||
override suspend fun bitNot(scope: Scope): Obj = of(this.value.inv())
|
||||
|
||||
override suspend fun lynonType(): LynonType = when (value) {
|
||||
0L -> LynonType.Int0
|
||||
@ -170,11 +170,11 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
val type = object : ObjClass("Int") {
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj =
|
||||
when (lynonType) {
|
||||
null -> ObjInt(decoder.unpackSigned())
|
||||
null -> of(decoder.unpackSigned())
|
||||
LynonType.Int0 -> Zero
|
||||
LynonType.IntPositive -> ObjInt(decoder.unpackUnsigned().toLong())
|
||||
LynonType.IntNegative -> ObjInt(-decoder.unpackUnsigned().toLong())
|
||||
LynonType.IntSigned -> ObjInt(decoder.unpackSigned())
|
||||
LynonType.IntPositive -> of(decoder.unpackUnsigned().toLong())
|
||||
LynonType.IntNegative -> of(-decoder.unpackUnsigned().toLong())
|
||||
LynonType.IntSigned -> of(decoder.unpackSigned())
|
||||
else -> scope.raiseIllegalState("illegal type code for Int: $lynonType")
|
||||
}
|
||||
}.apply {
|
||||
|
||||
@ -32,10 +32,10 @@ import kotlin.math.floor
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
override val longValue: Long by lazy { floor(value).toLong() }
|
||||
override val doubleValue: Double by lazy { value }
|
||||
override val toObjInt: ObjInt by lazy { ObjInt(longValue) }
|
||||
override val toObjReal: ObjReal by lazy { ObjReal(value) }
|
||||
override val longValue: Long get() = floor(value).toLong()
|
||||
override val doubleValue: Double get() = value
|
||||
override val toObjInt: ObjInt get() = ObjInt.of(longValue)
|
||||
override val toObjReal: ObjReal get() = this
|
||||
|
||||
override val objClass: ObjClass = type
|
||||
|
||||
@ -65,19 +65,19 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
}
|
||||
|
||||
override suspend fun plus(scope: Scope, other: Obj): Obj =
|
||||
ObjReal(this.value + other.toDouble())
|
||||
of(this.value + other.toDouble())
|
||||
|
||||
override suspend fun minus(scope: Scope, other: Obj): Obj =
|
||||
ObjReal(this.value - other.toDouble())
|
||||
of(this.value - other.toDouble())
|
||||
|
||||
override suspend fun mul(scope: Scope, other: Obj): Obj =
|
||||
ObjReal(this.value * other.toDouble())
|
||||
of(this.value * other.toDouble())
|
||||
|
||||
override suspend fun div(scope: Scope, other: Obj): Obj =
|
||||
ObjReal(this.value / other.toDouble())
|
||||
of(this.value / other.toDouble())
|
||||
|
||||
override suspend fun mod(scope: Scope, other: Obj): Obj =
|
||||
ObjReal(this.value % other.toDouble())
|
||||
of(this.value % other.toDouble())
|
||||
|
||||
/**
|
||||
* Returns unboxed Double value
|
||||
@ -96,7 +96,7 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
}
|
||||
|
||||
override suspend fun negate(scope: Scope): Obj {
|
||||
return ObjReal(-value)
|
||||
return of(-value)
|
||||
}
|
||||
|
||||
override suspend fun lynonType(): LynonType = LynonType.Real
|
||||
@ -110,9 +110,18 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Zero = ObjReal(0.0)
|
||||
val One = ObjReal(1.0)
|
||||
|
||||
fun of(value: Double): ObjReal = when (value) {
|
||||
0.0 -> Zero
|
||||
1.0 -> One
|
||||
else -> ObjReal(value)
|
||||
}
|
||||
|
||||
val type: ObjClass = object : ObjClass("Real") {
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj =
|
||||
ObjReal(decoder.unpackDouble())
|
||||
of(decoder.unpackDouble())
|
||||
}.apply {
|
||||
// roundToInt: number rounded to the nearest integer
|
||||
addConstDoc(
|
||||
@ -130,7 +139,7 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjInt(thisAs<ObjReal>().value.toLong())
|
||||
ObjInt.of(thisAs<ObjReal>().value.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,16 +132,16 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
||||
val av = a.value
|
||||
val bv = b.value
|
||||
val r: Obj? = when (op) {
|
||||
BinOp.PLUS -> ObjInt(av + bv)
|
||||
BinOp.MINUS -> ObjInt(av - bv)
|
||||
BinOp.STAR -> ObjInt(av * bv)
|
||||
BinOp.SLASH -> if (bv != 0L) ObjInt(av / bv) else null
|
||||
BinOp.PERCENT -> if (bv != 0L) ObjInt(av % bv) else null
|
||||
BinOp.BAND -> ObjInt(av and bv)
|
||||
BinOp.BXOR -> ObjInt(av xor bv)
|
||||
BinOp.BOR -> ObjInt(av or bv)
|
||||
BinOp.SHL -> ObjInt(av shl (bv.toInt() and 63))
|
||||
BinOp.SHR -> ObjInt(av shr (bv.toInt() and 63))
|
||||
BinOp.PLUS -> ObjInt.of(av + bv)
|
||||
BinOp.MINUS -> ObjInt.of(av - bv)
|
||||
BinOp.STAR -> ObjInt.of(av * bv)
|
||||
BinOp.SLASH -> if (bv != 0L) ObjInt.of(av / bv) else null
|
||||
BinOp.PERCENT -> if (bv != 0L) ObjInt.of(av % bv) else null
|
||||
BinOp.BAND -> ObjInt.of(av and bv)
|
||||
BinOp.BXOR -> ObjInt.of(av xor bv)
|
||||
BinOp.BOR -> ObjInt.of(av or bv)
|
||||
BinOp.SHL -> ObjInt.of(av shl (bv.toInt() and 63))
|
||||
BinOp.SHR -> ObjInt.of(av shr (bv.toInt() and 63))
|
||||
BinOp.EQ -> if (av == bv) ObjTrue else ObjFalse
|
||||
BinOp.NEQ -> if (av != bv) ObjTrue else ObjFalse
|
||||
BinOp.LT -> if (av < bv) ObjTrue else ObjFalse
|
||||
@ -216,11 +216,11 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
||||
val ad: Double = if (a is ObjInt) a.doubleValue else (a as ObjReal).value
|
||||
val bd: Double = if (b is ObjInt) b.doubleValue else (b as ObjReal).value
|
||||
val rNum: Obj? = when (op) {
|
||||
BinOp.PLUS -> ObjReal(ad + bd)
|
||||
BinOp.MINUS -> ObjReal(ad - bd)
|
||||
BinOp.STAR -> ObjReal(ad * bd)
|
||||
BinOp.SLASH -> ObjReal(ad / bd)
|
||||
BinOp.PERCENT -> ObjReal(ad % bd)
|
||||
BinOp.PLUS -> ObjReal.of(ad + bd)
|
||||
BinOp.MINUS -> ObjReal.of(ad - bd)
|
||||
BinOp.STAR -> ObjReal.of(ad * bd)
|
||||
BinOp.SLASH -> ObjReal.of(ad / bd)
|
||||
BinOp.PERCENT -> ObjReal.of(ad % bd)
|
||||
BinOp.LT -> if (ad < bd) ObjTrue else ObjFalse
|
||||
BinOp.LTE -> if (ad <= bd) ObjTrue else ObjFalse
|
||||
BinOp.GT -> if (ad > bd) ObjTrue else ObjFalse
|
||||
|
||||
@ -134,7 +134,7 @@ data class ObjString(val value: String) : Obj() {
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjInt(
|
||||
ObjInt.of(
|
||||
thisAs<ObjString>().value.toLongOrNull()
|
||||
?: raiseIllegalArgument("can't convert to int: $thisObj")
|
||||
)
|
||||
@ -159,7 +159,7 @@ data class ObjString(val value: String) : Obj() {
|
||||
}
|
||||
addConstDoc(
|
||||
name = "length",
|
||||
value = statement { ObjInt(thisAs<ObjString>().value.length.toLong()) },
|
||||
value = statement { ObjInt.of(thisAs<ObjString>().value.length.toLong()) },
|
||||
doc = "Number of UTF-16 code units in this string.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
@ -269,14 +269,14 @@ data class ObjString(val value: String) : Obj() {
|
||||
doc = "Alias for length: the number of characters (code units) in this string.",
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) { ObjInt(thisAs<ObjString>().value.length.toLong()) }
|
||||
) { ObjInt.of(thisAs<ObjString>().value.length.toLong()) }
|
||||
addFnDoc(
|
||||
name = "toReal",
|
||||
doc = "Parse this string as a real number (floating point).",
|
||||
returns = type("lyng.Real"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjReal(thisAs<ObjString>().value.toDouble())
|
||||
ObjReal.of(thisAs<ObjString>().value.toDouble())
|
||||
}
|
||||
addFnDoc(
|
||||
name = "trim",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user