diff options
Diffstat (limited to 'bin')
-rw-r--r-- | bin/dune | 14 | ||||
-rw-r--r-- | bin/main.ml | 26 | ||||
-rw-r--r-- | bin/repl.ml | 52 | ||||
-rw-r--r-- | bin/repl_cmd.ml | 178 | ||||
-rw-r--r-- | bin/run.ml | 163 | ||||
-rw-r--r-- | bin/settings.ml | 120 |
6 files changed, 553 insertions, 0 deletions
diff --git a/bin/dune b/bin/dune new file mode 100644 index 0000000..2a56b29 --- /dev/null +++ b/bin/dune | |||
@@ -0,0 +1,14 @@ | |||
1 | (executable | ||
2 | (public_name mininix) | ||
3 | (name main) | ||
4 | (preprocess | ||
5 | (pps ppx_let)) | ||
6 | (libraries | ||
7 | nix | ||
8 | core | ||
9 | core_unix.command_unix | ||
10 | linenoise | ||
11 | mininix | ||
12 | sexp_pretty | ||
13 | stdio | ||
14 | ppx_let)) | ||
diff --git a/bin/main.ml b/bin/main.ml new file mode 100644 index 0000000..e4ca4b9 --- /dev/null +++ b/bin/main.ml | |||
@@ -0,0 +1,26 @@ | |||
1 | open Core | ||
2 | |||
3 | let repl = | ||
4 | Command.basic ~summary:"run the Mininix REPL" (Command.Param.return Repl.run) | ||
5 | |||
6 | let eval = | ||
7 | Command.basic ~summary:"run a Nix file" | ||
8 | (let%map_open.Command filename = anon ("FILENAME" %: string) | ||
9 | and strict = flag "strict" no_arg ~doc:"use deep evaluation strategy" | ||
10 | and importsdef = | ||
11 | flag "importsdef" (optional string) ~doc:"import tree definition file" | ||
12 | in | ||
13 | fun () -> | ||
14 | Settings.opts.eval_strategy := if strict then `Deep else `Shallow; | ||
15 | Settings.opts.imports_def_file := importsdef; | ||
16 | let ok = | ||
17 | if String.(filename = "-") then Run.eval_stdin () | ||
18 | else Run.eval_file filename | ||
19 | in | ||
20 | if ok then exit 0 else exit 1) | ||
21 | |||
22 | let main = | ||
23 | Command.group ~summary:"the Mininix interpreter" | ||
24 | [ ("repl", repl); ("eval", eval) ] | ||
25 | |||
26 | let () = Command_unix.run main | ||
diff --git a/bin/repl.ml b/bin/repl.ml new file mode 100644 index 0000000..092c503 --- /dev/null +++ b/bin/repl.ml | |||
@@ -0,0 +1,52 @@ | |||
1 | open Core | ||
2 | open Option.Let_syntax | ||
3 | |||
4 | let ok = ref true | ||
5 | let opts = Settings.opts | ||
6 | |||
7 | let rec user_input cb = | ||
8 | let prompt = (if !ok then "[okay]" else "[fail]") ^ " (mini)nix> " in | ||
9 | try | ||
10 | match LNoise.linenoise prompt with | ||
11 | | None -> () | ||
12 | | Some v -> | ||
13 | cb v; | ||
14 | user_input cb | ||
15 | with Sys_unix.Break -> | ||
16 | printf "\n%!"; | ||
17 | user_input cb | ||
18 | |||
19 | let split_cmd_prefix cmd = | ||
20 | let%bind cmd = String.chop_prefix ~prefix:":" cmd in | ||
21 | let cmd' = Repl_cmd.lstrip_space cmd in | ||
22 | let space = String.chop_suffix_exn cmd ~suffix:cmd' in | ||
23 | return (":" ^ space, cmd') | ||
24 | |||
25 | let handle_cmd cmd = | ||
26 | let cmd = Repl_cmd.strip_space cmd in | ||
27 | (match split_cmd_prefix cmd with | ||
28 | | Some (_, cmd) -> ok := Repl_cmd.invoke cmd | ||
29 | | None -> | ||
30 | if String.(strip cmd <> "") then | ||
31 | ok := Run.eval_expr cmd ~origin:Interactive); | ||
32 | printf "\n%!" | ||
33 | |||
34 | let run () = | ||
35 | LNoise.set_multiline true; | ||
36 | LNoise.history_load ~filename:"mininix_history" |> ignore; | ||
37 | LNoise.history_set ~max_length:500 |> ignore; | ||
38 | LNoise.set_hints_callback (fun line -> | ||
39 | let%bind _, cmd = split_cmd_prefix line in | ||
40 | let%bind hint = Repl_cmd.hint cmd in | ||
41 | return (hint, LNoise.Yellow, true)); | ||
42 | LNoise.set_completion_callback (fun line_so_far completions -> | ||
43 | match split_cmd_prefix line_so_far with | ||
44 | | Some (prefix, cmd_so_far) -> | ||
45 | Repl_cmd.complete cmd_so_far | ||
46 | |> List.map ~f:(String.append prefix) | ||
47 | |> List.iter ~f:(LNoise.add_completion completions) | ||
48 | | None -> ()); | ||
49 | user_input (fun from_user -> | ||
50 | LNoise.history_add from_user |> ignore; | ||
51 | LNoise.history_save ~filename:"mininix_history" |> ignore; | ||
52 | handle_cmd from_user) | ||
diff --git a/bin/repl_cmd.ml b/bin/repl_cmd.ml new file mode 100644 index 0000000..9ebeae7 --- /dev/null +++ b/bin/repl_cmd.ml | |||
@@ -0,0 +1,178 @@ | |||
1 | open Core | ||
2 | open Option.Let_syntax | ||
3 | |||
4 | let join_str_list ~sep = function | ||
5 | | [] -> "" | ||
6 | | s :: ss -> List.fold ss ~init:s ~f:(fun acc s -> acc ^ sep ^ s) | ||
7 | |||
8 | type cmd = { | ||
9 | args : string; | ||
10 | opts : unit -> string list; | ||
11 | next : (string -> (string, cmd) Either.t) option; | ||
12 | call : string list -> bool; | ||
13 | } | ||
14 | |||
15 | let set_opt_cmd opt setting = | ||
16 | { | ||
17 | args = "<option value>"; | ||
18 | opts = (fun () -> Settings.allowed_values setting); | ||
19 | next = None; | ||
20 | call = | ||
21 | (fun args -> | ||
22 | match Settings.set_to setting args with | ||
23 | | None -> true | ||
24 | | Some msg -> | ||
25 | printf "Failed to set option %s: %s\n%!" opt msg; | ||
26 | false); | ||
27 | } | ||
28 | |||
29 | let set_cmd = | ||
30 | { | ||
31 | args = "<option name> <option value>"; | ||
32 | opts = (fun () -> Map.keys Settings.settings); | ||
33 | next = | ||
34 | Some | ||
35 | (fun opt -> | ||
36 | match Map.find Settings.settings opt with | ||
37 | | Some setting -> Second (set_opt_cmd opt setting) | ||
38 | | None -> First (sprintf "Unknown option '%s'" opt)); | ||
39 | call = | ||
40 | (fun _ -> | ||
41 | printf "Missing option argument value\n%!"; | ||
42 | false); | ||
43 | } | ||
44 | |||
45 | let settings_cmd = | ||
46 | { | ||
47 | args = ""; | ||
48 | opts = (fun () -> []); | ||
49 | next = None; | ||
50 | call = | ||
51 | (function | ||
52 | | [] -> | ||
53 | Settings.print (); | ||
54 | true | ||
55 | | _ -> | ||
56 | printf "Expected no arguments\n%!"; | ||
57 | false); | ||
58 | } | ||
59 | |||
60 | let run_cmd = | ||
61 | { | ||
62 | args = "<filename>"; | ||
63 | opts = (fun () -> []); | ||
64 | next = None; | ||
65 | call = | ||
66 | (function | ||
67 | | [ filename ] -> Run.eval_file filename | ||
68 | | _ -> | ||
69 | printf "Expected one argument (the filename)\n%!"; | ||
70 | false); | ||
71 | } | ||
72 | |||
73 | let quit_cmd = | ||
74 | { args = ""; opts = (fun () -> []); next = None; call = (fun _ -> exit 0) } | ||
75 | |||
76 | let commands = | ||
77 | Map.of_alist_exn | ||
78 | (module String) | ||
79 | [ | ||
80 | ("quit", quit_cmd); | ||
81 | ("set", set_cmd); | ||
82 | ("settings", settings_cmd); | ||
83 | ("run", run_cmd); | ||
84 | ] | ||
85 | |||
86 | let root_cmd = | ||
87 | { | ||
88 | args = "<command>"; | ||
89 | opts = (fun () -> Map.keys commands); | ||
90 | next = | ||
91 | Some | ||
92 | (fun cmd_name -> | ||
93 | match Map.find commands cmd_name with | ||
94 | | Some cmd -> Second cmd | ||
95 | | None -> | ||
96 | First | ||
97 | (sprintf "Unknown command '%s' (expected one of {%s})" cmd_name | ||
98 | (Map.keys commands |> join_str_list ~sep:", "))); | ||
99 | call = | ||
100 | (fun _ -> | ||
101 | printf "Missing command!\n%!"; | ||
102 | false); | ||
103 | } | ||
104 | |||
105 | let is_space = Char.( = ) ' ' | ||
106 | let strip_space = String.strip ~drop:is_space | ||
107 | let lstrip_space = String.lstrip ~drop:is_space | ||
108 | |||
109 | let clean_str_list ss = | ||
110 | ss |> List.map ~f:strip_space | ||
111 | |> List.filter ~f:(fun s -> not (String.is_empty s)) | ||
112 | |||
113 | let words s = s |> String.split ~on:' ' |> clean_str_list | ||
114 | let unwords ss = clean_str_list ss |> join_str_list ~sep:" " | ||
115 | |||
116 | let rec call cmd args = | ||
117 | match args with | ||
118 | | [] -> cmd.call [] | ||
119 | | arg0 :: argn -> ( | ||
120 | match cmd.next with | ||
121 | | None -> cmd.call args | ||
122 | | Some next -> ( | ||
123 | match next arg0 with | ||
124 | | First msg -> | ||
125 | printf "%s\n%!" msg; | ||
126 | false | ||
127 | | Second cmd' -> call cmd' argn)) | ||
128 | |||
129 | let try_lsplit2_space s = | ||
130 | match String.lsplit2 s ~on:' ' with Some (l, r) -> (l, r) | None -> (s, "") | ||
131 | |||
132 | let lsplit2_space' s = | ||
133 | let%bind l, r = String.lsplit2 s ~on:' ' in | ||
134 | (* s = l ^ " " ^ r *) | ||
135 | let r' = lstrip_space r in | ||
136 | let space = " " ^ String.chop_suffix_exn r ~suffix:r' in | ||
137 | (* s = l ^ space ^ r' *) | ||
138 | return (l, space, r') | ||
139 | |||
140 | let rec completions cmd args = | ||
141 | (* cmd|<TAB> -> options | ||
142 | cmd|abc<TAB> -> options with prefix 'abc' | ||
143 | cmd|abc .*<TAB> -> subcommand 'abc' options, pass .* *) | ||
144 | if String.(args = "") then cmd.opts () | ||
145 | else | ||
146 | match lsplit2_space' args with | ||
147 | | None -> cmd.opts () |> List.filter ~f:(String.is_prefix ~prefix:args) | ||
148 | | Some (arg0, space, argn) -> ( | ||
149 | match cmd.next with | ||
150 | | None -> [] | ||
151 | | Some next -> ( | ||
152 | match next arg0 with | ||
153 | | First _ -> [] | ||
154 | | Second cmd' -> | ||
155 | completions cmd' argn | ||
156 | |> List.map ~f:(String.append (arg0 ^ space)))) | ||
157 | |||
158 | let rec hints cmd args = | ||
159 | (* cmd: "" -> " <args>" | ||
160 | cmd: "<space>+" -> "<args>" | ||
161 | cmd: "<space>+<subcmd>" -> "<hints for subcmd>" | ||
162 | cmd: "<space>+<subcmd> .*" -> "<hints for subcmd with .*>" *) | ||
163 | if String.(args = "") then Some (" " ^ cmd.args) | ||
164 | else if String.(strip_space args = "") then Some cmd.args | ||
165 | else | ||
166 | let args = lstrip_space args in | ||
167 | let%bind next = cmd.next in | ||
168 | match lsplit2_space' args with | ||
169 | | None -> | ||
170 | let%bind cmd' = next args |> Either.Second.to_option in | ||
171 | hints cmd' "" | ||
172 | | Some (arg0, space, argn) -> | ||
173 | let%bind cmd' = next arg0 |> Either.Second.to_option in | ||
174 | hints cmd' (space ^ argn) | ||
175 | |||
176 | let invoke cmd = call root_cmd (words cmd) | ||
177 | let complete cmd = completions root_cmd cmd | ||
178 | let hint cmd = hints root_cmd cmd | ||
diff --git a/bin/run.ml b/bin/run.ml new file mode 100644 index 0000000..f39997c --- /dev/null +++ b/bin/run.ml | |||
@@ -0,0 +1,163 @@ | |||
1 | open Core | ||
2 | |||
3 | let opts = Settings.opts | ||
4 | |||
5 | module Origin = struct | ||
6 | type t = Filename of string | Stdin | Interactive | ||
7 | |||
8 | let to_string = function | ||
9 | | Filename name -> name | ||
10 | | Stdin -> "<stdin>" | ||
11 | | Interactive -> "<interactive>" | ||
12 | end | ||
13 | |||
14 | (* [dir] must be an absolute path *) | ||
15 | let rec find_imports_file dir : (string, string) result = | ||
16 | let def_filename = Filename.concat dir "importdef.sexp" in | ||
17 | match Core_unix.access def_filename [ `Read ] with | ||
18 | | Ok () -> Ok def_filename | ||
19 | | Error (Core_unix.Unix_error (ENOENT, _, _)) | ||
20 | | Error (Core_unix.Unix_error (EACCES, _, _)) -> | ||
21 | let parent = Filename.dirname dir in | ||
22 | if String.(parent = dir) then Error "Could not find importdef.sexp file" | ||
23 | else find_imports_file (Filename.dirname dir) | ||
24 | | Error _ -> Error "Could not find importdef.sexp file" | ||
25 | |||
26 | let load_imports ~for_ = | ||
27 | let cwd = Core_unix.getcwd () in | ||
28 | let filename = | ||
29 | match !(opts.imports_def_file) with | ||
30 | | None -> ( | ||
31 | let dir = | ||
32 | match for_ with | ||
33 | | Origin.Filename filename -> | ||
34 | Filename.to_absolute_exn | ||
35 | (Filename.dirname filename) | ||
36 | ~relative_to:cwd | ||
37 | | Origin.Stdin | Origin.Interactive -> cwd | ||
38 | in | ||
39 | match find_imports_file dir with | ||
40 | | Error _ -> | ||
41 | printf | ||
42 | "Note: no importdef.sexp was found / could be accessed; imports \ | ||
43 | will not work\n\ | ||
44 | %!"; | ||
45 | None | ||
46 | | Ok filename -> | ||
47 | let relative = | ||
48 | if Filename.is_absolute filename then | ||
49 | Filename.of_absolute_exn filename ~relative_to:cwd | ||
50 | else filename | ||
51 | in | ||
52 | printf "Imports definition found at %s\n%!" relative; | ||
53 | Some filename) | ||
54 | | Some filename -> Some filename | ||
55 | in | ||
56 | match filename with | ||
57 | | None -> Ok [] | ||
58 | | Some filename -> ( | ||
59 | (* User-provided filenames may not be absolute *) | ||
60 | let filename_abs = Filename.to_absolute_exn filename ~relative_to:cwd in | ||
61 | try | ||
62 | Ok | ||
63 | (In_channel.read_all filename | ||
64 | |> Sexp.of_string |> Mininix.Sexp.import_forest_of_sexp | ||
65 | |> Mininix.Import.materialize | ||
66 | ~relative_to:(Filename.dirname filename_abs)) | ||
67 | with Sys_error err -> Error ("Failed to read imports definition: " ^ err)) | ||
68 | |||
69 | let eval_expr_with_imports ~origin ~imports data = | ||
70 | let cwd = Core_unix.getcwd () in | ||
71 | let config = Sexp_pretty.Config.default | ||
72 | and formatter = Stdlib.Format.formatter_of_out_channel stdout in | ||
73 | try | ||
74 | if !(opts.print_input) then printf "==> Input Nix:\n%s\n\n%!" data; | ||
75 | let nexp = Nix.parse ~filename:(Origin.to_string origin) data in | ||
76 | if !(opts.print_parsed) then ( | ||
77 | print_string "==> Parsed Nix:\n"; | ||
78 | Nix.Printer.print stdout nexp; | ||
79 | printf "\n\n%!"); | ||
80 | let nnexp = | ||
81 | Nix.elaborate | ||
82 | ~dir: | ||
83 | (Some | ||
84 | (match origin with | ||
85 | | Filename name -> | ||
86 | Filename.to_absolute_exn ~relative_to:cwd | ||
87 | (Filename.dirname name) | ||
88 | | Stdin | Interactive -> cwd)) | ||
89 | nexp | ||
90 | in | ||
91 | if !(opts.print_elaborated) then ( | ||
92 | print_string "==> Parsed, elaborated Nix:\n"; | ||
93 | Nix.Printer.print stdout nnexp; | ||
94 | printf "\n\n%!"); | ||
95 | if !(opts.print_nix_sexp) then ( | ||
96 | let nsexp = Nix.Ast.sexp_of_expr nnexp in | ||
97 | print_string "==> Nix S-expr:\n"; | ||
98 | Sexp_pretty.pp_formatter config formatter nsexp; | ||
99 | printf "\n%!"); | ||
100 | let mnexp = Mininix.Nix2mininix.from_nix nnexp in | ||
101 | if !(opts.print_mininix_sexp) then ( | ||
102 | let mnsexp = Mininix.Sexp.expr_to_sexp mnexp in | ||
103 | print_string "==> Mininix S-expr:\n"; | ||
104 | Sexp_pretty.pp_formatter config formatter mnsexp; | ||
105 | printf "\n%!"); | ||
106 | let mnwpexp = Mininix.apply_prelude mnexp in | ||
107 | if !(opts.print_mininix_sexp_w_prelude) then ( | ||
108 | let mnwpsexp = Mininix.Sexp.expr_to_sexp mnwpexp in | ||
109 | print_string "==> Mininix S-expr (+ prelude):\n"; | ||
110 | Sexp_pretty.pp_formatter config formatter mnwpsexp; | ||
111 | printf "\n%!"); | ||
112 | let res = | ||
113 | Mininix.interp_tl ~fuel:!(opts.fuel_amount) ~mode:!(opts.eval_strategy) | ||
114 | ~imports mnwpexp | ||
115 | in | ||
116 | if !(opts.print_result_mininix_sexp) then ( | ||
117 | let ressexp = Mininix.Sexp.val_res_to_sexp res in | ||
118 | print_string "==> Evaluation result (Mininix S-exp):\n"; | ||
119 | Sexp_pretty.pp_formatter config formatter ressexp; | ||
120 | printf "\n%!"); | ||
121 | match res with | ||
122 | | Res (Some v) -> | ||
123 | let nixv = Mininix.Mininix2nix.from_val v in | ||
124 | if !(opts.print_result_nix_sexp) then ( | ||
125 | let nixvsexp = Nix.Ast.sexp_of_expr nixv in | ||
126 | print_string "==> Evaluation result (Nix S-exp):\n"; | ||
127 | Sexp_pretty.pp_formatter config formatter nixvsexp; | ||
128 | printf "\n%!"); | ||
129 | print_string "==> Evaluation result (Nix):\n"; | ||
130 | Nix.Printer.print stdout nixv; | ||
131 | printf "\n%!"; | ||
132 | true | ||
133 | | Res None -> | ||
134 | printf "Failed to evaluate\n%!"; | ||
135 | false | ||
136 | | _ -> | ||
137 | printf "Ran out of fuel\n%!"; | ||
138 | false | ||
139 | with | ||
140 | | Nix.ParseError msg -> | ||
141 | printf "Failed to parse: %s\n%!" msg; | ||
142 | false | ||
143 | | Nix.ElaborateError msg -> | ||
144 | printf "Elaboration failed: %s\n%!" msg; | ||
145 | false | ||
146 | | Mininix.Nix2mininix.FromNixError msg -> | ||
147 | printf "Failed to convert Nix to Mininix: %s\n%!" msg; | ||
148 | false | ||
149 | |||
150 | let eval_expr ~origin data = | ||
151 | match load_imports ~for_:origin with | ||
152 | | Ok imports -> eval_expr_with_imports ~origin ~imports data | ||
153 | | Error msg -> | ||
154 | print_endline msg; | ||
155 | false | ||
156 | |||
157 | let eval_ch ~origin ch = In_channel.input_all ch |> eval_expr ~origin | ||
158 | |||
159 | let eval_file filename = | ||
160 | In_channel.with_file filename ~binary:true | ||
161 | ~f:(eval_ch ~origin:(Filename filename)) | ||
162 | |||
163 | let eval_stdin () = eval_ch In_channel.stdin ~origin:Stdin | ||
diff --git a/bin/settings.ml b/bin/settings.ml new file mode 100644 index 0000000..55699ee --- /dev/null +++ b/bin/settings.ml | |||
@@ -0,0 +1,120 @@ | |||
1 | open Core | ||
2 | |||
3 | type fuel_amount = [ `Limited | `Unlimited ] | ||
4 | type eval_strategy = [ `Shallow | `Deep ] | ||
5 | |||
6 | type options = { | ||
7 | eval_strategy : eval_strategy ref; | ||
8 | fuel_amount : fuel_amount ref; | ||
9 | imports_def_file : string option ref; | ||
10 | print_input : bool ref; | ||
11 | print_parsed : bool ref; | ||
12 | print_elaborated : bool ref; | ||
13 | print_nix_sexp : bool ref; | ||
14 | print_mininix_sexp : bool ref; | ||
15 | print_mininix_sexp_w_prelude : bool ref; | ||
16 | print_result_mininix_sexp : bool ref; | ||
17 | print_result_nix_sexp : bool ref; | ||
18 | } | ||
19 | |||
20 | let opts = | ||
21 | { | ||
22 | eval_strategy = ref `Deep; | ||
23 | fuel_amount = ref `Unlimited; | ||
24 | imports_def_file = ref None; | ||
25 | print_input = ref false; | ||
26 | print_parsed = ref false; | ||
27 | print_elaborated = ref false; | ||
28 | print_nix_sexp = ref false; | ||
29 | print_mininix_sexp = ref false; | ||
30 | print_mininix_sexp_w_prelude = ref false; | ||
31 | print_result_mininix_sexp = ref false; | ||
32 | print_result_nix_sexp = ref false; | ||
33 | } | ||
34 | |||
35 | type 'a setter = 'a -> unit | ||
36 | |||
37 | type setting = | ||
38 | | BoolSetting of bool ref | ||
39 | | EvalStrategySetting of eval_strategy ref | ||
40 | | FilenameOptionSetting of string option ref | ||
41 | | FuelAmountSetting of fuel_amount ref | ||
42 | |||
43 | let allowed_values s = | ||
44 | match s with | ||
45 | | BoolSetting _ -> [ "true"; "false" ] | ||
46 | | EvalStrategySetting _ -> [ "shallow"; "deep" ] | ||
47 | | FilenameOptionSetting _ -> [ "none"; "some " ] | ||
48 | | FuelAmountSetting _ -> [ "limited"; "unlimited" ] | ||
49 | |||
50 | let set_to s v = | ||
51 | match s with | ||
52 | | BoolSetting vref -> ( | ||
53 | match v with | ||
54 | | [ "true" ] -> | ||
55 | vref := true; | ||
56 | None | ||
57 | | [ "false" ] -> | ||
58 | vref := false; | ||
59 | None | ||
60 | | _ -> Some "expected one argument: 'true' or 'false'") | ||
61 | | EvalStrategySetting vref -> ( | ||
62 | match v with | ||
63 | | [ "shallow" ] -> | ||
64 | vref := `Shallow; | ||
65 | None | ||
66 | | [ "deep" ] -> | ||
67 | vref := `Deep; | ||
68 | None | ||
69 | | _ -> Some "expected one argument: 'shallow' or 'deep'") | ||
70 | | FilenameOptionSetting vref -> ( | ||
71 | match v with | ||
72 | | [ "none" ] -> | ||
73 | vref := None; | ||
74 | None | ||
75 | | [ "some"; filename ] -> | ||
76 | vref := Some (String.strip filename); | ||
77 | None | ||
78 | | _ -> Some "expected 'none' or 'some <filename>'") | ||
79 | | FuelAmountSetting vref -> ( | ||
80 | match v with | ||
81 | | [ "limited" ] -> | ||
82 | vref := `Limited; | ||
83 | None | ||
84 | | [ "unlimited" ] -> | ||
85 | vref := `Unlimited; | ||
86 | None | ||
87 | | _ -> Some "expected 'limited' or 'unlimited'") | ||
88 | |||
89 | let to_string s = | ||
90 | match s with | ||
91 | | BoolSetting vref -> Bool.to_string !vref | ||
92 | | EvalStrategySetting vref -> ( | ||
93 | match !vref with `Shallow -> "shallow" | `Deep -> "deep") | ||
94 | | FilenameOptionSetting vref -> ( | ||
95 | match !vref with None -> "none" | Some v -> "some " ^ v) | ||
96 | | FuelAmountSetting vref -> ( | ||
97 | match !vref with `Limited -> "limited" | `Unlimited -> "unlimited") | ||
98 | |||
99 | let settings = | ||
100 | Map.of_alist_exn | ||
101 | (module String) | ||
102 | [ | ||
103 | ("print_input", BoolSetting opts.print_input); | ||
104 | ("print_parsed", BoolSetting opts.print_parsed); | ||
105 | ("print_elaborated", BoolSetting opts.print_elaborated); | ||
106 | ("print_nix_sexp", BoolSetting opts.print_nix_sexp); | ||
107 | ("print_mininix_sexp", BoolSetting opts.print_mininix_sexp); | ||
108 | ( "print_mininix_sexp_w_prelude", | ||
109 | BoolSetting opts.print_mininix_sexp_w_prelude ); | ||
110 | ("print_result_mininix_sexp", BoolSetting opts.print_result_mininix_sexp); | ||
111 | ("print_result_nix_sexp", BoolSetting opts.print_result_nix_sexp); | ||
112 | ("eval_strategy", EvalStrategySetting opts.eval_strategy); | ||
113 | ("fuel_amount", FuelAmountSetting opts.fuel_amount); | ||
114 | ("imports_def_file", FilenameOptionSetting opts.imports_def_file); | ||
115 | ] | ||
116 | |||
117 | let print () = | ||
118 | printf "==> Settings:\n"; | ||
119 | Map.iteri settings ~f:(fun ~key:name ~data:setting -> | ||
120 | printf " %s: %s\n" name (to_string setting)) | ||