while/else practical sample
!fixed else-while not calling on never run loop bug
This commit is contained in:
		
							parent
							
								
									25ace7370b
								
							
						
					
					
						commit
						3cd2786ef0
					
				@ -572,17 +572,15 @@ We can skip the rest of the loop and restart it, as usual, with `continue` opera
 | 
			
		||||
    "found even numbers: " + countEven
 | 
			
		||||
    >>> "found even numbers: 5"
 | 
			
		||||
 | 
			
		||||
`continue` can't "return" anything: it just restarts the loop. It can use labeled loops to restart outer ones:
 | 
			
		||||
`continue` can't "return" anything: it just restarts the loop. It can use labeled loops to restart outer ones (we intentionally avoid using for loops here):
 | 
			
		||||
 | 
			
		||||
    var count = 0
 | 
			
		||||
    var total = 0
 | 
			
		||||
    // notice the label:
 | 
			
		||||
    outerLoop@ while( count < 5 ) {
 | 
			
		||||
        count = count + 1
 | 
			
		||||
    outerLoop@ while( count++ < 5 ) {
 | 
			
		||||
        var innerCount = 0
 | 
			
		||||
        while( innerCount < 10 ) {
 | 
			
		||||
            innerCount = innerCount + 1
 | 
			
		||||
            if( innerCount == 10 )
 | 
			
		||||
            if( ++innerCount == 10 )
 | 
			
		||||
                continue@outerLoop
 | 
			
		||||
        }
 | 
			
		||||
        // we don't reach it because continue above restarts our loop
 | 
			
		||||
@ -600,6 +598,20 @@ The while and for loops can be followed by the else block, which is executed whe
 | 
			
		||||
ends normally, without breaks. It allows override loop result value, for example,
 | 
			
		||||
to not calculate it in every iteration. See for loop example just below.
 | 
			
		||||
 | 
			
		||||
    fun naive_is_prime(candidate) {
 | 
			
		||||
        val x = if( candidate !is Int) candidate.toInt() else candidate
 | 
			
		||||
        var divisor = 1
 | 
			
		||||
        while( ++divisor < x/2 || divisor == 2 ) {
 | 
			
		||||
            if( x % divisor == 0 ) break false
 | 
			
		||||
        }
 | 
			
		||||
        else true
 | 
			
		||||
    }
 | 
			
		||||
    assert( !naive_is_prime(16) )
 | 
			
		||||
    assert( naive_is_prime(17) )
 | 
			
		||||
    assert( naive_is_prime(3) )
 | 
			
		||||
    assert( !naive_is_prime(4) )
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
## Loop return value diagram
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
 | 
			
		||||
@ -753,23 +753,25 @@ class Compiler(
 | 
			
		||||
        }
 | 
			
		||||
        return statement(body.pos) {
 | 
			
		||||
            var result: Obj = ObjVoid
 | 
			
		||||
            var wasBroken = false
 | 
			
		||||
            while (condition.execute(it).toBool()) {
 | 
			
		||||
                try {
 | 
			
		||||
                    // we don't need to create new context here: if body is a block,
 | 
			
		||||
                    // parse block will do it, otherwise single statement doesn't need it:
 | 
			
		||||
                    result = body.execute(it)
 | 
			
		||||
                    elseStatement?.let { s -> result = s.execute(it) }
 | 
			
		||||
                } catch (lbe: LoopBreakContinueException) {
 | 
			
		||||
                    if (lbe.label == label || lbe.label == null) {
 | 
			
		||||
                        if (lbe.doContinue) continue
 | 
			
		||||
                        else {
 | 
			
		||||
                            result = lbe.result
 | 
			
		||||
                            wasBroken = true
 | 
			
		||||
                            break
 | 
			
		||||
                        }
 | 
			
		||||
                    } else
 | 
			
		||||
                        throw lbe
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if( !wasBroken ) elseStatement?.let { s -> result = s.execute(it) }
 | 
			
		||||
            result
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1041,7 +1041,8 @@ class ScriptTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testLambdaWithIt1() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
        eval(
 | 
			
		||||
            """
 | 
			
		||||
            val x = {
 | 
			
		||||
                it + "!" 
 | 
			
		||||
            }
 | 
			
		||||
@ -1050,43 +1051,51 @@ class ScriptTest {
 | 
			
		||||
            assert( x is Callable)
 | 
			
		||||
            assert(y == "OK")
 | 
			
		||||
            assert( x("hello") == "hello!")
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
        """.trimIndent()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testLambdaWithIt2() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
        eval(
 | 
			
		||||
            """
 | 
			
		||||
            val x = {
 | 
			
		||||
                assert(it == void)
 | 
			
		||||
            }
 | 
			
		||||
            assert( x() == void)
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
        """.trimIndent()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testLambdaWithIt3() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
        eval(
 | 
			
		||||
            """
 | 
			
		||||
            val x = {
 | 
			
		||||
                assert( it == [1,2,"end"])
 | 
			
		||||
            }
 | 
			
		||||
            println("0----")
 | 
			
		||||
            assert( x(1, 2, "end") == void)
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
        """.trimIndent()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testLambdaWithArgs() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
        eval(
 | 
			
		||||
            """
 | 
			
		||||
            val x = { x, y, z ->
 | 
			
		||||
                assert( [x, y, z] == [1,2,"end"])
 | 
			
		||||
            }
 | 
			
		||||
            assert( x(1, 2, "end") == void)
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
        """.trimIndent()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testLambdaWithArgsEllipsis() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
        eval(
 | 
			
		||||
            """
 | 
			
		||||
            val x = { x, y... ->
 | 
			
		||||
                println("-- y=",y)
 | 
			
		||||
                println(":: "+y::class)
 | 
			
		||||
@ -1094,7 +1103,8 @@ class ScriptTest {
 | 
			
		||||
            }
 | 
			
		||||
            assert( x(1, 2, "end") == void)
 | 
			
		||||
            assert( x(1, ...[2, "end"]) == void)
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
        """.trimIndent()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@ -1111,4 +1121,36 @@ class ScriptTest {
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testWhileExecuteElseIfNotExecuted() = runTest {
 | 
			
		||||
        assertEquals(
 | 
			
		||||
            "ok",
 | 
			
		||||
            eval(
 | 
			
		||||
                """
 | 
			
		||||
                while( 5 < 1 ) {
 | 
			
		||||
                    "bad"
 | 
			
		||||
                } else "ok"
 | 
			
		||||
        """.trimIndent()
 | 
			
		||||
            ).toString()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testIsPrimeSampleBug() = runTest {
 | 
			
		||||
        eval("""
 | 
			
		||||
                fun naive_is_prime(candidate) {
 | 
			
		||||
                    val x = if( candidate !is Int) candidate.toInt() else candidate
 | 
			
		||||
                    var divisor = 1
 | 
			
		||||
                    println("start with ",x)
 | 
			
		||||
                    while( ++divisor < x/2 && divisor != 2 ) {
 | 
			
		||||
                        println("x=", x, " // ", divisor, " :: ", x % divisor)
 | 
			
		||||
                        if( x % divisor == 0 ) break false
 | 
			
		||||
                    }
 | 
			
		||||
                    else true
 | 
			
		||||
                }
 | 
			
		||||
                naive_is_prime(4)
 | 
			
		||||
    
 | 
			
		||||
        """.trimIndent())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user