flan/test/programs/defvar-dyn.flan

76 lines
3.2 KiB
Plaintext

;;;; The third element of a defvar, both ways.
;;;;
;;;; The rule, 2026-09-20: a type there is the zeroed static global it has
;;;; always been, and anything else is a dyn global initialised from that
;;;; expression at startup. So this file is one program holding both kinds
;;;; side by side, and every line it prints is a claim about which reading
;;;; one of its declarations got.
;;;;
;;;; There is no new lowering under any of it. The dyn half is exactly what
;;;; [(defvar x dyn <expr>)] already compiled to — the initialiser lifted into
;;;; the startup function that main calls after the runtime is up, and a
;;;; collector root pushed for the global before it runs — which is why this
;;;; program runs identically on both backends and why neither of them
;;;; learned anything for it.
(defstruct Point [x i32 y i32])
;; ── The type reading, which is every declaration that worked before ──
;; A primitive, a fixed array, a struct and a container: all four are types in
;; the third position, so all four are the zeroed statics they were.
(defvar current-color i32)
(defvar grid [2 [3 u32]])
(defvar origin Point)
(defvar bytes (Vec u8))
;; ── The value reading, which is the new spelling ─────────────────────
;; None of these names a type, so each is a dyn global holding the value its
;; expression produced before the program's own code ran.
(defvar score 0)
(defvar label "start")
(defvar config {:level 1 :name "one"})
(defvar tally seeded)
;; A call, which is the shape the author kept writing: the file is read once,
;; at startup, into a global that outlives main.
(defn load [] dyn {:rows 3 :cols 4})
(defvar game-data (load))
;; And the value the bare symbol above was initialised from, declared *below*
;; it on purpose: which reading a defvar gets is decided with every name in
;; hand, not in the order the file was written.
(defvar seeded i64 7)
(defn main [] ()
;; The statics, untouched: zero, zero, zero, and an empty Vec that is a real
;; empty Vec rather than a placeholder.
(print current-color) (print " ") (print (at grid 1 2)) (print " ")
(print (.x origin)) (print " ") (print (len bytes)) (println "")
;; The dyn globals, as their initialisers left them.
(print score) (print " ") (print label) (print " ")
(print (get config :name)) (print " ") (print tally) (println "")
(print (get game-data :rows)) (print " ") (print (get game-data :cols))
(println "")
;; They are globals and not constants: each is assigned, and the map is
;; mutated in place through the same root the startup function filled.
(set score (+ score 5))
(set label "done")
(put config :level 2)
(set current-color 3)
(set (at grid 1 2) 9)
;; An allocation loop between filling them and reading them back, so the
;; collector runs with the run's own frames on the stack. A dyn global whose
;; root was not pushed reads back as a stale word here rather than as what
;; was stored.
(dotimes [i 20000]
(let [junk {:i i :s "forty-seven bytes of text to fatten each row"}]
(put config :seen (get junk :i))))
(print score) (print " ") (print label) (print " ")
(print (get config :level)) (println "")
(print current-color) (print " ") (print (at grid 1 2)) (println ""))