Skip to content

add ILO-P102 hint for top-level bindings without main wrapper#513

Merged
danieljohnmorris merged 4 commits into
mainfrom
feature/top-chain-assign-hint
May 21, 2026
Merged

add ILO-P102 hint for top-level bindings without main wrapper#513
danieljohnmorris merged 4 commits into
mainfrom
feature/top-chain-assign-hint

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

K-means and linear-regression personas both got stuck on the same misparse this week: a top-level imperative chain written without a `main>_;` wrapper. The parser either died on the bare `=` (a bare ILO-P003 with no actionable hint) or, when a prior `name>type;body` decl was in scope, slurped the whole chain into that fn's body and emitted a wall of misleading ILO-T005 cascades anchored on the wrong line. K-means hit the 600s watchdog because of the cascade. Pending #5aj.

This adds ILO-P102, which catches the shape at parse time and points at the `main>_;` fix.

Repro before/after

```
gen-pts>L(L n);[[2.0 3.0][8.0 8.0][0.5 0.5]]
iter cs:L(L n) pts:L(L n)>L(L n);cs
pts=gen-pts;cs0=[[4.8 4.9][6.2 7.1][1.0 1.0]];cs1=iter cs0 pts;cs2=iter cs1 pts;prnt cs2
```

Before (2 diagnostics, anchored on the wrong function):

```
ILO-T005: 'cs' is a L L n, not a function (called with 1 args) (in function 'iter')
ILO-T039: 'gen-pts' is a 0-arg function used as a value reference, not a call (in function 'iter')
```

After (1 diagnostic, anchored on the orphan line):

```
ILO-P102: top-level `pts=...` binding outside any function declaration
hint: ilo programs need a function header. Wrap imperative chains in `main>;`
(e.g. `main>
;pts=...;...;prnt result`) or give this binding a proper
signature like `pts>n;`
```

What's in the diff

  • `add ILO-P102 for top-level bindings without main wrapper` - two parser changes:
    • `can_start_operand` refuses to cross an un-indented newline into an `Ident=` binding shape, so a prior fn's body can't slurp the orphan chain as a call argument. This kills the T005 cascade at the source.
    • `parse_decl` recognises a bare `Ident=` at the top level (after the existing reserved-keyword / builtin / alias guards) and emits ILO-P102 with the `main>_;` wrapper hint.
    • Registry entry for ILO-P102 with the long-form `--explain` text.
  • `add ILO-P102 regression test and example` - cross-engine regression covering both repro shapes (bare top-level chain + chain slurped into a prior fn body), plus a workaround test (`main>_;` wrapper runs cleanly), a negative test (normal fn decl unaffected), and a guard test (`map=...` keeps its existing ILO-P011 builtin-shadow hint). New `examples/top-level-chain-hint.ilo` shows the corrected shape as agent-facing learning material.
  • `doc sync for ILO-P102` - CHANGELOG entry under Unreleased, plus a row in the SPEC cross-language gotchas table.

Parser-only change; output is identical across VM and JIT.

Test plan

  • `cargo test --release --features cranelift` clean
  • `cargo clippy --release --features cranelift --all-targets -- -D warnings` clean
  • `cargo fmt --check` clean
  • New `tests/regression_top_level_chain_hint.rs` passes on `--vm` and `--jit` (5 sub-checks each, plus a parser-only `ilo check` smoke)
  • `tests/examples_engines.rs` keeps passing (1004 example-engine combos) - confirms un-indented body continuations like `examples/apps/config-shaper.ilo` still parse cleanly

Follow-ups

  • None for this PR. The cascade-suppression infra in `parse_program` already covers P102 via `sync_to_decl_boundary` walking to EOF for orphan chains, so a single P102 covers any length of orphan run.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

When an agent writes a top-level chain like

  pts=gen-pts;cs0=[...];cs1=iter cs0 pts;prnt cs1

without wrapping it in a function header, the parser used to either die
on the bare = (a bare ILO-P003 with no actionable hint) or, when a prior
name>type;body declaration was in scope, slurp the chain into that fn's
body and emit a wall of misleading ILO-T005 cascades anchored on the
wrong line. K-means and linear-regression personas both hit this.

Two parser changes collapse both shapes into a single diagnostic:

- can_start_operand refuses to cross an un-indented newline into an
  Ident= binding shape, so the prior fn's body can't slurp the orphan
  chain as a call argument.
- parse_decl recognises a bare Ident= at the top level (after the
  existing reserved-keyword / builtin / alias guards) and emits
  ILO-P102 with the main>_; wrapper hint.

Parser-only, identical output across VM and JIT.
Cross-engine regression on the two repro shapes (bare top-level chain
and chain slurped into a prior fn body), plus a passing example that
shows the main>_; wrapper running cleanly. The example doubles as
agent-facing learning material for what the corrected form looks like.
CHANGELOG entry under Unreleased > Added and a row in the SPEC
cross-language gotchas table pointing at the main>_; wrapper fix.
Picks up the new ILO-P102 row in the cross-language gotchas table.
@danieljohnmorris danieljohnmorris force-pushed the feature/top-chain-assign-hint branch from 7b2906f to ccb2eb2 Compare May 21, 2026 08:06
@danieljohnmorris danieljohnmorris merged commit dc828d0 into main May 21, 2026
5 checks passed
@danieljohnmorris danieljohnmorris deleted the feature/top-chain-assign-hint branch May 21, 2026 08:27
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