module UCD.Parser.UnicodeData (
GeneralCategory (..),
DecompositionType (..),
Decomposition (..),
Entry (..),
NumericValue (..),
CharDetails (..),
parse,
) where
import Data.ByteString qualified as B
import Data.ByteString.Char8 qualified as B8
import Data.ByteString.Short qualified as BS
import Data.List qualified as L
import Data.Ratio ((%))
import Data.Word (Word8)
import UCD.Parser.Common (
UnicodeRange (..),
readCodePoint,
readCodePointM,
pattern Comma,
pattern NewLine,
pattern SemiColon,
pattern Slash,
)
data GeneralCategory
=
Lu
|
Ll
|
Lt
|
Lm
|
Lo
|
Mn
|
Mc
|
Me
|
Nd
|
Nl
|
No
|
Pc
|
Pd
|
Ps
|
Pe
|
Pi
|
Pf
|
Po
|
Sm
|
Sc
|
Sk
|
So
|
Zs
|
Zl
|
Zp
|
Cc
|
Cf
|
Cs
|
Co
|
Cn
deriving (GeneralCategory
GeneralCategory -> GeneralCategory -> Bounded GeneralCategory
forall a. a -> a -> Bounded a
$cminBound :: GeneralCategory
minBound :: GeneralCategory
$cmaxBound :: GeneralCategory
maxBound :: GeneralCategory
Bounded, Int -> GeneralCategory
GeneralCategory -> Int
GeneralCategory -> [GeneralCategory]
GeneralCategory -> GeneralCategory
GeneralCategory -> GeneralCategory -> [GeneralCategory]
GeneralCategory
-> GeneralCategory -> GeneralCategory -> [GeneralCategory]
(GeneralCategory -> GeneralCategory)
-> (GeneralCategory -> GeneralCategory)
-> (Int -> GeneralCategory)
-> (GeneralCategory -> Int)
-> (GeneralCategory -> [GeneralCategory])
-> (GeneralCategory -> GeneralCategory -> [GeneralCategory])
-> (GeneralCategory -> GeneralCategory -> [GeneralCategory])
-> (GeneralCategory
-> GeneralCategory -> GeneralCategory -> [GeneralCategory])
-> Enum GeneralCategory
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: GeneralCategory -> GeneralCategory
succ :: GeneralCategory -> GeneralCategory
$cpred :: GeneralCategory -> GeneralCategory
pred :: GeneralCategory -> GeneralCategory
$ctoEnum :: Int -> GeneralCategory
toEnum :: Int -> GeneralCategory
$cfromEnum :: GeneralCategory -> Int
fromEnum :: GeneralCategory -> Int
$cenumFrom :: GeneralCategory -> [GeneralCategory]
enumFrom :: GeneralCategory -> [GeneralCategory]
$cenumFromThen :: GeneralCategory -> GeneralCategory -> [GeneralCategory]
enumFromThen :: GeneralCategory -> GeneralCategory -> [GeneralCategory]
$cenumFromTo :: GeneralCategory -> GeneralCategory -> [GeneralCategory]
enumFromTo :: GeneralCategory -> GeneralCategory -> [GeneralCategory]
$cenumFromThenTo :: GeneralCategory
-> GeneralCategory -> GeneralCategory -> [GeneralCategory]
enumFromThenTo :: GeneralCategory
-> GeneralCategory -> GeneralCategory -> [GeneralCategory]
Enum, GeneralCategory -> GeneralCategory -> Bool
(GeneralCategory -> GeneralCategory -> Bool)
-> (GeneralCategory -> GeneralCategory -> Bool)
-> Eq GeneralCategory
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: GeneralCategory -> GeneralCategory -> Bool
== :: GeneralCategory -> GeneralCategory -> Bool
$c/= :: GeneralCategory -> GeneralCategory -> Bool
/= :: GeneralCategory -> GeneralCategory -> Bool
Eq, Int -> GeneralCategory -> ShowS
[GeneralCategory] -> ShowS
GeneralCategory -> [Char]
(Int -> GeneralCategory -> ShowS)
-> (GeneralCategory -> [Char])
-> ([GeneralCategory] -> ShowS)
-> Show GeneralCategory
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> GeneralCategory -> ShowS
showsPrec :: Int -> GeneralCategory -> ShowS
$cshow :: GeneralCategory -> [Char]
show :: GeneralCategory -> [Char]
$cshowList :: [GeneralCategory] -> ShowS
showList :: [GeneralCategory] -> ShowS
Show, ReadPrec [GeneralCategory]
ReadPrec GeneralCategory
Int -> ReadS GeneralCategory
ReadS [GeneralCategory]
(Int -> ReadS GeneralCategory)
-> ReadS [GeneralCategory]
-> ReadPrec GeneralCategory
-> ReadPrec [GeneralCategory]
-> Read GeneralCategory
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS GeneralCategory
readsPrec :: Int -> ReadS GeneralCategory
$creadList :: ReadS [GeneralCategory]
readList :: ReadS [GeneralCategory]
$creadPrec :: ReadPrec GeneralCategory
readPrec :: ReadPrec GeneralCategory
$creadListPrec :: ReadPrec [GeneralCategory]
readListPrec :: ReadPrec [GeneralCategory]
Read)
data DecompositionType
= DTCanonical
| DTCompat
| DTFont
| DTNoBreak
| DTInitial
| DTMedial
| DTFinal
| DTIsolated
| DTCircle
| DTSuper
| DTSub
| DTVertical
| DTWide
| DTNarrow
| DTSmall
| DTSquare
| DTFraction
deriving (Int -> DecompositionType -> ShowS
[DecompositionType] -> ShowS
DecompositionType -> [Char]
(Int -> DecompositionType -> ShowS)
-> (DecompositionType -> [Char])
-> ([DecompositionType] -> ShowS)
-> Show DecompositionType
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DecompositionType -> ShowS
showsPrec :: Int -> DecompositionType -> ShowS
$cshow :: DecompositionType -> [Char]
show :: DecompositionType -> [Char]
$cshowList :: [DecompositionType] -> ShowS
showList :: [DecompositionType] -> ShowS
Show, DecompositionType -> DecompositionType -> Bool
(DecompositionType -> DecompositionType -> Bool)
-> (DecompositionType -> DecompositionType -> Bool)
-> Eq DecompositionType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DecompositionType -> DecompositionType -> Bool
== :: DecompositionType -> DecompositionType -> Bool
$c/= :: DecompositionType -> DecompositionType -> Bool
/= :: DecompositionType -> DecompositionType -> Bool
Eq)
data Decomposition
= Self
| Decomposition !DecompositionType ![Char]
deriving (Int -> Decomposition -> ShowS
[Decomposition] -> ShowS
Decomposition -> [Char]
(Int -> Decomposition -> ShowS)
-> (Decomposition -> [Char])
-> ([Decomposition] -> ShowS)
-> Show Decomposition
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Decomposition -> ShowS
showsPrec :: Int -> Decomposition -> ShowS
$cshow :: Decomposition -> [Char]
show :: Decomposition -> [Char]
$cshowList :: [Decomposition] -> ShowS
showList :: [Decomposition] -> ShowS
Show, Decomposition -> Decomposition -> Bool
(Decomposition -> Decomposition -> Bool)
-> (Decomposition -> Decomposition -> Bool) -> Eq Decomposition
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Decomposition -> Decomposition -> Bool
== :: Decomposition -> Decomposition -> Bool
$c/= :: Decomposition -> Decomposition -> Bool
/= :: Decomposition -> Decomposition -> Bool
Eq)
data NumericValue
= NotNumeric
| Digit !Word8
| Integer !Integer
| Rational !Rational
deriving (NumericValue -> NumericValue -> Bool
(NumericValue -> NumericValue -> Bool)
-> (NumericValue -> NumericValue -> Bool) -> Eq NumericValue
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NumericValue -> NumericValue -> Bool
== :: NumericValue -> NumericValue -> Bool
$c/= :: NumericValue -> NumericValue -> Bool
/= :: NumericValue -> NumericValue -> Bool
Eq, Int -> NumericValue -> ShowS
[NumericValue] -> ShowS
NumericValue -> [Char]
(Int -> NumericValue -> ShowS)
-> (NumericValue -> [Char])
-> ([NumericValue] -> ShowS)
-> Show NumericValue
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NumericValue -> ShowS
showsPrec :: Int -> NumericValue -> ShowS
$cshow :: NumericValue -> [Char]
show :: NumericValue -> [Char]
$cshowList :: [NumericValue] -> ShowS
showList :: [NumericValue] -> ShowS
Show)
data CharDetails
= CharDetails
{ CharDetails -> GeneralCategory
_generalCategory ∷ !GeneralCategory
, CharDetails -> Int
_combiningClass ∷ !Int
, CharDetails -> Decomposition
_decomposition ∷ !Decomposition
, CharDetails -> NumericValue
_numericValue ∷ !NumericValue
, CharDetails -> Maybe Char
_simpleUpperCaseMapping ∷ !(Maybe Char)
, CharDetails -> Maybe Char
_simpleLowerCaseMapping ∷ !(Maybe Char)
, CharDetails -> Maybe Char
_simpleTitleCaseMapping ∷ !(Maybe Char)
}
deriving (CharDetails -> CharDetails -> Bool
(CharDetails -> CharDetails -> Bool)
-> (CharDetails -> CharDetails -> Bool) -> Eq CharDetails
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CharDetails -> CharDetails -> Bool
== :: CharDetails -> CharDetails -> Bool
$c/= :: CharDetails -> CharDetails -> Bool
/= :: CharDetails -> CharDetails -> Bool
Eq, Int -> CharDetails -> ShowS
[CharDetails] -> ShowS
CharDetails -> [Char]
(Int -> CharDetails -> ShowS)
-> (CharDetails -> [Char])
-> ([CharDetails] -> ShowS)
-> Show CharDetails
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CharDetails -> ShowS
showsPrec :: Int -> CharDetails -> ShowS
$cshow :: CharDetails -> [Char]
show :: CharDetails -> [Char]
$cshowList :: [CharDetails] -> ShowS
showList :: [CharDetails] -> ShowS
Show)
data Entry = Entry
{ Entry -> UnicodeRange ShortByteString
_range ∷ !(UnicodeRange BS.ShortByteString)
, Entry -> CharDetails
_details ∷ !CharDetails
}
deriving (Entry -> Entry -> Bool
(Entry -> Entry -> Bool) -> (Entry -> Entry -> Bool) -> Eq Entry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Entry -> Entry -> Bool
== :: Entry -> Entry -> Bool
$c/= :: Entry -> Entry -> Bool
/= :: Entry -> Entry -> Bool
Eq, Int -> Entry -> ShowS
[Entry] -> ShowS
Entry -> [Char]
(Int -> Entry -> ShowS)
-> (Entry -> [Char]) -> ([Entry] -> ShowS) -> Show Entry
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Entry -> ShowS
showsPrec :: Int -> Entry -> ShowS
$cshow :: Entry -> [Char]
show :: Entry -> [Char]
$cshowList :: [Entry] -> ShowS
showList :: [Entry] -> ShowS
Show)
newtype Name = Name BS.ShortByteString
data PendingUnicodeDataRange
= NoRange
|
FirstCode !BS.ShortByteString !Char !CharDetails
data UnicodeDataAcc = UnicodeDataAcc !B.ByteString !PendingUnicodeDataRange
data RawEntry = Complete !Entry | Incomplete !PendingUnicodeDataRange
parse ∷ B.ByteString → [Entry]
parse :: ByteString -> [Entry]
parse = (UnicodeDataAcc -> Maybe (Entry, UnicodeDataAcc))
-> UnicodeDataAcc -> [Entry]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
L.unfoldr UnicodeDataAcc -> Maybe (Entry, UnicodeDataAcc)
go (UnicodeDataAcc -> [Entry])
-> (ByteString -> UnicodeDataAcc) -> ByteString -> [Entry]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> PendingUnicodeDataRange -> UnicodeDataAcc
`UnicodeDataAcc` PendingUnicodeDataRange
NoRange)
where
go ∷ UnicodeDataAcc → Maybe (Entry, UnicodeDataAcc)
go :: UnicodeDataAcc -> Maybe (Entry, UnicodeDataAcc)
go (UnicodeDataAcc ByteString
raw PendingUnicodeDataRange
pending)
| ByteString -> Bool
B.null ByteString
raw = Maybe (Entry, UnicodeDataAcc)
forall a. Maybe a
Nothing
| Bool
otherwise = case (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
NewLine) ByteString
raw of
(ByteString -> ByteString
B8.strip → ByteString
line, Int -> ByteString -> ByteString
B.drop Int
1 → ByteString
raw')
| ByteString -> Bool
B.null ByteString
line → UnicodeDataAcc -> Maybe (Entry, UnicodeDataAcc)
go (ByteString -> PendingUnicodeDataRange -> UnicodeDataAcc
UnicodeDataAcc ByteString
raw' PendingUnicodeDataRange
pending)
| Bool
otherwise → case PendingUnicodeDataRange -> (Char, Name, CharDetails) -> RawEntry
combine PendingUnicodeDataRange
pending (ByteString -> (Char, Name, CharDetails)
parseDetailedChar ByteString
line) of
Complete Entry
dc → (Entry, UnicodeDataAcc) -> Maybe (Entry, UnicodeDataAcc)
forall a. a -> Maybe a
Just (Entry
dc, ByteString -> PendingUnicodeDataRange -> UnicodeDataAcc
UnicodeDataAcc ByteString
raw' PendingUnicodeDataRange
NoRange)
Incomplete PendingUnicodeDataRange
pending' → UnicodeDataAcc -> Maybe (Entry, UnicodeDataAcc)
go (ByteString -> PendingUnicodeDataRange -> UnicodeDataAcc
UnicodeDataAcc ByteString
raw' PendingUnicodeDataRange
pending')
combine ∷ PendingUnicodeDataRange → (Char, Name, CharDetails) → RawEntry
combine :: PendingUnicodeDataRange -> (Char, Name, CharDetails) -> RawEntry
combine = \case
PendingUnicodeDataRange
NoRange → \(Char
ch, Name ShortByteString
name, CharDetails
dc) → case (Word8 -> Bool)
-> ShortByteString -> (ShortByteString, ShortByteString)
BS.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
Comma) ShortByteString
name of
(ShortByteString
charRange, ShortByteString
suffix) | ShortByteString
suffix ShortByteString -> ShortByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ShortByteString
", First>" → PendingUnicodeDataRange -> RawEntry
Incomplete (ShortByteString -> Char -> CharDetails -> PendingUnicodeDataRange
FirstCode ShortByteString
charRange Char
ch CharDetails
dc)
(ShortByteString, ShortByteString)
_ → Entry -> RawEntry
Complete (UnicodeRange ShortByteString -> CharDetails -> Entry
Entry (Char -> UnicodeRange ShortByteString
forall a. Char -> UnicodeRange a
SingleChar Char
ch) CharDetails
dc)
FirstCode ShortByteString
range1 Char
ch1 CharDetails
dc1 → \(Char
ch2, Name ShortByteString
name, CharDetails
dc2) → case (Word8 -> Bool)
-> ShortByteString -> (ShortByteString, ShortByteString)
BS.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
Comma) ShortByteString
name of
(ShortByteString
range2, ShortByteString
suffix)
| ShortByteString
suffix ShortByteString -> ShortByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ShortByteString
", Last>" →
if ShortByteString
range1 ShortByteString -> ShortByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ShortByteString
range2 Bool -> Bool -> Bool
&& Char
ch1 Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
< Char
ch2
then Entry -> RawEntry
Complete (UnicodeRange ShortByteString -> CharDetails -> Entry
Entry (Char -> Char -> ShortByteString -> UnicodeRange ShortByteString
forall a. Char -> Char -> a -> UnicodeRange a
CharRange Char
ch1 Char
ch2 (Int -> ShortByteString -> ShortByteString
BS.drop Int
1 ShortByteString
range1)) CharDetails
dc1)
else [Char] -> RawEntry
forall a. HasCallStack => [Char] -> a
error ([Char] -> RawEntry) -> [Char] -> RawEntry
forall a b. (a -> b) -> a -> b
$ [Char]
"Cannot create range: incompatible ranges" [Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> (CharDetails, CharDetails) -> [Char]
forall a. Show a => a -> [Char]
show (CharDetails
dc1, CharDetails
dc2)
(ShortByteString, ShortByteString)
_ → [Char] -> RawEntry
forall a. HasCallStack => [Char] -> a
error ([Char] -> RawEntry) -> [Char] -> RawEntry
forall a b. (a -> b) -> a -> b
$ [Char]
"Cannot create range: missing <range, Last> entry corresponding to: " [Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> ShortByteString -> [Char]
forall a. Show a => a -> [Char]
show ShortByteString
range1
parseDetailedChar ∷ B.ByteString → (Char, Name, CharDetails)
parseDetailedChar :: ByteString -> (Char, Name, CharDetails)
parseDetailedChar ByteString
line =
( ByteString -> Char
readCodePoint ByteString
codePoint
, ShortByteString -> Name
Name (ByteString -> ShortByteString
BS.toShort ByteString
name)
, CharDetails
{ _generalCategory :: GeneralCategory
_generalCategory = [Char] -> GeneralCategory
forall a. Read a => [Char] -> a
read (ByteString -> [Char]
B8.unpack ByteString
gc)
, _combiningClass :: Int
_combiningClass = [Char] -> Int
forall a. Read a => [Char] -> a
read (ByteString -> [Char]
B8.unpack ByteString
combining)
, _decomposition :: Decomposition
_decomposition = Decomposition
decomposition
, _numericValue :: NumericValue
_numericValue = NumericValue
numericValue
, _simpleUpperCaseMapping :: Maybe Char
_simpleUpperCaseMapping = ByteString -> Maybe Char
readCodePointM ByteString
sUpper
, _simpleLowerCaseMapping :: Maybe Char
_simpleLowerCaseMapping = ByteString -> Maybe Char
readCodePointM ByteString
sLower
, _simpleTitleCaseMapping :: Maybe Char
_simpleTitleCaseMapping = ByteString -> Maybe Char
readCodePointM ByteString
sTitle
}
)
where
(ByteString
codePoint, ByteString
line1) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) ByteString
line
(ByteString
name, ByteString
line2) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line1)
(ByteString
gc, ByteString
line3) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line2)
(ByteString
combining, ByteString
line4) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line3)
(ByteString
__bidiClass, ByteString
line5) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line4)
(ByteString
rawDecomposition, ByteString
line6) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line5)
decomposition :: Decomposition
decomposition = ByteString -> Decomposition
parseDecomposition ByteString
rawDecomposition
(ByteString
__decimal, ByteString
line7) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line6)
(ByteString
__digit, ByteString
line8) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line7)
(ByteString
numeric, ByteString
line9) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line8)
numericValue :: NumericValue
numericValue = ByteString -> NumericValue
parseNumber ByteString
numeric
(ByteString
__bidiMirrored, ByteString
line10) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line9)
(ByteString
__uni1Name, ByteString
line11) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line10)
(ByteString
__iso, ByteString
line12) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line11)
(ByteString
sUpper, ByteString
line13) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line12)
(ByteString
sLower, ByteString
line14) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
SemiColon) (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line13)
sTitle :: ByteString
sTitle = HasCallStack => ByteString -> ByteString
ByteString -> ByteString
B.tail ByteString
line14
parseDecomposition ∷ B.ByteString → Decomposition
parseDecomposition :: ByteString -> Decomposition
parseDecomposition (ByteString -> [ByteString]
B8.words → [ByteString]
wrds)
| [ByteString] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ByteString]
wrds = Decomposition
Self
| Bool
otherwise = [ByteString] -> Decomposition
go [ByteString]
wrds
where
go :: [ByteString] -> Decomposition
go = \case
[] → [Char] -> Decomposition
forall a. HasCallStack => [Char] -> a
error ([Char]
"parseDecomposition: invalid entry: " [Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> [ByteString] -> [Char]
forall a. Show a => a -> [Char]
show [ByteString]
wrds)
ys :: [ByteString]
ys@(ByteString
x : [ByteString]
xs) → case ByteString -> DecompositionType
parseDecompositionType ByteString
x of
DecompositionType
DTCanonical → DecompositionType -> [Char] -> Decomposition
Decomposition DecompositionType
DTCanonical ([ByteString] -> [Char]
readCodePoints [ByteString]
ys)
DecompositionType
other → DecompositionType -> [Char] -> Decomposition
Decomposition DecompositionType
other ([ByteString] -> [Char]
readCodePoints [ByteString]
xs)
readCodePoints :: [ByteString] -> [Char]
readCodePoints = (ByteString -> Char) -> [ByteString] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> Char
readCodePoint
parseDecompositionType :: ByteString -> DecompositionType
parseDecompositionType = \case
ByteString
"<compat>" → DecompositionType
DTCompat
ByteString
"<circle>" → DecompositionType
DTCircle
ByteString
"<final>" → DecompositionType
DTFinal
ByteString
"<font>" → DecompositionType
DTFont
ByteString
"<fraction>" → DecompositionType
DTFraction
ByteString
"<initial>" → DecompositionType
DTInitial
ByteString
"<isolated>" → DecompositionType
DTIsolated
ByteString
"<medial>" → DecompositionType
DTMedial
ByteString
"<narrow>" → DecompositionType
DTNarrow
ByteString
"<noBreak>" → DecompositionType
DTNoBreak
ByteString
"<small>" → DecompositionType
DTSmall
ByteString
"<square>" → DecompositionType
DTSquare
ByteString
"<sub>" → DecompositionType
DTSub
ByteString
"<super>" → DecompositionType
DTSuper
ByteString
"<vertical>" → DecompositionType
DTVertical
ByteString
"<wide>" → DecompositionType
DTWide
ByteString
_ → DecompositionType
DTCanonical
parseNumber ∷ B.ByteString → NumericValue
parseNumber :: ByteString -> NumericValue
parseNumber ByteString
raw
| ByteString -> Bool
B.null ByteString
raw = NumericValue
NotNumeric
| Word8 -> ByteString -> Bool
B.elem Word8
Slash ByteString
raw = case (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
Slash) ByteString
raw of
(ByteString
num, ByteString
denum) → Rational -> NumericValue
Rational (ByteString -> Integer
readB ByteString
num Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% (ByteString -> Integer
readB (ByteString -> Integer)
-> (ByteString -> ByteString) -> ByteString -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ByteString -> ByteString
B.drop Int
1) ByteString
denum)
where
readB :: ByteString -> Integer
readB = [Char] -> Integer
forall a. Read a => [Char] -> a
read ([Char] -> Integer)
-> (ByteString -> [Char]) -> ByteString -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Char]
B8.unpack
| Bool
otherwise = Integer -> NumericValue
Integer ([Char] -> Integer
forall a. Read a => [Char] -> a
read (ByteString -> [Char]
B8.unpack ByteString
raw))