Skip to content

support range-for: for i in lo..hi#200

Merged
kacy merged 1 commit into
mainfrom
feat/range-for
May 23, 2026
Merged

support range-for: for i in lo..hi#200
kacy merged 1 commit into
mainfrom
feat/range-for

Conversation

@kacy
Copy link
Copy Markdown
Owner

@kacy kacy commented May 23, 2026

summary

counted iteration previously meant a manual mut i := 0; while i < n loop or
materializing a list with range(). this adds native range syntax that lowers
to a counted loop with no allocation:

for i in 0..n:      # exclusive, i in [0, n)
for i in 0..=n:     # inclusive, i in [0, n]

bounds may be any Int expression (for i in 1..n + 1:), the optional
value, index binding works (the index is the 0-based position), and break
/ continue behave as in any other loop.

examples/matrix_math.pith is reworked from while counters to range-for as
a worked example (its output snapshot is unchanged).

how

  • lexer: . now lookaheads to emit dotdot (..) and dotdoteq (..=)
  • parser: parse_for_stmt recognizes the range operator in the iterable
    position and builds a range node. range stays scoped to for-iterables for
    now, so the rest of the expression grammar is untouched.
  • checker: a range iterable requires Int bounds and binds the loop
    variable to Int (E217 otherwise)
  • ir emitter: ir_emit_for_stmt detects the range node and emits a counted
    loop directly — init the counter to lo, compare lt/lte against hi,
    bind the loop variable, step by one — reusing the existing break/continue
    label scaffolding.

what was tested

  • new regression tests/cases/test_range_for.pith covering exclusive,
    inclusive, empty (3..3), expression bounds, break/continue, and the
    value, index binding
  • new invalid-checker case invalid_range_bounds asserting E217 on non-Int
    bounds
  • full suite: regressions (93), invalid checker (13), invalid parse (3),
    examples via native and self-hosted compilers (83 each), and bootstrap fixed
    point — all 0 failures

notes

range is intentionally limited to the for-iterable position in this change.
generalizing it to a first-class lazy value belongs with the iterator-protocol
work, which would also let .map().filter() fuse without intermediate lists.

counted iteration previously meant a manual mut i := 0; while i < n loop,
or materializing a list with range(). this adds native range syntax that
lowers to a counted loop with no allocation:

    for i in 0..n:      # exclusive, i in [0, n)
    for i in 0..=n:     # inclusive, i in [0, n]

bounds may be any Int expression, and the optional value, index binding
works too (the index is the 0-based position). break and continue behave
as in any other loop.

the lexer emits dotdot/dotdoteq tokens; the parser recognizes the operator
in the for-iterable position and builds a range node; the checker requires
Int bounds and binds the loop variable to Int; the ir emitter emits the
counted loop directly. matrix_math.pith is reworked to range-for.
@kacy kacy merged commit 0d597e8 into main May 23, 2026
2 checks passed
@kacy kacy deleted the feat/range-for branch May 23, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant