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 {
 | 
			
		||||
        val EMPTY = Arguments(emptyList())
 | 
			
		||||
        fun from(values: Collection<Obj>) = Arguments(values.map { Info(it, Pos.UNKNOWN) })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun iterator(): Iterator<Obj> {
 | 
			
		||||
 | 
			
		||||
@ -347,22 +347,8 @@ class Compiler(
 | 
			
		||||
                }
 | 
			
		||||
                context.addItem("it", false, itValue)
 | 
			
		||||
            } else {
 | 
			
		||||
                // assign vars as declared
 | 
			
		||||
                if (args.size != argsDeclaration.args.size && !argsDeclaration.args.last().isEllipsis)
 | 
			
		||||
                    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)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                // assign vars as declared the standard way
 | 
			
		||||
                argsDeclaration.assignToContext(context)
 | 
			
		||||
            }
 | 
			
		||||
            body.execute(context)
 | 
			
		||||
        }
 | 
			
		||||
@ -411,29 +397,12 @@ class Compiler(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum class AccessType {
 | 
			
		||||
        Val, Var, Default
 | 
			
		||||
    enum class AccessType(val isMutable: Boolean) {
 | 
			
		||||
        Val(false), Var(true), Initialization(false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum class Visibility {
 | 
			
		||||
        Default, 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")
 | 
			
		||||
        }
 | 
			
		||||
        Public, Private, Protected, Internal
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -441,7 +410,7 @@ class Compiler(
 | 
			
		||||
     * @return declaration or null if there is no valid list of arguments
 | 
			
		||||
     */
 | 
			
		||||
    private fun parseArgsDeclaration(cc: CompilerContext, isClassDeclaration: Boolean = false): ArgsDeclaration? {
 | 
			
		||||
        val result = mutableListOf<ArgVar>()
 | 
			
		||||
        val result = mutableListOf<ArgsDeclaration.Item>()
 | 
			
		||||
        var endTokenType: Token.Type? = null
 | 
			
		||||
        val startPos = cc.savePos()
 | 
			
		||||
 | 
			
		||||
@ -484,7 +453,7 @@ class Compiler(
 | 
			
		||||
                            Visibility.Public
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        else -> Visibility.Default
 | 
			
		||||
                        else -> null
 | 
			
		||||
                    }
 | 
			
		||||
                    // val/var?
 | 
			
		||||
                    val access = when (t.value) {
 | 
			
		||||
@ -504,7 +473,7 @@ class Compiler(
 | 
			
		||||
                            AccessType.Var
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        else -> AccessType.Default
 | 
			
		||||
                        else -> null
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var defaultValue: Statement? = null
 | 
			
		||||
@ -514,7 +483,15 @@ class Compiler(
 | 
			
		||||
                    // type information
 | 
			
		||||
                    val typeInfo = parseTypeDeclaration(cc)
 | 
			
		||||
                    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 ')'
 | 
			
		||||
                    // otherwise it is not an argument list:
 | 
			
		||||
@ -714,24 +691,45 @@ class Compiler(
 | 
			
		||||
    private fun parseClassDeclaration(cc: CompilerContext, isStruct: Boolean): Statement {
 | 
			
		||||
        val nameToken = cc.requireToken(Token.Type.ID)
 | 
			
		||||
        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)
 | 
			
		||||
        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
 | 
			
		||||
        }
 | 
			
		||||
            TODO("parse body")
 | 
			
		||||
        } else null
 | 
			
		||||
 | 
			
		||||
        // create class
 | 
			
		||||
        val className = nameToken.value
 | 
			
		||||
        lateinit var classContext: Context
 | 
			
		||||
 | 
			
		||||
//        val constructorCode = statement {
 | 
			
		||||
//            val classContext = copy()
 | 
			
		||||
//        }
 | 
			
		||||
        val defaultAccess = if (isStruct) AccessType.Var else AccessType.Initialization
 | 
			
		||||
        val defaultVisibility = Visibility.Public
 | 
			
		||||
 | 
			
		||||
        // create instance constructor
 | 
			
		||||
        // create custom objClass with all fields and instance constructor
 | 
			
		||||
 | 
			
		||||
        val newClass = ObjClass(className, parsedArgs?.args ?: emptyList())
 | 
			
		||||
//        statement {
 | 
			
		||||
//            addConst(nameToken.value, )
 | 
			
		||||
//        }
 | 
			
		||||
//        }
 | 
			
		||||
        val constructorCode = statement {
 | 
			
		||||
            // constructor code is registered with class instance and is called over
 | 
			
		||||
            // 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()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -65,6 +65,9 @@ class Context(
 | 
			
		||||
    fun copy(pos: Pos, args: Arguments = Arguments.EMPTY,newThisObj: Obj? = null): Context =
 | 
			
		||||
        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 addItem(name: String, isMutable: Boolean, value: Obj?): StoredObj {
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ val ObjClassType by lazy { ObjClass("Class") }
 | 
			
		||||
 | 
			
		||||
class ObjClass(
 | 
			
		||||
    val className: String,
 | 
			
		||||
    val constructorArgs: List<Compiler.ArgVar> = emptyList(),
 | 
			
		||||
    val constructorArgs: List<ArgsDeclaration.Item> = emptyList(),
 | 
			
		||||
    vararg val parents: ObjClass,
 | 
			
		||||
) : Obj() {
 | 
			
		||||
    constructor(
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
class ObjList(val list: MutableList<Obj>) : Obj() {
 | 
			
		||||
class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        for (p in objClass.parents)
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@ data class Pos(val source: Source, val line: Int, val column: Int) {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        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"))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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") {
 | 
			
		||||
                delay((this.args.firstAndOnly().toDouble()/1000.0).roundToLong())
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ class Source(val fileName: String, text: String) {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val builtIn: Source by lazy { Source("built-in", "") }
 | 
			
		||||
        val UNKNOWN: Source by lazy { Source("UNKNOWN", "") }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    fun testWhileBlockIsolation1() = runTest {
 | 
			
		||||
        eval(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user