flan/test/programs/handler-reentry.flan
Joseph Ferano ed8dbbcd62 A handler-bind clause runs with only the handlers outside its own form in force, and a stale call in main's running loop stays listed until the callee changes back or the program re-runs
The first is CLHS 9.1.4.1: a clause that signalled the condition it handles used to re-enter itself until the stack ran out. The stale list now names a lifted clause by the function it is written in, and BUILT.md's cost line is measured against master.
2026-09-25 11:15:52 +07:00

47 lines
1.4 KiB
Plaintext

;;;; A handler-bind clause that signals the condition it is handling.
;;;;
;;;; While a clause runs, the handlers in force are the ones that were in force
;;;; when its handler-bind was established (CLHS 9.1.4.1). So the inner clause's
;;;; own bad index reaches the *outer* clause, once, and not the inner one
;;;; again — which used to recurse until the stack ran out.
;;;;
;;;; The second half is the other order: after the inner clause has run and
;;;; declined, the handler it belongs to is in force again for the next signal.
(defonce hits i64)
(def grid [4 i32] [1 2 3 4])
(defn bad [i i32] i32 (at grid i))
(defn nested [] i64
(restart-case
(handler-bind [(BoundsError [c] (set hits (+ hits 100)) (invoke-restart 'outer))]
(restart-case
(handler-bind [(BoundsError [c]
(set hits (+ hits 1))
(bad 9)
(invoke-restart 'inner))]
(bad 7))
(inner [] 0)))
(outer [] 0))
hits)
(defn again [] i64
(set hits 0)
(restart-case
(handler-bind [(BoundsError [c] (set hits (+ hits 1)) (invoke-restart 'out))]
(handler-bind [(BoundsError [c] (set hits (+ hits 10)))]
(bad 5)
0))
(out [] 0))
(restart-case
(handler-bind [(BoundsError [c] (set hits (+ hits 1000)) (invoke-restart 'out))]
(bad 6))
(out [] 0))
hits)
(defn main [] i32
(println (nested))
(println (again))
0)