+better comparison

+splat arguments in calls
This commit is contained in:
sergeych committed 2025-05-30 12:05:21 +04:00
1 parent b56b5c521d
commit 1479df4426
6 files changed
+83 -29

No files matched your search

@@ -1,15 +1,31 @@
package net.sergeych.ling
data class Arguments(val list: List<Info>): Iterable<Obj> {
data class ParsedArgument(val value: Statement, val pos: Pos, val isSplat: Boolean = false)
data class Info(val value: Obj,val pos: Pos)
suspend fun Collection<ParsedArgument>.toArguments(context: Context): Arguments {
val list = mutableListOf<Arguments.Info>()
for (x in this) {
val value = x.value.execute(context)
if (x.isSplat) {
(value as? ObjList) ?: context.raiseClassCastError("expected list of objects for splat argument")
for (subitem in value.list) list.add(Arguments.Info(subitem, x.pos))
} else
list.add(Arguments.Info(value, x.pos))
}
return Arguments(list)
}
data class Arguments(val list: List<Info>) : Iterable<Obj> {
data class Info(val value: Obj, val pos: Pos)
val size by list::size
operator fun get(index: Int): Obj = list[index].value
fun firstAndOnly(): Obj {
if( list.size != 1 ) throw IllegalArgumentException("Expected one argument, got ${list.size}")
if (list.size != 1) throw IllegalArgumentException("Expected one argument, got ${list.size}")
return list.first().value
}
@@ -20,4 +36,6 @@ data class Arguments(val list: List<Info>): Iterable<Obj> {
override fun iterator(): Iterator<Obj> {
return list.map { it.value }.iterator()
}
}
@@ -148,10 +148,7 @@ class Compiler(
v.callInstanceMethod(
context,
next.value,
Arguments(args.map {
val st = it.value as Statement
Arguments.Info(st.execute(context),it.pos) }
)
args.toArguments(context)
), isMutable = false
)
}
@@ -275,11 +272,11 @@ class Compiler(
} ?: run {
// no lvalue means pre-increment, expression to increment follows
val next = parseAccessor(cc) ?: throw ScriptError(t.pos, "Expecting expression")
operand = Accessor({ ctx ->
operand = Accessor { ctx ->
next.getter(ctx).also {
if (!it.isMutable) ctx.raiseError("Cannot increment immutable value")
}.value.incrementAndGet(ctx).asReadonly
})
}
}
}
@@ -351,15 +348,19 @@ class Compiler(
}
}
private fun parseArgs(cc: CompilerContext): List<Arguments.Info> {
val args = mutableListOf<Arguments.Info>()
private fun parseArgs(cc: CompilerContext): List<ParsedArgument> {
val args = mutableListOf<ParsedArgument>()
do {
val t = cc.next()
when (t.type) {
Token.Type.RPAREN, Token.Type.COMMA -> {}
Token.Type.ELLIPSIS -> {
parseStatement(cc)?.let { args += ParsedArgument(it, t.pos, isSplat = true) }
?: throw ScriptError(t.pos, "Expecting arguments list")
}
else -> {
cc.previous()
parseStatement(cc)?.let { args += Arguments.Info(it, t.pos) }
parseStatement(cc)?.let { args += ParsedArgument(it, t.pos) }
?: throw ScriptError(t.pos, "Expecting arguments list")
}
}
@@ -376,9 +377,10 @@ class Compiler(
val v = left.getter(context)
v.value.callOn(context.copy(
context.pos,
Arguments(
args.map { Arguments.Info((it.value as Statement).execute(context), it.pos) }
),
args.toArguments(context)
// Arguments(
// args.map { Arguments.Info((it.value as Statement).execute(context), it.pos) }
// ),
)
).asReadonly
}
@@ -55,11 +55,6 @@ sealed class Obj {
?: throw ScriptError(atPos, "symbol doesn't exist: $name")
suspend fun callInstanceMethod(context: Context, name: String, args: Arguments): Obj =
// instance _methods_ are our ObjClass instance:
// note that getInstanceMember traverses the hierarchy
// instance _methods_ are our ObjClass instance:
// note that getInstanceMember traverses the hierarchy
// instance _methods_ are our ObjClass instance:
// note that getInstanceMember traverses the hierarchy
objClass.getInstanceMember(context.pos, name).value.invoke(context, this, args)
@@ -154,7 +149,7 @@ sealed class Obj {
// could be property or class field:
val obj = objClass.getInstanceMemberOrNull(name)
val value = obj?.value
return when(value) {
return when (value) {
is Statement -> {
// readonly property, important: call it on this
value.execute(context.copy(context.pos, newThisObj = this)).asReadonly
@@ -253,7 +248,7 @@ object ObjNull : Obj() {
data class ObjString(val value: String) : Obj() {
override suspend fun compareTo(context: Context, other: Obj): Int {
if (other !is ObjString) context.raiseError("cannot compare string with $other")
if (other !is ObjString) return -2
return this.value.compareTo(other.value)
}
@@ -311,7 +306,7 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
override fun byValueCopy(): Obj = ObjReal(value)
override suspend fun compareTo(context: Context, other: Obj): Int {
if (other !is Numeric) context.raiseError("cannot compare $this with $other")
if (other !is Numeric) return -2
return value.compareTo(other.doubleValue)
}
@@ -372,7 +367,7 @@ data class ObjInt(var value: Long) : Obj(), Numeric {
}
override suspend fun compareTo(context: Context, other: Obj): Int {
if (other !is Numeric) context.raiseError("cannot compare $this with $other")
if (other !is Numeric) return -2
return value.compareTo(other.doubleValue)
}
@@ -412,7 +407,7 @@ data class ObjInt(var value: Long) : Obj(), Numeric {
* assignment
*/
override suspend fun assign(context: Context, other: Obj): Obj? {
return if( other is ObjInt) {
return if (other is ObjInt) {
value = other.value
this
} else null
@@ -427,7 +422,7 @@ data class ObjBool(val value: Boolean) : Obj() {
override val asStr by lazy { ObjString(value.toString()) }
override suspend fun compareTo(context: Context, other: Obj): Int {
if (other !is ObjBool) context.raiseError("cannot compare $this with $other")
if (other !is ObjBool) return -2
return value.compareTo(other.value)
}
@@ -6,8 +6,9 @@ class ObjList(val list: MutableList<Obj>) : Obj() {
list.joinToString(separator = ", ") { it.inspect() }
}]"
fun normalize(context: Context, index: Int): Int {
fun normalize(context: Context, index: Int,allowInclusiveEnd: Boolean = false): Int {
val i = if (index < 0) list.size + index else index
if( allowInclusiveEnd && i == list.size ) return i
if (i !in list.indices) context.raiseError("index $index out of bounds for size ${list.size}")
return i
}
@@ -23,7 +24,7 @@ class ObjList(val list: MutableList<Obj>) : Obj() {
}
override suspend fun compareTo(context: Context, other: Obj): Int {
if (other !is ObjList) context.raiseError("cannot compare $this with $other")
if (other !is ObjList) return -2
val mySize = list.size
val otherSize = other.list.size
val commonSize = minOf(mySize, otherSize)
@@ -72,7 +73,8 @@ class ObjList(val list: MutableList<Obj>) : Obj() {
statement {
if (args.size < 2) raiseError("addAt takes 2+ arguments")
val l = thisAs<ObjList>()
var index = l.normalize(this, requiredArg<ObjInt>(0).value.toInt())
var index = l.normalize(this, requiredArg<ObjInt>(0).value.toInt(),
allowInclusiveEnd = true)
for (i in 1..<args.size) l.list.add(index++, args[i])
ObjVoid
}