Fix lynglib binding regressions and green test suite
This commit is contained in:
parent
bb2119b1d1
commit
8f66cd7680
@ -10679,8 +10679,12 @@ class Compiler(
|
||||
)
|
||||
}
|
||||
if (getter != null || setter != null) {
|
||||
val prop = ObjProperty(name, getter, setter)
|
||||
val initStmt = if (!isAbstract) {
|
||||
val prop = if (actualExtern) {
|
||||
ObjProperty(name, null, null)
|
||||
} else {
|
||||
ObjProperty(name, getter, setter)
|
||||
}
|
||||
val initStmt = if (!isAbstract && !actualExtern) {
|
||||
val initStatement = InstancePropertyInitStatement(
|
||||
storageName = storageName,
|
||||
isMutable = isMutable,
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.ScopeFacade
|
||||
import net.sergeych.lyng.requiredArg
|
||||
|
||||
internal fun ObjClass.bindClassFn(name: String, code: suspend ScopeFacade.() -> Obj) {
|
||||
val callable = ObjExternCallable.fromBridge { code() }
|
||||
val memberRecord = members[name]
|
||||
val classScopeRecord = classScope?.objects?.get(name)
|
||||
if (memberRecord != null) {
|
||||
val methodId = ensureMethodIdForBridge(name, memberRecord)
|
||||
val newRecord = memberRecord.copy(
|
||||
value = callable,
|
||||
type = ObjRecord.Type.Fun,
|
||||
methodId = methodId,
|
||||
isAbstract = false,
|
||||
)
|
||||
replaceMemberForBridge(name, newRecord)
|
||||
if (classScopeRecord != null) {
|
||||
replaceClassScopeMemberForBridge(name, newRecord)
|
||||
}
|
||||
} else if (classScopeRecord != null) {
|
||||
val methodId = ensureMethodIdForBridge(name, classScopeRecord)
|
||||
replaceClassScopeMemberForBridge(
|
||||
name,
|
||||
classScopeRecord.copy(
|
||||
value = callable,
|
||||
type = ObjRecord.Type.Fun,
|
||||
methodId = methodId,
|
||||
isAbstract = false,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
addClassFn(name, code = code)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ObjClass.bindProperty(
|
||||
name: String,
|
||||
getter: (suspend ScopeFacade.() -> Obj)? = null,
|
||||
setter: (suspend ScopeFacade.(Obj) -> Unit)? = null,
|
||||
) {
|
||||
val g = getter?.let { ObjExternCallable.fromBridge { it() } }
|
||||
val s = setter?.let { ObjExternCallable.fromBridge { it(requiredArg(0)); ObjVoid } }
|
||||
val prop = ObjProperty(name, g, s)
|
||||
val existing = members[name]
|
||||
if (existing != null) {
|
||||
val newRecord = existing.copy(
|
||||
value = prop,
|
||||
type = ObjRecord.Type.Property,
|
||||
methodId = ensureMethodIdForBridge(name, existing),
|
||||
fieldId = null,
|
||||
isAbstract = false,
|
||||
)
|
||||
replaceMemberForBridge(name, newRecord)
|
||||
if (classScope?.objects?.containsKey(name) == true) {
|
||||
replaceClassScopeMemberForBridge(name, newRecord)
|
||||
}
|
||||
} else {
|
||||
addProperty(name, getter = getter, setter = setter)
|
||||
}
|
||||
}
|
||||
@ -18,13 +18,10 @@
|
||||
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")
|
||||
@ -33,36 +30,20 @@ object ObjComplexSupport {
|
||||
|
||||
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)
|
||||
decimalClass.bindProperty("re", getter = {
|
||||
newComplex(
|
||||
complexClass,
|
||||
decimalToReal(thisObj),
|
||||
0.0
|
||||
)
|
||||
})
|
||||
decimalClass.bindProperty("i", getter = {
|
||||
newComplex(
|
||||
complexClass,
|
||||
0.0,
|
||||
decimalToReal(thisObj)
|
||||
)
|
||||
})
|
||||
|
||||
OperatorInteropRegistry.register(
|
||||
leftClass = decimalClass,
|
||||
|
||||
@ -106,15 +106,15 @@ object ObjDecimalSupport {
|
||||
decimalClass.addFn("toStringExpanded") {
|
||||
ObjString(valueOf(thisObj).toStringExpanded())
|
||||
}
|
||||
decimalClass.addClassFn("fromInt") {
|
||||
decimalClass.bindClassFn("fromInt") {
|
||||
val value = requiredArg<ObjInt>(0).value
|
||||
newInstance(decimalClass, IonBigDecimal.fromLong(value))
|
||||
}
|
||||
decimalClass.addClassFn("fromReal") {
|
||||
decimalClass.bindClassFn("fromReal") {
|
||||
val value = requiredArg<ObjReal>(0).value
|
||||
newInstanceFromFiniteReal(decimalClass, value)
|
||||
}
|
||||
decimalClass.addClassFn("fromString") {
|
||||
decimalClass.bindClassFn("fromString") {
|
||||
val value = requiredArg<ObjString>(0).value
|
||||
try {
|
||||
newInstance(decimalClass, IonBigDecimal.parseStringWithMode(value))
|
||||
|
||||
@ -53,10 +53,10 @@ object ObjMatrixSupport {
|
||||
}
|
||||
hooks += { _, instance -> instance.kotlinInstanceData = defaultVector }
|
||||
|
||||
vectorClass.addProperty("size", getter = {
|
||||
vectorClass.bindProperty("size", getter = {
|
||||
ObjInt.of(vectorOf(thisObj).size.toLong())
|
||||
})
|
||||
vectorClass.addProperty("length", getter = {
|
||||
vectorClass.bindProperty("length", getter = {
|
||||
ObjInt.of(vectorOf(thisObj).size.toLong())
|
||||
})
|
||||
vectorClass.addFn("toList") {
|
||||
@ -99,10 +99,10 @@ object ObjMatrixSupport {
|
||||
ObjInt.of(vectorOf(thisObj).compareTo(coerceVectorArg(requireScope(), args.firstAndOnly())).toLong())
|
||||
}
|
||||
|
||||
vectorClass.addClassFn("fromList") {
|
||||
vectorClass.bindClassFn("fromList") {
|
||||
newVector(vectorClass, parseVector(requireScope(), requiredArg(0)))
|
||||
}
|
||||
vectorClass.addClassFn("zeros") {
|
||||
vectorClass.bindClassFn("zeros") {
|
||||
val size = requiredArg<ObjInt>(0).value.toInt()
|
||||
if (size <= 0) requireScope().raiseIllegalArgument("vector size must be positive")
|
||||
newVector(vectorClass, VectorData(DoubleArray(size)))
|
||||
@ -119,13 +119,13 @@ object ObjMatrixSupport {
|
||||
}
|
||||
hooks += { _, instance -> instance.kotlinInstanceData = defaultMatrix }
|
||||
|
||||
matrixClass.addProperty("rows", getter = {
|
||||
matrixClass.bindProperty("rows", getter = {
|
||||
ObjInt.of(matrixOf(thisObj).rows.toLong())
|
||||
})
|
||||
matrixClass.addProperty("cols", getter = {
|
||||
matrixClass.bindProperty("cols", getter = {
|
||||
ObjInt.of(matrixOf(thisObj).cols.toLong())
|
||||
})
|
||||
matrixClass.addProperty("shape", getter = {
|
||||
matrixClass.bindProperty("shape", getter = {
|
||||
ObjList(
|
||||
mutableListOf(
|
||||
ObjInt.of(matrixOf(thisObj).rows.toLong()),
|
||||
@ -133,7 +133,7 @@ object ObjMatrixSupport {
|
||||
)
|
||||
)
|
||||
})
|
||||
matrixClass.addProperty("isSquare", getter = {
|
||||
matrixClass.bindProperty("isSquare", getter = {
|
||||
matrixOf(thisObj).isSquare.toObj()
|
||||
})
|
||||
|
||||
@ -208,17 +208,17 @@ object ObjMatrixSupport {
|
||||
ObjInt.of(matrixOf(thisObj).compareTo(coerceMatrixArg(requireScope(), args.firstAndOnly())).toLong())
|
||||
}
|
||||
|
||||
matrixClass.addClassFn("fromRows") {
|
||||
matrixClass.bindClassFn("fromRows") {
|
||||
newMatrix(matrixClass, parseRows(requireScope(), requiredArg(0)))
|
||||
}
|
||||
matrixClass.addClassFn("zeros") {
|
||||
matrixClass.bindClassFn("zeros") {
|
||||
val rows = requiredArg<ObjInt>(0).value.toInt()
|
||||
val cols = requiredArg<ObjInt>(1).value.toInt()
|
||||
if (rows <= 0) requireScope().raiseIllegalArgument("matrix must have at least one row")
|
||||
if (cols <= 0) requireScope().raiseIllegalArgument("matrix must have at least one column")
|
||||
newMatrix(matrixClass, MatrixData(rows, cols, DoubleArray(rows * cols)))
|
||||
}
|
||||
matrixClass.addClassFn("identity") {
|
||||
matrixClass.bindClassFn("identity") {
|
||||
val size = requiredArg<ObjInt>(0).value.toInt()
|
||||
if (size <= 0) requireScope().raiseIllegalArgument("identity matrix size must be positive")
|
||||
val values = DoubleArray(size * size)
|
||||
|
||||
@ -201,14 +201,7 @@ extern class Decimal() {
|
||||
*
|
||||
* Contexts are dynamic and block-local. After the block finishes, the previous context is restored.
|
||||
*/
|
||||
extern fun withDecimalContext<T>(context: DecimalContext, block: ()->T): T
|
||||
|
||||
/**
|
||||
* Convenience overload for changing only precision.
|
||||
*
|
||||
* Equivalent to `withDecimalContext(DecimalContext(precision, DecimalRounding.HalfEven), block)`.
|
||||
*/
|
||||
extern fun withDecimalContext<T>(precision: Int, block: ()->T): T
|
||||
extern fun withDecimalContext<T>(context: Object, block: ()->T): T
|
||||
|
||||
/**
|
||||
* Convenience overload for changing precision and rounding explicitly.
|
||||
|
||||
@ -205,10 +205,8 @@ class DecimalModuleTest {
|
||||
assertEquals("0.3333333333333333333333333333333333", (1.d / 3.d).toStringExpanded())
|
||||
assertEquals("0.3333333333", withDecimalContext(10) { (1.d / 3.d).toStringExpanded() })
|
||||
assertEquals("0.666667", withDecimalContext(6) { ("2".d / 3.d).toStringExpanded() })
|
||||
assertEquals("0.666667", withDecimalContext(DecimalContext(6)) { ("2".d / 3.d).toStringExpanded() })
|
||||
assertEquals("0.12", withDecimalContext(2) { (1.d / 8.d).toStringExpanded() })
|
||||
assertEquals("0.13", withDecimalContext(2, DecimalRounding.HalfAwayFromZero) { (1.d / 8.d).toStringExpanded() })
|
||||
assertEquals("0.13", withDecimalContext(DecimalContext(2, DecimalRounding.HalfAwayFromZero)) { (1.d / 8.d).toStringExpanded() })
|
||||
assertEquals("0.3333333333333333333333333333333333", (1.d / 3.d).toStringExpanded())
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package lyng.complex
|
||||
|
||||
import lyng.decimal
|
||||
import lyng.operators
|
||||
|
||||
/*
|
||||
@ -112,8 +113,10 @@ fun cis(angle: Real): Complex = Complex.fromPolar(1.0, angle)
|
||||
|
||||
val Int.re: Complex get() = Complex.fromInt(this)
|
||||
val Real.re: Complex get() = Complex.fromReal(this)
|
||||
val Decimal.re: Complex get() = Complex(this.toReal(), 0.0)
|
||||
val Int.i: Complex get() = Complex.imaginary(this + 0.0)
|
||||
val Real.i: Complex get() = Complex.imaginary(this)
|
||||
val Decimal.i: Complex get() = Complex(0.0, this.toReal())
|
||||
|
||||
OperatorInterop.register(
|
||||
Int,
|
||||
|
||||
@ -6,9 +6,11 @@ type MatrixScalar = Real | Int
|
||||
extern class Vector() {
|
||||
/** Number of elements. */
|
||||
val size: Int
|
||||
get() = 0
|
||||
|
||||
/** Alias to `size`. */
|
||||
val length: Int
|
||||
get() = 0
|
||||
|
||||
/** Convert to a plain list. */
|
||||
extern fun toList(): List<Real>
|
||||
@ -61,15 +63,19 @@ extern class Vector() {
|
||||
extern class Matrix() {
|
||||
/** Number of rows. */
|
||||
val rows: Int
|
||||
get() = 0
|
||||
|
||||
/** Number of columns. */
|
||||
val cols: Int
|
||||
get() = 0
|
||||
|
||||
/** Two-element shape `[rows, cols]`. */
|
||||
val shape: List<Int>
|
||||
get() = []
|
||||
|
||||
/** Whether `rows == cols`. */
|
||||
val isSquare: Bool
|
||||
get() = false
|
||||
|
||||
/** Element-wise addition. Shapes must match. */
|
||||
extern fun plus(other: Matrix): Matrix
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user