Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / mlton / basic / reader.sml
1 (* Copyright (C) 2009 Matthew Fluet.
2 * Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 *
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
7 *)
8
9 structure Reader: READER =
10 struct
11
12 type ('a, 's) t = 's -> ('a * 's) option
13
14 fun char(r, c: char) s =
15 case r s of
16 NONE => NONE
17 | SOME(c', s) => if c = c' then SOME((), s) else NONE
18
19 fun or rs s =
20 let
21 val rec loop =
22 fn [] => NONE
23 | r :: rs =>
24 case r s of
25 NONE => loop rs
26 | z => z
27 in loop rs
28 end
29
30 fun all r s =
31 let
32 fun loop(s, ac) =
33 case r s of
34 NONE => SOME(rev ac, s)
35 | SOME(x, s) => loop(s, x :: ac)
36 in loop(s, [])
37 end
38
39 fun firstN(r, n: Int.t) s =
40 let
41 fun loop(n, s, ac) =
42 if n <= 0
43 then SOME(rev ac, s)
44 else (case r s of
45 NONE => NONE
46 | SOME(x, s) => loop(n - 1, s, x :: ac))
47 in loop(n, s, [])
48 end
49
50 fun mapFail(r, f) s =
51 case r s of
52 NONE => NONE
53 | SOME(a, s) => Option.map(f a, fn b => (b, s))
54
55 fun map(r, f) = mapFail(r, SOME o f)
56
57 fun seq2(r1, r2) s =
58 case r1 s of
59 NONE => NONE
60 | SOME(x1, s) =>
61 case r2 s of
62 NONE => NONE
63 | SOME(x2, s) => SOME((x1, x2), s)
64
65
66 fun seq3(r1, r2, r3) s =
67 case r1 s of
68 NONE => NONE
69 | SOME(x1, s) =>
70 case r2 s of
71 NONE => NONE
72 | SOME(x2, s) =>
73 case r3 s of
74 NONE => NONE
75 | SOME(x3, s) => SOME((x1, x2, x3), s)
76
77 fun seq4(r1, r2, r3, r4) s =
78 case seq3(r1, r2, r3) s of
79 NONE => NONE
80 | SOME((x1, x2, x3), s) =>
81 case r4 s of
82 NONE => NONE
83 | SOME(x4, s) => SOME((x1, x2, x3, x4), s)
84
85 fun seq5(r1, r2, r3, r4, r5) s =
86 case seq4(r1, r2, r3, r4) s of
87 NONE => NONE
88 | SOME((x1, x2, x3, x4), s) =>
89 case r5 s of
90 NONE => NONE
91 | SOME(x5, s) => SOME((x1, x2, x3, x4, x5), s)
92
93 fun stringOfLength(r, i: Int.t) s =
94 let
95 fun loop(i, s, cs) =
96 if i <= 0
97 then SOME(implode(rev cs), s)
98 else (case r s of
99 NONE => NONE
100 | SOME(c, s) => loop(i - 1, s, c :: cs))
101 in loop(i, s, [])
102 end
103
104 val info = Trace.info "Reader.readFromString"
105
106 fun readFromString(rm, s) =
107 let val n: Int.t = String.size s
108 fun reader(i: Int.t) =
109 if i < n
110 then SOME(String.sub(s, i), i + 1)
111 else NONE
112 val reader =
113 Trace.traceInfo
114 (info,
115 Int.layout,
116 fn NONE => Layout.str "NONE"
117 | SOME(c, _) => Char.layout c,
118 fn _ => (true, fn _ => true))
119 reader
120 in case rm reader (0: Int.t) of
121 NONE => NONE
122 | SOME(a, i) => if i = n then SOME a else NONE
123 end
124
125 end