flan/test/programs/array-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

114 lines
4.7 KiB
Plaintext

;;;; (array-fill [r c] v) and (array-gen [r c] f) — a fixed array as a value.
;;;;
;;;; DISCUSS.org's "need a value-producing array constructor": (array n T) is
;;;; the zeroed array and dotimes is Unit, so neither could be the initialiser
;;;; expression of a declaration. These are expressions, so they compose where
;;;; a bracket literal does — including as a defonce's initialiser, which is the
;;;; line the note was written about.
;;;;
;;;; The dimensions are in brackets and are the same compile-time lengths the
;;;; [n T] type spelling takes: an integer or a constant's name.
(defconst rows 3)
(defconst cols 4)
;; The line from the note. A typed declaration with a computed initialiser,
;; which is the startup-lifted path a defonce already had.
(defonce grid [rows [cols u8]] (array-fill [rows cols] 255))
;; One index per dimension, i32 each, and the return type is the element type.
(defn cell [r i32 c i32] i32 (+ (* r 100) c))
(defn one [i i32] i32 (* i i))
;; Row-major order is pinned, so a generator that counts observes it: this one
;; is called once per element and answers the call number, so the array it
;; fills is 0 1 2 ... in the order the elements are written.
(defonce ticks i32)
(defn tick [r i32 c i32] i32
(set ticks (+ ticks 1))
(- ticks 1))
;; An aggregate element: the store each loop pass writes is a struct copy.
(defstruct Cell [row i32 col i32])
;; Counts its own calls, for the evaluated-once line below.
(defonce calls i32)
(defn bump [] i32
(set calls (+ calls 1))
7)
(defn main [] i32
;; Rank 1.
(let [a (array-fill [5] 7)]
(print (at a 0)) (print " ") (print (at a 4)) (println "")) ; 7 7
;; Rank 2, and the element type is the fill value's.
(let [b (array-fill [2 3] (f32 1.5))]
(print (at b 1 2)) (println "")) ; 1.5
;; Rank 3.
(let [c (array-fill [2 2 2] -1)]
(print (at c 0 0 0)) (print " ") (print (at c 1 1 1)) (println "")) ; -1 -1
;; A dimension may be a constant's name, exactly as in [rows [cols u8]].
(let [d (array-fill [rows cols] 1)]
(print (at d 2 3)) (println "")) ; 1
;; The generator, rank 1: element i is i*i.
(let [g (array-gen [5] one)]
(print (at g 0)) (print " ") (print (at g 3)) (print " ")
(print (at g 4)) (println "")) ; 0 9 16
;; The generator, rank 2. Element [i][j] is i*100+j, which pins the index
;; arguments: the first is the outer index and the second the inner one, and
;; a form that passed them the other way round would print 1 and 300 here.
(let [h (array-gen [rows cols] cell)]
(print (at h 0 0)) (print " ") (print (at h 0 1)) (print " ")
(print (at h 1 0)) (print " ") (print (at h 2 3)) (println "")) ; 0 1 100 203
;; Row-major, pinned. [tick] answers the call number, so the element that
;; was written first holds 0 — and with four columns, [1][0] is the fifth.
(let [t (array-gen [rows cols] tick)]
(print (at t 0 0)) (print " ") (print (at t 0 1)) (print " ")
(print (at t 1 0)) (print " ") (print (at t 2 3)) (println "")) ; 0 1 4 11
;; The defonce from the top: 255 everywhere, read back as an i32 so the
;; printed value is the number and not a byte.
(print (i32 (at grid 0 0))) (print " ")
(print (i32 (at grid 2 3))) (println "") ; 255 255
;; An array value copies, which is what makes this a value and not a view:
;; writing through the copy leaves the global alone.
(let [copy grid]
(set (at copy 0 0) (u8 1))
(print (i32 (at copy 0 0))) (print " ")
(print (i32 (at grid 0 0))) (println "")) ; 1 255
;; The generator written in place — the canonical inline form. The brackets
;; are the only thing that says what [i] and [j] are: one i32 index per
;; dimension, and the element type is read off the body.
(let [q (array-gen [2 3] (fn [i j] (+ (* i 10) j)))]
(print (at q 0 0)) (print " ") (print (at q 1 2)) (println "")) ; 0 12
;; A struct-valued fill. The element is an aggregate, so what the loop
;; writes per element is a struct copy, on every backend.
(let [cs (array-fill [2 2] (Cell 3 4))]
(print (.row (at cs 0 0))) (print " ")
(print (.col (at cs 1 1))) (println "")) ; 3 4
;; Evaluated once: the fill *value* is bound before any loop runs, so a
;; call in that position is one call, however many elements get its answer.
(let [f (array-fill [4] (bump))]
(print (at f 3)) (print " ") (print calls) (println "")) ; 7 1
;; A zero dimension is an array with no elements, and the loop that fills it
;; runs no passes. Nothing to read, so the claim is that it compiles and the
;; program carries on.
(let [e (array-fill [0] 9)]
(println "empty ok"))
0)