apply_debug: add support for method re-play

This allows for execution to restart and re-play up
to the current "continue", regardless of whether or not
the overall execution has moved past it.
This commit is contained in:
Daniel Matichuk 2016-12-06 15:36:36 +11:00
parent f8c58793e5
commit 21bd775bc0
1 changed files with 757 additions and 0 deletions

757
lib/Apply_Debug.thy Normal file
View File

@ -0,0 +1,757 @@
(*
*
* Copyright 2017, Data61, CSIRO
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(DATA61_BSD)
*)
theory Apply_Debug
imports Main "~~/src/HOL/Eisbach/Eisbach_Tools"
keywords "apply_debug" :: "prf_script" % "proof" and
"continue" :: prf_script % "proof" and "finish" :: prf_script % "proof"
begin
ML \<open>fun method_evaluate text ctxt facts =
Method.NO_CONTEXT_TACTIC ctxt
(Method_Closure.method_evaluate text ctxt facts)\<close>
ML \<open>fun do_markup range m = Output.report [Markup.markup (Markup.properties (Position.properties_of_range range) m) ""];
\<close>
method_setup markup =
\<open>Scan.state :|-- (fn st => Scan.lift (Scan.trace (Scan.pass st Method_Closure.method_text))) >>
(fn (text, toks) => fn _ => fn facts =>
let
val range = case (Token.get_value (hd toks)) of
SOME (Token.Source src) => Token.range_of src
| _ => Position.no_range
fun tac (ctxt,thm) = Method_Closure.method_evaluate text ctxt facts (ctxt,thm)
fun traceify seq = Seq.make (fn () =>
let
val _ = do_markup range Markup.running;
val r = Seq.pull seq;
val _ = do_markup range Markup.finished;
in Option.map (apsnd traceify) r end)
in traceify o tac end)\<close>
ML \<open>fun wrap_src src =
let
val pos = Token.range_of src |> Position.set_range;
val tok = Token.make_string ("", pos);
val tok' = Token.assign (SOME (Token.Source src)) tok;
in Token.closure tok' end
\<close>
ML \<open>
fun add_debug (Method.Source src) =
(Method.Source (Token.make_src ("Apply_Debug.markup", Position.none) [wrap_src src]))
| add_debug (Method.Combinator (x,y,txts)) = (Method.Combinator (x,y, map add_debug txts))
| add_debug x = x
\<close>
ML \<open>fun st_eq (ctxt : Proof.context,st) (ctxt',st') =
pointer_eq (ctxt,ctxt') andalso Thm.eq_thm (st,st')\<close>
ML \<open>type result =
{ pre_state : (Proof.context * thm),
post_state : (Proof.context * thm) }
\<close>
ML \<open>datatype final_state = RESULT of (Proof.context * thm) | ERR of (unit -> string)\<close>
ML \<open>type debug_state =
{results : result list, (* this execution, in order of appearance *)
prev_results : (Proof.context * thm) list, (* continuations needed to get thread back to some state*)
next_state : (Proof.context * thm) option,
break_state : (Proof.context * thm) option, (* latest breakpoint *)
restart : (unit -> unit) * int, (* restart function (how many previous results to keep), restart requested *)
final : final_state option, (* final result, maybe error *)
trans_id : int, (* some attempt at synchronization *)
ignore_breaks: bool}
val init_state =
({results = [],
prev_results = [],
next_state = NONE, break_state = NONE,
final = NONE, ignore_breaks = false, restart = (K (), 0), trans_id = ~1} : debug_state)
fun map_next_state f ({results, next_state, break_state, final, ignore_breaks, prev_results, restart, trans_id} : debug_state) =
({results = results, next_state = f next_state, break_state = break_state, final = final, prev_results = prev_results,
restart = restart, ignore_breaks = ignore_breaks, trans_id = trans_id} : debug_state)
fun map_results f ({results, next_state, break_state, final, ignore_breaks, prev_results, restart, trans_id} : debug_state) =
({results = f results, next_state = next_state, break_state = break_state, final = final, prev_results = prev_results,
restart = restart, ignore_breaks = ignore_breaks, trans_id = trans_id} : debug_state)
fun map_prev_results f ({results, next_state, break_state, final, ignore_breaks, prev_results, restart, trans_id} : debug_state) =
({results = results, next_state = next_state, break_state = break_state, final = final, prev_results = f prev_results,
restart = restart, ignore_breaks = ignore_breaks, trans_id = trans_id} : debug_state)
fun map_ignore_breaks f ({results, next_state, break_state = break_state, final, ignore_breaks, prev_results, restart, trans_id} : debug_state) =
({results = results, next_state = next_state, break_state = break_state,final = final, prev_results = prev_results,
restart = restart, ignore_breaks = f ignore_breaks, trans_id = trans_id} : debug_state)
fun map_final f ({results, next_state, break_state, final, ignore_breaks, prev_results, restart, trans_id} : debug_state) =
({results = results, next_state = next_state, break_state =break_state ,final = f final, prev_results = prev_results,
restart = restart, ignore_breaks = ignore_breaks, trans_id = trans_id} : debug_state)
fun map_restart f ({results, next_state, break_state, final, ignore_breaks, prev_results, restart, trans_id} : debug_state) =
({results = results, next_state = next_state, break_state = break_state, final = final, prev_results = prev_results,
restart = f restart, ignore_breaks = ignore_breaks, trans_id = trans_id} : debug_state)
fun map_break_state f ({results, next_state, break_state, final, ignore_breaks, prev_results, restart, trans_id} : debug_state) =
({results = results, next_state = next_state, break_state = f break_state, final = final, prev_results = prev_results,
restart = restart, ignore_breaks = ignore_breaks, trans_id = trans_id} : debug_state)
fun map_trans_id f ({results, next_state, break_state, final, ignore_breaks, prev_results, restart, trans_id} : debug_state) =
({results = results, next_state = next_state, break_state = break_state, final = final, prev_results = prev_results,
restart = restart, ignore_breaks = ignore_breaks, trans_id = f trans_id} : debug_state)
fun is_restarting ({restart,...} : debug_state) = snd restart > ~1;
fun is_finished ({final,...} : debug_state) = is_some final;
val drop_states = map_break_state (K NONE) o map_next_state (K NONE);
fun add_result pre post = map_results (cons {pre_state = pre, post_state = post}) o drop_states;
\<close>
ML \<open>
fun guarded_access (id,trans_id) f =
Synchronized.guarded_access id
(fn (e : debug_state) =>
if trans_id = ~1 orelse #trans_id e = trans_id then
(case f e of
NONE => NONE
| SOME (e', g) => SOME (e', g e))
else NONE)
fun guarded_read (id,trans_id) f =
Synchronized.guarded_access id
(fn (e : debug_state) =>
if trans_id = ~1 orelse #trans_id e = trans_id then
(case f e of
NONE => NONE
| SOME e' => SOME (e', e))
else NONE)
(* Immediate return if there are previous results available or we are ignoring breakpoints *)
fun pop_state_no_block id pre = guarded_access (id,~1) (fn e =>
if is_restarting e then NONE else
if is_finished e then error "Attempted to pop state from finished proof" else
if (#ignore_breaks e) then SOME (SOME pre, add_result pre pre) else
case #prev_results e of
[] => SOME (NONE, I)
| (st :: sts) => SOME (SOME st, add_result pre st o map_prev_results (fn _ => sts)))
fun pop_next_state id pre = guarded_access (id,~1) (fn e =>
if is_restarting e then NONE else
if is_finished e then error "Attempted to pop state from finished proof" else
if not (null (#prev_results e)) then error "Attempted to pop state when previous results exist" else
if (#ignore_breaks e) then SOME (pre, add_result pre pre) else
(case #next_state e of
NONE => NONE
| SOME st => SOME (st, add_result pre st)))
fun set_next_state id st = guarded_access id (fn e =>
if is_restarting e then NONE else
if is_none (#next_state e) andalso is_some (#break_state e) then
SOME ((), map_next_state (fn _ => SOME st) o map_break_state (fn _ => NONE))
else error ("Attempted to set next state in inconsistent state" ^ (@{make_string} e)))
fun set_break_state id st = guarded_access id (fn e =>
if is_restarting e then NONE else
if is_none (#next_state e) andalso is_none (#break_state e) then
SOME ((), map_break_state (fn _ => SOME st))
else error ("Attempted to set break state in inconsistent state" ^ (@{make_string} e)))
fun pop_state id pre =
case pop_state_no_block id pre of SOME st => st | NONE => (set_break_state (id,~1) pre; pop_next_state id pre)
(* block until a breakpoint is hit or method finishes *)
fun wait_break_state id = guarded_read id
(fn e =>
if is_restarting e then NONE else
case (#final e) of SOME st => SOME (st, true) | NONE =>
case (#break_state e) of SOME st => SOME (RESULT st, false)
| NONE => NONE);
(* Trigger a restart if an existing nth entry differs from the given one *)
fun maybe_restart id n st =
let
val _ = guarded_access id (fn e =>
if is_some (#next_state e) then NONE
else if is_restarting e then NONE (* TODO, what to do if we're already restarting? *)
else if length (#results e) > n then
(if st_eq (#post_state (nth (rev (#results e)) n)) st then SOME ((), I)
else SOME ((), map_restart (apsnd (fn _ => n))))
else SOME ((), I))
val _ = guarded_read id (fn e => if is_restarting e then NONE else SOME ());
in () end;
fun peek_head_result id = guarded_read id (fn e => case #results e of [] => NONE | (x :: _) => SOME x)
fun peek_all_results id = guarded_read id (fn e => SOME (#results e));
fun peek_prev_results id = guarded_read id (fn e => SOME (#prev_results e));
fun push_result id st = guarded_access id
(fn e => if is_restarting e then NONE else SOME ((),map_results (cons st)));
fun peek_final_result id =
guarded_read id (fn e => #final e)
fun debug_print (id : debug_state Synchronized.var, trans_id) =
(@{print} (Synchronized.value id, trans_id));
fun poke_error (RESULT st) = st
| poke_error (ERR e) = error (e ())
fun new_transaction_id id = guarded_access (id,~1)
(fn _ => let val trans_id = serial () in SOME (trans_id, map_trans_id (fn _ => trans_id)) end);
\<close>
ML \<open>
fun nth_pre_result id i = guarded_read id
(fn e =>
if is_restarting e then NONE else
if length (#results e) > i then SOME (RESULT (#pre_state (nth (rev (#results e)) i)), false) else
if length (#results e) = i then
(case #break_state e of SOME st => SOME (RESULT st, false) | NONE => NONE) else
(case #final e of SOME st => SOME (st, true) | NONE => NONE))
\<close>
ML \<open>
fun tap_prf f st = Seq.pull (Proof.apply (Method.Basic (fn _ => fn _ => fn x =>
((f x : unit); Seq.make_results (Seq.single x))), Position.no_range) st)
fun set_finished_result id st =
guarded_access (id,~1) (fn _ => SOME ((), map_final (K (SOME st))));
fun is_finished_result id = guarded_read id (fn e => SOME (is_finished e));
fun get_finish id =
if is_finished_result id then peek_final_result id else
let
val _ = guarded_access id
(fn _ => SOME ((), (map_ignore_breaks (fn _ => true))))
in peek_final_result id end
\<close>
ML \<open>
structure Debug_Data = Proof_Data
(
type T = debug_state Synchronized.var option (* execution id *) *
int (* continuation counter *)
fun init _ : T = (NONE,~1)
);
fun set_debug_ident ident = Debug_Data.map (apfst (fn _ => SOME ident))
val get_debug_ident = the o fst o Debug_Data.get
val is_debug_ctxt = is_some o fst o Debug_Data.get;
val clear_debug = Debug_Data.map (apfst (fn _ => NONE));
val get_continuation = snd o Debug_Data.get;
(* Maintain pointer equality if possible *)
fun set_continuation i ctxt = if get_continuation ctxt = i then ctxt else
Debug_Data.map (apsnd (fn _ => i)) ctxt;
\<close>
method_setup break = \<open>Scan.succeed (fn ctxt => fn facts => fn st =>
let
val id = get_debug_ident ctxt;
val st' = Seq.make (fn () =>
SOME (pop_state id st,Seq.empty))
in Seq.make_results st' end)
\<close>
ML \<open>
fun map_state f state =
Seq.make (fn () =>
let
val r = Seq.pull (Proof.apply
(Method.Basic (fn _ => fn _ => fn st =>
Seq.make_results (Seq.single (f st))),
Position.no_range) state)
in r end);
\<close>
ML \<open>
fun do_apply pos ident rng m =
let
val _ = Method.report m;
in
(fn st =>
let
val _ = if get_continuation (#context (Proof.simple_goal st)) > ~1 then
error "Cannot use apply_debug while debugging" else ();
val _ = do_markup rng Markup.finished;
val _ = do_markup rng Markup.finished;
val st = Proof.map_context (set_debug_ident ident o set_continuation ~1) st;
fun do_fork b () = Future.fork (fn () =>
let
fun error_finish e = tap_prf (fn _ => set_finished_result ident (ERR e)) st;
val _ = case (Seq.pull (Proof.apply m st))
of SOME (Seq.Result st', _) =>
(tap_prf (fn r => set_finished_result ident (RESULT r)) st')
| SOME (Seq.Error e, _) => (error_finish e)
| NONE => (error_finish (fn _ => "No results"))
val _ = if b then do_markup rng Markup.running else ();
in () end)
val _ = Execution.fork {name = "apply_debug_main", pos = pos, pri = ~1} (fn () =>
let
fun restart_state gls e = e
|> map_prev_results (fn _ => map #post_state (take gls (rev (#results e))))
|> map_results (fn _ => [])
|> map_final (fn _ => NONE)
|> map_ignore_breaks (fn _ => false)
|> map_restart (fn _ => (K (), gls))
|> map_break_state (fn _ => NONE)
|> map_next_state (fn _ => NONE)
fun main_loop () =
let
val f = Synchronized.guarded_access ident (fn e as {restart,next_state,...} =>
if is_restarting e andalso is_none next_state then
SOME (fst restart, restart_state (snd restart) e) else NONE);
val _ = f ();
val thread = do_fork false ();
val _ = Synchronized.change ident (map_restart (fn _ => (fn () => Future.cancel thread, ~1)))
in main_loop () end
in main_loop () end)
val thread = do_fork true ();
val _ = Synchronized.change ident (map_restart (fn _ => (fn () => Future.cancel thread, ~1)));
fun do_peek () =
let
val trans_id = new_transaction_id ident;
val (r,b) = wait_break_state (ident,trans_id);
val st' = poke_error r;
val _ = if b then Output.writeln "Final result" else ();
in st' |> apfst (set_continuation 0) end
in map_state (fn _ =>
let val r = do_peek ()
val _ = do_markup rng Markup.running in r end) st
end)
end
val _ =
Outer_Syntax.command @{command_keyword apply_debug} "initial goal refinement step (unstructured)"
(Method.parse >> (fn (m',rng) =>
let
val m'' = add_debug m'
val m = (m'',rng)
val pos = Position.thread_data ();
val ident = Synchronized.var "debug_state" init_state;
val x = do_apply pos ident rng m;
in Toplevel.proofs x end));
\<close>
ML \<open>
val _ =
Outer_Syntax.command @{command_keyword finish} "finish debugging"
(Scan.succeed (Toplevel.proofs
(map_state (fn (ctxt,_) =>
let
val _ = if get_continuation ctxt < 0 then error "Cannot finish in a non-debug state" else ();
val id' = get_debug_ident ctxt;
val id = (id', new_transaction_id id');
val f = get_finish id;
in f |> poke_error |> apfst (set_continuation ~1) end))))
\<close>
ML \<open>
val _ =
Outer_Syntax.command @{command_keyword continue} "step to next breakpoint"
(Scan.optional Parse.int 1 >> (fn i =>
(Toplevel.proofs
(map_state (fn (ctxt,thm) =>
let
val _ = if i < 1 then error "Must continue a non-zero amount" else ();
val _ = if get_continuation ctxt < 0 then error "Cannot continue in a non-debug state" else ();
val id' = get_debug_ident ctxt;
val id = (id', new_transaction_id id');
val _ = debug_print id;
val start_cont = get_continuation ctxt; (* how many breakpoints so far *)
val _ = @{print} ("start_cont",start_cont);
val _ = maybe_restart id start_cont (ctxt,thm); (* possibly restart if the thread has made too much progress *)
val _ = @{print} "finished restart"
val _ = nth_pre_result id start_cont; (* block until we've hit the start of this continuation *)
val _ = @{print} "got up to speed";
val _ = debug_print id;
val cont = start_cont + i; (* final number of breakpoints hit *)
val ex_results = peek_all_results id |> rev;
fun tick_up n st = if n = cont then (st,false) else
let
val _ = set_next_state id st;
val (n_r, b) = wait_break_state id;
val st' = poke_error n_r;
in if b then ((st',b)) else tick_up (n + 1) st' end
val (st',b) =
if length ex_results > cont then
(#pre_state (nth ex_results cont), false)
else if length ex_results = cont then
wait_break_state id |> apfst poke_error
else if length ex_results = start_cont then
tick_up (length ex_results) (ctxt, thm)
else error "Unexpected number of existing results"
val st'' = if b then (Output.writeln "Final Result."; st' |> apfst (set_continuation ~1))
else st' |> apfst (set_continuation cont)
in st'' end)))))
\<close>
lemma foo: "A \<and> B"
ML_prf \<open>val ctxt1 = @{context}\<close>
ML_prf \<open>val ctxt2 = @{context}\<close>
ML_prf \<open>val b = pointer_eq (ctxt1,ctxt2)\<close>
ML \<open>Proof.apply\<close>
ML \<open>Proof_Context.update_cases_legacy\<close>
oops
lemma
assumes BA: "B \<Longrightarrow> A"
assumes CB: "C \<Longrightarrow> B"
assumes DC: "D \<Longrightarrow> C"
assumes ED: "E \<Longrightarrow> D"
assumes FE: "F \<Longrightarrow> E"
assumes EF: "E \<Longrightarrow> F"
shows
"A"
apply_debug (rule BA, break, rule CB, break, rule DC, break, rule ED, break, rule FE)
continue
continue
continue
apply (rule FE)
apply -
apply (rule EF)
continue
continue
oops
(*
apply_debug (sleep 1, rule BA, break, sleep 1, rule DC, break, rule FE, break)
apply (rule CB)
continue
apply (rule ED)
continue
finish
finish
oops
(* continue
oops
(* apply (rule DC)
continue
oops
(*
stop
continue
continue
apply -
subgoal
apply -
apply_debug ((sleep 1, rule quirk) | (sleep 1, rule baz) | sleep 2)
print_state
ML_prf \<open>Synchronized.value rr\<close>
ML \<open>error (Position.here_list (Synchronized.value rr)) \<close>
done
end
(*
(*let val n_ex =
if length ex_results > cont then
let
val _ = @{print} "restarting.."
val _ = Synchronized.guarded_access id (fn e => if snd (#restart e) > 0 then NONE else
SOME ((), map_restart (fn (f,_) => (f, start_cont)) e));
val _ = Synchronized.guarded_access id (fn e => if snd (#restart e) > 0 then NONE else SOME ((),e));
val _ = @{print} ("ex_results_pre", peek_all_results id)
val _ = @{print} ("prev_results_pre", #prev_results (Synchronized.value id))
val st = nth_result id (start_cont);
val _ = @{print} ("execution starts..", st)
in start_cont + 1 end
else length ex_results*)
ML \<open>
val _ =
Outer_Syntax.command @{command_keyword done'} "done proof"
(Scan.succeed
(Toplevel.end_proof_deferred
(fn defer => (@{print} "baz"; (K Proof.global_done_proof)))
(@{print} "foo"; (K Proof.global_done_proof))));
\<close>
(*
lemma "True"
apply (tactic \<open>fn st => (@{print} "pre_sleep"; Seq.single st)\<close>)
apply (sleep 10)
apply (tactic \<open>fn st => (@{print} "post_sleep"; Seq.single st)\<close>)
apply simp
done'*)
ML \<open>Exn.reraise\<close>
ML \<open>val e = error "foo" handle e => e\<close>
ML \<open>val e' = Exn_Properties.position e\<close>
ML \<open>Proof.pretty_state\<close>
ML \<open>Runtime.exn_messages_ids\<close>
ML \<open>Exn_Properties.get e\<close>
ML \<open>Runtime.exn_messages_ids\<close>
ML \<open>Runtime.exn_context\<close>
ML \<open> val pos = @{here}\<close>
ML \<open>Markup.markup_only\<close>
ML \<open>Output.error_message "foo"\<close>
ML \<open>
let
val _ = Position.report pos Markup.accepted
in () end\<close>
ML \<open>t : unit Exn.result\<close>
lemma
assumes A: "\<And>x :: 'b. PROP (P x)"
assumes B: "\<And>x :: 'b. PROP (P x) \<Longrightarrow> PROP (P x)"
shows
"\<And>x :: 'b. PROP (P x) \<Longrightarrow> PROP (P x)"
apply ( sleep 10)
subgoal for x
apply (rule B[where x=x])
term x
by -
apply -
apply (sleep 1)
apply (sleep 1)
apply (sleep 1, rule)
apply (rule B)
apply (rule B)
done
lemma "PROP P \<Longrightarrow> PROP P"
apply (sleep 5)
done
end
(*
ML \<open>fun f a b = a ? b\<close>
ML \<open>Runtime.controlled_execution\<close>
ML \<open>Proof_Context.cert_propp\<close>
lemmas
ML \<open>Thm.biresolution\<close>
ML \<open>Drule.multi_resolves\<close>
ML \<open>
(* Pending lemmas *)
structure Data = Generic_Data
(
type T = (Proof.context -> (local_theory -> local_theory)) list;
val empty = [];
val extend = I;
fun merge data : T = uncurry append data;
);
fun collapse_pending context =
let
val ps = Data.get context;
val ctxt = Context.proof_of context;
val (exit, lthy) = Named_Target.switch NONE context;
val context' = fold (fn f => fn lthy => f lthy) (map (fn p => p ctxt) ps) lthy |> exit;
in Data.map (fn _ => []) context' end
\<close>
ML \<open>is_none NONE\<close>
ML \<open>
local
val long_keyword =
Parse_Spec.includes >> K "" ||
Parse_Spec.long_statement_keyword;
val long_statement =
Scan.optional (Parse_Spec.opt_thm_name ":" --| Scan.ahead long_keyword) Binding.empty_atts --
Scan.optional Parse_Spec.includes [] -- Parse_Spec.long_statement
>> (fn ((binding, includes), (elems, concl)) => (true, binding, includes, elems, concl));
val short_statement =
Parse_Spec.statement -- Parse_Spec.if_statement -- Parse.for_fixes
>> (fn ((shows, assumes), fixes) =>
(false, Binding.empty_atts, [], [Element.Fixes fixes, Element.Assumes assumes],
Element.Shows shows));
fun wrap_shows' ctxt (nm, concls) =
(nm, map (fn (t, ts) => (Syntax.read_term ctxt t, Syntax.read_terms ctxt ts)) concls)
fun wrap_shows (Element.Shows l) = (fn ctxt => Element.Shows (map (wrap_shows' ctxt) l))
| wrap_shows _ = raise Fail "Unexpected";
local
val simple_asm = (fn ((_,atts),_) => List.all (fn att => length att < 2) atts)
in
fun simple_elem (Element.Fixes _) = true
| simple_elem (Element.Assumes l) = List.all simple_asm l
| simple_elem (Element.Constrains _) = true
| simple_elem (Element.Defines _) = true
| simple_elem (Element.Notes _) = false
end
fun do_proof long binding elems concl =
let
val finish = (fn ctxt =>
Specification.theorem_cmd long Thm.theoremK NONE (K I) binding [] elems concl true
#> Proof.global_skip_proof true)
in Proof.theorem NONE
(fn _ => Local_Theory.background_theory
(Context.theory_map (Data.map (fn ts => finish :: ts)))) [] end
fun theorem spec schematic descr =
Outer_Syntax.local_theory_to_proof' spec ("state " ^ descr)
((long_statement || short_statement) >>
(fn (long, binding, includes, elems, concl) =>
(if null includes andalso (List.all simple_elem elems)
then (fn _ => do_proof long binding elems concl) else
(if schematic then Specification.schematic_theorem_cmd else Specification.theorem_cmd)
long Thm.theoremK NONE (K I) binding includes elems concl)
));
val _ = theorem @{command_keyword lemma'} false "lemma'";
in end\<close>
lemmas
ML \<open>
Context.theory_of
\<close>
ML \<open>
\<close>
ML \<open>Parse.propp\<close>
ML \<open>Outer_Syntax.local_theory_to_proof' @{command_keyword lemma'} "lemma'"\<close>
syntax
"_bazz" :: "idt => bool" ("_!&" [70] 61)
parse_translation \<open>[(@{syntax_const "_bazz"},fn ctxt =>
fn ts => (OS.Process.sleep (seconds 0.1);@{print} "foo"; hd ts))]\<close>
lemma' baz:
assumes P:False
shows
"foo!&"
done
lemma' baz2:
assumes P:False
shows
"foo!&"
done
ML \<open>Data.get (Context.Theory @{theory})\<close>
ML \<open> Context.>> collapse_pending\<close>
thm baz
ML \<open>Named_Target.switch\<close>
lemma' baz[simp]: "([1,2] ! 3) = undefined (1 :: nat)"
apply sleep
apply (simp add: nth_def)
lemma "([] ! 1) = ([] ! 2)"
lemma foo
apply rule
oops
ML \<open>Named_Theorems.declare\<close>
named_theorems baz
method_setup add_named_theorem =
\<open>Attrib.thms >> (fn [thm'] => (fn thms' => fn ctxt =>
(fn (context,thm) => Seq.single (
Context.proof_map (Named_Theorems.add_thm "Scratch.baz" thm') context , thm)
|> Seq.make_results)))\<close>
ML \<open>Method.assumption\<close>
schematic_goal "?P"
subgoal
lemma assumes P:"P"
shows "P"
thm baz
subgoal
apply (add_named_theorem P)
thm baz
using P
apply (use in \<open>rule method_facts\<close>)
done
thm baz
done
thm baz
lemma P
apply (rule baz)
end