Skip to content

Commit

Permalink
Add -keywords CLI argument to the driver, matching the compilers
Browse files Browse the repository at this point in the history
Signed-off-by: Nathan Rebours <[email protected]>
  • Loading branch information
NathanReb committed Dec 9, 2024
1 parent 2c602da commit 7e48f7d
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 29 deletions.
7 changes: 4 additions & 3 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ details.

- Add initial OCaml 5.3 support (#487, @NathanReb, @hhugo, @nojb)

- Initialise OCaml 5.3's lexer with the `keywords` setting from `OCAMLPARAM` to
allow the standalone ppx driver to process old packages using `effect` as an
identifier (#535, @dra27)
- Initialise OCaml 5.3's lexer with the `keywords` setting from `OCAMLPARAM` or
the new `-keywords` driver's CLI option to allow the standalone ppx driver to
process old packages using `effect` as an identifier
(#535, @dra27, @NathanReb)

### Other changes

Expand Down
62 changes: 39 additions & 23 deletions astlib/keyword.ml
Original file line number Diff line number Diff line change
Expand Up @@ -58,26 +58,42 @@ let is_keyword = function
| "asr" -> true
| _ -> false

let apply_keyword_edition () =
match Sys.getenv "OCAMLPARAM" with
| s ->
let items =
if String.equal s "" then []
else
(* cf. Compenv.parse_args *)
match s.[0] with
| (':' | '|' | ';' | ' ' | ',') as c ->
List.tl (String.split_on_char c s)
| _ -> String.split_on_char ',' s
in
let fold_settings acc item =
let len = String.length item in
if len >= 9 && String.sub item 0 9 = "keywords=" then
Some (String.sub item 9 (len - 9))
else acc
in
let keyword_edition = List.fold_left fold_settings None items in
(*IF_AT_LEAST 503 let () = if Option.is_some keyword_edition then Clflags.keyword_edition := keyword_edition in*)
(*IF_NOT_AT_LEAST 503 let () = ignore keyword_edition in*)
()
| exception Not_found -> ()
let apply_keyword_edition ~cli () =
let from_ocaml_param =
match Sys.getenv "OCAMLPARAM" with
| s -> (
let items =
if String.equal s "" then []
else
(* cf. Compenv.parse_args *)
match s.[0] with
| (':' | '|' | ';' | ' ' | ',') as c ->
List.tl (String.split_on_char c s)
| _ -> String.split_on_char ',' s
in
let fold_settings (acc, after_cli) item =
match (item, acc) with
| "_", None -> (acc, true)
| _ ->
let len = String.length item in
if len >= 9 && String.sub item 0 9 = "keywords=" then
(Some (String.sub item 9 (len - 9)), after_cli)
else (acc, after_cli)
in
let from_ocaml_param, after_cli =
List.fold_left fold_settings (None, false) items
in
match from_ocaml_param with
| None -> None
| Some s -> Some (s, after_cli))
| exception Not_found -> None
in
let keyword_edition =
match (cli, from_ocaml_param) with
| None, None -> None
| None, Some (s, _) | Some _, Some (s, true) -> Some s
| _ -> cli
in
(*IF_AT_LEAST 503 let () = if Option.is_some keyword_edition then Clflags.keyword_edition := keyword_edition in*)
(*IF_NOT_AT_LEAST 503 let () = ignore keyword_edition in*)
()
5 changes: 3 additions & 2 deletions astlib/keyword.mli
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
val is_keyword : string -> bool
(** Check if a string is an OCaml keyword. *)

val apply_keyword_edition : unit -> unit
val apply_keyword_edition : cli:string option -> unit -> unit
(** Processes any keywords= sections from the OCAMLPARAM environment variable
and initialises the compiler's lexer with the correct keyword set. *)
and CLI option and initialises the compiler's lexer with the correct keyword
set. *)
11 changes: 10 additions & 1 deletion src/driver.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ let pretty = ref false
let styler = ref None
let output_metadata_filename = ref None
let corrected_suffix = ref ".ppx-corrected"
let keywords = ref None

let ghost =
object
Expand Down Expand Up @@ -1409,6 +1410,14 @@ let standalone_args =
( "-corrected-suffix",
Arg.Set_string corrected_suffix,
"SUFFIX Suffix to append to corrected files" );
( "-keywords",
Arg.String (fun s -> keywords := Some s),
"<version+list> Set keywords according to the version+list \
specification. Allows using a set of keywords different from the one of \
the current compiler for backword compatibility." );
( "--keywords",
Arg.String (fun s -> keywords := Some s),
"<version+list> Same as -keywords" );
]

let get_args ?(standalone_args = standalone_args) () =
Expand All @@ -1417,8 +1426,8 @@ let get_args ?(standalone_args = standalone_args) () =
let standalone_main () =
let usage = Printf.sprintf "%s [extra_args] [<files>]" exe_name in
let args = get_args () in
Astlib.Keyword.apply_keyword_edition ();
Arg.parse (Arg.align args) set_input usage;
Astlib.Keyword.apply_keyword_edition ~cli:!keywords ();
interpret_mask ();
if !request_print_transformations then (
print_transformations ();
Expand Down
1 change: 1 addition & 0 deletions test/driver/keywords-option/driver.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let () = Ppxlib.Driver.standalone ()
10 changes: 10 additions & 0 deletions test/driver/keywords-option/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(executable
(name driver)
(enabled_if
(>= %{ocaml_version} "5.3"))
(libraries ppxlib))

(cram
(enabled_if
(>= %{ocaml_version} "5.3"))
(deps driver.exe))
38 changes: 38 additions & 0 deletions test/driver/keywords-option/run.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
This test can only work with OCaml 5.3 or higher.

OCaml 5.3 introduced the new `effect` keyword. To allow old code to compile
under 5.3 it also introduced a `-keyword=version+list` CLI option, allowing one to
override the set of keywords.

The ppxlib driver also has such an option now to properly configure the lexer before
attempting to parse source code.

Let's consider the following source file:
$ cat > test.ml << EOF
> let effect = 1
> EOF
If passed to the driver as is, it will trigger a parse error:
$ ./driver.exe --impl test.ml -o ignore.ml
File "test.ml", line 1, characters 4-10:
1 | let effect = 1
^^^^^^
Error: Syntax error
[1]
Now, if we use the 5.2 set of keywords, it should happily handle the file:
$ ./driver.exe --keywords 5.2 --impl test.ml -o ignore.ml
It can also be set using OCAMLPARAM:
$ OCAMLPARAM=_,keywords=5.2 ./driver.exe --impl test.ml -o ignore.ml
The priority between the CLI option and OCAMLPARAM must be respected, therefore
both of the following invocation should parse:
$ OCAMLPARAM=_,keywords=5.2 ./driver.exe --keywords 5.3 --impl test.ml -o ignore.ml
$ OCAMLPARAM=keywords=5.3,_ ./driver.exe --keywords 5.2 --impl test.ml -o ignore.ml

0 comments on commit 7e48f7d

Please sign in to comment.