separate exec_id assignment for Command.print states, without affecting result of eval;
authorwenzelm
Thu, 04 Jul 2013 23:51:47 +0200
changeset 53664dbac84eab3bc
parent 53663 d234cb6b60e3
child 53665 b6a224676c04
separate exec_id assignment for Command.print states, without affecting result of eval;
tuned signature;
tuned;
src/Pure/Isar/toplevel.ML
src/Pure/PIDE/command.ML
src/Pure/PIDE/command.scala
src/Pure/PIDE/document.ML
src/Pure/PIDE/document.scala
src/Pure/PIDE/protocol.ML
src/Pure/PIDE/protocol.scala
src/Tools/jEdit/src/pretty_text_area.scala
     1.1 --- a/src/Pure/Isar/toplevel.ML	Thu Jul 04 16:04:53 2013 +0200
     1.2 +++ b/src/Pure/Isar/toplevel.ML	Thu Jul 04 23:51:47 2013 +0200
     1.3 @@ -81,8 +81,7 @@
     1.4    val actual_proof: (Proof_Node.T -> Proof_Node.T) -> transition -> transition
     1.5    val skip_proof: (int -> int) -> transition -> transition
     1.6    val skip_proof_to_theory: (int -> bool) -> transition -> transition
     1.7 -  val get_id: transition -> string option
     1.8 -  val put_id: string -> transition -> transition
     1.9 +  val put_id: int -> transition -> transition
    1.10    val unknown_theory: transition -> transition
    1.11    val unknown_proof: transition -> transition
    1.12    val unknown_context: transition -> transition
    1.13 @@ -584,13 +583,10 @@
    1.14  
    1.15  (** toplevel transactions **)
    1.16  
    1.17 -(* identification *)
    1.18 +(* runtime position *)
    1.19  
    1.20 -fun get_id (Transition {pos, ...}) = Position.get_id pos;
    1.21 -fun put_id id (tr as Transition {pos, ...}) = position (Position.put_id id pos) tr;
    1.22 -
    1.23 -
    1.24 -(* thread position *)
    1.25 +fun put_id id (tr as Transition {pos, ...}) =
    1.26 +  position (Position.put_id (Markup.print_int id) pos) tr;
    1.27  
    1.28  fun setmp_thread_position (Transition {pos, ...}) f x =
    1.29    Position.setmp_thread_data pos f x;
     2.1 --- a/src/Pure/PIDE/command.ML	Thu Jul 04 16:04:53 2013 +0200
     2.2 +++ b/src/Pure/PIDE/command.ML	Thu Jul 04 23:51:47 2013 +0200
     2.3 @@ -23,8 +23,8 @@
     2.4    val no_eval: eval
     2.5    val eval: span -> Toplevel.transition -> eval_state -> eval_state
     2.6    type print_fn = Toplevel.transition -> Toplevel.state -> unit
     2.7 -  type print = {name: string, pri: int, print: unit memo}
     2.8 -  val print: string -> eval -> print list
     2.9 +  type print = {name: string, pri: int, exec_id: int, print: unit memo}
    2.10 +  val print: (unit -> int) -> string -> eval -> print list
    2.11    val print_function: {name: string, pri: int} -> (string -> print_fn option) -> unit
    2.12  end;
    2.13  
    2.14 @@ -175,7 +175,7 @@
    2.15  
    2.16  (* print *)
    2.17  
    2.18 -type print = {name: string, pri: int, print: unit memo};
    2.19 +type print = {name: string, pri: int, exec_id: int, print: unit memo};
    2.20  type print_fn = Toplevel.transition -> Toplevel.state -> unit;
    2.21  
    2.22  local
    2.23 @@ -192,18 +192,28 @@
    2.24  
    2.25  in
    2.26  
    2.27 -fun print command_name eval =
    2.28 +fun print new_id command_name eval =
    2.29    rev (Synchronized.value print_functions) |> map_filter (fn (name, (pri, get_print_fn)) =>
    2.30      (case Exn.capture (Runtime.controlled_execution get_print_fn) command_name of
    2.31        Exn.Res NONE => NONE
    2.32      | Exn.Res (SOME print_fn) =>
    2.33 -        SOME {name = name, pri = pri,
    2.34 -          print = memo (fn () =>
    2.35 -            let val {failed, command = tr, state = st', ...} = memo_result eval
    2.36 -            in if failed then () else print_error tr (fn () => print_fn tr st') () end)}
    2.37 +        let
    2.38 +          val exec_id = new_id ();
    2.39 +          fun body () =
    2.40 +            let
    2.41 +              val {failed, command, state = st', ...} = memo_result eval;
    2.42 +              val tr = Toplevel.put_id exec_id command;
    2.43 +            in if failed then () else print_error tr (fn () => print_fn tr st') () end;
    2.44 +        in SOME {name = name, pri = pri, exec_id = exec_id, print = memo body} end
    2.45      | Exn.Exn exn =>
    2.46 -        SOME {name = name, pri = pri,
    2.47 -          print = memo (fn () => output_error (#command (memo_result eval)) exn)}));
    2.48 +        let
    2.49 +          val exec_id = new_id ();
    2.50 +          fun body () =
    2.51 +            let
    2.52 +              val {command, ...} = memo_result eval;
    2.53 +              val tr = Toplevel.put_id exec_id command;
    2.54 +            in output_error tr exn end;
    2.55 +        in SOME {name = name, pri = pri, exec_id = exec_id, print = memo body} end));
    2.56  
    2.57  fun print_function {name, pri} f =
    2.58    Synchronized.change print_functions (fn funs =>
     3.1 --- a/src/Pure/PIDE/command.scala	Thu Jul 04 16:04:53 2013 +0200
     3.2 +++ b/src/Pure/PIDE/command.scala	Thu Jul 04 23:51:47 2013 +0200
     3.3 @@ -75,7 +75,7 @@
     3.4      private def add_status(st: Markup): State = copy(status = st :: status)
     3.5      private def add_markup(m: Text.Markup): State = copy(markup = markup + m)
     3.6  
     3.7 -    def + (alt_id: Document.ID, message: XML.Elem): Command.State =
     3.8 +    def + (alt_id: Document.ID, message: XML.Elem): State =
     3.9        message match {
    3.10          case XML.Elem(Markup(Markup.STATUS, _), msgs) =>
    3.11            (this /: msgs)((state, msg) =>
    3.12 @@ -125,6 +125,9 @@
    3.13              case _ => System.err.println("Ignored message without serial number: " + message); this
    3.14            }
    3.15        }
    3.16 +
    3.17 +    def ++ (other: State): State =
    3.18 +      copy(results = results ++ other.results)  // FIXME merge more content!?
    3.19    }
    3.20  
    3.21  
    3.22 @@ -240,4 +243,6 @@
    3.23  
    3.24    val init_state: Command.State =
    3.25      Command.State(this, results = init_results, markup = init_markup)
    3.26 +
    3.27 +  val empty_state: Command.State = Command.State(this)
    3.28  }
     4.1 --- a/src/Pure/PIDE/document.ML	Thu Jul 04 16:04:53 2013 +0200
     4.2 +++ b/src/Pure/PIDE/document.ML	Thu Jul 04 23:51:47 2013 +0200
     4.3 @@ -31,7 +31,7 @@
     4.4    val start_execution: state -> unit
     4.5    val timing: bool Unsynchronized.ref
     4.6    val update: version_id -> version_id -> edit list -> state ->
     4.7 -    (command_id * exec_id option) list * state
     4.8 +    (command_id * exec_id list) list * state
     4.9    val state: unit -> state
    4.10    val change_state: (state -> state) -> unit
    4.11  end;
    4.12 @@ -61,11 +61,13 @@
    4.13  type exec = exec_id * (Command.eval * Command.print list);  (*eval/print process*)
    4.14  val no_exec: exec = (no_id, (Command.no_eval, []));
    4.15  
    4.16 +fun exec_ids_of ((exec_id, (_, prints)): exec) = exec_id :: map #exec_id prints;
    4.17 +
    4.18  fun exec_result ((_, (eval, _)): exec) = Command.memo_result eval;
    4.19  
    4.20  fun exec_run ((_, (eval, prints)): exec) =
    4.21   (Command.memo_eval eval;
    4.22 -  prints |> List.app (fn {name, pri, print} =>
    4.23 +  prints |> List.app (fn {name, pri, print, ...} =>
    4.24      Command.memo_fork {name = name, group = NONE, deps = [], pri = pri, interrupts = true} print));
    4.25  
    4.26  
    4.27 @@ -121,7 +123,6 @@
    4.28    map_node (fn (header, _, entries, result) => (header, make_perspective ids, entries, result));
    4.29  
    4.30  val visible_commands = #1 o get_perspective;
    4.31 -val visible_command = Inttab.defined o visible_commands;
    4.32  val visible_last = #2 o get_perspective;
    4.33  val visible_node = is_some o visible_last
    4.34  
    4.35 @@ -313,10 +314,14 @@
    4.36  
    4.37  (* consolidated states *)
    4.38  
    4.39 -fun stable_command ((exec_id, (eval, prints)): exec) =
    4.40 -  not (Par_Exn.is_interrupted (Future.join_results (Goal.peek_futures exec_id))) andalso
    4.41 -  Command.memo_stable eval andalso
    4.42 -  forall (Command.memo_stable o #print) prints;
    4.43 +fun stable_goals exec_id =
    4.44 +  not (Par_Exn.is_interrupted (Future.join_results (Goal.peek_futures exec_id)));
    4.45 +
    4.46 +fun stable_eval ((exec_id, (eval, _)): exec) =
    4.47 +  stable_goals exec_id andalso Command.memo_stable eval;
    4.48 +
    4.49 +fun stable_print ({exec_id, print, ...}: Command.print) =
    4.50 +  stable_goals exec_id andalso Command.memo_stable print;
    4.51  
    4.52  fun finished_theory node =
    4.53    (case Exn.capture (Command.memo_result o the) (get_result node) of
    4.54 @@ -422,7 +427,7 @@
    4.55              | SOME (exec_id, exec) =>
    4.56                  (case lookup_entry node0 id of
    4.57                    NONE => false
    4.58 -                | SOME (exec_id0, _) => exec_id = exec_id0 andalso stable_command (exec_id, exec)));
    4.59 +                | SOME (exec_id0, _) => exec_id = exec_id0 andalso stable_eval (exec_id, exec)));
    4.60          in SOME (same', (prev, flags')) end
    4.61        else NONE;
    4.62      val (same, (common, flags)) =
    4.63 @@ -438,11 +443,11 @@
    4.64    if not proper_init andalso is_none init then NONE
    4.65    else
    4.66      let
    4.67 -      val (name, span) = the_command state command_id' ||> Lazy.force;
    4.68 +      val (command_name, span) = the_command state command_id' ||> Lazy.force;
    4.69  
    4.70        fun illegal_init _ = error "Illegal theory header after end of theory";
    4.71        val (modify_init, init') =
    4.72 -        if Keyword.is_theory_begin name then
    4.73 +        if Keyword.is_theory_begin command_name then
    4.74            (Toplevel.modify_init (fn () => the_default illegal_init init span), NONE)
    4.75          else (I, init);
    4.76  
    4.77 @@ -456,13 +461,29 @@
    4.78                  (fn () =>
    4.79                    Command.read span
    4.80                    |> modify_init
    4.81 -                  |> Toplevel.put_id (print_id exec_id')) ();
    4.82 +                  |> Toplevel.put_id exec_id') ();
    4.83            in Command.eval span tr eval_state end);
    4.84 -      val prints' = if command_visible then Command.print name eval' else [];
    4.85 -
    4.86 +      val prints' = if command_visible then Command.print new_id command_name eval' else [];
    4.87        val command_exec' = (command_id', (exec_id', (eval', prints')));
    4.88      in SOME (command_exec' :: execs, command_exec', init') end;
    4.89  
    4.90 +fun update_prints state node command_id =
    4.91 +  (case the_entry node command_id of
    4.92 +    SOME (exec_id, (eval, prints)) =>
    4.93 +      let
    4.94 +        val (command_name, _) = the_command state command_id;
    4.95 +        val new_prints = Command.print new_id command_name eval;
    4.96 +        val prints' =
    4.97 +          new_prints |> map (fn new_print =>
    4.98 +            (case find_first (fn {name, ...} => name = #name new_print) prints of
    4.99 +              SOME print => if stable_print print then print else new_print
   4.100 +            | NONE => new_print));
   4.101 +      in
   4.102 +        if eq_list (op = o pairself #exec_id) (prints, prints') then NONE
   4.103 +        else SOME (command_id, (exec_id, (eval, prints')))
   4.104 +      end
   4.105 +  | NONE => NONE);
   4.106 +
   4.107  in
   4.108  
   4.109  fun update (old_id: version_id) (new_id: version_id) edits state =
   4.110 @@ -483,10 +504,10 @@
   4.111              (fn () =>
   4.112                let
   4.113                  val imports = map (apsnd Future.join) deps;
   4.114 -                val updated_imports = exists (is_some o #3 o #1 o #2) imports;
   4.115 +                val changed_imports = exists (#4 o #1 o #2) imports;
   4.116                  val node_required = is_required name;
   4.117                in
   4.118 -                if updated_imports orelse AList.defined (op =) edits name orelse
   4.119 +                if changed_imports orelse AList.defined (op =) edits name orelse
   4.120                    not (stable_entries node) orelse not (finished_theory node)
   4.121                  then
   4.122                    let
   4.123 @@ -496,9 +517,12 @@
   4.124                        check_theory false name node andalso
   4.125                        forall (fn (name, (_, node)) => check_theory true name node) imports;
   4.126  
   4.127 +                    val visible_commands = visible_commands node;
   4.128 +                    val visible_command = Inttab.defined visible_commands;
   4.129                      val last_visible = visible_last node;
   4.130 +
   4.131                      val (common, (still_visible, initial)) =
   4.132 -                      if updated_imports then (NONE, (true, true))
   4.133 +                      if changed_imports then (NONE, (true, true))
   4.134                        else last_common state last_visible node0 node;
   4.135                      val common_command_exec = the_default_entry node common;
   4.136  
   4.137 @@ -508,13 +532,18 @@
   4.138                          iterate_entries_after common
   4.139                            (fn ((prev, id), _) => fn res =>
   4.140                              if not node_required andalso prev = last_visible then NONE
   4.141 -                            else new_exec state proper_init (visible_command node id) id res) node;
   4.142 +                            else new_exec state proper_init (visible_command id) id res) node;
   4.143 +
   4.144 +                    val updated_execs =
   4.145 +                      (visible_commands, new_execs) |-> Inttab.fold (fn (id, ()) =>
   4.146 +                        if exists (fn (_, (id', _)) => id = id') new_execs then I
   4.147 +                        else append (the_list (update_prints state node id)));
   4.148  
   4.149                      val no_execs =
   4.150                        iterate_entries_after common
   4.151                          (fn ((_, id0), exec0) => fn res =>
   4.152                            if is_none exec0 then NONE
   4.153 -                          else if exists (fn (_, (id, _)) => id0 = id) new_execs
   4.154 +                          else if exists (fn (_, (id, _)) => id0 = id) updated_execs
   4.155                            then SOME res
   4.156                            else SOME (id0 :: res)) node0 [];
   4.157  
   4.158 @@ -525,20 +554,21 @@
   4.159  
   4.160                      val node' = node
   4.161                        |> fold reset_entry no_execs
   4.162 -                      |> fold (fn (id, exec) => update_entry id (SOME exec)) new_execs
   4.163 -                      |> entries_stable (null new_execs)
   4.164 +                      |> fold (fn (id, exec) => update_entry id (SOME exec)) updated_execs
   4.165 +                      |> entries_stable (null updated_execs)
   4.166                        |> set_result result;
   4.167                      val updated_node =
   4.168 -                      if null no_execs andalso null new_execs then NONE
   4.169 +                      if null no_execs andalso null updated_execs then NONE
   4.170                        else SOME (name, node');
   4.171 -                  in ((no_execs, new_execs, updated_node), node') end
   4.172 -                else (([], [], NONE), node)
   4.173 +                    val changed_result = not (null no_execs) orelse not (null new_execs);
   4.174 +                  in ((no_execs, updated_execs, updated_node, changed_result), node') end
   4.175 +                else (([], [], NONE, false), node)
   4.176                end))
   4.177        |> Future.joins |> map #1);
   4.178  
   4.179      val command_execs =
   4.180 -      map (rpair NONE) (maps #1 updated) @
   4.181 -      map (fn (command_id, (exec_id, _)) => (command_id, SOME exec_id)) (maps #2 updated);
   4.182 +      map (rpair []) (maps #1 updated) @
   4.183 +      map (fn (command_id, exec) => (command_id, exec_ids_of exec)) (maps #2 updated);
   4.184      val updated_nodes = map_filter #3 updated;
   4.185  
   4.186      val state' = state
     5.1 --- a/src/Pure/PIDE/document.scala	Thu Jul 04 16:04:53 2013 +0200
     5.2 +++ b/src/Pure/PIDE/document.scala	Thu Jul 04 23:51:47 2013 +0200
     5.3 @@ -289,7 +289,7 @@
     5.4        result: Command.State => PartialFunction[Text.Markup, A]): Stream[Text.Info[A]]
     5.5    }
     5.6  
     5.7 -  type Assign = List[(Document.Command_ID, Option[Document.Exec_ID])]  // exec state assignment
     5.8 +  type Assign = List[(Document.Command_ID, List[Document.Exec_ID])]  // exec state assignment
     5.9  
    5.10    object State
    5.11    {
    5.12 @@ -301,19 +301,19 @@
    5.13      }
    5.14  
    5.15      final class Assignment private(
    5.16 -      val command_execs: Map[Command_ID, Exec_ID] = Map.empty,
    5.17 +      val command_execs: Map[Command_ID, List[Exec_ID]] = Map.empty,
    5.18        val is_finished: Boolean = false)
    5.19      {
    5.20        def check_finished: Assignment = { require(is_finished); this }
    5.21        def unfinished: Assignment = new Assignment(command_execs, false)
    5.22  
    5.23 -      def assign(add_command_execs: List[(Command_ID, Option[Exec_ID])]): Assignment =
    5.24 +      def assign(add_command_execs: List[(Command_ID, List[Exec_ID])]): Assignment =
    5.25        {
    5.26          require(!is_finished)
    5.27          val command_execs1 =
    5.28            (command_execs /: add_command_execs) {
    5.29 -            case (res, (command_id, None)) => res - command_id
    5.30 -            case (res, (command_id, Some(exec_id))) => res + (command_id -> exec_id)
    5.31 +            case (res, (command_id, Nil)) => res - command_id
    5.32 +            case (res, assign) => res + assign
    5.33            }
    5.34          new Assignment(command_execs1, true)
    5.35        }
    5.36 @@ -357,8 +357,8 @@
    5.37        }
    5.38  
    5.39      def the_version(id: Version_ID): Version = versions.getOrElse(id, fail)
    5.40 -    def the_command_state(id: Command_ID): Command.State = commands.getOrElse(id, fail)
    5.41 -    def the_exec(id: Exec_ID): Command.State = execs.getOrElse(id, fail)
    5.42 +    def the_read_state(id: Command_ID): Command.State = commands.getOrElse(id, fail)
    5.43 +    def the_exec_state(id: Exec_ID): Command.State = execs.getOrElse(id, fail)
    5.44      def the_assignment(version: Version): State.Assignment =
    5.45        assignments.getOrElse(version.id, fail)
    5.46  
    5.47 @@ -383,12 +383,17 @@
    5.48        val (changed_commands, new_execs) =
    5.49          ((Nil: List[Command], execs) /: command_execs) {
    5.50            case ((commands1, execs1), (cmd_id, exec)) =>
    5.51 -            val st = the_command_state(cmd_id)
    5.52 -            val commands2 = st.command :: commands1
    5.53 +            val st1 = the_read_state(cmd_id)
    5.54 +            val command = st1.command
    5.55 +            val st0 = command.empty_state
    5.56 +
    5.57 +            val commands2 = command :: commands1
    5.58              val execs2 =
    5.59                exec match {
    5.60 -                case None => execs1
    5.61 -                case Some(exec_id) => execs1 + (exec_id -> st)
    5.62 +                case Nil => execs1
    5.63 +                case eval_id :: print_ids =>
    5.64 +                  execs1 + (eval_id -> execs.getOrElse(eval_id, st1)) ++
    5.65 +                    print_ids.iterator.map(id => id -> execs.getOrElse(id, st0))
    5.66                }
    5.67              (commands2, execs2)
    5.68          }
    5.69 @@ -445,12 +450,11 @@
    5.70          command <- node.commands.iterator
    5.71        } {
    5.72          val id = command.id
    5.73 -        if (!commands1.isDefinedAt(id) && commands.isDefinedAt(id))
    5.74 -          commands1 += (id -> commands(id))
    5.75 -        if (command_execs.isDefinedAt(id)) {
    5.76 -          val exec_id = command_execs(id)
    5.77 -          if (!execs1.isDefinedAt(exec_id) && execs.isDefinedAt(exec_id))
    5.78 -            execs1 += (exec_id -> execs(exec_id))
    5.79 +        if (!commands1.isDefinedAt(id))
    5.80 +          commands.get(id).foreach(st => commands1 += (id -> st))
    5.81 +        for (exec_id <- command_execs.getOrElse(id, Nil)) {
    5.82 +          if (!execs1.isDefinedAt(exec_id))
    5.83 +            execs.get(exec_id).foreach(st => execs1 += (exec_id -> st))
    5.84          }
    5.85        }
    5.86        copy(versions = versions1, commands = commands1, execs = execs1, assignments = assignments1)
    5.87 @@ -460,12 +464,15 @@
    5.88      {
    5.89        require(is_assigned(version))
    5.90        try {
    5.91 -        the_exec(the_assignment(version).check_finished.command_execs
    5.92 -          .getOrElse(command.id, fail))
    5.93 +        the_assignment(version).check_finished.command_execs.getOrElse(command.id, Nil)
    5.94 +          .map(the_exec_state(_)) match {
    5.95 +            case eval_state :: print_states => (eval_state /: print_states)(_ ++ _)
    5.96 +            case Nil => fail
    5.97 +          }
    5.98        }
    5.99        catch {
   5.100          case _: State.Fail =>
   5.101 -          try { the_command_state(command.id) }
   5.102 +          try { the_read_state(command.id) }
   5.103            catch { case _: State.Fail => command.init_state }
   5.104        }
   5.105      }
     6.1 --- a/src/Pure/PIDE/protocol.ML	Thu Jul 04 16:04:53 2013 +0200
     6.2 +++ b/src/Pure/PIDE/protocol.ML	Thu Jul 04 23:51:47 2013 +0200
     6.3 @@ -53,7 +53,7 @@
     6.4            Output.protocol_message Markup.assign_execs
     6.5              ((new_id, assignment) |>
     6.6                let open XML.Encode
     6.7 -              in pair int (list (pair int (option int))) end
     6.8 +              in pair int (list (pair int (list int))) end
     6.9                |> YXML.string_of_body);
    6.10  
    6.11          val _ = List.app Future.cancel_group (Goal.reset_futures ());
     7.1 --- a/src/Pure/PIDE/protocol.scala	Thu Jul 04 16:04:53 2013 +0200
     7.2 +++ b/src/Pure/PIDE/protocol.scala	Thu Jul 04 23:51:47 2013 +0200
     7.3 @@ -17,7 +17,7 @@
     7.4        try {
     7.5          import XML.Decode._
     7.6          val body = YXML.parse_body(text)
     7.7 -        Some(pair(long, list(pair(long, option(long))))(body))
     7.8 +        Some(pair(long, list(pair(long, list(long))))(body))
     7.9        }
    7.10        catch {
    7.11          case ERROR(_) => None
     8.1 --- a/src/Tools/jEdit/src/pretty_text_area.scala	Thu Jul 04 16:04:53 2013 +0200
     8.2 +++ b/src/Tools/jEdit/src/pretty_text_area.scala	Thu Jul 04 23:51:47 2013 +0200
     8.3 @@ -38,7 +38,7 @@
     8.4      val state1 =
     8.5        state0.continue_history(Future.value(version0), edits, Future.value(version1))._2
     8.6          .define_version(version1, state0.the_assignment(version0))
     8.7 -        .assign(version1.id, List(command.id -> Some(Document.new_id())))._2
     8.8 +        .assign(version1.id, List(command.id -> List(Document.new_id())))._2
     8.9  
    8.10      (command.source, state1)
    8.11    }