flan/test/programs/fill.flan
Joseph Ferano a4c6b996ff def re-runs its initialiser, and defvar is renamed defonce
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.
2026-09-21 07:12:04 +07:00

145 lines
6.2 KiB
Plaintext

;;;; (filled b) and (dead-beef), the two byte fills, read back as bytes.
;;;;
;;;; The whole point of this program is that every row is a *byte* and not a
;;;; value: the pattern fill's contract is "a hex dump reads the pattern left
;;;; to right", which is a claim about which byte lands at which address, and
;;;; only reading the bytes back in address order can check it. The u32 rows
;;;; are the same claim from the other side — a little-endian load of
;;;; DE AD BE EF is 0xEFBEADDE, which is 4022250974, so a backend that wrote
;;;; the word the other way round would print 3735928559 here and be caught.
;;;;
;;;; The lengths are chosen for the tail. 8 is a whole number of patterns, 9
;;;; ends on DE, 6 ends on DE AD, and 7 ends on DE AD BE — the three truncated
;;;; endings and the one that is not truncated at all.
;;;;
;;;; The rows that matter most are the last group: a pattern that is *not* a
;;;; literal, over a length that is not a multiple of four. That is the case a
;;;; constant-only implementation would pass by accident — the word reaches
;;;; the loop in a register and the tail bytes have to be shifted out of it
;;;; rather than folded, on both backends.
(defstruct Words [a u32 b u32])
;;;; A computed global initialiser: a fill is never a constant the linker can
;;;; write, so this one goes through the startup function on both backends.
(defonce gfill [4 u8] (filled 0x41))
(defonce gsent [5 u8])
(defn bytes4 [b [4 u8]] ()
(dotimes [i 4] (print (at b i)) (print " ")))
;;;; A u32 that no literal rule can see through: (u32 0xBAADF00D) will not do,
;;;; because the cast checks its operand as an i32 first and 0xBAADF00D is not
;;;; one. A parameter's declared type is what makes the literal a u32, and it
;;;; is also what stops the checker folding it at the fill.
(defn u32of [x u32] u32 x)
;;;; The pattern crosses a call boundary, so nothing can fold it at the fill.
(defn beef7 [pat u32] ()
(let [a (array 7 u8)]
(set a (dead-beef pat))
(dotimes [i 7] (print (at a i)) (print " "))
(println "")))
(defn main [] i32
;; One byte, repeated. 0xFF is the -1 fill a debug allocator wants.
(let [a (array 4 u8)]
(set a (filled 0xFF))
(bytes4 a) (println "")) ; 255 255 255 255
;; The byte is an expression, not a literal: this is a memset with the
;; operand in a register, and the register path is the one a constant would
;; otherwise hide.
(let [v (u8 7)
a (array 4 u8)]
(set a (filled v))
(bytes4 a) (println "")) ; 7 7 7 7
;; (filled 0) is (zeroed), byte for byte, and saying so here is what keeps
;; the two from drifting.
(let [a (array 4 u8)]
(set a (filled 0))
(bytes4 a) (println "")) ; 0 0 0 0
;; Four bytes, ascending, with nothing truncated.
(let [a (array 8 u8)]
(set a (dead-beef))
(dotimes [i 8] (print (at a i)) (print " "))
(println "")) ; 222 173 190 239 x2
;; The bare form is the spelled-out default, and this is the row that says
;; so: the same eight bytes from (dead-beef 0xDEADBEEF).
(let [a (array 8 u8)]
(set a (dead-beef 0xDEADBEEF))
(dotimes [i 8] (print (at a i)) (print " "))
(println "")) ; identical to the row above
;; The three truncated tails.
(let [a (array 9 u8)]
(set a (dead-beef))
(dotimes [i 9] (print (at a i)) (print " "))
(println "")) ; ... ends on 222
(let [a (array 6 u8)]
(set a (dead-beef))
(dotimes [i 6] (print (at a i)) (print " "))
(println "")) ; ... ends on 222 173
(let [a (array 7 u8)]
(set a (dead-beef))
(dotimes [i 7] (print (at a i)) (print " "))
(println "")) ; ... ends on 222 173 190
;; A pattern of the program's own choosing, laid down left to right the same
;; way: 0xBAADF00D is BA AD F0 0D, which is 186 173 240 13.
(let [a (array 6 u8)]
(set a (dead-beef 0xBAADF00D))
(dotimes [i 6] (print (at a i)) (print " "))
(println "")) ; 186 173 240 13 186 173
;; The same pattern read as words rather than as bytes, which is what says
;; which end the DE is at.
(let [w (Words {})]
(set w (dead-beef))
(print (.a w)) (print " ") (print (.b w)) (println ""))
(let [w (Words {})]
(set w (dead-beef 0xBAADF00D))
(print (.a w)) (print " ") (print (.b w)) (println ""))
;; A nested aggregate: a fixed array of structs is plain data all the way
;; down, so the fill reaches every byte of it.
(let [g (array 2 Words)]
(set g (filled 0xFF))
(print (.a (at g 0))) (print " ") (print (.b (at g 1))) (println ""))
;; The globals. [gfill] was filled before main ran; [gsent] is filled here.
(dotimes [i 4] (print (at gfill i)) (print " "))
(println "") ; 65 65 65 65
(set gsent (dead-beef))
(dotimes [i 5] (print (at gsent i)) (print " "))
(println "") ; 222 173 190 239 222
;; A fill in value position rather than as the value of a [set]: the same
;; bytes, reached through a temporary instead of through the place.
(bytes4 (filled 0xFF)) (println "") ; 255 255 255 255
;; ── The computed pattern ──────────────────────────────────────────
;; None of these can be folded: the pattern is a parameter, or arithmetic
;; the checker does not evaluate. Seven bytes is one whole pattern and a
;; three-byte tail, so the tail bytes have to come out of the register the
;; word is in rather than out of a constant.
(beef7 0xDEADBEEF) ; 222 173 190 239 222 173 190
(beef7 0xBAADF00D) ; 186 173 240 13 186 173 240
(let [p (u32of 0xBAADF00D)
a (array 6 u8)]
(set a (dead-beef p))
(dotimes [i 6] (print (at a i)) (print " "))
(println "")) ; 186 173 240 13 186 173
;; A pattern that is genuinely computed, not merely held in a slot, and read
;; back as a word so the byte order of the runtime path is pinned too.
(let [p (u32of 0xBAAD0000)
w (Words {})]
(set w (dead-beef (bit-or p (u32of 0xF00D))))
(print (.a w)) (print " ") (print (.b w)) (println ""))
0)