diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDecimalSupport.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDecimalSupport.kt index ab3a11e..f15d9fa 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDecimalSupport.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDecimalSupport.kt @@ -88,7 +88,7 @@ object ObjDecimalSupport { } decimalClass.addClassFn("fromInt") { val value = requiredArg(0).value - newInstance(decimalClass, IonBigDecimal.fromLongAsSignificand(value)) + newInstance(decimalClass, IonBigDecimal.fromLong(value)) } decimalClass.addClassFn("fromReal") { val value = requiredArg(0).value @@ -204,7 +204,7 @@ object ObjDecimalSupport { } private fun coerceArg(scope: Scope, value: Obj): IonBigDecimal = when (value) { - is ObjInt -> IonBigDecimal.fromLongAsSignificand(value.value) + is ObjInt -> IonBigDecimal.fromLong(value.value) is ObjReal -> IonBigDecimal.fromDouble(value.value, realConversionMode) is ObjInstance -> { if (value.objClass.className != "Decimal") { @@ -303,7 +303,7 @@ object ObjDecimalSupport { doc = "Convert this integer to a Decimal.", type = type("lyng.decimal.Decimal"), moduleName = "lyng.decimal", - getter = { newInstance(decimalClass, IonBigDecimal.fromLongAsSignificand(thisAs().value)) } + getter = { newInstance(decimalClass, IonBigDecimal.fromLong(thisAs().value)) } ) ObjInt.type.members["d"] = ObjInt.type.members.getValue("d").copy(typeDecl = decimalTypeDecl) ObjReal.type.addPropertyDoc( @@ -347,7 +347,7 @@ object ObjDecimalSupport { ), leftToCommon = ObjExternCallable.fromBridge { val value = requiredArg(0).value - newInstance(decimalClass, IonBigDecimal.fromLongAsSignificand(value)) + newInstance(decimalClass, IonBigDecimal.fromLong(value)) }, rightToCommon = ObjExternCallable.fromBridge { requiredArg(0) diff --git a/lynglib/src/commonTest/kotlin/GlobalBindingTest.kt b/lynglib/src/commonTest/kotlin/GlobalBindingTest.kt index cd671b3..c2679b4 100644 --- a/lynglib/src/commonTest/kotlin/GlobalBindingTest.kt +++ b/lynglib/src/commonTest/kotlin/GlobalBindingTest.kt @@ -17,14 +17,15 @@ package net.sergeych.lyng +import com.ionspin.kotlin.bignum.decimal.BigDecimal import kotlinx.coroutines.test.runTest -import net.sergeych.lyng.bridge.bindGlobalFun1 -import net.sergeych.lyng.bridge.bindGlobalFun3 -import net.sergeych.lyng.bridge.bindGlobalVar -import net.sergeych.lyng.bridge.globalBinder +import net.sergeych.lyng.bridge.* +import net.sergeych.lyng.obj.ObjInstance import net.sergeych.lyng.obj.ObjInt +import net.sergeych.lyng.obj.ObjReal import net.sergeych.lyng.obj.ObjString import kotlin.test.Test +import kotlin.test.assertEquals import kotlin.test.assertTrue class GlobalBindingTest { @@ -136,4 +137,87 @@ class GlobalBindingTest { assertTrue(readonlySetter) } } + + @Test + fun rawDecimalExternBindingDoesNotBreakDecimalLiteralRendering() = runTest { + val scope = Script.newScope() + var x = BigDecimal.ZERO + + scope.eval( + """ + import lyng.decimal + extern var X: Decimal + """.trimIndent() + ) + + scope.globalBinder().bindGlobalVarRaw( + name = "X", + get = { it.newDecimal(x) }, + set = { _, value -> + x = when (value) { + is ObjInt -> BigDecimal.fromLong(value.value) + is ObjReal -> BigDecimal.fromDouble(value.value) + is ObjInstance -> value.data as BigDecimal + else -> error("unexpected value: $value") + } + } + ) + + scope.eval( + """ + fun main() { + assertEquals("42", 42.d.toStringExpanded()) + } + + main() + """.trimIndent() + ) + + assertEquals(BigDecimal.ZERO, x) + } + + @Test + fun externDecimalDeclarationAloneDoesNotBreakDecimalLiteralRendering() = runTest { + val scope = Script.newScope() + + scope.eval( + """ + import lyng.decimal + extern var X: Decimal + + fun main() { + assertEquals("42", 42.d.toStringExpanded()) + } + + main() + """.trimIndent() + ) + } + + @Test + fun parserKeeps42DotDAsIntDotIdentifierAfterExternDecimalDeclaration() = runTest { + val tokens = parseLyng( + Source( + "test", + """ + import lyng.decimal + extern var X: Decimal + + fun main() { + 42.d.toStringExpanded() + } + """.trimIndent() + ) + ) + val tokenTexts = tokens.map { it.type to it.value } + val needle = listOf( + Token.Type.INT to "42", + Token.Type.DOT to ".", + Token.Type.ID to "d", + Token.Type.DOT to ".", + Token.Type.ID to "toStringExpanded", + ) + val found = tokenTexts.windowed(needle.size).any { it == needle } + assertTrue(found, tokenTexts.joinToString()) + } } diff --git a/lynglib/src/commonTest/kotlin/net/sergeych/lyng/DecimalModuleTest.kt b/lynglib/src/commonTest/kotlin/net/sergeych/lyng/DecimalModuleTest.kt index 2da9013..4aaced3 100644 --- a/lynglib/src/commonTest/kotlin/net/sergeych/lyng/DecimalModuleTest.kt +++ b/lynglib/src/commonTest/kotlin/net/sergeych/lyng/DecimalModuleTest.kt @@ -32,8 +32,10 @@ class DecimalModuleTest { assertEquals("12.34", Decimal.fromString("12.34").toStringExpanded()) assertEquals("1", Decimal.fromInt(1).toStringExpanded()) + assertEquals("42", Decimal.fromInt(42).toStringExpanded()) assertEquals("2.5", "2.5".d.toStringExpanded()) assertEquals("1", 1.d.toStringExpanded()) + assertEquals("42", 42.d.toStringExpanded()) assertEquals("2.2", 2.2.d.toStringExpanded()) assertEquals("3", (1 + 2).d.toStringExpanded()) assertEquals("1.5", (1 + 0.5).d.toStringExpanded()) @@ -229,6 +231,21 @@ class DecimalModuleTest { """) } + @Test + fun decimalPropertyWorksInsideFunctionBody() = runTest { + eval(""" + import lyng.decimal + + fun main() { + val x = 42.d + assertEquals(42.d, x) + assertEquals(53.d, x + 11) + } + + main() + """.trimIndent()) + } + @Test fun kotlinHelperCanWrapIonBigDecimal() = runTest { val scope = Script.newScope()