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.
55 lines
2.4 KiB
Plaintext
55 lines
2.4 KiB
Plaintext
;;;; A program that pushes values into the watch table from its own loop.
|
|
;;;;
|
|
;;;; The point of the case is that this needs no compiler change: the watch
|
|
;;;; entry points are ordinary C functions, so a program reaches them through
|
|
;;;; [declare-c] the same way it reaches anything else in the runtime. That is
|
|
;;;; deliberate — a [(watch "hp" hp)] form would be an arm in the checker, and
|
|
;;;; a scalar does not need one.
|
|
;;;;
|
|
;;;; The values are written every iteration and are *not* read back from here.
|
|
;;;; What reads them is the daemon's [watch] op, over the agent, while this
|
|
;;;; program is still running — which is the whole design: the program pushes
|
|
;;;; at frame rate and the editor reads memory.
|
|
(import agent "vendor:agent")
|
|
|
|
(declare-c watch-i64 [name string x i64] i32 "flan_dev_watch_i64")
|
|
(declare-c watch-f64 [name string x f64] i32 "flan_dev_watch_f64")
|
|
(declare-c watch-str [name string s string] i32 "flan_dev_watch_str")
|
|
;; The accumulator, for a value sampled from inside a hot loop. A scalar watch
|
|
;; there shows whichever iteration happened to run last, which is the case this
|
|
;; exists for; see flan_dev.c, "A number sampled thousands of times a frame".
|
|
(declare-c watch-num-i64 [name string x i64] i32 "flan_dev_watch_num_i64")
|
|
|
|
(defonce ticks i64)
|
|
|
|
(defn loop-cells [] i32
|
|
(let [i 0]
|
|
(while (< i 8)
|
|
(watch-num-i64 "cell" (i64 (* i 3)))
|
|
(set i (+ i 1)))
|
|
i))
|
|
|
|
(defn step [] i64
|
|
(set ticks (+ ticks 1))
|
|
;; Three types, because the table stores *rendered text* and the rendering
|
|
;; is per type: an i64 and an f64 do not print the same way, and a string is
|
|
;; quoted and escaped so that a newline in one cannot become a second row.
|
|
(watch-i64 "ticks" ticks)
|
|
(watch-f64 "half" (/ (f64 ticks) 2.0))
|
|
(watch-str "label" "sand")
|
|
;; A hot inner loop, and the value *varies* across it — which is what makes
|
|
;; the row a test of the accumulator rather than of the plumbing. A slot that
|
|
;; only kept [last] would report 21 and no range; n, min and max are each
|
|
;; pinned by a different part of this loop.
|
|
(loop-cells)
|
|
ticks)
|
|
|
|
(defn main [] i32
|
|
(agent/start "/tmp/flan-dev-watch-fallback.sock")
|
|
;; A watch call costs a load and a not-taken branch until somebody opens a
|
|
;; watch buffer, so spinning here writes nothing until the test arms it.
|
|
(while (= (agent/wait 20) 0) (step))
|
|
(step)
|
|
(while (= (agent/wait 20) 0) (step))
|
|
0)
|