fix #16 last-block argument now can be combined with defaults and ellipsis
This commit is contained in:
		
							parent
							
								
									382532e0e1
								
							
						
					
					
						commit
						194fc8aca6
					
				@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
 | 
			
		||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
 | 
			
		||||
 | 
			
		||||
group = "net.sergeych"
 | 
			
		||||
version = "0.3.0-SNAPSHOT"
 | 
			
		||||
version = "0.3.1-SNAPSHOT"
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    repositories {
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
 | 
			
		||||
     */
 | 
			
		||||
    suspend fun assignToContext(
 | 
			
		||||
        context: Context,
 | 
			
		||||
        _fromArgs: Arguments = context.args,
 | 
			
		||||
        arguments: Arguments = context.args,
 | 
			
		||||
        defaultAccessType: AccessType = AccessType.Var,
 | 
			
		||||
        defaultVisibility: Visibility = Visibility.Public
 | 
			
		||||
    ) {
 | 
			
		||||
@ -33,15 +33,25 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // will be used with last lambda arg fix
 | 
			
		||||
        val fromArgs = _fromArgs
 | 
			
		||||
        val callArgs: List<Obj>
 | 
			
		||||
        val paramsSize: Int
 | 
			
		||||
 | 
			
		||||
        if( arguments.tailBlockMode ) {
 | 
			
		||||
            paramsSize = params.size - 1
 | 
			
		||||
            assign(params.last(), arguments.list.last())
 | 
			
		||||
            callArgs = arguments.list.dropLast(1)
 | 
			
		||||
        } else {
 | 
			
		||||
            paramsSize = params.size
 | 
			
		||||
            callArgs = arguments.list
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        suspend fun processHead(index: Int): Int {
 | 
			
		||||
            var i = index
 | 
			
		||||
            while (i != params.size) {
 | 
			
		||||
            while (i != paramsSize) {
 | 
			
		||||
                val a = params[i]
 | 
			
		||||
                if (a.isEllipsis) break
 | 
			
		||||
                val value = when {
 | 
			
		||||
                    i < fromArgs.size -> fromArgs[i]
 | 
			
		||||
                    i < callArgs.size -> callArgs[i]
 | 
			
		||||
                    a.defaultValue != null -> a.defaultValue.execute(context)
 | 
			
		||||
                    else -> context.raiseArgumentError("too few arguments for the call")
 | 
			
		||||
                }
 | 
			
		||||
@ -52,14 +62,14 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        suspend fun processTail(index: Int): Int {
 | 
			
		||||
            var i = params.size - 1
 | 
			
		||||
            var j = fromArgs.size - 1
 | 
			
		||||
            var i = paramsSize - 1
 | 
			
		||||
            var j = callArgs.size - 1
 | 
			
		||||
            while (i > index) {
 | 
			
		||||
                val a = params[i]
 | 
			
		||||
                if (a.isEllipsis) break
 | 
			
		||||
                val value = when {
 | 
			
		||||
                    j >= index -> {
 | 
			
		||||
                        fromArgs[j--]
 | 
			
		||||
                        callArgs[j--]
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    a.defaultValue != null -> a.defaultValue.execute(context)
 | 
			
		||||
@ -74,16 +84,16 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
 | 
			
		||||
        fun processEllipsis(index: Int, toFromIndex: Int) {
 | 
			
		||||
            val a = params[index]
 | 
			
		||||
            val l = if (index > toFromIndex) ObjList()
 | 
			
		||||
            else ObjList(fromArgs.list.subList(index, toFromIndex + 1).toMutableList())
 | 
			
		||||
            else ObjList(callArgs.subList(index, toFromIndex + 1).toMutableList())
 | 
			
		||||
            assign(a, l)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val leftIndex = processHead(0)
 | 
			
		||||
        if (leftIndex < params.size) {
 | 
			
		||||
        if (leftIndex < paramsSize) {
 | 
			
		||||
            val end = processTail(leftIndex)
 | 
			
		||||
            processEllipsis(leftIndex, end)
 | 
			
		||||
        } else {
 | 
			
		||||
            if (leftIndex < fromArgs.size)
 | 
			
		||||
            if (leftIndex < callArgs.size)
 | 
			
		||||
                context.raiseArgumentError("too many arguments for the call")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
data class ParsedArgument(val value: Statement, val pos: Pos, val isSplat: Boolean = false)
 | 
			
		||||
 | 
			
		||||
suspend fun Collection<ParsedArgument>.toArguments(context: Context): Arguments {
 | 
			
		||||
suspend fun Collection<ParsedArgument>.toArguments(context: Context,tailBlockMode: Boolean): Arguments {
 | 
			
		||||
    val list = mutableListOf<Obj>()
 | 
			
		||||
 | 
			
		||||
    for (x in this) {
 | 
			
		||||
@ -23,10 +23,10 @@ suspend fun Collection<ParsedArgument>.toArguments(context: Context): Arguments
 | 
			
		||||
        } else
 | 
			
		||||
            list.add(value)
 | 
			
		||||
    }
 | 
			
		||||
    return Arguments(list)
 | 
			
		||||
    return Arguments(list,tailBlockMode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
data class Arguments(val list: List<Obj>) : List<Obj> by list {
 | 
			
		||||
data class Arguments(val list: List<Obj>,val tailBlockMode: Boolean = false) : List<Obj> by list {
 | 
			
		||||
 | 
			
		||||
    fun firstAndOnly(pos: Pos = Pos.UNKNOWN): Obj {
 | 
			
		||||
        if (list.size != 1) throw ScriptError(pos, "expected one argument, got ${list.size}")
 | 
			
		||||
 | 
			
		||||
@ -149,7 +149,7 @@ class Compiler(
 | 
			
		||||
                                            v.invokeInstanceMethod(
 | 
			
		||||
                                                context,
 | 
			
		||||
                                                next.value,
 | 
			
		||||
                                                args.toArguments(context)
 | 
			
		||||
                                                args.toArguments(context,false)
 | 
			
		||||
                                            ), isMutable = false
 | 
			
		||||
                                        )
 | 
			
		||||
                                    }
 | 
			
		||||
@ -157,7 +157,7 @@ class Compiler(
 | 
			
		||||
 | 
			
		||||
                                Token.Type.LBRACE -> {
 | 
			
		||||
                                    // single lambda arg, like assertTrows { ... }
 | 
			
		||||
                                    cc.next()
 | 
			
		||||
                                   cc.next()
 | 
			
		||||
                                    isCall = true
 | 
			
		||||
                                    val lambda =
 | 
			
		||||
                                        parseExpression(cc) ?: throw ScriptError(t.pos, "expected valid lambda here")
 | 
			
		||||
@ -170,7 +170,7 @@ class Compiler(
 | 
			
		||||
                                            v.invokeInstanceMethod(
 | 
			
		||||
                                                context,
 | 
			
		||||
                                                next.value,
 | 
			
		||||
                                                Arguments(listOf(lambda))
 | 
			
		||||
                                                Arguments(listOf(lambda),true)
 | 
			
		||||
                                            ), isMutable = false
 | 
			
		||||
                                        )
 | 
			
		||||
                                    }
 | 
			
		||||
@ -611,7 +611,7 @@ class Compiler(
 | 
			
		||||
            v.value.callOn(
 | 
			
		||||
                context.copy(
 | 
			
		||||
                    context.pos,
 | 
			
		||||
                    args.toArguments(context)
 | 
			
		||||
                    args.toArguments(context, blockArgument)
 | 
			
		||||
//                Arguments(
 | 
			
		||||
//                    args.map { Arguments.Info((it.value as Statement).execute(context), it.pos) }
 | 
			
		||||
//                ),
 | 
			
		||||
 | 
			
		||||
@ -1585,16 +1585,59 @@ class ScriptTest {
 | 
			
		||||
        assertEquals("1.0E-6", eval("1e-6").toString())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    @Test
 | 
			
		||||
//    fun testLambdaLastArgAfterDetault() = runTest {
 | 
			
		||||
//        val c = Context()
 | 
			
		||||
//        eval("""
 | 
			
		||||
//            // this means last is lambda:
 | 
			
		||||
//            fun f(e=1, f) {
 | 
			
		||||
//                "e="+e+"f="+f()
 | 
			
		||||
//            }
 | 
			
		||||
//            assertEquals("e=1f=xx", f { "xx" })
 | 
			
		||||
//        """.trimIndent())
 | 
			
		||||
//
 | 
			
		||||
//    }
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testCallLastBlockAfterDetault() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
            // this means last is lambda:
 | 
			
		||||
            fun f(e=1, f) {
 | 
			
		||||
                "e="+e+"f="+f()
 | 
			
		||||
            }
 | 
			
		||||
            assertEquals("e=1f=xx", f { "xx" })
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testCallLastBlockWithEllipsis() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
            // this means last is lambda:
 | 
			
		||||
            fun f(e..., f) {
 | 
			
		||||
                "e="+e+"f="+f()
 | 
			
		||||
            }
 | 
			
		||||
            assertEquals("e=[]f=xx", f { "xx" })
 | 
			
		||||
            assertEquals("e=[1, 2]f=xx", f(1,2) { "xx" })
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testMethodCallLastBlockAfterDefault() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
            class Foo {
 | 
			
		||||
                // this means last is lambda:
 | 
			
		||||
                fun f(e=1, f) {
 | 
			
		||||
                    "e="+e+"f="+f()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            val f = Foo()
 | 
			
		||||
            assertEquals("e=1f=xx", f.f { "xx" })
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testMethodCallLastBlockWithEllipsis() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
            class Foo {
 | 
			
		||||
                // this means last is lambda:
 | 
			
		||||
                fun f(e..., f) {
 | 
			
		||||
                    "e="+e+"f="+f()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            val f = Foo()
 | 
			
		||||
            assertEquals("e=[]f=xx", f.f { "xx" })
 | 
			
		||||
            assertEquals("e=[1, 2]f=xx", f.f(1,2) { "xx" })
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user