From 2c0a6c7b34e31419122f3e29afcc44ae676a8220 Mon Sep 17 00:00:00 2001 From: sergeych Date: Wed, 7 Jan 2026 09:33:10 +0100 Subject: [PATCH] operators overriding --- docs/OOP.md | 93 +++++++++++++++ .../kotlin/net/sergeych/lyng/Compiler.kt | 7 +- .../kotlin/net/sergeych/lyng/obj/Obj.kt | 112 ++++++++++++++---- .../net/sergeych/lyng/obj/ObjBitBuffer.kt | 2 +- .../kotlin/net/sergeych/lyng/obj/ObjBool.kt | 2 +- .../kotlin/net/sergeych/lyng/obj/ObjBuffer.kt | 2 +- .../kotlin/net/sergeych/lyng/obj/ObjChar.kt | 2 +- .../lyng/obj/ObjCompletableDeferred.kt | 2 +- .../net/sergeych/lyng/obj/ObjDeferred.kt | 2 +- .../net/sergeych/lyng/obj/ObjDuration.kt | 2 +- .../net/sergeych/lyng/obj/ObjDynamic.kt | 4 +- .../kotlin/net/sergeych/lyng/obj/ObjFlow.kt | 6 +- .../net/sergeych/lyng/obj/ObjInstanceClass.kt | 3 - .../sergeych/lyng/obj/ObjKotlinIterator.kt | 4 +- .../kotlin/net/sergeych/lyng/obj/ObjMap.kt | 4 +- .../kotlin/net/sergeych/lyng/obj/ObjMutex.kt | 2 +- .../kotlin/net/sergeych/lyng/obj/ObjRange.kt | 2 +- .../net/sergeych/lyng/obj/ObjRangeIterator.kt | 4 +- .../kotlin/net/sergeych/lyng/obj/ObjReal.kt | 2 +- .../kotlin/net/sergeych/lyng/obj/ObjRegex.kt | 4 +- .../net/sergeych/lyng/obj/ObjRingBuffer.kt | 2 +- .../kotlin/net/sergeych/lyng/obj/ObjSet.kt | 2 +- lynglib/src/commonTest/kotlin/ScriptTest.kt | 4 +- lynglib/stdlib/lyng/root.lyng | 4 +- 24 files changed, 216 insertions(+), 57 deletions(-) diff --git a/docs/OOP.md b/docs/OOP.md index 3739627..9eba039 100644 --- a/docs/OOP.md +++ b/docs/OOP.md @@ -544,6 +544,99 @@ class Critical { Attempting to override a `closed` member results in a compile-time error. +## Operator Overloading + +Lyng allows you to overload standard operators by defining specific named methods in your classes. When an operator expression is evaluated, Lyng delegates the operation to these methods if they are available. + +### Binary Operators + +To overload a binary operator, define the corresponding method that takes one argument: + +| Operator | Method Name | +| :--- | :--- | +| `a + b` | `plus(other)` | +| `a - b` | `minus(other)` | +| `a * b` | `mul(other)` | +| `a / b` | `div(other)` | +| `a % b` | `mod(other)` | +| `a && b` | `logicalAnd(other)` | +| `a \|\| b` | `logicalOr(other)` | +| `a =~ b` | `operatorMatch(other)` | +| `a & b` | `bitAnd(other)` | +| `a \| b` | `bitOr(other)` | +| `a ^ b` | `bitXor(other)` | +| `a << b` | `shl(other)` | +| `a >> b` | `shr(other)` | + +Example: +```lyng +class Vector(val x, val y) { + fun plus(other) = Vector(x + other.x, y + other.y) + override fun toString() = "Vector(${x}, ${y})" +} + +val v1 = Vector(1, 2) +val v2 = Vector(3, 4) +assertEquals(Vector(4, 6), v1 + v2) +``` + +### Unary Operators + +Unary operators are overloaded by defining methods with no arguments: + +| Operator | Method Name | +| :--- | :--- | +| `-a` | `negate()` | +| `!a` | `logicalNot()` | +| `~a` | `bitNot()` | + +### Assignment Operators + +Assignment operators like `+=` first attempt to call a specific assignment method. If that method is not defined, they fall back to a combination of the binary operator and a regular assignment (e.g., `a = a + b`). + +| Operator | Method Name | Fallback | +| :--- | :--- | :--- | +| `a += b` | `plusAssign(other)` | `a = a + b` | +| `a -= b` | `minusAssign(other)` | `a = a - b` | +| `a *= b` | `mulAssign(other)` | `a = a * b` | +| `a /= b` | `divAssign(other)` | `a = a / b` | +| `a %= b` | `modAssign(other)` | `a = a % b` | + +Example of in-place mutation: +```lyng +class Counter(var value) { + fun plusAssign(n) { + value = value + n + } +} + +val c = Counter(10) +c += 5 +assertEquals(15, c.value) +``` + +### Comparison Operators + +Comparison operators use `compareTo` and `equals`. + +| Operator | Method Name | +| :--- | :--- | +| `a == b`, `a != b` | `equals(other)` | +| `<`, `>`, `<=`, `>=`, `<=>` | `compareTo(other)` | + +- `compareTo` should return: + - `0` if `a == b` + - A negative integer if `a < b` + - A positive integer if `a > b` +- The `<=>` (shuttle) operator returns the result of `compareTo` directly. +- `equals` returns a `Bool`. If `equals` is not explicitly defined, Lyng falls back to `compareTo(other) == 0`. + +> **Note**: Methods that are already defined in the base `Obj` class (like `equals`, `toString`, or `contains`) require the `override` keyword when redefined in your class or as an extension. Other operator methods (like `plus` or `negate`) do not require `override` unless they are already present in your class's hierarchy. + +### Increment and Decrement + +`++` and `--` operators are implemented using `plus(1)` or `minus(1)` combined with an assignment back to the variable. If the variable is a field or local variable, it will be updated with the result of the operation. + Compatibility notes: - Existing single‑inheritance code continues to work unchanged; its resolution order reduces to the single base. diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 0abd75c..a0811a0 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -1351,8 +1351,11 @@ class Compiler( val isMember = (codeContexts.lastOrNull() is CodeContext.ClassBody) - if (!isMember && (isOverride || isClosed)) - throw ScriptError(currentToken.pos, "modifiers override and closed are only allowed for class members") + if (!isMember && isClosed) + throw ScriptError(currentToken.pos, "modifier closed is only allowed for class members") + + if (!isMember && isOverride && currentToken.value != "fun" && currentToken.value != "fn") + throw ScriptError(currentToken.pos, "modifier override outside class is only allowed for extension functions") if (!isMember && isAbstract && currentToken.value != "class") throw ScriptError(currentToken.pos, "modifier abstract at top level is only allowed for classes") diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt index 0c1bf1e..a227188 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt @@ -143,11 +143,17 @@ open class Obj { open suspend fun compareTo(scope: Scope, other: Obj): Int { if (other === this) return 0 if (other === ObjNull || other === ObjUnset || other === ObjVoid) return 2 - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "compareTo", Arguments(other)) { + scope.raiseNotImplemented("compareTo for ${objClass.className}") + }.cast(scope).toInt() } open suspend fun equals(scope: Scope, other: Obj): Boolean { if (other === this) return true + val m = objClass.getInstanceMemberOrNull("equals") ?: scope.findExtension(objClass, "equals") + if (m != null) { + return invokeInstanceMethod(scope, "equals", Arguments(other)).toBool() + } return try { compareTo(scope, other) == 0 } catch (e: ExecutionError) { @@ -225,46 +231,66 @@ open class Obj { * Class of the object: definition of member functions (top-level), etc. * Note that using lazy allows to avoid endless recursion here */ - open val objClass: ObjClass = rootObjectType + open val objClass: ObjClass get() = rootObjectType open suspend fun plus(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "plus", Arguments(other)) { + scope.raiseNotImplemented("plus for ${objClass.className}") + } } open suspend fun minus(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "minus", Arguments(other)) { + scope.raiseNotImplemented("minus for ${objClass.className}") + } } open suspend fun negate(scope: Scope): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "negate", Arguments.EMPTY) { + scope.raiseNotImplemented("negate for ${objClass.className}") + } } open suspend fun mul(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "mul", Arguments(other)) { + scope.raiseNotImplemented("mul for ${objClass.className}") + } } open suspend fun div(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "div", Arguments(other)) { + scope.raiseNotImplemented("div for ${objClass.className}") + } } open suspend fun mod(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "mod", Arguments(other)) { + scope.raiseNotImplemented("mod for ${objClass.className}") + } } open suspend fun logicalNot(scope: Scope): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "logicalNot", Arguments.EMPTY) { + scope.raiseNotImplemented("logicalNot for ${objClass.className}") + } } open suspend fun logicalAnd(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "logicalAnd", Arguments(other)) { + scope.raiseNotImplemented("logicalAnd for ${objClass.className}") + } } open suspend fun logicalOr(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "logicalOr", Arguments(other)) { + scope.raiseNotImplemented("logicalOr for ${objClass.className}") + } } open suspend fun operatorMatch(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "operatorMatch", Arguments(other)) { + scope.raiseNotImplemented("operatorMatch for ${objClass.className}") + } } open suspend fun operatorNotMatch(scope: Scope, other: Obj): Obj { @@ -273,27 +299,39 @@ open class Obj { // Bitwise ops default (override in numeric types that support them) open suspend fun bitAnd(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "bitAnd", Arguments(other)) { + scope.raiseNotImplemented("bitAnd for ${objClass.className}") + } } open suspend fun bitOr(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "bitOr", Arguments(other)) { + scope.raiseNotImplemented("bitOr for ${objClass.className}") + } } open suspend fun bitXor(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "bitXor", Arguments(other)) { + scope.raiseNotImplemented("bitXor for ${objClass.className}") + } } open suspend fun shl(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "shl", Arguments(other)) { + scope.raiseNotImplemented("shl for ${objClass.className}") + } } open suspend fun shr(scope: Scope, other: Obj): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "shr", Arguments(other)) { + scope.raiseNotImplemented("shr for ${objClass.className}") + } } open suspend fun bitNot(scope: Scope): Obj { - scope.raiseNotImplemented() + return invokeInstanceMethod(scope, "bitNot", Arguments.EMPTY) { + scope.raiseNotImplemented("bitNot for ${objClass.className}") + } } open suspend fun assign(scope: Scope, other: Obj): Obj? = null @@ -305,15 +343,43 @@ open class Obj { * if( the operation is not defined, it returns null and the compiler would try * to generate it as 'this = this + other', reassigning its variable */ - open suspend fun plusAssign(scope: Scope, other: Obj): Obj? = null + open suspend fun plusAssign(scope: Scope, other: Obj): Obj? { + val m = objClass.getInstanceMemberOrNull("plusAssign") ?: scope.findExtension(objClass, "plusAssign") + return if (m != null) { + invokeInstanceMethod(scope, "plusAssign", Arguments(other)) + } else null + } /** * `-=` operations, see [plusAssign] */ - open suspend fun minusAssign(scope: Scope, other: Obj): Obj? = null - open suspend fun mulAssign(scope: Scope, other: Obj): Obj? = null - open suspend fun divAssign(scope: Scope, other: Obj): Obj? = null - open suspend fun modAssign(scope: Scope, other: Obj): Obj? = null + open suspend fun minusAssign(scope: Scope, other: Obj): Obj? { + val m = objClass.getInstanceMemberOrNull("minusAssign") ?: scope.findExtension(objClass, "minusAssign") + return if (m != null) { + invokeInstanceMethod(scope, "minusAssign", Arguments(other)) + } else null + } + + open suspend fun mulAssign(scope: Scope, other: Obj): Obj? { + val m = objClass.getInstanceMemberOrNull("mulAssign") ?: scope.findExtension(objClass, "mulAssign") + return if (m != null) { + invokeInstanceMethod(scope, "mulAssign", Arguments(other)) + } else null + } + + open suspend fun divAssign(scope: Scope, other: Obj): Obj? { + val m = objClass.getInstanceMemberOrNull("divAssign") ?: scope.findExtension(objClass, "divAssign") + return if (m != null) { + invokeInstanceMethod(scope, "divAssign", Arguments(other)) + } else null + } + + open suspend fun modAssign(scope: Scope, other: Obj): Obj? { + val m = objClass.getInstanceMemberOrNull("modAssign") ?: scope.findExtension(objClass, "modAssign") + return if (m != null) { + invokeInstanceMethod(scope, "modAssign", Arguments(other)) + } else null + } open suspend fun getAndIncrement(scope: Scope): Obj { scope.raiseNotImplemented() diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBitBuffer.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBitBuffer.kt index 6389808..fe0173d 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBitBuffer.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBitBuffer.kt @@ -23,7 +23,7 @@ import net.sergeych.lynon.BitArray class ObjBitBuffer(val bitArray: BitArray) : Obj() { - override val objClass = type + override val objClass get() = type override suspend fun getAt(scope: Scope, index: Obj): Obj { return bitArray[index.toLong()].toObj() diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt index e99cd2c..7c2ca29 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBool.kt @@ -37,7 +37,7 @@ data class ObjBool(val value: Boolean) : Obj() { override fun toString(): String = value.toString() - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type override suspend fun logicalNot(scope: Scope): Obj = ObjBool(!value) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBuffer.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBuffer.kt index 9426f73..58f654e 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBuffer.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjBuffer.kt @@ -34,7 +34,7 @@ import kotlin.math.min open class ObjBuffer(val byteArray: UByteArray) : Obj() { - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type val hex by lazy { byteArray.encodeToHex("")} val base64 by lazy { byteArray.toByteArray().encodeToBase64Url()} diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjChar.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjChar.kt index ac61a23..26dfbaa 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjChar.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjChar.kt @@ -23,7 +23,7 @@ import net.sergeych.lyng.miniast.type class ObjChar(val value: Char): Obj() { - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type override suspend fun compareTo(scope: Scope, other: Obj): Int = (other as? ObjChar)?.let { value.compareTo(it.value) } ?: -1 diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjCompletableDeferred.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjCompletableDeferred.kt index 69eced7..74e6db6 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjCompletableDeferred.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjCompletableDeferred.kt @@ -25,7 +25,7 @@ import net.sergeych.lyng.miniast.type class ObjCompletableDeferred(val completableDeferred: CompletableDeferred): ObjDeferred(completableDeferred) { - override val objClass = type + override val objClass get() = type companion object { val type = object: ObjClass("CompletableDeferred", ObjDeferred.type){ diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDeferred.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDeferred.kt index 635e71f..54a85b0 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDeferred.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDeferred.kt @@ -24,7 +24,7 @@ import net.sergeych.lyng.miniast.type open class ObjDeferred(val deferred: Deferred): Obj() { - override val objClass = type + override val objClass get() = type companion object { val type = object: ObjClass("Deferred"){ diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDuration.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDuration.kt index 174735d..0761f0f 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDuration.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDuration.kt @@ -29,7 +29,7 @@ import kotlin.time.Duration.Companion.seconds import kotlin.time.DurationUnit class ObjDuration(val duration: Duration) : Obj() { - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type override fun toString(): String { return duration.toString() diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDynamic.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDynamic.kt index 157a200..d00c1b0 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDynamic.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDynamic.kt @@ -23,7 +23,7 @@ import net.sergeych.lyng.Scope import net.sergeych.lyng.Statement class ObjDynamicContext(val delegate: ObjDynamic) : Obj() { - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type companion object { val type = ObjClass("DelegateContext").apply { @@ -54,7 +54,7 @@ class ObjDynamicContext(val delegate: ObjDynamic) : Obj() { */ open class ObjDynamic(var readCallback: Statement? = null, var writeCallback: Statement? = null) : Obj() { - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type // Capture the lexical scope used to build this dynamic so callbacks can see outer locals internal var builderScope: Scope? = null diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjFlow.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjFlow.kt index b9a3540..1692e12 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjFlow.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjFlow.kt @@ -35,7 +35,7 @@ import kotlin.coroutines.cancellation.CancellationException class ObjFlowBuilder(val output: SendChannel) : Obj() { - override val objClass = type + override val objClass get() = type companion object { @OptIn(DelicateCoroutinesApi::class) @@ -91,7 +91,7 @@ private fun createLyngFlowInput(scope: Scope, producer: Statement): ReceiveChann class ObjFlow(val producer: Statement, val scope: Scope) : Obj() { - override val objClass = type + override val objClass get() = type companion object { val type = object : ObjClass("Flow", ObjIterable) { @@ -119,7 +119,7 @@ class ObjFlow(val producer: Statement, val scope: Scope) : Obj() { class ObjFlowIterator(val producer: Statement) : Obj() { - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type private var channel: ReceiveChannel? = null diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstanceClass.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstanceClass.kt index 3f211d4..59be2df 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstanceClass.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstanceClass.kt @@ -42,9 +42,6 @@ class ObjInstanceClass(val name: String, vararg parents: ObjClass) : ObjClass(na } init { - addFn("toString", true) { - thisObj.toString(this, true) - } } } \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjKotlinIterator.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjKotlinIterator.kt index 8da408b..0f606af 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjKotlinIterator.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjKotlinIterator.kt @@ -29,7 +29,7 @@ import net.sergeych.lyng.Scope */ class ObjKotlinIterator(val iterator: Iterator) : Obj() { - override val objClass = type + override val objClass get() = type companion object { val type = ObjClass("KotlinIterator", ObjIterator).apply { @@ -46,7 +46,7 @@ class ObjKotlinIterator(val iterator: Iterator) : Obj() { */ class ObjKotlinObjIterator(val iterator: Iterator) : Obj() { - override val objClass = type + override val objClass get() = type companion object { val type = ObjClass("KotlinIterator", ObjIterator).apply { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt index ae2633e..782db82 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMap.kt @@ -56,7 +56,7 @@ class ObjMapEntry(val key: Obj, val value: Obj) : Obj() { return ObjString("(${key.toString(scope).value} => ${value.toString(scope).value})") } - override val objClass = type + override val objClass get() = type override suspend fun serialize(scope: Scope, encoder: LynonEncoder, lynonType: LynonType?) { encoder.encodeAny(scope,key) @@ -106,7 +106,7 @@ class ObjMapEntry(val key: Obj, val value: Obj) : Obj() { class ObjMap(val map: MutableMap = mutableMapOf()) : Obj() { - override val objClass = type + override val objClass get() = type override suspend fun getAt(scope: Scope, index: Obj): Obj = map.get(index) ?: ObjNull diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMutex.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMutex.kt index 315153c..54197c8 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMutex.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMutex.kt @@ -26,7 +26,7 @@ import net.sergeych.lyng.miniast.addFnDoc import net.sergeych.lyng.miniast.type class ObjMutex(val mutex: Mutex): Obj() { - override val objClass = type + override val objClass get() = type companion object { val type = object: ObjClass("Mutex") { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt index de27744..94ab8a7 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt @@ -27,7 +27,7 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob val isOpenStart by lazy { start == null || start.isNull } val isOpenEnd by lazy { end == null || end.isNull } - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type override suspend fun defaultToString(scope: Scope): ObjString { val result = StringBuilder() diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRangeIterator.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRangeIterator.kt index e0abd7c..faa5dd5 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRangeIterator.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRangeIterator.kt @@ -26,7 +26,7 @@ class ObjRangeIterator(val self: ObjRange) : Obj() { private var lastIndex = 0 private var isCharRange: Boolean = false - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type fun Scope.init() { val s = self.start @@ -84,7 +84,7 @@ class ObjFastIntRangeIterator(private val start: Int, private val endExclusive: private var cur: Int = start - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type fun hasNext(): Boolean = cur < endExclusive diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt index a84ae41..e8ce96f 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjReal.kt @@ -37,7 +37,7 @@ data class ObjReal(val value: Double) : Obj(), Numeric { override val toObjInt: ObjInt get() = ObjInt.of(longValue) override val toObjReal: ObjReal get() = this - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type override fun byValueCopy(): Obj = this diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRegex.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRegex.kt index e50c081..c56ac05 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRegex.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRegex.kt @@ -26,7 +26,7 @@ import net.sergeych.lyng.miniast.addFnDoc import net.sergeych.lyng.miniast.type class ObjRegex(val regex: Regex) : Obj() { - override val objClass = type + override val objClass get() = type override suspend fun operatorMatch(scope: Scope, other: Obj): Obj { return regex.find(other.cast(scope).value)?.let { @@ -81,7 +81,7 @@ class ObjRegex(val regex: Regex) : Obj() { } class ObjRegexMatch(val match: MatchResult) : Obj() { - override val objClass = type + override val objClass get() = type val objGroups: ObjList by lazy { // Use groupValues so that index 0 is the whole match and subsequent indices are capturing groups, diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRingBuffer.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRingBuffer.kt index a9ec6fc..09a2440 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRingBuffer.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRingBuffer.kt @@ -81,7 +81,7 @@ class RingBuffer(val maxSize: Int) : Iterable { class ObjRingBuffer(val capacity: Int) : Obj() { val buffer = RingBuffer(capacity) - override val objClass: ObjClass = type + override val objClass: ObjClass get() = type override suspend fun plusAssign(scope: Scope, other: Obj): Obj { buffer.add(other.byValueCopy()) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjSet.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjSet.kt index 3d665ed..d9c72b3 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjSet.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjSet.kt @@ -28,7 +28,7 @@ import net.sergeych.lynon.LynonType class ObjSet(val set: MutableSet = mutableSetOf()) : Obj() { - override val objClass = type + override val objClass get() = type override suspend fun contains(scope: Scope, other: Obj): Boolean { return set.contains(other) diff --git a/lynglib/src/commonTest/kotlin/ScriptTest.kt b/lynglib/src/commonTest/kotlin/ScriptTest.kt index 65c66bf..537460f 100644 --- a/lynglib/src/commonTest/kotlin/ScriptTest.kt +++ b/lynglib/src/commonTest/kotlin/ScriptTest.kt @@ -4386,7 +4386,7 @@ class ScriptTest { """ class A(x,y) class B(x,y) { - fun toString() { + override fun toString() { "B(%d,%d)"(x,y) } } @@ -4394,7 +4394,7 @@ class ScriptTest { assertEquals("B(1,2)", B(1,2).toString()) assertEquals("A(x=1,y=2)", A(1,2).toString()) - // now tricky part: this _should_ cakk custom toString() + // now tricky part: this _should_ call custom toString() assertEquals(":B(1,2)", ":" + B(1,2).toString()) // and this must be exactly same: assertEquals(":B(1,2)", ":" + B(1,2)) diff --git a/lynglib/stdlib/lyng/root.lyng b/lynglib/stdlib/lyng/root.lyng index 2d587d8..af619c2 100644 --- a/lynglib/stdlib/lyng/root.lyng +++ b/lynglib/stdlib/lyng/root.lyng @@ -235,7 +235,7 @@ fun Iterable.flatMap(transform): List { } /* Return string representation like [a,b,c]. */ -fun List.toString() { +override fun List.toString() { "[" + joinToString(",") + "]" } @@ -257,7 +257,7 @@ class StackTraceEntry( val sourceString: String ) { /* Formatted representation: source:line:column: text. */ - fun toString() { + override fun toString() { "%s:%d:%d: %s"(sourceName, line, column, sourceString.trim()) } }