operators overriding

This commit is contained in:
sergeych committed 2026-01-07 09:33:10 +01:00
1 parent fe5dded7af
commit 2c0a6c7b34
24 files changed
+216 -57

No files matched your search

@@ -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")
@@ -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<ObjInt>(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()
@@ -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()
@@ -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)
@@ -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()}
@@ -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
@@ -25,7 +25,7 @@ import net.sergeych.lyng.miniast.type
class ObjCompletableDeferred(val completableDeferred: CompletableDeferred<Obj>): ObjDeferred(completableDeferred) {
override val objClass = type
override val objClass get() = type
companion object {
val type = object: ObjClass("CompletableDeferred", ObjDeferred.type){
@@ -24,7 +24,7 @@ import net.sergeych.lyng.miniast.type
open class ObjDeferred(val deferred: Deferred<Obj>): Obj() {
override val objClass = type
override val objClass get() = type
companion object {
val type = object: ObjClass("Deferred"){
@@ -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()
@@ -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
@@ -35,7 +35,7 @@ import kotlin.coroutines.cancellation.CancellationException
class ObjFlowBuilder(val output: SendChannel<Obj>) : 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<Obj>? = null
@@ -42,9 +42,6 @@ class ObjInstanceClass(val name: String, vararg parents: ObjClass) : ObjClass(na
}
init {
addFn("toString", true) {
thisObj.toString(this, true)
}
}
}
@@ -29,7 +29,7 @@ import net.sergeych.lyng.Scope
*/
class ObjKotlinIterator(val iterator: Iterator<Any?>) : 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<Any?>) : Obj() {
*/
class ObjKotlinObjIterator(val iterator: Iterator<Obj>) : Obj() {
override val objClass = type
override val objClass get() = type
companion object {
val type = ObjClass("KotlinIterator", ObjIterator).apply {
@@ -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<Obj, Obj> = mutableMapOf()) : Obj() {
override val objClass = type
override val objClass get() = type
override suspend fun getAt(scope: Scope, index: Obj): Obj =
map.get(index) ?: ObjNull
@@ -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") {
@@ -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()
@@ -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
@@ -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
@@ -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<ObjString>(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,
@@ -81,7 +81,7 @@ class RingBuffer<T>(val maxSize: Int) : Iterable<T> {
class ObjRingBuffer(val capacity: Int) : Obj() {
val buffer = RingBuffer<Obj>(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())
@@ -28,7 +28,7 @@ import net.sergeych.lynon.LynonType
class ObjSet(val set: MutableSet<Obj> = mutableSetOf()) : Obj() {
override val objClass = type
override val objClass get() = type
override suspend fun contains(scope: Scope, other: Obj): Boolean {
return set.contains(other)
+2 -2
View File
@@ -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))
+2 -2
View File
@@ -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())
}
}