operators overriding
This commit is contained in:
parent
fe5dded7af
commit
2c0a6c7b34
93
docs/OOP.md
93
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.
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user