Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix source quotation in OCaml 5.2 #480

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions astlib/location.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
include Ocaml_common.Location

let set_input_name name = input_name := name
let set_input_lexbuf lexbuf_opt = input_lexbuf := lexbuf_opt

module Error = struct
[@@@warning "-37"]
Expand Down
3 changes: 3 additions & 0 deletions astlib/location.mli
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ with type location := t
val set_input_name : string -> unit
(** Set the name of the input source, e.g. the file name. *)

val set_input_lexbuf : Lexing.lexbuf option -> unit
(** Set the name of the input source, e.g. the file name. *)

val none : t
(** An arbitrary value of type [t]; describes an empty ghost range. *)

Expand Down
28 changes: 13 additions & 15 deletions src/utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,19 @@ module Ast_io = struct
let input_version = (module Compiler_version : OCaml_version) in
try
(* To test if a file is an AST file, we have to read the first few bytes of the
file. If it is not, we have to parse these bytes and the rest of the file as
source code.

The compiler just does [seek_on 0] in this case, however this doesn't work when
the input is a pipe.

What we do instead is create a lexing buffer from the input channel and pre-fill
it with what we read to do the test. *)
let lexbuf = Lexing.from_channel ic in
let len = String.length prefix_read_from_source in
Bytes.blit_string ~src:prefix_read_from_source ~src_pos:0
~dst:lexbuf.lex_buffer ~dst_pos:0 ~len;
lexbuf.lex_buffer_len <- len;
lexbuf.lex_curr_p <-
{ pos_fname = input_name; pos_lnum = 1; pos_bol = 0; pos_cnum = 0 };
file. If it is not, we have to parse these bytes and the rest of the file as
source code.
The compiler just does [seek_on 0] in this case, however this doesn't work
when the input is a pipe.
What we do is we build a string of the whole source, append the prefix
and built a lexing buffer from that.
We have to put all the source into the lexing buffer at once this way
for source quotation to work in error messages.
See ocaml#12238 and ocaml/driver/pparse.ml. *)
let all_source = prefix_read_from_source ^ In_channel.input_all ic in
let lexbuf = Lexing.from_string all_source in
lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = input_name };
Astlib.Location.set_input_lexbuf (Some lexbuf);
Skip_hash_bang.skip_hash_bang lexbuf;
let ast : Intf_or_impl.t =
match kind with
Expand Down
8 changes: 8 additions & 0 deletions test/driver/source-quotation-in-errors/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(executable
(name raising_driver)
(libraries ppxlib))

(cram
(enabled_if
(>= %{ocaml_version} "4.08.0"))
(deps raising_driver.exe))
14 changes: 14 additions & 0 deletions test/driver/source-quotation-in-errors/raising_driver.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
open Ppxlib

let rules =
[
Extension.V3.declare "raise" Extension.Context.expression
Ast_pattern.(pstr nil)
(fun ~ctxt ->
let loc = Expansion_context.Extension.extension_point_loc ctxt in
Location.raise_errorf ~loc "An exception, raise be!")
|> Context_free.Rule.extension;
]

let () = Driver.V2.register_transformation ~rules "raise"
let () = Driver.standalone ()
26 changes: 26 additions & 0 deletions test/driver/source-quotation-in-errors/run.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
When the ppxlib driver reports an error by itself, source quotation should work
properly.

We start off by explicitly setting the error reporting style to contextual to
ensure source quotation is enabled:

$ export OCAML_ERROR_STYLE=contextual

Here we have a driver compiled with a single rule that will raise a located
exception for every "[%raise]" extension point.

We need an input file:

$ cat > file.ml << EOF
> let x = [%raise]
> EOF

When running the driver on this file, it should report the error and show
the relevant quoted source:

$ ./raising_driver.exe -impl file.ml
File "file.ml", line 1, characters 8-16:
1 | let x = [%raise]
^^^^^^^^
Error: An exception, raise be!
[1]
Loading