6118
|
1 |
(* Title: Pure/General/path.ML
|
5011
|
2 |
ID: $Id$
|
|
3 |
Author: Markus Wenzel, TU Muenchen
|
8806
|
4 |
License: GPL (GNU GENERAL PUBLIC LICENSE)
|
5011
|
5 |
|
6183
|
6 |
Abstract algebra of file paths (external encoding Unix-style).
|
5011
|
7 |
*)
|
|
8 |
|
|
9 |
signature PATH =
|
|
10 |
sig
|
6183
|
11 |
datatype elem = Root | Parent | Basic of string | Variable of string
|
|
12 |
eqtype T
|
|
13 |
val rep: T -> elem list
|
6460
|
14 |
val is_current: T -> bool
|
6183
|
15 |
val current: T
|
|
16 |
val root: T
|
|
17 |
val parent: T
|
|
18 |
val basic: string -> T
|
|
19 |
val variable: string -> T
|
|
20 |
val is_absolute: T -> bool
|
|
21 |
val is_basic: T -> bool
|
|
22 |
val append: T -> T -> T
|
6270
|
23 |
val appends: T list -> T
|
6319
|
24 |
val make: string list -> T
|
5011
|
25 |
val pack: T -> string
|
|
26 |
val unpack: string -> T
|
6183
|
27 |
val base: T -> T
|
|
28 |
val ext: string -> T -> T
|
7929
|
29 |
val drop_ext: T -> T
|
6319
|
30 |
val dir: T -> T
|
6183
|
31 |
val expand: T -> T
|
7714
|
32 |
val position: T -> Position.T
|
5011
|
33 |
end;
|
|
34 |
|
6187
|
35 |
structure Path: PATH =
|
5011
|
36 |
struct
|
|
37 |
|
6183
|
38 |
|
|
39 |
(* path elements *)
|
|
40 |
|
|
41 |
datatype elem = Root | Parent | Basic of string | Variable of string;
|
|
42 |
|
6223
|
43 |
fun err_elem msg chs = error (msg ^ " path element specification: " ^ quote (implode chs));
|
6183
|
44 |
|
6319
|
45 |
fun check_elem (chs as []) = err_elem "Illegal" chs
|
|
46 |
| check_elem (chs as ["~"]) = err_elem "Illegal" chs
|
6223
|
47 |
| check_elem (chs as ["~", "~"]) = err_elem "Illegal" chs
|
|
48 |
| check_elem chs =
|
|
49 |
(case ["/", "\\", "$", ":"] inter_string chs of
|
|
50 |
[] => chs
|
|
51 |
| bads => err_elem ("Illegal character(s) " ^ commas_quote bads ^ " in") chs);
|
|
52 |
|
|
53 |
val basic_elem = Basic o implode o check_elem;
|
|
54 |
val variable_elem = Variable o implode o check_elem;
|
6183
|
55 |
|
|
56 |
fun is_var (Variable _) = true
|
|
57 |
| is_var _ = false;
|
|
58 |
|
|
59 |
|
5011
|
60 |
(* type path *)
|
|
61 |
|
6183
|
62 |
datatype T = Path of elem list;
|
|
63 |
|
|
64 |
fun rep (Path xs) = xs;
|
5011
|
65 |
|
6460
|
66 |
fun is_current (Path []) = true
|
|
67 |
| is_current _ = false;
|
|
68 |
|
5011
|
69 |
val current = Path [];
|
6183
|
70 |
val root = Path [Root];
|
|
71 |
val parent = Path [Parent];
|
|
72 |
fun basic s = Path [basic_elem (explode s)];
|
|
73 |
fun variable s = Path [variable_elem (explode s)];
|
5011
|
74 |
|
6183
|
75 |
fun is_absolute (Path (Root :: _)) = true
|
|
76 |
| is_absolute _ = false;
|
5011
|
77 |
|
6183
|
78 |
fun is_basic (Path [Basic _]) = true
|
|
79 |
| is_basic _ = false;
|
5011
|
80 |
|
|
81 |
|
|
82 |
(* append and norm *)
|
|
83 |
|
|
84 |
(*append non-normal path (2n arg) to reversed normal one, result is normal*)
|
|
85 |
fun rev_app xs [] = rev xs
|
6183
|
86 |
| rev_app _ (Root :: ys) = rev_app [Root] ys
|
|
87 |
| rev_app (x :: xs) (Parent :: ys) =
|
|
88 |
if x = Parent orelse is_var x then rev_app (Parent :: x :: xs) ys
|
|
89 |
else if x = Root then rev_app (x :: xs) ys
|
5011
|
90 |
else rev_app xs ys
|
|
91 |
| rev_app xs (y :: ys) = rev_app (y :: xs) ys;
|
|
92 |
|
6183
|
93 |
fun append (Path xs) (Path ys) = Path (rev_app (rev xs) ys);
|
6270
|
94 |
fun appends paths = foldl (uncurry append) (current, paths);
|
6319
|
95 |
val make = appends o map basic;
|
5011
|
96 |
fun norm path = rev_app [] path;
|
|
97 |
|
6183
|
98 |
|
|
99 |
(* pack *)
|
5011
|
100 |
|
6183
|
101 |
fun pack_elem Root = ""
|
|
102 |
| pack_elem Parent = ".."
|
|
103 |
| pack_elem (Basic s) = s
|
|
104 |
| pack_elem (Variable s) = "$" ^ s;
|
5011
|
105 |
|
|
106 |
fun pack (Path []) = "."
|
6183
|
107 |
| pack (Path (Root :: xs)) = "/" ^ space_implode "/" (map pack_elem xs)
|
|
108 |
| pack (Path xs) = space_implode "/" (map pack_elem xs);
|
5011
|
109 |
|
|
110 |
|
6183
|
111 |
(* unpack *)
|
|
112 |
|
|
113 |
fun unpack_elem "" = Root
|
|
114 |
| unpack_elem ".." = Parent
|
|
115 |
| unpack_elem "~" = Variable "HOME"
|
|
116 |
| unpack_elem "~~" = Variable "ISABELLE_HOME"
|
|
117 |
| unpack_elem s =
|
|
118 |
(case explode s of
|
|
119 |
"$" :: cs => variable_elem cs
|
|
120 |
| cs => basic_elem cs);
|
|
121 |
|
|
122 |
val unpack_elems = map unpack_elem o filter_out (equal "" orf equal ".");
|
|
123 |
|
|
124 |
fun unpack str = Path (norm
|
|
125 |
(case space_explode "/" str of
|
|
126 |
"" :: ss => Root :: unpack_elems ss
|
|
127 |
| ss => unpack_elems ss));
|
|
128 |
|
5011
|
129 |
|
6183
|
130 |
(* base element *)
|
|
131 |
|
7929
|
132 |
fun split_path f (path as Path xs) =
|
|
133 |
(case try split_last xs of
|
|
134 |
Some (prfx, Basic s) => f (prfx, s)
|
|
135 |
| _ => error ("Cannot split path into dir/base: " ^ quote (pack path)));
|
6183
|
136 |
|
7929
|
137 |
val base = split_path (fn (_, s) => Path [Basic s]);
|
6183
|
138 |
|
7929
|
139 |
fun ext "" path = path
|
|
140 |
| ext e path = split_path (fn (prfx, s) => append (Path prfx) (basic (s ^ "." ^ e))) path;
|
6183
|
141 |
|
7929
|
142 |
val drop_ext = split_path (fn (prfx, s) => append (Path prfx)
|
|
143 |
(case take_suffix (not_equal ".") (explode s) of
|
|
144 |
([], _) => Path [Basic s]
|
|
145 |
| (cs, _) => Path [Basic (implode (take (length cs - 1, cs)))]));
|
|
146 |
|
|
147 |
val dir = split_path (fn (prfx, _) => Path prfx);
|
6319
|
148 |
|
6183
|
149 |
|
|
150 |
(* evaluate variables *)
|
|
151 |
|
|
152 |
fun eval env (Variable s) = rep (env s)
|
|
153 |
| eval _ x = [x];
|
5011
|
154 |
|
|
155 |
fun evaluate env (Path xs) =
|
|
156 |
Path (norm (flat (map (eval env) xs)));
|
|
157 |
|
6183
|
158 |
val expand = evaluate (unpack o getenv);
|
5011
|
159 |
|
7714
|
160 |
val position = Position.line_name 1 o quote o pack o expand;
|
|
161 |
|
5011
|
162 |
|
|
163 |
end;
|