M2-T06: exceptions — throw/try/catch/finally with value propagation - #111
Merged
Conversation
- AST Throw/Try -> both parser twins (optional catch binding) -> JsExpr -> lowering
(subst/free-vars honor catch-param shadowing) -> eval
- RuntimeError carries the thrown JS value; catch binds it verbatim; internal errors
bind their message string (ReferenceError parity)
- finally runs on every path; an error raised in finally replaces the pending outcome
- Error(message)/new Error(msg) builtin: Error-shaped object ({name, message})
- throws propagate across call frames; uncaught surface at flush/dispatch; error
boundaries still capture render-time throws
- Env::assign: JS assignment semantics (nearest existing binding) — fixes silent
shadowing for assignments from nested scopes
- tests/exceptions.rs: 12 tests; suite 208; records M2 6/15, 60/106Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes#32.
What
throw/try/catch/finallyas expression forms (matching the expression-oriented IR): ASTThrow/Try→ both parser twins (strict + recovery, in parity) →JsExpr::Throw/Try→ lowering (subst_expr/free-vars honor catch-param shadowing) → eval.RuntimeErrornow carries the thrown JS value.catch (e)binds the thrown value verbatim (strings, numbers,new Errorobjects); internal runtime errors (e.g. unbound variables — ECMA ReferenceError) bind their message string.catch { }supported per ES2019);finallyruns on every path (success, after catch, uncaught); an error raised in finally replaces the pending outcome.Error(msg)/new Error(msg)→ Error-shaped object{name: "Error", message};e.messagereads back through member access.getDerivedStateFromErrorinto the fallback.Env::assign— assignments useddefine(current-scope insert), so assigning from a nested scope (catch block, closure body) shadowed the outer binding instead of updating it. Assignment now walks to the nearest existing binding (JS semantics);defineremains the declaration path.Documented scoping
throw new Error(msg)already produces a real Error object.Tests
crates/r2n-runtime/tests/exceptions.rs— 12 acceptance tests: catch binding (string/number/Error.message), internal-error catchability, finally on all three paths + finally-error override, uncaught propagation at flush, cross-call propagation, nested try + rethrow, optional catch binding, handler-throw at dispatch, boundary interplay.Suite: 208 tests green; clippy -D warnings; fmt; verify-audit-claims OK. Records updated (CHECKLIST/README/ROADMAP/yaml/toml, M2 6/15 · 60/106; JOURNAL entry 28).