The printed form round-trips, and the macro is named before the walk replaces it
Two things the first pass left on unspecified ground. Form.to_source is the only field in the protocol carrying arbitrary literal data -- a macro may build any literal at all -- and Wire.quote escapes only the quote and the backslash, on the stated ground that both readers take everything else as itself. test_repl checks that ground now: every escape the reader knows, both byte-literal spellings to_string would have written raw, and a whole float, each sent through the printer and the socket and back. And expand_all read the macro's name out of a tuple beside the walk that replaces it. OCaml does not promise which half runs first; the failure would have been the wrong macro named, never an error.
This commit is contained in:
parent
3dd9f61b7d
commit
9534d5c077
10
lib/macro.ml
10
lib/macro.ml
@ -429,4 +429,12 @@ let expand_step (f : Form.t) : Form.t * string option =
|
||||
let expand_all (f : Form.t) : Form.t * string option =
|
||||
match loaded_for [ f ] with
|
||||
| None -> (f, None)
|
||||
| Some l -> with_module l (fun () -> (expand_form l f, head_macro l f))
|
||||
| Some l ->
|
||||
with_module l (fun () ->
|
||||
(* The name is read off the *input*, so it has to be taken before the
|
||||
walk replaces it. Bound rather than written as a tuple: OCaml does
|
||||
not promise the order a tuple's components are evaluated in, and
|
||||
[Dev.serve] already carries a comment about the one place that bit.
|
||||
Here it would be silent — the wrong macro named, never an error. *)
|
||||
let name = head_macro l f in
|
||||
(expand_form l f, name))
|
||||
|
||||
@ -261,6 +261,24 @@ let () =
|
||||
(* And the one typed at the editor a moment ago, which is the session's
|
||||
set rather than the file's: nothing on disk declares [thrice]. *)
|
||||
expands "a macro defined at the editor, expanded" "(thrice 14)" "(* 14 3)";
|
||||
(* Every escape the reader knows, through the printer and then through
|
||||
the wire, and back out as the same text. This is the one field in the
|
||||
protocol that carries arbitrary literal data — a macro may build any
|
||||
literal at all, which is why [Form.to_source] exists beside
|
||||
[Form.to_string] — and [Wire.quote] escapes only the quote and the
|
||||
backslash, on the stated ground that both readers take everything
|
||||
else as itself. This is that ground, checked. *)
|
||||
expands "every string escape survives the printer and the wire"
|
||||
"\"a\\nb\\0c\\\"d\\\\e\\tf\\rg\"" "\"a\\nb\\0c\\\"d\\\\e\\tf\\rg\"";
|
||||
(* And the byte literals, where [to_string] would have written a NUL and
|
||||
a carriage return into the middle of the line. *)
|
||||
expands "a byte literal is written as a name the reader has"
|
||||
"[\\nul \\return \\space \\tab \\newline \\A]"
|
||||
"[\\nul \\return \\space \\tab \\newline \\A]";
|
||||
(* A float that is a whole number, which [to_string]'s %g writes as an
|
||||
integer — and an integer is what it would read back as. *)
|
||||
expands "a whole float keeps its point" "[1.0 0.5 -2.0]" "[1.0 0.5 -2.0]";
|
||||
|
||||
(* A form with no macro in it comes back as itself, and says so rather
|
||||
than echoing and leaving the editor to diff. *)
|
||||
(let r =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user