more on classes
universal args declaration parser, lambda code rewritten to it
This commit is contained in:
parent
4dc73b91c2
commit
71a2933066
@ -0,0 +1,98 @@
|
|||||||
|
package net.sergeych.lyng
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of argument declarations in the __definition__ of the lambda, class constructor,
|
||||||
|
* function, etc. It is created by [Compiler.parseArgsDeclaration]
|
||||||
|
*/
|
||||||
|
data class ArgsDeclaration(val args: List<Item>, val endTokenType: Token.Type) {
|
||||||
|
init {
|
||||||
|
val i = args.count { it.isEllipsis }
|
||||||
|
if (i > 1) throw ScriptError(args[i].pos, "there can be only one argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse args and create local vars in a given context
|
||||||
|
*/
|
||||||
|
suspend fun assignToContext(
|
||||||
|
context: Context,
|
||||||
|
fromArgs: Arguments = context.args,
|
||||||
|
defaultAccessType: Compiler.AccessType = Compiler.AccessType.Var
|
||||||
|
) {
|
||||||
|
fun assign(a: Item, value: Obj) {
|
||||||
|
context.addItem(a.name, (a.accessType ?: defaultAccessType).isMutable, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun processHead(index: Int): Int {
|
||||||
|
var i = index
|
||||||
|
while (i != args.size) {
|
||||||
|
val a = args[i]
|
||||||
|
if (a.isEllipsis) break
|
||||||
|
val value = when {
|
||||||
|
i < fromArgs.size -> fromArgs[i]
|
||||||
|
a.defaultValue != null -> a.defaultValue.execute(context)
|
||||||
|
else -> context.raiseArgumentError("too few arguments for the call")
|
||||||
|
}
|
||||||
|
assign(a, value)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun processTail(index: Int): Int {
|
||||||
|
var i = args.size - 1
|
||||||
|
var j = fromArgs.size - 1
|
||||||
|
while (i > index) {
|
||||||
|
val a = args[i]
|
||||||
|
if (a.isEllipsis) break
|
||||||
|
val value = when {
|
||||||
|
j >= index -> {
|
||||||
|
fromArgs[j--]
|
||||||
|
}
|
||||||
|
|
||||||
|
a.defaultValue != null -> a.defaultValue.execute(context)
|
||||||
|
else -> context.raiseArgumentError("too few arguments for the call")
|
||||||
|
}
|
||||||
|
assign(a, value)
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processEllipsis(index: Int, toFromIndex: Int) {
|
||||||
|
val a = args[index]
|
||||||
|
val l = if (index > toFromIndex) ObjList()
|
||||||
|
else ObjList( fromArgs.values.subList(index, toFromIndex+1).toMutableList())
|
||||||
|
assign(a, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
val leftIndex = processHead(0)
|
||||||
|
if (leftIndex < args.size) {
|
||||||
|
val end = processTail(leftIndex)
|
||||||
|
processEllipsis(leftIndex, end)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if( leftIndex < fromArgs.size)
|
||||||
|
context.raiseArgumentError("too many arguments for the call")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single argument declaration descriptor.
|
||||||
|
*
|
||||||
|
* @param defaultValue default value, if set, can't be an [Obj] as it can depend on the call site, call args, etc.
|
||||||
|
* If not null, could be executed on __caller context__ only.
|
||||||
|
*/
|
||||||
|
data class Item(
|
||||||
|
val name: String,
|
||||||
|
val type: TypeDecl = TypeDecl.Obj,
|
||||||
|
val pos: Pos = Pos.builtIn,
|
||||||
|
val isEllipsis: Boolean = false,
|
||||||
|
/**
|
||||||
|
* Default value, if set, can't be an [Obj] as it can depend on the call site, call args, etc.
|
||||||
|
* So it is a [Statement] that must be executed on __caller context__.
|
||||||
|
*/
|
||||||
|
val defaultValue: Statement? = null,
|
||||||
|
val accessType: Compiler.AccessType? = null,
|
||||||
|
val visibility: Compiler.Visibility? = null,
|
||||||
|
)
|
||||||
|
}
|
@ -33,6 +33,7 @@ data class Arguments(val list: List<Info>) : Iterable<Obj> {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = Arguments(emptyList())
|
val EMPTY = Arguments(emptyList())
|
||||||
|
fun from(values: Collection<Obj>) = Arguments(values.map { Info(it, Pos.UNKNOWN) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iterator(): Iterator<Obj> {
|
override fun iterator(): Iterator<Obj> {
|
||||||
|
@ -347,22 +347,8 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
context.addItem("it", false, itValue)
|
context.addItem("it", false, itValue)
|
||||||
} else {
|
} else {
|
||||||
// assign vars as declared
|
// assign vars as declared the standard way
|
||||||
if (args.size != argsDeclaration.args.size && !argsDeclaration.args.last().isEllipsis)
|
argsDeclaration.assignToContext(context)
|
||||||
raiseArgumentError("Too many arguments : called with ${args.size}, lambda accepts only ${argsDeclaration.args.size}")
|
|
||||||
for ((n, a) in argsDeclaration.args.withIndex()) {
|
|
||||||
if (n >= args.size) {
|
|
||||||
if (a.initialValue != null)
|
|
||||||
context.addItem(a.name, false, a.initialValue.execute(context))
|
|
||||||
else throw ScriptError(a.pos, "argument $n is out of scope")
|
|
||||||
} else {
|
|
||||||
val value = if (a.isEllipsis) {
|
|
||||||
ObjList(args.values.subList(n, args.values.size).toMutableList())
|
|
||||||
} else
|
|
||||||
args[n]
|
|
||||||
context.addItem(a.name, false, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
body.execute(context)
|
body.execute(context)
|
||||||
}
|
}
|
||||||
@ -411,29 +397,12 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class AccessType {
|
enum class AccessType(val isMutable: Boolean) {
|
||||||
Val, Var, Default
|
Val(false), Var(true), Initialization(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Visibility {
|
enum class Visibility {
|
||||||
Default, Public, Private, Protected, Internal
|
Public, Private, Protected, Internal
|
||||||
}
|
|
||||||
|
|
||||||
data class ArgVar(
|
|
||||||
val name: String,
|
|
||||||
val type: TypeDecl = TypeDecl.Obj,
|
|
||||||
val pos: Pos,
|
|
||||||
val isEllipsis: Boolean,
|
|
||||||
val initialValue: Statement? = null,
|
|
||||||
val accessType: AccessType = AccessType.Default,
|
|
||||||
val visibility: Visibility = Visibility.Default
|
|
||||||
)
|
|
||||||
|
|
||||||
data class ArgsDeclaration(val args: List<ArgVar>, val endTokenType: Token.Type) {
|
|
||||||
init {
|
|
||||||
val i = args.indexOfFirst { it.isEllipsis }
|
|
||||||
if (i >= 0 && i != args.lastIndex) throw ScriptError(args[i].pos, "ellipsis argument must be last")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -441,7 +410,7 @@ class Compiler(
|
|||||||
* @return declaration or null if there is no valid list of arguments
|
* @return declaration or null if there is no valid list of arguments
|
||||||
*/
|
*/
|
||||||
private fun parseArgsDeclaration(cc: CompilerContext, isClassDeclaration: Boolean = false): ArgsDeclaration? {
|
private fun parseArgsDeclaration(cc: CompilerContext, isClassDeclaration: Boolean = false): ArgsDeclaration? {
|
||||||
val result = mutableListOf<ArgVar>()
|
val result = mutableListOf<ArgsDeclaration.Item>()
|
||||||
var endTokenType: Token.Type? = null
|
var endTokenType: Token.Type? = null
|
||||||
val startPos = cc.savePos()
|
val startPos = cc.savePos()
|
||||||
|
|
||||||
@ -484,7 +453,7 @@ class Compiler(
|
|||||||
Visibility.Public
|
Visibility.Public
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Visibility.Default
|
else -> null
|
||||||
}
|
}
|
||||||
// val/var?
|
// val/var?
|
||||||
val access = when (t.value) {
|
val access = when (t.value) {
|
||||||
@ -504,7 +473,7 @@ class Compiler(
|
|||||||
AccessType.Var
|
AccessType.Var
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> AccessType.Default
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultValue: Statement? = null
|
var defaultValue: Statement? = null
|
||||||
@ -514,7 +483,15 @@ class Compiler(
|
|||||||
// type information
|
// type information
|
||||||
val typeInfo = parseTypeDeclaration(cc)
|
val typeInfo = parseTypeDeclaration(cc)
|
||||||
val isEllipsis = cc.skipTokenOfType(Token.Type.ELLIPSIS, isOptional = true)
|
val isEllipsis = cc.skipTokenOfType(Token.Type.ELLIPSIS, isOptional = true)
|
||||||
result += ArgVar(t.value, typeInfo, t.pos, isEllipsis, defaultValue, access, visibility)
|
result += ArgsDeclaration.Item(
|
||||||
|
t.value,
|
||||||
|
typeInfo,
|
||||||
|
t.pos,
|
||||||
|
isEllipsis,
|
||||||
|
defaultValue,
|
||||||
|
access,
|
||||||
|
visibility
|
||||||
|
)
|
||||||
|
|
||||||
// important: valid argument list continues with ',' and ends with '->' or ')'
|
// important: valid argument list continues with ',' and ends with '->' or ')'
|
||||||
// otherwise it is not an argument list:
|
// otherwise it is not an argument list:
|
||||||
@ -714,24 +691,45 @@ class Compiler(
|
|||||||
private fun parseClassDeclaration(cc: CompilerContext, isStruct: Boolean): Statement {
|
private fun parseClassDeclaration(cc: CompilerContext, isStruct: Boolean): Statement {
|
||||||
val nameToken = cc.requireToken(Token.Type.ID)
|
val nameToken = cc.requireToken(Token.Type.ID)
|
||||||
val parsedArgs = parseArgsDeclaration(cc)
|
val parsedArgs = parseArgsDeclaration(cc)
|
||||||
|
|
||||||
|
if( parsedArgs != null && parsedArgs.endTokenType != Token.Type.RPAREN)
|
||||||
|
throw ScriptError(nameToken.pos, "Bad class declaration: expected ')' at the end of the primary constructor")
|
||||||
|
|
||||||
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
||||||
val t = cc.next()
|
val t = cc.next()
|
||||||
if (t.type == Token.Type.LBRACE) {
|
|
||||||
|
var extraInit: Statement? = null
|
||||||
|
val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) {
|
||||||
// parse body
|
// parse body
|
||||||
}
|
TODO("parse body")
|
||||||
|
} else null
|
||||||
|
|
||||||
// create class
|
// create class
|
||||||
val className = nameToken.value
|
val className = nameToken.value
|
||||||
|
lateinit var classContext: Context
|
||||||
|
|
||||||
// val constructorCode = statement {
|
val defaultAccess = if (isStruct) AccessType.Var else AccessType.Initialization
|
||||||
// val classContext = copy()
|
val defaultVisibility = Visibility.Public
|
||||||
// }
|
|
||||||
|
|
||||||
|
// create instance constructor
|
||||||
|
// create custom objClass with all fields and instance constructor
|
||||||
|
|
||||||
val newClass = ObjClass(className, parsedArgs?.args ?: emptyList())
|
val constructorCode = statement {
|
||||||
// statement {
|
// constructor code is registered with class instance and is called over
|
||||||
// addConst(nameToken.value, )
|
// new `thisObj` already set by class to ObjInstance
|
||||||
// }
|
thisObj as ObjInstance
|
||||||
|
// the context now is a "class creation context", we must use its args to initialize
|
||||||
|
// fields. Note that 'this' is already set by class
|
||||||
|
// parsedArgs?.let { pa ->
|
||||||
|
// pa.extractArgs { (def, value) ->
|
||||||
|
// val access = def.accessType ?: defaultAccess
|
||||||
|
// val visibility = def.visibility ?: defaultVisibility
|
||||||
|
// addItem(def.name, access.isMutable, value)
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
|
thisObj
|
||||||
|
|
||||||
|
}
|
||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,9 @@ class Context(
|
|||||||
fun copy(pos: Pos, args: Arguments = Arguments.EMPTY,newThisObj: Obj? = null): Context =
|
fun copy(pos: Pos, args: Arguments = Arguments.EMPTY,newThisObj: Obj? = null): Context =
|
||||||
Context(this, args, pos, newThisObj ?: thisObj)
|
Context(this, args, pos, newThisObj ?: thisObj)
|
||||||
|
|
||||||
|
fun copy(args: Arguments = Arguments.EMPTY,newThisObj: Obj? = null): Context =
|
||||||
|
Context(this, args, pos, newThisObj ?: thisObj)
|
||||||
|
|
||||||
fun copy() = Context(this, args, pos, thisObj)
|
fun copy() = Context(this, args, pos, thisObj)
|
||||||
|
|
||||||
fun addItem(name: String, isMutable: Boolean, value: Obj?): StoredObj {
|
fun addItem(name: String, isMutable: Boolean, value: Obj?): StoredObj {
|
||||||
|
@ -4,7 +4,7 @@ val ObjClassType by lazy { ObjClass("Class") }
|
|||||||
|
|
||||||
class ObjClass(
|
class ObjClass(
|
||||||
val className: String,
|
val className: String,
|
||||||
val constructorArgs: List<Compiler.ArgVar> = emptyList(),
|
val constructorArgs: List<ArgsDeclaration.Item> = emptyList(),
|
||||||
vararg val parents: ObjClass,
|
vararg val parents: ObjClass,
|
||||||
) : Obj() {
|
) : Obj() {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
class ObjList(val list: MutableList<Obj>) : Obj() {
|
class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
for (p in objClass.parents)
|
for (p in objClass.parents)
|
||||||
|
@ -16,6 +16,7 @@ data class Pos(val source: Source, val line: Int, val column: Int) {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val builtIn = Pos(Source.builtIn, 0, 0)
|
val builtIn = Pos(Source.builtIn, 0, 0)
|
||||||
|
val UNKNOWN = Pos(Source.UNKNOWN, -1, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,13 @@ class Script(
|
|||||||
raiseError(ObjAssertionError(this,"Assertion failed"))
|
raiseError(ObjAssertionError(this,"Assertion failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addVoidFn("assertEquals") {
|
||||||
|
val a = requiredArg<Obj>(0)
|
||||||
|
val b = requiredArg<Obj>(1)
|
||||||
|
if( a.compareTo(this, b) != 0 )
|
||||||
|
raiseError(ObjAssertionError(this,"Assertion failed: ${a.inspect()} == ${b.inspect()}"))
|
||||||
|
}
|
||||||
|
|
||||||
addVoidFn("delay") {
|
addVoidFn("delay") {
|
||||||
delay((this.args.firstAndOnly().toDouble()/1000.0).roundToLong())
|
delay((this.args.firstAndOnly().toDouble()/1000.0).roundToLong())
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ class Source(val fileName: String, text: String) {
|
|||||||
|
|
||||||
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 startPos: Pos = Pos(this, 0, 0)
|
val startPos: Pos = Pos(this, 0, 0)
|
||||||
|
@ -486,6 +486,136 @@ class ScriptTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAssignArgumentsNoEllipsis() = runTest {
|
||||||
|
// equal args, no ellipsis, no defaults, ok
|
||||||
|
val ttEnd = Token.Type.RBRACE
|
||||||
|
var pa = ArgsDeclaration(listOf(
|
||||||
|
ArgsDeclaration.Item("a"),
|
||||||
|
ArgsDeclaration.Item("b"),
|
||||||
|
ArgsDeclaration.Item("c"),
|
||||||
|
), ttEnd)
|
||||||
|
var c = Context(pos = Pos.builtIn, args = Arguments.from(listOf(1,2,3).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
assertEquals( ObjInt(1), c["a"]?.value)
|
||||||
|
assertEquals( ObjInt(2), c["b"]?.value)
|
||||||
|
assertEquals( ObjInt(3), c["c"]?.value)
|
||||||
|
// less args: error
|
||||||
|
c = Context(pos = Pos.builtIn, args = Arguments.from(listOf(1,2).map { it.toObj() }))
|
||||||
|
assertFailsWith<ScriptError> {
|
||||||
|
pa.assignToContext(c)
|
||||||
|
}
|
||||||
|
// less args, no ellipsis, defaults, ok
|
||||||
|
pa = ArgsDeclaration(listOf(
|
||||||
|
ArgsDeclaration.Item("a"),
|
||||||
|
ArgsDeclaration.Item("b"),
|
||||||
|
ArgsDeclaration.Item("c", defaultValue = statement { ObjInt(100) }),
|
||||||
|
), ttEnd)
|
||||||
|
pa.assignToContext(c)
|
||||||
|
assertEquals( ObjInt(1), c["a"]?.value)
|
||||||
|
assertEquals( ObjInt(2), c["b"]?.value)
|
||||||
|
assertEquals( ObjInt(100), c["c"]?.value)
|
||||||
|
// enough args. default value is ignored:
|
||||||
|
c = Context(pos = Pos.builtIn, args = Arguments.from(listOf(10, 2, 5).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
assertEquals( ObjInt(10), c["a"]?.value)
|
||||||
|
assertEquals( ObjInt(2), c["b"]?.value)
|
||||||
|
assertEquals( ObjInt(5), c["c"]?.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAssignArgumentsEndEllipsis() = runTest {
|
||||||
|
// equal args,
|
||||||
|
// less args, no ellipsis, defaults, ok
|
||||||
|
val ttEnd = Token.Type.RBRACE
|
||||||
|
var pa = ArgsDeclaration(listOf(
|
||||||
|
ArgsDeclaration.Item("a"),
|
||||||
|
ArgsDeclaration.Item("b", isEllipsis = true),
|
||||||
|
), ttEnd)
|
||||||
|
var c = Context(args = Arguments.from(listOf(1,2,3).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assert( a == 1 ); println(b)")
|
||||||
|
c.eval("assert( b == [2,3] )")
|
||||||
|
|
||||||
|
c = Context(args = Arguments.from(listOf(1,2).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assertEquals( a, 1 ); println(b)")
|
||||||
|
c.eval("assertEquals( b, [2] )")
|
||||||
|
|
||||||
|
c = Context(args = Arguments.from(listOf(1).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assert( a == 1 ); println(b)")
|
||||||
|
c.eval("assert( b == [] )")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAssignArgumentsStartEllipsis() = runTest {
|
||||||
|
val ttEnd = Token.Type.RBRACE
|
||||||
|
var pa = ArgsDeclaration(listOf(
|
||||||
|
ArgsDeclaration.Item("a", isEllipsis = true),
|
||||||
|
ArgsDeclaration.Item("b"),
|
||||||
|
ArgsDeclaration.Item("c"),
|
||||||
|
), ttEnd)
|
||||||
|
var c = Context(args = Arguments.from(listOf(0,1,2,3).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assertEquals( a,[0,1] )")
|
||||||
|
c.eval("assertEquals( b, 2 )")
|
||||||
|
c.eval("assertEquals( c, 3 )")
|
||||||
|
|
||||||
|
c = Context(args = Arguments.from(listOf(1,2,3).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assertEquals( a,[1] )")
|
||||||
|
c.eval("assertEquals( b, 2 )")
|
||||||
|
c.eval("assertEquals( c, 3 )")
|
||||||
|
|
||||||
|
c = Context(args = Arguments.from(listOf(2,3).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assertEquals( a,[] )")
|
||||||
|
c.eval("assertEquals( b, 2 )")
|
||||||
|
c.eval("assertEquals( c, 3 )")
|
||||||
|
|
||||||
|
c = Context(args = Arguments.from(listOf(3).map { it.toObj() }))
|
||||||
|
assertFailsWith<ExecutionError> {
|
||||||
|
pa.assignToContext(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAssignArgumentsmiddleEllipsis() = runTest {
|
||||||
|
val ttEnd = Token.Type.RBRACE
|
||||||
|
var pa = ArgsDeclaration(listOf(
|
||||||
|
ArgsDeclaration.Item("i"),
|
||||||
|
ArgsDeclaration.Item("a", isEllipsis = true),
|
||||||
|
ArgsDeclaration.Item("b"),
|
||||||
|
ArgsDeclaration.Item("c"),
|
||||||
|
), ttEnd)
|
||||||
|
var c = Context(args = Arguments.from(listOf(-1,0,1,2,3).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assertEquals( i, -1 )")
|
||||||
|
c.eval("assertEquals( a,[0,1] )")
|
||||||
|
c.eval("assertEquals( b, 2 )")
|
||||||
|
c.eval("assertEquals( c, 3 )")
|
||||||
|
|
||||||
|
c = Context(args = Arguments.from(listOf(0, 1,2,3).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assertEquals( i, 0 )")
|
||||||
|
c.eval("assertEquals( a,[1] )")
|
||||||
|
c.eval("assertEquals( b, 2 )")
|
||||||
|
c.eval("assertEquals( c, 3 )")
|
||||||
|
|
||||||
|
c = Context(args = Arguments.from(listOf(1,2,3).map { it.toObj() }))
|
||||||
|
pa.assignToContext(c)
|
||||||
|
c.eval("assertEquals( i, 1)")
|
||||||
|
c.eval("assertEquals( a,[] )")
|
||||||
|
c.eval("assertEquals( b, 2 )")
|
||||||
|
c.eval("assertEquals( c, 3 )")
|
||||||
|
|
||||||
|
c = Context(args = Arguments.from(listOf(2,3).map { it.toObj() }))
|
||||||
|
assertFailsWith<ExecutionError> {
|
||||||
|
pa.assignToContext(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testWhileBlockIsolation1() = runTest {
|
fun testWhileBlockIsolation1() = runTest {
|
||||||
eval(
|
eval(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user