author | clasohm |
Tue, 26 Oct 1993 22:24:20 +0100 | |
changeset 81 | 4cc5a34292a9 |
parent 78 | e76a1edc2e49 |
child 123 | 0a2f744e008a |
permissions | -rw-r--r-- |
0 | 1 |
(* Title: Pure/Thy/read |
2 |
ID: $Id$ |
|
3 |
Author: Sonia Mahjoub / Tobias Nipkow / L C Paulson |
|
4 |
Copyright 1992 TU Muenchen |
|
5 |
||
6 |
Reading and writing the theory definition files. |
|
7 |
||
8 |
For theory XXX, the input file is called XXX.thy |
|
9 |
the output file is called .XXX.thy.ML |
|
10 |
and it then tries to read XXX.ML |
|
11 |
*) |
|
12 |
||
13 |
signature READTHY = |
|
14 |
sig |
|
74 | 15 |
type thy_info |
81 | 16 |
datatype BaseType = Thy of string |
17 |
| File of string |
|
74 | 18 |
|
19 |
val use_thy : string -> unit |
|
20 |
val update : unit -> unit |
|
0 | 21 |
val time_use_thy : string -> unit |
81 | 22 |
val base_on : BaseType list -> string -> Thm.theory |
74 | 23 |
val store_theory : string -> Thm.theory -> unit |
24 |
val list_loaded : unit -> thy_info list |
|
25 |
val set_loaded : thy_info list -> unit |
|
26 |
val set_loadpath : string list -> unit |
|
27 |
val relations : string -> unit |
|
0 | 28 |
end; |
29 |
||
30 |
||
74 | 31 |
functor ReadthyFUN (structure ThySyn: THYSYN) : READTHY = |
0 | 32 |
struct |
33 |
||
81 | 34 |
datatype thy_info = ThyInfo of {name: string, children: string list, |
74 | 35 |
thy_info: string, ml_info: string, |
36 |
theory: Thm.theory}; |
|
0 | 37 |
|
81 | 38 |
datatype BaseType = Thy of string |
39 |
| File of string; |
|
40 |
||
41 |
val loaded_thys = ref [ThyInfo {name = "pure", children = [], thy_info = "", |
|
74 | 42 |
ml_info = "", theory = Thm.pure_thy}]; |
43 |
||
44 |
val loadpath = ref ["."]; |
|
45 |
||
46 |
||
47 |
(*Make name of the output ML file for a theory *) |
|
0 | 48 |
fun out_name thy = "." ^ thy ^ ".thy.ML"; |
49 |
||
74 | 50 |
(*Read a file specified by thy_file containing theory thy *) |
51 |
fun read_thy thy thy_file = |
|
52 |
let val instream = open_in thy_file; |
|
53 |
val outstream = open_out (out_name thy) |
|
0 | 54 |
in output (outstream, ThySyn.read (explode(input(instream, 999999)))); |
55 |
close_out outstream; |
|
56 |
close_in instream |
|
57 |
end; |
|
58 |
||
59 |
fun file_exists file = |
|
60 |
let val instream = open_in file in close_in instream; true end |
|
61 |
handle Io _ => false; |
|
62 |
||
74 | 63 |
exception FILE_NOT_FOUND; (*raised by find_file *) |
64 |
||
65 |
(*Find a file using a list of paths if no absolute or relative path is |
|
66 |
specified.*) |
|
67 |
fun find_file "" name = |
|
68 |
let fun find_it (curr :: paths) = |
|
69 |
if file_exists (tack_on curr name) then |
|
70 |
tack_on curr name |
|
71 |
else |
|
72 |
find_it paths |
|
73 |
| find_it [] = raise FILE_NOT_FOUND |
|
74 |
in find_it (!loadpath) end |
|
75 |
| find_file path name = |
|
76 |
if file_exists (tack_on path name) then tack_on path name |
|
77 |
else raise FILE_NOT_FOUND; |
|
78 |
||
79 |
(*Check if a theory was already loaded *) |
|
80 |
fun already_loaded thy = |
|
81 |
let fun do_search ((ThyInfo {name, ...}) :: loaded) = |
|
82 |
if name = thy then true else do_search loaded |
|
83 |
| do_search [] = false |
|
84 |
in do_search (!loaded_thys) end; |
|
85 |
||
86 |
(*Get thy_info for a loaded theory *) |
|
87 |
fun get_thyinfo thy = |
|
88 |
let fun do_search (t :: loaded : thy_info list) = |
|
89 |
let val ThyInfo {name, ...} = t |
|
90 |
in if name = thy then t else do_search loaded end |
|
91 |
| do_search [] = error ("Internal error (get_thyinfo): theory " |
|
92 |
^ thy ^ " not found.") |
|
93 |
in do_search (!loaded_thys) end; |
|
94 |
||
95 |
(*Check if a theory file has changed since its last use. |
|
81 | 96 |
Return a pair of boolean values for .thy and for .ML *) |
74 | 97 |
fun thy_unchanged thy thy_file ml_file = |
98 |
if already_loaded thy then |
|
81 | 99 |
let val ThyInfo {thy_info, ml_info, ...} = get_thyinfo thy |
74 | 100 |
in ((file_info (thy_file) = thy_info), (file_info (ml_file) = ml_info)) |
101 |
end |
|
102 |
else (false, false); |
|
103 |
||
104 |
(*Get theory object for a loaded theory *) |
|
105 |
fun get_theory name = |
|
106 |
let val ThyInfo {theory, ...} = get_thyinfo name |
|
107 |
in theory end; |
|
108 |
||
109 |
(*Read .thy and .ML files that haven't been read yet or have changed since |
|
110 |
they were last read; |
|
111 |
loaded_thys is a thy_info list ref containing all theories that have |
|
112 |
completly been read by this and preceeding use_thy calls. |
|
81 | 113 |
If a theory changed since its last use its children are marked as changed *) |
74 | 114 |
fun use_thy name = |
115 |
let val (path, thy_name) = split_filename name; |
|
116 |
val thy = to_lower thy_name; |
|
117 |
val thy_file = (find_file path (thy ^ ".thy") |
|
118 |
handle FILE_NOT_FOUND => ""); |
|
119 |
val (thy_path, _) = split_filename thy_file; |
|
120 |
val ml_file = if thy_file = "" |
|
121 |
then (find_file path (thy ^ ".ML") |
|
122 |
handle FILE_NOT_FOUND => |
|
123 |
error ("Could find no .thy or .ML file for theory " |
|
78
e76a1edc2e49
removed a bug that occured when a path was specified for use_thy's parameter
clasohm
parents:
74
diff
changeset
|
124 |
^ thy_name)) |
74 | 125 |
else if file_exists (thy_path ^ thy ^ ".ML") |
126 |
then thy_path ^ thy ^ ".ML" |
|
127 |
else "" |
|
128 |
val (thy_uptodate, ml_uptodate) = thy_unchanged thy thy_file ml_file; |
|
0 | 129 |
|
74 | 130 |
(*Remove theory from all child lists in loaded_thys. |
131 |
Afterwards add_child should be called for the (new) base theories *) |
|
132 |
fun remove_child thy = |
|
81 | 133 |
let fun do_remove (ThyInfo {name, children, thy_info, ml_info, theory} |
74 | 134 |
:: loaded) result = |
135 |
do_remove loaded |
|
81 | 136 |
(ThyInfo {name = name, children = children \ thy, |
74 | 137 |
thy_info = thy_info, ml_info = ml_info, |
138 |
theory = theory} :: result) |
|
139 |
| do_remove [] result = result; |
|
140 |
in loaded_thys := do_remove (!loaded_thys) [] end; |
|
141 |
||
142 |
exception THY_NOT_FOUND; (*Raised by set_info *) |
|
143 |
||
144 |
(*Change thy_info and ml_info for an existent item or create |
|
145 |
a new item with empty child list *) |
|
146 |
fun set_info thy_new ml_new thy = |
|
147 |
let fun make_change (t :: loaded) = |
|
81 | 148 |
let val ThyInfo {name, children, theory, ...} = t |
74 | 149 |
in if name = thy then |
81 | 150 |
ThyInfo {name = name, children = children, |
74 | 151 |
thy_info = thy_new, ml_info = ml_new, |
152 |
theory = theory} :: loaded |
|
153 |
else |
|
154 |
t :: (make_change loaded) |
|
155 |
end |
|
156 |
| make_change [] = raise THY_NOT_FOUND |
|
157 |
in loaded_thys := make_change (!loaded_thys) end; |
|
158 |
||
159 |
(*Mark all direct and indirect descendants of a theory as changed *) |
|
81 | 160 |
fun mark_children thy = |
161 |
let val ThyInfo {children, ...} = get_thyinfo thy |
|
162 |
in if children <> [] then |
|
163 |
(writeln ("The following children of theory " ^ (quote thy) |
|
164 |
^ " are now out-of-date: \"" |
|
165 |
^ (space_implode "\",\"" children) ^ "\""); |
|
166 |
seq (set_info "" "") children |
|
167 |
handle THY_NOT_FOUND => () |
|
74 | 168 |
(*If this theory was automatically loaded by a child |
169 |
then the child cannot be found in loaded_thys *) |
|
81 | 170 |
) |
171 |
else () |
|
74 | 172 |
end |
173 |
||
174 |
in if thy_uptodate andalso ml_uptodate then () |
|
175 |
else |
|
176 |
( |
|
81 | 177 |
writeln ("Loading theory " ^ (quote name)); |
74 | 178 |
if thy_uptodate orelse (thy_file = "") then () |
179 |
else |
|
180 |
( |
|
181 |
(*Allow dependency lists to be rebuild completely *) |
|
182 |
remove_child thy; |
|
183 |
||
184 |
read_thy thy thy_file |
|
185 |
); |
|
186 |
||
187 |
(*Actually read files!*) |
|
188 |
if thy_uptodate orelse (thy_file = "") then () |
|
189 |
else use (out_name thy); |
|
190 |
if (thy_file = "") then (*theory object created in .ML file*) |
|
191 |
( |
|
192 |
use ml_file; |
|
193 |
let val outstream = open_out (".tmp.ML") |
|
194 |
in |
|
78
e76a1edc2e49
removed a bug that occured when a path was specified for use_thy's parameter
clasohm
parents:
74
diff
changeset
|
195 |
output (outstream, "store_theory " ^ quote thy_name ^ " " |
e76a1edc2e49
removed a bug that occured when a path was specified for use_thy's parameter
clasohm
parents:
74
diff
changeset
|
196 |
^ thy_name ^ ".thy;\n"); |
74 | 197 |
close_out outstream |
198 |
end; |
|
199 |
use ".tmp.ML"; |
|
200 |
delete_file ".tmp.ML" |
|
201 |
) |
|
81 | 202 |
else if ml_file <> "" then use ml_file |
203 |
else (); |
|
74 | 204 |
|
205 |
(*Now set the correct info.*) |
|
206 |
(set_info (file_info thy_file) (file_info ml_file) thy |
|
78
e76a1edc2e49
removed a bug that occured when a path was specified for use_thy's parameter
clasohm
parents:
74
diff
changeset
|
207 |
handle THY_NOT_FOUND => error ("Could not find theory \"" ^ thy |
74 | 208 |
^ "\" (wrong filename?)")); |
209 |
||
210 |
(*Mark theories that have to be reloaded.*) |
|
81 | 211 |
mark_children thy; |
74 | 212 |
|
213 |
delete_file (out_name thy) |
|
214 |
) |
|
0 | 215 |
end; |
216 |
||
217 |
fun time_use_thy tname = timeit(fn()=> |
|
74 | 218 |
(writeln("\n**** Starting Theory " ^ tname ^ " ****"); |
219 |
use_thy tname; |
|
220 |
writeln("\n**** Finished Theory " ^ tname ^ " ****")) |
|
221 |
); |
|
222 |
||
223 |
(*Load all thy or ML files that have been changed and also |
|
224 |
all theories that depend on them *) |
|
225 |
fun update () = |
|
226 |
let (*List theories in the order they have to be loaded *) |
|
227 |
fun load_order [] result = result |
|
228 |
| load_order thys result = |
|
229 |
let fun next_level (t :: ts) = |
|
81 | 230 |
let val ThyInfo {children, ...} = get_thyinfo t |
231 |
in children union (next_level ts) |
|
74 | 232 |
end |
233 |
| next_level [] = []; |
|
234 |
||
81 | 235 |
val children = next_level thys |
236 |
in load_order children ((result \\ children) @ children) end; |
|
74 | 237 |
|
238 |
fun reload_changed (t :: ts) = |
|
239 |
let val curr = get_thyinfo t; |
|
240 |
val thy_file = (find_file "" (t ^ ".thy") |
|
241 |
handle FILE_NOT_FOUND => ""); |
|
242 |
val (thy_path, _) = split_filename thy_file; |
|
243 |
val ml_file = if thy_file = "" |
|
244 |
then (find_file "" (t ^ ".ML") |
|
245 |
handle FILE_NOT_FOUND => |
|
246 |
error ("Could find no .thy or .ML file for theory " |
|
247 |
^ t)) |
|
248 |
else if file_exists (thy_path ^ t ^ ".ML") |
|
249 |
then thy_path ^ t ^ ".ML" |
|
250 |
else "" |
|
251 |
val (thy_uptodate, ml_uptodate) = |
|
252 |
thy_unchanged t thy_file ml_file; |
|
253 |
||
254 |
in if thy_uptodate andalso ml_uptodate then () |
|
255 |
else use_thy t; |
|
256 |
reload_changed ts |
|
257 |
end |
|
258 |
| reload_changed [] = () |
|
259 |
in reload_changed (load_order ["pure"] []) end; |
|
260 |
||
261 |
(*Merge theories to build a base for a new theory. |
|
262 |
Base members are only loaded if they are missing. *) |
|
81 | 263 |
fun base_on bases child = |
74 | 264 |
let val childl = to_lower child; |
265 |
||
81 | 266 |
(*List all descendants of a theory list *) |
267 |
fun list_descendants (t :: ts) = |
|
268 |
if already_loaded t then |
|
269 |
let val ThyInfo {children, ...} = get_thyinfo t |
|
270 |
in children union |
|
271 |
(list_descendants (ts union children)) |
|
272 |
end |
|
273 |
else [] |
|
274 |
| list_descendants [] = []; |
|
74 | 275 |
|
81 | 276 |
(*Show the cycle that would be created by add_child *) |
277 |
fun show_cycle base = |
|
278 |
let fun find_it result curr = |
|
279 |
if base = curr then |
|
280 |
error ("Cyclic dependency of theories: " |
|
281 |
^ childl ^ "->" ^ base ^ result) |
|
282 |
else if already_loaded curr then |
|
283 |
let val ThyInfo {children, ...} = get_thyinfo curr |
|
284 |
in seq (find_it ("->" ^ curr ^ result)) children |
|
285 |
end |
|
286 |
else () |
|
287 |
in find_it "" childl end; |
|
288 |
||
289 |
(*Check if a cycle will be created by add_child *) |
|
290 |
fun find_cycle base = |
|
291 |
if base mem (list_descendants [childl]) then show_cycle base |
|
292 |
else (); |
|
293 |
||
294 |
(*Add child to child list of base *) |
|
295 |
fun add_child (t :: loaded) base = |
|
296 |
let val ThyInfo {name, children, thy_info, ml_info, theory} = t |
|
297 |
in if name = base then |
|
298 |
ThyInfo {name = name, |
|
299 |
children = childl ins children, |
|
300 |
thy_info = thy_info, ml_info = ml_info, |
|
301 |
theory = theory} :: loaded |
|
302 |
else |
|
303 |
t :: (add_child loaded base) |
|
304 |
end |
|
305 |
| add_child [] base = |
|
306 |
[ThyInfo {name = base, children = [childl], |
|
307 |
thy_info = "", ml_info = "", |
|
308 |
theory = Thm.pure_thy}]; |
|
309 |
(*Thm.pure_thy is used as a dummy *) |
|
74 | 310 |
|
81 | 311 |
fun do_load thy = |
312 |
let val basel = to_lower thy; |
|
74 | 313 |
|
81 | 314 |
val thy_present = already_loaded basel |
74 | 315 |
(*test this before child is added *) |
316 |
in |
|
317 |
if childl = basel then |
|
318 |
error ("Cyclic dependency of theories: " ^ child |
|
319 |
^ "->" ^ child) |
|
81 | 320 |
else |
321 |
(find_cycle thy; |
|
322 |
loaded_thys := add_child (!loaded_thys) basel; |
|
323 |
if thy_present then () |
|
324 |
else (writeln ("Autoloading theory " ^ (quote thy) |
|
325 |
^ " (used by " ^ (quote child) ^ ")"); |
|
326 |
use_thy thy) |
|
327 |
) |
|
328 |
end; |
|
329 |
||
330 |
fun load_base (Thy b :: bs) = |
|
331 |
(do_load b; |
|
332 |
(to_lower b) :: (load_base bs)) |
|
333 |
| load_base (File b :: bs) = |
|
334 |
(do_load b; |
|
335 |
load_base bs) (*don't add it to merge_theories' parameter *) |
|
336 |
| load_base [] = []; |
|
74 | 337 |
|
81 | 338 |
val (t :: ts) = load_base bases |
339 |
in foldl Thm.merge_theories (get_theory t, map get_theory ts) end; |
|
74 | 340 |
|
341 |
(*Change theory object for an existent item of loaded_thys |
|
342 |
or create a new item *) |
|
343 |
fun store_theory thy_name thy = |
|
344 |
let fun make_change (t :: loaded) = |
|
81 | 345 |
let val ThyInfo {name, children, thy_info, ml_info, ...} = t |
74 | 346 |
in if name = (to_lower thy_name) then |
81 | 347 |
ThyInfo {name = name, children = children, |
74 | 348 |
thy_info = thy_info, ml_info = ml_info, |
349 |
theory = thy} :: loaded |
|
350 |
else |
|
351 |
t :: (make_change loaded) |
|
352 |
end |
|
353 |
| make_change [] = |
|
81 | 354 |
[ThyInfo {name = (to_lower thy_name), children = [], thy_info = "", |
74 | 355 |
ml_info = "", theory = thy}] |
356 |
in loaded_thys := make_change (!loaded_thys) end; |
|
357 |
||
358 |
(*Create a list of all theories loaded by this structure *) |
|
359 |
fun list_loaded () = (!loaded_thys); |
|
360 |
||
361 |
(*Change the list of loaded theories *) |
|
362 |
fun set_loaded [] = |
|
81 | 363 |
loaded_thys := [ThyInfo {name = "pure", children = [], thy_info = "", |
74 | 364 |
ml_info = "", theory = Thm.pure_thy}] |
365 |
| set_loaded ts = |
|
366 |
loaded_thys := ts; |
|
367 |
||
368 |
(*Change the path list that is to be searched for .thy and .ML files *) |
|
369 |
fun set_loadpath new_path = |
|
370 |
loadpath := new_path; |
|
371 |
||
372 |
(*This function is for debugging purposes only *) |
|
373 |
fun relations thy = |
|
81 | 374 |
let val ThyInfo {children, ...} = get_thyinfo thy |
74 | 375 |
in |
81 | 376 |
writeln (thy ^ ": " ^ (space_implode ", " children)); |
377 |
seq relations children |
|
74 | 378 |
end |
0 | 379 |
|
380 |
end; |
|
74 | 381 |