summaryrefslogtreecommitdiff
path: root/proofs/tactic_debug.ml
diff options
context:
space:
mode:
Diffstat (limited to 'proofs/tactic_debug.ml')
-rw-r--r--proofs/tactic_debug.ml271
1 files changed, 182 insertions, 89 deletions
diff --git a/proofs/tactic_debug.ml b/proofs/tactic_debug.ml
index a7df80f6..3cc81daf 100644
--- a/proofs/tactic_debug.ml
+++ b/proofs/tactic_debug.ml
@@ -1,23 +1,21 @@
(************************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2014 *)
+(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2015 *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(************************************************************************)
+open Util
open Names
-open Constrextern
open Pp
open Tacexpr
open Termops
-let prtac = ref (fun _ -> assert false)
-let set_tactic_printer f = prtac := f
-let prmatchpatt = ref (fun _ _ -> assert false)
-let set_match_pattern_printer f = prmatchpatt := f
-let prmatchrl = ref (fun _ -> assert false)
-let set_match_rule_printer f = prmatchrl := f
+let (prtac, tactic_printer) = Hook.make ()
+let (prmatchpatt, match_pattern_printer) = Hook.make ()
+let (prmatchrl, match_rule_printer) = Hook.make ()
+
(* This module intends to be a beginning of debugger for tactic expressions.
Currently, it is quite simple and we can hope to have, in the future, a more
@@ -33,23 +31,29 @@ let explain_logic_error = ref (fun e -> mt())
let explain_logic_error_no_anomaly = ref (fun e -> mt())
+let msg_tac_debug s = Proofview.NonLogical.print (s++fnl())
+
(* Prints the goal *)
-let db_pr_goal g =
- let env = Refiner.pf_env g in
+let db_pr_goal gl =
+ let env = Proofview.Goal.env gl in
+ let concl = Proofview.Goal.concl gl in
let penv = print_named_context env in
- let pc = print_constr_env env (Goal.V82.concl (Refiner.project g) (Refiner.sig_it g)) in
- str" " ++ hv 0 (penv ++ fnl () ++
+ let pc = print_constr_env env concl in
+ str" " ++ hv 0 (penv ++ fnl () ++
str "============================" ++ fnl () ++
str" " ++ pc) ++ fnl ()
-let db_pr_goal g =
- msgnl (str "Goal:" ++ fnl () ++ db_pr_goal g)
+let db_pr_goal =
+ Proofview.Goal.nf_enter begin fun gl ->
+ let pg = db_pr_goal gl in
+ Proofview.tclLIFT (msg_tac_debug (str "Goal:" ++ fnl () ++ pg))
+ end
(* Prints the commands *)
let help () =
- msgnl (str "Commands: <Enter> = Continue" ++ fnl() ++
+ msg_tac_debug (str "Commands: <Enter> = Continue" ++ fnl() ++
str " h/? = Help" ++ fnl() ++
str " r <num> = Run <num> times" ++ fnl() ++
str " r <string> = Run up to next idtac <string>" ++ fnl() ++
@@ -57,168 +61,257 @@ let help () =
str " x = Exit")
(* Prints the goal and the command to be executed *)
-let goal_com g tac =
- begin
- db_pr_goal g;
- msg (str "Going to execute:" ++ fnl () ++ !prtac tac ++ fnl ())
- end
-
-let skipped = ref 0
-let skip = ref 0
-let breakpoint = ref None
+let goal_com tac =
+ Proofview.tclTHEN
+ db_pr_goal
+ (Proofview.tclLIFT (msg_tac_debug (str "Going to execute:" ++ fnl () ++ Hook.get prtac tac)))
+
+(* [run (new_ref _)] gives us a ref shared among [NonLogical.t]
+ expressions. It avoids parametrizing everything over a
+ reference. *)
+let skipped = Proofview.NonLogical.run (Proofview.NonLogical.ref 0)
+let skip = Proofview.NonLogical.run (Proofview.NonLogical.ref 0)
+let breakpoint = Proofview.NonLogical.run (Proofview.NonLogical.ref None)
let rec drop_spaces inst i =
- if String.length inst > i && inst.[i] = ' ' then drop_spaces inst (i+1)
+ if String.length inst > i && inst.[i] == ' ' then drop_spaces inst (i+1)
else i
let possibly_unquote s =
- if String.length s >= 2 & s.[0] = '"' & s.[String.length s - 1] = '"' then
+ if String.length s >= 2 && s.[0] == '"' && s.[String.length s - 1] == '"' then
String.sub s 1 (String.length s - 2)
else
s
(* (Re-)initialize debugger *)
-let db_initialize () =
- skip:=0;skipped:=0;breakpoint:=None
+let db_initialize =
+ let open Proofview.NonLogical in
+ (skip:=0) >> (skipped:=0) >> (breakpoint:=None)
+
+let int_of_string s =
+ try Proofview.NonLogical.return (int_of_string s)
+ with e -> Proofview.NonLogical.raise e
+
+let string_get s i =
+ try Proofview.NonLogical.return (String.get s i)
+ with e -> Proofview.NonLogical.raise e
(* Gives the number of steps or next breakpoint of a run command *)
let run_com inst =
- if (String.get inst 0)='r' then
+ let open Proofview.NonLogical in
+ string_get inst 0 >>= fun first_char ->
+ if first_char ='r' then
let i = drop_spaces inst 1 in
if String.length inst > i then
let s = String.sub inst i (String.length inst - i) in
if inst.[0] >= '0' && inst.[0] <= '9' then
- let num = int_of_string s in
- if num<0 then raise (Invalid_argument "run_com");
- skip:=num;skipped:=0
+ int_of_string s >>= fun num ->
+ (if num<0 then invalid_arg "run_com" else return ()) >>
+ (skip:=num) >> (skipped:=0)
else
breakpoint:=Some (possibly_unquote s)
else
- raise (Invalid_argument "run_com")
+ invalid_arg "run_com"
else
- raise (Invalid_argument "run_com")
+ invalid_arg "run_com"
(* Prints the run counter *)
let run ini =
+ let open Proofview.NonLogical in
if not ini then
- begin
- for i=1 to 2 do
- print_char (Char.chr 8);print_char (Char.chr 13)
- done;
- msg (str "Executed expressions: " ++ int !skipped ++ fnl() ++ fnl())
- end;
- incr skipped
+ begin
+ Proofview.NonLogical.print (str"\b\r\b\r") >>
+ !skipped >>= fun skipped ->
+ msg_tac_debug (str "Executed expressions: " ++ int skipped ++ fnl())
+ end >>
+ !skipped >>= fun x ->
+ skipped := x+1
+ else
+ return ()
(* Prints the prompt *)
let rec prompt level =
+ (* spiwack: avoid overriding by the open below *)
+ let runtrue = run true in
begin
- msg (fnl () ++ str "TcDebug (" ++ int level ++ str ") > ");
- flush stdout;
- let exit () = skip:=0;skipped:=0;raise Sys.Break in
- let inst = try read_line () with End_of_file -> exit () in
+ let open Proofview.NonLogical in
+ Proofview.NonLogical.print (fnl () ++ str "TcDebug (" ++ int level ++ str ") > ") >>
+ let exit = (skip:=0) >> (skipped:=0) >> raise Sys.Break in
+ Proofview.NonLogical.catch Proofview.NonLogical.read_line
+ begin function (e, info) -> match e with
+ | End_of_file -> exit
+ | e -> raise ~info e
+ end
+ >>= fun inst ->
match inst with
- | "" -> DebugOn (level+1)
- | "s" -> DebugOff
- | "x" -> print_char (Char.chr 8); exit ()
+ | "" -> return (DebugOn (level+1))
+ | "s" -> return (DebugOff)
+ | "x" -> Proofview.NonLogical.print_char '\b' >> exit
| "h"| "?" ->
begin
- help ();
+ help () >>
prompt level
end
| _ ->
- (try run_com inst;run true;DebugOn (level+1)
- with Failure _ | Invalid_argument _ -> prompt level)
+ Proofview.NonLogical.catch (run_com inst >> runtrue >> return (DebugOn (level+1)))
+ begin function (e, info) -> match e with
+ | Failure _ | Invalid_argument _ -> prompt level
+ | e -> raise ~info e
+ end
end
(* Prints the state and waits for an instruction *)
-let debug_prompt lev g tac f =
+(* spiwack: the only reason why we need to take the continuation [f]
+ as an argument rather than returning the new level directly seems to
+ be that [f] is wrapped in with "explain_logic_error". I don't think
+ it serves any purpose in the current design, so we could just drop
+ that. *)
+let debug_prompt lev tac f =
+ (* spiwack: avoid overriding by the open below *)
+ let runfalse = run false in
+ let open Proofview.NonLogical in
+ let (>=) = Proofview.tclBIND in
(* What to print and to do next *)
let newlevel =
- if !skip = 0 then
- if !breakpoint = None then (goal_com g tac; prompt lev)
- else (run false; DebugOn (lev+1))
- else (decr skip; run false; if !skip=0 then skipped:=0; DebugOn (lev+1)) in
+ Proofview.tclLIFT !skip >= fun initial_skip ->
+ if Int.equal initial_skip 0 then
+ Proofview.tclLIFT !breakpoint >= fun breakpoint ->
+ if Option.is_empty breakpoint then Proofview.tclTHEN (goal_com tac) (Proofview.tclLIFT (prompt lev))
+ else Proofview.tclLIFT(runfalse >> return (DebugOn (lev+1)))
+ else Proofview.tclLIFT begin
+ (!skip >>= fun s -> skip:=s-1) >>
+ runfalse >>
+ !skip >>= fun new_skip ->
+ (if Int.equal new_skip 0 then skipped:=0 else return ()) >>
+ return (DebugOn (lev+1))
+ end in
+ newlevel >= fun newlevel ->
(* What to execute *)
- try f newlevel
- with reraise ->
- skip:=0; skipped:=0;
- if Logic.catchable_exception reraise then
- ppnl (str "Level " ++ int lev ++ str ": " ++ !explain_logic_error reraise);
- raise reraise
+ Proofview.tclOR
+ (f newlevel)
+ begin fun (reraise, info) ->
+ Proofview.tclTHEN
+ (Proofview.tclLIFT begin
+ (skip:=0) >> (skipped:=0) >>
+ if Logic.catchable_exception reraise then
+ msg_tac_debug (str "Level " ++ int lev ++ str ": " ++ Pervasives.(!) explain_logic_error reraise)
+ else return ()
+ end)
+ (Proofview.tclZERO ~info reraise)
+ end
+
+let is_debug db =
+ let open Proofview.NonLogical in
+ !breakpoint >>= fun breakpoint ->
+ match db, breakpoint with
+ | DebugOff, _ -> return false
+ | _, Some _ -> return false
+ | _ ->
+ !skip >>= fun skip ->
+ return (Int.equal skip 0)
(* Prints a constr *)
let db_constr debug env c =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
- msgnl (str "Evaluated term: " ++ print_constr_env env c)
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
+ msg_tac_debug (str "Evaluated term: " ++ print_constr_env env c)
+ else return ()
(* Prints the pattern rule *)
let db_pattern_rule debug num r =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
begin
- msgnl (str "Pattern rule " ++ int num ++ str ":");
- msgnl (str "|" ++ spc () ++ !prmatchrl r)
+ msg_tac_debug (str "Pattern rule " ++ int num ++ str ":" ++ fnl () ++
+ str "|" ++ spc () ++ Hook.get prmatchrl r)
end
+ else return ()
(* Prints the hypothesis pattern identifier if it exists *)
let hyp_bound = function
| Anonymous -> " (unbound)"
- | Name id -> " (bound to "^(Names.string_of_id id)^")"
+ | Name id -> " (bound to "^(Names.Id.to_string id)^")"
(* Prints a matched hypothesis *)
let db_matched_hyp debug env (id,_,c) ido =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
- msgnl (str "Hypothesis " ++
- str ((Names.string_of_id id)^(hyp_bound ido)^
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
+ msg_tac_debug (str "Hypothesis " ++
+ str ((Names.Id.to_string id)^(hyp_bound ido)^
" has been matched: ") ++ print_constr_env env c)
+ else return ()
(* Prints the matched conclusion *)
let db_matched_concl debug env c =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
- msgnl (str "Conclusion has been matched: " ++ print_constr_env env c)
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
+ msg_tac_debug (str "Conclusion has been matched: " ++ print_constr_env env c)
+ else return ()
(* Prints a success message when the goal has been matched *)
let db_mc_pattern_success debug =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
- msgnl (str "The goal has been successfully matched!" ++ fnl() ++
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
+ msg_tac_debug (str "The goal has been successfully matched!" ++ fnl() ++
str "Let us execute the right-hand side part..." ++ fnl())
+ else return ()
(* Prints a failure message for an hypothesis pattern *)
-let db_hyp_pattern_failure debug env (na,hyp) =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
- msgnl (str ("The pattern hypothesis"^(hyp_bound na)^
+let db_hyp_pattern_failure debug env sigma (na,hyp) =
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
+ msg_tac_debug (str ("The pattern hypothesis"^(hyp_bound na)^
" cannot match: ") ++
- !prmatchpatt env hyp)
+ Hook.get prmatchpatt env sigma hyp)
+ else return ()
(* Prints a matching failure message for a rule *)
let db_matching_failure debug =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
- msgnl (str "This rule has failed due to matching errors!" ++ fnl() ++
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
+ msg_tac_debug (str "This rule has failed due to matching errors!" ++ fnl() ++
str "Let us try the next one...")
+ else return ()
(* Prints an evaluation failure message for a rule *)
let db_eval_failure debug s =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
let s = str "message \"" ++ s ++ str "\"" in
- msgnl
+ msg_tac_debug
(str "This rule has failed due to \"Fail\" tactic (" ++
s ++ str ", level 0)!" ++ fnl() ++ str "Let us try the next one...")
+ else return ()
(* Prints a logic failure message for a rule *)
let db_logic_failure debug err =
- if debug <> DebugOff & !skip = 0 & !breakpoint = None then
+ let open Proofview.NonLogical in
+ is_debug debug >>= fun db ->
+ if db then
begin
- msgnl (!explain_logic_error err);
- msgnl (str "This rule has failed due to a logic error!" ++ fnl() ++
+ msg_tac_debug (Pervasives.(!) explain_logic_error err) >>
+ msg_tac_debug (str "This rule has failed due to a logic error!" ++ fnl() ++
str "Let us try the next one...")
end
+ else return ()
let is_breakpoint brkname s = match brkname, s with
- | Some s, MsgString s'::_ -> s = s'
+ | Some s, MsgString s'::_ -> String.equal s s'
| _ -> false
let db_breakpoint debug s =
+ let open Proofview.NonLogical in
+ !breakpoint >>= fun opt_breakpoint ->
match debug with
- | DebugOn lev when s <> [] & is_breakpoint !breakpoint s ->
+ | DebugOn lev when not (CList.is_empty s) && is_breakpoint opt_breakpoint s ->
breakpoint:=None
| _ ->
- ()
+ return ()