Skip to content

Commit

Permalink
Remove dependency on fstar's Getopt, bring a copy here
Browse files Browse the repository at this point in the history
Coding against internal modules of the F* compiler is not maintainable,
and there is no need to do so here. With the new build, fstar-lib will
not even include this module (although maybe it could eventually), so
this is also more future-proof.
  • Loading branch information
mtzguido committed Oct 11, 2024
1 parent 6e15b95 commit 5f45a69
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/3d/FStarC.Getopt.fsti → src/3d/Getopt.fsti
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
*)
module FStarC.Getopt
module Getopt
open FStar.ST
open FStar.All
open FStar.Char
Expand Down
30 changes: 15 additions & 15 deletions src/3d/Options.fst
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ type cmd_option_kind =
(v: ref (list (valid_string valid))) ->
cmd_option_kind
let fstar_opt = FStarC.Getopt.opt & string
let fstar_opt = Getopt.opt & string
noeq
type cmd_option
Expand Down Expand Up @@ -167,7 +167,7 @@ let cmd_option_arg_desc (a: cmd_option) : Tot string =
match a with
| CmdFStarOption ((_, _, arg), _) ->
begin match arg with
| FStarC.Getopt.OneArg (_, argdesc) -> argdesc
| Getopt.OneArg (_, argdesc) -> argdesc
| _ -> ""
end
| CmdOption _ kind _ _ ->
Expand Down Expand Up @@ -206,15 +206,15 @@ let fstar_options_of_cmd_option
begin match kind with
| OptBool v ->
[
((FStarC.Getopt.noshort, name, FStarC.Getopt.ZeroArgs (fun _ -> set_implies options implies; v := true)), desc);
((FStarC.Getopt.noshort, negate_name name, FStarC.Getopt.ZeroArgs (fun _ -> v := false)), negate_description desc);
((Getopt.noshort, name, Getopt.ZeroArgs (fun _ -> set_implies options implies; v := true)), desc);
((Getopt.noshort, negate_name name, Getopt.ZeroArgs (fun _ -> v := false)), negate_description desc);
]
| OptStringOption arg_desc valid v ->
[
(
(
FStarC.Getopt.noshort, name,
FStarC.Getopt.OneArg (
Getopt.noshort, name,
Getopt.OneArg (
(fun (x: string) ->
if valid x
then begin
Expand All @@ -228,14 +228,14 @@ let fstar_options_of_cmd_option
),
desc
);
((FStarC.Getopt.noshort, negate_name name, FStarC.Getopt.ZeroArgs (fun _ -> v := None)), negate_description desc)
((Getopt.noshort, negate_name name, Getopt.ZeroArgs (fun _ -> v := None)), negate_description desc)
]
| OptList arg_desc valid v ->
[
(
(
FStarC.Getopt.noshort, name,
FStarC.Getopt.OneArg (
Getopt.noshort, name,
Getopt.OneArg (
(fun (x: string) ->
if valid x
then begin
Expand All @@ -251,8 +251,8 @@ let fstar_options_of_cmd_option
);
(
(
FStarC.Getopt.noshort, negate_name name,
FStarC.Getopt.ZeroArgs (fun _ -> v := [])
Getopt.noshort, negate_name name,
Getopt.ZeroArgs (fun _ -> v := [])
),
desc
);
Expand Down Expand Up @@ -342,7 +342,7 @@ let (display_usage_2, compute_options_2, fstar_options) =
CmdOption "input_stream_include" (OptStringOption ".h file" always_valid input_stream_include) "Include file defining the EverParseInputStreamBase type (only for --input_stream extern or static)" [];
CmdOption "no_copy_everparse_h" (OptBool no_copy_everparse_h) "Do not Copy EverParse.h (--batch only)" [];
CmdOption "debug" (OptBool debug) "Emit a lot of debugging output" [];
CmdFStarOption (('h', "help", FStarC.Getopt.ZeroArgs (fun _ -> display_usage (); exit 0)), "Show this help message");
CmdFStarOption (('h', "help", Getopt.ZeroArgs (fun _ -> display_usage (); exit 0)), "Show this help message");
CmdOption "json" (OptBool json) "Dump the AST in JSON format" [];
CmdOption "makefile" (OptStringOption "gmake|nmake" valid_makefile makefile) "Do not produce anything, other than a Makefile to produce everything" [];
CmdOption "makefile_name" (OptStringOption "some file name" always_valid makefile_name) "Name of the Makefile to produce (with --makefile, default <output directory>/EverParse.Makefile" [];
Expand All @@ -352,7 +352,7 @@ let (display_usage_2, compute_options_2, fstar_options) =
CmdOption "skip_c_makefiles" (OptBool skip_c_makefiles) "Do not Generate Makefile.basic, Makefile.include" [];
CmdOption "skip_o_rules" (OptBool skip_o_rules) "With --makefile, do not generate rules for .o files" [];
CmdOption "test_checker" (OptStringOption "parser name" always_valid test_checker) "produce a test checker executable" [];
CmdFStarOption ((let open FStarC.Getopt in noshort, "version", ZeroArgs (fun _ -> FStar.IO.print_string (Printf.sprintf "EverParse/3d %s\nCopyright 2018, 2019, 2020 Microsoft Corporation\n" Version.everparse_version); exit 0)), "Show this version of EverParse");
CmdFStarOption ((let open Getopt in noshort, "version", ZeroArgs (fun _ -> FStar.IO.print_string (Printf.sprintf "EverParse/3d %s\nCopyright 2018, 2019, 2020 Microsoft Corporation\n" Version.everparse_version); exit 0)), "Show this version of EverParse");
CmdOption "equate_types" (OptList "an argument of the form A,B, to generate asserts of the form (A.t == B.t)" valid_equate_types equate_types_list) "Takes an argument of the form A,B and then for each entrypoint definition in B, it generates an assert (A.t == B.t) in the B.Types file, useful when refactoring specs, you can provide multiple equate_types on the command line" [];
CmdOption "z3_branch_depth" (OptStringOption "nb" always_valid z3_branch_depth) "enumerate branch choices up to depth nb (default 0)" [];
CmdOption "z3_diff_test" (OptStringOption "parser1,parser2" valid_equate_types z3_diff_test) "produce differential tests for two parsers" [];
Expand All @@ -376,8 +376,8 @@ let display_usage = display_usage_2
let compute_options = compute_options_2
let parse_cmd_line () : ML (list string) =
let open FStarC.Getopt in
let res = FStarC.Getopt.parse_cmdline (List.Tot.map fst fstar_options) (fun file -> input_file := file :: !input_file; Success) in
let open Getopt in
let res = Getopt.parse_cmdline (List.Tot.map fst fstar_options) (fun file -> input_file := file :: !input_file; Success) in
match res with
| Success -> !input_file
| Help -> display_usage(); exit 0
Expand Down
108 changes: 108 additions & 0 deletions src/3d/ocaml/Getopt.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
let noshort = 0
type 'a opt_variant =
| ZeroArgs of (unit -> 'a)
| OneArg of (string -> 'a) * string
type 'a opt' = FStar_Char.char * string * 'a opt_variant
type opt = unit opt'
type parse_cmdline_res =
| Empty
| Help
| Error of string
| Success

let bind l f =
match l with
| Help
| Error _ -> l
| Success -> f ()
(* | Empty *)
(* ^ Empty does not occur internally. *)

(* Returns None if this wasn't an option arg (did not start with "-")
* Otherwise, returns Some (o, s) where [s] is the trimmed option, and [o]
* is the opt we found in specs (possibly None if not present, which should
* trigger an error) *)
let find_matching_opt specs s : (opt option * string) option =
if String.length s < 2 then
None
else if String.sub s 0 2 = "--" then
(* long opts *)
let strim = String.sub s 2 ((String.length s) - 2) in
let o = FStar_List.tryFind (fun (_, option, _) -> option = strim) specs in
Some (o, strim)
else if String.sub s 0 1 = "-" then
(* short opts *)
let strim = String.sub s 1 ((String.length s) - 1) in
let o = FStar_List.tryFind (fun (shortoption, _, _) -> FStar_String.make Z.one shortoption = strim) specs in
Some (o, strim)
else
None

(* remark: doesn't work with files starting with -- *)
let rec parse (opts:opt list) def ar ix max i : parse_cmdline_res =
if ix > max then Success
else
let arg = ar.(ix) in
let go_on () = bind (def arg) (fun _ -> parse opts def ar (ix + 1) max (i + 1)) in
match find_matching_opt opts arg with
| None -> go_on ()
| Some (None, _) -> Error ("unrecognized option '" ^ arg ^ "'\n")
| Some (Some (_, _, p), argtrim) ->
begin match p with
| ZeroArgs f -> f (); parse opts def ar (ix + 1) max (i + 1)
| OneArg (f, _) ->
if ix + 1 > max
then Error ("last option '" ^ argtrim ^ "' takes an argument but has none\n")
else
let r =
try (f (ar.(ix + 1)); Success)
with _ -> Error ("wrong argument given to option `" ^ argtrim ^ "`\n")
in bind r (fun () -> parse opts def ar (ix + 2) max (i + 1))
end

let parse_array specs others args offset =
parse specs others args offset (Array.length args - 1) 0

let parse_cmdline specs others =
if Array.length Sys.argv = 1 then Empty
else parse_array specs others Sys.argv 1

let parse_string specs others (str:string) =
let split_spaces (str:string) =
let seps = [int_of_char ' '; int_of_char '\t'] in
FStar_List.filter (fun s -> s != "") (FStar_String.split seps str)
in
(* to match the style of the F# code in FStar.GetOpt.fs *)
let index_of str c =
try
String.index str c
with Not_found -> -1
in
let substring_from s j =
let len = String.length s - j in
String.sub s j len
in
let rec split_quoted_fragments (str:string) =
let i = index_of str '\'' in
if i < 0 then Some (split_spaces str)
else let prefix = String.sub str 0 i in
let suffix = substring_from str (i + 1) in
let j = index_of suffix '\'' in
if j < 0 then None
else let quoted_frag = String.sub suffix 0 j in
let rest = split_quoted_fragments (substring_from suffix (j + 1)) in
match rest with
| None -> None
| Some rest -> Some (split_spaces prefix @ quoted_frag::rest)

in
match split_quoted_fragments str with
| None -> Error("Failed to parse options; unmatched quote \"'\"")
| Some args ->
parse_array specs others (Array.of_list args) 0

let parse_list specs others lst =
parse_array specs others (Array.of_list lst) 0

let cmdline () =
Array.to_list (Sys.argv)

0 comments on commit 5f45a69

Please sign in to comment.