Commit | Line | Data |
---|---|---|
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 | ||
8 | structure String0 = | |
9 | struct | |
10 | ||
11 | structure PInt = Pervasive.Int | |
12 | type int = PInt.int | |
13 | structure PS = Pervasive.String | |
14 | local | |
15 | open PS | |
16 | in | |
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 | |
31 | end | |
32 | structure Char = Char0 | |
33 | ||
34 | type t = string | |
35 | ||
36 | val empty = "" | |
37 | ||
38 | val dquote = "\"" | |
39 | val newline = "\n" | |
40 | val lparen = "(" | |
41 | val rparen = ")" | |
42 | ||
43 | val isEmpty = | |
44 | fn "" => true | |
45 | | _ => false | |
46 | ||
47 | val length = size | |
48 | ||
49 | fun last s = sub (s, length s - 1) | |
50 | ||
51 | fun append (x, y) = x ^ y | |
52 | ||
53 | fun toChar s = if length s = 1 then sub (s, 0) else Error.bug "String0.toChar" | |
54 | ||
55 | val fromChar = str | |
56 | ||
57 | fun contains (s, c) = Pervasive.Char.contains s c | |
58 | ||
59 | val equals: t * t -> bool = op = | |
60 | ||
61 | val {compare, min, max, ...} = Relation0.lessEqual {< = PS.<, equals = equals} | |
62 | ||
63 | fun output (s, out) = Pervasive.TextIO.output (out, s) | |
64 | ||
65 | val tabulate = CharVector.tabulate | |
66 | ||
67 | fun make (n, c) = tabulate (n, fn _ => c) | |
68 | ||
69 | fun substring1 (s, {start, length}) = | |
70 | substring (s, start, length) | |
71 | ||
72 | fun substring2 (s, {start, finish}) = | |
73 | substring (s, start, finish-start) | |
74 | ||
75 | fun prefix (s, len) = | |
76 | substring1 (s, {start = 0, length = len}) | |
77 | ||
78 | fun suffix (s, len) = | |
79 | substring1 (s, {start = length s - len, | |
80 | length = len}) | |
81 | ||
82 | fun dropPrefix (s,n) = | |
83 | substring1 (s, {start=n, length = length s - n}) | |
84 | fun dropSuffix (s,n) = | |
85 | substring1 (s, {start=0, length = length s - n}) | |
86 | ||
87 | fun dropFirst s = dropPrefix (s, 1) | |
88 | fun dropLast s = dropSuffix (s, 1) | |
89 | ||
90 | fun dropPrefix (s, n) = | |
91 | substring2 (s, {start = n, finish = length s}) | |
92 | ||
93 | fun hasPrefix (string, {prefix}) = PS.isPrefix prefix string | |
94 | ||
95 | fun 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 | ||
106 | fun 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 | ||
116 | fun 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 | ||
140 | val hasSubstring = isSome o findSubstring | |
141 | ||
142 | fun baseName (x, y) = | |
143 | if hasSuffix (x, {suffix = y}) | |
144 | then dropSuffix (x, size y) | |
145 | else Error.bug "String0.baseName" | |
146 | ||
147 | fun 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 | ||
157 | fun translate (s, f) = PS.translate f s | |
158 | ||
159 | fun tokens (s, f) = PS.tokens f s | |
160 | fun fields (s, f) = PS.fields f s | |
161 | ||
162 | fun split (s, c) = fields (s, fn c' => c = c') | |
163 | ||
164 | fun 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 | ||
174 | fun translateChar (s, f) = translate (s, fromChar o f) | |
175 | ||
176 | fun toUpper s = translateChar (s, Char.toUpper) | |
177 | fun toLower s = translateChar (s, Char.toLower) | |
178 | ||
179 | fun 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 | ||
197 | fun alphabetize s = implode (sort (explode s, Char.<)) | |
198 | ||
199 | fun fromCharArray (a: CharArray.array): t = | |
200 | CharVector.tabulate (CharArray.length a, fn i => CharArray.sub (a, i)) | |
201 | ||
202 | fun toString s = s | |
203 | ||
204 | fun a / b = concat [a, "/", b] | |
205 | ||
206 | local | |
207 | open PS | |
208 | in | |
209 | val op <= = op <= | |
210 | val op < = op < | |
211 | val op >= = op >= | |
212 | val op > = op > | |
213 | end | |
214 | ||
215 | fun 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 | ||
223 | val fromListRev = rev o implode | |
224 | ||
225 | end |