Skip to content

M3: Ranges (infix <-, inclusive, 4<-1 descends)#34

Merged
assapir merged 1 commit into
mainfrom
worktree-agent-a2a218286a37cdea3
Jun 27, 2026
Merged

M3: Ranges (infix <-, inclusive, 4<-1 descends)#34
assapir merged 1 commit into
mainfrom
worktree-agent-a2a218286a37cdea3

Conversation

@assapir

@assapir assapir commented Jun 27, 2026

Copy link
Copy Markdown
Owner

M3: Ranges via infix <-

Adds an infix range operator <- that materializes an inclusive []Num:

  • 1 <- 4[1, 2, 3, 4]
  • 4 <- 1[4, 3, 2, 1] (descends when the left end is larger)
  • 5 <- 5[5]

It is pure array sugar — there is no distinct Range type. The result is a []Num, so it composes with .size, indexing [i], and for loops.

Implementation (localized to the new precedence level + a checker arm + range codegen)

  • Lexer: reuses the existing LeftArrow token — no new token.
  • Parser: new non-associative parse_range level between comparison and pipeline. The for header still consumes its own <- in parse_for_loop, so for n <- coll parses exactly as before (regression-tested).
  • AST: new Expr::Range { start, end, span } (+ span() arm).
  • Type checker: Num <- Num → []Num.
  • Codegen: generate_range emits the shared {ptr, size} array shape with a runtime fill loop; element count |hi - lo| + 1 and ascending/descending direction are decided at runtime (ends may be dynamic). Backing storage is GC-allocated (__alloc) so the array may safely escape the frame.

Coexistence

The pre-existing for n <- collection => body loop is unchanged. The infix range only applies in general expression position (between two value expressions); the for header's <- is parsed separately. Both forms are covered by tests.

Tests & docs

  • examples/ranges.ql (exit code 14), wired into tests/examples_test.rs — runs under both JIT and native AOT (clang + gcc).
  • tests/ranges_test.rs: (1<-4).size == 4, single-point, ascending values, descending order, dynamic ends, range drives a for loop, and for n <- [...] still runs.
  • Parser unit tests: infix <- parses as Expr::Range; for header still parses as ForLoop.
  • LANGUAGE.md: symbol table, prose section, and feature matrix.

Gate

cargo build, cargo test (incl. native-AOT examples gate with clang+gcc), cargo fmt --check, cargo clippy --all-targets -- -D warnings — all green. Ran /code-review and /simplify; addressed findings (reused ptr_len_struct_type, collapsed a redundant subtraction, trimmed docs/tests). The doc-comment overstatement flagged by review was corrected; numeric-edge findings (f64 truncation, NaN/overflow) were left as-is for consistency with the language's unguarded f64-everywhere 0.9 core.

🤖 Generated with Claude Code

Add an infix range operator `<-` that materializes an inclusive `[]Num`:
`1 <- 4` -> [1,2,3,4]; `4 <- 1` descends to [4,3,2,1]. It is pure array
sugar — no distinct Range type — so the result composes with `.size`,
indexing, and `for` loops.

- Lexer: reuses the existing `LeftArrow` token (no new token).
- Parser: a new non-associative `parse_range` precedence level between
  comparison and pipeline. The `for` header keeps consuming its own `<-`
  in `parse_for_loop`, so `for n <- coll` is unaffected (regression-tested).
- AST: new `Expr::Range { start, end, span }`.
- Type checker: `Num <- Num -> []Num`.
- Codegen: `generate_range` emits the `{ptr, size}` array shape with a
  runtime fill loop; element count `|hi - lo| + 1` and direction are decided
  at runtime (ends may be dynamic). Backing store is GC-allocated so the
  array may safely escape the frame.

Ships `examples/ranges.ql` (wired into the JIT + native-AOT examples gate),
`tests/ranges_test.rs`, parser unit tests, and LANGUAGE.md docs (symbol
table, prose, feature matrix).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@assapir assapir merged commit 58f06af into main Jun 27, 2026
2 checks passed
@assapir assapir deleted the worktree-agent-a2a218286a37cdea3 branch June 27, 2026 14:22
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