Loops

Quadrate provides several ways to repeat operations.

for loops

Iterate over a range:

fn main() {
    0 5 1 for i {
        i print nl
    }
    // Output: 0 1 2 3 4
}

The syntax is start end step for <iterator> { body }:

  • start - Initial value (inclusive)
  • end - Final value (exclusive)
  • step - Increment per iteration
  • iterator - A named variable (e.g., i) that holds the current value and is accessible inside the loop body

The range is [start, end) - includes start, excludes end.

for with step

Specify a custom step:

fn main() {
    0 10 2 for i {
        i print nl
    }
    // Output: 0 2 4 6 8
}

Counting down

Use negative step:

fn main() {
    5 0 -1 for i {
        i print nl
    }
    // Output: 5 4 3 2 1
}

Iterating over arrays

Use index-based iteration:

fn main() {
    [1 2 3 4 5] -> arr

    0 arr len 1 for i {
        arr i nth print " " print
    }
    nl
    // Output: 1 2 3 4 5
}

loop - infinite loop

Use loop with break:

fn main() {
    0 -> count
    loop {
        count print nl
        count inc -> count
        count 5 >= if {
            break
        }
    }
    // Output: 0 1 2 3 4
}

while - conditional loop

Loop while a condition is true:

fn main() {
    0 -> count
    count 5 < while {
        count print nl
        count 1 + -> count
        count 5 <  // condition for next iteration
    }
    // Output: 0 1 2 3 4
}

The while pops a condition from the stack. If true, it executes the body. The body must leave a new condition on the stack for the next iteration.

break - exit loop

Exit immediately:

fn main() {
    0 10 1 for i {
        i 5 == if {
            break
        }
        i print nl
    }
    // Output: 0 1 2 3 4
}

continue - skip iteration

Skip to next iteration:

fn main() {
    0 10 1 for i {
        i 2 % 0 == if {
            continue
        }
        i print nl
    }
    // Output: 1 3 5 7 9 (odd numbers only)
}

Nested loops

Loops can be nested:

fn main() {
    1 4 1 for i {
        1 4 1 for j {
            i print " * " print j print " = " print
            i j * print nl
        }
    }
}

Loop with accumulator

Build up a result:

fn sum_to_n(n:i64 -- sum:i64) {
    -> n  // bind parameter
    0 -> sum
    1 n 1 + 1 for i {
        sum i + -> sum
    }
    sum
}

fn main() {
    10 sum_to_n print nl  // 55
}

Finding elements

Search with early exit:

fn contains(arr:ptr value:i64 -- found:i64) {
    -> value -> arr
    0 -> found

    0 arr len 1 for i {
        arr i nth value == if {
            1 -> found
            break
        }
    }
    found
}

fn main() {
    [1 2 3 4 5] 3 contains print nl  // 1
    [1 2 3 4 5] 9 contains print nl  // 0
}

Common patterns

Sum array

fn sum_array(arr:ptr -- total:i64) {
    -> arr  // bind parameter
    0 -> total
    0 arr len 1 for i {
        total arr i nth + -> total
    }
    total
}

Count matches

fn count_positive(arr:ptr -- count:i64) {
    -> arr  // bind parameter
    0 -> count
    0 arr len 1 for i {
        arr i nth 0 > if {
            count 1 + -> count
        }
    }
    count
}

What's next?

Learn about Switch Statements for multi-way branching.