fixed Decima/Complex interop bug

This commit is contained in:
Sergey Chernov 2026-03-30 09:25:23 +03:00
parent cdd48ec871
commit f845213332
4 changed files with 48 additions and 8 deletions

View File

@ -87,11 +87,37 @@ object ObjComplexSupport {
)
}
internal suspend fun decimalBinary(scope: ScopeFacade, decimal: Obj, other: Obj, operator: InteropOperator): Obj? {
val left = ObjDecimalSupport.toDoubleOrNull(decimal) ?: return null
val complex = other as? ObjInstance ?: return null
if (complex.objClass.className != "Complex") return null
val otherReal = complex.readField(scope.requireScope(), "real").value.toDouble()
val otherImag = complex.readField(scope.requireScope(), "imag").value.toDouble()
return when (operator) {
InteropOperator.Plus -> instantiateComplex(scope, complex.objClass, left + otherReal, otherImag)
InteropOperator.Minus -> instantiateComplex(scope, complex.objClass, left - otherReal, -otherImag)
InteropOperator.Mul -> instantiateComplex(scope, complex.objClass, left * otherReal, left * otherImag)
InteropOperator.Div -> {
val denominator = otherReal * otherReal + otherImag * otherImag
instantiateComplex(scope, complex.objClass, left * otherReal / denominator, -left * otherImag / denominator)
}
else -> null
}
}
private suspend fun ScopeFacade.newComplex(complexClass: ObjClass, real: Double, imag: Double): ObjInstance =
call(
complexClass,
Arguments(ObjReal.of(real), ObjReal.of(imag))
) as? ObjInstance ?: raiseIllegalState("Complex() did not return an object instance")
instantiateComplex(this, complexClass, real, imag)
private suspend fun instantiateComplex(scope: ScopeFacade, complexClass: ObjClass, real: Double, imag: Double): ObjInstance {
val runtimeScope = scope.requireScope()
val instance = complexClass.createInstance(runtimeScope)
complexClass.initializeInstance(
instance,
Arguments(ObjReal.of(real), ObjReal.of(imag)),
runConstructors = false
)
return instance
}
private fun ScopeFacade.decimalToReal(value: Obj): Double =
ObjDecimalSupport.toDoubleOrNull(value)

View File

@ -54,19 +54,23 @@ object ObjDecimalSupport {
instance.kotlinInstanceData = zero
}
decimalClass.addFn("plus") {
OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Plus)
ObjComplexSupport.decimalBinary(this, thisObj, args.firstAndOnly(), InteropOperator.Plus)
?: OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Plus)
?: newInstance(decimalClass, valueOf(thisObj).plus(coerceArg(requireScope(), args.firstAndOnly())))
}
decimalClass.addFn("minus") {
OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Minus)
ObjComplexSupport.decimalBinary(this, thisObj, args.firstAndOnly(), InteropOperator.Minus)
?: OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Minus)
?: newInstance(decimalClass, valueOf(thisObj).minus(coerceArg(requireScope(), args.firstAndOnly())))
}
decimalClass.addFn("mul") {
OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Mul)
ObjComplexSupport.decimalBinary(this, thisObj, args.firstAndOnly(), InteropOperator.Mul)
?: OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Mul)
?: newInstance(decimalClass, valueOf(thisObj).times(coerceArg(requireScope(), args.firstAndOnly())))
}
decimalClass.addFn("div") {
OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Div)
ObjComplexSupport.decimalBinary(this, thisObj, args.firstAndOnly(), InteropOperator.Div)
?: OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Div)
?: newInstance(decimalClass, divideWithContext(valueOf(thisObj), coerceArg(requireScope(), args.firstAndOnly()), currentDivisionMode(requireScope())))
}
decimalClass.addFn("mod") {

View File

@ -97,6 +97,15 @@ class ComplexModuleTest {
assert( 5 + 1.d.i is Complex )
assert( 5.d + 1.i is Complex )
assert( 5.d + 2.d.i is Complex )
assertEquals("0.0+1.0i", 1.d.i.toString())
assertEquals("1.0+0.0i", 1.d.re.toString())
var c = 1 + 2.i
assert(c is Complex)
assertEquals("1.0+2.0i", c.toString())
c = 1.d + 2.i
assertEquals("1.0+2.0i", c.toString())
""".trimIndent()
)
}

View File

@ -308,4 +308,5 @@ class DecimalModuleTest {
assertEquals(10,t)
""".trimIndent())
}
}