aboutsummaryrefslogtreecommitdiff
path: root/toplevel/coqloop.ml
diff options
context:
space:
mode:
Diffstat (limited to 'toplevel/coqloop.ml')
-rw-r--r--toplevel/coqloop.ml216
1 files changed, 110 insertions, 106 deletions
diff --git a/toplevel/coqloop.ml b/toplevel/coqloop.ml
index 977cae6254..5499ae0fa3 100644
--- a/toplevel/coqloop.ml
+++ b/toplevel/coqloop.ml
@@ -371,100 +371,104 @@ let exit_on_error =
declare_bool_option_and_ref ~depr:false ~name:"coqtop-exit-on-error" ~key:["Coqtop";"Exit";"On";"Error"]
~value:false
-let rec vernac_loop ~state =
- let open CAst in
+(* XXX: This is duplicated with Vernacentries.show_proof , at some
+ point we should consolidate the code *)
+let show_proof_diff_to_pp pstate =
+ let p = Option.get pstate in
+ let sigma, env = Pfedit.get_proof_context p in
+ let pprf = Proof.partial_proof p in
+ Pp.prlist_with_sep Pp.fnl (Printer.pr_econstr_env env sigma) pprf
+
+let show_proof_diff_cmd ~state removed =
let open Vernac.State in
- let open G_toplevel in
- loop_flush_all ();
- top_stderr (fnl());
- if !print_emacs then top_stderr (str (top_buffer.prompt state.doc));
- resynch_buffer top_buffer;
- (* execute one command *)
try
- let input = top_buffer.tokens in
- match read_sentence ~state input with
- | Some (VernacBackTo bid) ->
- let bid = Stateid.of_int bid in
- let doc, res = Stm.edit_at ~doc:state.doc bid in
- assert (res = `NewTip);
- let state = { state with doc; sid = bid } in
- vernac_loop ~state
-
- | Some VernacQuit ->
- exit 0
-
- | Some VernacDrop ->
- if Mltop.is_ocaml_top()
- then (drop_last_doc := Some state; state)
- else (Feedback.msg_warning (str "There is no ML toplevel."); vernac_loop ~state)
-
- | Some VernacControl { loc; v=c } ->
- let nstate = Vernac.process_expr ~state (make ?loc c) in
- top_goal_print ~doc:state.doc c state.proof nstate.proof;
- vernac_loop ~state:nstate
-
- | Some (VernacShowGoal {gid; sid}) ->
- let proof = Stm.get_proof ~doc:state.doc (Stateid.of_int sid) in
- let goal = Printer.pr_goal_emacs ~proof gid sid in
- let evars =
- match proof with
- | None -> mt()
- | Some p ->
- let gl = (Evar.unsafe_of_int gid) in
- let { Proof.sigma } = Proof.data p in
- try Printer.print_dependent_evars (Some gl) sigma [ gl ]
- with Not_found -> mt()
- in
- Feedback.msg_notice (v 0 (goal ++ evars));
- vernac_loop ~state
-
- | Some VernacShowProofDiffs removed ->
- (* extension of Vernacentries.show_proof *)
- let to_pp pstate =
- let p = Option.get pstate in
- let sigma, env = Pfedit.get_proof_context p in
- let pprf = Proof.partial_proof p in
- Pp.prlist_with_sep Pp.fnl (Printer.pr_econstr_env env sigma) pprf
- (* We print nothing if there are no goals left *)
- in
-
- if not (Proof_diffs.color_enabled ()) then
- CErrors.user_err Pp.(str "Show Proof Diffs requires setting the \"-color\" command line argument to \"on\" or \"auto\".")
- else begin
- let out =
- try
- let n_pp = to_pp state.proof in
- if true (*Proof_diffs.show_diffs ()*) then
- let doc = state.doc in
- let oproof = Stm.get_prev_proof ~doc (Stm.get_current_state ~doc) in
- try
- let o_pp = to_pp oproof in
- let tokenize_string = Proof_diffs.tokenize_string in
- let show_removed = Some removed in
- Pp_diff.diff_pp_combined ~tokenize_string ?show_removed o_pp n_pp
- with
- | Pfedit.NoSuchGoal
- | Option.IsNone -> n_pp
- | Pp_diff.Diff_Failure msg -> begin
- (* todo: print the unparsable string (if we know it) *)
- Feedback.msg_warning Pp.(str ("Diff failure: " ^ msg) ++ cut()
- ++ str "Showing results without diff highlighting" );
- n_pp
- end
- else
- n_pp
- with
- | Pfedit.NoSuchGoal
- | Option.IsNone ->
- CErrors.user_err (str "No goals to show.")
- in
- Feedback.msg_notice out;
- end;
- vernac_loop ~state
-
- | None ->
- top_stderr (fnl ()); exit 0
+ let n_pp = show_proof_diff_to_pp state.proof in
+ if true (*Proof_diffs.show_diffs ()*) then
+ let doc = state.doc in
+ let oproof = Stm.get_prev_proof ~doc (Stm.get_current_state ~doc) in
+ try
+ let o_pp = show_proof_diff_to_pp oproof in
+ let tokenize_string = Proof_diffs.tokenize_string in
+ let show_removed = Some removed in
+ Pp_diff.diff_pp_combined ~tokenize_string ?show_removed o_pp n_pp
+ with
+ | Pfedit.NoSuchGoal
+ | Option.IsNone -> n_pp
+ | Pp_diff.Diff_Failure msg -> begin
+ (* todo: print the unparsable string (if we know it) *)
+ Feedback.msg_warning Pp.(str ("Diff failure: " ^ msg) ++ cut()
+ ++ str "Showing results without diff highlighting" );
+ n_pp
+ end
+ else
+ n_pp
+ with
+ | Pfedit.NoSuchGoal
+ | Option.IsNone ->
+ CErrors.user_err (str "No goals to show.")
+let process_toplevel_command ~state stm =
+ let open Vernac.State in
+ let open G_toplevel in
+ match stm with
+ (* Usually handled in the caller *)
+ | VernacDrop ->
+ state
+
+ | VernacBackTo bid ->
+ let bid = Stateid.of_int bid in
+ let doc, res = Stm.edit_at ~doc:state.doc bid in
+ assert (res = `NewTip);
+ { state with doc; sid = bid }
+
+ | VernacQuit ->
+ exit 0
+
+ | VernacControl { CAst.loc; v=c } ->
+ let nstate = Vernac.process_expr ~state (CAst.make ?loc c) in
+ top_goal_print ~doc:state.doc c state.proof nstate.proof;
+ nstate
+
+ | VernacShowGoal { gid; sid } ->
+ let proof = Stm.get_proof ~doc:state.doc (Stateid.of_int sid) in
+ let goal = Printer.pr_goal_emacs ~proof gid sid in
+ let evars =
+ match proof with
+ | None -> mt()
+ | Some p ->
+ let gl = (Evar.unsafe_of_int gid) in
+ let { Proof.sigma } = Proof.data p in
+ try Printer.print_dependent_evars (Some gl) sigma [ gl ]
+ with Not_found -> mt()
+ in
+ Feedback.msg_notice (v 0 (goal ++ evars));
+ state
+
+ | VernacShowProofDiffs removed ->
+ (* We print nothing if there are no goals left *)
+ if not (Proof_diffs.color_enabled ()) then
+ CErrors.user_err Pp.(str "Show Proof Diffs requires setting the \"-color\" command line argument to \"on\" or \"auto\".")
+ else
+ let out = show_proof_diff_cmd ~state removed in
+ Feedback.msg_notice out;
+ state
+
+(* We return a new state and true if we got a `Drop` command *)
+let read_and_execute_base ~state =
+ let input = top_buffer.tokens in
+ match read_sentence ~state input with
+ | Some G_toplevel.VernacDrop ->
+ if Mltop.is_ocaml_top()
+ then (drop_last_doc := Some state; state, true)
+ else (Feedback.msg_warning (str "There is no ML toplevel."); state, false)
+ | Some stm ->
+ process_toplevel_command ~state stm, false
+ (* End of file *)
+ | None ->
+ top_stderr (fnl ()); exit 0
+
+let read_and_execute ~state =
+ try read_and_execute_base ~state
with
(* Exception printing should be done by the feedback listener,
however this is not yet ready so we rely on the exception for
@@ -473,7 +477,7 @@ let rec vernac_loop ~state =
(* the parser doesn't like nonblocking mode, cf #10918 *)
let msg =
Pp.(strbrk "Coqtop needs the standard input to be in blocking mode." ++ spc()
- ++ str "One way of clearing the non-blocking flag is through python:" ++ fnl()
+ ++ str "One way of clearing the non-blocking flag is through Python:" ++ fnl()
++ str " import os" ++ fnl()
++ str " os.set_blocking(0, True)")
in
@@ -485,21 +489,17 @@ let rec vernac_loop ~state =
let msg = CErrors.iprint (e, info) in
TopErr.print_error_for_buffer ?loc Feedback.Error msg top_buffer;
if exit_on_error () then exit 1;
- vernac_loop ~state
+ state, false
-let rec loop ~state =
+(* This function will only return on [Drop], careful to keep it tail-recursive *)
+let rec vernac_loop ~state =
let open Vernac.State in
- Sys.catch_break true;
- try
- reset_input_buffer state.doc stdin top_buffer;
- vernac_loop ~state
- with
- | any ->
- top_stderr
- (hov 0 (str "Anomaly: main loop exited with exception:" ++ spc () ++
- str (Printexc.to_string any)) ++ spc () ++
- hov 0 (str "Please report at " ++ str Coq_config.wwwbugtracker ++ str "."));
- loop ~state
+ loop_flush_all ();
+ top_stderr (fnl());
+ if !print_emacs then top_stderr (str (top_buffer.prompt state.doc));
+ resynch_buffer top_buffer;
+ let state, drop = read_and_execute ~state in
+ if drop then state else vernac_loop ~state
(* Default toplevel loop *)
@@ -511,7 +511,11 @@ let loop ~opts ~state =
print_emacs := opts.config.print_emacs;
(* We initialize the console only if we run the toploop_run *)
let tl_feed = Feedback.add_feeder coqloop_feed in
- let _ = loop ~state in
+ (* Initialize buffer *)
+ Sys.catch_break true;
+ reset_input_buffer state.Vernac.State.doc stdin top_buffer;
+ (* Call the main loop *)
+ let _ : Vernac.State.t = vernac_loop ~state in
(* Initialise and launch the Ocaml toplevel *)
Coqinit.init_ocaml_path();
Mltop.ocaml_toploop();