The Scaly Programming Language

Chapter 8

Control Flow

Overview

Conditions and loops are expressions like every other construct: an if with both branches has a value, and a repeat loop answers the operand of the break that ends it. A condition needs no parentheses; a body of one statement needs no braces, a longer one is a block in braces that begins on a line of its own. if cond stmt without an else runs the statement when the condition is true, and control continues after it.

Conditions are written as and/or chains. A null test proves its name for what follows it in the chain: in p <> null and p.x = 7 the right side reads p.x only where p is there.

If Expressions

If expressions evaluate a condition and return one of two values.

Basic If

The if expression takes a boolean condition and two branches.

InputResult
if true : 1 else 21
if false : 1 else 22
if 5 > 3 : 10 else 2010

If with Bindings

If expressions can use values from let bindings.

InputResult
let x 5
if x > 3 : x * 2 else x
10
let a 7
let b 3
if a > b : a else b
7

Else-If Chains without a Final Else

An if statement may chain an else if without a final else. Such a chain yields no value; when no condition holds, the statement falls through and any bindings keep their prior values. (Regression: the emitter used to merge the arms' values into a dead phi node that failed LLVM verification when the inner arm's value was computed inside its own branch.)

InputResult
function clamp(dmin: int) returns int
{
    var adj 7
    if dmin > 100
        adj := 0
    else if dmin > 50
        adj := dmin + 1
    adj
}
clamp(200) * 10000 + clamp(60) * 100 + clamp(10)
6107

While Loops

While loops repeat as long as a condition is true.

Basic While

A while loop evaluates its body repeatedly while the condition is true.

InputResult
var x 0
while x < 3 : x := x + 1
x
3
var x 10
while x < 5 : x := x + 1
x
10

While with Accumulation

While loops can accumulate values across iterations.

InputResult
var sum 0
var i 1
while i <= 3 : { sum := sum + i: i := i + 1 }
sum
6
var result 1
var n 5
while n > 0 : { result := result * n: n := n - 1 }
result
120

For Loops

For loops iterate over a range of integers.

Basic For

A for loop iterates from 0 to n-1 where n is the range expression.

InputResult
var count 0
for i in 3 : count := count + 1
count
3
var x 42
for i in 0 : x := 0
x
42

For with Accumulation

For loops can accumulate values using the loop variable.

InputResult
var sum 0
for i in 5 : sum := sum + i
sum
10
var prod 1
for i in 4 : prod := prod * (i + 1)
prod
24

Break and Continue

Break exits a loop early, continue skips to the next iteration.

Break Statements

Break exits the innermost enclosing loop.

InputResult
var sum 0
for i in 10 : { if i = 3 : break else sum := sum + i }
sum
3
var x 0
while x < 100 : { x := x + 1: if x = 5 : break }
x
5

Continue Statements

Continue skips the rest of the current iteration and continues with the next.

InputResult
var sum 0
for i in 6 : { if i % 2 = 1 : continue else sum := sum + i }
sum
6
var sum 0
var i 0
while i < 10 : { let current i: i := i + 1: if current % 2 = 1 : continue else sum := sum + current }
sum
20

Nested Loops

By default break and continue affect only the innermost loop.

InputResult
var count 0
for i in 3 : { for j in 10 : { if j = 2 : break else count := count + 1 } }
count
6
var count 0
for i in 3 : { for j in 5 : { if j % 2 = 1 : continue else count := count + 1 } }
count
9

Labeled Break and Continue

A loop may carry a label written label NAME after its colon. From within a nested loop, break loop NAME exits the named loop and continue loop NAME jumps to its next iteration, rather than acting on the innermost loop.

InputResult
var count 0
for i in 3 : label outer { for j in 5 : { if j = 2 : break loop outer else count := count + 1 } }
count
2
var count 0
for i in 3 : label outer { for j in 5 : { if j = 0 : continue loop outer else count := count + 100 } }
count
0

Repeat Loops

A repeat loop runs its body forever and exits only through break (or return). Because break is the only way out, a break carrying a value (break v) makes the repeat an expression that yields that value.

Repeat and Break Value

The value of a repeat expression is the operand of the break that exits it.

InputResult
var i 0
let answer repeat { if i = 5 : break i + 100 else i := i + 1 }
answer
105
var i 0
repeat { if i = 3 : break else i := i + 1 }
i
3

Mutable Variables

A binding introduced with var may be assigned a new value; one introduced with let may not. The assignment is written target := source, in the Algol tradition, and is a statement of its own: it introduces no name and is never part of a condition. The equals sign always compares.

Var and Assignment

Var creates a mutable variable, and := assigns it.

InputResult
var x 5
x
5
var x 5
x := 10
x
10
var x 3
x := x + 1
x
4
var a 2
var b 3
a := a * b
a
6

Match

match compares one value against a list of case alternatives and takes the first that is equal; one case may name several values, and else takes the rest. It works on numbers, characters and strings, which it compares by content:


function kind(n: int) returns int
    match n
        case 1: 10
        case 2 case 3: 20
        else 0

let word "b"
match word
    case "a": print "A"
    case "b": print "B"
    else print "?"

A union is matched by its variants with choose, described under Union Types.