Skip to content

Commit eed75dd

Browse files
authored
Merge pull request #535 from dra27/keywords_edition
PoC: support OCaml 5.3's `keywords` entry in `OCAMLPARAM`
2 parents f15df48 + 9deca0e commit eed75dd

File tree

7 files changed

+109
-0
lines changed

7 files changed

+109
-0
lines changed

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ details.
1212

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

15+
- Initialise OCaml 5.3's lexer with the `keywords` setting from `OCAMLPARAM` or
16+
the new `-keywords` driver's CLI option to allow the standalone ppx driver to
17+
process old packages using `effect` as an identifier
18+
(#535, @dra27, @NathanReb)
19+
1520
### Other changes
1621

1722
- Add `Pprintast.binding`, `longident` and `payload` (#542, @mattiasdrp)

astlib/keyword.ml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,43 @@ let is_keyword = function
5757
| "lsr" -> true
5858
| "asr" -> true
5959
| _ -> false
60+
61+
let apply_keyword_edition ~cli () =
62+
let from_ocaml_param =
63+
match Sys.getenv "OCAMLPARAM" with
64+
| s -> (
65+
let items =
66+
if String.equal s "" then []
67+
else
68+
(* cf. Compenv.parse_args *)
69+
match s.[0] with
70+
| (':' | '|' | ';' | ' ' | ',') as c ->
71+
List.tl (String.split_on_char c s)
72+
| _ -> String.split_on_char ',' s
73+
in
74+
let fold_settings (acc, after_cli) item =
75+
match (item, acc) with
76+
| "_", None -> (acc, true)
77+
| _ ->
78+
let len = String.length item in
79+
if len >= 9 && String.sub item 0 9 = "keywords=" then
80+
(Some (String.sub item 9 (len - 9)), after_cli)
81+
else (acc, after_cli)
82+
in
83+
let from_ocaml_param, after_cli =
84+
List.fold_left fold_settings (None, false) items
85+
in
86+
match from_ocaml_param with
87+
| None -> None
88+
| Some s -> Some (s, after_cli))
89+
| exception Not_found -> None
90+
in
91+
let keyword_edition =
92+
match (cli, from_ocaml_param) with
93+
| None, None -> None
94+
| None, Some (s, _) | Some _, Some (s, true) -> Some s
95+
| _ -> cli
96+
in
97+
(*IF_AT_LEAST 503 let () = if Option.is_some keyword_edition then Clflags.keyword_edition := keyword_edition in*)
98+
(*IF_NOT_AT_LEAST 503 let () = ignore keyword_edition in*)
99+
()

astlib/keyword.mli

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
val is_keyword : string -> bool
22
(** Check if a string is an OCaml keyword. *)
3+
4+
val apply_keyword_edition : cli:string option -> unit -> unit
5+
(** Processes any keywords= sections from the OCAMLPARAM environment variable
6+
and CLI option and initialises the compiler's lexer with the correct keyword
7+
set. *)

src/driver.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ let pretty = ref false
2424
let styler = ref None
2525
let output_metadata_filename = ref None
2626
let corrected_suffix = ref ".ppx-corrected"
27+
let keywords = ref None
2728

2829
let ghost =
2930
object
@@ -1409,6 +1410,14 @@ let standalone_args =
14091410
( "-corrected-suffix",
14101411
Arg.Set_string corrected_suffix,
14111412
"SUFFIX Suffix to append to corrected files" );
1413+
( "-keywords",
1414+
Arg.String (fun s -> keywords := Some s),
1415+
"<version+list> Set keywords according to the version+list \
1416+
specification. Allows using a set of keywords different from the one of \
1417+
the current compiler for backward compatibility." );
1418+
( "--keywords",
1419+
Arg.String (fun s -> keywords := Some s),
1420+
"<version+list> Same as -keywords" );
14121421
]
14131422

14141423
let get_args ?(standalone_args = standalone_args) () =
@@ -1418,6 +1427,7 @@ let standalone_main () =
14181427
let usage = Printf.sprintf "%s [extra_args] [<files>]" exe_name in
14191428
let args = get_args () in
14201429
Arg.parse (Arg.align args) set_input usage;
1430+
Astlib.Keyword.apply_keyword_edition ~cli:!keywords ();
14211431
interpret_mask ();
14221432
if !request_print_transformations then (
14231433
print_transformations ();

test/driver/keywords-option/driver.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
let () = Ppxlib.Driver.standalone ()

test/driver/keywords-option/dune

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
(executable
2+
(name driver)
3+
(enabled_if
4+
(>= %{ocaml_version} "5.3"))
5+
(libraries ppxlib))
6+
7+
(cram
8+
(enabled_if
9+
(>= %{ocaml_version} "5.3"))
10+
(deps driver.exe))

test/driver/keywords-option/run.t

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
This test can only work with OCaml 5.3 or higher.
2+
3+
OCaml 5.3 introduced the new `effect` keyword. To allow old code to compile
4+
under 5.3 it also introduced a `-keyword=version+list` CLI option, allowing one to
5+
override the set of keywords.
6+
7+
The ppxlib driver also has such an option now to properly configure the lexer before
8+
attempting to parse source code.
9+
10+
Let's consider the following source file:
11+
12+
$ cat > test.ml << EOF
13+
> let effect = 1
14+
> EOF
15+
16+
If passed to the driver as is, it will trigger a parse error:
17+
18+
$ ./driver.exe --impl test.ml -o ignore.ml
19+
File "test.ml", line 1, characters 4-10:
20+
1 | let effect = 1
21+
^^^^^^
22+
Error: Syntax error
23+
[1]
24+
25+
Now, if we use the 5.2 set of keywords, it should happily handle the file:
26+
27+
$ ./driver.exe --keywords 5.2 --impl test.ml -o ignore.ml
28+
29+
It can also be set using OCAMLPARAM:
30+
31+
$ OCAMLPARAM=_,keywords=5.2 ./driver.exe --impl test.ml -o ignore.ml
32+
33+
The priority between the CLI option and OCAMLPARAM must be respected, therefore
34+
both of the following invocation should parse:
35+
36+
$ OCAMLPARAM=_,keywords=5.2 ./driver.exe --keywords 5.3 --impl test.ml -o ignore.ml
37+
38+
$ OCAMLPARAM=keywords=5.3,_ ./driver.exe --keywords 5.2 --impl test.ml -o ignore.ml

0 commit comments

Comments
 (0)