flan/test/programs/dev-break-bounds.flan

53 lines
2.3 KiB
Plaintext

;;;; A program that stops on a bad index, for driving the break loop over one.
;;;;
;;;; bounds-condition.flan is the other half of the same change and covers the
;;;; path where a `handler-bind` answers. This one covers the path the change
;;;; is actually *for*: **nothing handles it**, so the signal walks the
;;;; handlers, finds none, and reaches `flan_break_hook` — which is where an
;;;; editor picks up a stopped program with the stack, the locals and the
;;;; globals readable and the restarts on offer.
;;;;
;;;; That is the claim `docs/PORTING.md` said was missing, and it is worth testing
;;;; end to end rather than reasoning about: before this, a bad index called
;;;; exit(134), and with `flan dev` running as one process that took the
;;;; compiler and the session with it.
;;;;
;;;; The shape is a frame loop's: one `restart-case` offering `continue` around
;;;; the work, which is sand.flan's shape and the game's. No restart is
;;;; established at the failing index — nothing a handler could do would make
;;;; index 9 valid for a length-4 array — so `continue` is the *program's* own
;;;; restart, found by the ordinary walk, and taking it is the proof that a
;;;; bounds failure now lands somewhere a session can be recovered from.
(import agent "vendor:agent")
(defvar grid [4 i32])
(defvar skipped i64)
;;; One frame deep under the restart-case, so the transfer has something to
;;; cross and the backtrace has something to show.
(defn touch [i i32] ()
(set (at grid i) 1))
(defn frame [i i32] ()
(restart-case
(do (touch i) (println "frame done"))
(continue [] (set skipped (+ skipped 1)))))
(defvar ticks i64)
(defn main [] i32
(agent/start "/tmp/flan-dev-break-bounds-fallback.sock")
;; Out of bounds on the first frame, with nothing handling it: the daemon
;; meets a program that has already stopped, which is the state an editor
;; has to cope with and the hardest one to arrange later.
(frame 9)
;; 1 once `continue` was taken. Printing it is how the transcript says which
;; way the program left the break, rather than that it left.
(print skipped) (println "")
;; And it keeps polling on the far side, because the claim worth testing is
;; that everything still works after a break over a bad index.
(dotimes [i 4000]
(agent/wait 5)
(set ticks (+ ticks 1)))
0)