The trio the author decided on 2026-09-20 is now all built: def is CL's defparameter — its initialiser runs on every daemon re-run, unguarded, so an edited initialiser repaints the same storage on C-c C-c plus re-run — defonce (Clojure's name for CL's defvar, per the author) initialises once behind the .init~once. flag, and defconst stays the image. One parse arm reads both forms; the difference is Ast.reinit, carried to Tast.global's grerun. Emit.startup_plan gives a def no guard flag, and Check.check_global lifts every def initialiser — zero and literal included — into global/<n>, so the host's startup reaches it through the function cell and a re-evaluated def swaps it (Session's def_inits; Emit.redefinition declares the cell for a non-sibling target). The old defvar spelling is refused with the rename and both compiling spellings, and every program, test, doc and editor list is swept — except sand.flan, the author's live WIP, whose seven defvar lines are flagged in FIX.org and keep its three dependent tests red on this branch.
53 lines
2.3 KiB
Plaintext
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")
|
|
|
|
(defonce grid [4 i32])
|
|
(defonce 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)))))
|
|
|
|
(defonce 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)
|