diff options
Diffstat (limited to 'proofs/proof_global.ml')
-rw-r--r-- | proofs/proof_global.ml | 257 |
1 files changed, 120 insertions, 137 deletions
diff --git a/proofs/proof_global.ml b/proofs/proof_global.ml index ed985f292..0c0aac715 100644 --- a/proofs/proof_global.ml +++ b/proofs/proof_global.ml @@ -17,6 +17,7 @@ open Util open Pp open Names +open Util (*** Proof Modes ***) @@ -59,32 +60,31 @@ let _ = (*** Proof Global Environment ***) -(* local shorthand *) -type nproof = Id.t*Proof.proof - (* Extra info on proofs. *) type lemma_possible_guards = int list list -type proof_info = { - strength : Decl_kinds.goal_kind ; - compute_guard : lemma_possible_guards; - hook : unit Tacexpr.declaration_hook ; - mode : proof_mode + +type pstate = { + pid : Id.t; + endline_tactic : unit Proofview.tactic; + section_vars : Context.section_context option; + proof : Proof.proof; + strength : Decl_kinds.goal_kind; + compute_guard : lemma_possible_guards; + hook : unit Tacexpr.declaration_hook; + mode : proof_mode; } -(* Invariant: the domain of proof_info is current_proof.*) -(* The head of [!current_proof] is the actual current proof, the other ones are +(* The head of [!pstates] is the actual current proof, the other ones are to be resumed when the current proof is closed or aborted. *) -let current_proof = ref ([]:nproof list) -let proof_info = ref (Id.Map.empty : proof_info Id.Map.t) +let pstates = ref ([] : pstate list) (* Current proof_mode, for bookkeeping *) let current_proof_mode = ref !default_proof_mode (* combinators for proof modes *) let update_proof_mode () = - match !current_proof with - | (id,_)::_ -> - let { mode = m } = Id.Map.find id !proof_info in + match !pstates with + | { mode = m } :: _ -> !current_proof_mode.reset (); current_proof_mode := m; !current_proof_mode.set () @@ -103,7 +103,7 @@ let _ = Errors.register_handler begin function end let extract id l = let rec aux = function - | ((id',_) as np)::l when Id.equal id id' -> (np,l) + | ({pid = id' } as np)::l when Id.equal id id' -> (np,l) | np::l -> let (np', l) = aux l in (np' , np::l) | [] -> raise NoSuchProof in @@ -121,10 +121,6 @@ let extract_top l = match !l with | np::l' -> l := l' ; update_proof_mode (); np | [] -> raise NoCurrentProof -let find_top l = - match !l with - | np::_ -> np - | [] -> raise NoCurrentProof (* combinators for the proof_info map *) let add id info m = @@ -135,13 +131,28 @@ let remove id m = (*** Proof Global manipulation ***) let get_all_proof_names () = - List.map fst !current_proof + List.map (function { pid = id } -> id) !pstates -let give_me_the_proof () = - snd (find_top current_proof) +let cur_pstate () = + match !pstates with + | np::_ -> np + | [] -> raise NoCurrentProof -let get_current_proof_name () = - fst (find_top current_proof) +let give_me_the_proof () = (cur_pstate ()).proof +let get_current_proof_name () = (cur_pstate ()).pid + +let with_current_proof f = + match !pstates with + | [] -> raise NoCurrentProof + | p :: rest -> + let p = { p with proof = f p.endline_tactic p.proof } in + pstates := p :: rest + +(* Sets the tactic to be used when a tactic line is closed with [...] *) +let set_endline_tactic tac = + match !pstates with + | [] -> raise NoCurrentProof + | p :: rest -> pstates := { p with endline_tactic = tac } :: rest (* spiwack: it might be considered to move error messages away. Or else to remove special exceptions from Proof_global. @@ -155,7 +166,7 @@ let msg_proofs () = | l -> (str"." ++ fnl () ++ str"Proofs currently edited:" ++ spc () ++ (pr_sequence Nameops.pr_id l) ++ str".") -let there_is_a_proof () = not (List.is_empty !current_proof) +let there_is_a_proof () = not (List.is_empty !pstates) let there_are_pending_proofs () = there_is_a_proof () let check_no_pending_proof () = if not (there_are_pending_proofs ()) then @@ -167,51 +178,40 @@ let check_no_pending_proof () = end let discard_gen id = - ignore (extract id current_proof); - remove id proof_info + pstates := List.filter (fun { pid = id' } -> id <> id') !pstates let discard (loc,id) = - try - discard_gen id - with NoSuchProof -> + let n = List.length !pstates in + discard_gen id; + if List.length !pstates = n then Errors.user_err_loc (loc,"Pfedit.delete_proof",str"No such proof" ++ msg_proofs ()) let discard_current () = - let (id,_) = extract_top current_proof in - remove id proof_info + if !pstates = [] then raise NoCurrentProof else pstates := List.tl !pstates -let discard_all () = - current_proof := []; - proof_info := Id.Map.empty +let discard_all () = pstates := [] (* [set_proof_mode] sets the proof mode to be used after it's called. It is typically called by the Proof Mode command. *) -(* Core component. - No undo handling. - Applies to proof [id], and proof mode [m]. *) let set_proof_mode m id = - let info = Id.Map.find id !proof_info in - let info = { info with mode = m } in - proof_info := Id.Map.add id info !proof_info; + pstates := + List.map (function { pid = id' } as p -> + if Id.equal id' id then { p with mode = m } else p) !pstates; update_proof_mode () -(* Complete function. - Handles undo. - Applies to current proof, and proof mode name [mn]. *) + let set_proof_mode mn = - let m = find_proof_mode mn in - let id = get_current_proof_name () in - let pr = give_me_the_proof () in - Proof.add_undo begin let curr = !current_proof_mode in fun () -> - set_proof_mode curr id ; update_proof_mode () - end pr ; - set_proof_mode m id + set_proof_mode (find_proof_mode mn) (get_current_proof_name ()) + +let activate_proof_mode mode = (find_proof_mode mode).set () +let disactivate_proof_mode mode = (find_proof_mode mode).reset () exception AlreadyExists let _ = Errors.register_handler begin function | AlreadyExists -> Errors.error "Already editing something of that name." | _ -> raise Errors.Unhandled end + (* [start_proof s str env t hook tac] starts a proof of name [s] and conclusion [t]; [hook] is optionally a function to be applied at proof end (e.g. to declare the built constructions as a coercion @@ -220,84 +220,67 @@ end proof of mutually dependent theorems). It raises exception [ProofInProgress] if there is a proof being currently edited. *) -let start_proof id str goals ?(compute_guard=[]) hook = - begin - List.iter begin fun (id_ex,_) -> - if Names.Id.equal id id_ex then raise AlreadyExists - end !current_proof - end; - let p = Proof.start goals in - add id { strength=str ; - compute_guard=compute_guard ; - hook=hook ; - mode = ! default_proof_mode } proof_info ; - push (id,p) current_proof - -(* arnaud: à enlever *) -let run_tactic tac = - let p = give_me_the_proof () in - let env = Global.env () in - Proof.run_tactic env tac p -(* Sets the tactic to be used when a tactic line is closed with [...] *) -let set_endline_tactic tac = - let p = give_me_the_proof () in - Proof.set_endline_tactic tac p +let start_proof id str goals ?(compute_guard=[]) hook = + let initial_state = { + pid = id; + proof = Proof.start goals; + endline_tactic = Proofview.tclUNIT (); + section_vars = None; + strength = str; + compute_guard = compute_guard; + hook = hook; + mode = ! default_proof_mode } in + push initial_state pstates + +let get_used_variables () = (cur_pstate ()).section_vars let set_used_variables l = - let p = give_me_the_proof () in let env = Global.env () in let ids = List.fold_right Id.Set.add l Id.Set.empty in let ctx = Environ.keep_hyps env ids in - Proof.set_used_variables ctx p - -let get_used_variables () = - Proof.get_used_variables (give_me_the_proof ()) - -let with_end_tac tac = - let p = give_me_the_proof () in - Proof.with_end_tac p tac - + match !pstates with + | [] -> raise NoCurrentProof + | p :: rest -> + if p.section_vars <> None then + Errors.error "Used section variables can be declared only once"; + pstates := { p with section_vars = Some ctx} :: rest + +let get_open_goals () = + let gl, gll, _ = Proof.proof (cur_pstate ()).proof in + List.length gl + + List.fold_left (+) 0 + (List.map (fun (l1,l2) -> List.length l1 + List.length l2) gll) + +type closed_proof = + Names.Id.t * + (Entries.definition_entry list * lemma_possible_guards * + Decl_kinds.goal_kind * unit Tacexpr.declaration_hook) + +let close_proof ~now ?(fix_exn = fun x -> x) ps side_eff = + let { pid; section_vars; compute_guard; strength; hook; proof } = ps in + let entries = List.map (fun (c, t) -> { Entries. + const_entry_body = Future.chain side_eff (fun () -> + try Proof.return (cur_pstate ()).proof c with + | Proof.UnfinishedProof -> + raise (fix_exn(Errors.UserError("last tactic before Qed", + str"Attempt to save an incomplete proof"))) + | Proof.HasUnresolvedEvar -> + raise (fix_exn(Errors.UserError("last tactic before Qed", + str"Attempt to save a proof with existential " ++ + str"variables still non-instantiated")))); + const_entry_secctx = section_vars; + const_entry_type = Some t; + const_entry_inline_code = false; + const_entry_opaque = true }) (Proof.initial_goals proof) in + if now then + List.iter (fun x -> ignore(Future.join x.Entries.const_entry_body)) entries; + (pid, (entries, compute_guard, strength, hook)) + +let close_future_proof ~fix_exn proof = + close_proof ~now:false ~fix_exn (cur_pstate ()) proof let close_proof () = - (* spiwack: for now close_proof doesn't actually discard the proof, it is done - by [Command.save]. *) - try - let id = get_current_proof_name () in - let p = give_me_the_proof () in - let proofs_and_types = Proof.return p in - let section_vars = Proof.get_used_variables p in - let entries = List.map - (fun (c,t) -> { Entries.const_entry_body = c; - const_entry_secctx = section_vars; - const_entry_type = Some t; - const_entry_opaque = true; - const_entry_inline_code = false }) - proofs_and_types - in - let { compute_guard=cg ; strength=str ; hook=hook } = - Id.Map.find id !proof_info - in - (id, (entries,cg,str,hook)) - with - | Proof.UnfinishedProof -> - Errors.error "Attempt to save an incomplete proof" - | Proof.HasUnresolvedEvar -> - Errors.error "Attempt to save a proof with existential variables still non-instantiated" - - -(**********************************************************) -(* *) -(* Utility functions *) -(* *) -(**********************************************************) - -let maximal_unfocus k p = - begin try while Proof.no_focused_goal p do - Proof.unfocus k p - done - with Proof.FullyUnfocused | Proof.CannotUnfocusThisWay -> () - end - + close_proof ~now:true (cur_pstate ()) (Future.from_val()) (**********************************************************) (* *) @@ -317,7 +300,7 @@ module Bullet = struct type behavior = { name : string; - put : Proof.proof -> t -> unit + put : Proof.proof -> t -> Proof.proof } let behaviors = Hashtbl.create 4 @@ -326,7 +309,7 @@ module Bullet = struct (*** initial modes ***) let none = { name = "None"; - put = fun _ _ -> () + put = fun x _ -> x } let _ = register_behavior none @@ -356,8 +339,8 @@ module Bullet = struct let pop pr = match get_bullets pr with | b::_ -> - Proof.unfocus bullet_kind pr; - (*returns*) b + let pr = Proof.unfocus bullet_kind pr () in + pr, b | _ -> assert false let push b pr = @@ -365,10 +348,10 @@ module Bullet = struct let put p bul = if has_bullet bul p then - Proof.transaction p begin fun () -> - while not (bullet_eq bul (pop p)) do () done; - push bul p - end + let rec aux p = + let p, b = pop p in + if not (bullet_eq bul b) then aux p else p in + push bul (aux p) else push bul p @@ -403,11 +386,11 @@ end module V82 = struct let get_current_initial_conclusions () = - let p = give_me_the_proof () in - let id = get_current_proof_name () in - let { strength=str ; hook=hook } = - Id.Map.find id !proof_info - in - (id,(Proof.V82.get_initial_conclusions p, str, hook)) + let { pid; strength; hook; proof } = cur_pstate () in + pid, (List.map snd (Proof.initial_goals proof), strength, hook) end +type state = pstate list +let freeze () = !pstates +let unfreeze s = pstates := s; update_proof_mode () + |