fix #58 improper toString overload processing in Lyng
fix #57 Exception#getStackTrace() ref #56 StackTraceEntry is serializable now
This commit is contained in:
1 parent
8d1cafae80
commit
4b613fda7c
30 files changed
+250
-119
No files matched your search
@@ -63,7 +63,7 @@ data class Arguments(val list: List<Obj>, val tailBlockMode: Boolean = false) :
|
||||
return list.map { it.toKotlin(scope) }
|
||||
}
|
||||
|
||||
fun inspect(): String = list.joinToString(", ") { it.inspect() }
|
||||
suspend fun inspect(scope: Scope): String = list.map{ it.inspect(scope)}.joinToString(",")
|
||||
|
||||
companion object {
|
||||
val EMPTY = Arguments(emptyList())
|
||||
|
||||
@@ -1363,8 +1363,8 @@ class Compiler(
|
||||
}
|
||||
|
||||
|
||||
return statement(body.pos) { ctx ->
|
||||
val forContext = ctx.copy(start)
|
||||
return statement(body.pos) { cxt ->
|
||||
val forContext = cxt.copy(start)
|
||||
|
||||
// loop var: StoredObject
|
||||
val loopSO = forContext.addItem(tVar.value, true, ObjNull)
|
||||
@@ -1393,7 +1393,7 @@ class Compiler(
|
||||
.getOrElse {
|
||||
throw ScriptError(
|
||||
tOp.pos,
|
||||
"object is not enumerable: no index access for ${sourceObj.inspect()}",
|
||||
"object is not enumerable: no index access for ${sourceObj.inspect(cxt)}",
|
||||
it
|
||||
)
|
||||
}
|
||||
@@ -1420,7 +1420,7 @@ class Compiler(
|
||||
}
|
||||
}
|
||||
if (!breakCaught && elseStatement != null) {
|
||||
result = elseStatement.execute(ctx)
|
||||
result = elseStatement.execute(cxt)
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@@ -57,15 +57,15 @@ class Script(
|
||||
ObjException.addExceptionsToContext(this)
|
||||
addFn("print") {
|
||||
for ((i, a) in args.withIndex()) {
|
||||
if (i > 0) print(' ' + a.asStr.value)
|
||||
else print(a.asStr.value)
|
||||
if (i > 0) print(' ' + a.toString(this).value)
|
||||
else print(a.toString(this).value)
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
addFn("println") {
|
||||
for ((i, a) in args.withIndex()) {
|
||||
if (i > 0) print(' ' + a.asStr.value)
|
||||
else print(a.asStr.value)
|
||||
if (i > 0) print(' ' + a.toString(this).value)
|
||||
else print(a.toString(this).value)
|
||||
}
|
||||
println()
|
||||
ObjVoid
|
||||
@@ -165,13 +165,13 @@ class Script(
|
||||
val a = requiredArg<Obj>(0)
|
||||
val b = requiredArg<Obj>(1)
|
||||
if( a.compareTo(this, b) != 0 )
|
||||
raiseError(ObjAssertionFailedException(this,"Assertion failed: ${a.inspect()} == ${b.inspect()}"))
|
||||
raiseError(ObjAssertionFailedException(this,"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"))
|
||||
}
|
||||
addVoidFn("assertNotEquals") {
|
||||
val a = requiredArg<Obj>(0)
|
||||
val b = requiredArg<Obj>(1)
|
||||
if( a.compareTo(this, b) == 0 )
|
||||
raiseError(ObjAssertionFailedException(this,"Assertion failed: ${a.inspect()} != ${b.inspect()}"))
|
||||
raiseError(ObjAssertionFailedException(this,"Assertion failed: ${a.inspect(this)} != ${b.inspect(this)}"))
|
||||
}
|
||||
addFn("assertThrows") {
|
||||
val code = requireOnlyArg<Statement>()
|
||||
@@ -287,7 +287,7 @@ class Script(
|
||||
is ObjInt -> delay(a.value * 1000)
|
||||
is ObjReal -> delay((a.value * 1000).roundToLong())
|
||||
is ObjDuration -> delay(a.duration)
|
||||
else -> raiseIllegalArgument("Expected Duration, Int or Real, got ${a.inspect()}")
|
||||
else -> raiseIllegalArgument("Expected Duration, Int or Real, got ${a.inspect(this)}")
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
|
||||
@@ -17,10 +17,14 @@
|
||||
|
||||
package net.sergeych.lyng
|
||||
|
||||
import net.sergeych.lyng.obj.ObjString
|
||||
|
||||
class Source(val fileName: String, text: String) {
|
||||
|
||||
val lines = text.lines().map { it.trimEnd() }
|
||||
|
||||
val objSourceName by lazy { ObjString(fileName) }
|
||||
|
||||
companion object {
|
||||
val builtIn: Source by lazy { Source("built-in", "") }
|
||||
val UNKNOWN: Source by lazy { Source("UNKNOWN", "") }
|
||||
|
||||
@@ -26,6 +26,7 @@ import net.sergeych.lyng.*
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonType
|
||||
import net.sergeych.mptools.CachedExpression
|
||||
import net.sergeych.synctools.ProtectedOp
|
||||
import net.sergeych.synctools.withLock
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
@@ -49,7 +50,7 @@ open class Obj {
|
||||
|
||||
private val opInstances = ProtectedOp()
|
||||
|
||||
open fun inspect(): String = toString()
|
||||
open suspend fun inspect(scope: Scope): String = toString(scope).value
|
||||
|
||||
/**
|
||||
* Some objects are by-value, historically [ObjInt] and [ObjReal] are usually treated as such.
|
||||
@@ -84,14 +85,14 @@ open class Obj {
|
||||
scope: Scope,
|
||||
name: String,
|
||||
args: Arguments = Arguments.EMPTY,
|
||||
onNotFoundResult: Obj?=null
|
||||
onNotFoundResult: (()->Obj?)? = null
|
||||
): Obj {
|
||||
return objClass.getInstanceMemberOrNull(name)?.value?.invoke(
|
||||
scope,
|
||||
this,
|
||||
args
|
||||
)
|
||||
?: onNotFoundResult
|
||||
?: onNotFoundResult?.invoke()
|
||||
?: scope.raiseSymbolNotFound(name)
|
||||
}
|
||||
|
||||
@@ -115,8 +116,11 @@ open class Obj {
|
||||
return invokeInstanceMethod(scope, "contains", other).toBool()
|
||||
}
|
||||
|
||||
open val asStr: ObjString by lazy {
|
||||
if (this is ObjString) this else ObjString(this.toString())
|
||||
suspend open fun toString(scope: Scope): ObjString {
|
||||
return if (this is ObjString) this
|
||||
else invokeInstanceMethod(scope, "toString") {
|
||||
ObjString(this.toString())
|
||||
} as ObjString
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,9 +280,9 @@ open class Obj {
|
||||
scope.raiseNotImplemented()
|
||||
}
|
||||
|
||||
fun autoInstanceScope(parent: Scope): Scope {
|
||||
val scope = parent.copy(newThisObj = this, args = parent.args)
|
||||
for( m in objClass.members) {
|
||||
fun autoInstanceScope(parent: Scope): Scope {
|
||||
val scope = parent.copy(newThisObj = this, args = parent.args)
|
||||
for (m in objClass.members) {
|
||||
scope.objects[m.key] = m.value
|
||||
}
|
||||
return scope
|
||||
@@ -287,11 +291,11 @@ open class Obj {
|
||||
companion object {
|
||||
|
||||
val rootObjectType = ObjClass("Obj").apply {
|
||||
addFn("toString") {
|
||||
thisObj.asStr
|
||||
addFn("toString", true) {
|
||||
ObjString(thisObj.toString())
|
||||
}
|
||||
addFn("inspect", true) {
|
||||
thisObj.inspect().toObj()
|
||||
thisObj.inspect(this).toObj()
|
||||
}
|
||||
addFn("contains") {
|
||||
ObjBool(thisObj.contains(this, args.firstAndOnly()))
|
||||
@@ -392,9 +396,14 @@ object ObjNull : Obj() {
|
||||
scope.raiseNPE()
|
||||
}
|
||||
|
||||
override suspend fun invokeInstanceMethod(scope: Scope, name: String, args: Arguments, onNotFoundResult: Obj?): Obj {
|
||||
scope.raiseNPE()
|
||||
}
|
||||
// override suspend fun invokeInstanceMethod(
|
||||
// scope: Scope,
|
||||
// name: String,
|
||||
// args: Arguments,
|
||||
// onNotFoundResult: (()->Obj?)?
|
||||
// ): Obj {
|
||||
// scope.raiseNPE()
|
||||
// }
|
||||
|
||||
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
||||
scope.raiseNPE()
|
||||
@@ -469,20 +478,51 @@ fun Obj.toBool(): Boolean =
|
||||
data class ObjNamespace(val name: String) : Obj() {
|
||||
override val objClass by lazy { ObjClass(name) }
|
||||
|
||||
override fun inspect(): String = "Ns[$name]"
|
||||
override suspend fun inspect(scope: Scope): String = "Ns[$name]"
|
||||
|
||||
override fun toString(): String {
|
||||
return "package $name"
|
||||
}
|
||||
}
|
||||
|
||||
open class ObjException(exceptionClass: ExceptionClass, val scope: Scope, val message: String) : Obj() {
|
||||
open class ObjException(
|
||||
val exceptionClass: ExceptionClass,
|
||||
val scope: Scope,
|
||||
val message: String,
|
||||
@Suppress("unused") val extraData: Obj = ObjNull
|
||||
) : Obj() {
|
||||
constructor(name: String, scope: Scope, message: String) : this(
|
||||
getOrCreateExceptionClass(name),
|
||||
scope,
|
||||
message
|
||||
)
|
||||
|
||||
private val cachedStackTrace = CachedExpression<ObjList>()
|
||||
|
||||
suspend fun getStackTrace(): ObjList {
|
||||
return cachedStackTrace.get {
|
||||
val result = ObjList()
|
||||
val cls = scope.get("StackTraceEntry")!!.value as ObjClass
|
||||
var s: Scope? = scope
|
||||
var lastPos: Pos? = null
|
||||
while( s != null ) {
|
||||
val pos = s.pos
|
||||
if( pos != lastPos && !pos.currentLine.isEmpty() ) {
|
||||
result.list += cls.callWithArgs(
|
||||
scope,
|
||||
pos.source.objSourceName,
|
||||
ObjInt(pos.line.toLong()),
|
||||
ObjInt(pos.column.toLong()),
|
||||
ObjString(pos.currentLine)
|
||||
)
|
||||
}
|
||||
s = s.parent
|
||||
lastPos = pos
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
constructor(scope: Scope, message: String) : this(Root, scope, message)
|
||||
|
||||
fun raise(): Nothing {
|
||||
@@ -495,6 +535,12 @@ open class ObjException(exceptionClass: ExceptionClass, val scope: Scope, val me
|
||||
return "ObjException:${objClass.className}:${scope.pos}@${hashCode().encodeToHex()}"
|
||||
}
|
||||
|
||||
override suspend fun serialize(scope: Scope, encoder: LynonEncoder, lynonType: LynonType?) {
|
||||
encoder.encodeAny(scope, ObjString(exceptionClass.name))
|
||||
encoder.encodeAny(scope, ObjString(message))
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
class ExceptionClass(val name: String, vararg parents: ObjClass) : ObjClass(name, *parents) {
|
||||
@@ -510,6 +556,9 @@ open class ObjException(exceptionClass: ExceptionClass, val scope: Scope, val me
|
||||
addConst("message", statement {
|
||||
(thisObj as ObjException).message.toObj()
|
||||
})
|
||||
addFn("getStackTrace") {
|
||||
(thisObj as ObjException).getStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private val op = ProtectedOp()
|
||||
|
||||
@@ -50,6 +50,5 @@ val ObjArray by lazy {
|
||||
addFn("indices") {
|
||||
ObjRange(0.toObj(), thisObj.invokeInstanceMethod(this, "size"), false)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonType
|
||||
|
||||
data class ObjBool(val value: Boolean) : Obj() {
|
||||
override val asStr by lazy { ObjString(value.toString()) }
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if (other !is ObjBool) return -2
|
||||
|
||||
@@ -87,7 +87,7 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
byteArray + other.toFlow(scope).map { it.toLong().toUByte() }.toList().toTypedArray()
|
||||
.toUByteArray()
|
||||
)
|
||||
} else scope.raiseIllegalArgument("can't concatenate buffer with ${other.inspect()}")
|
||||
} else scope.raiseIllegalArgument("can't concatenate buffer with ${other.inspect(scope)}")
|
||||
}
|
||||
|
||||
override fun toString(): String = base64
|
||||
@@ -107,7 +107,7 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
encoder.encodeCachedBytes(byteArray.asByteArray())
|
||||
}
|
||||
|
||||
override fun inspect(): String = "Buf($base64)"
|
||||
override suspend fun inspect(scope: Scope): String = "Buf($base64)"
|
||||
|
||||
companion object {
|
||||
private suspend fun createBufferFrom(scope: Scope, obj: Obj): ObjBuffer =
|
||||
@@ -129,7 +129,7 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
)
|
||||
} else
|
||||
scope.raiseIllegalArgument(
|
||||
"can't construct buffer from ${obj.inspect()}"
|
||||
"can't construct buffer from ${obj.inspect(scope)}"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
is ObjChar -> b.value.code.toUByte()
|
||||
is ObjInt -> b.value.toUByte()
|
||||
else -> scope.raiseIllegalArgument(
|
||||
"invalid byte value for buffer constructor at index $i: ${b.inspect()}"
|
||||
"invalid byte value for buffer constructor at index $i: ${b.inspect(scope)}"
|
||||
)
|
||||
}
|
||||
data[i] = code
|
||||
|
||||
@@ -28,7 +28,7 @@ class ObjChar(val value: Char): Obj() {
|
||||
|
||||
override fun toString(): String = value.toString()
|
||||
|
||||
override fun inspect(): String = "'$value'"
|
||||
override suspend fun inspect(scope: Scope): String = "'$value'"
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return value.hashCode()
|
||||
|
||||
@@ -61,13 +61,17 @@ open class ObjClass(
|
||||
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
val instance = ObjInstance(this)
|
||||
instance.instanceScope = scope.copy(newThisObj = instance,args = scope.args)
|
||||
instance.instanceScope = scope.copy(newThisObj = instance, args = scope.args)
|
||||
if (instanceConstructor != null) {
|
||||
instanceConstructor!!.execute(instance.instanceScope)
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
suspend fun callWithArgs(scope: Scope, vararg plainArgs: Obj): Obj {
|
||||
return callOn(scope.copy(Arguments(*plainArgs)))
|
||||
}
|
||||
|
||||
|
||||
fun createField(
|
||||
name: String,
|
||||
@@ -77,13 +81,13 @@ open class ObjClass(
|
||||
pos: Pos = Pos.builtIn
|
||||
) {
|
||||
val existing = members[name] ?: allParentsSet.firstNotNullOfOrNull { it.members[name] }
|
||||
if( existing?.isMutable == false)
|
||||
if (existing?.isMutable == false)
|
||||
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
||||
members[name] = ObjRecord(initialValue, isMutable, visibility)
|
||||
}
|
||||
|
||||
private fun initClassScope(): Scope {
|
||||
if( classScope == null ) classScope = Scope()
|
||||
if (classScope == null) classScope = Scope()
|
||||
return classScope!!
|
||||
}
|
||||
|
||||
@@ -96,7 +100,7 @@ open class ObjClass(
|
||||
) {
|
||||
initClassScope()
|
||||
val existing = classScope!!.objects[name]
|
||||
if( existing != null)
|
||||
if (existing != null)
|
||||
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
||||
classScope!!.addItem(name, isMutable, initialValue, visibility)
|
||||
}
|
||||
@@ -127,26 +131,29 @@ open class ObjClass(
|
||||
|
||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||
classScope?.objects?.get(name)?.let {
|
||||
if( it.visibility.isPublic ) return it
|
||||
if (it.visibility.isPublic) return it
|
||||
}
|
||||
return super.readField(scope, name)
|
||||
}
|
||||
|
||||
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
|
||||
initClassScope().objects[name]?.let {
|
||||
if( it.isMutable) it.value = newValue
|
||||
if (it.isMutable) it.value = newValue
|
||||
else scope.raiseIllegalAssignment("can't assign $name is not mutable")
|
||||
}
|
||||
?: super.writeField(scope, name, newValue)
|
||||
}
|
||||
|
||||
override suspend fun invokeInstanceMethod(scope: Scope, name: String, args: Arguments,
|
||||
onNotFoundResult: Obj?): Obj {
|
||||
override suspend fun invokeInstanceMethod(
|
||||
scope: Scope, name: String, args: Arguments,
|
||||
onNotFoundResult: (() -> Obj?)?
|
||||
): Obj {
|
||||
return classScope?.objects?.get(name)?.value?.invoke(scope, this, args)
|
||||
?: super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||
}
|
||||
|
||||
open suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj = scope.raiseNotImplemented()
|
||||
open suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj =
|
||||
scope.raiseNotImplemented()
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,4 +22,4 @@ package net.sergeych.lyng.obj
|
||||
*/
|
||||
val ObjCollection = ObjClass("Collection", ObjIterable).apply {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
val args = scope.args
|
||||
if( args.list.size > 1 )
|
||||
scope.raiseIllegalArgument("can't construct Duration(${args.inspect()})")
|
||||
scope.raiseIllegalArgument("can't construct Duration(${args.inspect(scope)})")
|
||||
val a0 = args.list.getOrNull(0)
|
||||
|
||||
return ObjDuration(
|
||||
@@ -66,7 +66,7 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
is ObjInt -> a0.value.seconds
|
||||
is ObjReal -> a0.value.seconds
|
||||
else -> {
|
||||
scope.raiseIllegalArgument("can't construct Instant(${args.inspect()})")
|
||||
scope.raiseIllegalArgument("can't construct Instant(${args.inspect(scope)})")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -48,7 +48,7 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
}
|
||||
|
||||
override suspend fun invokeInstanceMethod(scope: Scope, name: String, args: Arguments,
|
||||
onNotFoundResult: Obj?): Obj =
|
||||
onNotFoundResult: (()->Obj?)?): Obj =
|
||||
instanceScope[name]?.let {
|
||||
if (it.visibility.isPublic)
|
||||
it.value.invoke(
|
||||
|
||||
@@ -30,12 +30,19 @@ class ObjInstanceClass(val name: String) : ObjClass(name) {
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||
val args = decoder.decodeAnyList(scope)
|
||||
val actualSize = constructorMeta?.params?.size ?: 0
|
||||
if( args.size > actualSize )
|
||||
if (args.size > actualSize)
|
||||
scope.raiseIllegalArgument("constructor $name has only $actualSize but serialized version has ${args.size}")
|
||||
val newScope = scope.copy(args = Arguments(args))
|
||||
return (callOn(newScope) as ObjInstance).apply {
|
||||
deserializeStateVars(scope,decoder)
|
||||
invokeInstanceMethod(scope, "onDeserialized", onNotFoundResult = ObjVoid)
|
||||
deserializeStateVars(scope, decoder)
|
||||
invokeInstanceMethod(scope, "onDeserialized") { ObjVoid }
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
addFn("toString", true) {
|
||||
println("-------------- tos! --------------")
|
||||
ObjString(thisObj.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
||||
is ObjInstant -> a0.instant
|
||||
|
||||
else -> {
|
||||
scope.raiseIllegalArgument("can't construct Instant(${args.inspect()})")
|
||||
scope.raiseIllegalArgument("can't construct Instant(${args.inspect(scope)})")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -23,7 +23,6 @@ import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonType
|
||||
|
||||
class ObjInt(var value: Long, override val isConst: Boolean = false) : Obj(), Numeric {
|
||||
override val asStr get() = ObjString(value.toString())
|
||||
override val longValue get() = value
|
||||
override val doubleValue get() = value.toDouble()
|
||||
override val toObjInt get() = this
|
||||
|
||||
@@ -82,18 +82,18 @@ fun Obj.toFlow(scope: Scope): Flow<Obj> = flow {
|
||||
*
|
||||
* IF callback returns false, iteration is stopped.
|
||||
*/
|
||||
suspend fun Obj.enumerate(scope: Scope,callback: suspend (Obj)->Boolean) {
|
||||
suspend fun Obj.enumerate(scope: Scope, callback: suspend (Obj) -> Boolean) {
|
||||
val iterator = invokeInstanceMethod(scope, "iterator")
|
||||
val hasNext = iterator.getInstanceMethod(scope, "hasNext")
|
||||
val next = iterator.getInstanceMethod(scope, "next")
|
||||
var closeIt = false
|
||||
while (hasNext.invoke(scope, iterator).toBool()) {
|
||||
val nextValue = next.invoke(scope, iterator)
|
||||
if( !callback(nextValue) ) {
|
||||
if (!callback(nextValue)) {
|
||||
closeIt = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if( closeIt )
|
||||
iterator.invokeInstanceMethod(scope, "cancelIteration", onNotFoundResult = ObjVoid)
|
||||
if (closeIt)
|
||||
iterator.invokeInstanceMethod(scope, "cancelIteration") { ObjVoid }
|
||||
}
|
||||
@@ -25,10 +25,6 @@ import net.sergeych.lynon.LynonType
|
||||
|
||||
class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
|
||||
override fun toString(): String = "[${
|
||||
list.joinToString(separator = ", ") { it.inspect() }
|
||||
}]"
|
||||
|
||||
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
||||
return when (index) {
|
||||
is ObjInt -> {
|
||||
@@ -65,7 +61,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
}
|
||||
}
|
||||
|
||||
else -> scope.raiseIllegalArgument("Illegal index object for a list: ${index.inspect()}")
|
||||
else -> scope.raiseIllegalArgument("Illegal index object for a list: ${index.inspect(scope)}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class ObjMutableBuffer(byteArray: UByteArray) : ObjBuffer(byteArray) {
|
||||
is ObjInt -> newValue.value.toUByte()
|
||||
is ObjChar -> newValue.value.code.toUByte()
|
||||
else -> scope.raiseIllegalArgument(
|
||||
"invalid byte value for buffer at index ${index.inspect()}: ${newValue.inspect()}"
|
||||
"invalid byte value for buffer at index ${index.inspect(scope)}: ${newValue.inspect(scope)}"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ class ObjMutableBuffer(byteArray: UByteArray) : ObjBuffer(byteArray) {
|
||||
)
|
||||
} else
|
||||
scope.raiseIllegalArgument(
|
||||
"can't construct buffer from ${obj.inspect()}"
|
||||
"can't construct buffer from ${obj.inspect(scope)}"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ class ObjMutableBuffer(byteArray: UByteArray) : ObjBuffer(byteArray) {
|
||||
is ObjChar -> b.value.code.toUByte()
|
||||
is ObjInt -> b.value.toUByte()
|
||||
else -> scope.raiseIllegalArgument(
|
||||
"invalid byte value for buffer constructor at index $i: ${b.inspect()}"
|
||||
"invalid byte value for buffer constructor at index $i: ${b.inspect(scope)}"
|
||||
)
|
||||
}
|
||||
data[i] = code
|
||||
|
||||
@@ -26,12 +26,12 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
|
||||
|
||||
override val objClass: ObjClass = type
|
||||
|
||||
override fun toString(): String {
|
||||
override suspend fun toString(scope: Scope): ObjString {
|
||||
val result = StringBuilder()
|
||||
result.append("${start?.inspect() ?: '∞'} ..")
|
||||
result.append("${start?.inspect(scope) ?: '∞'} ..")
|
||||
if (!isEndInclusive) result.append('<')
|
||||
result.append(" ${end?.inspect() ?: '∞'}")
|
||||
return result.toString()
|
||||
result.append(" ${end?.inspect(scope) ?: '∞'}")
|
||||
return ObjString(result.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,11 +52,11 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
|
||||
* if start is not ObjInt, raises [ObjIllegalArgumentException]
|
||||
* otherwise returns start.value.toInt()
|
||||
*/
|
||||
fun startInt(scope: Scope): Int =
|
||||
suspend fun startInt(scope: Scope): Int =
|
||||
if( start == null || start is ObjNull) 0
|
||||
else {
|
||||
if( start is ObjInt) start.value.toInt()
|
||||
else scope.raiseIllegalArgument("start is not Int: ${start.inspect()}")
|
||||
else scope.raiseIllegalArgument("start is not Int: ${start.inspect(scope)}")
|
||||
}
|
||||
|
||||
suspend fun containsRange(scope: Scope, other: ObjRange): Boolean {
|
||||
|
||||
@@ -27,7 +27,6 @@ import kotlin.math.floor
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
override val asStr by lazy { ObjString(value.toString()) }
|
||||
override val longValue: Long by lazy { floor(value).toLong() }
|
||||
override val doubleValue: Double by lazy { value }
|
||||
override val toObjInt: ObjInt by lazy { ObjInt(longValue) }
|
||||
|
||||
@@ -44,9 +44,7 @@ data class ObjString(val value: String) : Obj() {
|
||||
|
||||
override fun toString(): String = value
|
||||
|
||||
override val asStr: ObjString by lazy { this }
|
||||
|
||||
override fun inspect(): String {
|
||||
override suspend fun inspect(scope: Scope): String {
|
||||
return "\"$value\""
|
||||
}
|
||||
|
||||
@@ -54,7 +52,7 @@ data class ObjString(val value: String) : Obj() {
|
||||
get() = type
|
||||
|
||||
override suspend fun plus(scope: Scope, other: Obj): Obj {
|
||||
return ObjString(value + other.asStr.value)
|
||||
return ObjString(value + other.toString(scope).value)
|
||||
}
|
||||
|
||||
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
||||
@@ -159,6 +157,9 @@ data class ObjString(val value: String) : Obj() {
|
||||
addFn("toReal") {
|
||||
ObjReal(thisAs<ObjString>().value.toDouble())
|
||||
}
|
||||
addFn("trim") {
|
||||
thisAs<ObjString>().value.trim().let(::ObjString)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,21 @@ fun Iterable.any(predicate): Bool {
|
||||
fun Iterable.all(predicate): Bool {
|
||||
!any { !predicate(it) }
|
||||
}
|
||||
|
||||
fun List.toString() {
|
||||
"[" + joinToString(",") + "]"
|
||||
}
|
||||
|
||||
class StackTraceEntry(
|
||||
val sourceName: String,
|
||||
val line: Int,
|
||||
val column: Int,
|
||||
val sourceString: String
|
||||
) {
|
||||
fun toString() {
|
||||
"%s:%d:%d: %s"(sourceName, line, column, sourceString.trim())
|
||||
}
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
|
||||
Reference in new issue
Block a user