fix #26 lists redesigned for ranges, less chaotic and serpentic

This commit is contained in:
sergeych committed 2025-06-14 14:51:41 +04:00
1 parent 19eae213ec
commit 8a4363bd84
7 files changed
+236 -72

No files matched your search

@@ -365,7 +365,7 @@ class Compiler(
} ?: parseLambdaExpression(cc)
}
Token.Type.RBRACKET -> {
Token.Type.RBRACKET, Token.Type.RPAREN -> {
cc.previous()
return operand
}
@@ -161,13 +161,26 @@ val ObjArray by lazy {
addFn("contains", isOpen = true) {
val obj = args.firstAndOnly()
for( i in 0..< thisObj.invokeInstanceMethod(this, "size").toInt()) {
if( thisObj.getAt(this, ObjInt(i.toLong())).compareTo(this, obj) == 0 ) return@addFn ObjTrue
for (i in 0..<thisObj.invokeInstanceMethod(this, "size").toInt()) {
if (thisObj.getAt(this, ObjInt(i.toLong())).compareTo(this, obj) == 0) return@addFn ObjTrue
}
ObjFalse
}
addFn("isample") { "ok".toObj() }
addFn("last") {
thisObj.invokeInstanceMethod(
this,
"getAt",
(thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj()
)
}
addFn("lastIndex") { (thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj() }
addFn("indices") {
ObjRange(0.toObj(), thisObj.invokeInstanceMethod(this, "size"), false)
}
}
}
@@ -11,20 +11,48 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
list.joinToString(separator = ", ") { it.inspect() }
}]"
fun normalize(context: Context, index: Int, allowsEndInclusive: Boolean = false): Int {
val i = if (index < 0) list.size + index else index
if (allowsEndInclusive && i == list.size) return i
if (i !in list.indices) context.raiseError("index $index out of bounds for size ${list.size}")
return i
}
override suspend fun getAt(context: Context, index: Obj): Obj {
val i = normalize(context, index.toInt())
return list[i]
return when (index) {
is ObjInt -> {
list[index.toInt()]
}
is ObjRange -> {
when {
index.start is ObjInt && index.end is ObjInt -> {
if (index.isEndInclusive)
ObjList(list.subList(index.start.toInt(), index.end.toInt() + 1).toMutableList())
else
ObjList(list.subList(index.start.toInt(), index.end.toInt()).toMutableList())
}
index.isOpenStart && !index.isOpenEnd -> {
if (index.isEndInclusive)
ObjList(list.subList(0, index.end!!.toInt() + 1).toMutableList())
else
ObjList(list.subList(0, index.end!!.toInt()).toMutableList())
}
index.isOpenEnd && !index.isOpenStart -> {
ObjList(list.subList(index.start!!.toInt(), list.size).toMutableList())
}
index.isOpenStart && index.isOpenEnd -> {
ObjList(list.toMutableList())
}
else -> {
throw RuntimeException("Can't apply range for index: $index")
}
}
}
else -> context.raiseArgumentError("Illegal index object for a list: ${index.inspect()}")
}
}
override suspend fun putAt(context: Context, index: Int, newValue: Obj) {
val i = normalize(context, index)
val i = index
list[i] = newValue
}
@@ -111,33 +139,74 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
ObjVoid
}
)
createField("addAt",
statement {
if (args.size < 2) raiseError("addAt takes 2+ arguments")
val l = thisAs<ObjList>()
var index = l.normalize(
this, requiredArg<ObjInt>(0).value.toInt(),
allowsEndInclusive = true
)
for (i in 1..<args.size) l.list.add(index++, args[i])
ObjVoid
}
)
addFn("insertAt") {
if (args.size < 2) raiseError("addAt takes 2+ arguments")
val l = thisAs<ObjList>()
var index = requiredArg<ObjInt>(0).value.toInt()
for (i in 1..<args.size) l.list.add(index++, args[i])
ObjVoid
}
addFn("removeAt") {
val self = thisAs<ObjList>()
val start = self.normalize(this, requiredArg<ObjInt>(0).value.toInt())
val start = requiredArg<ObjInt>(0).value.toInt()
if (args.size == 2) {
val end = requireOnlyArg<ObjInt>().value.toInt()
self.list.subList(start, self.normalize(this, end)).clear()
self.list.subList(start, end).clear()
} else
self.list.removeAt(start)
self
}
addFn("removeRangeInclusive") {
addFn("removeLast") {
val self = thisAs<ObjList>()
val start = self.normalize(this, requiredArg<ObjInt>(0).value.toInt())
val end = self.normalize(this, requiredArg<ObjInt>(1).value.toInt()) + 1
self.list.subList(start, end).clear()
if (args.isNotEmpty()) {
val count = requireOnlyArg<ObjInt>().value.toInt()
val size = self.list.size
if (count >= size) self.list.clear()
else self.list.subList(size - count, size).clear()
} else self.list.removeLast()
self
}
addFn("removeRange") {
val self = thisAs<ObjList>()
val list = self.list
val range = requiredArg<Obj>(0)
if (range is ObjRange) {
val index = range
when {
index.start is ObjInt && index.end is ObjInt -> {
if (index.isEndInclusive)
list.subList(index.start.toInt(), index.end.toInt() + 1)
else
list.subList(index.start.toInt(), index.end.toInt())
}
index.isOpenStart && !index.isOpenEnd -> {
if (index.isEndInclusive)
list.subList(0, index.end!!.toInt() + 1)
else
list.subList(0, index.end!!.toInt())
}
index.isOpenEnd && !index.isOpenStart -> {
list.subList(index.start!!.toInt(), list.size)
}
index.isOpenStart && index.isOpenEnd -> {
list
}
else -> {
throw RuntimeException("Can't apply range for index: $index")
}
}.clear()
} else {
val start = range.toInt()
val end = requiredArg<ObjInt>(1).value.toInt() + 1
self.list.subList(start, end).clear()
}
self
}
}
@@ -2,6 +2,9 @@ package net.sergeych.lyng
class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Obj() {
val isOpenStart by lazy { start == null || start.isNull }
val isOpenEnd by lazy { end == null || end.isNull }
override val objClass: ObjClass = type
override fun toString(): String {
+31 -10
View File
@@ -1137,7 +1137,8 @@ class ScriptTest {
@Test
fun testOpenStartRanges() = runTest {
eval("""
eval(
"""
var r = ..5
assert( r::class == Range)
assert( r.start == null)
@@ -1155,17 +1156,20 @@ class ScriptTest {
assert( (-2..3) in r)
assert( (-2..12) !in r)
""".trimIndent())
""".trimIndent()
)
}
@Test
fun testOpenEndRanges() = runTest {
eval("""
eval(
"""
var r = 5..
assert( r::class == Range)
assert( r.end == null)
assert( r.start == 5)
""".trimIndent())
""".trimIndent()
)
}
@Test
@@ -1226,7 +1230,7 @@ class ScriptTest {
val list = (1..1024).toList()
assert(list.size == 1024)
assert(list[0] == 1)
assert(list[-1] == 1024)
assert(list.last == 1024)
}
""".trimIndent()
)
@@ -2149,7 +2153,8 @@ class ScriptTest {
@Test
fun testNull1() = runTest {
eval("""
eval(
"""
var s = null
assertThrows { s.length }
assertThrows { s.size() }
@@ -2164,25 +2169,41 @@ class ScriptTest {
s = "xx"
assert(s.lower().size == 2)
assert(s.length == 2)
""".trimIndent())
""".trimIndent()
)
}
@Test
fun testSprintf() = runTest {
eval("""
eval(
"""
assertEquals( "123.45", "%3.2f"(123.451678) )
assertEquals( "123.45: hello", "%3.2f: %s"(123.451678, "hello") )
assertEquals( "123.45: true", "%3.2f: %s"(123.451678, true) )
""".trimIndent())
""".trimIndent()
)
}
@Test
fun testSubstringRangeFailure() = runTest {
eval("""
eval(
"""
assertEquals("pult", "catapult"[4..])
assertEquals("cat", "catapult"[..2])
""".trimIndent()
)
}
@Test
fun passingOpenEndedRangeAsParam() = runTest {
eval(
"""
fun test(r) {
assert( r is Range )
}
test( 1.. )
""".trimIndent()
)
}
}