fixed many bugs in closures processing also in flows
This commit is contained in:
		
							parent
							
								
									9aae33d564
								
							
						
					
					
						commit
						e0ed27a01f
					
				@ -205,6 +205,20 @@ open class Scope(
 | 
			
		||||
        return "S[this=$thisObj $contents]"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun trace(text: String="") {
 | 
			
		||||
        println("trace Scope: $text ------------------")
 | 
			
		||||
        var p = this.parent
 | 
			
		||||
        var level = 0
 | 
			
		||||
        while (p != null) {
 | 
			
		||||
            println("     parent#${++level}: $p")
 | 
			
		||||
            println("     ( ${p.args.list} )")
 | 
			
		||||
            p = p.parent
 | 
			
		||||
        }
 | 
			
		||||
        println("--------------------")
 | 
			
		||||
        ObjVoid
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
 | 
			
		||||
        fun new(): Scope =
 | 
			
		||||
 | 
			
		||||
@ -26,8 +26,15 @@ class Script(
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
 | 
			
		||||
        private val rootScope: Scope = Scope(null).apply {
 | 
			
		||||
        internal val rootScope: Scope = Scope(null).apply {
 | 
			
		||||
            ObjException.addExceptionsToContext(this)
 | 
			
		||||
            addFn("print") {
 | 
			
		||||
                for ((i, a) in args.withIndex()) {
 | 
			
		||||
                    if (i > 0) print(' ' + a.asStr.value)
 | 
			
		||||
                    else print(a.asStr.value)
 | 
			
		||||
                }
 | 
			
		||||
                ObjVoid
 | 
			
		||||
            }
 | 
			
		||||
            addFn("println") {
 | 
			
		||||
                for ((i, a) in args.withIndex()) {
 | 
			
		||||
                    if (i > 0) print(' ' + a.asStr.value)
 | 
			
		||||
@ -153,16 +160,26 @@ class Script(
 | 
			
		||||
                }
 | 
			
		||||
                result ?: raiseError(ObjAssertionFailedException(this,"Expected exception but nothing was thrown"))
 | 
			
		||||
            }
 | 
			
		||||
            addFn("traceScope") {
 | 
			
		||||
                println("trace Scope: $this")
 | 
			
		||||
                var p = this.parent
 | 
			
		||||
                var level = 0
 | 
			
		||||
                while (p != null) {
 | 
			
		||||
                    println("     parent#${++level}: $p")
 | 
			
		||||
                    p = p.parent
 | 
			
		||||
            addFn("require") {
 | 
			
		||||
                val condition = requiredArg<ObjBool>(0)
 | 
			
		||||
                if( !condition.value ) {
 | 
			
		||||
                    val message = args.list.getOrNull(1)?.toString() ?: "requirement not met"
 | 
			
		||||
                    raiseIllegalArgument(message)
 | 
			
		||||
                }
 | 
			
		||||
                ObjVoid
 | 
			
		||||
            }
 | 
			
		||||
            addFn("check") {
 | 
			
		||||
                val condition = requiredArg<ObjBool>(0)
 | 
			
		||||
                if( !condition.value ) {
 | 
			
		||||
                    val message = args.list.getOrNull(1)?.toString() ?: "check failed"
 | 
			
		||||
                    raiseIllegalState(message)
 | 
			
		||||
                }
 | 
			
		||||
                ObjVoid
 | 
			
		||||
            }
 | 
			
		||||
            addFn("traceScope") {
 | 
			
		||||
                this.trace(args.get(0)?.toString() ?: "")
 | 
			
		||||
                ObjVoid
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            addVoidFn("delay") {
 | 
			
		||||
                delay((this.args.firstAndOnly().toDouble()/1000.0).roundToLong())
 | 
			
		||||
@ -204,7 +221,9 @@ class Script(
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            addFn("flow") {
 | 
			
		||||
                ObjFlow(requireOnlyArg<Statement>())
 | 
			
		||||
                // important is: current context contains closure often used in call;
 | 
			
		||||
                // we'll need it for the producer
 | 
			
		||||
                ObjFlow(requireOnlyArg<Statement>(), this)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val pi = ObjReal(PI)
 | 
			
		||||
 | 
			
		||||
@ -7,9 +7,7 @@ import kotlinx.coroutines.channels.ReceiveChannel
 | 
			
		||||
import kotlinx.coroutines.channels.SendChannel
 | 
			
		||||
import kotlinx.coroutines.sync.Mutex
 | 
			
		||||
import kotlinx.coroutines.sync.withLock
 | 
			
		||||
import net.sergeych.lyng.Scope
 | 
			
		||||
import net.sergeych.lyng.ScriptFlowIsNoMoreCollected
 | 
			
		||||
import net.sergeych.lyng.Statement
 | 
			
		||||
import net.sergeych.lyng.*
 | 
			
		||||
import net.sergeych.mp_tools.globalLaunch
 | 
			
		||||
import kotlin.coroutines.cancellation.CancellationException
 | 
			
		||||
 | 
			
		||||
@ -60,7 +58,7 @@ private fun createLyngFlowInput(scope: Scope, producer: Statement): ReceiveChann
 | 
			
		||||
    return channel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ObjFlow(val producer: Statement) : Obj() {
 | 
			
		||||
class ObjFlow(val producer: Statement, val scope: Scope) : Obj() {
 | 
			
		||||
 | 
			
		||||
    override val objClass = type
 | 
			
		||||
 | 
			
		||||
@ -71,7 +69,8 @@ class ObjFlow(val producer: Statement) : Obj() {
 | 
			
		||||
            }
 | 
			
		||||
        }.apply {
 | 
			
		||||
            addFn("iterator") {
 | 
			
		||||
                ObjFlowIterator(thisAs<ObjFlow>().producer)
 | 
			
		||||
                val objFlow = thisAs<ObjFlow>()
 | 
			
		||||
                ObjFlowIterator( statement { objFlow.producer.execute(ClosureScope(this,objFlow.scope)) } )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -111,6 +111,5 @@ val ObjIterable by lazy {
 | 
			
		||||
                    .not()
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,5 @@
 | 
			
		||||
package net.sergeych.lyng.stdlib_included
 | 
			
		||||
 | 
			
		||||
internal val rootLyng = """
 | 
			
		||||
    
 | 
			
		||||
""".trimIndent()
 | 
			
		||||
							
								
								
									
										16
									
								
								lynglib/src/commonMain/lyng/stdlib/Iterable.lyng
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lynglib/src/commonMain/lyng/stdlib/Iterable.lyng
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
 | 
			
		||||
fun Iterable.filter( predicate ) {
 | 
			
		||||
    flow {
 | 
			
		||||
        for( item in this )
 | 
			
		||||
            if( predicate(item) )
 | 
			
		||||
                emit(item)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun Iterable.drop(n) {
 | 
			
		||||
    require( n >= 0, "drop amount must be non-negative")
 | 
			
		||||
    var count = 0
 | 
			
		||||
    filter {
 | 
			
		||||
        count++ < N
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -106,4 +106,67 @@ class TestCoroutines {
 | 
			
		||||
                assertEquals( result, f.toList())
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testFlowClosures() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
            fun filter( a, b ) {
 | 
			
		||||
                println("filter: %s, %s"(a,b))
 | 
			
		||||
                flow {
 | 
			
		||||
                    emit(a)
 | 
			
		||||
                    emit(b)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            assertEquals( [5, 1], filter(5,1).toList() )
 | 
			
		||||
            assertEquals( [2, 3], filter(2,3).toList() )
 | 
			
		||||
            
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testFilterFlow() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
            fun filter( list, predicate ) {
 | 
			
		||||
                val p = predicate
 | 
			
		||||
                println("predicate "+predicate+" / "+p)
 | 
			
		||||
                flow {
 | 
			
		||||
                    // here p is captured only once and does not change!
 | 
			
		||||
                    for( item in list ) {
 | 
			
		||||
                        print("filter "+p+" "+item+": ")
 | 
			
		||||
                        if( p(item) ) {
 | 
			
		||||
                            println("OK")
 | 
			
		||||
                            emit(item)
 | 
			
		||||
                        }
 | 
			
		||||
                        else println("NO")
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
//            fun drop(i, n) {
 | 
			
		||||
//                require( n >= 0, "drop amount must be non-negative")
 | 
			
		||||
//                var count = 0
 | 
			
		||||
//                println("drop %d"(n))
 | 
			
		||||
//                filter(i) {
 | 
			
		||||
//                    count++ >= n
 | 
			
		||||
//                }
 | 
			
		||||
//            }
 | 
			
		||||
            
 | 
			
		||||
            val src = (1..1).toList()
 | 
			
		||||
            assertEquals( 1, filter(src) { true }.toList().size )
 | 
			
		||||
            println("----------------------------------------------------------")
 | 
			
		||||
            println("----------------------------------------------------------")
 | 
			
		||||
            println("----------------------------------------------------------")
 | 
			
		||||
            println("----------------------------------------------------------")
 | 
			
		||||
            assertEquals( 0, filter(src) { false }.toList().size )
 | 
			
		||||
//            assertEquals( 3, filter(src) { true }.size() ) 
 | 
			
		||||
            
 | 
			
		||||
//            assertEquals( [7,8], drop((1..8).toList(),6).toList())
 | 
			
		||||
//            assertEquals( [1,3,5,7], filter((1..8).toList()) { 
 | 
			
		||||
//                println("call2")
 | 
			
		||||
//                it % 2 == 1 
 | 
			
		||||
//            }.toList())
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user