Skip to content

Commit

Permalink
Merge pull request #535 from dra27/keywords_edition
Browse files Browse the repository at this point in the history
PoC: support OCaml 5.3's `keywords` entry in `OCAMLPARAM`
  • Loading branch information
NathanReb authored Dec 13, 2024
2 parents f15df48 + 9deca0e commit eed75dd
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ details.

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

- 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

- Add `Pprintast.binding`, `longident` and `payload` (#542, @mattiasdrp)
Expand Down
40 changes: 40 additions & 0 deletions astlib/keyword.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,43 @@ let is_keyword = function
| "lsr" -> true
| "asr" -> true
| _ -> false

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: 5 additions & 0 deletions astlib/keyword.mli
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
val is_keyword : string -> bool
(** Check if a string is an OCaml keyword. *)

val apply_keyword_edition : cli:string option -> unit -> unit
(** Processes any keywords= sections from the OCAMLPARAM environment variable
and CLI option and initialises the compiler's lexer with the correct keyword
set. *)
10 changes: 10 additions & 0 deletions 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 backward compatibility." );
( "--keywords",
Arg.String (fun s -> keywords := Some s),
"<version+list> Same as -keywords" );
]

let get_args ?(standalone_args = standalone_args) () =
Expand All @@ -1418,6 +1427,7 @@ let standalone_main () =
let usage = Printf.sprintf "%s [extra_args] [<files>]" exe_name in
let args = get_args () in
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 eed75dd

Please sign in to comment.