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 82 83 84 85 86 87
|
#!/usr/bin/env runhaskell
{-# LANGUAGE OverloadedStrings
#-}
module CompileRanges where
import Prelude hiding (concat, lines, unlines, takeWhile)
import Data.List (foldl')
import Data.Char hiding (isDigit)
import Data.Maybe
import Data.Either
import Control.Applicative hiding (empty)
import System.IO (stdin, stdout, stderr)
import Data.ByteString.Char8 hiding (takeWhile, count, foldl', reverse)
import Data.Attoparsec (parseOnly)
import Data.Attoparsec.Char8
main = compile_ranges stdin stdout
compile_ranges i o = do
ranges <- rights . parse' . lines <$> hGetContents i
--sequence_ . (hPut o . display <$>) $ collate ranges
hPut o preamble
(sequence_ . (hPut o . compile <$>) . collate) ranges
hPut o postamble
where
parse' = (parseOnly range <$>)
display ((a,z),w) = a `append` pack ".." `append` z `snoc` '\n'
compile ((a,z),w) = guard `append` eq `append` w `snoc` '\n'
where
guard = pack " | i <= " `append` z
eq = pack " = "
preamble = (unlines . fmap pack) [warning, mod, sig, f]
where
warning = "\n\n-- This file was autogenerated.\n"
mod = "\nmodule Data.Char.Cols.Generated where\n\n"
sig = "cols :: Char -> Int\n"
f = "cols c\n"
postamble = otherwise_clause `append` where_clause
where
otherwise_clause = pack " | otherwise = -1\n"
where_clause = pack " where\n" `append` pack i `snoc` '\n'
where
i = " i = fromEnum c\n"
range = do
start <- short_hex
string ".."
end <- short_hex
some (char ' ')
columns <- little_int
return ((start, end), columns)
short_hex :: Parser ByteString
short_hex = do
ox <- string "0x"
count 4 (char '0')
append ox . pack <$> count 4 (satisfy isHexDigit)
little_int :: Parser ByteString
little_int = do
sign <- maybe empty id <$> optional minus
digits <- takeWhile isDigit
return (append sign digits)
where
minus = string "-"
collate = reverse . foldl' collate' []
where
collate' [] range = [range]
collate' (((a,z),w):t) ((a',z'),w')
| w == w' = ((a,z'),w) : t
| otherwise = ((a',z'),w') : ((a,z),w) : t
|