142 (** datatype theory **) |
141 (** datatype theory **) |
143 |
142 |
144 datatype theory = |
143 datatype theory = |
145 Theory of |
144 Theory of |
146 (*identity*) |
145 (*identity*) |
147 {self: theory ref option, (*dynamic self reference -- follows theory changes*) |
146 {self: theory ref option, (*dynamic self reference -- follows theory changes*) |
148 id: serial * (string * int), (*identifier/name of this theory node*) |
147 draft: bool, (*draft mode -- linear changes*) |
149 ids: (string * int) Inttab.table} * (*ancestors and checkpoints*) |
148 id: serial, (*identifier*) |
150 (*data*) |
149 ids: unit Inttab.table} * (*cumulative identifiers of non-drafts -- symbolic body content*) |
151 Object.T Datatab.table * |
150 (*data*) |
152 (*ancestry*) |
151 Object.T Datatab.table * |
153 {parents: theory list, (*immediate predecessors*) |
152 (*ancestry*) |
154 ancestors: theory list} * (*all predecessors*) |
153 {parents: theory list, (*immediate predecessors*) |
155 (*history*) |
154 ancestors: theory list} * (*all predecessors -- canonical reverse order*) |
156 {name: string, (*prospective name of finished theory*) |
155 (*history*) |
157 version: int}; (*checkpoint counter*) |
156 {name: string, (*official theory name*) |
|
157 stage: int}; (*checkpoint counter*) |
158 |
158 |
159 exception THEORY of string * theory list; |
159 exception THEORY of string * theory list; |
160 |
160 |
161 fun rep_theory (Theory args) = args; |
161 fun rep_theory (Theory args) = args; |
162 |
162 |
163 val identity_of = #1 o rep_theory; |
163 val identity_of = #1 o rep_theory; |
164 val data_of = #2 o rep_theory; |
164 val data_of = #2 o rep_theory; |
165 val ancestry_of = #3 o rep_theory; |
165 val ancestry_of = #3 o rep_theory; |
166 val history_of = #4 o rep_theory; |
166 val history_of = #4 o rep_theory; |
167 |
167 |
168 fun make_identity self id ids = {self = self, id = id, ids = ids}; |
168 fun make_identity self draft id ids = {self = self, draft = draft, id = id, ids = ids}; |
169 fun make_ancestry parents ancestors = {parents = parents, ancestors = ancestors}; |
169 fun make_ancestry parents ancestors = {parents = parents, ancestors = ancestors}; |
170 fun make_history name version = {name = name, version = version}; |
170 fun make_history name stage = {name = name, stage = stage}; |
171 |
171 |
172 val the_self = the o #self o identity_of; |
172 val the_self = the o #self o identity_of; |
173 val parents_of = #parents o ancestry_of; |
173 val parents_of = #parents o ancestry_of; |
174 val ancestors_of = #ancestors o ancestry_of; |
174 val ancestors_of = #ancestors o ancestry_of; |
175 val theory_name = #name o history_of; |
175 val theory_name = #name o history_of; |
176 |
176 |
177 |
177 |
178 (* staleness *) |
178 (* staleness *) |
179 |
179 |
180 fun eq_id ((i: int, _), (j, _)) = (i = j); |
180 fun eq_id (i: int, j) = i = j; |
181 |
181 |
182 fun is_stale |
182 fun is_stale |
183 (Theory ({self = SOME (ref (Theory ({id = id', ...}, _, _, _))), id, ...}, _, _, _)) = |
183 (Theory ({self = SOME (ref (Theory ({id = id', ...}, _, _, _))), id, ...}, _, _, _)) = |
184 not (eq_id (id, id')) |
184 not (eq_id (id, id')) |
185 | is_stale (Theory ({self = NONE, ...}, _, _, _)) = true; |
185 | is_stale (Theory ({self = NONE, ...}, _, _, _)) = true; |
186 |
186 |
187 fun vitalize (thy as Theory ({self = SOME r, ...}, _, _, _)) = (r := thy; thy) |
187 fun vitalize (thy as Theory ({self = SOME r, ...}, _, _, _)) = (r := thy; thy) |
188 | vitalize (thy as Theory ({self = NONE, id, ids}, data, ancestry, history)) = |
188 | vitalize (thy as Theory ({self = NONE, draft, id, ids}, data, ancestry, history)) = |
189 let |
189 let |
190 val r = ref thy; |
190 val r = ref thy; |
191 val thy' = Theory (make_identity (SOME r) id ids, data, ancestry, history); |
191 val thy' = Theory (make_identity (SOME r) draft id ids, data, ancestry, history); |
192 in r := thy'; thy' end; |
192 in r := thy'; thy' end; |
193 |
193 |
194 |
194 |
195 (* names *) |
195 (* draft mode *) |
196 |
196 |
197 val PureN = "Pure"; |
197 val is_draft = #draft o identity_of; |
198 |
|
199 val draftN = "#"; |
|
200 val draft_name = (draftN, ~1); |
|
201 |
|
202 fun draft_id (_, (name, _)) = (name = draftN); |
|
203 val is_draft = draft_id o #id o identity_of; |
|
204 |
198 |
205 fun reject_draft thy = |
199 fun reject_draft thy = |
206 if is_draft thy then raise THEORY ("Illegal draft theory -- stable checkpoint required", [thy]) |
200 if is_draft thy then raise THEORY ("Illegal draft theory -- stable checkpoint required", [thy]) |
207 else thy; |
201 else thy; |
208 |
202 |
209 fun exists_name name (thy as Theory ({id = (_, (a, _)), ids, ...}, _, _, _)) = |
203 |
210 name = theory_name thy orelse |
204 (* names *) |
211 name = a orelse |
205 |
212 Inttab.exists (fn (_, (b, _)) => b = name) ids; |
206 val PureN = "Pure"; |
213 |
207 val draftN = "#"; |
214 fun name_of (a, ~1) = a |
208 |
215 | name_of (a, i) = a ^ ":" ^ string_of_int i; |
209 fun display_names thy = |
216 |
210 let |
217 fun names_of (Theory ({id = (_, a), ids, ...}, _, _, _)) = |
211 val draft = if is_draft thy then [draftN] else []; |
218 rev (name_of a :: Inttab.fold (fn (_, (b, ~1)) => cons b | _ => I) ids []); |
212 val name = |
219 |
213 (case #stage (history_of thy) of |
220 fun pretty_thy thy = |
214 ~1 => theory_name thy |
221 Pretty.str_list "{" "}" (names_of thy @ (if is_stale thy then ["!"] else [])); |
215 | n => theory_name thy ^ ":" ^ string_of_int n); |
222 |
216 val ancestor_names = map theory_name (ancestors_of thy); |
|
217 val stale = if is_stale thy then ["!"] else []; |
|
218 in rev (stale @ draft @ [name] @ ancestor_names) end; |
|
219 |
|
220 val pretty_thy = Pretty.str_list "{" "}" o display_names; |
223 val string_of_thy = Pretty.string_of o pretty_thy; |
221 val string_of_thy = Pretty.string_of o pretty_thy; |
224 val pprint_thy = Pretty.pprint o pretty_thy; |
222 val pprint_thy = Pretty.pprint o pretty_thy; |
225 |
223 |
226 fun pretty_abbrev_thy thy = |
224 fun pretty_abbrev_thy thy = |
227 let |
225 let |
228 val names = names_of thy; |
226 val names = display_names thy; |
229 val n = length names; |
227 val n = length names; |
230 val abbrev = if n > 5 then "..." :: List.drop (names, n - 5) else names; |
228 val abbrev = if n > 5 then "..." :: List.drop (names, n - 5) else names; |
231 in Pretty.str_list "{" "}" abbrev end; |
229 in Pretty.str_list "{" "}" abbrev end; |
232 |
230 |
233 val str_of_thy = Pretty.str_of o pretty_abbrev_thy; |
231 val str_of_thy = Pretty.str_of o pretty_abbrev_thy; |
250 end; |
248 end; |
251 |
249 |
252 val pprint_thy_ref = Pretty.pprint o pretty_thy o deref; |
250 val pprint_thy_ref = Pretty.pprint o pretty_thy o deref; |
253 |
251 |
254 |
252 |
255 (* consistency *) |
253 (* build ids *) |
256 |
254 |
257 fun check_insert id ids = |
255 fun insert_id draft id ids = |
258 if draft_id id orelse Inttab.defined ids (#1 id) then ids |
256 if draft then ids |
259 else if Inttab.exists (fn (_, a) => a = #2 id) ids then |
257 else Inttab.update (id, ()) ids; |
260 error ("Different versions of theory component " ^ quote (name_of (#2 id))) |
258 |
261 else Inttab.update id ids; |
259 fun merge_ids |
262 |
260 (Theory ({draft = draft1, id = id1, ids = ids1, ...}, _, _, _)) |
263 fun check_merge |
261 (Theory ({draft = draft2, id = id2, ids = ids2, ...}, _, _, _)) = |
264 (Theory ({id = id1, ids = ids1, ...}, _, _, _)) |
262 Inttab.merge (K true) (ids1, ids2) |
265 (Theory ({id = id2, ids = ids2, ...}, _, _, _)) = |
263 |> insert_id draft1 id1 |
266 Inttab.fold check_insert ids2 ids1 |
264 |> insert_id draft2 id2; |
267 |> check_insert id1 |
|
268 |> check_insert id2; |
|
269 |
265 |
270 |
266 |
271 (* equality and inclusion *) |
267 (* equality and inclusion *) |
272 |
268 |
273 val eq_thy = eq_id o pairself (#id o identity_of); |
269 val eq_thy = eq_id o pairself (#id o identity_of); |
274 |
270 |
275 fun proper_subthy (Theory ({id, ...}, _, _, _), Theory ({ids, ...}, _, _, _)) = |
271 fun proper_subthy (Theory ({id, ...}, _, _, _), Theory ({ids, ...}, _, _, _)) = |
276 Inttab.defined ids (#1 id); |
272 Inttab.defined ids id; |
277 |
273 |
278 fun subthy thys = eq_thy thys orelse proper_subthy thys; |
274 fun subthy thys = eq_thy thys orelse proper_subthy thys; |
279 |
275 |
280 fun joinable (thy1, thy2) = subthy (thy1, thy2) orelse subthy (thy2, thy1); |
276 fun joinable (thy1, thy2) = subthy (thy1, thy2) orelse subthy (thy2, thy1); |
|
277 |
|
278 |
|
279 (* consistent ancestors *) |
|
280 |
|
281 fun extend_ancestors thy thys = |
|
282 if member eq_thy thys thy then raise THEORY ("Duplicate theory node", thy :: thys) |
|
283 else thy :: thys; |
|
284 |
|
285 fun extend_ancestors_of thy = extend_ancestors thy (ancestors_of thy); |
|
286 |
|
287 val merge_ancestors = merge (fn (thy1, thy2) => |
|
288 eq_thy (thy1, thy2) orelse |
|
289 theory_name thy1 = theory_name thy2 andalso |
|
290 raise THEORY ("Inconsistent theory versions", [thy1, thy2])); |
281 |
291 |
282 |
292 |
283 (* trivial merge *) |
293 (* trivial merge *) |
284 |
294 |
285 fun merge (thy1, thy2) = |
295 fun merge (thy1, thy2) = |
286 if eq_thy (thy1, thy2) then thy1 |
296 if eq_thy (thy1, thy2) then thy1 |
287 else if proper_subthy (thy2, thy1) then thy1 |
297 else if proper_subthy (thy2, thy1) then thy1 |
288 else if proper_subthy (thy1, thy2) then thy2 |
298 else if proper_subthy (thy1, thy2) then thy2 |
289 else (check_merge thy1 thy2; |
299 else error (cat_lines ["Attempt to perform non-trivial merge of theories:", |
290 error (cat_lines ["Attempt to perform non-trivial merge of theories:", |
300 str_of_thy thy1, str_of_thy thy2]); |
291 str_of_thy thy1, str_of_thy thy2])); |
|
292 |
301 |
293 fun merge_refs (ref1, ref2) = |
302 fun merge_refs (ref1, ref2) = |
294 if ref1 = ref2 then ref1 |
303 if ref1 = ref2 then ref1 |
295 else check_thy (merge (deref ref1, deref ref2)); |
304 else check_thy (merge (deref ref1, deref ref2)); |
296 |
305 |
298 |
307 |
299 (** build theories **) |
308 (** build theories **) |
300 |
309 |
301 (* primitives *) |
310 (* primitives *) |
302 |
311 |
303 fun create_thy name self id ids data ancestry history = |
312 fun create_thy self draft ids data ancestry history = |
304 let |
313 let val identity = make_identity self draft (serial ()) ids; |
305 val {version, ...} = history; |
314 in vitalize (Theory (identity, data, ancestry, history)) end; |
306 val ids' = check_insert id ids; |
315 |
307 val id' = (serial (), name); |
316 fun change_thy draft' f thy = |
308 val _ = check_insert id' ids'; |
317 let |
309 val identity' = make_identity self id' ids'; |
318 val Theory ({self, draft, id, ids}, data, ancestry, history) = thy; |
310 in vitalize (Theory (identity', data, ancestry, history)) end; |
|
311 |
|
312 fun change_thy name f thy = |
|
313 let |
|
314 val Theory ({self, id, ids}, data, ancestry, history) = thy; |
|
315 val (self', data', ancestry') = |
319 val (self', data', ancestry') = |
316 if is_draft thy then (self, data, ancestry) (*destructive change!*) |
320 if draft then (self, data, ancestry) (*destructive change!*) |
317 else if #version history > 0 |
321 else if #stage history > 0 |
318 then (NONE, copy_data data, ancestry) |
322 then (NONE, copy_data data, ancestry) |
319 else (NONE, extend_data data, make_ancestry [thy] (thy :: #ancestors ancestry)); |
323 else (NONE, extend_data data, make_ancestry [thy] (extend_ancestors_of thy)); |
|
324 val ids' = insert_id draft id ids; |
320 val data'' = f data'; |
325 val data'' = f data'; |
321 val thy' = NAMED_CRITICAL "theory" (fn () => |
326 val thy' = NAMED_CRITICAL "theory" (fn () => |
322 (check_thy thy; create_thy name self' id ids data'' ancestry' history)); |
327 (check_thy thy; create_thy self' draft' ids' data'' ancestry' history)); |
323 in thy' end; |
328 in thy' end; |
324 |
329 |
325 fun name_thy name = change_thy name I; |
330 val name_thy = change_thy false I; |
326 val modify_thy = change_thy draft_name; |
331 val extend_thy = change_thy true I; |
327 val extend_thy = modify_thy I; |
332 val modify_thy = change_thy true; |
328 |
333 |
329 fun copy_thy thy = |
334 fun copy_thy thy = |
330 let |
335 let |
331 val Theory ({id, ids, ...}, data, ancestry, history) = thy; |
336 val Theory ({draft, id, ids, ...}, data, ancestry, history) = thy; |
|
337 val ids' = insert_id draft id ids; |
332 val data' = copy_data data; |
338 val data' = copy_data data; |
333 val thy' = NAMED_CRITICAL "theory" (fn () => |
339 val thy' = NAMED_CRITICAL "theory" (fn () => |
334 (check_thy thy; create_thy draft_name NONE id ids data' ancestry history)); |
340 (check_thy thy; create_thy NONE true ids' data' ancestry history)); |
335 in thy' end; |
341 in thy' end; |
336 |
342 |
337 val pre_pure_thy = create_thy draft_name NONE (serial (), draft_name) Inttab.empty |
343 val pre_pure_thy = create_thy NONE true Inttab.empty |
338 Datatab.empty (make_ancestry [] []) (make_history PureN 0); |
344 Datatab.empty (make_ancestry [] []) (make_history PureN 0); |
339 |
345 |
340 |
346 |
341 (* named theory nodes *) |
347 (* named theory nodes *) |
342 |
348 |
343 fun merge_thys pp (thy1, thy2) = |
349 fun merge_thys pp (thy1, thy2) = |
344 let |
350 let |
345 val ids = check_merge thy1 thy2; |
351 val ids = merge_ids thy1 thy2; |
346 val data = merge_data (pp thy1) (data_of thy1, data_of thy2); |
352 val data = merge_data (pp thy1) (data_of thy1, data_of thy2); |
347 val ancestry = make_ancestry [] []; |
353 val ancestry = make_ancestry [] []; |
348 val history = make_history "" 0; |
354 val history = make_history "" 0; |
349 val thy' = NAMED_CRITICAL "theory" (fn () => |
355 val thy' = NAMED_CRITICAL "theory" (fn () => |
350 (check_thy thy1; check_thy thy2; |
356 (check_thy thy1; check_thy thy2; create_thy NONE true ids data ancestry history)); |
351 create_thy draft_name NONE (serial (), draft_name) ids data ancestry history)); |
|
352 in thy' end; |
357 in thy' end; |
353 |
358 |
354 fun maximal_thys thys = |
359 fun maximal_thys thys = |
355 thys |> filter_out (fn thy => exists (fn thy' => proper_subthy (thy, thy')) thys); |
360 thys |> filter_out (fn thy => exists (fn thy' => proper_subthy (thy, thy')) thys); |
356 |
361 |
357 fun begin_thy pp name imports = |
362 fun begin_thy pp name imports = |
358 if name = draftN then error ("Illegal theory name: " ^ quote draftN) |
363 if name = "" orelse name = draftN then error ("Bad theory name: " ^ quote name) |
359 else |
364 else |
360 let |
365 let |
361 val parents = maximal_thys (distinct eq_thy imports); |
366 val parents = maximal_thys (distinct eq_thy imports); |
362 val ancestors = distinct eq_thy (parents @ maps ancestors_of parents); |
367 val ancestors = |
363 val Theory ({id, ids, ...}, data, _, _) = |
368 Library.foldl merge_ancestors ([], map ancestors_of parents) |
|
369 |> fold extend_ancestors parents; |
|
370 |
|
371 val Theory ({ids, ...}, data, _, _) = |
364 (case parents of |
372 (case parents of |
365 [] => error "No parent theories" |
373 [] => error "No parent theories" |
366 | [thy] => extend_thy thy |
374 | [thy] => extend_thy thy |
367 | thy :: thys => Library.foldl (merge_thys pp) (thy, thys)); |
375 | thy :: thys => Library.foldl (merge_thys pp) (thy, thys)); |
|
376 |
368 val ancestry = make_ancestry parents ancestors; |
377 val ancestry = make_ancestry parents ancestors; |
369 val history = make_history name 0; |
378 val history = make_history name 0; |
370 val thy' = NAMED_CRITICAL "theory" (fn () => |
379 val thy' = NAMED_CRITICAL "theory" (fn () => |
371 (map check_thy imports; create_thy draft_name NONE id ids data ancestry history)); |
380 (map check_thy imports; create_thy NONE true ids data ancestry history)); |
372 in thy' end; |
381 in thy' end; |
373 |
382 |
374 |
383 |
375 (* persistent checkpoints *) |
384 (* history stages *) |
|
385 |
|
386 fun history_stage f thy = |
|
387 let |
|
388 val {name, stage} = history_of thy; |
|
389 val _ = stage = ~1 andalso raise THEORY ("Theory already finished", [thy]); |
|
390 val history' = make_history name (f stage); |
|
391 val thy' as Theory (identity', data', ancestry', _) = name_thy thy; |
|
392 val thy'' = NAMED_CRITICAL "theory" (fn () => |
|
393 (check_thy thy'; vitalize (Theory (identity', data', ancestry', history')))); |
|
394 in thy'' end; |
376 |
395 |
377 fun checkpoint_thy thy = |
396 fun checkpoint_thy thy = |
378 if not (is_draft thy) then thy |
397 if is_draft thy then history_stage (fn stage => stage + 1) thy |
379 else |
398 else thy; |
380 let |
399 |
381 val {name, version} = history_of thy; |
400 val finish_thy = history_stage (fn _ => ~1); |
382 val thy' as Theory (identity', data', ancestry', _) = name_thy (name, version) thy; |
|
383 val history' = make_history name (version + 1); |
|
384 val thy'' = NAMED_CRITICAL "theory" (fn () => |
|
385 (check_thy thy'; vitalize (Theory (identity', data', ancestry', history')))); |
|
386 in thy'' end; |
|
387 |
|
388 fun finish_thy thy = NAMED_CRITICAL "theory" (fn () => |
|
389 let |
|
390 val name = theory_name thy; |
|
391 val Theory (identity', data', ancestry', _) = name_thy (name, ~1) thy; |
|
392 val history' = make_history name 0; |
|
393 val thy' = vitalize (Theory (identity', data', ancestry', history')); |
|
394 in thy' end); |
|
395 |
401 |
396 |
402 |
397 (* theory data *) |
403 (* theory data *) |
398 |
404 |
399 structure TheoryData = |
405 structure TheoryData = |