+list + / += Iterable

+CLI app started
This commit is contained in:
sergeych committed 2025-06-02 07:39:31 +04:00
1 parent 939e391a20
commit 6ef94fff65
14 files changed
+271 -82

No files matched your search

@@ -44,6 +44,12 @@ open class Obj {
suspend fun invokeInstanceMethod(context: Context, name: String, vararg args: Obj): Obj =
invokeInstanceMethod(context, name, Arguments(args.map { Arguments.Info(it, context.pos) }))
inline suspend fun <reified T : Obj> callMethod(
context: Context,
name: String,
args: Arguments = Arguments.EMPTY
): T = invokeInstanceMethod(context, name, args) as T
suspend fun invokeInstanceMethod(
context: Context,
name: String,
@@ -3,8 +3,8 @@ package net.sergeych.ling
class ObjList(val list: MutableList<Obj>) : Obj() {
init {
for( p in objClass.parents)
parentInstances.add( p.defaultInstance())
for (p in objClass.parents)
parentInstances.add(p.defaultInstance())
}
override fun toString(): String = "[${
@@ -46,21 +46,32 @@ class ObjList(val list: MutableList<Obj>) : Obj() {
}
}
override suspend fun plus(context: Context, other: Obj): Obj {
(other as? ObjList) ?: context.raiseError("'+': can't concatenate $this with $other")
return ObjList((list + other.list).toMutableList())
}
override suspend fun plus(context: Context, other: Obj): Obj =
when {
other is ObjList ->
ObjList((list + other.list).toMutableList())
other.isInstanceOf(ObjIterable) -> {
val l = other.callMethod<ObjList>(context, "toList")
ObjList((list + l.list).toMutableList())
}
else ->
context.raiseError("'+': can't concatenate $this with $other")
}
override suspend fun plusAssign(context: Context, other: Obj): Obj {
// optimization
if( other is ObjList) {
if (other is ObjList) {
list += other.list
return this
}
if( other.isInstanceOf(ObjIterable)) {
TODO("plusassign for iterable is not yet implemented")
}
list += other
if (other.isInstanceOf(ObjIterable)) {
val otherList = other.invokeInstanceMethod(context, "toList") as ObjList
list += otherList.list
} else
list += other
return this
}
@@ -56,24 +56,6 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
return true
}
override suspend fun getAt(context: Context, index: Int): Obj {
if (!isIntRange && !isCharRange) {
return when (index) {
0 -> start ?: ObjNull
1 -> end ?: ObjNull
else -> context.raiseIndexOutOfBounds("index out of range: $index for max of 2 for non-int ranges")
}
}
// int range, should be finite
val r0 = start?.toInt() ?: context.raiseArgumentError("start is not integer")
var r1 = end?.toInt() ?: context.raiseArgumentError("end is not integer")
if (isEndInclusive) r1++
val i = index + r0
if (i >= r1) context.raiseIndexOutOfBounds("index $index is not in range (${r1 - r0})")
return if (isIntRange) ObjInt(i.toLong()) else ObjChar(i.toChar())
}
val isIntRange: Boolean by lazy {
start is ObjInt && end is ObjInt
}
@@ -82,6 +64,13 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
start is ObjChar && end is ObjChar
}
override suspend fun compareTo(context: Context, other: Obj): Int {
return (other as? ObjRange)?.let {
if( start == other.start && end == other.end ) 0 else -1
}
?: -1
}
companion object {
val type = ObjClass("Range", ObjIterable).apply {
addFn("start") {
@@ -110,50 +99,3 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
}
}
class ObjRangeIterator(val self: ObjRange) : Obj() {
private var nextIndex = 0
private var lastIndex = 0
private var isCharRange: Boolean = false
override val objClass: ObjClass = type
fun Context.init() {
if (self.start == null || self.end == null)
raiseError("next is only available for finite ranges")
isCharRange = self.isCharRange
lastIndex = if (self.isIntRange || self.isCharRange) {
if (self.isEndInclusive)
self.end.toInt() - self.start.toInt() + 1
else
self.end.toInt() - self.start.toInt()
} else {
raiseError("not implemented iterator for range of $this")
}
}
fun hasNext(): Boolean = nextIndex < lastIndex
fun next(context: Context): Obj =
if (nextIndex < lastIndex) {
val x = if (self.isEndInclusive)
self.start!!.toLong() + nextIndex++
else
self.start!!.toLong() + nextIndex++
if( isCharRange ) ObjChar(x.toInt().toChar()) else ObjInt(x)
}
else {
context.raiseError(ObjIterationFinishedError(context))
}
companion object {
val type = ObjClass("RangeIterator", ObjIterable).apply {
addFn("hasNext") {
thisAs<ObjRangeIterator>().hasNext().toObj()
}
addFn("next") {
thisAs<ObjRangeIterator>().next(this)
}
}
}
}
@@ -0,0 +1,49 @@
package net.sergeych.ling
class ObjRangeIterator(val self: ObjRange) : Obj() {
private var nextIndex = 0
private var lastIndex = 0
private var isCharRange: Boolean = false
override val objClass: ObjClass = type
fun Context.init() {
if (self.start == null || self.end == null)
raiseError("next is only available for finite ranges")
isCharRange = self.isCharRange
lastIndex = if (self.isIntRange || self.isCharRange) {
if (self.isEndInclusive)
self.end.toInt() - self.start.toInt() + 1
else
self.end.toInt() - self.start.toInt()
} else {
raiseError("not implemented iterator for range of $this")
}
}
fun hasNext(): Boolean = nextIndex < lastIndex
fun next(context: Context): Obj =
if (nextIndex < lastIndex) {
val x = if (self.isEndInclusive)
self.start!!.toLong() + nextIndex++
else
self.start!!.toLong() + nextIndex++
if( isCharRange ) ObjChar(x.toInt().toChar()) else ObjInt(x)
}
else {
context.raiseError(ObjIterationFinishedError(context))
}
companion object {
val type = ObjClass("RangeIterator", ObjIterable).apply {
addFn("hasNext") {
thisAs<ObjRangeIterator>().hasNext().toObj()
}
addFn("next") {
thisAs<ObjRangeIterator>().next(this)
}
}
}
}