Added Decimal support for complex number
This commit is contained in:
parent
8a560f5417
commit
286ec30422
@ -875,6 +875,7 @@ class Script(
|
|||||||
}
|
}
|
||||||
addPackage("lyng.complex") { module ->
|
addPackage("lyng.complex") { module ->
|
||||||
module.eval(Source("lyng.complex", complexLyng))
|
module.eval(Source("lyng.complex", complexLyng))
|
||||||
|
ObjComplexSupport.bindTo(module)
|
||||||
}
|
}
|
||||||
addPackage("lyng.buffer") {
|
addPackage("lyng.buffer") {
|
||||||
it.addConstDoc(
|
it.addConstDoc(
|
||||||
|
|||||||
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.sergeych.lyng.obj
|
||||||
|
|
||||||
|
import net.sergeych.lyng.*
|
||||||
|
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||||
|
import net.sergeych.lyng.miniast.type
|
||||||
|
import net.sergeych.lyng.requiredArg
|
||||||
|
|
||||||
|
object ObjComplexSupport {
|
||||||
|
private object BoundMarker
|
||||||
|
private val complexTypeDecl = TypeDecl.Simple("lyng.complex.Complex", false)
|
||||||
|
|
||||||
|
suspend fun bindTo(module: ModuleScope) {
|
||||||
|
val complexClass = module.requireClass("Complex")
|
||||||
|
if (complexClass.kotlinClassData === BoundMarker) return
|
||||||
|
complexClass.kotlinClassData = BoundMarker
|
||||||
|
|
||||||
|
val decimalModule = module.currentImportProvider.createModuleScope(module.pos, "lyng.decimal")
|
||||||
|
val decimalClass = decimalModule.requireClass("Decimal")
|
||||||
|
|
||||||
|
decimalClass.addPropertyDoc(
|
||||||
|
name = "re",
|
||||||
|
doc = "Convert this Decimal to a Complex with zero imaginary part.",
|
||||||
|
type = type("lyng.complex.Complex"),
|
||||||
|
moduleName = "lyng.complex",
|
||||||
|
getter = {
|
||||||
|
newComplex(
|
||||||
|
complexClass,
|
||||||
|
decimalToReal(thisObj),
|
||||||
|
0.0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
decimalClass.members["re"] = decimalClass.members.getValue("re").copy(typeDecl = complexTypeDecl)
|
||||||
|
|
||||||
|
decimalClass.addPropertyDoc(
|
||||||
|
name = "i",
|
||||||
|
doc = "Convert this Decimal to a pure imaginary Complex after rounding to Real.",
|
||||||
|
type = type("lyng.complex.Complex"),
|
||||||
|
moduleName = "lyng.complex",
|
||||||
|
getter = {
|
||||||
|
newComplex(
|
||||||
|
complexClass,
|
||||||
|
0.0,
|
||||||
|
decimalToReal(thisObj)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
decimalClass.members["i"] = decimalClass.members.getValue("i").copy(typeDecl = complexTypeDecl)
|
||||||
|
|
||||||
|
OperatorInteropRegistry.register(
|
||||||
|
leftClass = decimalClass,
|
||||||
|
rightClass = complexClass,
|
||||||
|
commonClass = complexClass,
|
||||||
|
operatorNames = listOf(
|
||||||
|
InteropOperator.Plus.name,
|
||||||
|
InteropOperator.Minus.name,
|
||||||
|
InteropOperator.Mul.name,
|
||||||
|
InteropOperator.Div.name
|
||||||
|
),
|
||||||
|
leftToCommon = ObjExternCallable.fromBridge {
|
||||||
|
newComplex(
|
||||||
|
complexClass,
|
||||||
|
decimalToReal(requiredArg(0)),
|
||||||
|
0.0
|
||||||
|
)
|
||||||
|
},
|
||||||
|
rightToCommon = ObjExternCallable.fromBridge {
|
||||||
|
requiredArg<Obj>(0)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
private fun ScopeFacade.decimalToReal(value: Obj): Double =
|
||||||
|
ObjDecimalSupport.toDoubleOrNull(value)
|
||||||
|
?: raiseClassCastError("expected Decimal-compatible value, got ${value.objClass.className}")
|
||||||
|
}
|
||||||
@ -54,16 +54,20 @@ object ObjDecimalSupport {
|
|||||||
instance.kotlinInstanceData = zero
|
instance.kotlinInstanceData = zero
|
||||||
}
|
}
|
||||||
decimalClass.addFn("plus") {
|
decimalClass.addFn("plus") {
|
||||||
newInstance(decimalClass, valueOf(thisObj).plus(coerceArg(requireScope(), args.firstAndOnly())))
|
OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Plus)
|
||||||
|
?: newInstance(decimalClass, valueOf(thisObj).plus(coerceArg(requireScope(), args.firstAndOnly())))
|
||||||
}
|
}
|
||||||
decimalClass.addFn("minus") {
|
decimalClass.addFn("minus") {
|
||||||
newInstance(decimalClass, valueOf(thisObj).minus(coerceArg(requireScope(), args.firstAndOnly())))
|
OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Minus)
|
||||||
|
?: newInstance(decimalClass, valueOf(thisObj).minus(coerceArg(requireScope(), args.firstAndOnly())))
|
||||||
}
|
}
|
||||||
decimalClass.addFn("mul") {
|
decimalClass.addFn("mul") {
|
||||||
newInstance(decimalClass, valueOf(thisObj).times(coerceArg(requireScope(), args.firstAndOnly())))
|
OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Mul)
|
||||||
|
?: newInstance(decimalClass, valueOf(thisObj).times(coerceArg(requireScope(), args.firstAndOnly())))
|
||||||
}
|
}
|
||||||
decimalClass.addFn("div") {
|
decimalClass.addFn("div") {
|
||||||
newInstance(decimalClass, divideWithContext(valueOf(thisObj), coerceArg(requireScope(), args.firstAndOnly()), currentDivisionMode(requireScope())))
|
OperatorInteropRegistry.invokeBinary(requireScope(), thisObj, args.firstAndOnly(), InteropOperator.Div)
|
||||||
|
?: newInstance(decimalClass, divideWithContext(valueOf(thisObj), coerceArg(requireScope(), args.firstAndOnly()), currentDivisionMode(requireScope())))
|
||||||
}
|
}
|
||||||
decimalClass.addFn("mod") {
|
decimalClass.addFn("mod") {
|
||||||
newInstance(decimalClass, valueOf(thisObj).rem(coerceArg(requireScope(), args.firstAndOnly())))
|
newInstance(decimalClass, valueOf(thisObj).rem(coerceArg(requireScope(), args.firstAndOnly())))
|
||||||
|
|||||||
@ -73,4 +73,32 @@ class ComplexModuleTest {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testInferences() = runTest {
|
||||||
|
eval(
|
||||||
|
$$"""
|
||||||
|
import lyng.decimal
|
||||||
|
import lyng.complex
|
||||||
|
|
||||||
|
assert( 1.i is Complex )
|
||||||
|
assert( 5 + 1.i is Complex )
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun testDecimalInferences() = runTest {
|
||||||
|
eval(
|
||||||
|
$$"""
|
||||||
|
import lyng.decimal
|
||||||
|
import lyng.complex
|
||||||
|
|
||||||
|
assert( 1.d.i is Complex )
|
||||||
|
assert( 5 + 1.d.i is Complex )
|
||||||
|
assert( 5.d + 1.i is Complex )
|
||||||
|
assert( 5.d + 2.d.i is Complex )
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user