From 76f23fc68bb57da799877527f3429dbfaf617876 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 19 Sep 2026 06:26:33 +0700 Subject: [PATCH] C-c C-m over a provider, and what it has to show MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The live loop's two halves, asserted where they live. The path first: a macro reading a data file resolves it against the directory of the source file the form is written in, and here that file is an origin the editor sent rather than anything on a command line — assets/edn/tuning.edn sits beside programs/edn-provide.flan and nowhere near the process's own directory, so an expansion that answered at all read the right file. Nothing is cached but the macro module, which holds the macro's code and not the data, so editing the .edn and expanding again is the loop. Then that the answer is readable, which is the point of generating code a person can look at rather than the smallest code there is: the struct with a type per field, the nested struct named for the path that reaches it, and the reader's dispatch on a key onto a field. Substrings and not a golden copy — the expansion is some hundreds of characters and a full one would fail on every comment reflowed in the derivation. @x86 matches on the generated reader and @sanitize is clean over it. The x86 run is the one worth naming: the set became a (Map [2 i64] bool), and a fixed-array key is a hash and equality pair the backend emits, which nothing generated had asked it for before. --- test/test_session.ml | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/test_session.ml b/test/test_session.ml index 8cc38fb..de8a717 100644 --- a/test/test_session.ml +++ b/test/test_session.ml @@ -723,6 +723,55 @@ let () = | exception Loc.Error { Loc.dmsg = m; _ } -> fail "a session that refused an expansion could not expand afterwards: %s" m); + (* ── A type provider, expanded ───────────────────────────────────── + Two claims, and they are the two halves of the live-tuning loop. + + The first is the path. A macro that reads a data file resolves it the way + (embed "...") does — against the directory of the source file the *form* + is written in — and a macro cannot know where that is, because a Form + carries no location. The compiler pokes the call site's directory in + before every expansion, and the call site here is an origin the editor + sent, not a file on a command line. "assets/edn/tuning.edn" is beside + programs/edn-provide.flan and nowhere near this process's directory, so an + expansion that answered anything at all read the right file. + + The second is that the answer is readable. `C-c C-m` over a provider is + the only way to see what it decided, and a provider whose output nobody + can look at is a plugin. So this asserts on text a person would recognise: + the struct with its fields and derived types, the nested struct named for + its path, and the reader's dispatch on a key. Asserted as substrings + rather than in full — the expansion is some hundreds of characters and a + golden copy of it would fail on every comment reflowed in the derivation. + + It also re-reads on every expansion, which is what makes editing the .edn + and hitting C-c C-m a loop: nothing is cached but the macro module, and + that holds the macro's code, not the data. *) + (let pt, _ = Session.create ~file:"programs/edn-provide.flan" () in + match + Session.macroexpand ~origin:"programs/edn-provide.flan" ~all:false pt + "(edn/defedn Tuning \"assets/edn/tuning.edn\")" + with + | x -> + let got = Form.to_source x.Session.xafter in + List.iter + (fun want -> + if not (has got want) then + fail "expanding a defedn: %S is not in\n%s" want got) + [ (* The struct, with a type per field derived from the value. *) + "(defstruct Tuning [name string hp i64 speed f64 boss? bool"; + (* The vector, and the constructor that states its type so that + (vec-new) has something to take it from. *) + "drops (Vec i64)"; + (* The nested map, named for the path that reaches it, and the one + nested inside that. *) + "(defstruct Tuning-hitbox-offset [x i64 y i64])"; + "hitbox Tuning-hitbox"; + (* And the reader, dispatching on a key onto a field. *) + "(edn/keyword=? k \"speed\")"; + "(set (.speed out) (edn/need-float c))" ] + | exception Loc.Error { Loc.dmsg = m; _ } -> + fail "expanding a defedn through a session: %s" m); + (* A form typed into a file that is *imported as a package* has to be qualified the way the import qualified it, or it splices as a brand-new unrelated name: the evaluation reports success and the running program