fix #58 improper toString overload processing in Lyng
fix #57 Exception#getStackTrace() ref #56 StackTraceEntry is serializable now
This commit is contained in:
parent
8d1cafae80
commit
4b613fda7c
@ -24,7 +24,7 @@ There is a shortcut for the last:
|
|||||||
|
|
||||||
val list = [10, 20, 30]
|
val list = [10, 20, 30]
|
||||||
[list.last, list.lastIndex]
|
[list.last, list.lastIndex]
|
||||||
>>> [30, 2]
|
>>> [30,2]
|
||||||
|
|
||||||
__Important__ negative indexes works wherever indexes are used, e.g. in insertion and removal methods too.
|
__Important__ negative indexes works wherever indexes are used, e.g. in insertion and removal methods too.
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ You can use Char as both ends of the closed range:
|
|||||||
Exclusive end char ranges are supported too:
|
Exclusive end char ranges are supported too:
|
||||||
|
|
||||||
('a'..<'c').toList
|
('a'..<'c').toList
|
||||||
>>> ['a', 'b']
|
>>> [a,b]
|
||||||
|
|
||||||
|
|
||||||
# Instance members
|
# Instance members
|
||||||
|
@ -71,7 +71,7 @@ destructuring arrays when calling functions and lambdas:
|
|||||||
[ first, last ]
|
[ first, last ]
|
||||||
}
|
}
|
||||||
getFirstAndLast( ...(1..10) ) // see "splats" section below
|
getFirstAndLast( ...(1..10) ) // see "splats" section below
|
||||||
>>> [1, 10]
|
>>> [1,10]
|
||||||
|
|
||||||
# Splats
|
# Splats
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ or whatever implementing [Iterable], is called _splats_. Here is how we use it:
|
|||||||
}
|
}
|
||||||
val array = [1,2,3]
|
val array = [1,2,3]
|
||||||
testSplat("start", ...array, "end")
|
testSplat("start", ...array, "end")
|
||||||
>>> ["start", 1, 2, 3, "end"]
|
>>> [start,1,2,3,end]
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
There could be any number of splats at any positions. You can splat any other [Iterable] type:
|
There could be any number of splats at any positions. You can splat any other [Iterable] type:
|
||||||
@ -93,7 +93,7 @@ There could be any number of splats at any positions. You can splat any other [I
|
|||||||
}
|
}
|
||||||
val range = 1..3
|
val range = 1..3
|
||||||
testSplat("start", ...range, "end")
|
testSplat("start", ...range, "end")
|
||||||
>>> ["start", 1, 2, 3, "end"]
|
>>> [start,1,2,3,end]
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,8 +183,8 @@ Important difference from the channels or like, every time you collect the flow,
|
|||||||
// and again:
|
// and again:
|
||||||
assertEquals( result, f.toList() )
|
assertEquals( result, f.toList() )
|
||||||
|
|
||||||
>>> ["start", 1, 2, 3, 4]
|
>>> [start,1,2,3,4]
|
||||||
>>> ["start", 1, 2, 3, 4]
|
>>> [start,1,2,3,4]
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
Notice that flow's lambda is not called until actual collection is started. Cold flows are
|
Notice that flow's lambda is not called until actual collection is started. Cold flows are
|
||||||
|
@ -505,21 +505,21 @@ Notice usage of indexing. You can use negative indexes to offset from the end of
|
|||||||
When you want to "flatten" it to single array, you can use splat syntax:
|
When you want to "flatten" it to single array, you can use splat syntax:
|
||||||
|
|
||||||
[1, ...[2,3], 4]
|
[1, ...[2,3], 4]
|
||||||
>>> [1, 2, 3, 4]
|
>>> [1,2,3,4]
|
||||||
|
|
||||||
Of course, you can splat from anything that is List (or list-like, but it will be defined later):
|
Of course, you can splat from anything that is List (or list-like, but it will be defined later):
|
||||||
|
|
||||||
val a = ["one", "two"]
|
val a = ["one", "two"]
|
||||||
val b = [10.1, 20.2]
|
val b = [10.1, 20.2]
|
||||||
["start", ...b, ...a, "end"]
|
["start", ...b, ...a, "end"]
|
||||||
>>> ["start", 10.1, 20.2, "one", "two", "end"]
|
>>> [start,10.1,20.2,one,two,end]
|
||||||
|
|
||||||
Of course, you can set any list element:
|
Of course, you can set any list element:
|
||||||
|
|
||||||
val a = [1, 2, 3]
|
val a = [1, 2, 3]
|
||||||
a[1] = 200
|
a[1] = 200
|
||||||
a
|
a
|
||||||
>>> [1, 200, 3]
|
>>> [1,200,3]
|
||||||
|
|
||||||
Lists are comparable, and it works well as long as their respective elements are:
|
Lists are comparable, and it works well as long as their respective elements are:
|
||||||
|
|
||||||
@ -609,20 +609,20 @@ Using splat arguments can simplify inserting list in list:
|
|||||||
val x = [1, 2, 3]
|
val x = [1, 2, 3]
|
||||||
x.insertAt( 1, ...[0,100,0])
|
x.insertAt( 1, ...[0,100,0])
|
||||||
x
|
x
|
||||||
>>> [1, 0, 100, 0, 2, 3]
|
>>> [1,0,100,0,2,3]
|
||||||
|
|
||||||
Note that to add to the end you still need to use `add` or positive index of the after-last element:
|
Note that to add to the end you still need to use `add` or positive index of the after-last element:
|
||||||
|
|
||||||
val x = [1,2,3]
|
val x = [1,2,3]
|
||||||
x.insertAt(3, 10)
|
x.insertAt(3, 10)
|
||||||
x
|
x
|
||||||
>>> [1, 2, 3, 10]
|
>>> [1,2,3,10]
|
||||||
|
|
||||||
but it is much simpler, and we recommend to use '+='
|
but it is much simpler, and we recommend to use '+='
|
||||||
|
|
||||||
val x = [1,2,3]
|
val x = [1,2,3]
|
||||||
x += 10
|
x += 10
|
||||||
>>> [1, 2, 3, 10]
|
>>> [1,2,3,10]
|
||||||
|
|
||||||
## Removing list items
|
## Removing list items
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ data class Arguments(val list: List<Obj>, val tailBlockMode: Boolean = false) :
|
|||||||
return list.map { it.toKotlin(scope) }
|
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 {
|
companion object {
|
||||||
val EMPTY = Arguments(emptyList())
|
val EMPTY = Arguments(emptyList())
|
||||||
|
@ -1363,8 +1363,8 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return statement(body.pos) { ctx ->
|
return statement(body.pos) { cxt ->
|
||||||
val forContext = ctx.copy(start)
|
val forContext = cxt.copy(start)
|
||||||
|
|
||||||
// loop var: StoredObject
|
// loop var: StoredObject
|
||||||
val loopSO = forContext.addItem(tVar.value, true, ObjNull)
|
val loopSO = forContext.addItem(tVar.value, true, ObjNull)
|
||||||
@ -1393,7 +1393,7 @@ class Compiler(
|
|||||||
.getOrElse {
|
.getOrElse {
|
||||||
throw ScriptError(
|
throw ScriptError(
|
||||||
tOp.pos,
|
tOp.pos,
|
||||||
"object is not enumerable: no index access for ${sourceObj.inspect()}",
|
"object is not enumerable: no index access for ${sourceObj.inspect(cxt)}",
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1420,7 +1420,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!breakCaught && elseStatement != null) {
|
if (!breakCaught && elseStatement != null) {
|
||||||
result = elseStatement.execute(ctx)
|
result = elseStatement.execute(cxt)
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -57,15 +57,15 @@ class Script(
|
|||||||
ObjException.addExceptionsToContext(this)
|
ObjException.addExceptionsToContext(this)
|
||||||
addFn("print") {
|
addFn("print") {
|
||||||
for ((i, a) in args.withIndex()) {
|
for ((i, a) in args.withIndex()) {
|
||||||
if (i > 0) print(' ' + a.asStr.value)
|
if (i > 0) print(' ' + a.toString(this).value)
|
||||||
else print(a.asStr.value)
|
else print(a.toString(this).value)
|
||||||
}
|
}
|
||||||
ObjVoid
|
ObjVoid
|
||||||
}
|
}
|
||||||
addFn("println") {
|
addFn("println") {
|
||||||
for ((i, a) in args.withIndex()) {
|
for ((i, a) in args.withIndex()) {
|
||||||
if (i > 0) print(' ' + a.asStr.value)
|
if (i > 0) print(' ' + a.toString(this).value)
|
||||||
else print(a.asStr.value)
|
else print(a.toString(this).value)
|
||||||
}
|
}
|
||||||
println()
|
println()
|
||||||
ObjVoid
|
ObjVoid
|
||||||
@ -165,13 +165,13 @@ class Script(
|
|||||||
val a = requiredArg<Obj>(0)
|
val a = requiredArg<Obj>(0)
|
||||||
val b = requiredArg<Obj>(1)
|
val b = requiredArg<Obj>(1)
|
||||||
if( a.compareTo(this, b) != 0 )
|
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") {
|
addVoidFn("assertNotEquals") {
|
||||||
val a = requiredArg<Obj>(0)
|
val a = requiredArg<Obj>(0)
|
||||||
val b = requiredArg<Obj>(1)
|
val b = requiredArg<Obj>(1)
|
||||||
if( a.compareTo(this, b) == 0 )
|
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") {
|
addFn("assertThrows") {
|
||||||
val code = requireOnlyArg<Statement>()
|
val code = requireOnlyArg<Statement>()
|
||||||
@ -287,7 +287,7 @@ class Script(
|
|||||||
is ObjInt -> delay(a.value * 1000)
|
is ObjInt -> delay(a.value * 1000)
|
||||||
is ObjReal -> delay((a.value * 1000).roundToLong())
|
is ObjReal -> delay((a.value * 1000).roundToLong())
|
||||||
is ObjDuration -> delay(a.duration)
|
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
|
ObjVoid
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,14 @@
|
|||||||
|
|
||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
|
import net.sergeych.lyng.obj.ObjString
|
||||||
|
|
||||||
class Source(val fileName: String, text: String) {
|
class Source(val fileName: String, text: String) {
|
||||||
|
|
||||||
val lines = text.lines().map { it.trimEnd() }
|
val lines = text.lines().map { it.trimEnd() }
|
||||||
|
|
||||||
|
val objSourceName by lazy { ObjString(fileName) }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val builtIn: Source by lazy { Source("built-in", "") }
|
val builtIn: Source by lazy { Source("built-in", "") }
|
||||||
val UNKNOWN: Source by lazy { Source("UNKNOWN", "") }
|
val UNKNOWN: Source by lazy { Source("UNKNOWN", "") }
|
||||||
|
@ -26,6 +26,7 @@ import net.sergeych.lyng.*
|
|||||||
import net.sergeych.lynon.LynonDecoder
|
import net.sergeych.lynon.LynonDecoder
|
||||||
import net.sergeych.lynon.LynonEncoder
|
import net.sergeych.lynon.LynonEncoder
|
||||||
import net.sergeych.lynon.LynonType
|
import net.sergeych.lynon.LynonType
|
||||||
|
import net.sergeych.mptools.CachedExpression
|
||||||
import net.sergeych.synctools.ProtectedOp
|
import net.sergeych.synctools.ProtectedOp
|
||||||
import net.sergeych.synctools.withLock
|
import net.sergeych.synctools.withLock
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
@ -49,7 +50,7 @@ open class Obj {
|
|||||||
|
|
||||||
private val opInstances = ProtectedOp()
|
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.
|
* Some objects are by-value, historically [ObjInt] and [ObjReal] are usually treated as such.
|
||||||
@ -84,14 +85,14 @@ open class Obj {
|
|||||||
scope: Scope,
|
scope: Scope,
|
||||||
name: String,
|
name: String,
|
||||||
args: Arguments = Arguments.EMPTY,
|
args: Arguments = Arguments.EMPTY,
|
||||||
onNotFoundResult: Obj?=null
|
onNotFoundResult: (()->Obj?)? = null
|
||||||
): Obj {
|
): Obj {
|
||||||
return objClass.getInstanceMemberOrNull(name)?.value?.invoke(
|
return objClass.getInstanceMemberOrNull(name)?.value?.invoke(
|
||||||
scope,
|
scope,
|
||||||
this,
|
this,
|
||||||
args
|
args
|
||||||
)
|
)
|
||||||
?: onNotFoundResult
|
?: onNotFoundResult?.invoke()
|
||||||
?: scope.raiseSymbolNotFound(name)
|
?: scope.raiseSymbolNotFound(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,8 +116,11 @@ open class Obj {
|
|||||||
return invokeInstanceMethod(scope, "contains", other).toBool()
|
return invokeInstanceMethod(scope, "contains", other).toBool()
|
||||||
}
|
}
|
||||||
|
|
||||||
open val asStr: ObjString by lazy {
|
suspend open fun toString(scope: Scope): ObjString {
|
||||||
if (this is ObjString) this else ObjString(this.toString())
|
return if (this is ObjString) this
|
||||||
|
else invokeInstanceMethod(scope, "toString") {
|
||||||
|
ObjString(this.toString())
|
||||||
|
} as ObjString
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -276,9 +280,9 @@ open class Obj {
|
|||||||
scope.raiseNotImplemented()
|
scope.raiseNotImplemented()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun autoInstanceScope(parent: Scope): Scope {
|
fun autoInstanceScope(parent: Scope): Scope {
|
||||||
val scope = parent.copy(newThisObj = this, args = parent.args)
|
val scope = parent.copy(newThisObj = this, args = parent.args)
|
||||||
for( m in objClass.members) {
|
for (m in objClass.members) {
|
||||||
scope.objects[m.key] = m.value
|
scope.objects[m.key] = m.value
|
||||||
}
|
}
|
||||||
return scope
|
return scope
|
||||||
@ -287,11 +291,11 @@ open class Obj {
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val rootObjectType = ObjClass("Obj").apply {
|
val rootObjectType = ObjClass("Obj").apply {
|
||||||
addFn("toString") {
|
addFn("toString", true) {
|
||||||
thisObj.asStr
|
ObjString(thisObj.toString())
|
||||||
}
|
}
|
||||||
addFn("inspect", true) {
|
addFn("inspect", true) {
|
||||||
thisObj.inspect().toObj()
|
thisObj.inspect(this).toObj()
|
||||||
}
|
}
|
||||||
addFn("contains") {
|
addFn("contains") {
|
||||||
ObjBool(thisObj.contains(this, args.firstAndOnly()))
|
ObjBool(thisObj.contains(this, args.firstAndOnly()))
|
||||||
@ -392,9 +396,14 @@ object ObjNull : Obj() {
|
|||||||
scope.raiseNPE()
|
scope.raiseNPE()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun invokeInstanceMethod(scope: Scope, name: String, args: Arguments, onNotFoundResult: Obj?): Obj {
|
// override suspend fun invokeInstanceMethod(
|
||||||
scope.raiseNPE()
|
// scope: Scope,
|
||||||
}
|
// name: String,
|
||||||
|
// args: Arguments,
|
||||||
|
// onNotFoundResult: (()->Obj?)?
|
||||||
|
// ): Obj {
|
||||||
|
// scope.raiseNPE()
|
||||||
|
// }
|
||||||
|
|
||||||
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
||||||
scope.raiseNPE()
|
scope.raiseNPE()
|
||||||
@ -469,20 +478,51 @@ fun Obj.toBool(): Boolean =
|
|||||||
data class ObjNamespace(val name: String) : Obj() {
|
data class ObjNamespace(val name: String) : Obj() {
|
||||||
override val objClass by lazy { ObjClass(name) }
|
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 {
|
override fun toString(): String {
|
||||||
return "package $name"
|
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(
|
constructor(name: String, scope: Scope, message: String) : this(
|
||||||
getOrCreateExceptionClass(name),
|
getOrCreateExceptionClass(name),
|
||||||
scope,
|
scope,
|
||||||
message
|
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)
|
constructor(scope: Scope, message: String) : this(Root, scope, message)
|
||||||
|
|
||||||
fun raise(): Nothing {
|
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()}"
|
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 {
|
companion object {
|
||||||
|
|
||||||
class ExceptionClass(val name: String, vararg parents: ObjClass) : ObjClass(name, *parents) {
|
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 {
|
addConst("message", statement {
|
||||||
(thisObj as ObjException).message.toObj()
|
(thisObj as ObjException).message.toObj()
|
||||||
})
|
})
|
||||||
|
addFn("getStackTrace") {
|
||||||
|
(thisObj as ObjException).getStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val op = ProtectedOp()
|
private val op = ProtectedOp()
|
||||||
|
@ -50,6 +50,5 @@ val ObjArray by lazy {
|
|||||||
addFn("indices") {
|
addFn("indices") {
|
||||||
ObjRange(0.toObj(), thisObj.invokeInstanceMethod(this, "size"), false)
|
ObjRange(0.toObj(), thisObj.invokeInstanceMethod(this, "size"), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,7 +23,6 @@ import net.sergeych.lynon.LynonEncoder
|
|||||||
import net.sergeych.lynon.LynonType
|
import net.sergeych.lynon.LynonType
|
||||||
|
|
||||||
data class ObjBool(val value: Boolean) : Obj() {
|
data class ObjBool(val value: Boolean) : Obj() {
|
||||||
override val asStr by lazy { ObjString(value.toString()) }
|
|
||||||
|
|
||||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||||
if (other !is ObjBool) return -2
|
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()
|
byteArray + other.toFlow(scope).map { it.toLong().toUByte() }.toList().toTypedArray()
|
||||||
.toUByteArray()
|
.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
|
override fun toString(): String = base64
|
||||||
@ -107,7 +107,7 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
|||||||
encoder.encodeCachedBytes(byteArray.asByteArray())
|
encoder.encodeCachedBytes(byteArray.asByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun inspect(): String = "Buf($base64)"
|
override suspend fun inspect(scope: Scope): String = "Buf($base64)"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private suspend fun createBufferFrom(scope: Scope, obj: Obj): ObjBuffer =
|
private suspend fun createBufferFrom(scope: Scope, obj: Obj): ObjBuffer =
|
||||||
@ -129,7 +129,7 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
|||||||
)
|
)
|
||||||
} else
|
} else
|
||||||
scope.raiseIllegalArgument(
|
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 ObjChar -> b.value.code.toUByte()
|
||||||
is ObjInt -> b.value.toUByte()
|
is ObjInt -> b.value.toUByte()
|
||||||
else -> scope.raiseIllegalArgument(
|
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
|
data[i] = code
|
||||||
|
@ -28,7 +28,7 @@ class ObjChar(val value: Char): Obj() {
|
|||||||
|
|
||||||
override fun toString(): String = value.toString()
|
override fun toString(): String = value.toString()
|
||||||
|
|
||||||
override fun inspect(): String = "'$value'"
|
override suspend fun inspect(scope: Scope): String = "'$value'"
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return value.hashCode()
|
return value.hashCode()
|
||||||
|
@ -61,13 +61,17 @@ open class ObjClass(
|
|||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj {
|
override suspend fun callOn(scope: Scope): Obj {
|
||||||
val instance = ObjInstance(this)
|
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) {
|
if (instanceConstructor != null) {
|
||||||
instanceConstructor!!.execute(instance.instanceScope)
|
instanceConstructor!!.execute(instance.instanceScope)
|
||||||
}
|
}
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun callWithArgs(scope: Scope, vararg plainArgs: Obj): Obj {
|
||||||
|
return callOn(scope.copy(Arguments(*plainArgs)))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun createField(
|
fun createField(
|
||||||
name: String,
|
name: String,
|
||||||
@ -77,13 +81,13 @@ open class ObjClass(
|
|||||||
pos: Pos = Pos.builtIn
|
pos: Pos = Pos.builtIn
|
||||||
) {
|
) {
|
||||||
val existing = members[name] ?: allParentsSet.firstNotNullOfOrNull { it.members[name] }
|
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")
|
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
||||||
members[name] = ObjRecord(initialValue, isMutable, visibility)
|
members[name] = ObjRecord(initialValue, isMutable, visibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initClassScope(): Scope {
|
private fun initClassScope(): Scope {
|
||||||
if( classScope == null ) classScope = Scope()
|
if (classScope == null) classScope = Scope()
|
||||||
return classScope!!
|
return classScope!!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +100,7 @@ open class ObjClass(
|
|||||||
) {
|
) {
|
||||||
initClassScope()
|
initClassScope()
|
||||||
val existing = classScope!!.objects[name]
|
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")
|
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
||||||
classScope!!.addItem(name, isMutable, initialValue, visibility)
|
classScope!!.addItem(name, isMutable, initialValue, visibility)
|
||||||
}
|
}
|
||||||
@ -127,26 +131,29 @@ open class ObjClass(
|
|||||||
|
|
||||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||||
classScope?.objects?.get(name)?.let {
|
classScope?.objects?.get(name)?.let {
|
||||||
if( it.visibility.isPublic ) return it
|
if (it.visibility.isPublic) return it
|
||||||
}
|
}
|
||||||
return super.readField(scope, name)
|
return super.readField(scope, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
|
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
|
||||||
initClassScope().objects[name]?.let {
|
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")
|
else scope.raiseIllegalAssignment("can't assign $name is not mutable")
|
||||||
}
|
}
|
||||||
?: super.writeField(scope, name, newValue)
|
?: super.writeField(scope, name, newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun invokeInstanceMethod(scope: Scope, name: String, args: Arguments,
|
override suspend fun invokeInstanceMethod(
|
||||||
onNotFoundResult: Obj?): Obj {
|
scope: Scope, name: String, args: Arguments,
|
||||||
|
onNotFoundResult: (() -> Obj?)?
|
||||||
|
): Obj {
|
||||||
return classScope?.objects?.get(name)?.value?.invoke(scope, this, args)
|
return classScope?.objects?.get(name)?.value?.invoke(scope, this, args)
|
||||||
?: super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
?: 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 {
|
val ObjCollection = ObjClass("Collection", ObjIterable).apply {
|
||||||
|
|
||||||
}
|
}
|
@ -57,7 +57,7 @@ class ObjDuration(val duration: Duration) : Obj() {
|
|||||||
override suspend fun callOn(scope: Scope): Obj {
|
override suspend fun callOn(scope: Scope): Obj {
|
||||||
val args = scope.args
|
val args = scope.args
|
||||||
if( args.list.size > 1 )
|
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)
|
val a0 = args.list.getOrNull(0)
|
||||||
|
|
||||||
return ObjDuration(
|
return ObjDuration(
|
||||||
@ -66,7 +66,7 @@ class ObjDuration(val duration: Duration) : Obj() {
|
|||||||
is ObjInt -> a0.value.seconds
|
is ObjInt -> a0.value.seconds
|
||||||
is ObjReal -> a0.value.seconds
|
is ObjReal -> a0.value.seconds
|
||||||
else -> {
|
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,
|
override suspend fun invokeInstanceMethod(scope: Scope, name: String, args: Arguments,
|
||||||
onNotFoundResult: Obj?): Obj =
|
onNotFoundResult: (()->Obj?)?): Obj =
|
||||||
instanceScope[name]?.let {
|
instanceScope[name]?.let {
|
||||||
if (it.visibility.isPublic)
|
if (it.visibility.isPublic)
|
||||||
it.value.invoke(
|
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 {
|
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||||
val args = decoder.decodeAnyList(scope)
|
val args = decoder.decodeAnyList(scope)
|
||||||
val actualSize = constructorMeta?.params?.size ?: 0
|
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}")
|
scope.raiseIllegalArgument("constructor $name has only $actualSize but serialized version has ${args.size}")
|
||||||
val newScope = scope.copy(args = Arguments(args))
|
val newScope = scope.copy(args = Arguments(args))
|
||||||
return (callOn(newScope) as ObjInstance).apply {
|
return (callOn(newScope) as ObjInstance).apply {
|
||||||
deserializeStateVars(scope,decoder)
|
deserializeStateVars(scope, decoder)
|
||||||
invokeInstanceMethod(scope, "onDeserialized", onNotFoundResult = ObjVoid)
|
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
|
is ObjInstant -> a0.instant
|
||||||
|
|
||||||
else -> {
|
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
|
import net.sergeych.lynon.LynonType
|
||||||
|
|
||||||
class ObjInt(var value: Long, override val isConst: Boolean = false) : Obj(), Numeric {
|
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 longValue get() = value
|
||||||
override val doubleValue get() = value.toDouble()
|
override val doubleValue get() = value.toDouble()
|
||||||
override val toObjInt get() = this
|
override val toObjInt get() = this
|
||||||
|
@ -82,18 +82,18 @@ fun Obj.toFlow(scope: Scope): Flow<Obj> = flow {
|
|||||||
*
|
*
|
||||||
* IF callback returns false, iteration is stopped.
|
* 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 iterator = invokeInstanceMethod(scope, "iterator")
|
||||||
val hasNext = iterator.getInstanceMethod(scope, "hasNext")
|
val hasNext = iterator.getInstanceMethod(scope, "hasNext")
|
||||||
val next = iterator.getInstanceMethod(scope, "next")
|
val next = iterator.getInstanceMethod(scope, "next")
|
||||||
var closeIt = false
|
var closeIt = false
|
||||||
while (hasNext.invoke(scope, iterator).toBool()) {
|
while (hasNext.invoke(scope, iterator).toBool()) {
|
||||||
val nextValue = next.invoke(scope, iterator)
|
val nextValue = next.invoke(scope, iterator)
|
||||||
if( !callback(nextValue) ) {
|
if (!callback(nextValue)) {
|
||||||
closeIt = true
|
closeIt = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( closeIt )
|
if (closeIt)
|
||||||
iterator.invokeInstanceMethod(scope, "cancelIteration", onNotFoundResult = ObjVoid)
|
iterator.invokeInstanceMethod(scope, "cancelIteration") { ObjVoid }
|
||||||
}
|
}
|
@ -25,10 +25,6 @@ import net.sergeych.lynon.LynonType
|
|||||||
|
|
||||||
class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
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 {
|
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
||||||
return when (index) {
|
return when (index) {
|
||||||
is ObjInt -> {
|
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 ObjInt -> newValue.value.toUByte()
|
||||||
is ObjChar -> newValue.value.code.toUByte()
|
is ObjChar -> newValue.value.code.toUByte()
|
||||||
else -> scope.raiseIllegalArgument(
|
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
|
} else
|
||||||
scope.raiseIllegalArgument(
|
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 ObjChar -> b.value.code.toUByte()
|
||||||
is ObjInt -> b.value.toUByte()
|
is ObjInt -> b.value.toUByte()
|
||||||
else -> scope.raiseIllegalArgument(
|
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
|
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 val objClass: ObjClass = type
|
||||||
|
|
||||||
override fun toString(): String {
|
override suspend fun toString(scope: Scope): ObjString {
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
result.append("${start?.inspect() ?: '∞'} ..")
|
result.append("${start?.inspect(scope) ?: '∞'} ..")
|
||||||
if (!isEndInclusive) result.append('<')
|
if (!isEndInclusive) result.append('<')
|
||||||
result.append(" ${end?.inspect() ?: '∞'}")
|
result.append(" ${end?.inspect(scope) ?: '∞'}")
|
||||||
return result.toString()
|
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]
|
* if start is not ObjInt, raises [ObjIllegalArgumentException]
|
||||||
* otherwise returns start.value.toInt()
|
* otherwise returns start.value.toInt()
|
||||||
*/
|
*/
|
||||||
fun startInt(scope: Scope): Int =
|
suspend fun startInt(scope: Scope): Int =
|
||||||
if( start == null || start is ObjNull) 0
|
if( start == null || start is ObjNull) 0
|
||||||
else {
|
else {
|
||||||
if( start is ObjInt) start.value.toInt()
|
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 {
|
suspend fun containsRange(scope: Scope, other: ObjRange): Boolean {
|
||||||
|
@ -27,7 +27,6 @@ import kotlin.math.floor
|
|||||||
import kotlin.math.roundToLong
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
data class ObjReal(val value: Double) : Obj(), Numeric {
|
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 longValue: Long by lazy { floor(value).toLong() }
|
||||||
override val doubleValue: Double by lazy { value }
|
override val doubleValue: Double by lazy { value }
|
||||||
override val toObjInt: ObjInt by lazy { ObjInt(longValue) }
|
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 fun toString(): String = value
|
||||||
|
|
||||||
override val asStr: ObjString by lazy { this }
|
override suspend fun inspect(scope: Scope): String {
|
||||||
|
|
||||||
override fun inspect(): String {
|
|
||||||
return "\"$value\""
|
return "\"$value\""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +52,7 @@ data class ObjString(val value: String) : Obj() {
|
|||||||
get() = type
|
get() = type
|
||||||
|
|
||||||
override suspend fun plus(scope: Scope, other: Obj): Obj {
|
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 {
|
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
||||||
@ -159,6 +157,9 @@ data class ObjString(val value: String) : Obj() {
|
|||||||
addFn("toReal") {
|
addFn("toReal") {
|
||||||
ObjReal(thisAs<ObjString>().value.toDouble())
|
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 {
|
fun Iterable.all(predicate): Bool {
|
||||||
!any { !predicate(it) }
|
!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()
|
""".trimIndent()
|
||||||
|
|
||||||
|
@ -1789,7 +1789,7 @@ class ScriptTest {
|
|||||||
"e="+e+"f="+f()
|
"e="+e+"f="+f()
|
||||||
}
|
}
|
||||||
assertEquals("e=[]f=xx", f { "xx" })
|
assertEquals("e=[]f=xx", f { "xx" })
|
||||||
assertEquals("e=[1, 2]f=xx", f(1,2) { "xx" })
|
assertEquals("e=[1,2]f=xx", f(1,2) { "xx" })
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1824,7 +1824,7 @@ class ScriptTest {
|
|||||||
}
|
}
|
||||||
val f = Foo()
|
val f = Foo()
|
||||||
assertEquals("e=[]f=xx", f.f { "xx" })
|
assertEquals("e=[]f=xx", f.f { "xx" })
|
||||||
assertEquals("e=[1, 2]f=xx", f.f(1,2) { "xx" })
|
assertEquals("e=[1,2]f=xx", f.f(1,2) { "xx" })
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -2661,7 +2661,8 @@ class ScriptTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBufferEncodings() = runTest {
|
fun testBufferEncodings() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
import lyng.buffer
|
import lyng.buffer
|
||||||
|
|
||||||
val b = Buffer("hello")
|
val b = Buffer("hello")
|
||||||
@ -2676,7 +2677,8 @@ class ScriptTest {
|
|||||||
|
|
||||||
println(b.inspect())
|
println(b.inspect())
|
||||||
|
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -2900,7 +2902,8 @@ class ScriptTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun tesFunAnnotation() = runTest {
|
fun tesFunAnnotation() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
|
|
||||||
val exportedSymbols = Map()
|
val exportedSymbols = Map()
|
||||||
|
|
||||||
@ -2919,7 +2922,8 @@ class ScriptTest {
|
|||||||
assert( exportedSymbols["getBalance"] != null )
|
assert( exportedSymbols["getBalance"] != null )
|
||||||
assertEquals(122, getBalance(1))
|
assertEquals(122, getBalance(1))
|
||||||
|
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -2939,12 +2943,14 @@ class ScriptTest {
|
|||||||
assertEquals( Color.valueOf("GREEN"), Color.GREEN )
|
assertEquals( Color.valueOf("GREEN"), Color.GREEN )
|
||||||
|
|
||||||
|
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun enumSerializationTest() = runTest {
|
fun enumSerializationTest() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
import lyng.serialization
|
import lyng.serialization
|
||||||
|
|
||||||
enum Color {
|
enum Color {
|
||||||
@ -2960,12 +2966,14 @@ class ScriptTest {
|
|||||||
assert( e1.size / 1000.0 < 6)
|
assert( e1.size / 1000.0 < 6)
|
||||||
println(Lynon.encode( (1..100).map { "RED" } ).toDump() )
|
println(Lynon.encode( (1..100).map { "RED" } ).toDump() )
|
||||||
|
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun cachedTest() = runTest {
|
fun cachedTest() = runTest {
|
||||||
eval( """
|
eval(
|
||||||
|
"""
|
||||||
|
|
||||||
var counter = 0
|
var counter = 0
|
||||||
var value = cached {
|
var value = cached {
|
||||||
@ -2978,66 +2986,82 @@ class ScriptTest {
|
|||||||
assertEquals(1, counter)
|
assertEquals(1, counter)
|
||||||
assertEquals("ok", value())
|
assertEquals("ok", value())
|
||||||
assertEquals(1, counter)
|
assertEquals(1, counter)
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testJoinToString() = runTest {
|
fun testJoinToString() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
assertEquals( (1..3).joinToString(), "1 2 3")
|
assertEquals( (1..3).joinToString(), "1 2 3")
|
||||||
assertEquals( (1..3).joinToString(":"), "1:2:3")
|
assertEquals( (1..3).joinToString(":"), "1:2:3")
|
||||||
assertEquals( (1..3).joinToString { it * 10 }, "10 20 30")
|
assertEquals( (1..3).joinToString { it * 10 }, "10 20 30")
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testElvisAndThrow() = runTest {
|
fun testElvisAndThrow() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
val x = assertThrows {
|
val x = assertThrows {
|
||||||
null ?: throw "test" + "x"
|
null ?: throw "test" + "x"
|
||||||
}
|
}
|
||||||
assertEquals( "testx", x.message)
|
assertEquals( "testx", x.message)
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testElvisAndThrow2() = runTest {
|
fun testElvisAndThrow2() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
val t = "112"
|
val t = "112"
|
||||||
val x = t ?: run { throw "testx" }
|
val x = t ?: run { throw "testx" }
|
||||||
}
|
}
|
||||||
assertEquals( "112", x)
|
assertEquals( "112", x)
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testElvisAndRunThrow() = runTest {
|
fun testElvisAndRunThrow() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
val x = assertThrows {
|
val x = assertThrows {
|
||||||
null ?: run { throw "testx" }
|
null ?: run { throw "testx" }
|
||||||
}
|
}
|
||||||
assertEquals( "testx", x.message)
|
assertEquals( "testx", x.message)
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNewlinesAnsCommentsInExpressions() = runTest {
|
fun testNewlinesAnsCommentsInExpressions() = runTest {
|
||||||
assertEquals( 2, (Scope().eval("""
|
assertEquals(
|
||||||
|
2, (Scope().eval(
|
||||||
|
"""
|
||||||
val e = 1 + 4 -
|
val e = 1 + 4 -
|
||||||
3
|
3
|
||||||
""".trimIndent())).toInt())
|
""".trimIndent()
|
||||||
|
)).toInt()
|
||||||
|
)
|
||||||
|
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
val x = [1,2,3]
|
val x = [1,2,3]
|
||||||
.map { it * 10 }
|
.map { it * 10 }
|
||||||
.map { it + 1 }
|
.map { it + 1 }
|
||||||
assertEquals( [11,21,31], x)
|
assertEquals( [11,21,31], x)
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNotExpressionWithoutWs() = runTest {
|
fun testNotExpressionWithoutWs() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
fun test() { false }
|
fun test() { false }
|
||||||
class T(value)
|
class T(value)
|
||||||
assert( !false )
|
assert( !false )
|
||||||
@ -3046,12 +3070,14 @@ class ScriptTest {
|
|||||||
val t = T(false)
|
val t = T(false)
|
||||||
assert( !t.value )
|
assert( !t.value )
|
||||||
assert( !if( true ) false else true )
|
assert( !if( true ) false else true )
|
||||||
""".trimIndent())
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMultilineFnDeclaration() = runTest {
|
fun testMultilineFnDeclaration() = runTest {
|
||||||
eval("""
|
eval(
|
||||||
|
"""
|
||||||
fun test(
|
fun test(
|
||||||
x = 1,
|
x = 1,
|
||||||
y = 2
|
y = 2
|
||||||
@ -3063,8 +3089,38 @@ class ScriptTest {
|
|||||||
6,
|
6,
|
||||||
7
|
7
|
||||||
) )
|
) )
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOverridenListToString() = runTest {
|
||||||
|
eval("""
|
||||||
|
val x = [1,2,3]
|
||||||
|
assertEquals( "[1,2,3]", x.toString() )
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testExceptionSerialization() = runTest {
|
||||||
|
eval(
|
||||||
|
"""
|
||||||
|
import lyng.serialization
|
||||||
|
val x = [1,2,3]
|
||||||
|
assertEquals( "[1,2,3]", x.toString() )
|
||||||
|
try {
|
||||||
|
require(false)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
println(e)
|
||||||
|
println(e.getStackTrace())
|
||||||
|
for( t in e.getStackTrace() ) {
|
||||||
|
println(t)
|
||||||
|
}
|
||||||
|
// val coded = Lynon.encode(e)
|
||||||
|
// println(coded.toDump())
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
@ -177,11 +177,11 @@ suspend fun DocTest.test(_scope: Scope? = null) {
|
|||||||
scope.apply {
|
scope.apply {
|
||||||
addFn("println") {
|
addFn("println") {
|
||||||
if( bookMode ) {
|
if( bookMode ) {
|
||||||
println("${currentTest.fileNamePart}:${currentTest.line}> ${args.joinToString(" "){it.asStr.value}}")
|
println("${currentTest.fileNamePart}:${currentTest.line}> ${args.map{it.toString(this).value}.joinToString(" ")}")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for ((i, a) in args.withIndex()) {
|
for ((i, a) in args.withIndex()) {
|
||||||
if (i > 0) collectedOutput.append(' '); collectedOutput.append(a.asStr.value)
|
if (i > 0) collectedOutput.append(' '); collectedOutput.append(a.toString(this).value)
|
||||||
collectedOutput.append('\n')
|
collectedOutput.append('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ suspend fun DocTest.test(_scope: Scope? = null) {
|
|||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
error = e
|
error = e
|
||||||
null
|
null
|
||||||
}?.inspect()?.replace(Regex("@\\d+"), "@...")
|
}?.inspect(scope)?.replace(Regex("@\\d+"), "@...")
|
||||||
|
|
||||||
if (bookMode) {
|
if (bookMode) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user