Load.program takes forms: it reads the import forms, resolves them with the one resolver it always had, and parses the file with the packages' macros in front of it. The refusal said this needed a second import resolver at the Form level. It did not notice that the file being compiled is parsed before Load runs too, so no shape of the feature could have left import resolution where it was. Names arrive qualified, as a defn's do. (mac/twice 4) is a call and (twice 4) is an unknown name. Stopped mid-task: dune test was never run and the acceptance wiring is unfinished. HANDOFF-macros.md has what is left.
4.2 KiB
Handoff: macros in an imported package
Stopped mid-task when the session ended. The feature works; the acceptance wiring is unfinished. Its author's last words were "Works. Now the acceptance wiring." This file was written by the coordinator from the diff and from running the program, not by the lane, so treat the "what remains" list as read off the tree rather than as the author's own account.
State
dune build succeeds. test/programs/pkg-macro.flan runs and prints 8 12 10 12 10 8 70 60,
which is a package macro, a package macro that quasiquotes another, and a program macro, all
coexisting. dune test was never run. That is the first thing to do.
The shape picked, and why the refusal's reasoning was wrong
The old refusal in lib/load.ml said collecting a package's macros would need that package's
imports resolved at the Form level, before Load runs — a second import resolver — and refused
rather than build one.
The lane found the premise false, and this is the finding worth keeping:
the file being compiled is parsed before
Loadruns too, so no shape of the feature could have left import resolution where it was.
So the phases moved instead of being duplicated. Load.program takes forms now: it reads the
import forms, resolves them with the one resolver it always had, and parses the file with the
packages' macros already in front of it. There is no second resolver.
The acyclic-import guarantee is what makes this sound, and it was already there for this reason —
load.ml's own comment says a definite package order is what the macro expander needs.
The rule
Package macros arrive qualified, exactly as a defn does. A program importing the directory as
mac writes (mac/twice 4); (twice 4) is an unknown name. Nothing becomes globally visible by
importing a package. Inside the package the names are unqualified, which is the rule every other
declaration there follows.
Files touched
bin/main.ml, lib/load.ml, lib/macro.ml, lib/parse.ml, lib/session.ml,
test/programs/pkg-macro.flan, test/programs/pkgs/mac/mac.flan, test/test_acceptance.ml,
test/test_reload.ml, test/test_sanitize.ml, test/test_session.ml, test/test_valgrind.ml,
test/test_web.ml. 447 insertions, 117 deletions.
The test files are mostly signature churn from Load.program taking forms — that call is made in
many places and each had to move.
What remains
- Run
dune test --root .and make it green. Nothing has run it.Load.program's signature changed and it is called from most test binaries, so expect breakage that is mechanical rather than deep. - Finish the acceptance wiring.
test_acceptance.ml:1423-1427was the refusal case (refuses "a macro in an imported package"). The diff touches it; confirm it now asserts the working program and that a sibling refusal pins the qualified-name rule — that(twice 4)unqualified is an unknown name.pkg-macro.flan's header says that refusal exists; verify it does. - Check the non-termination refusals still fire when the macros come from a package: a ring of
macros is named, a macro that does not settle is bounded.
BUILT.mdrecords both. Neither was confirmed under the new path. - Check the dev loop. A macro imported by the file being edited must still be available on a
C-c C-c.lib/session.mlis in the diff, so this was at least considered, but nothing proves it.test/test_session.mlandtest/test_dev.mlshow how sessions are driven. - Measure the build cost against the recorded baseline in
BUILT.md: 50ms for a build naming no macro, 310ms cold and 70ms warm for one calling a macro. Whether reading a package's forms earlier moved those numbers is unknown. vendor/raylibis the customer.with-drawingandwith-mode-2dover raylib'sBeginDrawing/EndDrawingandBeginMode2D/EndMode2D, so an unbalanced pair stops being possible. A raylib lane tried and could not; that is what prompted this work. Not started here and deliberately out of scope — that file was held by another lane at the time.
Not verified
Everything above item 1. The program runs and the build is clean; that is the whole of what is known to work.