You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Real exceptions: throw + finally on top of the existing try/catch
First step of the Python-ergonomics catch-up goal. The existing
Statement::Try only supported `try { ... } catch err { ... }` where
the caught value was an error string produced by builtin failures.
This commit adds:
- `throw expr` — explicit exception raise. Expression is evaluated
and its display-string becomes the error the surrounding catch
receives. New Statement::Throw(Expression).
- `finally { ... }` clause on try blocks. Optional, runs after
both the body AND any handler — including when the handler
itself raises (matches Python's try/except/finally). Statement::Try
extended with `finally: Option<Vec<Statement>>`.
Implementation surfaces touched:
- ast.rs: Try gains `finally: Option<Vec<Statement>>`;
Throw(Expression) added
- parser.rs: Token::Throw, Token::Finally lexed; parse_try_stmt
reads optional finally; throw is its own statement
- interpreter.rs: execute_stmt handles Throw via eval+Err; Try now
runs finally regardless of outcome; rewrite_module_calls
+ register_user_functions visit the new shape
- formatter.rs: Try formatter outputs the finally clause; Throw
formats as `throw expr;`
- compiler.rs: Throw falls back to Op::ExecStmt like Try (the
tree-walk path handles unwind; bytecode VM would
need a try-stack to compile these natively)
Test cases (examples/tests/test_exceptions.omc — 8 tests, all pass):
1. Basic throw + catch with string
2. Throw number; catch receives stringified form
3. Catch does NOT run when try succeeds
4. Finally runs after successful try
5. Finally runs after catch
6. Nested try — inner catch consumes, outer doesn't run
7. Nested try with rethrow — outer catch sees rethrown value
8. Throw propagates through fn call boundary
What's NOT yet shipped (future work toward "feel like a real
language"):
- Typed-catch hierarchies. The caught value is currently always a
Value::String. To support `catch e: SomeType { ... }` the
Err(String) contract would need to be Err(Value), threading the
thrown object through every Err propagation site in the
interpreter. Single-session lift but ~40 sites to update.
- Try-without-catch (`try { ... } finally { ... }`). Parser
currently requires catch before finally; runtime semantics
already handle the case.
- Custom exception classes. Once classes/methods land, exception
types will compose with them naturally.
Regression: 161 prior OMC tests + 8 new = 169 OMC tests pass.
77 codegen tests, cargo unit tests all green. No prior heal-pass /
substrate / harmonic_libs tests touched.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
0 commit comments