diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjComplexSupport.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjComplexSupport.kt index dde3bb6..06bb393 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjComplexSupport.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjComplexSupport.kt @@ -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) 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 cda492a..5b92444 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDecimalSupport.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDecimalSupport.kt @@ -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") { diff --git a/lynglib/src/commonTest/kotlin/net/sergeych/lyng/ComplexModuleTest.kt b/lynglib/src/commonTest/kotlin/net/sergeych/lyng/ComplexModuleTest.kt index 43f7da9..a60f749 100644 --- a/lynglib/src/commonTest/kotlin/net/sergeych/lyng/ComplexModuleTest.kt +++ b/lynglib/src/commonTest/kotlin/net/sergeych/lyng/ComplexModuleTest.kt @@ -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() ) } diff --git a/lynglib/src/commonTest/kotlin/net/sergeych/lyng/DecimalModuleTest.kt b/lynglib/src/commonTest/kotlin/net/sergeych/lyng/DecimalModuleTest.kt index 1d06af0..0e6cdf8 100644 --- a/lynglib/src/commonTest/kotlin/net/sergeych/lyng/DecimalModuleTest.kt +++ b/lynglib/src/commonTest/kotlin/net/sergeych/lyng/DecimalModuleTest.kt @@ -308,4 +308,5 @@ class DecimalModuleTest { assertEquals(10,t) """.trimIndent()) } + }