src/Pure/PIDE/command.ML
author wenzelm
Fri Jul 05 16:22:28 2013 +0200 (2013-07-05 ago)
changeset 52532 c81d76f7f63d
parent 52530 99dd8b4ef3fe
child 52533 a95440dcd59c
permissions -rw-r--r--
tuned signature;
     1 (*  Title:      Pure/PIDE/command.ML
     2     Author:     Makarius
     3 
     4 Prover command execution.
     5 *)
     6 
     7 signature COMMAND =
     8 sig
     9   type span = Token.T list
    10   val range: span -> Position.range
    11   val proper_range: span -> Position.range
    12   type 'a memo
    13   val memo: (unit -> 'a) -> 'a memo
    14   val memo_value: 'a -> 'a memo
    15   val memo_eval: 'a memo -> 'a
    16   val memo_fork: Future.params -> 'a memo -> unit
    17   val memo_result: 'a memo -> 'a
    18   val memo_stable: 'a memo -> bool
    19   val read: span -> Toplevel.transition
    20   type eval_state =
    21     {failed: bool, malformed: bool, command: Toplevel.transition, state: Toplevel.state}
    22   type eval = eval_state memo
    23   val no_eval: eval
    24   val eval: span -> Toplevel.transition -> eval_state -> eval_state
    25   type print_fn = Toplevel.transition -> Toplevel.state -> unit
    26   type print = {name: string, pri: int, exec_id: Document_ID.exec, print: unit memo}
    27   val print: string -> eval -> print list
    28   val print_function: {name: string, pri: int} -> (string -> print_fn option) -> unit
    29   type exec = Document_ID.exec * (eval * print list)
    30   val no_exec: exec
    31   val exec_ids: exec -> Document_ID.exec list
    32   val exec_result: exec -> eval_state
    33   val exec_run: exec -> unit
    34   val stable_eval: exec -> bool
    35   val stable_print: print -> bool
    36 end;
    37 
    38 structure Command: COMMAND =
    39 struct
    40 
    41 (* source *)
    42 
    43 type span = Token.T list;
    44 
    45 val range = Token.position_range_of;
    46 val proper_range = Token.position_range_of o #1 o take_suffix Token.is_improper;
    47 
    48 
    49 (* memo results *)
    50 
    51 datatype 'a expr =
    52   Expr of unit -> 'a |
    53   Result of 'a Exn.result;
    54 
    55 abstype 'a memo = Memo of 'a expr Synchronized.var
    56 with
    57 
    58 fun memo e = Memo (Synchronized.var "Command.memo" (Expr e));
    59 fun memo_value a = Memo (Synchronized.var "Command.memo" (Result (Exn.Res a)));
    60 
    61 fun memo_eval (Memo v) =
    62   (case Synchronized.value v of
    63     Result res => res
    64   | _ =>
    65       Synchronized.guarded_access v
    66         (fn Result res => SOME (res, Result res)
    67           | Expr e =>
    68               let val res = Exn.capture e ();  (*memoing of physical interrupts!*)
    69               in SOME (res, Result res) end))
    70   |> Exn.release;
    71 
    72 fun memo_fork params (Memo v) =
    73   (case Synchronized.value v of
    74     Result _ => ()
    75   | _ => ignore ((singleton o Future.forks) params (fn () => memo_eval (Memo v))));
    76 
    77 fun memo_result (Memo v) =
    78   (case Synchronized.value v of
    79     Result res => Exn.release res
    80   | _ => raise Fail "Unfinished memo result");
    81 
    82 fun memo_stable (Memo v) =
    83   (case Synchronized.value v of
    84     Expr _ => true
    85   | Result res => not (Exn.is_interrupt_exn res));
    86 
    87 end;
    88 
    89 
    90 (** main phases: read -- eval -- print **)
    91 
    92 (* read *)
    93 
    94 fun read span =
    95   let
    96     val outer_syntax = #2 (Outer_Syntax.get_syntax ());
    97     val command_reports = Outer_Syntax.command_reports outer_syntax;
    98 
    99     val proper_range = Position.set_range (proper_range span);
   100     val pos =
   101       (case find_first Token.is_command span of
   102         SOME tok => Token.position_of tok
   103       | NONE => proper_range);
   104 
   105     val (is_malformed, token_reports) = Thy_Syntax.reports_of_tokens span;
   106     val _ = Position.reports_text (token_reports @ maps command_reports span);
   107   in
   108     if is_malformed then Toplevel.malformed pos "Malformed command syntax"
   109     else
   110       (case Outer_Syntax.read_spans outer_syntax span of
   111         [tr] =>
   112           if Keyword.is_control (Toplevel.name_of tr) then
   113             Toplevel.malformed pos "Illegal control command"
   114           else tr
   115       | [] => Toplevel.ignored (Position.set_range (range span))
   116       | _ => Toplevel.malformed proper_range "Exactly one command expected")
   117       handle ERROR msg => Toplevel.malformed proper_range msg
   118   end;
   119 
   120 
   121 (* eval *)
   122 
   123 type eval_state =
   124   {failed: bool, malformed: bool, command: Toplevel.transition, state: Toplevel.state};
   125 val no_eval_state: eval_state =
   126   {failed = false, malformed = false, command = Toplevel.empty, state = Toplevel.toplevel};
   127 
   128 type eval = eval_state memo;
   129 val no_eval = memo_value no_eval_state;
   130 
   131 local
   132 
   133 fun run int tr st =
   134   if Goal.future_enabled () andalso Keyword.is_diag (Toplevel.name_of tr) then
   135     (Goal.fork_params {name = "Toplevel.diag", pos = Toplevel.pos_of tr, pri = ~1}
   136       (fn () => Toplevel.command_exception int tr st); ([], SOME st))
   137   else Toplevel.command_errors int tr st;
   138 
   139 fun check_cmts span tr st' =
   140   Toplevel.setmp_thread_position tr
   141     (fn () =>
   142       Outer_Syntax.side_comments span |> maps (fn cmt =>
   143         (Thy_Output.check_text (Token.source_position_of cmt) st'; [])
   144           handle exn => ML_Compiler.exn_messages_ids exn)) ();
   145 
   146 fun proof_status tr st =
   147   (case try Toplevel.proof_of st of
   148     SOME prf => Toplevel.status tr (Proof.status_markup prf)
   149   | NONE => ());
   150 
   151 in
   152 
   153 fun eval span tr ({malformed, state = st, ...}: eval_state) =
   154   if malformed then
   155     {failed = true, malformed = malformed, command = tr, state = Toplevel.toplevel}
   156   else
   157     let
   158       val malformed' = Toplevel.is_malformed tr;
   159       val is_init = Toplevel.is_init tr;
   160       val is_proof = Keyword.is_proof (Toplevel.name_of tr);
   161 
   162       val _ = Multithreading.interrupted ();
   163       val _ = Toplevel.status tr Markup.running;
   164       val (errs1, result) = run (is_init orelse is_proof) (Toplevel.set_print false tr) st;
   165       val errs2 = (case result of NONE => [] | SOME st' => check_cmts span tr st');
   166       val errs = errs1 @ errs2;
   167       val _ = Toplevel.status tr Markup.finished;
   168       val _ = List.app (Future.error_msg (Toplevel.pos_of tr)) errs;
   169     in
   170       (case result of
   171         NONE =>
   172           let
   173             val _ = if null errs then Exn.interrupt () else ();
   174             val _ = Toplevel.status tr Markup.failed;
   175           in {failed = true, malformed = malformed', command = tr, state = st} end
   176       | SOME st' =>
   177           let
   178             val _ = proof_status tr st';
   179           in {failed = false, malformed = malformed', command = tr, state = st'} end)
   180     end;
   181 
   182 end;
   183 
   184 
   185 (* print *)
   186 
   187 type print = {name: string, pri: int, exec_id: Document_ID.exec, print: unit memo};
   188 type print_fn = Toplevel.transition -> Toplevel.state -> unit;
   189 
   190 local
   191 
   192 type print_function = string * (int * (string -> print_fn option));
   193 val print_functions = Synchronized.var "Command.print_functions" ([]: print_function list);
   194 
   195 fun output_error tr exn =
   196   List.app (Future.error_msg (Toplevel.pos_of tr)) (ML_Compiler.exn_messages_ids exn);
   197 
   198 fun print_error tr f x =
   199   (Toplevel.setmp_thread_position tr o Runtime.controlled_execution) f x
   200     handle exn => output_error tr exn;
   201 
   202 in
   203 
   204 fun print command_name eval =
   205   rev (Synchronized.value print_functions) |> map_filter (fn (name, (pri, get_print_fn)) =>
   206     (case Exn.capture (Runtime.controlled_execution get_print_fn) command_name of
   207       Exn.Res NONE => NONE
   208     | Exn.Res (SOME print_fn) =>
   209         let
   210           val exec_id = Document_ID.make ();
   211           fun body () =
   212             let
   213               val {failed, command, state = st', ...} = memo_result eval;
   214               val tr = Toplevel.put_id exec_id command;
   215             in if failed then () else print_error tr (fn () => print_fn tr st') () end;
   216         in SOME {name = name, pri = pri, exec_id = exec_id, print = memo body} end
   217     | Exn.Exn exn =>
   218         let
   219           val exec_id = Document_ID.make ();
   220           fun body () =
   221             let
   222               val {command, ...} = memo_result eval;
   223               val tr = Toplevel.put_id exec_id command;
   224             in output_error tr exn end;
   225         in SOME {name = name, pri = pri, exec_id = exec_id, print = memo body} end));
   226 
   227 fun print_function {name, pri} f =
   228   Synchronized.change print_functions (fn funs =>
   229    (if not (AList.defined (op =) funs name) then ()
   230     else warning ("Redefining command print function: " ^ quote name);
   231     AList.update (op =) (name, (pri, f)) funs));
   232 
   233 end;
   234 
   235 val _ =
   236   print_function {name = "print_state", pri = 0} (fn command_name => SOME (fn tr => fn st' =>
   237     let
   238       val is_init = Keyword.is_theory_begin command_name;
   239       val is_proof = Keyword.is_proof command_name;
   240       val do_print =
   241         not is_init andalso
   242           (Toplevel.print_of tr orelse (is_proof andalso Toplevel.is_proof st'));
   243     in if do_print then Toplevel.print_state false st' else () end));
   244 
   245 
   246 
   247 (** managed evaluation with potential interrupts **)
   248 
   249 (* execution *)
   250 
   251 type exec = Document_ID.exec * (eval * print list);
   252 val no_exec: exec = (Document_ID.none, (no_eval, []));
   253 
   254 fun exec_ids ((exec_id, (_, prints)): exec) = exec_id :: map #exec_id prints;
   255 
   256 fun exec_result ((_, (eval, _)): exec) = memo_result eval;
   257 
   258 fun exec_run ((_, (eval, prints)): exec) =
   259  (memo_eval eval;
   260   prints |> List.app (fn {name, pri, print, ...} =>
   261     memo_fork {name = name, group = NONE, deps = [], pri = pri, interrupts = true} print));
   262 
   263 
   264 (* stable situations *)
   265 
   266 fun stable_goals exec_id =
   267   not (Par_Exn.is_interrupted (Future.join_results (Goal.peek_futures exec_id)));
   268 
   269 fun stable_eval ((exec_id, (eval, _)): exec) =
   270   stable_goals exec_id andalso memo_stable eval;
   271 
   272 fun stable_print ({exec_id, print, ...}: print) =
   273   stable_goals exec_id andalso memo_stable print;
   274 
   275 end;
   276