diff --git a/TODO.org b/TODO.org index a76e8535..1ba9ec00 100644 --- a/TODO.org +++ b/TODO.org @@ -1804,10 +1804,15 @@ pass. Deriving from clojure-mode at runtime stays rejected: it would add an external dependency to a mode that ships in this repository and needs nothing beyond stock Emacs, and that community is mid-transition to a tree-sitter mode. -** TODO 373 lines in 20 files still reindent differently -Concentrated in four files, untouched by the Emacs pass and untouched before it. -The indenter and the hand-formatting there disagree about shapes nothing has -looked at. +** DONE Every tracked .flan file reindents to itself +CLOSED: [2026-09-25] +clojure-mode decided each shape. The indenter was wrong on one: a =with-= head, +and a qualified =def…= or =with-= head, now indents as a body, and a qualified +name finds its unqualified part's spec. The rest was hand formatting and was +reindented: a =cond= or =match= result on its own line sits under its test, and +an ordinary call's later arguments align under its first. A lone =;= comment +line goes to =comment-column= in every Lisp mode, so continuation comments are +written as =;;= lines above the code instead. ** DONE C-c C-i inspects the expression at point No prompt, because the expression is already written in the buffer. =C-u= opens diff --git a/emacs/flan-mode.el b/emacs/flan-mode.el index 3a78cbfa..d73d54f1 100644 --- a/emacs/flan-mode.el +++ b/emacs/flan-mode.el @@ -585,8 +585,22 @@ Anything not named here that begins with `def' is treated as `:defn' by `flan-indent-function'; anything else indents as a function call.") (defun flan--indent-spec (name) - "The indent spec for the form called NAME, or nil." - (and name (cdr (assoc name flan-indent-specs)))) + "The indent spec for the form called NAME, or nil. +A qualified name falls back to its unqualified part, so `rl/when' would find +the entry for `when' — `clojure--get-indent-method' does the same." + (and name + (cdr (or (assoc name flan-indent-specs) + (and (string-match "/\\([^/]+\\)\\'" name) + (assoc (match-string 1 name) flan-indent-specs)))))) + +(defun flan--definer-p (name) + "Non-nil if NAME indents as a definition or a `with-' form. +Either may be qualified: `rl/with-drawing' is a `with-' form. This is +`clojure-indent-function''s fallback for a head with no spec, regexp and all; +`default…' is excluded there because it is not a definer, and here too." + (and name + (string-match "\\`\\(?:\\S +/\\)?\\(def[a-z]*\\|with-\\)" name) + (not (string-match-p "\\`default" (match-string 1 name))))) (defconst flan--labelled-forms '("dotimes" "while" "until") "Loops that may carry a label, which `break' and `continue' name. @@ -755,8 +769,9 @@ decision to `calculate-lisp-indent'." ;; No spec. Anything else spelled `def…' is a definition and indents ;; like one, which covers `defstruct', `defdata', `defunion', ;; `defenum', `defonce', `defconst' and `defalias' without naming - ;; them. - ((and name (string-match-p "\\`def" name)) + ;; them. A `with-' form is a body too — `rl/with-drawing', + ;; `rl/with-mode-2d camera' — whatever it takes before the body. + ((flan--definer-p name) (+ lisp-body-indent head-column)) ;; A clause: `(name [params] body…)'. `handler-bind', `handler-case' ;; and `restart-case' all write their clauses this way, and the head is diff --git a/emacs/test-flan-mode.el b/emacs/test-flan-mode.el index d150748b..be9d1761 100644 --- a/emacs/test-flan-mode.el +++ b/emacs/test-flan-mode.el @@ -326,6 +326,54 @@ y 2.0] (print y))") +;; A `with-' form is a body, qualified or not, whatever it takes on the head's +;; line — `clojure-indent-function''s fallback. From `examples/core-2d-camera.flan'. +(test-flan-mode--check + "a qualified with- form indents its body by two past an argument" + "(rl/with-mode-2d camera + (rl/draw-rectangle-rec player rl/red) + (rl/draw-grid 10 1.0))") + +(test-flan-mode--check + "a qualified def form indents its body by two" + "(m/defthing name + (body))") + +;; A qualified name finds the spec of its unqualified part. +(test-flan-mode--check + "a qualified when keeps when's spec" + "(rl/when (ready?) + (go))") + +;; `default…' begins with `def' and is not a definer. +(test-flan-mode--check + "a default-prefixed call aligns its arguments" + "(default-color a + b)") + +;; A cond result on its own line sits under its test, not deeper. +(test-flan-mode--check + "a cond result on its own line aligns with its test" + "(cond + (= k 1) + (one) + :else + (other))") + +(test-flan-mode--check + "a match result on its own line aligns with its pattern" + "(match v + (Int n) n + (List items) + (length items))") + +;; A trailing argument of an ordinary call aligns under the first argument, +;; even when it is long; only a `with-', `def' or specced head gives a body. +(test-flan-mode--check + "an ordinary call's arguments align under the first one" + "(push missing + `(when (ok) (go)))") + ;;; Font lock diff --git a/examples/textures-image-generation.flan b/examples/textures-image-generation.flan index 78d38739..4c4b8529 100644 --- a/examples/textures-image-generation.flan +++ b/examples/textures-image-generation.flan @@ -65,13 +65,13 @@ ;; to corner. (set (at textures 0) (upload (rl/gen-image-gradient-linear screen-width screen-height 0 - rl/red rl/blue))) + rl/red rl/blue))) (set (at textures 1) (upload (rl/gen-image-gradient-linear screen-width screen-height 90 - rl/red rl/blue))) + rl/red rl/blue))) (set (at textures 2) (upload (rl/gen-image-gradient-linear screen-width screen-height 45 - rl/red rl/blue))) + rl/red rl/blue))) ;; density 0 means the falloff reaches the edge of the image. (set (at textures 3) (upload (rl/gen-image-gradient-radial screen-width screen-height 0.0 diff --git a/syntax-sketch.flan b/syntax-sketch.flan index f52bb6eb..07bfce3b 100644 --- a/syntax-sketch.flan +++ b/syntax-sketch.flan @@ -13,8 +13,8 @@ ;; Normative references: spec-memory.md (ownership, containers, places, ;; generics, function values) and spec-conditions.md (restart semantics). -(import rl "vendor:raylib") ; directory = package, declaration optional; - ; imports are always qualified rl/foo +;; Imports are always qualified: rl/foo. +(import rl "vendor:raylib") ; directory = package, declaration optional ;; ── Type notation ───────────────────────────────────────────────────── ;; [4 f32] fixed array — a value, copies on assignment diff --git a/test/programs/arena-region.flan b/test/programs/arena-region.flan index 397b8170..69077139 100644 --- a/test/programs/arena-region.flan +++ b/test/programs/arena-region.flan @@ -28,82 +28,82 @@ (let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)] (cond (= which 1) - ;; The refusal. The context here is the heap, which can free one - ;; block, and a (Vec Value) against it is a free that would release - ;; the slots and strand every inner Vec — so the construction dies - ;; rather than the free three hundred lines later. - (let [bad (vec-new Value)] - (println (length bad))) + ;; The refusal. The context here is the heap, which can free one + ;; block, and a (Vec Value) against it is a free that would release + ;; the slots and strand every inner Vec — so the construction dies + ;; rather than the free three hundred lines later. + (let [bad (vec-new Value)] + (println (length bad))) (= which 2) - ;; Use after free-all, which is a different mechanism and worth - ;; pinning separately: the allocator's epoch moves on every free-all - ;; and every container records the epoch it was made at. The header - ;; below was copied *out* of the arena container into a local before - ;; the release, which is the case the check has to cover and the - ;; reason spec-memory.md makes an Allocator a pointer rather than a - ;; copied value — a copied allocator would carry its own epoch and - ;; the copy would never notice. - (let [outer (vec-new Value frame)] - (let [inner (vec-new Value frame)] - (push inner (Value.Int {.n (i64 7)})) - (push outer (Value.List {.items inner}))) - (match (at outer 0) - (List items) - (do (println (length items)) - (free-all frame) - (println (length items))) - _ (println 0))) + ;; Use after free-all, which is a different mechanism and worth + ;; pinning separately: the allocator's epoch moves on every free-all + ;; and every container records the epoch it was made at. The header + ;; below was copied *out* of the arena container into a local before + ;; the release, which is the case the check has to cover and the + ;; reason spec-memory.md makes an Allocator a pointer rather than a + ;; copied value — a copied allocator would carry its own epoch and + ;; the copy would never notice. + (let [outer (vec-new Value frame)] + (let [inner (vec-new Value frame)] + (push inner (Value.Int {.n (i64 7)})) + (push outer (Value.List {.items inner}))) + (match (at outer 0) + (List items) + (do (println (length items)) + (free-all frame) + (println (length items))) + _ (println 0))) (= which 3) - ;; ZII, which is the hole a guard only at the construction would have - ;; left. The items field is omitted from the literal, so it is a zeroed - ;; Vec with no allocator at all — it never went near (vec-new) — and - ;; the first push is what adopts the context. So the branch is emitted - ;; at every growth too, and there it asks the container, which answers - ;; from the allocator it will adopt when it has none of its own. - (let [v (Value.List {})] - (match v - (List items) - (do (push items (Value.Int {.n (i64 1)})) - (println (length items))) - _ (println 0))) + ;; ZII, which is the hole a guard only at the construction would have + ;; left. The items field is omitted from the literal, so it is a zeroed + ;; Vec with no allocator at all — it never went near (vec-new) — and + ;; the first push is what adopts the context. So the branch is emitted + ;; at every growth too, and there it asks the container, which answers + ;; from the allocator it will adopt when it has none of its own. + (let [v (Value.List {})] + (match v + (List items) + (do (push items (Value.Int {.n (i64 1)})) + (println (length items))) + _ (println 0))) :else - (do - ;; The control, and it is the case the frame tier exists for: a - ;; (Vec (Vec i32)) owns storage at two levels and is perfectly happy - ;; in a region, because free-all releases every block the region - ;; handed out and the inner ones are among them. The rule asks about - ;; the *allocator*, never "does this element own anything", so this - ;; must be built without complaint. - (with-allocator frame - (let [rows (vec-new Row)] - (let [row (vec-new i32)] - (push row 1) - (push row 2) - (push rows row)) - (println (length rows)) - (println (length (at rows 0))))) - (free-all frame) - ;; And the same container against the heap dies — asserted from the - ;; other side in run 1 above; here the point is only that the region - ;; run above got no complaint. - (with-allocator frame - (let [vs (vec-new Value)] - (push vs (Value.Int {.n (i64 41)})) - (println (length vs)))) - (free-all frame) - ;; And the zeroed field of run 3, this time in the region: the growth - ;; guard has to pass here as surely as it has to fail there, or every - ;; ZII container in an arena would be unusable. - (with-allocator frame - (let [v (Value.List {})] - (match v - (List items) - (do (push items (Value.Int {.n (i64 1)})) - (println (length items))) - _ (println 0)))) - (free-all frame)))) + (do + ;; The control, and it is the case the frame tier exists for: a + ;; (Vec (Vec i32)) owns storage at two levels and is perfectly happy + ;; in a region, because free-all releases every block the region + ;; handed out and the inner ones are among them. The rule asks about + ;; the *allocator*, never "does this element own anything", so this + ;; must be built without complaint. + (with-allocator frame + (let [rows (vec-new Row)] + (let [row (vec-new i32)] + (push row 1) + (push row 2) + (push rows row)) + (println (length rows)) + (println (length (at rows 0))))) + (free-all frame) + ;; And the same container against the heap dies — asserted from the + ;; other side in run 1 above; here the point is only that the region + ;; run above got no complaint. + (with-allocator frame + (let [vs (vec-new Value)] + (push vs (Value.Int {.n (i64 41)})) + (println (length vs)))) + (free-all frame) + ;; And the zeroed field of run 3, this time in the region: the growth + ;; guard has to pass here as surely as it has to fail there, or every + ;; ZII container in an arena would be unusable. + (with-allocator frame + (let [v (Value.List {})] + (match v + (List items) + (do (push items (Value.Int {.n (i64 1)})) + (println (length items))) + _ (println 0)))) + (free-all frame)))) (arena-destroy frame) 0) diff --git a/test/programs/arena-value.flan b/test/programs/arena-value.flan index 3c1b846b..8fd9a508 100644 --- a/test/programs/arena-value.flan +++ b/test/programs/arena-value.flan @@ -51,13 +51,13 @@ (match v (Int n) n (List items) - (let [t (i64 0)] - (dotimes [i (length items)] - (set t (+ t (total (at items i))))) - t) + (let [t (i64 0)] + (dotimes [i (length items)] + (set t (+ t (total (at items i))))) + t) (Table entries) - (+ (match (get entries "xs") (Some x) (total x) None (i64 0)) - (match (get entries "ys") (Some y) (total y) None (i64 0))) + (+ (match (get entries "xs") (Some x) (total x) None (i64 0)) + (match (get entries "ys") (Some y) (total y) None (i64 0))) _ (i64 0))) (defn build [] i64 diff --git a/test/programs/edn.flan b/test/programs/edn.flan index f57b7731..9b39d880 100644 --- a/test/programs/edn.flan +++ b/test/programs/edn.flan @@ -213,8 +213,9 @@ ;; ── The refusals, each asserted on its own reason ───────────────── (refusal "\"a\\nb\"") ; an escape inside a string - (refusal "\"a\\\"b\"") ; an escaped quote — the case where a wrong - ; version returns `a\` and leaves `b"` behind + ;; An escaped quote is the case where a wrong version returns `a\` and + ;; leaves `b"` behind. + (refusal "\"a\\\"b\"") ; an escaped quote (refusal "\"unterminated") ; not a refusal, but the other string failure ;; A set is read now, so what is left to refuse about one is its balance. A ;; `#{` that pushed nothing would answer "no error" for both of these. @@ -228,8 +229,8 @@ (refusal "\\a") ; a character literal (refusal "12x") ; starts like a number, is not one (refusal "[1 :]") ; a colon with no name - (refusal "@") ; not the start of any value — and the case a - ; scan-to-delimiter reads as a one-byte symbol + ;; `@` is the case a scan-to-delimiter reads as a one-byte symbol. + (refusal "@") ; not the start of any value (refusal "`x") ; a Clojure reader macro, not EDN (refusal "[1 2}") ; the wrong closer (refusal "]") ; a closer with nothing open diff --git a/test/programs/frame-rollback.flan b/test/programs/frame-rollback.flan index 2d3ffe66..1fae5248 100644 --- a/test/programs/frame-rollback.flan +++ b/test/programs/frame-rollback.flan @@ -154,7 +154,7 @@ (do (update-frame col) (set frames (+ frames 1))) (continue [] (restore) - (set skipped (+ skipped 1))))) + (set skipped (+ skipped 1))))) (defn main [] i32 (set (.brush world) 1) diff --git a/test/programs/json.flan b/test/programs/json.flan index b5010fc9..73be92bc 100644 --- a/test/programs/json.flan +++ b/test/programs/json.flan @@ -118,41 +118,41 @@ (defn read-value [c (Ptr json/Cursor) t json/Token] Value (cond (= (.kind t) json/tok-bool) - (Value.Bool {.b (match (json/bool-of t) (Some v) v None false)}) + (Value.Bool {.b (match (json/bool-of t) (Some v) v None false)}) (= (.kind t) json/tok-int) - (Value.Int {.n (match (json/int-of t) (Some v) v None (i64 0))}) + (Value.Int {.n (match (json/int-of t) (Some v) v None (i64 0))}) (= (.kind t) json/tok-float) - (Value.Float {.x (match (json/float-of t) (Some v) v None 0.0)}) + (Value.Float {.x (match (json/float-of t) (Some v) v None 0.0)}) (= (.kind t) json/tok-string) - (Value.Text {.s (match (json/string-of t) (Some s) s None "")}) + (Value.Text {.s (match (json/string-of t) (Some s) s None "")}) (= (.kind t) json/tok-array-open) - (let [items (vec-new Value) - u (json/next c) - more (and (json/ok? c) (!= (.kind u) json/tok-array-close))] - (while more - (push items (read-value c u)) - (let [sep (json/next c)] - (cond - (not (json/ok? c)) (set more false) - (= (.kind sep) json/tok-array-close) (set more false) - (!= (.kind sep) json/tok-comma) - (do (json/fail c json/err-unexpected-token (.pos sep)) - (set more false)) - :else - (do (set u (json/next c)) - ;; A comma and then the closer. Named, because a trailing - ;; comma is legal JSON5 and a reader that quietly allowed - ;; it would be reading a different format than it claims. - ;; - ;; The fail is what ends the loop, through the ok? test - ;; below it and not on its own — so these two are in this - ;; order on purpose, and swapping them spins. - (when (= (.kind u) json/tok-array-close) - (json/fail c json/err-trailing-comma (.pos u))) - (when (not (json/ok? c)) - (set more false)))))) - (Value.Array {.items items})) + (let [items (vec-new Value) + u (json/next c) + more (and (json/ok? c) (!= (.kind u) json/tok-array-close))] + (while more + (push items (read-value c u)) + (let [sep (json/next c)] + (cond + (not (json/ok? c)) (set more false) + (= (.kind sep) json/tok-array-close) (set more false) + (!= (.kind sep) json/tok-comma) + (do (json/fail c json/err-unexpected-token (.pos sep)) + (set more false)) + :else + (do (set u (json/next c)) + ;; A comma and then the closer. Named, because a trailing + ;; comma is legal JSON5 and a reader that quietly allowed + ;; it would be reading a different format than it claims. + ;; + ;; The fail is what ends the loop, through the ok? test + ;; below it and not on its own — so these two are in this + ;; order on purpose, and swapping them spins. + (when (= (.kind u) json/tok-array-close) + (json/fail c json/err-trailing-comma (.pos u))) + (when (not (json/ok? c)) + (set more false)))))) + (Value.Array {.items items})) ;; An object key is a quoted string and nothing else — an unquoted one was ;; already refused by the tokenizer as a bare word, so what reaches here is @@ -160,41 +160,41 @@ ;; same string-of the values use, so the map owns its keys and the source ;; buffer is not in the picture. (= (.kind t) json/tok-object-open) - (let [entries (map-new string Value) - k (json/next c) - more (and (json/ok? c) (!= (.kind k) json/tok-object-close))] - (while more - (if (!= (.kind k) json/tok-string) - (do (json/fail c json/err-unexpected-token (.pos k)) - (set more false)) - (let [key (match (json/string-of k) (Some s) s None "")] - (json/expect c json/tok-colon) - (if (not (json/ok? c)) - (set more false) - (let [v (json/next c)] - (if (not (json/ok? c)) - (set more false) - (do - (put entries key (read-value c v)) - (let [sep (json/next c)] - (cond - (not (json/ok? c)) (set more false) - (= (.kind sep) json/tok-object-close) (set more false) - (!= (.kind sep) json/tok-comma) - (do (json/fail c json/err-unexpected-token (.pos sep)) - (set more false)) - :else - ;; Same two steps, same order, same reason as the - ;; array arm: the fail ends the loop through the - ;; ok? test under it, and it has to, because the - ;; next pass would otherwise ask string-of for the - ;; text of a closing brace. - (do (set k (json/next c)) - (when (= (.kind k) json/tok-object-close) - (json/fail c json/err-trailing-comma (.pos k))) - (when (not (json/ok? c)) - (set more false)))))))))))) - (Value.Object {.entries entries})) + (let [entries (map-new string Value) + k (json/next c) + more (and (json/ok? c) (!= (.kind k) json/tok-object-close))] + (while more + (if (!= (.kind k) json/tok-string) + (do (json/fail c json/err-unexpected-token (.pos k)) + (set more false)) + (let [key (match (json/string-of k) (Some s) s None "")] + (json/expect c json/tok-colon) + (if (not (json/ok? c)) + (set more false) + (let [v (json/next c)] + (if (not (json/ok? c)) + (set more false) + (do + (put entries key (read-value c v)) + (let [sep (json/next c)] + (cond + (not (json/ok? c)) (set more false) + (= (.kind sep) json/tok-object-close) (set more false) + (!= (.kind sep) json/tok-comma) + (do (json/fail c json/err-unexpected-token (.pos sep)) + (set more false)) + :else + ;; Same two steps, same order, same reason as the + ;; array arm: the fail ends the loop through the + ;; ok? test under it, and it has to, because the + ;; next pass would otherwise ask string-of for the + ;; text of a closing brace. + (do (set k (json/next c)) + (when (= (.kind k) json/tok-object-close) + (json/fail c json/err-trailing-comma (.pos k))) + (when (not (json/ok? c)) + (set more false)))))))))))) + (Value.Object {.entries entries})) :else Value.Null)) @@ -204,34 +204,34 @@ (defn count-leaves [v Value] i32 (match v (Array items) - (let [n 0] - (dotimes [i (length items)] - (set n (+ n (count-leaves (at items i))))) - n) + (let [n 0] + (dotimes [i (length items)] + (set n (+ n (count-leaves (at items i))))) + n) ;; map-next fills an out-parameter with a copy of the value's bytes, which ;; for a Value holding a container is a second header over the same block. ;; In a region that is an alias and not a second owner, so walking a map is ;; the ordinary iteration and needs no accessor of its own. (Object entries) - (let [n 0 - cur (i64 0) - k "" - e Value.Null] - (while (map-next entries (addr cur) (addr k) (addr e)) - (set n (+ n (count-leaves e)))) - n) + (let [n 0 + cur (i64 0) + k "" + e Value.Null] + (while (map-next entries (addr cur) (addr k) (addr e)) + (set n (+ n (count-leaves e)))) + n) _ 1)) (defn sum-ints [v Value] i64 (match v (Int n) n (Array items) - (let [t (i64 0)] - (dotimes [i (length items)] - (set t (+ t (sum-ints (at items i))))) - t) + (let [t (i64 0)] + (dotimes [i (length items)] + (set t (+ t (sum-ints (at items i))))) + t) (Object entries) - (match (get entries "xs") (Some x) (sum-ints x) None (i64 0)) + (match (get entries "xs") (Some x) (sum-ints x) None (i64 0)) _ (i64 0))) (defn describe [v Value] string @@ -244,9 +244,9 @@ (defn text-at [v Value key string] string (match v (Object entries) - (match (get entries key) - (Some x) (match x (Text s) s _ "") - None "") + (match (get entries key) + (Some x) (match x (Text s) s _ "") + None "") _ "")) (defn read-doc [src [u8]] Value @@ -413,7 +413,7 @@ (println (sum-ints v)) ; [1 2 3] (println (describe (match v (Object e) (match (get e "gravity") (Some g) g None Value.Null) - _ Value.Null))) + _ Value.Null))) ;; The escapes, resolved. The quotes in `name` never existed as bytes ;; in the source; é is two bytes out of six and the emoji is four out ;; of twelve; and the eight one-character escapes are eight bytes. diff --git a/test/programs/pkgs/tree/tree.flan b/test/programs/pkgs/tree/tree.flan index 920cbf6d..7f8c067c 100644 --- a/test/programs/pkgs/tree/tree.flan +++ b/test/programs/pkgs/tree/tree.flan @@ -25,8 +25,8 @@ (match t (Leaf n) n (Branch kids) - (let [s (i64 0)] - (dotimes [i (length kids)] - (set s (+ s (total (at kids i))))) - s) + (let [s (i64 0)] + (dotimes [i (length kids)] + (set s (+ s (total (at kids i))))) + s) Empty (i64 0))) diff --git a/test/programs/utf8.flan b/test/programs/utf8.flan index fb8d27d0..4ecbd325 100644 --- a/test/programs/utf8.flan +++ b/test/programs/utf8.flan @@ -102,9 +102,9 @@ (show-dec (slice lone-cont 0 1)) ; a continuation byte leading (show-dec (slice overlong2 0 2)) ; overlong "/" (show-dec (slice overlong3 0 3)) ; overlong "/" again, three bytes - (show-dec (slice overlong4 0 4)) ; and four. Added after a mutation run: - ; relaxing 0xf0's floor to 0x80 left the - ; whole suite green without this line. + ;; Added after a mutation run: relaxing 0xf0's floor to 0x80 left the + ;; whole suite green without this line. + (show-dec (slice overlong4 0 4)) ; and four (show-dec (slice surrogate 0 3)) ; U+D800 (show-dec (slice above-max 0 4)) ; U+110000 (show-dec (slice lead-f5 0 4)) ; 0xf5 leads nothing diff --git a/vendor/edn/provide.flan b/vendor/edn/provide.flan index 6196ea6e..f9456dc6 100644 --- a/vendor/edn/provide.flan +++ b/vendor/edn/provide.flan @@ -216,8 +216,8 @@ (let [t (next c)] (when (not (ok? c)) (return (derived-bad - (joined3 "the data file could not be read at " (where src (error-pos c)) - (joined ": " (error-message (.err c))))))) + (joined3 "the data file could not be read at " (where src (error-pos c)) + (joined ": " (error-message (.err c))))))) (cond (= (.kind t) tok-int) (ok-derived `i64 (form-nil) `(need-int c)) (= (.kind t) tok-float) (ok-derived `f64 (form-nil) `(need-float c)) @@ -231,12 +231,12 @@ (= (.kind t) tok-nil) (derived-bad (joined3 "the nil at " (where src (.pos t)) - " has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out")) + " has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out")) :else (derived-bad (joined3 "the value at " (where src (.pos t)) - " is not one defedn derives a type from — a map, a vector, a set, an integer, a float, a boolean or a string"))))) + " is not one defedn derives a type from — a map, a vector, a set, an integer, a float, a boolean or a string"))))) ;; A vector, whose elements must all come to the same type. The first element ;; decides; every one after it is compared against that decision and both @@ -245,8 +245,8 @@ (defn- derive-vec [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived (when (at-byte? c \]) (return (derived-bad - (joined3 "the empty vector at " (where src at-pos) - " has no element to derive an element type from — defedn reads the shape out of the data, and an empty collection carries none")))) + (joined3 "the empty vector at " (where src at-pos) + " has no element to derive an element type from — defedn reads the shape out of the data, and an empty collection carries none")))) (let [head (derive c (joined name "-item") src)] (when (bad? head) (return head)) @@ -266,12 +266,12 @@ cn (Form.Sym {.s (joined name "-new")})] (ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty (vec-new a))) - `(let [xs (~cn a)] - (expect c tok-vec-open) - (while (and (ok? c) (not (at-byte? c \]))) - (push xs ~read1)) - (expect c tok-vec-close) - xs)))))) + `(let [xs (~cn a)] + (expect c tok-vec-open) + (while (and (ok? c) (not (at-byte? c \]))) + (push xs ~read1)) + (expect c tok-vec-close) + xs)))))) ;; Why every collection gets a one-line constructor of its own. ;; @@ -294,8 +294,8 @@ (defn- derive-set [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived (when (at-byte? c \}) (return (derived-bad - (joined3 "the empty set at " (where src at-pos) - " has no element to derive an element type from")))) + (joined3 "the empty set at " (where src at-pos) + " has no element to derive an element type from")))) (let [head (derive-key c (joined name "-key") src)] (when (bad? head) (return head)) @@ -315,12 +315,12 @@ cn (Form.Sym {.s (joined name "-new")})] (ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty (map-new a))) - `(let [tbl (~cn a)] - (expect c tok-set-open) - (while (and (ok? c) (not (at-byte? c \}))) - (put tbl ~read1 true)) - (expect c tok-map-close) - tbl)))))) + `(let [tbl (~cn a)] + (expect c tok-set-open) + (while (and (ok? c) (not (at-byte? c \}))) + (put tbl ~read1 true)) + (expect c tok-map-close) + tbl)))))) ;; One element of a set. The scalars that are map keys pass; a vector becomes a ;; fixed array, which is one where a Vec is not; anything else is refused here @@ -334,8 +334,8 @@ (return d)) (when (not (key-type? (.ty d))) (return (derived-bad - (joined3 "a set of " (render (.ty d)) - " is not something this builds: a set becomes a (Map T bool), so its elements are map keys. Integers, booleans, strings and vectors of those are")))) + (joined3 "a set of " (render (.ty d)) + " is not something this builds: a set becomes a (Map T bool), so its elements are map keys. Integers, booleans, strings and vectors of those are")))) d)) ;; A vector in key position. Its length is part of its type, so every element @@ -346,8 +346,8 @@ (let [open (next c)] (when (at-byte? c \]) (return (derived-bad - (joined3 "the empty vector at " (where src (.pos open)) - " is inside a set, and an empty fixed array has no element type and no length")))) + (joined3 "the empty vector at " (where src (.pos open)) + " is inside a set, and an empty fixed array has no element type and no length")))) (let [head (derive c (joined name "-item") src)] (when (bad? head) (return head)) @@ -364,30 +364,30 @@ (expect c tok-vec-close) (when (not (key-type? (.ty head))) (return (derived-bad - (joined3 "a set of vectors of " (render (.ty head)) - " is not something this builds: the vector becomes a fixed array, which is a map key only when its elements are compared bytewise")))) + (joined3 "a set of vectors of " (render (.ty head)) + " is not something this builds: the vector becomes a fixed array, which is a map key only when its elements are compared bytewise")))) (let [elem (.ty head) read1 (.reader head) count (Form.Int {.i n})] (ok-derived `[~count ~elem] (.decls head) - `(let [arr (array ~count ~elem) - i 0] - (expect c tok-vec-open) - (while (and (ok? c) (not (at-byte? c \])) (< i ~count)) - (set (at arr i) ~read1) - (set i (+ i 1))) - (expect c tok-vec-close) - arr))))))) + `(let [arr (array ~count ~elem) + i 0] + (expect c tok-vec-open) + (while (and (ok? c) (not (at-byte? c \])) (< i ~count)) + (set (at arr i) ~read1) + (set i (+ i 1))) + (expect c tok-vec-close) + arr))))))) (defn- disagreement [what string src [u8] at-pos i32 n i64 - first Form second Form] string + first Form second Form] string (joined3 (joined3 "the " what " at ") (where src at-pos) (joined3 (joined3 " holds more than one shape: its first element is " (render first) " and element ") (i64->string n) (joined3 " is " (render second) - ". Every element has to be the same shape, because the type this becomes has one element type")))) + ". Every element has to be the same shape, because the type this becomes has one element type")))) ;; ── A map, which is a struct ──────────────────────────────────────── ;; @@ -403,8 +403,8 @@ (defn- derive-map [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived (when (at-byte? c \}) (return (derived-bad - (joined3 "the empty map at " (where src at-pos) - " has no keys to derive fields from — a struct with no fields is not a shape anything can be read into")))) + (joined3 "the empty map at " (where src at-pos) + " has no keys to derive fields from — a struct with no fields is not a shape anything can be read into")))) (let [fields (vec-new Form) ; the defstruct's [name type ...] vector clauses (vec-new Form) ; the reader's cond: test, body, test, body missing (vec-new Form) ; one per field, checked when the map closes @@ -414,14 +414,14 @@ (let [k (next c)] (when (not (ok? c)) (return (derived-bad - (joined3 "the data file could not be read at " - (where src (error-pos c)) - (joined ": " (error-message (.err c))))))) + (joined3 "the data file could not be read at " + (where src (error-pos c)) + (joined ": " (error-message (.err c))))))) (when (!= (.kind k) tok-keyword) (return (derived-bad - (joined3 (joined3 "the map at " (where src at-pos) " has a key at ") - (where src (.pos k)) - " that is not a keyword. A struct's fields are named, so every key of a map defedn reads has to be one — :name, not \"name\" and not 1")))) + (joined3 (joined3 "the map at " (where src at-pos) " has a key at ") + (where src (.pos k)) + " that is not a keyword. A struct's fields are named, so every key of a map defedn reads has to be one — :name, not \"name\" and not 1")))) (let [fname (copy-text (.text k)) d (derive c (joined3 name "-" fname) src)] (when (bad? d) @@ -441,11 +441,11 @@ ;; bit is decided here, where the field is, so the two cannot fall ;; out of step the way a parallel list of names would. (push missing - `(when (= (bit-and seen ~bit) 0) - (signal (SchemaDrift {.field ~lit - .struct ~(Form.Str {.s name}) - .extra? false - .pos (.pos k)}))))) + `(when (= (bit-and seen ~bit) 0) + (signal (SchemaDrift {.field ~lit + .struct ~(Form.Str {.s name}) + .extra? false + .pos (.pos k)}))))) (set idx (+ idx 1))))) (expect c tok-map-close) ;; An unknown key. The hand-written reader skips one, which is right when a @@ -455,12 +455,12 @@ ;; handle the condition still reads the rest. (push clauses `:else) (push clauses - `(do (signal (SchemaDrift {.field (copy-text (.text k)) - .struct ~(Form.Str {.s name}) - .extra? true - .pos (.pos k)})) - (when (not (skip-value c)) - (return out)))) + `(do (signal (SchemaDrift {.field (copy-text (.text k)) + .struct ~(Form.Str {.s name}) + .extra? true + .pos (.pos k)})) + (when (not (skip-value c)) + (return out)))) (let [sname (Form.Sym {.s name}) rname (Form.Sym {.s (joined "read-" name)}) struct `(defstruct ~sname ~(Form.Vec {.xs (slice fields)})) @@ -539,7 +539,7 @@ (Some src) (provide name path src) None (refuse (joined3 "there is no file at " path - ", read relative to the file this defedn is written in — the same place (embed \"...\") would look"))) + ", read relative to the file this defedn is written in — the same place (embed \"...\") would look"))) _ (refuse "defedn's first argument is the name of the struct to declare, written as a name")) _ (refuse "defedn's second argument is the path to the data file, written as a string literal — the file is read while this is being compiled, so there is nothing here to compute a path from")))) diff --git a/vendor/edn/read.flan b/vendor/edn/read.flan index cb973ff1..1a8b0a1d 100644 --- a/vendor/edn/read.flan +++ b/vendor/edn/read.flan @@ -93,44 +93,44 @@ (= (.kind t) tok-symbol) (keyword (.text t)) (= (.kind t) tok-vec-open) - (let [items (vec-new dyn) - u (next c)] - (while (and (ok? c) - (!= (.kind u) tok-vec-close) - (!= (.kind u) tok-eof)) - (push items (read-value c u)) - (set u (next c))) - items) + (let [items (vec-new dyn) + u (next c)] + (while (and (ok? c) + (!= (.kind u) tok-vec-close) + (!= (.kind u) tok-eof)) + (push items (read-value c u)) + (set u (next c))) + items) ;; A set ends on tok-map-close, because `}` is the byte that ends it. The ;; dedup is the map's own: put replaces the value of an equal key, so a ;; set with a duplicate in it never exists and #{[0 0] [0 0]} is one ;; element by structure, not by header identity. (= (.kind t) tok-set-open) - (let [s {} - u (next c)] - (while (and (ok? c) - (!= (.kind u) tok-map-close) - (!= (.kind u) tok-eof)) - (put s (read-value c u) true) - (set u (next c))) - s) + (let [s {} + u (next c)] + (while (and (ok? c) + (!= (.kind u) tok-map-close) + (!= (.kind u) tok-eof)) + (put s (read-value c u) true) + (set u (next c))) + s) ;; A map's key is a whole value, read by the same recursion as anything ;; else — :a and "a" are two keys, [0 0] can key a map, and the old ;; (Map string Value) narrowing that collapsed them is gone with the type ;; that forced it. (= (.kind t) tok-map-open) - (let [m {} - k (next c)] - (while (and (ok? c) - (!= (.kind k) tok-map-close) - (!= (.kind k) tok-eof)) - (let [key (read-value c k) - u (next c)] - (put m key (read-value c u))) - (set k (next c))) - m) + (let [m {} + k (next c)] + (while (and (ok? c) + (!= (.kind k) tok-map-close) + (!= (.kind k) tok-eof)) + (let [key (read-value c k) + u (next c)] + (put m key (read-value c u))) + (set k (next c))) + m) :else nil)) diff --git a/vendor/json/provide.flan b/vendor/json/provide.flan index cc5fddef..8d85892b 100644 --- a/vendor/json/provide.flan +++ b/vendor/json/provide.flan @@ -177,8 +177,8 @@ (let [t (next c)] (when (not (ok? c)) (return (derived-bad - (joined3 "the data file could not be read at " (where src (error-pos c)) - (joined ": " (error-message (.err c))))))) + (joined3 "the data file could not be read at " (where src (error-pos c)) + (joined ": " (error-message (.err c))))))) (cond (= (.kind t) tok-int) (ok-derived `i64 (form-nil) `(need-int c)) (= (.kind t) tok-float) (ok-derived `f64 (form-nil) `(need-float c)) @@ -191,12 +191,12 @@ (= (.kind t) tok-null) (derived-bad (joined3 "the null at " (where src (.pos t)) - " has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out")) + " has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out")) :else (derived-bad (joined3 "the value at " (where src (.pos t)) - " is not one defjson derives a type from — an object, an array, a number, a boolean or a string"))))) + " is not one defjson derives a type from — an object, an array, a number, a boolean or a string"))))) ;; An array, whose elements must all come to the same type. The first decides; ;; every one after it is compared against that, and both positions are named @@ -205,8 +205,8 @@ (defn- derive-array [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived (when (at-byte? c \]) (return (derived-bad - (joined3 "the empty array at " (where src at-pos) - " has no element to derive an element type from — defjson reads the shape out of the data, and an empty collection carries none")))) + (joined3 "the empty array at " (where src at-pos) + " has no element to derive an element type from — defjson reads the shape out of the data, and an empty collection carries none")))) (let [head (derive c (joined name "-item") src)] (when (bad? head) (return head)) @@ -218,12 +218,12 @@ (return item)) (when (not (same-type? (.ty head) (.ty item))) (return (derived-bad - (joined3 (joined3 "the array at " (where src at-pos) - " holds more than one shape: element 0 is ") - (render (.ty head)) - (joined3 (joined3 " and element " (i64->string n) " is ") - (render (.ty item)) - ". Every element of an array has to be the same shape, because the (Vec T) it becomes has one element type"))))) + (joined3 (joined3 "the array at " (where src at-pos) + " holds more than one shape: element 0 is ") + (render (.ty head)) + (joined3 (joined3 " and element " (i64->string n) " is ") + (render (.ty item)) + ". Every element of an array has to be the same shape, because the (Vec T) it becomes has one element type"))))) (comma c) (set n (+ n 1)))) (expect c tok-array-close) @@ -238,21 +238,21 @@ ;; better for it too. (ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty (vec-new a))) - `(let [xs (~cn a)] - (expect c tok-array-open) - (while (and (ok? c) (not (at-byte? c \]))) - (push xs ~read1) - (comma c)) - (expect c tok-array-close) - xs)))))) + `(let [xs (~cn a)] + (expect c tok-array-open) + (while (and (ok? c) (not (at-byte? c \]))) + (push xs ~read1) + (comma c)) + (expect c tok-array-close) + xs)))))) ;; ── An object, which is a struct ──────────────────────────────────── (defn- derive-object [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived (when (at-byte? c \}) (return (derived-bad - (joined3 "the empty object at " (where src at-pos) - " has no members to derive fields from — a struct with no fields is not a shape anything can be read into")))) + (joined3 "the empty object at " (where src at-pos) + " has no members to derive fields from — a struct with no fields is not a shape anything can be read into")))) (let [fields (vec-new Form) ; the defstruct's [name type ...] vector clauses (vec-new Form) ; the reader's cond: test, body, test, body missing (vec-new Form) ; one per field, checked when the object closes @@ -262,12 +262,12 @@ (let [k (next c)] (when (not (ok? c)) (return (derived-bad - (joined3 "the data file could not be read at " (where src (error-pos c)) - (joined ": " (error-message (.err c))))))) + (joined3 "the data file could not be read at " (where src (error-pos c)) + (joined ": " (error-message (.err c))))))) (when (!= (.kind k) tok-string) (return (derived-bad - (joined3 "the object at " (joined3 (where src at-pos) " has a member at " (where src (.pos k))) - " whose name is not a string, which JSON requires")))) + (joined3 "the object at " (joined3 (where src at-pos) " has a member at " (where src (.pos k))) + " whose name is not a string, which JSON requires")))) ;; The comparison in the generated reader is against the token's RAW ;; text, which costs no allocation per key. That is only the same ;; question as "is this the field" when the name has no escape in it — @@ -277,12 +277,12 @@ (let [raw (.text k)] (when (has-escape? raw) (return (derived-bad - (joined3 "the member name at " (where src (.pos k)) - " has an escape in it. A generated reader compares a key against the bytes as written, which costs nothing per key and is only the same question when the name is written plainly — so this one is refused rather than matched wrongly")))) + (joined3 "the member name at " (where src (.pos k)) + " has an escape in it. A generated reader compares a key against the bytes as written, which costs nothing per key and is only the same question when the name is written plainly — so this one is refused rather than matched wrongly")))) (when (not (name-like? raw)) (return (derived-bad - (joined3 "the member name at " (where src (.pos k)) - " is not a name a program could write, so there is no field it can become. A struct's fields are named; letters, digits, - and ? are what a name is made of")))) + (joined3 "the member name at " (where src (.pos k)) + " is not a name a program could write, so there is no field it can become. A struct's fields are named; letters, digits, - and ? are what a name is made of")))) (expect c tok-colon) (let [fname (copy-of raw) d (derive c (joined3 name "-" fname) src)] @@ -303,11 +303,11 @@ ;; beside the field, so the two cannot fall out of step the way a ;; parallel list of names would. (push missing - `(when (= (bit-and seen ~bit) 0) - (signal (SchemaDrift {.field ~lit - .struct ~(Form.Str {.s name}) - .extra? false - .pos (.pos close)}))))) + `(when (= (bit-and seen ~bit) 0) + (signal (SchemaDrift {.field ~lit + .struct ~(Form.Str {.s name}) + .extra? false + .pos (.pos close)}))))) (comma c) (set idx (+ idx 1)))))) (expect c tok-object-close) @@ -316,12 +316,12 @@ ;; program that declines to handle the condition still reads the rest. (push clauses `:else) (push clauses - `(do (signal (SchemaDrift {.field (match (string-of k) (Some s) s None "") - .struct ~(Form.Str {.s name}) - .extra? true - .pos (.pos k)})) - (when (not (skip-value c)) - (return out)))) + `(do (signal (SchemaDrift {.field (match (string-of k) (Some s) s None "") + .struct ~(Form.Str {.s name}) + .extra? true + .pos (.pos k)})) + (when (not (skip-value c)) + (return out)))) (let [sname (Form.Sym {.s name}) rname (Form.Sym {.s (joined "read-" name)}) struct `(defstruct ~sname ~(Form.Vec {.xs (slice fields)})) @@ -420,7 +420,7 @@ (Some src) (provide name path src) None (refuse (joined3 "there is no file at " path - ", read relative to the file this defjson is written in — the same place (embed \"...\") would look"))) + ", read relative to the file this defjson is written in — the same place (embed \"...\") would look"))) _ (refuse "defjson's first argument is the name of the struct to declare, written as a name")) _ (refuse "defjson's second argument is the path to the data file, written as a string literal — the file is read while this is being compiled, so there is nothing here to compute a path from")))) diff --git a/vendor/raylib/raylib.flan b/vendor/raylib/raylib.flan index a6c985e6..1c6a5d29 100644 --- a/vendor/raylib/raylib.flan +++ b/vendor/raylib/raylib.flan @@ -551,7 +551,7 @@ "CheckCollisionCircleRec") (declare-c collision-circle-line? [center Vector2 radius f32 - p1 Vector2 p2 Vector2] bool "CheckCollisionCircleLine") + p1 Vector2 p2 Vector2] bool "CheckCollisionCircleLine") (declare-c collision-point-rec? [point Vector2 rec Rectangle] bool @@ -562,13 +562,13 @@ "CheckCollisionPointCircle") (declare-c collision-point-triangle? [point Vector2 a Vector2 b Vector2 - c Vector2] bool "CheckCollisionPointTriangle") + c Vector2] bool "CheckCollisionPointTriangle") ;; `threshold` is in pixels, and it is not optional in practice: raylib's test ;; is a distance comparison in floats, so a point exactly on the line fails at ;; a threshold of 0. 1 is the useful smallest value. (declare-c collision-point-line? [point Vector2 p1 Vector2 p2 Vector2 - threshold i32] bool "CheckCollisionPointLine") + threshold i32] bool "CheckCollisionPointLine") ;; The one binding whose Flan face is not raylib's, and one of only two in ;; this file with a hand-written wrapper on top. A Flan slice crosses as @@ -685,12 +685,12 @@ "DrawTextureV") (declare-c draw-texture-ex [texture Texture2D position Vector2 rotation f32 - scale f32 tint Color] "DrawTextureEx") + scale f32 tint Color] "DrawTextureEx") ;; A negative source width or height flips the sprite, which is how a sheet is ;; drawn facing the other way without a second image. (declare-c draw-texture-rec [texture Texture2D source Rectangle position Vector2 - tint Color] "DrawTextureRec") + tint Color] "DrawTextureRec") ;; The two above, in one call, and the only one of the four that both takes a ;; source rectangle and scales: `source` picks a cell out of an atlas, `dest` @@ -933,10 +933,10 @@ ;; Angles are degrees, clockwise from the +x axis, and `segments` is how many ;; straight pieces the arc is made of — 0 lets raylib pick from the radius. (declare-c draw-ring [center Vector2 inner f32 outer f32 start f32 end f32 - segments i32 color Color] "DrawRing") + segments i32 color Color] "DrawRing") (declare-c draw-ring-lines [center Vector2 inner f32 outer f32 start f32 end f32 - segments i32 color Color] "DrawRingLines") + segments i32 color Color] "DrawRingLines") ;; Counter-clockwise, and raylib means it: the clockwise winding is culled and ;; draws nothing at all, which looks exactly like a broken binding. @@ -968,15 +968,15 @@ ;; `roundness` is 0 to 1 as a fraction of the shorter side, so 0 is a plain ;; rectangle and 1 is a stadium. (declare-c draw-rectangle-rounded [rec Rectangle roundness f32 segments i32 - color Color] "DrawRectangleRounded") + color Color] "DrawRectangleRounded") ;; No thickness here — see the section note. The `-ex` form below is the one ;; that takes it. (declare-c draw-rectangle-rounded-lines [rec Rectangle roundness f32 segments i32 - color Color] "DrawRectangleRoundedLines") + color Color] "DrawRectangleRoundedLines") (declare-c draw-rectangle-rounded-lines-ex [rec Rectangle roundness f32 - segments i32 thick f32 color Color] "DrawRectangleRoundedLinesEx") + segments i32 thick f32 color Color] "DrawRectangleRoundedLinesEx") ;; ── A slice where raylib wants a pointer and a count ───────────────── ;; @@ -1524,7 +1524,7 @@ ;; so a one-character string is unaffected by it. raylib's own DrawTextEx adds ;; it the same way measure-text-ex counts it, which is why the two agree. (declare-c draw-text-ex [font Font text string position Vector2 - font-size f32 spacing f32 tint Color] "DrawTextEx") + font-size f32 spacing f32 tint Color] "DrawTextEx") ;; Pure arithmetic over the font — no GL, no window — and therefore the one ;; thing in this section the acceptance table can assert. See the note above: @@ -1568,7 +1568,7 @@ "GetGlyphAtlasRec") (declare-c draw-text-codepoint [font Font codepoint i32 position Vector2 - font-size f32 tint Color] "DrawTextCodepoint") + font-size f32 tint Color] "DrawTextCodepoint") ;; DrawTextCodepoints and LoadFontData are not bound. The first is the slice ;; problem again and adds nothing draw-text-ex does not already do from a