Skip to content

feat: !! panic-unwrap operator#272

Merged
danieljohnmorris merged 4 commits into
mainfrom
fix/bangbang-panic-unwrap
May 14, 2026
Merged

feat: !! panic-unwrap operator#272
danieljohnmorris merged 4 commits into
mainfrom
fix/bangbang-panic-unwrap

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

Adds !! as a sibling to !: same auto-unwrap shape over R and O, but on ^e / nil it aborts with a runtime diagnostic and exit 1 instead of propagating via the enclosing function's return type. This removes the viral R/O constraint for one-shot scripts and personas:

main>t;rdl!! "input.txt"            -- read file, abort if missing
main>n;v=num!! "42";v               -- parse number, abort on parse error

The token-cost win is real: a persona that just wants to read a file and bail on error no longer has to wrap main in >R t t and emit ~v, then deal with a propagated Err the runner has nowhere sensible to send.

Repro before / after

Before, this required a Result-typed main and explicit unwrapping:

main>R t t;v=rdl "input.txt";?v{^e:^e;~xs:~"got "+str (len xs)+" lines"}

After:

main>t;xs=rdl!! "input.txt";"got "+str (len xs)+" lines"

What's in the diff (per commit)

  1. lexer: add BangBang token — Higher priority than single-char Bang so logos picks the longer match.
  2. feat: !! panic-unwrap operator across all enginesUnwrapMode { None, Propagate, Panic } replaces unwrap: bool on Expr::Call. Parser probes !! at every postfix-Bang site. Verifier accepts the same R/O callee shape as ! but skips the enclosing-return-type check. Tree, VM (OP_PANIC_UNWRAP), and Cranelift (jit_panic_unwrap) all route through the existing JIT_RUNTIME_ERROR channel for identical surfacing. fmt emits !!; python emits a _ilo_panic_unwrap raise helper. New diagnostic ILO-R026.
  3. docs: SPEC.md + ai.txt — New Panic-Unwrap section, updated rules.
  4. test + example: cross-engine coveragetests/regression_bangbang.rs covers success path, abort paths, R and O callees, no-enclosing-return-constraint, composition with !, and verifier rejection of non-failing callees, across tree / VM / Cranelift. examples/bangbang-panic-unwrap.ilo is picked up by the existing examples_engines harness.

Test plan

  • cargo build --release --features cranelift clean
  • cargo test --release --features cranelift — 4699 passed, 0 failed
  • cargo fmt --check clean
  • cargo clippy --release --features cranelift --all-targets -- -D warnings clean
  • All 8 cross-engine regression_bangbang.rs tests pass
  • examples/bangbang-panic-unwrap.ilo exercised by examples_engines.rs across every engine

Follow-ups

None planned. Documents the design rationale for picking single-enum UnwrapMode over paired booleans inline (type-system enforcement that the two modes are mutually exclusive).

Higher priority than single-char Bang so logos picks the longer match
when scanning `func!! args`.
Symmetric with `!` over Result and Optional, but on Err / nil aborts
with a diagnostic + exit 1 instead of propagating via the enclosing
function's return type. Removes the viral R/O constraint for one-shot
scripts: `rdl!! path` from `main>t` now works without the `>R t t` +
`~v` wrapping ceremony.

- ast: replace `unwrap: bool` on Expr::Call with `UnwrapMode { None,
  Propagate, Panic }`. Single enum field makes the two modes mutually
  exclusive at the type level.
- parser: probe `!!` at every postfix-Bang site, emit Panic mode.
- verify: Panic mode accepts callee returning R or O, skips the
  enclosing-return-type check that `!` requires.
- interpreter (tree): new Panic arm returns RuntimeError directly
  without propagate_value, ILO-R026 with the inner Err / nil context.
- vm: new OP_PANIC_UNWRAP opcode that routes through
  jit_set_runtime_error so the existing JIT_RUNTIME_ERROR channel
  surfaces it identically across VM and Cranelift.
- cranelift: new jit_panic_unwrap helper mirroring the VM opcode.
- codegen/fmt: emit `!!` for Panic mode.
- codegen/python: emit a `_ilo_panic_unwrap` raise helper.
- diagnostic: register ILO-R026 with examples.
New Panic-Unwrap section explaining semantics, examples for `main>t`,
`main>n` contexts, and the rule difference from `!` (no
enclosing-return-type constraint). Updates the auto-unwrap rules to
note both `R` and `O` callees are accepted. ai.txt picks up the same
operator entry and updated rules in token-dense form.
regression_bangbang.rs exercises tree / VM / Cranelift on the success
path, Err / nil abort paths, callee returning R, callee returning O,
no-enclosing-return-constraint case, and composition with `!`. Also
covers verifier rejection when the callee return type cannot fail.

examples/bangbang-panic-unwrap.ilo gives agents an in-context demo of
the now-correct behaviour and is exercised by tests/examples_engines.rs
across every engine.
@danieljohnmorris danieljohnmorris merged commit 4822801 into main May 14, 2026
4 checks passed
@danieljohnmorris danieljohnmorris deleted the fix/bangbang-panic-unwrap branch May 14, 2026 11:21
@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

❌ Patch coverage is 96.89922% with 8 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/vm/mod.rs 92.55% 7 Missing ⚠️
src/codegen/fmt.rs 75.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

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