| author | wenzelm | 
| Sat, 14 Jun 2008 23:20:11 +0200 | |
| changeset 27218 | 4548c83cd508 | 
| parent 26881 | bb68f50644a9 | 
| child 29606 | fedb8be05f24 | 
| permissions | -rw-r--r-- | 
| 6118 | 1  | 
(* Title: Pure/General/path.ML  | 
| 5011 | 2  | 
ID: $Id$  | 
3  | 
Author: Markus Wenzel, TU Muenchen  | 
|
4  | 
||
| 23863 | 5  | 
Abstract algebra of file paths (external encoding in Unix style).  | 
| 5011 | 6  | 
*)  | 
7  | 
||
8  | 
signature PATH =  | 
|
9  | 
sig  | 
|
| 6183 | 10  | 
eqtype T  | 
| 6460 | 11  | 
val is_current: T -> bool  | 
| 6183 | 12  | 
val current: T  | 
13  | 
val root: T  | 
|
14  | 
val parent: T  | 
|
15  | 
val basic: string -> T  | 
|
16  | 
val variable: string -> T  | 
|
17  | 
val is_absolute: T -> bool  | 
|
18  | 
val is_basic: T -> bool  | 
|
19  | 
val append: T -> T -> T  | 
|
| 6270 | 20  | 
val appends: T list -> T  | 
| 6319 | 21  | 
val make: string list -> T  | 
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
22  | 
val implode: T -> string  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
23  | 
val explode: string -> T  | 
| 14912 | 24  | 
val dir: T -> T  | 
| 6183 | 25  | 
val base: T -> T  | 
26  | 
val ext: string -> T -> T  | 
|
| 14912 | 27  | 
val split_ext: T -> T * string  | 
| 6183 | 28  | 
val expand: T -> T  | 
| 26881 | 29  | 
val position: T -> Position.T  | 
| 5011 | 30  | 
end;  | 
31  | 
||
| 6187 | 32  | 
structure Path: PATH =  | 
| 5011 | 33  | 
struct  | 
34  | 
||
| 6183 | 35  | 
|
36  | 
(* path elements *)  | 
|
37  | 
||
38  | 
datatype elem = Root | Parent | Basic of string | Variable of string;  | 
|
39  | 
||
| 6223 | 40  | 
fun err_elem msg chs = error (msg ^ " path element specification: " ^ quote (implode chs));  | 
| 6183 | 41  | 
|
| 6319 | 42  | 
fun check_elem (chs as []) = err_elem "Illegal" chs  | 
43  | 
| check_elem (chs as ["~"]) = err_elem "Illegal" chs  | 
|
| 6223 | 44  | 
| check_elem (chs as ["~", "~"]) = err_elem "Illegal" chs  | 
45  | 
| check_elem chs =  | 
|
46  | 
(case ["/", "\\", "$", ":"] inter_string chs of  | 
|
47  | 
[] => chs  | 
|
48  | 
      | bads => err_elem ("Illegal character(s) " ^ commas_quote bads ^ " in") chs);
 | 
|
49  | 
||
50  | 
val basic_elem = Basic o implode o check_elem;  | 
|
51  | 
val variable_elem = Variable o implode o check_elem;  | 
|
| 6183 | 52  | 
|
53  | 
fun is_var (Variable _) = true  | 
|
54  | 
| is_var _ = false;  | 
|
55  | 
||
56  | 
||
| 5011 | 57  | 
(* type path *)  | 
58  | 
||
| 6183 | 59  | 
datatype T = Path of elem list;  | 
60  | 
||
61  | 
fun rep (Path xs) = xs;  | 
|
| 5011 | 62  | 
|
| 6460 | 63  | 
fun is_current (Path []) = true  | 
64  | 
| is_current _ = false;  | 
|
65  | 
||
| 5011 | 66  | 
val current = Path [];  | 
| 6183 | 67  | 
val root = Path [Root];  | 
68  | 
val parent = Path [Parent];  | 
|
69  | 
fun basic s = Path [basic_elem (explode s)];  | 
|
70  | 
fun variable s = Path [variable_elem (explode s)];  | 
|
| 5011 | 71  | 
|
| 6183 | 72  | 
fun is_absolute (Path (Root :: _)) = true  | 
73  | 
| is_absolute _ = false;  | 
|
| 5011 | 74  | 
|
| 6183 | 75  | 
fun is_basic (Path [Basic _]) = true  | 
76  | 
| is_basic _ = false;  | 
|
| 5011 | 77  | 
|
78  | 
||
79  | 
(* append and norm *)  | 
|
80  | 
||
81  | 
(*append non-normal path (2n arg) to reversed normal one, result is normal*)  | 
|
82  | 
fun rev_app xs [] = rev xs  | 
|
| 6183 | 83  | 
| rev_app _ (Root :: ys) = rev_app [Root] ys  | 
84  | 
| rev_app (x :: xs) (Parent :: ys) =  | 
|
85  | 
if x = Parent orelse is_var x then rev_app (Parent :: x :: xs) ys  | 
|
86  | 
else if x = Root then rev_app (x :: xs) ys  | 
|
| 5011 | 87  | 
else rev_app xs ys  | 
88  | 
| rev_app xs (y :: ys) = rev_app (y :: xs) ys;  | 
|
89  | 
||
| 6183 | 90  | 
fun append (Path xs) (Path ys) = Path (rev_app (rev xs) ys);  | 
| 15570 | 91  | 
fun appends paths = Library.foldl (uncurry append) (current, paths);  | 
| 6319 | 92  | 
val make = appends o map basic;  | 
| 5011 | 93  | 
fun norm path = rev_app [] path;  | 
94  | 
||
| 6183 | 95  | 
|
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
96  | 
(* implode *)  | 
| 5011 | 97  | 
|
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
98  | 
fun implode_elem Root = ""  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
99  | 
| implode_elem Parent = ".."  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
100  | 
| implode_elem (Basic s) = s  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
101  | 
| implode_elem (Variable s) = "$" ^ s;  | 
| 5011 | 102  | 
|
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
103  | 
fun implode_path (Path []) = "."  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
104  | 
| implode_path (Path (Root :: xs)) = "/" ^ space_implode "/" (map implode_elem xs)  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
105  | 
| implode_path (Path xs) = space_implode "/" (map implode_elem xs);  | 
| 5011 | 106  | 
|
107  | 
||
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
108  | 
(* explode *)  | 
| 6183 | 109  | 
|
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
110  | 
fun explode_elem "" = Root  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
111  | 
| explode_elem ".." = Parent  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
112  | 
| explode_elem "~" = Variable "HOME"  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
113  | 
| explode_elem "~~" = Variable "ISABELLE_HOME"  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
114  | 
| explode_elem s =  | 
| 6183 | 115  | 
(case explode s of  | 
116  | 
"$" :: cs => variable_elem cs  | 
|
117  | 
| cs => basic_elem cs);  | 
|
118  | 
||
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
119  | 
val explode_elems = map explode_elem o filter_out (fn c => c = "" orelse c = ".");  | 
| 6183 | 120  | 
|
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
121  | 
fun explode_path str = Path (norm  | 
| 6183 | 122  | 
(case space_explode "/" str of  | 
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
123  | 
"" :: ss => Root :: explode_elems ss  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
124  | 
| ss => explode_elems ss));  | 
| 6183 | 125  | 
|
| 5011 | 126  | 
|
| 6183 | 127  | 
(* base element *)  | 
128  | 
||
| 7929 | 129  | 
fun split_path f (path as Path xs) =  | 
130  | 
(case try split_last xs of  | 
|
| 15531 | 131  | 
SOME (prfx, Basic s) => f (prfx, s)  | 
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
132  | 
  | _ => error ("Cannot split path into dir/base: " ^ quote (implode_path path)));
 | 
| 6183 | 133  | 
|
| 14912 | 134  | 
val dir = split_path (fn (prfx, _) => Path prfx);  | 
| 7929 | 135  | 
val base = split_path (fn (_, s) => Path [Basic s]);  | 
| 6183 | 136  | 
|
| 7929 | 137  | 
fun ext "" path = path  | 
138  | 
| ext e path = split_path (fn (prfx, s) => append (Path prfx) (basic (s ^ "." ^ e))) path;  | 
|
| 6183 | 139  | 
|
| 14912 | 140  | 
val split_ext = split_path (fn (prfx, s) => apfst (append (Path prfx))  | 
| 19305 | 141  | 
(case take_suffix (fn c => c <> ".") (explode s) of  | 
| 14912 | 142  | 
([], _) => (Path [Basic s], "")  | 
| 15570 | 143  | 
| (cs, e) => (Path [Basic (implode (Library.take (length cs - 1, cs)))], implode e)));  | 
| 6319 | 144  | 
|
| 6183 | 145  | 
|
| 17827 | 146  | 
(* expand variables *)  | 
| 5011 | 147  | 
|
| 17827 | 148  | 
fun eval (Variable s) =  | 
149  | 
(case getenv s of  | 
|
150  | 
      "" => error ("Undefined Isabelle environment variable: " ^ quote s)
 | 
|
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
151  | 
| path => rep (explode_path path))  | 
| 17827 | 152  | 
| eval x = [x];  | 
| 5011 | 153  | 
|
| 
19482
 
9f11af8f7ef9
tuned basic list operators (flat, maps, map_filter);
 
wenzelm 
parents: 
19305 
diff
changeset
 | 
154  | 
val expand = rep #> maps eval #> norm #> Path;  | 
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
155  | 
|
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
156  | 
|
| 26881 | 157  | 
(* source position *)  | 
158  | 
||
159  | 
val position = Position.file o implode_path o expand;  | 
|
160  | 
||
161  | 
||
| 
21858
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
162  | 
(*final declarations of this structure!*)  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
163  | 
val implode = implode_path;  | 
| 
 
05f57309170c
avoid conflict with Alice keywords: renamed pack -> implode, unpack -> explode, any -> many, avoided assert;
 
wenzelm 
parents: 
19482 
diff
changeset
 | 
164  | 
val explode = explode_path;  | 
| 5011 | 165  | 
|
166  | 
end;  |