diff --git a/CHANGES.md b/CHANGES.md index 70a1788e76..7ec9361a49 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,9 +14,14 @@ profile. This started with version 0.26.0. This might change the formatting of some functions due to the formatting code being completely rewritten. -- Support OCaml 5.3 syntax (#2609, #2610, #2611, #2622, @Julow) +- Support OCaml 5.3 syntax (#2609, #2610, #2611, #2622, #2623, @Julow) This adds support for short functor type arguments syntax and utf8 identifiers. + To format code using the new `effect` syntax, add this option to your + `.ocamlformat`: + ``` + ocaml-version = 5.3 + ``` - Documentation comments are now formatted by default (#2390, @Julow) Use the option `parse-docstrings = false` to restore the previous behavior. diff --git a/lib/Extended_ast.ml b/lib/Extended_ast.ml index 9a9172a112..a685f3142e 100644 --- a/lib/Extended_ast.ml +++ b/lib/Extended_ast.ml @@ -242,15 +242,18 @@ module Parse = struct map fg (normalize_mapper ~ocaml_version ~preserve_beginend) @@ let lexbuf = Lexing.from_string str in + let ocaml_version = + Some Ocaml_version.(major ocaml_version, minor ocaml_version) + in Location.init_info lexbuf input_name ; match fg with - | Structure -> Parse.implementation lexbuf - | Signature -> Parse.interface lexbuf - | Use_file -> Parse.use_file lexbuf - | Core_type -> Parse.core_type lexbuf - | Module_type -> Parse.module_type lexbuf - | Expression -> Parse.expression lexbuf - | Repl_file -> Toplevel_lexer.repl_file lexbuf + | Structure -> Parse.implementation ~ocaml_version lexbuf + | Signature -> Parse.interface ~ocaml_version lexbuf + | Use_file -> Parse.use_file ~ocaml_version lexbuf + | Core_type -> Parse.core_type ~ocaml_version lexbuf + | Module_type -> Parse.module_type ~ocaml_version lexbuf + | Expression -> Parse.expression ~ocaml_version lexbuf + | Repl_file -> Toplevel_lexer.repl_file ~ocaml_version lexbuf | Documentation -> let pos = (Location.curr lexbuf).loc_start in let pos = {pos with pos_fname= input_name} in diff --git a/lib/Parse_with_comments.ml b/lib/Parse_with_comments.ml index 966e0aa936..f60fb2bea6 100644 --- a/lib/Parse_with_comments.ml +++ b/lib/Parse_with_comments.ml @@ -84,7 +84,8 @@ let parse ?(disable_w50 = false) ?(disable_deprecated = false) parse fragment if Warning.is_deprecated_alert alert && disable_deprecated then false else not conf.opr_opts.quiet.v ) ~f:(fun () -> - let ast = parse fragment ~input_name source in + let ocaml_version = conf.opr_opts.ocaml_version.v in + let ast = parse fragment ~ocaml_version ~input_name source in Warnings.check_fatal () ; let comments = let mk_cmt = function @@ -102,9 +103,8 @@ let parse ?(disable_w50 = false) ?(disable_deprecated = false) parse fragment in match List.rev !w50 with [] -> t | w50 -> raise (Warning50 w50) -let parse_ast (conf : Conf.t) fg ~input_name s = - let ocaml_version = conf.opr_opts.ocaml_version.v - and preserve_beginend = Poly.(conf.fmt_opts.exp_grouping.v = `Preserve) in +let parse_ast (conf : Conf.t) fg ~ocaml_version ~input_name s = + let preserve_beginend = Poly.(conf.fmt_opts.exp_grouping.v = `Preserve) in Extended_ast.Parse.ast fg ~ocaml_version ~preserve_beginend ~input_name s (** [is_repl_block x] returns whether [x] is a list of REPL phrases and diff --git a/lib/Parse_with_comments.mli b/lib/Parse_with_comments.mli index 08fa3a1d99..f2fc03ce2b 100644 --- a/lib/Parse_with_comments.mli +++ b/lib/Parse_with_comments.mli @@ -29,7 +29,11 @@ exception Warning50 of (Location.t * Warnings.t) list val parse : ?disable_w50:bool -> ?disable_deprecated:bool - -> ('b -> input_name:string -> string -> 'a) + -> ( 'b + -> ocaml_version:Ocaml_version.t + -> input_name:string + -> string + -> 'a ) -> 'b -> Conf.t -> input_name:string @@ -50,5 +54,10 @@ val parse_toplevel : function handles [conf.parse_toplevel_phrases]. *) val parse_ast : - Conf.t -> 'a Extended_ast.t -> input_name:string -> string -> 'a + Conf.t + -> 'a Extended_ast.t + -> ocaml_version:Ocaml_version.t + -> input_name:string + -> string + -> 'a (** Argument to {!parse}. *) diff --git a/lib/Std_ast.ml b/lib/Std_ast.ml index a4f794ba8f..ad53edfc48 100644 --- a/lib/Std_ast.ml +++ b/lib/Std_ast.ml @@ -56,16 +56,19 @@ let map (type a) (x : a t) (m : Ast_mapper.mapper) : a -> a = | Documentation -> Fn.id module Parse = struct - let ast (type a) (fg : a t) ~input_name str : a = + let ast (type a) (fg : a t) ~ocaml_version ~input_name str : a = let lexbuf = Lexing.from_string str in + let ocaml_version = + Some Ocaml_version.(major ocaml_version, minor ocaml_version) + in Location.init_info lexbuf input_name ; match fg with - | Structure -> Parse.implementation lexbuf - | Signature -> Parse.interface lexbuf - | Use_file -> Parse.use_file lexbuf - | Core_type -> Parse.core_type lexbuf - | Module_type -> Parse.module_type lexbuf - | Expression -> Parse.expression lexbuf + | Structure -> Parse.implementation ~ocaml_version lexbuf + | Signature -> Parse.interface ~ocaml_version lexbuf + | Use_file -> Parse.use_file ~ocaml_version lexbuf + | Core_type -> Parse.core_type ~ocaml_version lexbuf + | Module_type -> Parse.module_type ~ocaml_version lexbuf + | Expression -> Parse.expression ~ocaml_version lexbuf | Repl_file -> () | Documentation -> () end diff --git a/lib/Std_ast.mli b/lib/Std_ast.mli index 5942908d2c..981b66e9ff 100644 --- a/lib/Std_ast.mli +++ b/lib/Std_ast.mli @@ -33,7 +33,12 @@ type any_t = Any : 'a t -> any_t [@@unboxed] val of_syntax : Syntax.t -> any_t module Parse : sig - val ast : 'a t -> input_name:string -> string -> 'a + val ast : + 'a t + -> ocaml_version:Ocaml_version.t + -> input_name:string + -> string + -> 'a end val equal : 'a t -> 'a -> 'a -> bool diff --git a/lib/Toplevel_lexer.mli b/lib/Toplevel_lexer.mli index 08bac8e64b..d7f3b4cbd1 100644 --- a/lib/Toplevel_lexer.mli +++ b/lib/Toplevel_lexer.mli @@ -9,4 +9,7 @@ (* *) (**************************************************************************) -val repl_file : Lexing.lexbuf -> Parsetree.repl_phrase list +val repl_file : + ocaml_version:(int * int) option + -> Lexing.lexbuf + -> Parsetree.repl_phrase list diff --git a/lib/Toplevel_lexer.mll b/lib/Toplevel_lexer.mll index 1bcc8a56a5..8b18db7f6f 100644 --- a/lib/Toplevel_lexer.mll +++ b/lib/Toplevel_lexer.mll @@ -52,7 +52,7 @@ and phrase buf = parse | _ as c { Buffer.add_char buf c; phrase buf lexbuf } { -let repl_file lx = +let repl_file ~ocaml_version lx = let x = token lx in let open Ocamlformat_parser_extended.Parsetree in List.fold_left (fun acc -> function @@ -61,7 +61,7 @@ let repl_file lx = let filename = (Location.curr lx).loc_start.pos_fname in Lexing.set_filename cmd_lexbuf filename ; Lexing.set_position cmd_lexbuf pos_start ; - { prepl_phrase= Parse.toplevel_phrase cmd_lexbuf + { prepl_phrase= Parse.toplevel_phrase ~ocaml_version cmd_lexbuf ; prepl_output= "" } :: acc | `Output ("", _) -> acc diff --git a/test/passing/gen/dune.inc b/test/passing/gen/dune.inc index ff65935a81..04e0fa5061 100644 --- a/test/passing/gen/dune.inc +++ b/test/passing/gen/dune.inc @@ -3712,6 +3712,21 @@ (alias runtest) (action (diff polytypes.ml.err polytypes.ml.stderr))) +(rule + (deps .ocamlformat dune-project) + (action + (with-stdout-to pre42_syntax.ml.stdout + (with-stderr-to pre42_syntax.ml.stderr + (run %{bin:ocamlformat} --name pre42_syntax.ml --margin-check --ocaml-version=4.1 %{dep:../tests/pre42_syntax.ml}))))) + +(rule + (alias runtest) + (action (diff pre42_syntax.ml.ref pre42_syntax.ml.stdout))) + +(rule + (alias runtest) + (action (diff pre42_syntax.ml.err pre42_syntax.ml.stderr))) + (rule (deps .ocamlformat dune-project) (action diff --git a/test/passing/refs.default/pre42_syntax.ml.ref b/test/passing/refs.default/pre42_syntax.ml.ref new file mode 100644 index 0000000000..847157c869 --- /dev/null +++ b/test/passing/refs.default/pre42_syntax.ml.ref @@ -0,0 +1,4 @@ +type nonrec = nonrec +(** The [nonrec] keyword has been added in OCaml 4.2. *) + +let nonrec nonrec : nonrec = nonrec diff --git a/test/passing/refs.janestreet/pre42_syntax.ml.ref b/test/passing/refs.janestreet/pre42_syntax.ml.ref new file mode 100644 index 0000000000..a99b3fe718 --- /dev/null +++ b/test/passing/refs.janestreet/pre42_syntax.ml.ref @@ -0,0 +1,4 @@ +(** The [nonrec] keyword has been added in OCaml 4.2. *) +type nonrec = nonrec + +let nonrec nonrec : nonrec = nonrec diff --git a/test/passing/refs.ocamlformat/pre42_syntax.ml.ref b/test/passing/refs.ocamlformat/pre42_syntax.ml.ref new file mode 100644 index 0000000000..a99b3fe718 --- /dev/null +++ b/test/passing/refs.ocamlformat/pre42_syntax.ml.ref @@ -0,0 +1,4 @@ +(** The [nonrec] keyword has been added in OCaml 4.2. *) +type nonrec = nonrec + +let nonrec nonrec : nonrec = nonrec diff --git a/test/passing/tests/pre42_syntax.ml b/test/passing/tests/pre42_syntax.ml new file mode 100644 index 0000000000..9e0f44b48d --- /dev/null +++ b/test/passing/tests/pre42_syntax.ml @@ -0,0 +1,3 @@ +(** The [nonrec] keyword has been added in OCaml 4.2. *) +type nonrec = nonrec +let nonrec nonrec : nonrec = nonrec diff --git a/test/passing/tests/pre42_syntax.ml.opts b/test/passing/tests/pre42_syntax.ml.opts new file mode 100644 index 0000000000..3385e6f309 --- /dev/null +++ b/test/passing/tests/pre42_syntax.ml.opts @@ -0,0 +1 @@ +--ocaml-version=4.1 diff --git a/tools/printast/printast.ml b/tools/printast/printast.ml index c940164aee..48337d6251 100644 --- a/tools/printast/printast.ml +++ b/tools/printast/printast.ml @@ -12,7 +12,7 @@ let extended_ast ppf syntax ~input_name content = let std_ast ppf syntax ~input_name content = let open Std_ast in let (Any kind) = of_syntax syntax in - Parse.ast kind ~input_name content |> Printast.ast kind ppf + Parse.ast kind ~ocaml_version ~input_name content |> Printast.ast kind ppf let get_arg () = let std = ref false and input = ref None in diff --git a/vendor/parser-extended/lexer.mll b/vendor/parser-extended/lexer.mll index e1941d0a63..d4631298b6 100644 --- a/vendor/parser-extended/lexer.mll +++ b/vendor/parser-extended/lexer.mll @@ -36,73 +36,100 @@ type error = | Invalid_char_in_ident of Uchar.t | Non_lowercase_delimiter of string | Capitalized_raw_identifier of string + | Unknown_keyword of string exception Error of error * Location.t (* The table of keywords *) -let keyword_table = - create_hashtable 149 [ - "and", AND; - "as", AS; - "assert", ASSERT; - "begin", BEGIN; - "class", CLASS; - "constraint", CONSTRAINT; - "do", DO; - "done", DONE; - "downto", DOWNTO; - "else", ELSE; - "end", END; - "exception", EXCEPTION; - "external", EXTERNAL; - "false", FALSE; - "for", FOR; - "fun", FUN; - "function", FUNCTION; - "functor", FUNCTOR; - "if", IF; - "in", IN; - "include", INCLUDE; - "inherit", INHERIT; - "initializer", INITIALIZER; - "lazy", LAZY; - "let", LET; - "match", MATCH; - "method", METHOD; - "module", MODULE; - "mutable", MUTABLE; - "new", NEW; - "nonrec", NONREC; - "object", OBJECT; - "of", OF; - "open", OPEN; - "or", OR; +let all_keywords = + let v1_0 = Some (1,0) in + let v1_6 = Some (1,6) in + let v4_2 = Some (4,2) in + let always = None in + [ + "and", AND, always; + "as", AS, always; + "assert", ASSERT, v1_6; + "begin", BEGIN, always; + "class", CLASS, v1_0; + "constraint", CONSTRAINT, v1_0; + "do", DO, always; + "done", DONE, always; + "downto", DOWNTO, always; + "else", ELSE, always; + "end", END, always; + "exception", EXCEPTION, always; + "external", EXTERNAL, always; + "false", FALSE, always; + "for", FOR, always; + "fun", FUN, always; + "function", FUNCTION, always; + "functor", FUNCTOR, always; + "if", IF, always; + "in", IN, always; + "include", INCLUDE, always; + "inherit", INHERIT, v1_0; + "initializer", INITIALIZER, v1_0; + "lazy", LAZY, v1_6; + "let", LET, always; + "match", MATCH, always; + "method", METHOD, v1_0; + "module", MODULE, always; + "mutable", MUTABLE, always; + "new", NEW, v1_0; + "nonrec", NONREC, v4_2; + "object", OBJECT, v1_0; + "of", OF, always; + "open", OPEN, always; + "or", OR, always; (* "parser", PARSER; *) - "private", PRIVATE; - "rec", REC; - "sig", SIG; - "struct", STRUCT; - "then", THEN; - "to", TO; - "true", TRUE; - "try", TRY; - "type", TYPE; - "val", VAL; - "virtual", VIRTUAL; - "when", WHEN; - "while", WHILE; - "with", WITH; - - "lor", INFIXOP3("lor"); (* Should be INFIXOP2 *) - "lxor", INFIXOP3("lxor"); (* Should be INFIXOP2 *) - "mod", INFIXOP3("mod"); - "land", INFIXOP3("land"); - "lsl", INFIXOP4("lsl"); - "lsr", INFIXOP4("lsr"); - "asr", INFIXOP4("asr") + "private", PRIVATE, v1_0; + "rec", REC, always; + "sig", SIG, always; + "struct", STRUCT, always; + "then", THEN, always; + "to", TO, always; + "true", TRUE, always; + "try", TRY, always; + "type", TYPE, always; + "val", VAL, always; + "virtual", VIRTUAL, v1_0; + "when", WHEN, always; + "while", WHILE, always; + "with", WITH, always; + + "lor", INFIXOP3("lor"), always; (* Should be INFIXOP2 *) + "lxor", INFIXOP3("lxor"), always; (* Should be INFIXOP2 *) + "mod", INFIXOP3("mod"), always; + "land", INFIXOP3("land"), always; + "lsl", INFIXOP4("lsl"), always; + "lsr", INFIXOP4("lsr"), always; + "asr", INFIXOP4("asr"), always ] + +let keyword_table = Hashtbl.create 149 + +let populate_keywords (version,keywords) = + let greater (x:(int*int) option) (y:(int*int) option) = + match x, y with + | None, _ | _, None -> true + | Some x, Some y -> x >= y + in + let tbl = keyword_table in + Hashtbl.clear tbl; + let add_keyword (name, token, since) = + if greater version since then Hashtbl.replace tbl name (Some token) + in + List.iter add_keyword all_keywords; + List.iter (fun name -> + match List.find (fun (n,_,_) -> n = name) all_keywords with + | (_,tok,_) -> Hashtbl.replace tbl name (Some tok) + | exception Not_found -> Hashtbl.replace tbl name None + ) keywords + + (* To buffer string literals *) let string_buffer = Buffer.create 256 @@ -266,7 +293,14 @@ let lax_delim raw_name = if Utf8_lexeme.is_lowercase name then Some name else None -let is_keyword name = Hashtbl.mem keyword_table name +let is_keyword name = + Hashtbl.mem keyword_table name + +let find_keyword lexbuf name = + match Hashtbl.find keyword_table name with + | Some x -> x + | None -> error lexbuf (Unknown_keyword name) + | exception Not_found -> LIDENT name let check_label_name ?(raw_escape=false) lexbuf name = if Utf8_lexeme.is_capitalized name then @@ -399,6 +433,11 @@ let prepare_error loc = function "%a cannot be used as a quoted string delimiter,@ \ it must contain only lowercase letters." Style.inline_code name + | Unknown_keyword name -> + Location.errorf ~loc + "%a has been defined as an additional keyword.@ \ + This version of OCaml does not support this keyword." + Style.inline_code name let () = Location.register_error_of_exn @@ -493,8 +532,7 @@ rule token = parse OPTLABEL (escape ^ name) } | lowercase identchar * as name - { try Hashtbl.find keyword_table name - with Not_found -> LIDENT name } + { find_keyword lexbuf name } | uppercase identchar * as name { UIDENT name } (* No capitalized keywords *) | (raw_ident_escape? as escape) (ident_ext as raw_name) @@ -954,7 +992,8 @@ and skip_hash_bang = parse in loop NoLine Initial lexbuf - let init () = + let init ?(keyword_edition=None,[]) () = + populate_keywords keyword_edition; is_in_string := false; comment_start_loc := []; comment_list := []; diff --git a/vendor/parser-extended/parse.ml b/vendor/parser-extended/parse.ml index 0f141cf098..6394464fc4 100644 --- a/vendor/parser-extended/parse.ml +++ b/vendor/parser-extended/parse.ml @@ -42,10 +42,13 @@ let maybe_skip_phrase lexbuf = type 'a parser = Lexing.position -> 'a Parser.MenhirInterpreter.checkpoint -let wrap (parser : 'a parser) lexbuf : 'a = +let wrap (parser : 'a parser) ~ocaml_version lexbuf : 'a = try Docstrings.init (); - Lexer.init (); + let keyword_edition = + Some (ocaml_version, []) + in + Lexer.init ?keyword_edition (); let open Parser.MenhirInterpreter in let rec fix_resume = function | InputNeeded _ | Accepted _ | Rejected | HandlingError _ as cp -> cp diff --git a/vendor/parser-standard/lexer.mll b/vendor/parser-standard/lexer.mll index 5fad8bc9b4..572c05812d 100644 --- a/vendor/parser-standard/lexer.mll +++ b/vendor/parser-standard/lexer.mll @@ -36,73 +36,100 @@ type error = | Invalid_char_in_ident of Uchar.t | Non_lowercase_delimiter of string | Capitalized_raw_identifier of string + | Unknown_keyword of string exception Error of error * Location.t (* The table of keywords *) -let keyword_table = - create_hashtable 149 [ - "and", AND; - "as", AS; - "assert", ASSERT; - "begin", BEGIN; - "class", CLASS; - "constraint", CONSTRAINT; - "do", DO; - "done", DONE; - "downto", DOWNTO; - "else", ELSE; - "end", END; - "exception", EXCEPTION; - "external", EXTERNAL; - "false", FALSE; - "for", FOR; - "fun", FUN; - "function", FUNCTION; - "functor", FUNCTOR; - "if", IF; - "in", IN; - "include", INCLUDE; - "inherit", INHERIT; - "initializer", INITIALIZER; - "lazy", LAZY; - "let", LET; - "match", MATCH; - "method", METHOD; - "module", MODULE; - "mutable", MUTABLE; - "new", NEW; - "nonrec", NONREC; - "object", OBJECT; - "of", OF; - "open", OPEN; - "or", OR; +let all_keywords = + let v1_0 = Some (1,0) in + let v1_6 = Some (1,6) in + let v4_2 = Some (4,2) in + let always = None in + [ + "and", AND, always; + "as", AS, always; + "assert", ASSERT, v1_6; + "begin", BEGIN, always; + "class", CLASS, v1_0; + "constraint", CONSTRAINT, v1_0; + "do", DO, always; + "done", DONE, always; + "downto", DOWNTO, always; + "else", ELSE, always; + "end", END, always; + "exception", EXCEPTION, always; + "external", EXTERNAL, always; + "false", FALSE, always; + "for", FOR, always; + "fun", FUN, always; + "function", FUNCTION, always; + "functor", FUNCTOR, always; + "if", IF, always; + "in", IN, always; + "include", INCLUDE, always; + "inherit", INHERIT, v1_0; + "initializer", INITIALIZER, v1_0; + "lazy", LAZY, v1_6; + "let", LET, always; + "match", MATCH, always; + "method", METHOD, v1_0; + "module", MODULE, always; + "mutable", MUTABLE, always; + "new", NEW, v1_0; + "nonrec", NONREC, v4_2; + "object", OBJECT, v1_0; + "of", OF, always; + "open", OPEN, always; + "or", OR, always; (* "parser", PARSER; *) - "private", PRIVATE; - "rec", REC; - "sig", SIG; - "struct", STRUCT; - "then", THEN; - "to", TO; - "true", TRUE; - "try", TRY; - "type", TYPE; - "val", VAL; - "virtual", VIRTUAL; - "when", WHEN; - "while", WHILE; - "with", WITH; - - "lor", INFIXOP3("lor"); (* Should be INFIXOP2 *) - "lxor", INFIXOP3("lxor"); (* Should be INFIXOP2 *) - "mod", INFIXOP3("mod"); - "land", INFIXOP3("land"); - "lsl", INFIXOP4("lsl"); - "lsr", INFIXOP4("lsr"); - "asr", INFIXOP4("asr") + "private", PRIVATE, v1_0; + "rec", REC, always; + "sig", SIG, always; + "struct", STRUCT, always; + "then", THEN, always; + "to", TO, always; + "true", TRUE, always; + "try", TRY, always; + "type", TYPE, always; + "val", VAL, always; + "virtual", VIRTUAL, v1_0; + "when", WHEN, always; + "while", WHILE, always; + "with", WITH, always; + + "lor", INFIXOP3("lor"), always; (* Should be INFIXOP2 *) + "lxor", INFIXOP3("lxor"), always; (* Should be INFIXOP2 *) + "mod", INFIXOP3("mod"), always; + "land", INFIXOP3("land"), always; + "lsl", INFIXOP4("lsl"), always; + "lsr", INFIXOP4("lsr"), always; + "asr", INFIXOP4("asr"), always ] + +let keyword_table = Hashtbl.create 149 + +let populate_keywords (version,keywords) = + let greater (x:(int*int) option) (y:(int*int) option) = + match x, y with + | None, _ | _, None -> true + | Some x, Some y -> x >= y + in + let tbl = keyword_table in + Hashtbl.clear tbl; + let add_keyword (name, token, since) = + if greater version since then Hashtbl.replace tbl name (Some token) + in + List.iter add_keyword all_keywords; + List.iter (fun name -> + match List.find (fun (n,_,_) -> n = name) all_keywords with + | (_,tok,_) -> Hashtbl.replace tbl name (Some tok) + | exception Not_found -> Hashtbl.replace tbl name None + ) keywords + + (* To buffer string literals *) let string_buffer = Buffer.create 256 @@ -293,7 +320,14 @@ let lax_delim raw_name = if Utf8_lexeme.is_lowercase name then Some name else None -let is_keyword name = Hashtbl.mem keyword_table name +let is_keyword name = + Hashtbl.mem keyword_table name + +let find_keyword lexbuf name = + match Hashtbl.find keyword_table name with + | Some x -> x + | None -> error lexbuf (Unknown_keyword name) + | exception Not_found -> LIDENT name let check_label_name ?(raw_escape=false) lexbuf name = if Utf8_lexeme.is_capitalized name then @@ -425,6 +459,11 @@ let prepare_error loc = function "%a cannot be used as a quoted string delimiter,@ \ it must contain only lowercase letters." Style.inline_code name + | Unknown_keyword name -> + Location.errorf ~loc + "%a has been defined as an additional keyword.@ \ + This version of OCaml does not support this keyword." + Style.inline_code name let () = Location.register_error_of_exn @@ -519,8 +558,7 @@ rule token = parse OPTLABEL name } | lowercase identchar * as name - { try Hashtbl.find keyword_table name - with Not_found -> LIDENT name } + { find_keyword lexbuf name } | uppercase identchar * as name { UIDENT name } (* No capitalized keywords *) | (raw_ident_escape? as escape) (ident_ext as raw_name) @@ -983,7 +1021,8 @@ and skip_hash_bang = parse in loop NoLine Initial lexbuf - let init () = + let init ?(keyword_edition=None,[]) () = + populate_keywords keyword_edition; is_in_string := false; comment_start_loc := []; comment_list := []; diff --git a/vendor/parser-standard/parse.ml b/vendor/parser-standard/parse.ml index 0f141cf098..6394464fc4 100644 --- a/vendor/parser-standard/parse.ml +++ b/vendor/parser-standard/parse.ml @@ -42,10 +42,13 @@ let maybe_skip_phrase lexbuf = type 'a parser = Lexing.position -> 'a Parser.MenhirInterpreter.checkpoint -let wrap (parser : 'a parser) lexbuf : 'a = +let wrap (parser : 'a parser) ~ocaml_version lexbuf : 'a = try Docstrings.init (); - Lexer.init (); + let keyword_edition = + Some (ocaml_version, []) + in + Lexer.init ?keyword_edition (); let open Parser.MenhirInterpreter in let rec fix_resume = function | InputNeeded _ | Accepted _ | Rejected | HandlingError _ as cp -> cp