From ba61dfd69504ec6263a9dee9931d93adeb6f3142 Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Mon, 7 Jul 2025 21:52:08 +0200 Subject: Initialize repository --- bin/dune | 14 +++++ bin/main.ml | 26 +++++++++ bin/repl.ml | 52 +++++++++++++++++ bin/repl_cmd.ml | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bin/run.ml | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++ bin/settings.ml | 120 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 553 insertions(+) create mode 100644 bin/dune create mode 100644 bin/main.ml create mode 100644 bin/repl.ml create mode 100644 bin/repl_cmd.ml create mode 100644 bin/run.ml create mode 100644 bin/settings.ml (limited to 'bin') diff --git a/bin/dune b/bin/dune new file mode 100644 index 0000000..2a56b29 --- /dev/null +++ b/bin/dune @@ -0,0 +1,14 @@ +(executable + (public_name mininix) + (name main) + (preprocess + (pps ppx_let)) + (libraries + nix + core + core_unix.command_unix + linenoise + mininix + sexp_pretty + stdio + 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 @@ +open Core + +let repl = + Command.basic ~summary:"run the Mininix REPL" (Command.Param.return Repl.run) + +let eval = + Command.basic ~summary:"run a Nix file" + (let%map_open.Command filename = anon ("FILENAME" %: string) + and strict = flag "strict" no_arg ~doc:"use deep evaluation strategy" + and importsdef = + flag "importsdef" (optional string) ~doc:"import tree definition file" + in + fun () -> + Settings.opts.eval_strategy := if strict then `Deep else `Shallow; + Settings.opts.imports_def_file := importsdef; + let ok = + if String.(filename = "-") then Run.eval_stdin () + else Run.eval_file filename + in + if ok then exit 0 else exit 1) + +let main = + Command.group ~summary:"the Mininix interpreter" + [ ("repl", repl); ("eval", eval) ] + +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 @@ +open Core +open Option.Let_syntax + +let ok = ref true +let opts = Settings.opts + +let rec user_input cb = + let prompt = (if !ok then "[okay]" else "[fail]") ^ " (mini)nix> " in + try + match LNoise.linenoise prompt with + | None -> () + | Some v -> + cb v; + user_input cb + with Sys_unix.Break -> + printf "\n%!"; + user_input cb + +let split_cmd_prefix cmd = + let%bind cmd = String.chop_prefix ~prefix:":" cmd in + let cmd' = Repl_cmd.lstrip_space cmd in + let space = String.chop_suffix_exn cmd ~suffix:cmd' in + return (":" ^ space, cmd') + +let handle_cmd cmd = + let cmd = Repl_cmd.strip_space cmd in + (match split_cmd_prefix cmd with + | Some (_, cmd) -> ok := Repl_cmd.invoke cmd + | None -> + if String.(strip cmd <> "") then + ok := Run.eval_expr cmd ~origin:Interactive); + printf "\n%!" + +let run () = + LNoise.set_multiline true; + LNoise.history_load ~filename:"mininix_history" |> ignore; + LNoise.history_set ~max_length:500 |> ignore; + LNoise.set_hints_callback (fun line -> + let%bind _, cmd = split_cmd_prefix line in + let%bind hint = Repl_cmd.hint cmd in + return (hint, LNoise.Yellow, true)); + LNoise.set_completion_callback (fun line_so_far completions -> + match split_cmd_prefix line_so_far with + | Some (prefix, cmd_so_far) -> + Repl_cmd.complete cmd_so_far + |> List.map ~f:(String.append prefix) + |> List.iter ~f:(LNoise.add_completion completions) + | None -> ()); + user_input (fun from_user -> + LNoise.history_add from_user |> ignore; + LNoise.history_save ~filename:"mininix_history" |> ignore; + 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 @@ +open Core +open Option.Let_syntax + +let join_str_list ~sep = function + | [] -> "" + | s :: ss -> List.fold ss ~init:s ~f:(fun acc s -> acc ^ sep ^ s) + +type cmd = { + args : string; + opts : unit -> string list; + next : (string -> (string, cmd) Either.t) option; + call : string list -> bool; +} + +let set_opt_cmd opt setting = + { + args = "