From 90cb51a907a0f78b83cb66f497f6dc0f24f01706 Mon Sep 17 00:00:00 2001 From: Marcos Magueta Date: Sun, 12 Jul 2026 18:52:52 -0300 Subject: repl session commands: load, reset, quit; emacs load-file binding --- bin/main.ml | 80 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 16 deletions(-) (limited to 'bin/main.ml') diff --git a/bin/main.ml b/bin/main.ml index eb212d2..26375da 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -44,30 +44,78 @@ let run_file path = | Ok statements -> ( match run_statements statements with Ok () -> () | Error () -> exit 1) +let declarations statements = + List.filter + (function Sol.Ast.Directive ("Query", _) -> false | _ -> true) + statements + +(* Feeding statements into the session: declarations accumulate, + queries answer immediately, and a failure changes nothing, so the + session only ever holds an admitted program. *) +let feed history statements = + match run_statements (history @ statements) with + | Ok () -> history @ declarations statements + | Error () -> history + +let strip_quotes s = + let n = String.length s in + if n >= 2 && s.[0] = '"' && s.[n - 1] = '"' then String.sub s 1 (n - 2) + else s + +let load_file history argument = + let path = strip_quotes argument in + match In_channel.with_open_text path In_channel.input_all with + | exception Sys_error message -> + prerr_endline message; + history + | contents -> ( + match Sol.Front.parse_string contents with + | Error message -> + prerr_endline (path ^ ": " ^ message); + history + | Ok statements -> + let next = feed history statements in + if next != history then + Printf.printf "loaded %s: %d declarations, %d queries run.\n" path + (List.length (declarations statements)) + (List.length statements - List.length (declarations statements)); + next) + let repl () = - print_endline "Sol. Statements accumulate; Query expression: ... runs."; + print_endline + "Sol. Statements accumulate; Query expression: ... runs; :help for commands."; let rec loop history = print_string "sol> "; flush stdout; match In_channel.input_line stdin with | None -> () - | Some line when String.trim line = "" -> loop history | Some line -> ( - match Sol.Front.parse_string line with - | Error message -> - prerr_endline message; + let line = String.trim line in + match String.index_opt line ' ' with + | _ when line = "" -> loop history + | _ when line = ":quit" -> () + | _ when line = ":reset" -> + print_endline "session cleared."; + loop [] + | _ when line = ":help" -> + print_endline + ":load FILE bring a program into the session (atomic: a rejected file changes nothing)\n\ + :reset clear the session\n\ + :quit leave"; + loop history + | Some i when String.sub line 0 i = ":load" -> + loop + (load_file history + (String.trim (String.sub line i (String.length line - i)))) + | _ when String.length line > 0 && line.[0] = ':' -> + prerr_endline "unknown command; :help lists them."; loop history - | Ok statements -> ( - let declarations = - List.filter - (function - | Sol.Ast.Directive ("Query", _) -> false - | _ -> true) - statements - in - match run_statements (history @ statements) with - | Ok () -> loop (history @ declarations) - | Error () -> loop history)) + | _ -> ( + match Sol.Front.parse_string line with + | Error message -> + prerr_endline message; + loop history + | Ok statements -> loop (feed history statements))) in loop [] -- cgit v1.2.3