Appearance
| 1 | namespace Syntax.Process is | |
| 2 | ||
| 3 | // Base class for scanners that flag a particular suspending | |
| 4 | // statement (`await`, `yield`, possibly others later) inside a | |
| 5 | // `catch` or `finally` HANDLER body. | |
| 6 | // | |
| 7 | // The state-machine codegen handles suspensions inside a `try` | |
| 8 | // BODY via per-region cold-resume dispatch + V_state local + | |
| 9 | // state-guarded finally. Handlers (the body of a `catch` clause | |
| 10 | // or a `finally` block) still need an AST-level rewrite — pend | |
| 11 | // the in-flight exception, perform the suspension outside the | |
| 12 | // handler, re-raise — which ghūl doesn't yet do. So subclasses | |
| 13 | // walk a method body, track depth into handler bodies, and | |
| 14 | // override the suspending-statement `pre` to emit a clean | |
| 15 | // compile-time error when caught inside one. | |
| 16 | // | |
| 17 | // Stops at nested function / lambda boundaries: their bodies | |
| 18 | // are their own state machines and their own scanner walks. | |
| 19 | class HANDLER_DEPTH_SCANNER: Visitor is | |
| 20 | _handler_depth: int; | |
| 21 | _logger: Logging.Logger; | |
| 22 | ||
| 23 | init(logger: Logging.Logger) is | |
| 24 | super.init(); | |
| 25 | _logger = logger; | |
| 26 | si | |
| 27 | ||
| 28 | handler_depth: int => _handler_depth; | |
| 29 | logger: Logging.Logger => _logger; | |
| 30 | ||
| 31 | scan(body: Trees.Bodies.Body?) is | |
| 32 | if !body? then | |
| 33 | return; | |
| 34 | fi | |
| 35 | ||
| 36 | _handler_depth = 0; | |
| 37 | ||
| 38 | body.walk(self); | |
| 39 | si | |
| 40 | ||
| 41 | // CATCH body is a handler — walk it with depth bumped. | |
| 42 | pre(`catch: Trees.Statements.CATCH) -> bool is | |
| 43 | _handler_depth = _handler_depth + 1; | |
| 44 | return false; | |
| 45 | si | |
| 46 | ||
| 47 | visit(`catch: Trees.Statements.CATCH) is | |
| 48 | _handler_depth = _handler_depth - 1; | |
| 49 | si | |
| 50 | ||
| 51 | // TRY's finally body is also a handler. Walk body / catches | |
| 52 | // / finally explicitly so only the finally bumps depth (the | |
| 53 | // try body itself is OK — state-machine codegen handles | |
| 54 | // suspensions inside it). | |
| 55 | pre(`try: Trees.Statements.TRY) -> bool is | |
| 56 | `try.body.walk(self); | |
| 57 | ||
| 58 | for c in `try.catches do | |
| 59 | c.walk(self); | |
| 60 | od | |
| 61 | ||
| 62 | let `finally = `try.`finally; | |
| 63 | ||
| 64 | if `finally? then | |
| 65 | _handler_depth = _handler_depth + 1; | |
| 66 | `finally.walk(self); | |
| 67 | _handler_depth = _handler_depth - 1; | |
| 68 | fi | |
| 69 | ||
| 70 | return true; | |
| 71 | si | |
| 72 | ||
| 73 | // Stop at nested function / lambda boundaries — each has | |
| 74 | // its own state machine and its own scanner pass. | |
| 75 | pre(function: Trees.Definitions.FUNCTION) -> bool => true; | |
| 76 | pre(function: Trees.Expressions.FUNCTION) -> bool => true; | |
| 77 | si | |
| 78 | si |