Source file path.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
type token =
| Empty
| DotDot
| String of string
let rec tokenise = function
| [] -> []
| ["."] -> [Empty]
| "." :: xs -> tokenise xs
| "" :: xs -> Empty :: tokenise xs
| ".." :: xs -> DotDot :: tokenise xs
| x :: xs -> String x :: tokenise xs
module Rel = struct
type t =
| Leaf of { basename : string; trailing_slash : bool }
| Self
| Child of string * t
| Parent of t
let rec parse = function
| [] -> Self
| [String basename; Empty] -> Leaf { basename; trailing_slash = true }
| [String basename] -> Leaf { basename; trailing_slash = false }
| [DotDot] -> Parent Self
| DotDot :: xs -> Parent (parse xs)
| String s :: xs -> Child (s, parse xs)
| Empty :: xs -> parse xs
let parse s = parse (tokenise s)
let rec concat a b =
match a with
| Leaf { basename; trailing_slash = _ } -> Child (basename, b)
| Child (name, xs) -> Child (name, concat xs b)
| Parent xs -> Parent (concat xs b)
| Self -> b
let rec dump f = function
| Child (x, xs) -> Fmt.pf f "%S / %a" x dump xs
| Parent xs -> Fmt.pf f ".. / %a" dump xs
| Self -> Fmt.pf f "."
| Leaf { basename; trailing_slash } ->
Fmt.pf f "%S" basename;
if trailing_slash then Fmt.pf f " /"
let rec segs = function
| Leaf { basename; trailing_slash } -> [if trailing_slash then basename ^ "/" else basename]
| Self -> [""]
| Child (x, xs) -> x :: segs xs
| Parent Self -> [".."]
| Parent xs -> ".." :: segs xs
let to_string = function
| Self -> "."
| t -> String.concat "/" (segs t)
end
type t =
| Relative of Rel.t
| Absolute of Rel.t
let rec parse_abs = function
| "" :: [] -> Absolute Self
| "" :: xs -> parse_abs xs
| xs -> Absolute (Rel.parse xs)
let parse = function
| "" -> Relative Self
| s ->
match String.split_on_char '/' s with
| "" :: path -> parse_abs path
| path -> Relative (Rel.parse path)
let dump f = function
| Relative r -> Rel.dump f r
| Absolute r -> Fmt.pf f "/ %a" Rel.dump r
let to_string = function
| Relative r -> Rel.to_string r
| Absolute r -> String.concat "/" ("" :: Rel.segs r)