Files
hakorune/docs/guides/exception-handling.md
Selfhosting Dev c8063c9e41 pyvm: split op handlers into ops_core/ops_box/ops_ctrl; add ops_flow + intrinsic; delegate vm.py without behavior change
net-plugin: modularize constants (consts.rs) and sockets (sockets.rs); remove legacy commented socket code; fix unused imports
mir: move instruction unit tests to tests/mir_instruction_unit.rs (file lean-up); no semantic changes
runner/pyvm: ensure using pre-strip; misc docs updates

Build: cargo build ok; legacy cfg warnings remain as before
2025-09-21 08:53:00 +09:00

89 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Exception Handling — Postfix catch / cleanup (Stage3)
Summary
- Nyash adopts a flatter, postfix-first exception style:
- try is deprecated. Use postfix `catch` and `cleanup` instead.
- `catch` = handle exceptions from the immediately preceding expression/call.
- `cleanup` = always-run finalization (formerly finally), regardless of success or failure.
- This matches the languages scope unification and keeps blocks shallow and readable.
Status
- Phase 1: normalization sugar既存
- `NYASH_CATCH_NEW=1` でコア正規化パスが有効化。
- 後置フォームは内部 `TryCatch` AST に変換され、既存経路で降下。
- 実行時コストはゼロ(意味論不変)。
- Phase 2実装済み・Stage3ゲート
- パーサが式レベルの後置 `catch/cleanup` を直接受理。
- ゲート: `NYASH_PARSER_STAGE3=1`
- 糖衣正規化はそのまま併存(関数糖衣専用)。キーワード直受理と二重適用はしない設計。
Syntax (postfix)
- Expression-level postfix handlers (Stage3):
- `expr catch(Type e) { /* handle */ }`
- `expr catch { /* handle (no variable) */ }`
- `expr cleanup { /* always-run */ }`
- Combine: `expr catch(Type e){...} cleanup{...}`
- Method/function calls are just expressions, so postfix applies:
- `call(arg1, arg2) catch(Error e) { log(e) }`
- `obj.method(x) cleanup { obj.release() }`
Precedence and chaining
- Postfix `catch`/`cleanup` binds to the immediately preceding expression (call/chain result), not to the whole statement.
- For long chains, we recommend parentheses to make intent explicit:
- `(obj.m1().m2()) catch { ... }`
- `f(a, b) catch { ... } cleanup { ... }`
- Parser rule (Stage3): postfix attaches once at the end of a call/chain and stops further chaining on that expression.
Diagram (conceptual)
```
// before (parse)
obj.m1().m2() catch { H } cleanup { C }
// precedence (binding)
obj.m1().[ m2() ↖ binds to this call ] catch { H } cleanup { C }
// normalization (conceptual AST)
TryCatch {
try: [ obj.m1().m2() ],
catch: [ (type:Any, var:None) -> H ],
finally: [ C ]
}
```
Normalization (Phase 1)
- With `NYASH_CATCH_NEW=1`, postfix sugar is transformed into legacy `TryCatch` AST:
- `EXPR catch(T e){B}``TryCatch { try_body:[EXPR], catch:[(T,e,B)], finally:None }`
- `EXPR cleanup {B}``TryCatch { try_body:[EXPR], catch:[], finally:Some(B) }`
- Multiple `catch` are ordered top-to-bottom; first matching type handles the error.
- Combined `catch ... cleanup ...` expands to a single `TryCatch` with both blocks.
- Lowering uses the existing builder (`cf_try_catch`) which already supports cleanup semantics.
Semantics
- catch handles exceptions from the immediately preceding expression only.
- cleanup is always executed regardless of success/failure (formerly finally).
- Multiple catch blocks match by type in order; the first match is taken.
- In loops, `break/continue` cooperate with cleanup: cleanup is run before leaving the scope.
Migration notes
- try is deprecated: prefer postfix `catch/cleanup`.
- Member-level handlers (computed/once/birth_once/method) keep allowing postfix `catch/cleanup` (Stage3), unchanged.
- Parser acceptance of postfix at expression level will land in Phase 2; until then use the gate for normalization.
Examples
```
// Postfix catch on a call
do_work() catch(Error e) { env.console.log("error: " + e) }
// Always-run cleanup
open_file(path) cleanup { env.console.log("closed") }
// Combined
connect(url)
catch(NetworkError e) { env.console.warn(e) }
cleanup { env.console.log("done") }
// Stage3 parser gate quick smoke (direct acceptance)
// NYASH_PARSER_STAGE3=1 ./target/release/nyash --backend vm \
// apps/tests/macro/exception/expr_postfix_direct.nyash
```