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.
54 lines
1.9 KiB
Plaintext
54 lines
1.9 KiB
Plaintext
;;;; A stopped stack whose OUTER frame holds a local the evaluator cannot see.
|
|
;;;;
|
|
;;;; dev-locals.flan is about what one frame holds; this one is about which
|
|
;;;; frame the answer came from. The whole of the bug the `inspect' verb
|
|
;;;; exists for is that an expression is evaluated where the evaluator stands,
|
|
;;;; so a local's *name* reaches the right storage only when the frame is the
|
|
;;;; innermost one. `mark' below is a global AND a local of the outer frame,
|
|
;;;; holding different things of different types: evaluating the name answers
|
|
;;;; the global, and rooting at the frame and slot answers the frame.
|
|
;;;;
|
|
;;;; The other locals are the shapes a path step has to walk and that an
|
|
;;;; expression cannot reach at all: an option's payload, which has no
|
|
;;;; accessor form in the language, and a union case's field, whose offset
|
|
;;;; depends on which case the value is in.
|
|
(import agent "vendor:agent")
|
|
|
|
(defstruct Point [x f32 y f32])
|
|
(defstruct Boom [why i32])
|
|
|
|
(defdata Shape
|
|
[Empty
|
|
(Dot [x f64 y f64])
|
|
(Rect [w i32 h i32])])
|
|
|
|
;; The discriminator. `outer' binds a local of this name to something else, so
|
|
;; every claim about which frame answered is visible in the value itself.
|
|
(defonce mark i64)
|
|
|
|
;; The innermost frame, and it is deliberately dull: it holds nothing worth
|
|
;; inspecting, so that the frame worth inspecting is not the one an expression
|
|
;; would have found by luck.
|
|
(defn deeper [] i64
|
|
(restart-case
|
|
(do (error (Boom {.why 7})) 1)
|
|
(carry-on [] 5)))
|
|
|
|
(defn outer [] i64
|
|
(let [mark (Point {.x 1.5 .y 2.5})
|
|
xs [10 20 30]
|
|
box (Some (Point {.x 4.5 .y 5.5}))
|
|
s (Shape.Rect {.w 3 .h 6})]
|
|
(deeper)))
|
|
|
|
(defonce ticks i64)
|
|
|
|
(defn main [] i32
|
|
(set mark 99)
|
|
(agent/start "/tmp/flan-dev-inspect-fallback.sock")
|
|
(print (outer)) (println "")
|
|
(dotimes [i 4000]
|
|
(agent/wait 5)
|
|
(set ticks (+ ticks 1)))
|
|
0)
|