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