;;;; defedn over two real files, and the condition a drifted one signals. ;;;; ;;;; The first half is the claim the feature is for: `(.texture-path t)` here ;;;; is a field load off a struct nobody declared, and the same numbers ;;;; edn-read.flan prints through the dynamic reader come out of it. Two ;;;; readers over one file agreeing is what says the derived one is right — ;;;; either alone could be self-consistently wrong. ;;;; ;;;; The second half is the shape matrix: a string, an integer, a float, a ;;;; boolean, a vector, and a map inside a map, each read back. ;;;; ;;;; The third is drift. The struct was derived from the file as it was when ;;;; this was compiled; the bytes read at run time are a later version of it, ;;;; with one key gone and one arrived. Both are named by SchemaDrift, which is ;;;; the whole reason the reader carries one: a missing key otherwise leaves a ;;;; field at zero and the program draws nothing for a reason nothing reports. (import edn "vendor:edn") ;; Both derived at compile time, from the files as they sit beside this one. ;; The path is the (embed "...") path — relative to this file — and not the ;; path the run-time reads below use, which is relative to the process. (edn/defedn Tileset "assets/edn/tileset.edn") (edn/defedn Tuning "assets/edn/tuning.edn") ;; The same file the dynamic reader in edn-read.flan walks. Embedded rather ;; than read, so this half asserts the reader and not the filesystem. (defconst tileset (embed "assets/edn/tileset.edn")) (defconst tuning (embed "assets/edn/tuning.edn")) (defn show-tileset [a Allocator] () (let [t (Tileset-of-bytes tileset a)] ;; The line edn-read.flan prints first, off a struct field this time. (println (.texture-path t)) ;; 54 pairs, and the same three memberships and one miss. A derivation ;; that flattened the pairs into 108 integers would have a different count ;; and would answer no to every one of these. (println (len (.selected-cells t))) (println (has-key? (.selected-cells t) [3 4])) (println (has-key? (.selected-cells t) [0 0])) (println (has-key? (.selected-cells t) [4 11])) (println (has-key? (.selected-cells t) [9 9])))) (defn show-tuning [a Allocator] () (let [t (Tuning-of-bytes tuning a)] (println (.name t)) (println (.hp t)) (println (.speed t)) (println (if (.boss? t) "yes" "no")) (println (len (.drops t))) ;; 3 + 1 + 4 + 1 + 5. A vector read that stopped at the first element would ;; still have a plausible length from a zeroed Vec, so the sum is the claim. (let [total (i64 0)] (dotimes [i (len (.drops t))] (set total (+ total (at (.drops t) i)))) (println total)) ;; The nested structs, by the names the paths give them: Tuning-hitbox and ;; Tuning-hitbox-offset. Both are ordinary field loads, two deep. (println (.w (.hitbox t))) (println (.h (.hitbox t))) (println (.x (.offset (.hitbox t)))) (println (.y (.offset (.hitbox t)))))) ;; ── Drift ─────────────────────────────────────────────────────────── ;; ;; The struct says :name :hp :speed :boss? :drops :hitbox. These bytes have no ;; :speed and have a :level the struct has never heard of, which is what a ;; tuning file looks like a month after the program was built. (defconst drifted string "{:name \"imp\" :hp 3 :level 7 :boss? true :drops [1] :hitbox {:w 1 :h 1 :offset {:x 0 :y 0}}}") (defn show-drift [a Allocator] () (handler-bind [(edn/SchemaDrift [d] (do (print (if (.extra? d) "extra " "missing ")) (print (.field d)) (print " in ") (println (.struct d))))] (let [t (Tuning-of-bytes (bytes drifted) a)] ;; The fields that were there are read, which is the other half of the ;; contract: a drifted file is reported, not refused. :speed is the one ;; that was missing and is zero. (println (.name t)) (println (.hp t)) (println (.speed t))))) ;; ── A file that does not parse ────────────────────────────────────── ;; ;; The louder failure, and the one that had the quieter answer until ReadFailed ;; existed: a generated reader accumulates errors on the cursor, and the cursor ;; is made and dropped inside the entry point, so a stray brace gave back a ;; zeroed struct with nothing said. The rest of this package refuses to do ;; that — read-file answers an Option so that a malformed document is ;; distinguishable from one that is literally nil — and a derived reader has to ;; be at least as honest. (defconst broken string "{:name \"orc\" :hp }") (defn show-broken [a Allocator] () (handler-bind [(edn/ReadFailed [e] (do (print "unreadable ") (print (.struct e)) (print ": ") (println (edn/error-message (.code e)))))] (let [t (Tuning-of-bytes (bytes broken) a)] ;; Read anyway, and zeroed, which is the half a handler that carries on ;; is choosing. Printed so that "it signalled" and "it gave back nothing ;; usable" are two claims rather than one. (println (.hp t))))) (defn main [] i32 (let [a (heap-allocator)] (show-tileset a) (println "") (show-tuning a) (println "") (show-drift a) (println "") (show-broken a)) 0)