## Remaining `for` iteration statements

**Priority:** P2
**Status:** wip — classic `for` and generic `for…of` syntax are implemented.
FunctionalScript admission of `for…of` and `for…in` remains open.
Admitting either remaining form is a
language change that needs formal language-design approval first
([DESIGN.md §12](../../doc/DESIGN.md#12-preserve-harmless-javascript-conventions))

### Problem

The compiler admits classic `for (init; condition; step)` and `for (;;)`
through the implemented [loop contract](../control-flow/loops/README.md).
Iteration forms remain separate language extensions. This issue owns them.
The generic syntax AST can represent a form before FunctionalScript admits it;
the dependency graph needs that boundary even for modules that cannot compile.
They were the most common first refusal:
at `442ea8f`, 43 of the 279 refused modules stop at a `for`, 18 of them among
the 98 the self-hosting loader depends on
([where self-hosting stands](../../nanvm/lib/todo/mvp-roadmap.md#where-self-hosting-stands)).
At that revision, the authored `module.f.mjs` files held 126 `for` statements
in 60 files, in three forms:

| Count | Form | Example |
| ---: | --- | --- |
| 93 | `for…of` | `for (const item of items) { … }` (`fjs/edag/value/array`) |
| 30 | a counting loop | `for (let i = 0; i < source.length; i++) { … }` (`fjs/compiler/tokenizer`) |
| 3 | `for (;;)` | `for (;;) { … }` (`fjs/js/tokenizer`) |

Many of their bodies use what general loops add — `break`, `continue`, a
`return` inside the loop, more than one variable — and every form lowers to a
loop, so the forms build on the completed
[loop integration](../../fjs/compiler/architecture.md#loop-integration).

### Proposal (sketch)

Each form is surface syntax over the admitted general `while`, with no new
EDAG node.

- Implemented: `for (;;) { … }` is `while (true) { … }`.
- Implemented: `for (let i = a; c; u) { … }` is `let i = a; while (c) { …; u }`, with
  `continue` running `u` before the test and `i` scoped to the loop.
  JavaScript gives each iteration a fresh `i`, which a function captures; the
  write-based [capture rule](../bindings/variables/README.md#capture-compatibility) refuses a
  capture of a reassigned variable, so that difference is refused rather than
  answered differently. Compound assignments such as `i += 1` are admitted;
  `i++` and `i--` remain part of [assignments](./3430-assignments.md).
  Empty clauses, initialized `const` declarations, assignment and call
  initializers, and assignment and call steps use the same lowering.
- `for (const x of a) { … }` over an array is an index loop over `a`, whose
  length cannot change. The open question is everything else: over a string
  JavaScript visits code points, not code units, and over any other value it
  calls `Symbol.iterator`, a generator included (`fjs/types/list`'s
  `iterable`). Which kinds the form admits, and whether a kind known only at
  run time is refused there, is the decision this form needs.

### Benefits and drawbacks

Benefits: `for…of` and the counting loop are the ordinary JavaScript
spellings of the loops the standard modules write, and the largest group of
first refusals; each form lowers onto the existing structured loop.

Drawbacks: three more statement forms to parse and prove; `for…of` brings
JavaScript's iteration protocol to the language boundary, where arrays,
strings and iterables behave differently; the counting loop's per-iteration
binding is a JavaScript subtlety the capture rule has to keep refusing.

Rewriting iteration modules to index-based `while` or classic `for` is the
alternative, and costs `for…of` its readability.

### Generic `for…of` syntax

The syntax-only foundation covers braced declaration loops:

```js
for (const item of items) { consume(item); }
for (let [key, value] of entries) { consume(key, value); }
```

The AST retains the declaration kind and binding target, the iterable expression,
the body and the starting token. Classic `for` keeps its existing representation.
The contextual separator `of` remains a valid ordinary identifier elsewhere.

`parseSyntax` can form this AST, so `fjs deps` can inspect such modules without
executing or resolving them. FunctionalScript admission explicitly refuses the
new loop at its starting `for`. This adds no iteration protocol, admitted value
kinds, desugaring, FAST/EDAG operation or serializer behavior. Assignment-target
iteration, `for…in` and `for await…of` remain separate syntax work.

This expands AST coverage for repository source while keeping the unresolved
iteration policy separate. The cost is a syntax form whose later admission
still needs its own design and proofs.

`sergey-shandar` requested this syntax-only increment in the
[working session](https://chatgpt.com/local/01a1908b-f970-713f-b7cb-e16f7ffb2006)
and confirmed that it is only AST support. This records no approval for FJS
iteration semantics.

### Classic `for` authorization and scope

`sergey-shandar`, the language designer named in
[DESIGN.md §12](../../doc/DESIGN.md#12-preserve-harmless-javascript-conventions),
explicitly requested this implementation in the
[working session](https://chatgpt.com/local/01a1890d-59f3-7124-b8e8-a763dc98c003):

> Implement desugaring from `for (init, cond, step)` to `while`.

The accompanying example uses `for (let i = 0; i < count; i += 1)`.
That request is the authorization used for classic-for desugaring. The
implemented header variants are documented in the
[loop contract](../control-flow/loops/README.md#classic-for): initialized
`let` or `const`, assignment or call initializers and steps, optional clauses,
and terminal `for (;;)`, subject to the existing source and capture rules.
`for…of`, `for…in`, `++` and `--` remain separate work.

No separate formal language-design approval comment is recorded for those
header variants beyond the linked implementation request. The earlier
[general-loop approval](../control-flow/loops/README.md#design-approval)
covers the `while` and binding extension; it does not approve classic `for`.

### Tasks

- [x] Form a generic AST for braced `const`/`let` declaration `for…of` loops;
      retain explicit FJS refusal and prove `fjs deps` uses the syntax boundary.
- [ ] Settle the remaining forms and the `for…of` kinds; record formal
      language-design approval, with a link, under
      [DESIGN.md §12](../../doc/DESIGN.md#12-preserve-harmless-javascript-conventions).
- [x] `for (;;)` and the counting loop lower to the existing loop; the
      [loops](../control-flow/loops/README.md) page and
      [refused constructs](./refused-constructs.md) updated.
- [ ] `for…of` over the admitted kinds.
- [ ] Recount the modules this unblocks and rename those that then compile.

### Related

- [Variables](../bindings/variables/README.md) and
  [loops](../control-flow/loops/README.md) — current source contracts.
- [Loop integration](../../fjs/compiler/architecture.md#loop-integration) —
  the shared pipeline these forms can reuse.
- [3430 assignments](./3430-assignments.md) — `++` and `+=`.
- [MVP roadmap](../../nanvm/lib/todo/mvp-roadmap.md#where-self-hosting-stands)
  — what self-hosting waits on.
