src/Pure/Isar/isar_document.ML
changeset 29484 15863d782ae3
parent 29468 c9bb4e06d173
child 29487 06f4bb9fdb85
equal deleted inserted replaced
29483:e959ae4a0bca 29484:15863d782ae3
    16 end;
    16 end;
    17 
    17 
    18 structure IsarDocument: ISAR_DOCUMENT =
    18 structure IsarDocument: ISAR_DOCUMENT =
    19 struct
    19 struct
    20 
    20 
    21 
       
    22 (* unique identifiers *)
    21 (* unique identifiers *)
    23 
    22 
       
    23 type state_id = string;
       
    24 type command_id = string;
    24 type document_id = string;
    25 type document_id = string;
    25 type command_id = string;
       
    26 type state_id = string;
       
    27 
    26 
    28 fun new_id () = "isabelle:" ^ serial_string ();
    27 fun new_id () = "isabelle:" ^ serial_string ();
    29 
    28 
    30 fun err_dup kind id = error ("Duplicate " ^ kind ^ ": " ^ quote id);
    29 fun err_dup kind id = error ("Duplicate " ^ kind ^ ": " ^ quote id);
    31 fun err_undef kind id = error ("Unknown " ^ kind ^ ": " ^ quote id);
    30 fun err_undef kind id = error ("Unknown " ^ kind ^ ": " ^ quote id);
    32 
    31 
    33 
    32 
    34 (** execution states **)
       
    35 
       
    36 (* command status *)
       
    37 
       
    38 datatype status =
       
    39   Unprocessed |
       
    40   Running of Toplevel.state option future |
       
    41   Failed |
       
    42   Finished of Toplevel.state;
       
    43 
       
    44 fun markup_status Unprocessed = Markup.unprocessed
       
    45   | markup_status (Running future) = Markup.running (Task_Queue.str_of_task (Future.task_of future))
       
    46   | markup_status Failed = Markup.failed
       
    47   | markup_status (Finished _) = Markup.finished;
       
    48 
       
    49 fun update_status retry tr state status =
       
    50   (case status of
       
    51     Unprocessed => SOME (Running (Future.fork_pri 1 (fn () =>
       
    52       (case Toplevel.transition true tr state of
       
    53         NONE => (Toplevel.error_msg tr (ERROR "Cannot terminate here!", ""); NONE)
       
    54       | SOME (_, SOME err) => (Toplevel.error_msg tr err; NONE)
       
    55       | SOME (state', NONE) => SOME state'))))
       
    56   | Running future =>
       
    57       (case Future.peek future of
       
    58         NONE => NONE
       
    59       | SOME (Exn.Result NONE) => SOME Failed
       
    60       | SOME (Exn.Result (SOME state')) => SOME (Finished state')
       
    61       | SOME (Exn.Exn exn) => (Toplevel.error_msg tr (exn, ""); SOME Failed))
       
    62   | Failed => if retry then SOME Unprocessed else NONE
       
    63   | _ => NONE);
       
    64 
       
    65 
       
    66 (* state *)
       
    67 
       
    68 datatype state = State of
       
    69  {prev: state_id option,
       
    70   command: command_id,
       
    71   status: status};
       
    72 
       
    73 fun make_state prev command status = State {prev = prev, command = command, status = status};
       
    74 
       
    75 
       
    76 
    33 
    77 (** documents **)
    34 (** documents **)
    78 
    35 
    79 (* command entries *)
    36 (* command entries *)
    80 
    37 
    81 datatype entry = Entry of
    38 datatype entry = Entry of {next: command_id option, state: state_id option};
    82  {prev: command_id option,
    39 fun make_entry next state = Entry {next = next, state = state};
    83   next: command_id option,
       
    84   state: state_id option};
       
    85 
       
    86 fun make_entry prev next state = Entry {prev = prev, next = next, state = state};
       
    87 
    40 
    88 fun the_entry entries (id: command_id) =
    41 fun the_entry entries (id: command_id) =
    89   (case Symtab.lookup entries id of
    42   (case Symtab.lookup entries id of
    90     NONE => err_undef "document entry" id
    43     NONE => err_undef "document entry" id
    91   | SOME (Entry entry) => entry);
    44   | SOME (Entry entry) => entry);
    92 
    45 
    93 fun put_entry (id: command_id, entry: entry) = Symtab.update (id, entry);
    46 fun put_entry (id: command_id, entry: entry) = Symtab.update (id, entry);
    94 
       
    95 fun map_entry (id: command_id) f entries =
       
    96   let
       
    97     val {prev, next, state} = the_entry entries id;
       
    98     val (prev', next', state') = f (prev, next, state);
       
    99   in put_entry (id, make_entry prev' next' state') entries end;
       
   100 
    47 
   101 
    48 
   102 (* document *)
    49 (* document *)
   103 
    50 
   104 datatype document = Document of
    51 datatype document = Document of
   112 
    59 
   113 fun map_entries f (Document {dir, name, start, entries}) =
    60 fun map_entries f (Document {dir, name, start, entries}) =
   114   make_document dir name start (f entries);
    61   make_document dir name start (f entries);
   115 
    62 
   116 
    63 
   117 (* iterating entries *)
    64 (* iterate entries *)
   118 
    65 
   119 fun fold_entries opt_id f (Document {start, entries, ...}) =
    66 fun fold_entries opt_id f (Document {start, entries, ...}) =
   120   let
    67   let
   121     fun apply NONE x = x
    68     fun apply NONE x = x
   122       | apply (SOME id) x = apply (#next (the_entry entries id)) (f id x);
    69       | apply (SOME id) x = apply (#next (the_entry entries id)) (f id x);
   123   in if is_some opt_id then apply opt_id else apply (SOME start) end;
    70   in if is_some opt_id then apply opt_id else apply (SOME start) end;
   124 
    71 
   125 fun get_first_entries opt_id f (Document {start, entries, ...}) =
    72 fun find_entries P (Document {start, entries, ...}) =
   126   let
    73   let
   127     fun get NONE = NONE
    74     fun find _ NONE = NONE
   128       | get (SOME id) = (case f id of NONE => get (#next (the_entry entries id)) | some => some);
    75       | find prev (SOME id) =
   129   in if is_some opt_id then get opt_id else get (SOME start) end;
    76           if P id then SOME (prev, id)
   130 
    77           else find (SOME id) (#next (the_entry entries id));
   131 fun find_first_entries opt_id P =
    78   in find NONE (SOME start) end;
   132   get_first_entries opt_id (fn x => if P x then SOME x else NONE);
       
   133 
    79 
   134 
    80 
   135 (* modify entries *)
    81 (* modify entries *)
   136 
    82 
   137 fun insert_entry (id: command_id, id2: command_id) = map_entries (fn entries =>
    83 fun insert_after (id: command_id) (id2: command_id) = map_entries (fn entries =>
   138   let val {prev, next, state} = the_entry entries id in
    84   let val {next, state} = the_entry entries id in
   139     entries |>
    85     entries
   140       (case next of
    86     |> put_entry (id, make_entry (SOME id2) state)
   141         NONE => put_entry (id2, make_entry (SOME id) NONE NONE)
    87     |> put_entry (id2, make_entry next NONE)
   142       | SOME id3 =>
       
   143           put_entry (id, make_entry prev (SOME id2) state) #>
       
   144           put_entry (id2, make_entry (SOME id) (SOME id3) NONE) #>
       
   145           put_entry (id3, make_entry (SOME id2) (#next (the_entry entries id3)) NONE))
       
   146   end);
    88   end);
   147 
    89 
   148 fun delete_after (id: command_id) = map_entries (fn entries =>
    90 fun delete_after (id: command_id) = map_entries (fn entries =>
   149   let val {prev, next, state} = the_entry entries id in
    91   let val {next, state} = the_entry entries id in
   150     entries |>
    92     (case next of
   151       (case next of
    93       NONE => error ("No next entry to delete: " ^ quote id)
   152         NONE => error ("Missing next entry: " ^ quote id)
    94     | SOME id2 =>
   153       | SOME id2 =>
    95         entries |>
   154           (case #next (the_entry entries id2) of
    96           (case #next (the_entry entries id2) of
   155             NONE => put_entry (id, make_entry prev NONE state)
    97             NONE => put_entry (id, make_entry NONE state)
   156           | SOME id3 =>
    98           | SOME id3 =>
   157               put_entry (id, make_entry prev (SOME id3) state) #>
    99               put_entry (id, make_entry (SOME id3) state) #>
   158               put_entry (id3, make_entry (SOME id) (#next (the_entry entries id3)) NONE)))
   100               put_entry (id3, make_entry (#next (the_entry entries id3)) NONE)))
   159   end);
   101   end);
   160 
   102 
   161 
   103 
   162 
   104 
   163 (** global configuration **)
   105 (** global configuration **)
   164 
   106 
   165 local
   107 local
   166   val global_states = ref (Symtab.empty: state Symtab.table);
   108   val global_states = ref (Symtab.empty: Toplevel.state option future Symtab.table);
   167   val global_commands = ref (Symtab.empty: Toplevel.transition Symtab.table);
   109   val global_commands = ref (Symtab.empty: Toplevel.transition Symtab.table);
   168   val global_documents = ref (Symtab.empty: document Symtab.table);
   110   val global_documents = ref (Symtab.empty: document Symtab.table);
   169 in
   111 in
   170 
   112 
   171 fun change_states f = NAMED_CRITICAL "Isar" (fn () => change global_states f);
   113 fun change_states f = NAMED_CRITICAL "Isar" (fn () => change global_states f);
   190     handle Symtab.DUP dup => err_dup "state" dup;
   132     handle Symtab.DUP dup => err_dup "state" dup;
   191 
   133 
   192 fun the_state (id: state_id) =
   134 fun the_state (id: state_id) =
   193   (case Symtab.lookup (get_states ()) id of
   135   (case Symtab.lookup (get_states ()) id of
   194     NONE => err_undef "state" id
   136     NONE => err_undef "state" id
   195   | SOME (State state) => state);
   137   | SOME state => state);
   196 
   138 
   197 
   139 
   198 fun define_command id tr =
   140 fun define_command id tr =
   199   change_commands (Symtab.update_new (id, Toplevel.put_id id tr))
   141   change_commands (Symtab.update_new (id, Toplevel.put_id id tr))
   200     handle Symtab.DUP dup => err_dup ("command " ^ Toplevel.name_of tr) dup;
   142     handle Symtab.DUP dup => err_dup "command" dup;
   201 
   143 
   202 fun the_command (id: command_id) =
   144 fun the_command (id: command_id) =
   203   (case Symtab.lookup (get_commands ()) id of
   145   (case Symtab.lookup (get_commands ()) id of
   204     NONE => err_undef "command" id
   146     NONE => err_undef "command" id
   205   | SOME tr => tr);
   147   | SOME tr => tr);
   219 
   161 
   220 fun begin_document (id: document_id) path =
   162 fun begin_document (id: document_id) path =
   221   let
   163   let
   222     val (dir, name) = ThyLoad.split_thy_path path;
   164     val (dir, name) = ThyLoad.split_thy_path path;
   223     val _ = define_command id Toplevel.empty;
   165     val _ = define_command id Toplevel.empty;
   224     val _ = define_state id (make_state NONE id (Finished Toplevel.toplevel));
   166     val _ = define_state id (Future.value (SOME Toplevel.toplevel));
   225     val entries = Symtab.make [(id, make_entry NONE NONE (SOME id))];
   167     val entries = Symtab.make [(id, make_entry NONE (SOME id))];
   226     val _ = define_document id (make_document dir name id entries);
   168     val _ = define_document id (make_document dir name id entries);
   227   in () end;
   169   in () end;
   228 
   170 
   229 fun end_document (id: document_id) = error "FIXME";
   171 fun end_document (id: document_id) = error "FIXME";
   230 
   172 
   231 
   173 
   232 (* document editing *)
   174 (* document editing *)
   233 
   175 
   234 fun refresh_states old_document new_document =
   176 fun update_state tr state = Future.fork_deps [state] (fn () =>
       
   177   (case Future.join state of NONE => NONE | SOME st => Toplevel.run_command tr st));
       
   178 
       
   179 fun update_entry (id, state_id) entries =
       
   180   Symtab.map_entry
       
   181 
       
   182 fun update_states old_document new_document =
   235   let
   183   let
   236     val Document {entries = old_entries, ...} = old_document;
   184     val Document {entries = old_entries, ...} = old_document;
   237     val Document {entries = new_entries, ...} = new_document;
   185     val Document {entries = new_entries, ...} = new_document;
   238 
   186 
   239     fun is_changed id =
   187     fun is_changed id =
   241         SOME {state = SOME _, ...} => false
   189         SOME {state = SOME _, ...} => false
   242       | _ => true);
   190       | _ => true);
   243 
   191 
   244     fun cancel_state id () =
   192     fun cancel_state id () =
   245       (case the_entry old_entries id of
   193       (case the_entry old_entries id of
   246         {state = SOME state_id, ...} =>
   194         {state = SOME state_id, ...} => Future.cancel (the_state state_id)
   247           (case the_state state_id of
       
   248             {status = Running future, ...} => Future.cancel future
       
   249           | _ => ())
       
   250       | _ => ());
   195       | _ => ());
   251 
   196 
   252     fun new_state id (prev_state_id, new_states) =
   197     fun new_state id (state_id, updates) =
   253       let
   198       let
   254         val state_id = new_id ();
   199         val state_id' = new_id ();
   255         val state = make_state prev_state_id id Unprocessed;
   200         val state' = update_state (the_command id) (the_state state_id);
   256         val _ = define_state state_id state;
   201         val _ = define_state state_id' state';
   257       in (SOME state_id, (state_id, state) :: new_states) end;
   202       in (state_id', (id, state_id') :: updates) end;
       
   203 
       
   204     fun update_state (id, state_id) entries =
       
   205       let val _ = Output.status (Markup.markup (Markup.command_state id state_id) "")
       
   206       in put_entry (id, make_entry (#next (the_entry entries id)) (SOME state_id)) entries end;
   258   in
   207   in
   259     (case find_first_entries NONE is_changed old_document of
   208     (case find_entries is_changed old_document of
   260       NONE => new_document
   209       NONE => new_document
   261     | SOME id =>
   210     | SOME (prev, id) =>
   262         let
   211         let
   263           val _ = fold_entries (SOME id) cancel_state old_document ();
   212           val _ = fold_entries (SOME id) cancel_state old_document ();
   264           val (_, new_states) = fold_entries (SOME id) new_state new_document (NONE, []);
   213           val prev_state_id = the (#state (the_entry new_entries (the prev)));
   265           (* FIXME update states *)
   214           val (_, updates) = fold_entries (SOME id) new_state new_document (prev_state_id, []);
   266         in new_document end)
   215           val new_document' = new_document |> map_entries (fold update_state updates);
       
   216         in new_document' end)
   267   end;
   217   end;
   268 
   218 
   269 fun edit_document (id: document_id) (id': document_id) edits =
   219 fun edit_document (id: document_id) (id': document_id) edits =
   270   let
   220   let
   271     val document = Document (the_document id);
   221     val document = Document (the_document id);
   272     val document' =
   222     val document' =
   273       document
   223       document
   274       |> fold (fn (id, SOME id2) => insert_entry (id, id2) | (id, NONE) => delete_after id) edits
   224       |> fold (fn (id, SOME id2) => insert_after id id2 | (id, NONE) => delete_after id) edits
   275       |> refresh_states document;
   225       |> update_states document;
   276     val _ = define_document id' document';
   226     val _ = define_document id' document';
   277   in () end;
   227   in () end;
   278 
   228 
   279 
   229 
   280 
   230