diff --git a/lib/macro.ml b/lib/macro.ml index 4ffb065..7be9038 100644 --- a/lib/macro.ml +++ b/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)) diff --git a/test/test_repl.ml b/test/test_repl.ml index e5c9a03..9486d49 100644 --- a/test/test_repl.ml +++ b/test/test_repl.ml @@ -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 =