Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / mlton / basic / string0.sml
CommitLineData
7f918cf1
CE
1(* Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 *
4 * MLton is released under a BSD-style license.
5 * See the file MLton-LICENSE for details.
6 *)
7
8structure String0 =
9struct
10
11structure PInt = Pervasive.Int
12type int = PInt.int
13structure PS = Pervasive.String
14local
15 open PS
16in
17 val op ^ = op ^
18 val concat = concat
19 val concatWith = fn (ss,s) => concatWith s ss
20 val escapeC = toCString
21 val escapeSML = toString
22 val explode = explode
23 val extract = extract
24 val fromCString = fromCString
25 val fromString = fromString
26 val implode = implode
27 val maxLength = maxSize
28 val size = size
29 val sub = sub
30 val substring = substring
31end
32structure Char = Char0
33
34type t = string
35
36val empty = ""
37
38val dquote = "\""
39val newline = "\n"
40val lparen = "("
41val rparen = ")"
42
43val isEmpty =
44 fn "" => true
45 | _ => false
46
47val length = size
48
49fun last s = sub (s, length s - 1)
50
51fun append (x, y) = x ^ y
52
53fun toChar s = if length s = 1 then sub (s, 0) else Error.bug "String0.toChar"
54
55val fromChar = str
56
57fun contains (s, c) = Pervasive.Char.contains s c
58
59val equals: t * t -> bool = op =
60
61val {compare, min, max, ...} = Relation0.lessEqual {< = PS.<, equals = equals}
62
63fun output (s, out) = Pervasive.TextIO.output (out, s)
64
65val tabulate = CharVector.tabulate
66
67fun make (n, c) = tabulate (n, fn _ => c)
68
69fun substring1 (s, {start, length}) =
70 substring (s, start, length)
71
72fun substring2 (s, {start, finish}) =
73 substring (s, start, finish-start)
74
75fun prefix (s, len) =
76 substring1 (s, {start = 0, length = len})
77
78fun suffix (s, len) =
79 substring1 (s, {start = length s - len,
80 length = len})
81
82fun dropPrefix (s,n) =
83 substring1 (s, {start=n, length = length s - n})
84fun dropSuffix (s,n) =
85 substring1 (s, {start=0, length = length s - n})
86
87fun dropFirst s = dropPrefix (s, 1)
88fun dropLast s = dropSuffix (s, 1)
89
90fun dropPrefix (s, n) =
91 substring2 (s, {start = n, finish = length s})
92
93fun hasPrefix (string, {prefix}) = PS.isPrefix prefix string
94
95fun removeTrailing (s: t, p: char -> bool): t =
96 let
97 fun loop (i: int) =
98 if i < 0
99 then i
100 else if p (sub (s, i))
101 then loop (i - 1)
102 else i
103 in substring (s, 0, 1 + (loop (size s - 1)))
104 end
105
106fun hasSuffix (string, {suffix}) =
107 let
108 val n = length string
109 val n' = length suffix
110 fun loop (i: int, j: int): bool =
111 i >= n orelse (Char.equals (sub (string, i), sub (suffix, j))
112 andalso loop (i + 1, j + 1))
113 in n' <= n andalso loop (n - n', 0)
114 end
115
116fun findSubstring (string: t, {substring: t}) =
117 let
118 val n = length substring
119 val maxIndex = length string - n
120 fun loopString i =
121 if i > maxIndex
122 then NONE
123 else
124 let
125 val start = i
126 fun loopSubstring (i, j) =
127 if j >= n
128 then SOME start
129 else
130 if Char.equals (sub (string, i), sub (substring, j))
131 then loopSubstring (i + 1, j + 1)
132 else loopString (i + 1)
133 in
134 loopSubstring (i, 0)
135 end
136 in
137 loopString 0
138 end
139
140val hasSubstring = isSome o findSubstring
141
142fun baseName (x, y) =
143 if hasSuffix (x, {suffix = y})
144 then dropSuffix (x, size y)
145 else Error.bug "String0.baseName"
146
147fun fold (s, b, f) =
148 let
149 val n = size s
150 fun loop (i, b) =
151 if i >= n
152 then b
153 else loop (i + 1, f (sub (s, i), b))
154 in loop (0, b)
155 end
156
157fun translate (s, f) = PS.translate f s
158
159fun tokens (s, f) = PS.tokens f s
160fun fields (s, f) = PS.fields f s
161
162fun split (s, c) = fields (s, fn c' => c = c')
163
164fun dropTrailing (s, c) =
165 let
166 val n = size s
167 fun loop i =
168 if PInt.< (i, 0) orelse c <> sub (s, i)
169 then i
170 else loop (i - 1)
171 in dropSuffix (s, n - 1 - loop (n - 1))
172 end
173
174fun translateChar (s, f) = translate (s, fromChar o f)
175
176fun toUpper s = translateChar (s, Char.toUpper)
177fun toLower s = translateChar (s, Char.toLower)
178
179fun sort (l, f) =
180 let
181 fun loop l =
182 case l of
183 [] => []
184 | x :: l =>
185 let
186 fun loop' l =
187 case l of
188 [] => [x]
189 | x' :: l => if f (x, x')
190 then x :: x' :: l
191 else x' :: loop' l
192 in loop' (loop l)
193 end
194 in loop l
195 end
196
197fun alphabetize s = implode (sort (explode s, Char.<))
198
199fun fromCharArray (a: CharArray.array): t =
200 CharVector.tabulate (CharArray.length a, fn i => CharArray.sub (a, i))
201
202fun toString s = s
203
204fun a / b = concat [a, "/", b]
205
206local
207 open PS
208in
209 val op <= = op <=
210 val op < = op <
211 val op >= = op >=
212 val op > = op >
213end
214
215fun rev (s: t): t =
216 let
217 val n = size s
218 val n1 = n - 1
219 in
220 CharVector.tabulate (n, fn i => sub (s, n1 - i))
221 end
222
223val fromListRev = rev o implode
224
225end