The delimiter half of the backtick fix was observed by nothing
Every sigil in the corpus test sat in leading position, where read_form handles it before is_delimiter is ever consulted — so reverting the is_delimiter line alone left every case green. a`b now has the case a~b already had, and the corpus carries both, which is what makes the class guard cover the delimiter change rather than only the read branches. The handoff note hedged on the one thing it exists to decide: expansion runs over Form before Parse, not over Ast. There is no Ast.Defmacro, so an Ast pass would have nothing to read. Says milestone 6 for union values because that is the number check.ml itself gives.
This commit is contained in:
parent
f590436ed3
commit
a311664a08
17
NEXT.md
17
NEXT.md
@ -1621,14 +1621,15 @@ The shape it wants:
|
||||
accessors. That is the real work, and it is bigger than the expander itself:
|
||||
the compiler and the compiled macro have to agree on the *layout* of a
|
||||
`Form`, not merely its shape, so whatever the checker does for unions has to
|
||||
be exact here. Until unions are values this cannot start; that is milestone 6
|
||||
work landing before milestone 5's.
|
||||
2. **Expansion is a pass between `Parse` and `Check`**, over `Ast`, not over
|
||||
`Form` — or, better, over `Form` before `Parse` ever runs, which is why
|
||||
`Parse` refusing `defmacro` rather than storing it is not a dead end: the
|
||||
expander runs first and `Parse` never sees a macro call at all. That is the
|
||||
Clojure ordering and the one to prefer, because a macro expanding to a
|
||||
special form is then ordinary rather than a special case.
|
||||
be exact here. Until unions are values this cannot start — `check.ml` puts
|
||||
union values and `match` on a union at **milestone 6**, so that is milestone
|
||||
6 work landing before milestone 5's.
|
||||
2. **Expansion runs over `Form`, before `Parse`.** Not a pass over `Ast`:
|
||||
there is no `Ast.Defmacro` and `Parse` refuses `defmacro` outright, so an
|
||||
`Ast`-level pass would have nothing to work with. That refusal is not a dead
|
||||
end, it is the ordering — the expander runs first and `Parse` never sees a
|
||||
macro call at all. It is also the Clojure ordering, and the reason a macro
|
||||
expanding to a special form is ordinary rather than a special case.
|
||||
3. **Order matters and files do not have one.** Top-level names in a package
|
||||
are order-independent everywhere else (`declared_types`, the constant
|
||||
fixpoint in `check.ml`). Macros cannot be: a macro must be compiled and
|
||||
|
||||
@ -113,6 +113,7 @@ let () =
|
||||
reads "quote in quasi" "`(a 'b)" "(quasiquote (a (quote b)))";
|
||||
(* The delimiter half of the fix: without it ~x is one symbol named "~x". *)
|
||||
reads "tilde ends a name" "(f a~b)" "(f a (unquote b))";
|
||||
reads "backtick ends a name" "(f a`b)" "(f a (quasiquote b))";
|
||||
reads "backtick in vec" "[`a ~b]" "[(quasiquote a) (unquote b)]";
|
||||
|
||||
(* The whole class: no reader-significant character may end up inside a name. *)
|
||||
@ -127,7 +128,7 @@ let () =
|
||||
in
|
||||
let corpus =
|
||||
"(invoke-restart 'skip-form) (a 'b [c 'd] {:e 'f}) '(g 'h) \
|
||||
`(i ~j ~@k) `(l `(m ~n)) [`o ~p] {:q `r}"
|
||||
`(i ~j ~@k) `(l `(m ~n)) [`o ~p] {:q `r} (f a~b x`y)"
|
||||
in
|
||||
check "no sigils leak into names"
|
||||
(bad_names (Form.make (Form.List (Reader.read_all ~file:"<test>" corpus))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user