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 |