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 = "