FIX.org, NEXT.md, DISCUSS.org, docs/DISCUSS.md and the session handoff at the root are one TODO.org now: 293 entries under seven subsystem headings, each carrying an org keyword that says where it stands. A DONE entry is a few lines saying what was decided and what that rules out; the reasoning that would not compress — the embedding spike and the four reports the hand-written x86 backend was built from — moved into docs/BUILT.md instead, and its entries point there in one line. Every entry was checked against the tree before it got a keyword, and the prose was wrong in both directions. Things the deleted files called open were built: the first-evaluation stall, main being redefinable, macro parameter lists, the type-limit constants, the array constructors, the byte fills, inc/dec, the discard's fontification, the Emacs buffers, rt_die's _exit, the backtrace surface, and the acceptance failure that could print and still exit zero. Things they called done were not: the backend reports' no-plan buckets had gone stale in the other direction, the value-dependent defvar was superseded rather than built, and macro-expansion source locations are on an unmerged lane, so that entry is NEXT and names the branch. Every comment that cited one of the five by name now cites a heading that exists, in TODO.org or in docs/BUILT.md. The session reports under docs/handoffs/ keep naming the files they worked on, because rewriting them would falsify what those sessions did; each carries a note saying where the content went.
114 lines
4.7 KiB
Plaintext
114 lines
4.7 KiB
Plaintext
;;;; (array-fill [r c] v) and (array-gen [r c] f) — a fixed array as a value.
|
|
;;;;
|
|
;;;; TODO.org, "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)
|