From 51df451e7b50ff9b3f42782c96b0bd088aec6244 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Fri, 18 Sep 2026 23:03:56 +0700 Subject: [PATCH] The map dedup is asserted by the case that can only pass if it works #{{:a 1} {:a 1} {:a 2}} answers 2 whether tables=? compares anything or compares nothing, so it was proving the count and not the compare. The pair beside it isolates both halves: one map twice must collapse to 1, and two maps of one entry each with different keys must stay 2, which is what a size-only compare would get wrong. And read's comment stops implying a property it does not have: empty input answers (Some Value.Nil), indistinguishable from the document that is nil. Empty is not malformed and the reader is not the thing that gets to decide it is. --- test/programs/edn-read.flan | 7 +++++++ test/test_acceptance.ml | 8 ++++++-- vendor/edn/read.flan | 6 ++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/test/programs/edn-read.flan b/test/programs/edn-read.flan index 2e1d295..f2b7f4a 100644 --- a/test/programs/edn-read.flan +++ b/test/programs/edn-read.flan @@ -110,6 +110,13 @@ (set-size "#{[0 0] [0 0] [0 1]}") (set-size "#{\"a\" \"a\" :a :a}") (set-size "#{#{1 2} #{2 1}}") + ;; Three map cases and not one, because #{{:a 1} {:a 1} {:a 2}} answers 2 + ;; whether tables=? works or does nothing at all — two merge and one does + ;; not, or none merge and there were only ever three. The pair below + ;; isolates it: the first must be 1, and the second must be 2 on the + ;; *keys*, which a size compare alone would get wrong. + (set-size "#{{:a 1} {:a 1}}") + (set-size "#{{:a 1} {:b 1}}") (set-size "#{{:a 1} {:a 1} {:a 2}}") (set-size "#{1 1.0}") ; an int and a float are two values (set-size "#{true false true}") diff --git a/test/test_acceptance.ml b/test/test_acceptance.ml index e7de03e..babf608 100644 --- a/test/test_acceptance.ml +++ b/test/test_acceptance.ml @@ -592,7 +592,11 @@ let () = #{#{1 2} #{2 1}} needs set equality to ignore order, 2 for #{1 1.0} needs an int and a float to stay two values, and 2 for #{[0 0] [0 0] [0 1]} is the one a dedup written with `=` gets wrong, because two Vec - headers over two blocks are never equal. + headers over two blocks are never equal. The three map sizes are three + and not one because #{{:a 1} {:a 1} {:a 2}} answers 2 whether the map + compare works or does nothing: 1 for #{{:a 1} {:a 1}} is the one that + says it works, and 2 for #{{:a 1} {:b 1}} is the one that says a size + compare alone is not it. Then "level-1", which is the whole of the copy contract: the document is read out of a (Vec u8) and every byte of that buffer is then overwritten @@ -607,7 +611,7 @@ let () = "./source-assets/Sprout Lands Premium/Objects/Mushrooms, Flowers, \ Stones.png\n\ 54\ntrue\ntrue\ntrue\nfalse\n\n\ - 0\n2\n2\n2\n1\n2\n2\n2\n\n\ + 0\n2\n2\n2\n1\n1\n2\n2\n2\n2\n\n\ level-1\nmalformed\nread\n" in outputs "edn/read over the tileset" "programs/edn-read.flan" edn_read_out; diff --git a/vendor/edn/read.flan b/vendor/edn/read.flan index 03fbc0d..b09bba4 100644 --- a/vendor/edn/read.flan +++ b/vendor/edn/read.flan @@ -222,6 +222,12 @@ ;; document that is literally `nil`, which is the class of quiet wrongness the ;; package's refusals exist to avoid. A caller who needs the byte offset builds ;; the Cursor itself and calls read-value; that is the three lines below. +;; +;; One collision the Option does NOT resolve, said here rather than discovered: +;; empty input answers (Some Value.Nil), the same as the document `nil`. Empty +;; is not malformed — a tokenizer over no bytes reports no error, correctly — +;; and the alternative is this function deciding that an empty file is a +;; failure, which is the caller's question and not the reader's. (defn read [src [u8]] (Option Value) (let [c (cursor src) t (next (addr c))