wenzelm@47336: (* Title: Pure/PIDE/command.ML wenzelm@47336: Author: Makarius wenzelm@47336: wenzelm@52534: Prover command execution: read -- eval -- print. wenzelm@47336: *) wenzelm@47336: wenzelm@47336: signature COMMAND = wenzelm@47336: sig wenzelm@52534: type eval_process wenzelm@52534: type eval = {exec_id: Document_ID.exec, eval_process: eval_process} wenzelm@52536: val eval_result_state: eval -> Toplevel.state wenzelm@52534: type print_process wenzelm@52534: type print = {name: string, pri: int, exec_id: Document_ID.exec, print_process: print_process} wenzelm@52534: type exec = eval * print list wenzelm@52536: val no_exec: exec wenzelm@52536: val exec_ids: exec -> Document_ID.exec list wenzelm@52535: val read: (unit -> theory) -> Token.T list -> Toplevel.transition wenzelm@52535: val eval: (unit -> theory) -> Token.T list -> eval -> eval wenzelm@52534: val print: string -> eval -> print list wenzelm@52526: type print_fn = Toplevel.transition -> Toplevel.state -> unit wenzelm@52526: val print_function: {name: string, pri: int} -> (string -> print_fn option) -> unit wenzelm@52536: val execute: exec -> unit wenzelm@52533: val stable_eval: eval -> bool wenzelm@52532: val stable_print: print -> bool wenzelm@47336: end; wenzelm@47336: wenzelm@47336: structure Command: COMMAND = wenzelm@47336: struct wenzelm@47336: wenzelm@52534: (** memo results -- including physical interrupts! **) wenzelm@47341: wenzelm@47341: datatype 'a expr = wenzelm@47341: Expr of unit -> 'a | wenzelm@47341: Result of 'a Exn.result; wenzelm@47341: wenzelm@47341: abstype 'a memo = Memo of 'a expr Synchronized.var wenzelm@47341: with wenzelm@47341: wenzelm@47341: fun memo e = Memo (Synchronized.var "Command.memo" (Expr e)); wenzelm@47341: fun memo_value a = Memo (Synchronized.var "Command.memo" (Result (Exn.Res a))); wenzelm@47341: wenzelm@47342: fun memo_eval (Memo v) = wenzelm@47341: (case Synchronized.value v of wenzelm@47341: Result res => res wenzelm@47341: | _ => wenzelm@47341: Synchronized.guarded_access v wenzelm@47341: (fn Result res => SOME (res, Result res) wenzelm@47341: | Expr e => wenzelm@52534: let val res = Exn.capture e (); (*sic!*) wenzelm@47342: in SOME (res, Result res) end)) wenzelm@47342: |> Exn.release; wenzelm@47342: wenzelm@52526: fun memo_fork params (Memo v) = wenzelm@52526: (case Synchronized.value v of wenzelm@52526: Result _ => () wenzelm@52526: | _ => ignore ((singleton o Future.forks) params (fn () => memo_eval (Memo v)))); wenzelm@52526: wenzelm@47342: fun memo_result (Memo v) = wenzelm@47342: (case Synchronized.value v of wenzelm@47342: Result res => Exn.release res wenzelm@47342: | _ => raise Fail "Unfinished memo result"); wenzelm@47341: wenzelm@52526: fun memo_stable (Memo v) = wenzelm@52526: (case Synchronized.value v of wenzelm@52526: Expr _ => true wenzelm@52526: | Result res => not (Exn.is_interrupt_exn res)); wenzelm@52526: wenzelm@47341: end; wenzelm@47341: wenzelm@47341: wenzelm@52534: wenzelm@52536: (** main phases of execution **) wenzelm@52536: wenzelm@52536: (* basic type definitions *) wenzelm@52534: wenzelm@52534: type eval_state = wenzelm@52534: {failed: bool, malformed: bool, command: Toplevel.transition, state: Toplevel.state}; wenzelm@52536: val init_eval_state = wenzelm@52536: {failed = false, malformed = false, command = Toplevel.empty, state = Toplevel.toplevel}; wenzelm@52536: wenzelm@52534: type eval_process = eval_state memo; wenzelm@52534: type eval = {exec_id: Document_ID.exec, eval_process: eval_process}; wenzelm@52534: wenzelm@52536: fun eval_result ({eval_process, ...}: eval) = memo_result eval_process; wenzelm@52536: val eval_result_state = #state o eval_result; wenzelm@52536: wenzelm@52534: type print_process = unit memo; wenzelm@52534: type print = {name: string, pri: int, exec_id: Document_ID.exec, print_process: print_process}; wenzelm@52534: wenzelm@52536: type exec = eval * print list; wenzelm@52536: val no_exec: exec = ({exec_id = Document_ID.none, eval_process = memo_value init_eval_state}, []); wenzelm@52536: wenzelm@52536: fun exec_ids (({exec_id, ...}, prints): exec) = exec_id :: map #exec_id prints; wenzelm@52536: wenzelm@52532: wenzelm@52510: (* read *) wenzelm@52509: wenzelm@52534: fun read init span = wenzelm@52510: let wenzelm@52510: val outer_syntax = #2 (Outer_Syntax.get_syntax ()); wenzelm@52510: val command_reports = Outer_Syntax.command_reports outer_syntax; wenzelm@52509: wenzelm@52534: val proper_range = wenzelm@52534: Position.set_range (Token.position_range_of (#1 (take_suffix Token.is_improper span))); wenzelm@52510: val pos = wenzelm@52510: (case find_first Token.is_command span of wenzelm@52510: SOME tok => Token.position_of tok wenzelm@52510: | NONE => proper_range); wenzelm@52509: wenzelm@52510: val (is_malformed, token_reports) = Thy_Syntax.reports_of_tokens span; wenzelm@52510: val _ = Position.reports_text (token_reports @ maps command_reports span); wenzelm@52510: in wenzelm@52510: if is_malformed then Toplevel.malformed pos "Malformed command syntax" wenzelm@52510: else wenzelm@52510: (case Outer_Syntax.read_spans outer_syntax span of wenzelm@52510: [tr] => wenzelm@52510: if Keyword.is_control (Toplevel.name_of tr) then wenzelm@52510: Toplevel.malformed pos "Illegal control command" wenzelm@52534: else Toplevel.modify_init init tr wenzelm@52534: | [] => Toplevel.ignored (Position.set_range (Token.position_range_of span)) wenzelm@52510: | _ => Toplevel.malformed proper_range "Exactly one command expected") wenzelm@52510: handle ERROR msg => Toplevel.malformed proper_range msg wenzelm@52510: end; wenzelm@52509: wenzelm@52509: wenzelm@52509: (* eval *) wenzelm@47336: wenzelm@47336: local wenzelm@47336: wenzelm@47336: fun run int tr st = wenzelm@51284: if Goal.future_enabled () andalso Keyword.is_diag (Toplevel.name_of tr) then wenzelm@51605: (Goal.fork_params {name = "Toplevel.diag", pos = Toplevel.pos_of tr, pri = ~1} wenzelm@51605: (fn () => Toplevel.command_exception int tr st); ([], SOME st)) wenzelm@51284: else Toplevel.command_errors int tr st; wenzelm@47336: wenzelm@52510: fun check_cmts span tr st' = wenzelm@52510: Toplevel.setmp_thread_position tr wenzelm@52510: (fn () => wenzelm@52510: Outer_Syntax.side_comments span |> maps (fn cmt => wenzelm@52510: (Thy_Output.check_text (Token.source_position_of cmt) st'; []) wenzelm@52510: handle exn => ML_Compiler.exn_messages_ids exn)) (); wenzelm@52510: wenzelm@47336: fun proof_status tr st = wenzelm@47336: (case try Toplevel.proof_of st of wenzelm@47336: SOME prf => Toplevel.status tr (Proof.status_markup prf) wenzelm@47336: | NONE => ()); wenzelm@47336: wenzelm@52534: fun eval_state span tr ({malformed, state = st, ...}: eval_state) = wenzelm@52509: if malformed then wenzelm@52526: {failed = true, malformed = malformed, command = tr, state = Toplevel.toplevel} wenzelm@48772: else wenzelm@48772: let wenzelm@48772: val malformed' = Toplevel.is_malformed tr; wenzelm@48772: val is_init = Toplevel.is_init tr; wenzelm@48772: val is_proof = Keyword.is_proof (Toplevel.name_of tr); wenzelm@47336: wenzelm@48772: val _ = Multithreading.interrupted (); wenzelm@50201: val _ = Toplevel.status tr Markup.running; wenzelm@48918: val (errs1, result) = run (is_init orelse is_proof) (Toplevel.set_print false tr) st; wenzelm@52509: val errs2 = (case result of NONE => [] | SOME st' => check_cmts span tr st'); wenzelm@48918: val errs = errs1 @ errs2; wenzelm@50201: val _ = Toplevel.status tr Markup.finished; wenzelm@50914: val _ = List.app (Future.error_msg (Toplevel.pos_of tr)) errs; wenzelm@48772: in wenzelm@48772: (case result of wenzelm@48772: NONE => wenzelm@48772: let wenzelm@48772: val _ = if null errs then Exn.interrupt () else (); wenzelm@50201: val _ = Toplevel.status tr Markup.failed; wenzelm@52526: in {failed = true, malformed = malformed', command = tr, state = st} end wenzelm@48772: | SOME st' => wenzelm@48772: let wenzelm@48772: val _ = proof_status tr st'; wenzelm@52526: in {failed = false, malformed = malformed', command = tr, state = st'} end) wenzelm@48772: end; wenzelm@47336: wenzelm@52534: in wenzelm@52534: wenzelm@52534: fun eval init span eval0 = wenzelm@52534: let wenzelm@52534: val exec_id = Document_ID.make (); wenzelm@52534: fun process () = wenzelm@52534: let wenzelm@52534: val tr = wenzelm@52534: Position.setmp_thread_data (Position.id_only (Document_ID.print exec_id)) wenzelm@52536: (fn () => read init span |> Toplevel.exec_id exec_id) (); wenzelm@52534: in eval_state span tr (eval_result eval0) end; wenzelm@52534: in {exec_id = exec_id, eval_process = memo process} end; wenzelm@52534: wenzelm@47336: end; wenzelm@47336: wenzelm@52509: wenzelm@52509: (* print *) wenzelm@52509: wenzelm@52526: type print_fn = Toplevel.transition -> Toplevel.state -> unit; wenzelm@52515: wenzelm@52511: local wenzelm@52511: wenzelm@52526: type print_function = string * (int * (string -> print_fn option)); wenzelm@52526: val print_functions = Synchronized.var "Command.print_functions" ([]: print_function list); wenzelm@52511: wenzelm@52516: fun output_error tr exn = wenzelm@52516: List.app (Future.error_msg (Toplevel.pos_of tr)) (ML_Compiler.exn_messages_ids exn); wenzelm@52516: wenzelm@52516: fun print_error tr f x = wenzelm@52516: (Toplevel.setmp_thread_position tr o Runtime.controlled_execution) f x wenzelm@52516: handle exn => output_error tr exn; wenzelm@52516: wenzelm@52511: in wenzelm@52509: wenzelm@52530: fun print command_name eval = wenzelm@52526: rev (Synchronized.value print_functions) |> map_filter (fn (name, (pri, get_print_fn)) => wenzelm@52526: (case Exn.capture (Runtime.controlled_execution get_print_fn) command_name of wenzelm@52516: Exn.Res NONE => NONE wenzelm@52526: | Exn.Res (SOME print_fn) => wenzelm@52527: let wenzelm@52530: val exec_id = Document_ID.make (); wenzelm@52534: fun process () = wenzelm@52527: let wenzelm@52533: val {failed, command, state = st', ...} = eval_result eval; wenzelm@52536: val tr = Toplevel.exec_id exec_id command; wenzelm@52527: in if failed then () else print_error tr (fn () => print_fn tr st') () end; wenzelm@52534: in SOME {name = name, pri = pri, exec_id = exec_id, print_process = memo process} end wenzelm@52526: | Exn.Exn exn => wenzelm@52527: let wenzelm@52530: val exec_id = Document_ID.make (); wenzelm@52534: fun process () = wenzelm@52527: let wenzelm@52533: val {command, ...} = eval_result eval; wenzelm@52536: val tr = Toplevel.exec_id exec_id command; wenzelm@52527: in output_error tr exn end; wenzelm@52534: in SOME {name = name, pri = pri, exec_id = exec_id, print_process = memo process} end)); wenzelm@52511: wenzelm@52526: fun print_function {name, pri} f = wenzelm@52511: Synchronized.change print_functions (fn funs => wenzelm@52511: (if not (AList.defined (op =) funs name) then () wenzelm@52511: else warning ("Redefining command print function: " ^ quote name); wenzelm@52515: AList.update (op =) (name, (pri, f)) funs)); wenzelm@52511: wenzelm@52511: end; wenzelm@52511: wenzelm@52526: val _ = wenzelm@52526: print_function {name = "print_state", pri = 0} (fn command_name => SOME (fn tr => fn st' => wenzelm@52526: let wenzelm@52526: val is_init = Keyword.is_theory_begin command_name; wenzelm@52526: val is_proof = Keyword.is_proof command_name; wenzelm@52526: val do_print = wenzelm@52526: not is_init andalso wenzelm@52526: (Toplevel.print_of tr orelse (is_proof andalso Toplevel.is_proof st')); wenzelm@52526: in if do_print then Toplevel.print_state false st' else () end)); wenzelm@52509: wenzelm@52532: wenzelm@52536: (* overall execution process *) wenzelm@52532: wenzelm@52536: fun execute (({eval_process, ...}, prints): exec) = wenzelm@52534: (memo_eval eval_process; wenzelm@52534: prints |> List.app (fn {name, pri, print_process, ...} => wenzelm@52534: memo_fork {name = name, group = NONE, deps = [], pri = pri, interrupts = true} print_process)); wenzelm@52532: wenzelm@52532: fun stable_goals exec_id = wenzelm@52532: not (Par_Exn.is_interrupted (Future.join_results (Goal.peek_futures exec_id))); wenzelm@52532: wenzelm@52534: fun stable_eval ({exec_id, eval_process}: eval) = wenzelm@52534: stable_goals exec_id andalso memo_stable eval_process; wenzelm@52532: wenzelm@52534: fun stable_print ({exec_id, print_process, ...}: print) = wenzelm@52534: stable_goals exec_id andalso memo_stable print_process; wenzelm@52532: wenzelm@47336: end; wenzelm@47336: