23 Bytes, |
23 Bytes, |
24 make, unmake, pack, unpack, |
24 make, unmake, pack, unpack, |
25 empty, null, length, index, all, any, |
25 empty, null, length, index, all, any, |
26 head, last, take, drop, isPrefixOf, isSuffixOf, |
26 head, last, take, drop, isPrefixOf, isSuffixOf, |
27 concat, space, spaces, singleton, char, byte, |
27 concat, space, spaces, singleton, char, byte, |
28 trim_line, space_explode, split_lines |
28 trim_line |
29 ) |
29 ) |
30 where |
30 where |
31 |
31 |
32 import Prelude hiding (null, length, all, any, head, last, take, drop, concat) |
32 import Prelude hiding (null, length, all, any, head, last, take, drop, concat) |
33 |
33 |
128 else if n >= 1 && (at (n - 1) == '\r' || at (n - 1) == '\n') then take (n - 1) s |
128 else if n >= 1 && (at (n - 1) == '\r' || at (n - 1) == '\n') then take (n - 1) s |
129 else s |
129 else s |
130 where |
130 where |
131 n = length s |
131 n = length s |
132 at = char . index s |
132 at = char . index s |
133 |
|
134 space_explode :: Word8 -> Bytes -> [Bytes] |
|
135 space_explode sep str = |
|
136 if null str then [] |
|
137 else if all (/= sep) str then [str] |
|
138 else explode (unpack str) |
|
139 where |
|
140 explode rest = |
|
141 case span (/= sep) rest of |
|
142 (_, []) -> [pack rest] |
|
143 (prfx, _ : rest') -> pack prfx : explode rest' |
|
144 |
|
145 split_lines :: Bytes -> [Bytes] |
|
146 split_lines = space_explode (byte '\n') |
|
147 \<close> |
133 \<close> |
148 |
134 |
149 generate_file "Isabelle/UTF8.hs" = \<open> |
135 generate_file "Isabelle/UTF8.hs" = \<open> |
150 {- Title: Isabelle/UTF8.hs |
136 {- Title: Isabelle/UTF8.hs |
151 Author: Makarius |
137 Author: Makarius |
248 where |
234 where |
249 |
235 |
250 import qualified Data.Text as Text |
236 import qualified Data.Text as Text |
251 import Data.Text (Text) |
237 import Data.Text (Text) |
252 import qualified Data.Text.Lazy as Lazy |
238 import qualified Data.Text.Lazy as Lazy |
|
239 import GHC.Exts (IsList, Item) |
253 import Data.String (IsString) |
240 import Data.String (IsString) |
254 import qualified Data.List.Split as Split |
241 import qualified Data.List.Split as Split |
255 import qualified Isabelle.Symbol as Symbol |
242 import qualified Isabelle.Symbol as Symbol |
|
243 import qualified Isabelle.Bytes as Bytes |
256 import Isabelle.Bytes (Bytes) |
244 import Isabelle.Bytes (Bytes) |
257 import qualified Isabelle.UTF8 as UTF8 |
245 import qualified Isabelle.UTF8 as UTF8 |
258 |
246 |
259 |
247 |
260 {- functions -} |
248 {- functions -} |
316 separate _ xs = xs; |
304 separate _ xs = xs; |
317 |
305 |
318 |
306 |
319 {- string-like interfaces -} |
307 {- string-like interfaces -} |
320 |
308 |
321 class (IsString a, Monoid a, Eq a, Ord a) => StringLike a |
309 class (IsList a, IsString a, Monoid a, Eq a, Ord a) => StringLike a |
322 instance StringLike String |
310 where |
323 instance StringLike Text |
311 space_explode :: Item a -> a -> [a] |
324 instance StringLike Lazy.Text |
312 split_lines :: a -> [a] |
325 instance StringLike Bytes |
313 |
|
314 instance StringLike String where |
|
315 space_explode sep = Split.split (Split.dropDelims (Split.whenElt (== sep))) |
|
316 split_lines = space_explode '\n' |
|
317 |
|
318 instance StringLike Text where |
|
319 space_explode sep str = |
|
320 if Text.null str then [] |
|
321 else if Text.all (/= sep) str then [str] |
|
322 else map Text.pack $ space_explode sep $ Text.unpack str |
|
323 split_lines = space_explode '\n' |
|
324 |
|
325 instance StringLike Lazy.Text where |
|
326 space_explode sep str = |
|
327 if Lazy.null str then [] |
|
328 else if Lazy.all (/= sep) str then [str] |
|
329 else map Lazy.pack $ space_explode sep $ Lazy.unpack str |
|
330 split_lines = space_explode '\n' |
|
331 |
|
332 instance StringLike Bytes where |
|
333 space_explode sep str = |
|
334 if Bytes.null str then [] |
|
335 else if Bytes.all (/= sep) str then [str] |
|
336 else explode (Bytes.unpack str) |
|
337 where |
|
338 explode rest = |
|
339 case span (/= sep) rest of |
|
340 (_, []) -> [Bytes.pack rest] |
|
341 (prfx, _ : rest') -> Bytes.pack prfx : explode rest' |
|
342 split_lines = space_explode (Bytes.byte '\n') |
326 |
343 |
327 class StringLike a => STRING a where make_string :: a -> String |
344 class StringLike a => STRING a where make_string :: a -> String |
328 instance STRING String where make_string = id |
345 instance STRING String where make_string = id |
329 instance STRING Text where make_string = Text.unpack |
346 instance STRING Text where make_string = Text.unpack |
330 instance STRING Lazy.Text where make_string = Lazy.unpack |
347 instance STRING Lazy.Text where make_string = Lazy.unpack |
364 commas = space_implode ", " |
381 commas = space_implode ", " |
365 commas_quote = commas . map quote |
382 commas_quote = commas . map quote |
366 |
383 |
367 cat_lines :: StringLike a => [a] -> a |
384 cat_lines :: StringLike a => [a] -> a |
368 cat_lines = space_implode "\n" |
385 cat_lines = space_implode "\n" |
369 |
|
370 |
|
371 space_explode :: Char -> String -> [String] |
|
372 space_explode c = Split.split (Split.dropDelims (Split.whenElt (== c))) |
|
373 |
|
374 split_lines :: String -> [String] |
|
375 split_lines = space_explode '\n' |
|
376 |
386 |
377 trim_line :: String -> String |
387 trim_line :: String -> String |
378 trim_line line = |
388 trim_line line = |
379 if not (null line) && Symbol.is_ascii_line_terminator (last line) then |
389 if not (null line) && Symbol.is_ascii_line_terminator (last line) then |
380 case reverse line of |
390 case reverse line of |
1716 keyword1, keyword2 :: BYTES a => a -> T |
1726 keyword1, keyword2 :: BYTES a => a -> T |
1717 keyword1 name = mark_str (Markup.keyword1, name) |
1727 keyword1 name = mark_str (Markup.keyword1, name) |
1718 keyword2 name = mark_str (Markup.keyword2, name) |
1728 keyword2 name = mark_str (Markup.keyword2, name) |
1719 |
1729 |
1720 text :: BYTES a => a -> [T] |
1730 text :: BYTES a => a -> [T] |
1721 text = breaks . map str . filter (not . Bytes.null) . Bytes.space_explode Bytes.space . make_bytes |
1731 text = breaks . map str . filter (not . Bytes.null) . space_explode Bytes.space . make_bytes |
1722 |
1732 |
1723 paragraph :: [T] -> T |
1733 paragraph :: [T] -> T |
1724 paragraph = markup Markup.paragraph |
1734 paragraph = markup Markup.paragraph |
1725 |
1735 |
1726 para :: BYTES a => a -> T |
1736 para :: BYTES a => a -> T |
2467 write_message socket = write socket . make_message |
2477 write_message socket = write socket . make_message |
2468 |
2478 |
2469 parse_header :: Bytes -> [Int] |
2479 parse_header :: Bytes -> [Int] |
2470 parse_header line = |
2480 parse_header line = |
2471 let |
2481 let |
2472 res = map Value.parse_nat (Bytes.space_explode (Bytes.byte ',') line) |
2482 res = map Value.parse_nat (space_explode (Bytes.byte ',') line) |
2473 in |
2483 in |
2474 if all isJust res then map fromJust res |
2484 if all isJust res then map fromJust res |
2475 else error ("Malformed message header: " <> quote (UTF8.decode line)) |
2485 else error ("Malformed message header: " <> quote (UTF8.decode line)) |
2476 |
2486 |
2477 read_chunk :: Socket -> Int -> IO Bytes |
2487 read_chunk :: Socket -> Int -> IO Bytes |