unicode-data-names 0.2.0 → 0.3.0
raw patch · 17 files changed
+1728/−495 lines, 17 filesdep +bytestringdep +ghc-primdep +icudep ~basedep ~deepseqdep ~hspec
Dependencies added: bytestring, ghc-prim, icu, text
Dependency ranges changed: base, deepseq, hspec, tasty, unicode-data
Files
- Changelog.md +11/−0
- README.md +17/−1
- bench/Main.hs +243/−35
- lib/Unicode/Char/General/Names.hs +132/−22
- lib/Unicode/Char/General/Names/ByteString.hs +232/−0
- lib/Unicode/Char/General/Names/Text.hs +206/−0
- lib/Unicode/Internal/Bits/Names.hs +73/−0
- lib/Unicode/Internal/Char/Names/Version.hs +20/−0
- lib/Unicode/Internal/Char/UnicodeData/DerivedName.hs too large to diff
- lib/Unicode/Internal/Char/UnicodeData/NameAliases.hs +406/−405
- test/ICU/NamesSpec.hs +110/−0
- test/Main.hs +31/−1
- test/Unicode/Char/General/Names/ByteStringSpec.hs +51/−0
- test/Unicode/Char/General/Names/TextSpec.hs +51/−0
- test/Unicode/Char/General/NamesSpec.hs +54/−3
- test/export_all_chars.hs +5/−7
- unicode-data-names.cabal +86/−21
Changelog.md view
@@ -1,5 +1,16 @@ # Changelog +## 0.3.0 (July 2024)++- Improve performance.+- Added opional support for `ByteString` API.+ Use the package flag `has-bytestring` to enable it.+- Added opional support for `Text` API.+ Use the package flag `has-text` to enable it.+- Add `unicodeVersion` to `Unicode.Char.General.Names`.+- Fix the inlining of `Addr#` literals and reduce their size. This results in+ a sensible decrease of the executable size.+ ## 0.2.0 (September 2022) - Update to [Unicode 15.0.0](https://www.unicode.org/versions/Unicode15.0.0/).
README.md view
@@ -4,6 +4,11 @@ character names and aliases from the [Unicode character database](https://www.unicode.org/ucd/). +There are 3 APIs:+- `String` API: enabled by default.+- `ByteString` API: enabled via the package flag `has-bytestring`.+- `Text` API: enabled via the package flag `has-text`.+ The Haskell data structures are generated programmatically from the Unicode character database (UCD) files. The latest Unicode version supported by this library is@@ -13,6 +18,17 @@ [Haddock documentation](https://hackage.haskell.org/package/unicode-data-names) for reference documentation. +## Comparing with ICU++We can compare the implementation against ICU. This requires working with the+source repository, as we need the _internal_ package `icu`.++__Warning:__ An ICU version with the _exact same Unicode version_ is required.++```bash+cabal run -O2 --flag dev-has-icu unicode-data-names:tests -- -m ICU+```+ ## Comparing with Python In order to check Unicode implementation in Haskell, we compare the results obtained@@ -21,7 +37,7 @@ __Warning:__ A Python version with the _exact same Unicode version_ is required. ```bash-cabal run -f "export-all-chars" -v0 export-all-chars > ./test/all_chars.csv+cabal run -O2 -f "export-all-chars" -v0 export-all-chars > ./test/all_chars.csv python3 ./test/check.py -v ./test/all_chars.csv ```
bench/Main.hs view
@@ -1,60 +1,268 @@-{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE CPP, ExistentialQuantification #-}+{-# OPTIONS_GHC -Wno-orphans #-} -import Control.DeepSeq (NFData, deepseq)+import Control.DeepSeq (NFData, deepseq, force)+import Control.Exception (evaluate) import Data.Ix (Ix(..))-import Test.Tasty.Bench (Benchmark, bgroup, bcompare, bench, nf, defaultMain)+import Data.Proxy (Proxy(..))+import GHC.Exts (Char(..), indexCharOffAddr#)+import Test.Tasty (askOption, includingOptions)+import Test.Tasty.Bench (Benchmark, bgroup, bcompare, bench, benchIngredients, nf, env)+import Test.Tasty.Options+ ( IsOption(defaultValue, optionHelp, optionName, parseValue)+ , OptionDescription(..) )+import Test.Tasty.Runners (TestTree, defaultMainWithIngredients) -import qualified Unicode.Char.General.Names as Names+import qualified Unicode.Char as UChar+import qualified Unicode.Char.General.Names as String import qualified Unicode.Internal.Char.UnicodeData.DerivedName as DerivedName import qualified Unicode.Internal.Char.UnicodeData.NameAliases as NameAliases+#ifdef HAS_BYTESTRING+import qualified Unicode.Char.General.Names.ByteString as ByteString+import Data.ByteString ()+#endif+#ifdef HAS_TEXT+import qualified Unicode.Char.General.Names.Text as Text+import Data.Text ()+#endif+#ifdef HAS_ICU+import qualified ICU.Names as ICUString+#ifdef HAS_TEXT+import qualified ICU.Names.Text as ICUText+#endif+#endif +--------------------------------------------------------------------------------+-- CLI options+--------------------------------------------------------------------------------++data CharRange = CharRange !Char !Char++instance IsOption CharRange where+ defaultValue = CharRange minBound maxBound+ parseValue = \case+ "ascii" -> Just (CharRange minBound '\x7f')+ "bmp" -> Just (CharRange minBound '\xffff')+ "planes0To3" -> Just (CharRange minBound '\x3FFFF')+ -- [TODO] handle errors+ s ->+ let (l, u) = drop 1 <$> break (== '-') s+ in Just (CharRange (UChar.chr (read l)) (UChar.chr (read u)))+ optionName = pure "chars"+ optionHelp = pure "Range of chars to test"++data Filter+ = NoFilter -- ^ No condition+ | WithName -- ^ Char has a name+ | WithNameAlias -- ^ Char has a name alias+ | WithNameOrAlias -- ^ Char has a name or an alias++instance IsOption Filter where+ defaultValue = WithNameOrAlias+ parseValue = \case+ "name" -> Just WithName+ "alias" -> Just WithNameAlias+ "nameOrAlias" -> Just WithNameOrAlias+ "none" -> Just NoFilter+ _ -> Nothing+ optionName = pure "chars-filter"+ optionHelp = pure "Filter the chars to test"++--------------------------------------------------------------------------------+-- Benchmark utils+--------------------------------------------------------------------------------++-- Orphan instance+instance NFData String.NameAliasType+ -- | A unit benchmark data Bench = forall a. (NFData a) => Bench- { _title :: !String -- ^ Name- , _func :: Char -> a -- ^ Function to benchmark- }+ { -- | Name+ _title :: !String+ -- | Function to benchmark+ , _func :: Char -> a } +hasName :: Char -> Bool+hasName (C# c#) = case DerivedName.name c# of+ (# _, 0# #) -> False+ _ -> True++hasNameAlias :: Char -> Bool+hasNameAlias (C# c#) =+ let addr# = NameAliases.nameAliases c#+ in case indexCharOffAddr# addr# 0# of+ '\xff'# -> False+ _ -> True++--------------------------------------------------------------------------------+-- Benchmark+--------------------------------------------------------------------------------+ main :: IO ()-main = defaultMain+main = do+ let customOpts = [ Option (Proxy :: Proxy CharRange)+ , Option (Proxy :: Proxy Filter)]+ ingredients = includingOptions customOpts : benchIngredients+ defaultMainWithIngredients ingredients+ (askOption (askOption . benchmarks))++benchmarks :: CharRange -> Filter -> TestTree+benchmarks charRange charFilter = bgroup "All" [ bgroup "Unicode.Char.General.Names"- -- Character classification- [ bgroup' "name"- [ Bench "CString" DerivedName.name- , Bench "String" Names.name+ [ bgroup "name"+ [ bgroup' "name" "String"+ [ Bench "unicode-data" String.name+#ifdef HAS_ICU+ , Bench "icu" ICUString.name+#endif+ ]+#ifdef HAS_BYTESTRING+ , bgroup' "name" "ByteString"+ [ Bench "unicode-data" ByteString.name+-- #ifdef HAS_ICU+-- , Bench "icu" ICUByteString.name+-- #endif+ ]+#endif+#ifdef HAS_TEXT+ , bgroup' "name" "Text"+ [ Bench "unicode-data" Text.name+#ifdef HAS_ICU+ , Bench "icu" ICUText.name+#endif+ ]+#endif ]- , bgroup' "correctedName"- [ Bench "String" Names.correctedName+ , bgroup "correctedName"+ [ bgroup' "correctedName" "String"+ [ Bench "unicode-data" String.correctedName+#ifdef HAS_ICU+ , Bench "icu" ICUString.correctedName+#endif+ ]+#ifdef HAS_BYTESTRING+ , bgroup' "name" "ByteString"+ [ Bench "unicode-data" ByteString.correctedName+-- #ifdef HAS_ICU+-- , Bench "icu" ICUByteString.correctedName+-- #endif+ ]+#endif+#ifdef HAS_TEXT+ , bgroup' "correctedName" "Text"+ [ Bench "unicode-data" Text.correctedName+#ifdef HAS_ICU+ , Bench "icu" ICUText.correctedName+#endif+ ]+#endif ]- , bgroup' "nameOrAlias"- [ Bench "String" Names.name+ , bgroup "nameOrAlias"+ [ bgroup' "nameOrAlias" "String"+ [ Bench "unicode-data" String.nameOrAlias+ ]+#ifdef HAS_BYTESTRING+ , bgroup' "nameOrAlias" "ByteString"+ [ Bench "unicode-data" ByteString.nameOrAlias+ ]+#endif+#ifdef HAS_TEXT+ , bgroup' "nameOrAlias" "Text"+ [ Bench "unicode-data" Text.nameOrAlias+ ]+#endif ]- , bgroup' "nameAliasesByType"- [ Bench "CString"- (\c -> (`NameAliases.nameAliasesByType` c) <$> [minBound..maxBound])- , Bench "String"- (\c -> (`Names.nameAliasesByType` c) <$> [minBound..maxBound])+ , bgroup "nameAliasesByType"+ [ bgroup' "nameAliasesByType" "String"+ [ Bench "unicode-data"+ (\c -> fold_ (`String.nameAliasesByType` c))+ ]+#ifdef HAS_BYTESTRING+ , bgroup' "nameAliasesByType" "ByteString"+ [ Bench "unicode-data"+ (\c -> fold_ (`String.nameAliasesByType` c))+ ]+#endif+#ifdef HAS_TEXT+ , bgroup' "nameAliasesByType" "Text"+ [ Bench "unicode-data"+ (\c -> fold_ (`String.nameAliasesByType` c))+ ]+#endif ]- , bgroup' "nameAliasesWithTypes"- [ Bench "CString" (show . NameAliases.nameAliasesWithTypes)- , Bench "String" (show . Names.nameAliasesWithTypes)+ , bgroup "nameAliasesWithTypes"+ [ bgroup' "nameAliasesWithTypes" "String"+ [ Bench "unicode-data" String.nameAliasesWithTypes+ ]+#ifdef HAS_BYTESTRING+ , bgroup' "nameAliasesWithTypes" "ByteString"+ [ Bench "unicode-data" ByteString.nameAliasesWithTypes+ ]+#endif+#ifdef HAS_TEXT+ , bgroup' "nameAliasesWithTypes" "Text"+ [ Bench "unicode-data" Text.nameAliasesWithTypes+ ]+#endif ]+ , bgroup "nameAliases"+ [ bgroup' "nameAliases" "String"+ [ Bench "unicode-data" String.nameAliases+ ]+#ifdef HAS_BYTESTRING+ , bgroup' "nameAliases" "ByteString"+ [ Bench "unicode-data" ByteString.nameAliases+ ]+#endif+#ifdef HAS_TEXT+ , bgroup' "nameAliases" "Text"+ [ Bench "unicode-data" Text.nameAliases+ ]+#endif+ ] ] ] where- bgroup' groupTitle bs = bgroup groupTitle- [ benchNF' groupTitle title f+ bgroup' superGroupTitle groupTitle bs = bgroup groupTitle+ [ benchNF' superGroupTitle groupTitle title f | Bench title f <- bs ] -- [NOTE] Works if groupTitle uniquely identifies the benchmark group.- benchNF' groupTitle title = case title of- "CString" -> benchNF title- _ ->- bcompare ("$NF == \"CString\" && $(NF-1) == \"" ++ groupTitle ++ "\"")- . benchNF title+ benchNF' superGroupTitle groupTitle title = case title of+ "unicode-data" -> benchCharsNF title+ _ ->+ bcompare ( mconcat+ [ "$NF == \"unicode-data\" && $(NF-1) == \""+ , groupTitle+ , "\" && $(NF-2) == \""+ , superGroupTitle+ , "\"" ] )+ . benchCharsNF title - benchNF :: forall a. (NFData a) => String -> (Char -> a) -> Benchmark- benchNF t f = bench t $ nf (fold_ f) (minBound, maxBound)+ {-# INLINE benchCharsNF #-}+ benchCharsNF+ :: forall a. (NFData a)+ => String+ -> (Char -> a)+ -> Benchmark+ benchCharsNF t f =+ -- Avoid side-effects with garbage collection (see tasty-bench doc)+ env+ (evaluate (force chars')) -- initialize+ (bench t . nf (foldr (deepseq . f) ())) -- benchmark+ where+ CharRange l u = charRange+ extraFilter = case charFilter of+ NoFilter -> const True+ WithName -> hasName+ WithNameAlias -> hasNameAlias+ WithNameOrAlias -> \c -> hasName c || hasNameAlias c+ chars = filter isValid [l..u]+ -- Ensure to have sufficiently chars+ n = 0x10FFFF `div` length chars+ chars' = mconcat (replicate n chars)+ isValid c = UChar.generalCategory c < UChar.Surrogate && extraFilter c - fold_ :: forall a. (NFData a) => (Char -> a) -> (Char, Char) -> ()- fold_ f = foldr (deepseq . f) () . range+ fold_ :: forall a. (NFData a) => (String.NameAliasType -> a) -> ()+ fold_ f = foldr (deepseq . f) () (range (minBound, maxBound))
lib/Unicode/Char/General/Names.hs view
@@ -5,14 +5,21 @@ -- Maintainer : streamly@composewell.com -- Stability : experimental ----- Unicode character names and name aliases.+-- Unicode character names and name aliases with 'String' API. -- See Unicode standard 15.0.0, section 4.8. --+-- There are also two optional APIs:+--+-- * @ByteString@ API, which requires using the package flag @has-bytestring@.+-- * @Text@ API, which requires using the package flag @has-text@.+-- -- @since 0.1.0 module Unicode.Char.General.Names- ( -- * Name- name+ ( -- Unicode version+ unicodeVersion+ -- * Name+ , name , nameOrAlias , correctedName -- * Name Aliases@@ -23,37 +30,96 @@ ) where import Control.Applicative ((<|>))-import Data.Maybe (listToMaybe)-import Foreign.C.String (CString, peekCAString)-import System.IO.Unsafe (unsafePerformIO)+import GHC.Exts+ ( Addr#, Char(..), Char#, Int#+ , indexCharOffAddr#, plusAddr#, (+#), (-#), (<#), isTrue#, quotRemInt#+ , dataToTag#, ord# ) +import Unicode.Internal.Bits.Names (unpackNBytes#) import qualified Unicode.Internal.Char.UnicodeData.DerivedName as DerivedName import qualified Unicode.Internal.Char.UnicodeData.NameAliases as NameAliases+import Unicode.Internal.Char.Names.Version (unicodeVersion) -- | Name of a character, if defined. -- -- @since 0.1.0-{-# INLINE name #-} name :: Char -> Maybe String-name = fmap unpack . DerivedName.name+name (C# c#) = case DerivedName.name c# of+ (# name#, len# #) -> case len# of+ DerivedName.NoName -> Nothing+ DerivedName.CjkCompatibilityIdeograph -> Just n+ where+ !hex = showHex c#+ !n = 'C':'J':'K':' ':'C':'O':'M':'P':'A':'T':'I':'B':'I':'L':'I':'T':'Y':' ':'I':'D':'E':'O':'G':'R':'A':'P':'H':'-':hex+ DerivedName.CjkUnifiedIdeograph -> Just n+ where+ !hex = showHex c#+ !n = 'C':'J':'K':' ':'U':'N':'I':'F':'I':'E':'D':' ':'I':'D':'E':'O':'G':'R':'A':'P':'H':'-':hex+ DerivedName.TangutIdeograph -> Just n+ where+ !hex = showHex c#+ !n = 'T':'A':'N':'G':'U':'T':' ':'I':'D':'E':'O':'G':'R':'A':'P':'H':'-':hex+ _+ | isTrue# (len# <# DerivedName.HangulSyllable) -> let !n = unpack name# [] len# in Just n+ | otherwise ->+ let !rest = unpack name# [] (len# -# DerivedName.HangulSyllable)+ !n = 'H':'A':'N':'G':'U':'L':' ':'S':'Y':'L':'L':'A':'B':'L':'E':' ':rest+ in Just n +{-# INLINE unpack #-}+unpack :: Addr# -> String -> Int# -> String+unpack !addr# !acc = \case+ 0# -> acc+ !i -> unpack addr# acc' i'+ where+ !i' = i -# 1#+ !c'# = indexCharOffAddr# addr# i'+ !c' = C# c'#+ !acc' = c' : acc++-- [NOTE] We assume c# >= '\x1000' to avoid to check for padding+showHex :: Char# -> String+showHex !c# = showIt [] (quotRemInt# (ord# c#) 16#)+ where+ showIt !acc (# q, r #) = case q of+ 0# -> acc'+ _ -> showIt acc' (quotRemInt# q 16#)+ where+ !c = C# (indexCharOffAddr# "0123456789ABCDEF"# r)+ !acc' = c : acc+ -- | Returns /corrected/ name of a character (see 'NameAliases.Correction'), -- if defined, otherwise returns its original 'name' if defined. -- -- @since 0.1.0 {-# INLINE correctedName #-} correctedName :: Char -> Maybe String-correctedName c =- listToMaybe (nameAliasesByType NameAliases.Correction c) <|> name c+correctedName c@(C# c#) = corrected <|> name c+ where+ -- Assumption: fromEnum NameAliases.Correction == 0+ !corrected = case indexCharOffAddr# addr# 0# of+ '\xff'# -> Nothing -- no aliases+ '\x00'# -> Nothing -- no correction+ i# ->+ let !n = unpackNBytes'# (addr# `plusAddr#` ord# i#)+ in Just n+ !addr# = NameAliases.nameAliases c# -- | Returns a character’s 'name' if defined, -- otherwise returns its first name alias if defined. -- -- @since 0.1.0 nameOrAlias :: Char -> Maybe String-nameOrAlias c = name c <|> case NameAliases.nameAliasesWithTypes c of- (_, n:_):_ -> Just (unpack n)- _ -> Nothing+nameOrAlias c@(C# c#) = name c <|> case indexCharOffAddr# addr# 0# of+ '\xff'# -> Nothing -- no aliases+ '\x00'# -> let !n = go 1# in Just n+ _ -> let !n = go 0# in Just n+ where+ !addr# = NameAliases.nameAliases c#+ go t# = case ord# (indexCharOffAddr# (addr# `plusAddr#` t#) 0#) of+ -- No bound check for t#: there is at least one alias+ 0# -> go (t# +# 1#)+ i# -> unpackNBytes'# (addr# `plusAddr#` i#) -- | All name aliases of a character, if defined. -- The names are listed in the original order of the UCD.@@ -63,14 +129,34 @@ -- @since 0.1.0 {-# INLINE nameAliases #-} nameAliases :: Char -> [String]-nameAliases = fmap unpack . NameAliases.nameAliases+nameAliases (C# c#) = case indexCharOffAddr# addr0# 0# of+ '\xff'# -> [] -- no aliases+ _ -> go (addr0# `plusAddr#` (NameAliases.MaxNameAliasType +# 1#))+ where+ go addr# = case ord# (indexCharOffAddr# addr# 0#) of+ 0# -> case ord# (indexCharOffAddr# (addr# `plusAddr#` 1#) 0#) of+ -- End of list+ 0# -> []+ -- skip empty entry+ l# ->+ let !s = unpackNBytes# (addr# `plusAddr#` 2#) l#+ in s : go (addr# `plusAddr#` (l# +# 2#))+ l# ->+ let !s = unpackNBytes# (addr# `plusAddr#` 1#) l#+ in s : go (addr# `plusAddr#` (l# +# 1#))+ where+ addr0# = NameAliases.nameAliases c# -- | Name aliases of a character for a specific name alias type. -- -- @since 0.1.0 {-# INLINE nameAliasesByType #-} nameAliasesByType :: NameAliases.NameAliasType -> Char -> [String]-nameAliasesByType t = fmap unpack . NameAliases.nameAliasesByType t+nameAliasesByType t (C# c#) = case indexCharOffAddr# addr# 0# of+ '\xff'# -> [] -- no aliases+ _ -> nameAliasesByType# addr# t+ where+ addr# = NameAliases.nameAliases c# -- | Detailed character names aliases. -- The names are listed in the original order of the UCD.@@ -80,11 +166,35 @@ -- @since 0.1.0 {-# INLINE nameAliasesWithTypes #-} nameAliasesWithTypes :: Char -> [(NameAliases.NameAliasType, [String])]-nameAliasesWithTypes- = fmap (fmap (fmap unpack))- . NameAliases.nameAliasesWithTypes+nameAliasesWithTypes (C# c#) = case indexCharOffAddr# addr# 0# of+ '\xff'# -> [] -- no aliases+ '\x00'# -> foldr mk mempty [succ minBound..maxBound]+ _ -> foldr mk mempty [minBound..maxBound]+ where+ addr# = NameAliases.nameAliases c#+ mk t acc = case nameAliasesByType# addr# t of+ [] -> acc+ !as -> (t, as) : acc --- Note: names are ASCII. See Unicode Standard 15.0.0, section 4.8.-{-# INLINE unpack #-}-unpack :: CString -> String-unpack = unsafePerformIO . peekCAString+{-# INLINE unpackNBytes'# #-}+unpackNBytes'# :: Addr# -> String+unpackNBytes'# addr# = unpackNBytes#+ (addr# `plusAddr#` 1#)+ (ord# (indexCharOffAddr# addr# 0#))++{-# INLINE nameAliasesByType# #-}+nameAliasesByType# :: Addr# -> NameAliases.NameAliasType -> [String]+nameAliasesByType# addr# t = case indexCharOffAddr# (addr# `plusAddr#` t#) 0# of+ '\0'# -> [] -- no aliases for this type+ i# -> unpackCStrings# (addr# `plusAddr#` ord# i#)+ where t# = dataToTag# t++{-# INLINE unpackCStrings# #-}+unpackCStrings# :: Addr# -> [String]+unpackCStrings# = go+ where+ go addr# = case ord# (indexCharOffAddr# addr# 0#) of+ 0# -> []+ l# ->+ let !s = unpackNBytes# (addr# `plusAddr#` 1#) l#+ in s : go (addr# `plusAddr#` (l# +# 1#))
+ lib/Unicode/Char/General/Names/ByteString.hs view
@@ -0,0 +1,232 @@+-- |+-- Module : Unicode.Char.General.Names.Text+-- Copyright : (c) 2022 Composewell Technologies and Contributors+-- License : Apache-2.0+-- Maintainer : streamly@composewell.com+-- Stability : experimental+--+-- Unicode character names and name aliases with 'Data.ByteString' API.+-- See Unicode standard 15.0.0, section 4.8.+--+-- This API is /optional/ and requires using the package flag @has-bytestring@.+--+-- @since 0.3.0++module Unicode.Char.General.Names.ByteString+ ( -- * Name+ name+ , nameOrAlias+ , correctedName+ -- * Name Aliases+ , NameAliases.NameAliasType(..)+ , nameAliases+ , nameAliasesByType+ , nameAliasesWithTypes+ ) where++import Control.Applicative ((<|>))+import qualified Data.ByteString as BS+import qualified Data.ByteString.Internal as BS+import GHC.Exts+ ( Addr#, indexCharOffAddr#, indexWord8OffAddr#, plusAddr#+ , Char(..), ord#+ , Int#, Int(..), (+#), (-#), (<#), isTrue#, andI#, uncheckedIShiftRL#+ , dataToTag#+ , newPinnedByteArray#, byteArrayContents#+ , copyAddrToByteArray#, writeWord8Array#+ , unsafeCoerce# )+import GHC.IO (IO(..))+import GHC.ForeignPtr (ForeignPtr(..), ForeignPtrContents (PlainPtr))+import System.IO.Unsafe (unsafeDupablePerformIO)++import qualified Unicode.Internal.Char.UnicodeData.DerivedName as DerivedName+import qualified Unicode.Internal.Char.UnicodeData.NameAliases as NameAliases++--------------------------------------------------------------------------------+-- Name+--------------------------------------------------------------------------------++-- | Name of a character, if defined.+--+-- @since 0.3.0+name :: Char -> Maybe BS.ByteString+name (C# c#) = case DerivedName.name c# of+ (# name#, len# #) -> case len# of+ DerivedName.NoName -> Nothing+ DerivedName.CjkCompatibilityIdeograph -> Just n+ where+ !n = mkNameFromTemplate# "CJK COMPATIBILITY IDEOGRAPH-"# 28# (ord# c#)+ DerivedName.CjkUnifiedIdeograph -> Just n+ where+ !n = mkNameFromTemplate# "CJK UNIFIED IDEOGRAPH-"# 22# (ord# c#)+ DerivedName.TangutIdeograph -> Just n+ where+ !n = mkNameFromTemplate# "TANGUT IDEOGRAPH-"# 17# (ord# c#)+ _+ | isTrue# (len# <# DerivedName.HangulSyllable) ->+ let !n = unpackAddr# name# len#+ in Just n+ | otherwise ->+ let !n = unsafePack2LenLiteral#+ 16#+ "HANGUL SYLLABLE "#+ (len# -# DerivedName.HangulSyllable)+ name#+ in Just n++{-# INLINE unpackAddr# #-}+unpackAddr# :: Addr# -> Int# -> BS.ByteString+unpackAddr# addr# len# = BS.unsafePackLenLiteral (I# len#) addr#++-- [NOTE] bytestring does not expose enough primitives for working with raw+-- Addr# literals. Therefore we go low level, which performs better than FFI.+-- Inspiration:+-- • Data.ByteString.Internal.unsafeCreate+-- • GHC.ForeignPtr.mallocPlainForeignPtrBytes++-- | Pack 2 'Addr#' literal into a 'BS.ByteString'.+{-# INLINE unsafePack2LenLiteral# #-}+unsafePack2LenLiteral# :: Int# -> Addr# -> Int# -> Addr# -> BS.ByteString+unsafePack2LenLiteral# l1# addr1# l2# addr2# = unsafeDupablePerformIO (+ IO (\s0 -> let l# = l1# +# l2# in case newPinnedByteArray# l# s0 of+ (# s1, marr# #) -> case copyAddrToByteArray# addr1# marr# 0# l1# s1 of+ s2 -> case copyAddrToByteArray# addr2# marr# l1# l2# s2 of+ s3 ->+ (# s3+ -- Note: for compatibility reason we cannot use+ -- mutableByteArrayContents# here.+ , BS.BS (ForeignPtr (byteArrayContents# (unsafeCoerce# marr#))+ (PlainPtr marr#))+ (I# l#) #)))++-- | Create a 'BS.ByteString' from a template prefix and then format the given+-- codepoint into hexadecimal string.+mkNameFromTemplate# :: Addr# -> Int# -> Int# -> BS.ByteString+mkNameFromTemplate# template# len# cp# =+ let len'# = len# +# if isTrue# (cp# <# 0x10000#) then 4# else 5#+ in unsafeDupablePerformIO (IO (\s0 -> case newPinnedByteArray# len'# s0 of+ (# s1, marr# #) -> case copyAddrToByteArray# template# marr# 0# len# s1 of+ s2 -> case go marr# s2 (len'# -# 1#) cp# of+ s3 ->+ (# s3+ , BS.BS (ForeignPtr (byteArrayContents# (unsafeCoerce# marr#))+ (PlainPtr marr#))+ (I# len'#) #)+ where+ -- Write hex in reverse order+ -- [NOTE] We assume cp# >= 0x1000 to avoid to check for padding+ go ma !s !offset = \case+ 0# -> s+ n -> go ma+ (writeWord8Array# ma offset+ (indexWord8OffAddr# "0123456789ABCDEF"#+ (andI# 0xf# n)) s)+ (offset -# 1#)+ (uncheckedIShiftRL# n 4#)++ ))++-- | Returns /corrected/ name of a character (see 'NameAliases.Correction'),+-- if defined, otherwise returns its original 'name' if defined.+--+-- @since 0.3.0+{-# INLINE correctedName #-}+correctedName :: Char -> Maybe BS.ByteString+correctedName c@(C# c#) = corrected <|> name c+ where+ -- Assumption: fromEnum NameAliases.Correction == 0+ !corrected = case indexCharOffAddr# addr# 0# of+ '\xff'# -> Nothing -- no aliases+ '\x00'# -> Nothing -- no correction+ i# ->+ let !n = unpackAddr#+ (addr# `plusAddr#` (ord# i# +# 1#))+ (ord# (indexCharOffAddr# (addr# `plusAddr#` ord# i#) 0#))+ in Just n+ !addr# = NameAliases.nameAliases c#++-- | Returns a character’s 'name' if defined,+-- otherwise returns its first name alias if defined.+--+-- @since 0.3.0+nameOrAlias :: Char -> Maybe BS.ByteString+nameOrAlias c@(C# c#) = name c <|> case indexCharOffAddr# addr# 0# of+ '\xff'# -> Nothing -- no aliases+ '\x00'# -> let !n = go 1# in Just n+ _ -> let !n = go 0# in Just n+ where+ !addr# = NameAliases.nameAliases c#+ go t# = case ord# (indexCharOffAddr# (addr# `plusAddr#` t#) 0#) of+ -- No bound check for t#: there is at least one alias+ 0# -> go (t# +# 1#)+ i# -> unpackAddr#+ (addr# `plusAddr#` (i# +# 1#))+ (ord# (indexCharOffAddr# (addr# `plusAddr#` i#) 0#))++-- | All name aliases of a character, if defined.+-- The names are listed in the original order of the UCD.+--+-- See 'nameAliasesWithTypes' for the detailed list by alias type.+--+-- @since 0.3.0+{-# INLINE nameAliases #-}+nameAliases :: Char -> [BS.ByteString]+nameAliases (C# c#) = case indexCharOffAddr# addr0# 0# of+ '\xff'# -> [] -- no aliases+ _ -> go (addr0# `plusAddr#` (NameAliases.MaxNameAliasType +# 1#))+ where+ go addr# = case ord# (indexCharOffAddr# addr# 0#) of+ 0# -> case ord# (indexCharOffAddr# (addr# `plusAddr#` 1#) 0#) of+ -- End of list+ 0# -> []+ -- Skip empty entry+ l# ->+ let !s = unpackAddr# (addr# `plusAddr#` 2#) l#+ in s : go (addr# `plusAddr#` (l# +# 2#))+ l# ->+ let !s = unpackAddr# (addr# `plusAddr#` 1#) l#+ in s : go (addr# `plusAddr#` (l# +# 1#))+ where+ addr0# = NameAliases.nameAliases c#++-- | Name aliases of a character for a specific name alias type.+--+-- @since 0.3.0+{-# INLINE nameAliasesByType #-}+nameAliasesByType :: NameAliases.NameAliasType -> Char -> [BS.ByteString]+nameAliasesByType t (C# c#) = case indexCharOffAddr# addr# 0# of+ '\xff'# -> [] -- no aliases+ _ -> nameAliasesByType# addr# t+ where+ addr# = NameAliases.nameAliases c#++-- | Detailed character names aliases.+-- The names are listed in the original order of the UCD.+--+-- See 'nameAliases' if the alias type is not required.+--+-- @since 0.3.0+{-# INLINE nameAliasesWithTypes #-}+nameAliasesWithTypes :: Char -> [(NameAliases.NameAliasType, [BS.ByteString])]+nameAliasesWithTypes (C# c#) = case indexCharOffAddr# addr# 0# of+ '\xff'# -> [] -- no aliases+ '\x00'# -> foldr mk mempty [succ minBound..maxBound]+ _ -> foldr mk mempty [minBound..maxBound]+ where+ addr# = NameAliases.nameAliases c#+ mk t acc = case nameAliasesByType# addr# t of+ [] -> acc+ as -> (t, as) : acc++{-# INLINE nameAliasesByType# #-}+nameAliasesByType# :: Addr# -> NameAliases.NameAliasType -> [BS.ByteString]+nameAliasesByType# addr0# t =+ case ord# (indexCharOffAddr# (addr0# `plusAddr#` dataToTag# t) 0#) of+ 0# -> [] -- no aliases for this type+ i# -> go (addr0# `plusAddr#` i#)+ where+ go addr# = case ord# (indexCharOffAddr# addr# 0#) of+ 0# -> []+ l# ->+ let !s = unpackAddr# (addr# `plusAddr#` 1#) l#+ in s : go (addr# `plusAddr#` (l# +# 1#))
+ lib/Unicode/Char/General/Names/Text.hs view
@@ -0,0 +1,206 @@+-- |+-- Module : Unicode.Char.General.Names.Text+-- Copyright : (c) 2022 Composewell Technologies and Contributors+-- License : Apache-2.0+-- Maintainer : streamly@composewell.com+-- Stability : experimental+--+-- Unicode character names and name aliases with 'Data.Text' API.+-- See Unicode standard 15.0.0, section 4.8.+--+-- This API is /optional/ and requires using the package flag @has-text@.+--+-- @since 0.3.0++module Unicode.Char.General.Names.Text+ ( -- * Name+ name+ , nameOrAlias+ , correctedName+ -- * Name Aliases+ , NameAliases.NameAliasType(..)+ , nameAliases+ , nameAliasesByType+ , nameAliasesWithTypes+ ) where++import Control.Applicative ((<|>))+import qualified Control.Monad.ST as ST+import qualified Data.Text as T+import qualified Data.Text.Internal as T+import qualified Data.Text.Array as A+import GHC.Exts+ ( Addr#, Ptr(..), indexCharOffAddr#, indexWord8OffAddr#, plusAddr#+ , Char(..), ord#+ , Int#, Int(..), (+#), (-#), (<#), isTrue#, quotRemInt#, dataToTag# )+import GHC.Word (Word8(..))++import qualified Unicode.Internal.Char.UnicodeData.DerivedName as DerivedName+import qualified Unicode.Internal.Char.UnicodeData.NameAliases as NameAliases++-- | Name of a character, if defined.+--+-- @since 0.3.0+name :: Char -> Maybe T.Text+name (C# c#) = case DerivedName.name c# of+ (# name#, len# #) -> case len# of+ DerivedName.NoName -> Nothing+ DerivedName.CjkCompatibilityIdeograph -> Just n+ where+ !n = mkNameFromTemplate "CJK COMPATIBILITY IDEOGRAPH-"# 28# (ord# c#)+ DerivedName.CjkUnifiedIdeograph -> Just n+ where+ !n = mkNameFromTemplate "CJK UNIFIED IDEOGRAPH-"# 22# (ord# c#)+ DerivedName.TangutIdeograph -> Just n+ where+ !n = mkNameFromTemplate "TANGUT IDEOGRAPH-"# 17# (ord# c#)+ _+ | isTrue# (len# <# DerivedName.HangulSyllable) ->+ let !n = unpackAddr# name# len#+ in Just n+ | otherwise ->+ let !len = I# (len# -# DerivedName.HangulSyllable +# 16#)+ ba = ST.runST (do+ marr <- A.new len+ A.copyFromPointer marr 0 (Ptr "HANGUL SYLLABLE "#) 16+ A.copyFromPointer marr 16+ (Ptr name#)+ (I# (len# -# DerivedName.HangulSyllable))+ A.unsafeFreeze marr)+ !n = T.Text ba 0 len+ in Just n++-- See: unpackCStringAscii#. Here we know the length.+unpackAddr# :: Addr# -> Int# -> T.Text+unpackAddr# addr# len# = T.Text ba 0 (I# len#)+ where+ ba = ST.runST (do+ marr <- A.new (I# len#)+ A.copyFromPointer marr 0 (Ptr addr#) (I# len#)+ A.unsafeFreeze marr)++mkNameFromTemplate :: Addr# -> Int# -> Int# -> T.Text+mkNameFromTemplate template# len# cp# = T.Text ba 0 (I# len'#)+ where+ len'# = len# +# if isTrue# (cp# <# 0x10000#) then 4# else 5#+ ba = ST.runST (do+ marr <- A.new (I# len'#)+ A.copyFromPointer marr 0 (Ptr template#) (I# len#)+ writeHex cp# (len'# -# 1#) marr+ A.unsafeFreeze marr)++-- [NOTE] We assume c# >= '\x1000' to avoid to check for padding+{-# INLINE writeHex #-}+writeHex :: Int# -> Int# -> A.MArray s -> ST.ST s ()+writeHex cp# offset0# !marr = showIt offset0# (quotRemInt# cp# 16#)+ where+ showIt offset# (# q, r #)+ = A.unsafeWrite marr (I# offset#)+ (W8# (indexWord8OffAddr# "0123456789ABCDEF"# r))+ *> case q of+ 0# -> pure ()+ _ -> showIt (offset# -# 1#) (quotRemInt# q 16#)++-- | Returns /corrected/ name of a character (see 'NameAliases.Correction'),+-- if defined, otherwise returns its original 'name' if defined.+--+-- @since 0.3.0+{-# INLINE correctedName #-}+correctedName :: Char -> Maybe T.Text+correctedName c@(C# c#) = corrected <|> name c+ where+ -- Assumption: fromEnum NameAliases.Correction == 0+ !corrected = case ord# (indexCharOffAddr# addr# 0#) of+ 0xff# -> Nothing -- no aliases+ 0x00# -> Nothing -- no correction+ i# ->+ let l# = ord# (indexCharOffAddr# (addr# `plusAddr#` i#) 0#)+ !n = unpackAddr# (addr# `plusAddr#` (i# +# 1#)) l#+ in Just n+ !addr# = NameAliases.nameAliases c#++-- | Returns a character’s 'name' if defined,+-- otherwise returns its first name alias if defined.+--+-- @since 0.3.0+nameOrAlias :: Char -> Maybe T.Text+nameOrAlias c@(C# c#) = name c <|> case indexCharOffAddr# addr# 0# of+ '\xff'# -> Nothing -- no aliases+ '\x00'# -> let !n = go 1# in Just n+ _ -> let !n = go 0# in Just n+ where+ !addr# = NameAliases.nameAliases c#+ go t# = case ord# (indexCharOffAddr# (addr# `plusAddr#` t#) 0#) of+ -- No bound check for t#: there is at least one alias+ 0# -> go (t# +# 1#)+ i# ->+ let l# = ord# (indexCharOffAddr# (addr# `plusAddr#` i#) 0#)+ in unpackAddr# (addr# `plusAddr#` (i# +# 1#)) l#++-- | All name aliases of a character, if defined.+-- The names are listed in the original order of the UCD.+--+-- See 'nameAliasesWithTypes' for the detailed list by alias type.+--+-- @since 0.3.0+{-# INLINE nameAliases #-}+nameAliases :: Char -> [T.Text]+nameAliases (C# c#) = case indexCharOffAddr# addr0# 0# of+ '\xff'# -> [] -- no aliases+ _ -> go (addr0# `plusAddr#` (NameAliases.MaxNameAliasType +# 1#))+ where+ go addr# = case ord# (indexCharOffAddr# addr# 0#) of+ 0# -> case ord# (indexCharOffAddr# (addr# `plusAddr#` 1#) 0#) of+ -- End of list+ 0# -> []+ -- Skip empty entry+ l# ->+ let !s = unpackAddr# (addr# `plusAddr#` 2#) l#+ in s : go (addr# `plusAddr#` (l# +# 2#))+ l# ->+ let !s = unpackAddr# (addr# `plusAddr#` 1#) l#+ in s : go (addr# `plusAddr#` (l# +# 1#))+ where+ addr0# = NameAliases.nameAliases c#++-- | Name aliases of a character for a specific name alias type.+--+-- @since 0.3.0+{-# INLINE nameAliasesByType #-}+nameAliasesByType :: NameAliases.NameAliasType -> Char -> [T.Text]+nameAliasesByType t (C# c#) = case indexCharOffAddr# addr# 0# of+ '\xff'# -> [] -- no aliases+ _ -> nameAliasesByType# addr# t+ where+ addr# = NameAliases.nameAliases c#++-- | Detailed character names aliases.+-- The names are listed in the original order of the UCD.+--+-- See 'nameAliases' if the alias type is not required.+--+-- @since 0.3.0+{-# INLINE nameAliasesWithTypes #-}+nameAliasesWithTypes :: Char -> [(NameAliases.NameAliasType, [T.Text])]+nameAliasesWithTypes (C# c#) = case indexCharOffAddr# addr# 0# of+ '\xff'# -> [] -- no aliases+ '\x00'# -> foldr mk mempty [succ minBound..maxBound]+ _ -> foldr mk mempty [minBound..maxBound]+ where+ addr# = NameAliases.nameAliases c#+ mk t acc = case nameAliasesByType# addr# t of+ [] -> acc+ as -> (t, as) : acc++{-# INLINE nameAliasesByType# #-}+nameAliasesByType# :: Addr# -> NameAliases.NameAliasType -> [T.Text]+nameAliasesByType# addr0# t =+ case ord# (indexCharOffAddr# (addr0# `plusAddr#` dataToTag# t) 0#) of+ 0# -> [] -- no aliases for this type+ i# -> go (addr0# `plusAddr#` i#)+ where+ go addr# = case ord# (indexCharOffAddr# addr# 0#) of+ 0# -> []+ l# ->+ let !s = unpackAddr# (addr# `plusAddr#` 1#) l#+ in s : go (addr# `plusAddr#` (l# +# 1#))
+ lib/Unicode/Internal/Bits/Names.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}+{-# HLINT ignore "Use fewer imports" #-}++-- |+-- Module : Unicode.Internal.Bits+-- Copyright : (c) 2020 Andrew Lelechenko+-- (c) 2020 Composewell Technologies+-- License : BSD-3-Clause+-- Maintainer : streamly@composewell.com+-- Stability : experimental+-- Portability : GHC+--+-- Fast, static bitmap lookup utilities++module Unicode.Internal.Bits.Names+ ( -- * Bitmap lookup+ lookupInt32#+ -- * CString+ , unpackNBytes#+ ) where++#include "MachDeps.h"++import GHC.Exts (Addr#, Int#)++#ifdef WORDS_BIGENDIAN++import GHC.Exts (narrow32Word#, word2Int#, byteSwap32#, indexWord32OffAddr#)+#if MIN_VERSION_base(4,16,0)+import GHC.Exts (word32ToWord#)+#endif++#else++import GHC.Exts (indexInt32OffAddr#)+#if MIN_VERSION_base(4,16,0)+import GHC.Exts (int32ToInt#)+#endif++#endif++#if MIN_VERSION_base(4,15,0)+import GHC.Exts (unpackNBytes#)+#else+import GHC.CString (unpackNBytes#)+#endif++{-| @lookupInt32# addr index@ looks up for the @index@-th 32-bits word in+the bitmap starting at @addr@, then convert it to an 'Int#'.++The caller must make sure that:++* @ceiling (addr + (n * 32))@ is legally accessible 'GHC.Exts.Word32#'.++@since 0.4.1+-}+lookupInt32#+ :: Addr# -- ^ Bitmap address+ -> Int# -- ^ Word index+ -> Int# -- ^ Resulting int+lookupInt32#+#ifdef WORDS_BIGENDIAN+#if MIN_VERSION_base(4,16,0)+ addr# k# = word2Int# (narrow32Word# (byteSwap32# (word32ToWord# (indexWord32OffAddr# addr# k#))))+#else+ addr# k# = word2Int# (narrow32Word# (byteSwap32# (indexWord32OffAddr# addr# k#)))+#endif+#elif MIN_VERSION_base(4,16,0)+ addr# k# = int32ToInt# (indexInt32OffAddr# addr# k#)+#else+ = indexInt32OffAddr#+#endif
+ lib/Unicode/Internal/Char/Names/Version.hs view
@@ -0,0 +1,20 @@+-- DO NOT EDIT MANUALLY: autogenerated by ucd2haskell+{-# OPTIONS_HADDOCK hide #-}++-- |+-- Module : Unicode.Internal.Char.Names.Version+-- Copyright : (c) 2024 Composewell Technologies and Contributors+-- License : Apache-2.0+-- Maintainer : streamly@composewell.com+-- Stability : experimental++module Unicode.Internal.Char.Names.Version (unicodeVersion) where++import Data.Version (Version, makeVersion)++-- | Version of the Unicode standard used by this package:+-- [15.0.0](https://www.unicode.org/versions/Unicode15.0.0/).+--+-- @since 0.3.0+unicodeVersion :: Version+unicodeVersion = makeVersion [15,0,0]
lib/Unicode/Internal/Char/UnicodeData/DerivedName.hs view
file too large to diff
lib/Unicode/Internal/Char/UnicodeData/NameAliases.hs view
@@ -6,16 +6,16 @@ -- Maintainer : streamly@composewell.com -- Stability : experimental +{-# LANGUAGE DeriveGeneric, PatternSynonyms #-} {-# OPTIONS_HADDOCK hide #-} module Unicode.Internal.Char.UnicodeData.NameAliases-(NameAliasType(..), nameAliases, nameAliasesByType, nameAliasesWithTypes)+(NameAliasType(..), pattern MaxNameAliasType, nameAliases) where import Data.Ix (Ix)-import Data.Maybe (fromMaybe)-import Foreign.C.String (CString)-import GHC.Exts (Ptr(..))+import GHC.Exts (Addr#, Char#, Int#)+import GHC.Generics (Generic) -- | Type of name alias. See Unicode Standard 15.0.0, section 4.8. --@@ -34,412 +34,413 @@ | Abbreviation -- ^ Commonly occurring abbreviations (or acronyms) for control codes, -- format characters, spaces, and variation selectors.- deriving (Enum, Bounded, Eq, Ord, Ix, Show)+ deriving (Generic, Enum, Bounded, Eq, Ord, Ix, Show) --- | All name aliases of a character.--- The names are listed in the original order of the UCD.------ See 'nameAliasesWithTypes' for the detailed list by alias type.------ @since 0.1.0-{-# INLINE nameAliases #-}-nameAliases :: Char -> [CString]-nameAliases = mconcat . fmap snd . nameAliasesWithTypes+-- $setup+-- >>> import GHC.Exts (Int(..)) --- | Name aliases of a character for a specific name alias type.------ @since 0.1.0-{-# INLINE nameAliasesByType #-}-nameAliasesByType :: NameAliasType -> Char -> [CString]-nameAliasesByType t = fromMaybe mempty . lookup t . nameAliasesWithTypes+-- |+-- >>> I# MaxNameAliasType == fromEnum (maxBound :: NameAliasType)+-- True+pattern MaxNameAliasType :: Int#+pattern MaxNameAliasType = 4# -- | Detailed character names aliases. -- The names are listed in the original order of the UCD. ----- See 'nameAliases' if the alias type is not required.+-- Encoding: --+-- * If there is no alias, return @"\\xff"#@.+-- * For each type of alias, the aliases are encoded as list of (length, alias).+-- The list terminates with @\\0@.+-- * The list are then concatenated in order of type of alias and+-- terminates with @\\0@.+-- * The first 5 bytes represent each one the index of the first element of the+-- corresponding list of aliases. When the list is empty, then the index is 0.+-- * Example: @\"\\5\\0\\13\\0\\0\\3XXX\\2YY\\0\\4ZZZZ\\0\\0\"#@+-- represents: @[('Correction',[\"XXX\", \"YY\"]),('Alternate', [\"ZZZZ\"])]@.+-- -- @since 0.1.0-nameAliasesWithTypes :: Char -> [(NameAliasType, [CString])]-nameAliasesWithTypes = \case- '\x0000' -> [(Control,[Ptr "NULL\0"#]),(Abbreviation,[Ptr "NUL\0"#])]- '\x0001' -> [(Control,[Ptr "START OF HEADING\0"#]),(Abbreviation,[Ptr "SOH\0"#])]- '\x0002' -> [(Control,[Ptr "START OF TEXT\0"#]),(Abbreviation,[Ptr "STX\0"#])]- '\x0003' -> [(Control,[Ptr "END OF TEXT\0"#]),(Abbreviation,[Ptr "ETX\0"#])]- '\x0004' -> [(Control,[Ptr "END OF TRANSMISSION\0"#]),(Abbreviation,[Ptr "EOT\0"#])]- '\x0005' -> [(Control,[Ptr "ENQUIRY\0"#]),(Abbreviation,[Ptr "ENQ\0"#])]- '\x0006' -> [(Control,[Ptr "ACKNOWLEDGE\0"#]),(Abbreviation,[Ptr "ACK\0"#])]- '\x0007' -> [(Control,[Ptr "ALERT\0"#]),(Abbreviation,[Ptr "BEL\0"#])]- '\x0008' -> [(Control,[Ptr "BACKSPACE\0"#]),(Abbreviation,[Ptr "BS\0"#])]- '\x0009' -> [(Control,[Ptr "CHARACTER TABULATION\0"#,Ptr "HORIZONTAL TABULATION\0"#]),(Abbreviation,[Ptr "HT\0"#,Ptr "TAB\0"#])]- '\x000a' -> [(Control,[Ptr "LINE FEED\0"#,Ptr "NEW LINE\0"#,Ptr "END OF LINE\0"#]),(Abbreviation,[Ptr "LF\0"#,Ptr "NL\0"#,Ptr "EOL\0"#])]- '\x000b' -> [(Control,[Ptr "LINE TABULATION\0"#,Ptr "VERTICAL TABULATION\0"#]),(Abbreviation,[Ptr "VT\0"#])]- '\x000c' -> [(Control,[Ptr "FORM FEED\0"#]),(Abbreviation,[Ptr "FF\0"#])]- '\x000d' -> [(Control,[Ptr "CARRIAGE RETURN\0"#]),(Abbreviation,[Ptr "CR\0"#])]- '\x000e' -> [(Control,[Ptr "SHIFT OUT\0"#,Ptr "LOCKING-SHIFT ONE\0"#]),(Abbreviation,[Ptr "SO\0"#])]- '\x000f' -> [(Control,[Ptr "SHIFT IN\0"#,Ptr "LOCKING-SHIFT ZERO\0"#]),(Abbreviation,[Ptr "SI\0"#])]- '\x0010' -> [(Control,[Ptr "DATA LINK ESCAPE\0"#]),(Abbreviation,[Ptr "DLE\0"#])]- '\x0011' -> [(Control,[Ptr "DEVICE CONTROL ONE\0"#]),(Abbreviation,[Ptr "DC1\0"#])]- '\x0012' -> [(Control,[Ptr "DEVICE CONTROL TWO\0"#]),(Abbreviation,[Ptr "DC2\0"#])]- '\x0013' -> [(Control,[Ptr "DEVICE CONTROL THREE\0"#]),(Abbreviation,[Ptr "DC3\0"#])]- '\x0014' -> [(Control,[Ptr "DEVICE CONTROL FOUR\0"#]),(Abbreviation,[Ptr "DC4\0"#])]- '\x0015' -> [(Control,[Ptr "NEGATIVE ACKNOWLEDGE\0"#]),(Abbreviation,[Ptr "NAK\0"#])]- '\x0016' -> [(Control,[Ptr "SYNCHRONOUS IDLE\0"#]),(Abbreviation,[Ptr "SYN\0"#])]- '\x0017' -> [(Control,[Ptr "END OF TRANSMISSION BLOCK\0"#]),(Abbreviation,[Ptr "ETB\0"#])]- '\x0018' -> [(Control,[Ptr "CANCEL\0"#]),(Abbreviation,[Ptr "CAN\0"#])]- '\x0019' -> [(Control,[Ptr "END OF MEDIUM\0"#]),(Abbreviation,[Ptr "EOM\0"#,Ptr "EM\0"#])]- '\x001a' -> [(Control,[Ptr "SUBSTITUTE\0"#]),(Abbreviation,[Ptr "SUB\0"#])]- '\x001b' -> [(Control,[Ptr "ESCAPE\0"#]),(Abbreviation,[Ptr "ESC\0"#])]- '\x001c' -> [(Control,[Ptr "INFORMATION SEPARATOR FOUR\0"#,Ptr "FILE SEPARATOR\0"#]),(Abbreviation,[Ptr "FS\0"#])]- '\x001d' -> [(Control,[Ptr "INFORMATION SEPARATOR THREE\0"#,Ptr "GROUP SEPARATOR\0"#]),(Abbreviation,[Ptr "GS\0"#])]- '\x001e' -> [(Control,[Ptr "INFORMATION SEPARATOR TWO\0"#,Ptr "RECORD SEPARATOR\0"#]),(Abbreviation,[Ptr "RS\0"#])]- '\x001f' -> [(Control,[Ptr "INFORMATION SEPARATOR ONE\0"#,Ptr "UNIT SEPARATOR\0"#]),(Abbreviation,[Ptr "US\0"#])]- '\x0020' -> [(Abbreviation,[Ptr "SP\0"#])]- '\x007f' -> [(Control,[Ptr "DELETE\0"#]),(Abbreviation,[Ptr "DEL\0"#])]- '\x0080' -> [(Figment,[Ptr "PADDING CHARACTER\0"#]),(Abbreviation,[Ptr "PAD\0"#])]- '\x0081' -> [(Figment,[Ptr "HIGH OCTET PRESET\0"#]),(Abbreviation,[Ptr "HOP\0"#])]- '\x0082' -> [(Control,[Ptr "BREAK PERMITTED HERE\0"#]),(Abbreviation,[Ptr "BPH\0"#])]- '\x0083' -> [(Control,[Ptr "NO BREAK HERE\0"#]),(Abbreviation,[Ptr "NBH\0"#])]- '\x0084' -> [(Control,[Ptr "INDEX\0"#]),(Abbreviation,[Ptr "IND\0"#])]- '\x0085' -> [(Control,[Ptr "NEXT LINE\0"#]),(Abbreviation,[Ptr "NEL\0"#])]- '\x0086' -> [(Control,[Ptr "START OF SELECTED AREA\0"#]),(Abbreviation,[Ptr "SSA\0"#])]- '\x0087' -> [(Control,[Ptr "END OF SELECTED AREA\0"#]),(Abbreviation,[Ptr "ESA\0"#])]- '\x0088' -> [(Control,[Ptr "CHARACTER TABULATION SET\0"#,Ptr "HORIZONTAL TABULATION SET\0"#]),(Abbreviation,[Ptr "HTS\0"#])]- '\x0089' -> [(Control,[Ptr "CHARACTER TABULATION WITH JUSTIFICATION\0"#,Ptr "HORIZONTAL TABULATION WITH JUSTIFICATION\0"#]),(Abbreviation,[Ptr "HTJ\0"#])]- '\x008a' -> [(Control,[Ptr "LINE TABULATION SET\0"#,Ptr "VERTICAL TABULATION SET\0"#]),(Abbreviation,[Ptr "VTS\0"#])]- '\x008b' -> [(Control,[Ptr "PARTIAL LINE FORWARD\0"#,Ptr "PARTIAL LINE DOWN\0"#]),(Abbreviation,[Ptr "PLD\0"#])]- '\x008c' -> [(Control,[Ptr "PARTIAL LINE BACKWARD\0"#,Ptr "PARTIAL LINE UP\0"#]),(Abbreviation,[Ptr "PLU\0"#])]- '\x008d' -> [(Control,[Ptr "REVERSE LINE FEED\0"#,Ptr "REVERSE INDEX\0"#]),(Abbreviation,[Ptr "RI\0"#])]- '\x008e' -> [(Control,[Ptr "SINGLE SHIFT TWO\0"#,Ptr "SINGLE-SHIFT-2\0"#]),(Abbreviation,[Ptr "SS2\0"#])]- '\x008f' -> [(Control,[Ptr "SINGLE SHIFT THREE\0"#,Ptr "SINGLE-SHIFT-3\0"#]),(Abbreviation,[Ptr "SS3\0"#])]- '\x0090' -> [(Control,[Ptr "DEVICE CONTROL STRING\0"#]),(Abbreviation,[Ptr "DCS\0"#])]- '\x0091' -> [(Control,[Ptr "PRIVATE USE ONE\0"#,Ptr "PRIVATE USE-1\0"#]),(Abbreviation,[Ptr "PU1\0"#])]- '\x0092' -> [(Control,[Ptr "PRIVATE USE TWO\0"#,Ptr "PRIVATE USE-2\0"#]),(Abbreviation,[Ptr "PU2\0"#])]- '\x0093' -> [(Control,[Ptr "SET TRANSMIT STATE\0"#]),(Abbreviation,[Ptr "STS\0"#])]- '\x0094' -> [(Control,[Ptr "CANCEL CHARACTER\0"#]),(Abbreviation,[Ptr "CCH\0"#])]- '\x0095' -> [(Control,[Ptr "MESSAGE WAITING\0"#]),(Abbreviation,[Ptr "MW\0"#])]- '\x0096' -> [(Control,[Ptr "START OF GUARDED AREA\0"#,Ptr "START OF PROTECTED AREA\0"#]),(Abbreviation,[Ptr "SPA\0"#])]- '\x0097' -> [(Control,[Ptr "END OF GUARDED AREA\0"#,Ptr "END OF PROTECTED AREA\0"#]),(Abbreviation,[Ptr "EPA\0"#])]- '\x0098' -> [(Control,[Ptr "START OF STRING\0"#]),(Abbreviation,[Ptr "SOS\0"#])]- '\x0099' -> [(Figment,[Ptr "SINGLE GRAPHIC CHARACTER INTRODUCER\0"#]),(Abbreviation,[Ptr "SGC\0"#])]- '\x009a' -> [(Control,[Ptr "SINGLE CHARACTER INTRODUCER\0"#]),(Abbreviation,[Ptr "SCI\0"#])]- '\x009b' -> [(Control,[Ptr "CONTROL SEQUENCE INTRODUCER\0"#]),(Abbreviation,[Ptr "CSI\0"#])]- '\x009c' -> [(Control,[Ptr "STRING TERMINATOR\0"#]),(Abbreviation,[Ptr "ST\0"#])]- '\x009d' -> [(Control,[Ptr "OPERATING SYSTEM COMMAND\0"#]),(Abbreviation,[Ptr "OSC\0"#])]- '\x009e' -> [(Control,[Ptr "PRIVACY MESSAGE\0"#]),(Abbreviation,[Ptr "PM\0"#])]- '\x009f' -> [(Control,[Ptr "APPLICATION PROGRAM COMMAND\0"#]),(Abbreviation,[Ptr "APC\0"#])]- '\x00a0' -> [(Abbreviation,[Ptr "NBSP\0"#])]- '\x00ad' -> [(Abbreviation,[Ptr "SHY\0"#])]- '\x01a2' -> [(Correction,[Ptr "LATIN CAPITAL LETTER GHA\0"#])]- '\x01a3' -> [(Correction,[Ptr "LATIN SMALL LETTER GHA\0"#])]- '\x034f' -> [(Abbreviation,[Ptr "CGJ\0"#])]- '\x0616' -> [(Correction,[Ptr "ARABIC SMALL HIGH LIGATURE ALEF WITH YEH BARREE\0"#])]- '\x061c' -> [(Abbreviation,[Ptr "ALM\0"#])]- '\x0709' -> [(Correction,[Ptr "SYRIAC SUBLINEAR COLON SKEWED LEFT\0"#])]- '\x0cde' -> [(Correction,[Ptr "KANNADA LETTER LLLA\0"#])]- '\x0e9d' -> [(Correction,[Ptr "LAO LETTER FO FON\0"#])]- '\x0e9f' -> [(Correction,[Ptr "LAO LETTER FO FAY\0"#])]- '\x0ea3' -> [(Correction,[Ptr "LAO LETTER RO\0"#])]- '\x0ea5' -> [(Correction,[Ptr "LAO LETTER LO\0"#])]- '\x0fd0' -> [(Correction,[Ptr "TIBETAN MARK BKA- SHOG GI MGO RGYAN\0"#])]- '\x11ec' -> [(Correction,[Ptr "HANGUL JONGSEONG YESIEUNG-KIYEOK\0"#])]- '\x11ed' -> [(Correction,[Ptr "HANGUL JONGSEONG YESIEUNG-SSANGKIYEOK\0"#])]- '\x11ee' -> [(Correction,[Ptr "HANGUL JONGSEONG SSANGYESIEUNG\0"#])]- '\x11ef' -> [(Correction,[Ptr "HANGUL JONGSEONG YESIEUNG-KHIEUKH\0"#])]- '\x180b' -> [(Abbreviation,[Ptr "FVS1\0"#])]- '\x180c' -> [(Abbreviation,[Ptr "FVS2\0"#])]- '\x180d' -> [(Abbreviation,[Ptr "FVS3\0"#])]- '\x180e' -> [(Abbreviation,[Ptr "MVS\0"#])]- '\x180f' -> [(Abbreviation,[Ptr "FVS4\0"#])]- '\x1bbd' -> [(Correction,[Ptr "SUNDANESE LETTER ARCHAIC I\0"#])]- '\x200b' -> [(Abbreviation,[Ptr "ZWSP\0"#])]- '\x200c' -> [(Abbreviation,[Ptr "ZWNJ\0"#])]- '\x200d' -> [(Abbreviation,[Ptr "ZWJ\0"#])]- '\x200e' -> [(Abbreviation,[Ptr "LRM\0"#])]- '\x200f' -> [(Abbreviation,[Ptr "RLM\0"#])]- '\x202a' -> [(Abbreviation,[Ptr "LRE\0"#])]- '\x202b' -> [(Abbreviation,[Ptr "RLE\0"#])]- '\x202c' -> [(Abbreviation,[Ptr "PDF\0"#])]- '\x202d' -> [(Abbreviation,[Ptr "LRO\0"#])]- '\x202e' -> [(Abbreviation,[Ptr "RLO\0"#])]- '\x202f' -> [(Abbreviation,[Ptr "NNBSP\0"#])]- '\x205f' -> [(Abbreviation,[Ptr "MMSP\0"#])]- '\x2060' -> [(Abbreviation,[Ptr "WJ\0"#])]- '\x2066' -> [(Abbreviation,[Ptr "LRI\0"#])]- '\x2067' -> [(Abbreviation,[Ptr "RLI\0"#])]- '\x2068' -> [(Abbreviation,[Ptr "FSI\0"#])]- '\x2069' -> [(Abbreviation,[Ptr "PDI\0"#])]- '\x2118' -> [(Correction,[Ptr "WEIERSTRASS ELLIPTIC FUNCTION\0"#])]- '\x2448' -> [(Correction,[Ptr "MICR ON US SYMBOL\0"#])]- '\x2449' -> [(Correction,[Ptr "MICR DASH SYMBOL\0"#])]- '\x2b7a' -> [(Correction,[Ptr "LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE VERTICAL STROKE\0"#])]- '\x2b7c' -> [(Correction,[Ptr "RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE VERTICAL STROKE\0"#])]- '\xa015' -> [(Correction,[Ptr "YI SYLLABLE ITERATION MARK\0"#])]- '\xaa6e' -> [(Correction,[Ptr "MYANMAR LETTER KHAMTI LLA\0"#])]- '\xfe00' -> [(Abbreviation,[Ptr "VS1\0"#])]- '\xfe01' -> [(Abbreviation,[Ptr "VS2\0"#])]- '\xfe02' -> [(Abbreviation,[Ptr "VS3\0"#])]- '\xfe03' -> [(Abbreviation,[Ptr "VS4\0"#])]- '\xfe04' -> [(Abbreviation,[Ptr "VS5\0"#])]- '\xfe05' -> [(Abbreviation,[Ptr "VS6\0"#])]- '\xfe06' -> [(Abbreviation,[Ptr "VS7\0"#])]- '\xfe07' -> [(Abbreviation,[Ptr "VS8\0"#])]- '\xfe08' -> [(Abbreviation,[Ptr "VS9\0"#])]- '\xfe09' -> [(Abbreviation,[Ptr "VS10\0"#])]- '\xfe0a' -> [(Abbreviation,[Ptr "VS11\0"#])]- '\xfe0b' -> [(Abbreviation,[Ptr "VS12\0"#])]- '\xfe0c' -> [(Abbreviation,[Ptr "VS13\0"#])]- '\xfe0d' -> [(Abbreviation,[Ptr "VS14\0"#])]- '\xfe0e' -> [(Abbreviation,[Ptr "VS15\0"#])]- '\xfe0f' -> [(Abbreviation,[Ptr "VS16\0"#])]- '\xfe18' -> [(Correction,[Ptr "PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRACKET\0"#])]- '\xfeff' -> [(Alternate,[Ptr "BYTE ORDER MARK\0"#]),(Abbreviation,[Ptr "BOM\0"#,Ptr "ZWNBSP\0"#])]- '\x122d4' -> [(Correction,[Ptr "CUNEIFORM SIGN NU11 TENU\0"#])]- '\x122d5' -> [(Correction,[Ptr "CUNEIFORM SIGN NU11 OVER NU11 BUR OVER BUR\0"#])]- '\x16e56' -> [(Correction,[Ptr "MEDEFAIDRIN CAPITAL LETTER H\0"#])]- '\x16e57' -> [(Correction,[Ptr "MEDEFAIDRIN CAPITAL LETTER NG\0"#])]- '\x16e76' -> [(Correction,[Ptr "MEDEFAIDRIN SMALL LETTER H\0"#])]- '\x16e77' -> [(Correction,[Ptr "MEDEFAIDRIN SMALL LETTER NG\0"#])]- '\x1b001' -> [(Correction,[Ptr "HENTAIGANA LETTER E-1\0"#])]- '\x1d0c5' -> [(Correction,[Ptr "BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA VASIS\0"#])]- '\xe0100' -> [(Abbreviation,[Ptr "VS17\0"#])]- '\xe0101' -> [(Abbreviation,[Ptr "VS18\0"#])]- '\xe0102' -> [(Abbreviation,[Ptr "VS19\0"#])]- '\xe0103' -> [(Abbreviation,[Ptr "VS20\0"#])]- '\xe0104' -> [(Abbreviation,[Ptr "VS21\0"#])]- '\xe0105' -> [(Abbreviation,[Ptr "VS22\0"#])]- '\xe0106' -> [(Abbreviation,[Ptr "VS23\0"#])]- '\xe0107' -> [(Abbreviation,[Ptr "VS24\0"#])]- '\xe0108' -> [(Abbreviation,[Ptr "VS25\0"#])]- '\xe0109' -> [(Abbreviation,[Ptr "VS26\0"#])]- '\xe010a' -> [(Abbreviation,[Ptr "VS27\0"#])]- '\xe010b' -> [(Abbreviation,[Ptr "VS28\0"#])]- '\xe010c' -> [(Abbreviation,[Ptr "VS29\0"#])]- '\xe010d' -> [(Abbreviation,[Ptr "VS30\0"#])]- '\xe010e' -> [(Abbreviation,[Ptr "VS31\0"#])]- '\xe010f' -> [(Abbreviation,[Ptr "VS32\0"#])]- '\xe0110' -> [(Abbreviation,[Ptr "VS33\0"#])]- '\xe0111' -> [(Abbreviation,[Ptr "VS34\0"#])]- '\xe0112' -> [(Abbreviation,[Ptr "VS35\0"#])]- '\xe0113' -> [(Abbreviation,[Ptr "VS36\0"#])]- '\xe0114' -> [(Abbreviation,[Ptr "VS37\0"#])]- '\xe0115' -> [(Abbreviation,[Ptr "VS38\0"#])]- '\xe0116' -> [(Abbreviation,[Ptr "VS39\0"#])]- '\xe0117' -> [(Abbreviation,[Ptr "VS40\0"#])]- '\xe0118' -> [(Abbreviation,[Ptr "VS41\0"#])]- '\xe0119' -> [(Abbreviation,[Ptr "VS42\0"#])]- '\xe011a' -> [(Abbreviation,[Ptr "VS43\0"#])]- '\xe011b' -> [(Abbreviation,[Ptr "VS44\0"#])]- '\xe011c' -> [(Abbreviation,[Ptr "VS45\0"#])]- '\xe011d' -> [(Abbreviation,[Ptr "VS46\0"#])]- '\xe011e' -> [(Abbreviation,[Ptr "VS47\0"#])]- '\xe011f' -> [(Abbreviation,[Ptr "VS48\0"#])]- '\xe0120' -> [(Abbreviation,[Ptr "VS49\0"#])]- '\xe0121' -> [(Abbreviation,[Ptr "VS50\0"#])]- '\xe0122' -> [(Abbreviation,[Ptr "VS51\0"#])]- '\xe0123' -> [(Abbreviation,[Ptr "VS52\0"#])]- '\xe0124' -> [(Abbreviation,[Ptr "VS53\0"#])]- '\xe0125' -> [(Abbreviation,[Ptr "VS54\0"#])]- '\xe0126' -> [(Abbreviation,[Ptr "VS55\0"#])]- '\xe0127' -> [(Abbreviation,[Ptr "VS56\0"#])]- '\xe0128' -> [(Abbreviation,[Ptr "VS57\0"#])]- '\xe0129' -> [(Abbreviation,[Ptr "VS58\0"#])]- '\xe012a' -> [(Abbreviation,[Ptr "VS59\0"#])]- '\xe012b' -> [(Abbreviation,[Ptr "VS60\0"#])]- '\xe012c' -> [(Abbreviation,[Ptr "VS61\0"#])]- '\xe012d' -> [(Abbreviation,[Ptr "VS62\0"#])]- '\xe012e' -> [(Abbreviation,[Ptr "VS63\0"#])]- '\xe012f' -> [(Abbreviation,[Ptr "VS64\0"#])]- '\xe0130' -> [(Abbreviation,[Ptr "VS65\0"#])]- '\xe0131' -> [(Abbreviation,[Ptr "VS66\0"#])]- '\xe0132' -> [(Abbreviation,[Ptr "VS67\0"#])]- '\xe0133' -> [(Abbreviation,[Ptr "VS68\0"#])]- '\xe0134' -> [(Abbreviation,[Ptr "VS69\0"#])]- '\xe0135' -> [(Abbreviation,[Ptr "VS70\0"#])]- '\xe0136' -> [(Abbreviation,[Ptr "VS71\0"#])]- '\xe0137' -> [(Abbreviation,[Ptr "VS72\0"#])]- '\xe0138' -> [(Abbreviation,[Ptr "VS73\0"#])]- '\xe0139' -> [(Abbreviation,[Ptr "VS74\0"#])]- '\xe013a' -> [(Abbreviation,[Ptr "VS75\0"#])]- '\xe013b' -> [(Abbreviation,[Ptr "VS76\0"#])]- '\xe013c' -> [(Abbreviation,[Ptr "VS77\0"#])]- '\xe013d' -> [(Abbreviation,[Ptr "VS78\0"#])]- '\xe013e' -> [(Abbreviation,[Ptr "VS79\0"#])]- '\xe013f' -> [(Abbreviation,[Ptr "VS80\0"#])]- '\xe0140' -> [(Abbreviation,[Ptr "VS81\0"#])]- '\xe0141' -> [(Abbreviation,[Ptr "VS82\0"#])]- '\xe0142' -> [(Abbreviation,[Ptr "VS83\0"#])]- '\xe0143' -> [(Abbreviation,[Ptr "VS84\0"#])]- '\xe0144' -> [(Abbreviation,[Ptr "VS85\0"#])]- '\xe0145' -> [(Abbreviation,[Ptr "VS86\0"#])]- '\xe0146' -> [(Abbreviation,[Ptr "VS87\0"#])]- '\xe0147' -> [(Abbreviation,[Ptr "VS88\0"#])]- '\xe0148' -> [(Abbreviation,[Ptr "VS89\0"#])]- '\xe0149' -> [(Abbreviation,[Ptr "VS90\0"#])]- '\xe014a' -> [(Abbreviation,[Ptr "VS91\0"#])]- '\xe014b' -> [(Abbreviation,[Ptr "VS92\0"#])]- '\xe014c' -> [(Abbreviation,[Ptr "VS93\0"#])]- '\xe014d' -> [(Abbreviation,[Ptr "VS94\0"#])]- '\xe014e' -> [(Abbreviation,[Ptr "VS95\0"#])]- '\xe014f' -> [(Abbreviation,[Ptr "VS96\0"#])]- '\xe0150' -> [(Abbreviation,[Ptr "VS97\0"#])]- '\xe0151' -> [(Abbreviation,[Ptr "VS98\0"#])]- '\xe0152' -> [(Abbreviation,[Ptr "VS99\0"#])]- '\xe0153' -> [(Abbreviation,[Ptr "VS100\0"#])]- '\xe0154' -> [(Abbreviation,[Ptr "VS101\0"#])]- '\xe0155' -> [(Abbreviation,[Ptr "VS102\0"#])]- '\xe0156' -> [(Abbreviation,[Ptr "VS103\0"#])]- '\xe0157' -> [(Abbreviation,[Ptr "VS104\0"#])]- '\xe0158' -> [(Abbreviation,[Ptr "VS105\0"#])]- '\xe0159' -> [(Abbreviation,[Ptr "VS106\0"#])]- '\xe015a' -> [(Abbreviation,[Ptr "VS107\0"#])]- '\xe015b' -> [(Abbreviation,[Ptr "VS108\0"#])]- '\xe015c' -> [(Abbreviation,[Ptr "VS109\0"#])]- '\xe015d' -> [(Abbreviation,[Ptr "VS110\0"#])]- '\xe015e' -> [(Abbreviation,[Ptr "VS111\0"#])]- '\xe015f' -> [(Abbreviation,[Ptr "VS112\0"#])]- '\xe0160' -> [(Abbreviation,[Ptr "VS113\0"#])]- '\xe0161' -> [(Abbreviation,[Ptr "VS114\0"#])]- '\xe0162' -> [(Abbreviation,[Ptr "VS115\0"#])]- '\xe0163' -> [(Abbreviation,[Ptr "VS116\0"#])]- '\xe0164' -> [(Abbreviation,[Ptr "VS117\0"#])]- '\xe0165' -> [(Abbreviation,[Ptr "VS118\0"#])]- '\xe0166' -> [(Abbreviation,[Ptr "VS119\0"#])]- '\xe0167' -> [(Abbreviation,[Ptr "VS120\0"#])]- '\xe0168' -> [(Abbreviation,[Ptr "VS121\0"#])]- '\xe0169' -> [(Abbreviation,[Ptr "VS122\0"#])]- '\xe016a' -> [(Abbreviation,[Ptr "VS123\0"#])]- '\xe016b' -> [(Abbreviation,[Ptr "VS124\0"#])]- '\xe016c' -> [(Abbreviation,[Ptr "VS125\0"#])]- '\xe016d' -> [(Abbreviation,[Ptr "VS126\0"#])]- '\xe016e' -> [(Abbreviation,[Ptr "VS127\0"#])]- '\xe016f' -> [(Abbreviation,[Ptr "VS128\0"#])]- '\xe0170' -> [(Abbreviation,[Ptr "VS129\0"#])]- '\xe0171' -> [(Abbreviation,[Ptr "VS130\0"#])]- '\xe0172' -> [(Abbreviation,[Ptr "VS131\0"#])]- '\xe0173' -> [(Abbreviation,[Ptr "VS132\0"#])]- '\xe0174' -> [(Abbreviation,[Ptr "VS133\0"#])]- '\xe0175' -> [(Abbreviation,[Ptr "VS134\0"#])]- '\xe0176' -> [(Abbreviation,[Ptr "VS135\0"#])]- '\xe0177' -> [(Abbreviation,[Ptr "VS136\0"#])]- '\xe0178' -> [(Abbreviation,[Ptr "VS137\0"#])]- '\xe0179' -> [(Abbreviation,[Ptr "VS138\0"#])]- '\xe017a' -> [(Abbreviation,[Ptr "VS139\0"#])]- '\xe017b' -> [(Abbreviation,[Ptr "VS140\0"#])]- '\xe017c' -> [(Abbreviation,[Ptr "VS141\0"#])]- '\xe017d' -> [(Abbreviation,[Ptr "VS142\0"#])]- '\xe017e' -> [(Abbreviation,[Ptr "VS143\0"#])]- '\xe017f' -> [(Abbreviation,[Ptr "VS144\0"#])]- '\xe0180' -> [(Abbreviation,[Ptr "VS145\0"#])]- '\xe0181' -> [(Abbreviation,[Ptr "VS146\0"#])]- '\xe0182' -> [(Abbreviation,[Ptr "VS147\0"#])]- '\xe0183' -> [(Abbreviation,[Ptr "VS148\0"#])]- '\xe0184' -> [(Abbreviation,[Ptr "VS149\0"#])]- '\xe0185' -> [(Abbreviation,[Ptr "VS150\0"#])]- '\xe0186' -> [(Abbreviation,[Ptr "VS151\0"#])]- '\xe0187' -> [(Abbreviation,[Ptr "VS152\0"#])]- '\xe0188' -> [(Abbreviation,[Ptr "VS153\0"#])]- '\xe0189' -> [(Abbreviation,[Ptr "VS154\0"#])]- '\xe018a' -> [(Abbreviation,[Ptr "VS155\0"#])]- '\xe018b' -> [(Abbreviation,[Ptr "VS156\0"#])]- '\xe018c' -> [(Abbreviation,[Ptr "VS157\0"#])]- '\xe018d' -> [(Abbreviation,[Ptr "VS158\0"#])]- '\xe018e' -> [(Abbreviation,[Ptr "VS159\0"#])]- '\xe018f' -> [(Abbreviation,[Ptr "VS160\0"#])]- '\xe0190' -> [(Abbreviation,[Ptr "VS161\0"#])]- '\xe0191' -> [(Abbreviation,[Ptr "VS162\0"#])]- '\xe0192' -> [(Abbreviation,[Ptr "VS163\0"#])]- '\xe0193' -> [(Abbreviation,[Ptr "VS164\0"#])]- '\xe0194' -> [(Abbreviation,[Ptr "VS165\0"#])]- '\xe0195' -> [(Abbreviation,[Ptr "VS166\0"#])]- '\xe0196' -> [(Abbreviation,[Ptr "VS167\0"#])]- '\xe0197' -> [(Abbreviation,[Ptr "VS168\0"#])]- '\xe0198' -> [(Abbreviation,[Ptr "VS169\0"#])]- '\xe0199' -> [(Abbreviation,[Ptr "VS170\0"#])]- '\xe019a' -> [(Abbreviation,[Ptr "VS171\0"#])]- '\xe019b' -> [(Abbreviation,[Ptr "VS172\0"#])]- '\xe019c' -> [(Abbreviation,[Ptr "VS173\0"#])]- '\xe019d' -> [(Abbreviation,[Ptr "VS174\0"#])]- '\xe019e' -> [(Abbreviation,[Ptr "VS175\0"#])]- '\xe019f' -> [(Abbreviation,[Ptr "VS176\0"#])]- '\xe01a0' -> [(Abbreviation,[Ptr "VS177\0"#])]- '\xe01a1' -> [(Abbreviation,[Ptr "VS178\0"#])]- '\xe01a2' -> [(Abbreviation,[Ptr "VS179\0"#])]- '\xe01a3' -> [(Abbreviation,[Ptr "VS180\0"#])]- '\xe01a4' -> [(Abbreviation,[Ptr "VS181\0"#])]- '\xe01a5' -> [(Abbreviation,[Ptr "VS182\0"#])]- '\xe01a6' -> [(Abbreviation,[Ptr "VS183\0"#])]- '\xe01a7' -> [(Abbreviation,[Ptr "VS184\0"#])]- '\xe01a8' -> [(Abbreviation,[Ptr "VS185\0"#])]- '\xe01a9' -> [(Abbreviation,[Ptr "VS186\0"#])]- '\xe01aa' -> [(Abbreviation,[Ptr "VS187\0"#])]- '\xe01ab' -> [(Abbreviation,[Ptr "VS188\0"#])]- '\xe01ac' -> [(Abbreviation,[Ptr "VS189\0"#])]- '\xe01ad' -> [(Abbreviation,[Ptr "VS190\0"#])]- '\xe01ae' -> [(Abbreviation,[Ptr "VS191\0"#])]- '\xe01af' -> [(Abbreviation,[Ptr "VS192\0"#])]- '\xe01b0' -> [(Abbreviation,[Ptr "VS193\0"#])]- '\xe01b1' -> [(Abbreviation,[Ptr "VS194\0"#])]- '\xe01b2' -> [(Abbreviation,[Ptr "VS195\0"#])]- '\xe01b3' -> [(Abbreviation,[Ptr "VS196\0"#])]- '\xe01b4' -> [(Abbreviation,[Ptr "VS197\0"#])]- '\xe01b5' -> [(Abbreviation,[Ptr "VS198\0"#])]- '\xe01b6' -> [(Abbreviation,[Ptr "VS199\0"#])]- '\xe01b7' -> [(Abbreviation,[Ptr "VS200\0"#])]- '\xe01b8' -> [(Abbreviation,[Ptr "VS201\0"#])]- '\xe01b9' -> [(Abbreviation,[Ptr "VS202\0"#])]- '\xe01ba' -> [(Abbreviation,[Ptr "VS203\0"#])]- '\xe01bb' -> [(Abbreviation,[Ptr "VS204\0"#])]- '\xe01bc' -> [(Abbreviation,[Ptr "VS205\0"#])]- '\xe01bd' -> [(Abbreviation,[Ptr "VS206\0"#])]- '\xe01be' -> [(Abbreviation,[Ptr "VS207\0"#])]- '\xe01bf' -> [(Abbreviation,[Ptr "VS208\0"#])]- '\xe01c0' -> [(Abbreviation,[Ptr "VS209\0"#])]- '\xe01c1' -> [(Abbreviation,[Ptr "VS210\0"#])]- '\xe01c2' -> [(Abbreviation,[Ptr "VS211\0"#])]- '\xe01c3' -> [(Abbreviation,[Ptr "VS212\0"#])]- '\xe01c4' -> [(Abbreviation,[Ptr "VS213\0"#])]- '\xe01c5' -> [(Abbreviation,[Ptr "VS214\0"#])]- '\xe01c6' -> [(Abbreviation,[Ptr "VS215\0"#])]- '\xe01c7' -> [(Abbreviation,[Ptr "VS216\0"#])]- '\xe01c8' -> [(Abbreviation,[Ptr "VS217\0"#])]- '\xe01c9' -> [(Abbreviation,[Ptr "VS218\0"#])]- '\xe01ca' -> [(Abbreviation,[Ptr "VS219\0"#])]- '\xe01cb' -> [(Abbreviation,[Ptr "VS220\0"#])]- '\xe01cc' -> [(Abbreviation,[Ptr "VS221\0"#])]- '\xe01cd' -> [(Abbreviation,[Ptr "VS222\0"#])]- '\xe01ce' -> [(Abbreviation,[Ptr "VS223\0"#])]- '\xe01cf' -> [(Abbreviation,[Ptr "VS224\0"#])]- '\xe01d0' -> [(Abbreviation,[Ptr "VS225\0"#])]- '\xe01d1' -> [(Abbreviation,[Ptr "VS226\0"#])]- '\xe01d2' -> [(Abbreviation,[Ptr "VS227\0"#])]- '\xe01d3' -> [(Abbreviation,[Ptr "VS228\0"#])]- '\xe01d4' -> [(Abbreviation,[Ptr "VS229\0"#])]- '\xe01d5' -> [(Abbreviation,[Ptr "VS230\0"#])]- '\xe01d6' -> [(Abbreviation,[Ptr "VS231\0"#])]- '\xe01d7' -> [(Abbreviation,[Ptr "VS232\0"#])]- '\xe01d8' -> [(Abbreviation,[Ptr "VS233\0"#])]- '\xe01d9' -> [(Abbreviation,[Ptr "VS234\0"#])]- '\xe01da' -> [(Abbreviation,[Ptr "VS235\0"#])]- '\xe01db' -> [(Abbreviation,[Ptr "VS236\0"#])]- '\xe01dc' -> [(Abbreviation,[Ptr "VS237\0"#])]- '\xe01dd' -> [(Abbreviation,[Ptr "VS238\0"#])]- '\xe01de' -> [(Abbreviation,[Ptr "VS239\0"#])]- '\xe01df' -> [(Abbreviation,[Ptr "VS240\0"#])]- '\xe01e0' -> [(Abbreviation,[Ptr "VS241\0"#])]- '\xe01e1' -> [(Abbreviation,[Ptr "VS242\0"#])]- '\xe01e2' -> [(Abbreviation,[Ptr "VS243\0"#])]- '\xe01e3' -> [(Abbreviation,[Ptr "VS244\0"#])]- '\xe01e4' -> [(Abbreviation,[Ptr "VS245\0"#])]- '\xe01e5' -> [(Abbreviation,[Ptr "VS246\0"#])]- '\xe01e6' -> [(Abbreviation,[Ptr "VS247\0"#])]- '\xe01e7' -> [(Abbreviation,[Ptr "VS248\0"#])]- '\xe01e8' -> [(Abbreviation,[Ptr "VS249\0"#])]- '\xe01e9' -> [(Abbreviation,[Ptr "VS250\0"#])]- '\xe01ea' -> [(Abbreviation,[Ptr "VS251\0"#])]- '\xe01eb' -> [(Abbreviation,[Ptr "VS252\0"#])]- '\xe01ec' -> [(Abbreviation,[Ptr "VS253\0"#])]- '\xe01ed' -> [(Abbreviation,[Ptr "VS254\0"#])]- '\xe01ee' -> [(Abbreviation,[Ptr "VS255\0"#])]- '\xe01ef' -> [(Abbreviation,[Ptr "VS256\0"#])]-- _ -> mempty+nameAliases :: Char# -> Addr#+nameAliases = \case+ '\x0000'# -> "\0\5\0\0\11\4NULL\0\3NUL\0\0"#+ '\x0001'# -> "\0\5\0\0\23\16START OF HEADING\0\3SOH\0\0"#+ '\x0002'# -> "\0\5\0\0\20\13START OF TEXT\0\3STX\0\0"#+ '\x0003'# -> "\0\5\0\0\18\11END OF TEXT\0\3ETX\0\0"#+ '\x0004'# -> "\0\5\0\0\26\19END OF TRANSMISSION\0\3EOT\0\0"#+ '\x0005'# -> "\0\5\0\0\14\7ENQUIRY\0\3ENQ\0\0"#+ '\x0006'# -> "\0\5\0\0\18\11ACKNOWLEDGE\0\3ACK\0\0"#+ '\x0007'# -> "\0\5\0\0\12\5ALERT\0\3BEL\0\0"#+ '\x0008'# -> "\0\5\0\0\16\9BACKSPACE\0\2BS\0\0"#+ '\x0009'# -> "\0\5\0\0\49\20CHARACTER TABULATION\21HORIZONTAL TABULATION\0\2HT\3TAB\0\0"#+ '\x000A'# -> "\0\5\0\0\37\9LINE FEED\8NEW LINE\11END OF LINE\0\2LF\2NL\3EOL\0\0"#+ '\x000B'# -> "\0\5\0\0\42\15LINE TABULATION\19VERTICAL TABULATION\0\2VT\0\0"#+ '\x000C'# -> "\0\5\0\0\16\9FORM FEED\0\2FF\0\0"#+ '\x000D'# -> "\0\5\0\0\22\15CARRIAGE RETURN\0\2CR\0\0"#+ '\x000E'# -> "\0\5\0\0\34\9SHIFT OUT\17LOCKING-SHIFT ONE\0\2SO\0\0"#+ '\x000F'# -> "\0\5\0\0\34\8SHIFT IN\18LOCKING-SHIFT ZERO\0\2SI\0\0"#+ '\x0010'# -> "\0\5\0\0\23\16DATA LINK ESCAPE\0\3DLE\0\0"#+ '\x0011'# -> "\0\5\0\0\25\18DEVICE CONTROL ONE\0\3DC1\0\0"#+ '\x0012'# -> "\0\5\0\0\25\18DEVICE CONTROL TWO\0\3DC2\0\0"#+ '\x0013'# -> "\0\5\0\0\27\20DEVICE CONTROL THREE\0\3DC3\0\0"#+ '\x0014'# -> "\0\5\0\0\26\19DEVICE CONTROL FOUR\0\3DC4\0\0"#+ '\x0015'# -> "\0\5\0\0\27\20NEGATIVE ACKNOWLEDGE\0\3NAK\0\0"#+ '\x0016'# -> "\0\5\0\0\23\16SYNCHRONOUS IDLE\0\3SYN\0\0"#+ '\x0017'# -> "\0\5\0\0\32\25END OF TRANSMISSION BLOCK\0\3ETB\0\0"#+ '\x0018'# -> "\0\5\0\0\13\6CANCEL\0\3CAN\0\0"#+ '\x0019'# -> "\0\5\0\0\20\13END OF MEDIUM\0\3EOM\2EM\0\0"#+ '\x001A'# -> "\0\5\0\0\17\10SUBSTITUTE\0\3SUB\0\0"#+ '\x001B'# -> "\0\5\0\0\13\6ESCAPE\0\3ESC\0\0"#+ '\x001C'# -> "\0\5\0\0\48\26INFORMATION SEPARATOR FOUR\14FILE SEPARATOR\0\2FS\0\0"#+ '\x001D'# -> "\0\5\0\0\50\27INFORMATION SEPARATOR THREE\15GROUP SEPARATOR\0\2GS\0\0"#+ '\x001E'# -> "\0\5\0\0\49\25INFORMATION SEPARATOR TWO\16RECORD SEPARATOR\0\2RS\0\0"#+ '\x001F'# -> "\0\5\0\0\47\25INFORMATION SEPARATOR ONE\14UNIT SEPARATOR\0\2US\0\0"#+ '\x0020'# -> "\0\0\0\0\5\2SP\0\0"#+ '\x007F'# -> "\0\5\0\0\13\6DELETE\0\3DEL\0\0"#+ '\x0080'# -> "\0\0\0\5\24\17PADDING CHARACTER\0\3PAD\0\0"#+ '\x0081'# -> "\0\0\0\5\24\17HIGH OCTET PRESET\0\3HOP\0\0"#+ '\x0082'# -> "\0\5\0\0\27\20BREAK PERMITTED HERE\0\3BPH\0\0"#+ '\x0083'# -> "\0\5\0\0\20\13NO BREAK HERE\0\3NBH\0\0"#+ '\x0084'# -> "\0\5\0\0\12\5INDEX\0\3IND\0\0"#+ '\x0085'# -> "\0\5\0\0\16\9NEXT LINE\0\3NEL\0\0"#+ '\x0086'# -> "\0\5\0\0\29\22START OF SELECTED AREA\0\3SSA\0\0"#+ '\x0087'# -> "\0\5\0\0\27\20END OF SELECTED AREA\0\3ESA\0\0"#+ '\x0088'# -> "\0\5\0\0\57\24CHARACTER TABULATION SET\25HORIZONTAL TABULATION SET\0\3HTS\0\0"#+ '\x0089'# -> "\0\5\0\0\87\39CHARACTER TABULATION WITH JUSTIFICATION\40HORIZONTAL TABULATION WITH JUSTIFICATION\0\3HTJ\0\0"#+ '\x008A'# -> "\0\5\0\0\50\19LINE TABULATION SET\23VERTICAL TABULATION SET\0\3VTS\0\0"#+ '\x008B'# -> "\0\5\0\0\45\20PARTIAL LINE FORWARD\17PARTIAL LINE DOWN\0\3PLD\0\0"#+ '\x008C'# -> "\0\5\0\0\44\21PARTIAL LINE BACKWARD\15PARTIAL LINE UP\0\3PLU\0\0"#+ '\x008D'# -> "\0\5\0\0\38\17REVERSE LINE FEED\13REVERSE INDEX\0\2RI\0\0"#+ '\x008E'# -> "\0\5\0\0\38\16SINGLE SHIFT TWO\14SINGLE-SHIFT-2\0\3SS2\0\0"#+ '\x008F'# -> "\0\5\0\0\40\18SINGLE SHIFT THREE\14SINGLE-SHIFT-3\0\3SS3\0\0"#+ '\x0090'# -> "\0\5\0\0\28\21DEVICE CONTROL STRING\0\3DCS\0\0"#+ '\x0091'# -> "\0\5\0\0\36\15PRIVATE USE ONE\13PRIVATE USE-1\0\3PU1\0\0"#+ '\x0092'# -> "\0\5\0\0\36\15PRIVATE USE TWO\13PRIVATE USE-2\0\3PU2\0\0"#+ '\x0093'# -> "\0\5\0\0\25\18SET TRANSMIT STATE\0\3STS\0\0"#+ '\x0094'# -> "\0\5\0\0\23\16CANCEL CHARACTER\0\3CCH\0\0"#+ '\x0095'# -> "\0\5\0\0\22\15MESSAGE WAITING\0\2MW\0\0"#+ '\x0096'# -> "\0\5\0\0\52\21START OF GUARDED AREA\23START OF PROTECTED AREA\0\3SPA\0\0"#+ '\x0097'# -> "\0\5\0\0\48\19END OF GUARDED AREA\21END OF PROTECTED AREA\0\3EPA\0\0"#+ '\x0098'# -> "\0\5\0\0\22\15START OF STRING\0\3SOS\0\0"#+ '\x0099'# -> "\0\0\0\5\42\35SINGLE GRAPHIC CHARACTER INTRODUCER\0\3SGC\0\0"#+ '\x009A'# -> "\0\5\0\0\34\27SINGLE CHARACTER INTRODUCER\0\3SCI\0\0"#+ '\x009B'# -> "\0\5\0\0\34\27CONTROL SEQUENCE INTRODUCER\0\3CSI\0\0"#+ '\x009C'# -> "\0\5\0\0\24\17STRING TERMINATOR\0\2ST\0\0"#+ '\x009D'# -> "\0\5\0\0\31\24OPERATING SYSTEM COMMAND\0\3OSC\0\0"#+ '\x009E'# -> "\0\5\0\0\22\15PRIVACY MESSAGE\0\2PM\0\0"#+ '\x009F'# -> "\0\5\0\0\34\27APPLICATION PROGRAM COMMAND\0\3APC\0\0"#+ '\x00A0'# -> "\0\0\0\0\5\4NBSP\0\0"#+ '\x00AD'# -> "\0\0\0\0\5\3SHY\0\0"#+ '\x01A2'# -> "\5\0\0\0\0\24LATIN CAPITAL LETTER GHA\0\0"#+ '\x01A3'# -> "\5\0\0\0\0\22LATIN SMALL LETTER GHA\0\0"#+ '\x034F'# -> "\0\0\0\0\5\3CGJ\0\0"#+ '\x0616'# -> "\5\0\0\0\0\47ARABIC SMALL HIGH LIGATURE ALEF WITH YEH BARREE\0\0"#+ '\x061C'# -> "\0\0\0\0\5\3ALM\0\0"#+ '\x0709'# -> "\5\0\0\0\0\34SYRIAC SUBLINEAR COLON SKEWED LEFT\0\0"#+ '\x0CDE'# -> "\5\0\0\0\0\19KANNADA LETTER LLLA\0\0"#+ '\x0E9D'# -> "\5\0\0\0\0\17LAO LETTER FO FON\0\0"#+ '\x0E9F'# -> "\5\0\0\0\0\17LAO LETTER FO FAY\0\0"#+ '\x0EA3'# -> "\5\0\0\0\0\13LAO LETTER RO\0\0"#+ '\x0EA5'# -> "\5\0\0\0\0\13LAO LETTER LO\0\0"#+ '\x0FD0'# -> "\5\0\0\0\0\35TIBETAN MARK BKA- SHOG GI MGO RGYAN\0\0"#+ '\x11EC'# -> "\5\0\0\0\0\32HANGUL JONGSEONG YESIEUNG-KIYEOK\0\0"#+ '\x11ED'# -> "\5\0\0\0\0\37HANGUL JONGSEONG YESIEUNG-SSANGKIYEOK\0\0"#+ '\x11EE'# -> "\5\0\0\0\0\30HANGUL JONGSEONG SSANGYESIEUNG\0\0"#+ '\x11EF'# -> "\5\0\0\0\0\33HANGUL JONGSEONG YESIEUNG-KHIEUKH\0\0"#+ '\x180B'# -> "\0\0\0\0\5\4FVS1\0\0"#+ '\x180C'# -> "\0\0\0\0\5\4FVS2\0\0"#+ '\x180D'# -> "\0\0\0\0\5\4FVS3\0\0"#+ '\x180E'# -> "\0\0\0\0\5\3MVS\0\0"#+ '\x180F'# -> "\0\0\0\0\5\4FVS4\0\0"#+ '\x1BBD'# -> "\5\0\0\0\0\26SUNDANESE LETTER ARCHAIC I\0\0"#+ '\x200B'# -> "\0\0\0\0\5\4ZWSP\0\0"#+ '\x200C'# -> "\0\0\0\0\5\4ZWNJ\0\0"#+ '\x200D'# -> "\0\0\0\0\5\3ZWJ\0\0"#+ '\x200E'# -> "\0\0\0\0\5\3LRM\0\0"#+ '\x200F'# -> "\0\0\0\0\5\3RLM\0\0"#+ '\x202A'# -> "\0\0\0\0\5\3LRE\0\0"#+ '\x202B'# -> "\0\0\0\0\5\3RLE\0\0"#+ '\x202C'# -> "\0\0\0\0\5\3PDF\0\0"#+ '\x202D'# -> "\0\0\0\0\5\3LRO\0\0"#+ '\x202E'# -> "\0\0\0\0\5\3RLO\0\0"#+ '\x202F'# -> "\0\0\0\0\5\5NNBSP\0\0"#+ '\x205F'# -> "\0\0\0\0\5\4MMSP\0\0"#+ '\x2060'# -> "\0\0\0\0\5\2WJ\0\0"#+ '\x2066'# -> "\0\0\0\0\5\3LRI\0\0"#+ '\x2067'# -> "\0\0\0\0\5\3RLI\0\0"#+ '\x2068'# -> "\0\0\0\0\5\3FSI\0\0"#+ '\x2069'# -> "\0\0\0\0\5\3PDI\0\0"#+ '\x2118'# -> "\5\0\0\0\0\29WEIERSTRASS ELLIPTIC FUNCTION\0\0"#+ '\x2448'# -> "\5\0\0\0\0\17MICR ON US SYMBOL\0\0"#+ '\x2449'# -> "\5\0\0\0\0\16MICR DASH SYMBOL\0\0"#+ '\x2B7A'# -> "\5\0\0\0\0\59LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE VERTICAL STROKE\0\0"#+ '\x2B7C'# -> "\5\0\0\0\0\60RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE VERTICAL STROKE\0\0"#+ '\xA015'# -> "\5\0\0\0\0\26YI SYLLABLE ITERATION MARK\0\0"#+ '\xAA6E'# -> "\5\0\0\0\0\25MYANMAR LETTER KHAMTI LLA\0\0"#+ '\xFE00'# -> "\0\0\0\0\5\3VS1\0\0"#+ '\xFE01'# -> "\0\0\0\0\5\3VS2\0\0"#+ '\xFE02'# -> "\0\0\0\0\5\3VS3\0\0"#+ '\xFE03'# -> "\0\0\0\0\5\3VS4\0\0"#+ '\xFE04'# -> "\0\0\0\0\5\3VS5\0\0"#+ '\xFE05'# -> "\0\0\0\0\5\3VS6\0\0"#+ '\xFE06'# -> "\0\0\0\0\5\3VS7\0\0"#+ '\xFE07'# -> "\0\0\0\0\5\3VS8\0\0"#+ '\xFE08'# -> "\0\0\0\0\5\3VS9\0\0"#+ '\xFE09'# -> "\0\0\0\0\5\4VS10\0\0"#+ '\xFE0A'# -> "\0\0\0\0\5\4VS11\0\0"#+ '\xFE0B'# -> "\0\0\0\0\5\4VS12\0\0"#+ '\xFE0C'# -> "\0\0\0\0\5\4VS13\0\0"#+ '\xFE0D'# -> "\0\0\0\0\5\4VS14\0\0"#+ '\xFE0E'# -> "\0\0\0\0\5\4VS15\0\0"#+ '\xFE0F'# -> "\0\0\0\0\5\4VS16\0\0"#+ '\xFE18'# -> "\5\0\0\0\0\61PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRACKET\0\0"#+ '\xFEFF'# -> "\0\0\5\0\22\15BYTE ORDER MARK\0\3BOM\6ZWNBSP\0\0"#+ '\x122D4'# -> "\5\0\0\0\0\24CUNEIFORM SIGN NU11 TENU\0\0"#+ '\x122D5'# -> "\5\0\0\0\0\42CUNEIFORM SIGN NU11 OVER NU11 BUR OVER BUR\0\0"#+ '\x16E56'# -> "\5\0\0\0\0\28MEDEFAIDRIN CAPITAL LETTER H\0\0"#+ '\x16E57'# -> "\5\0\0\0\0\29MEDEFAIDRIN CAPITAL LETTER NG\0\0"#+ '\x16E76'# -> "\5\0\0\0\0\26MEDEFAIDRIN SMALL LETTER H\0\0"#+ '\x16E77'# -> "\5\0\0\0\0\27MEDEFAIDRIN SMALL LETTER NG\0\0"#+ '\x1B001'# -> "\5\0\0\0\0\21HENTAIGANA LETTER E-1\0\0"#+ '\x1D0C5'# -> "\5\0\0\0\0\52BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA VASIS\0\0"#+ '\xE0100'# -> "\0\0\0\0\5\4VS17\0\0"#+ '\xE0101'# -> "\0\0\0\0\5\4VS18\0\0"#+ '\xE0102'# -> "\0\0\0\0\5\4VS19\0\0"#+ '\xE0103'# -> "\0\0\0\0\5\4VS20\0\0"#+ '\xE0104'# -> "\0\0\0\0\5\4VS21\0\0"#+ '\xE0105'# -> "\0\0\0\0\5\4VS22\0\0"#+ '\xE0106'# -> "\0\0\0\0\5\4VS23\0\0"#+ '\xE0107'# -> "\0\0\0\0\5\4VS24\0\0"#+ '\xE0108'# -> "\0\0\0\0\5\4VS25\0\0"#+ '\xE0109'# -> "\0\0\0\0\5\4VS26\0\0"#+ '\xE010A'# -> "\0\0\0\0\5\4VS27\0\0"#+ '\xE010B'# -> "\0\0\0\0\5\4VS28\0\0"#+ '\xE010C'# -> "\0\0\0\0\5\4VS29\0\0"#+ '\xE010D'# -> "\0\0\0\0\5\4VS30\0\0"#+ '\xE010E'# -> "\0\0\0\0\5\4VS31\0\0"#+ '\xE010F'# -> "\0\0\0\0\5\4VS32\0\0"#+ '\xE0110'# -> "\0\0\0\0\5\4VS33\0\0"#+ '\xE0111'# -> "\0\0\0\0\5\4VS34\0\0"#+ '\xE0112'# -> "\0\0\0\0\5\4VS35\0\0"#+ '\xE0113'# -> "\0\0\0\0\5\4VS36\0\0"#+ '\xE0114'# -> "\0\0\0\0\5\4VS37\0\0"#+ '\xE0115'# -> "\0\0\0\0\5\4VS38\0\0"#+ '\xE0116'# -> "\0\0\0\0\5\4VS39\0\0"#+ '\xE0117'# -> "\0\0\0\0\5\4VS40\0\0"#+ '\xE0118'# -> "\0\0\0\0\5\4VS41\0\0"#+ '\xE0119'# -> "\0\0\0\0\5\4VS42\0\0"#+ '\xE011A'# -> "\0\0\0\0\5\4VS43\0\0"#+ '\xE011B'# -> "\0\0\0\0\5\4VS44\0\0"#+ '\xE011C'# -> "\0\0\0\0\5\4VS45\0\0"#+ '\xE011D'# -> "\0\0\0\0\5\4VS46\0\0"#+ '\xE011E'# -> "\0\0\0\0\5\4VS47\0\0"#+ '\xE011F'# -> "\0\0\0\0\5\4VS48\0\0"#+ '\xE0120'# -> "\0\0\0\0\5\4VS49\0\0"#+ '\xE0121'# -> "\0\0\0\0\5\4VS50\0\0"#+ '\xE0122'# -> "\0\0\0\0\5\4VS51\0\0"#+ '\xE0123'# -> "\0\0\0\0\5\4VS52\0\0"#+ '\xE0124'# -> "\0\0\0\0\5\4VS53\0\0"#+ '\xE0125'# -> "\0\0\0\0\5\4VS54\0\0"#+ '\xE0126'# -> "\0\0\0\0\5\4VS55\0\0"#+ '\xE0127'# -> "\0\0\0\0\5\4VS56\0\0"#+ '\xE0128'# -> "\0\0\0\0\5\4VS57\0\0"#+ '\xE0129'# -> "\0\0\0\0\5\4VS58\0\0"#+ '\xE012A'# -> "\0\0\0\0\5\4VS59\0\0"#+ '\xE012B'# -> "\0\0\0\0\5\4VS60\0\0"#+ '\xE012C'# -> "\0\0\0\0\5\4VS61\0\0"#+ '\xE012D'# -> "\0\0\0\0\5\4VS62\0\0"#+ '\xE012E'# -> "\0\0\0\0\5\4VS63\0\0"#+ '\xE012F'# -> "\0\0\0\0\5\4VS64\0\0"#+ '\xE0130'# -> "\0\0\0\0\5\4VS65\0\0"#+ '\xE0131'# -> "\0\0\0\0\5\4VS66\0\0"#+ '\xE0132'# -> "\0\0\0\0\5\4VS67\0\0"#+ '\xE0133'# -> "\0\0\0\0\5\4VS68\0\0"#+ '\xE0134'# -> "\0\0\0\0\5\4VS69\0\0"#+ '\xE0135'# -> "\0\0\0\0\5\4VS70\0\0"#+ '\xE0136'# -> "\0\0\0\0\5\4VS71\0\0"#+ '\xE0137'# -> "\0\0\0\0\5\4VS72\0\0"#+ '\xE0138'# -> "\0\0\0\0\5\4VS73\0\0"#+ '\xE0139'# -> "\0\0\0\0\5\4VS74\0\0"#+ '\xE013A'# -> "\0\0\0\0\5\4VS75\0\0"#+ '\xE013B'# -> "\0\0\0\0\5\4VS76\0\0"#+ '\xE013C'# -> "\0\0\0\0\5\4VS77\0\0"#+ '\xE013D'# -> "\0\0\0\0\5\4VS78\0\0"#+ '\xE013E'# -> "\0\0\0\0\5\4VS79\0\0"#+ '\xE013F'# -> "\0\0\0\0\5\4VS80\0\0"#+ '\xE0140'# -> "\0\0\0\0\5\4VS81\0\0"#+ '\xE0141'# -> "\0\0\0\0\5\4VS82\0\0"#+ '\xE0142'# -> "\0\0\0\0\5\4VS83\0\0"#+ '\xE0143'# -> "\0\0\0\0\5\4VS84\0\0"#+ '\xE0144'# -> "\0\0\0\0\5\4VS85\0\0"#+ '\xE0145'# -> "\0\0\0\0\5\4VS86\0\0"#+ '\xE0146'# -> "\0\0\0\0\5\4VS87\0\0"#+ '\xE0147'# -> "\0\0\0\0\5\4VS88\0\0"#+ '\xE0148'# -> "\0\0\0\0\5\4VS89\0\0"#+ '\xE0149'# -> "\0\0\0\0\5\4VS90\0\0"#+ '\xE014A'# -> "\0\0\0\0\5\4VS91\0\0"#+ '\xE014B'# -> "\0\0\0\0\5\4VS92\0\0"#+ '\xE014C'# -> "\0\0\0\0\5\4VS93\0\0"#+ '\xE014D'# -> "\0\0\0\0\5\4VS94\0\0"#+ '\xE014E'# -> "\0\0\0\0\5\4VS95\0\0"#+ '\xE014F'# -> "\0\0\0\0\5\4VS96\0\0"#+ '\xE0150'# -> "\0\0\0\0\5\4VS97\0\0"#+ '\xE0151'# -> "\0\0\0\0\5\4VS98\0\0"#+ '\xE0152'# -> "\0\0\0\0\5\4VS99\0\0"#+ '\xE0153'# -> "\0\0\0\0\5\5VS100\0\0"#+ '\xE0154'# -> "\0\0\0\0\5\5VS101\0\0"#+ '\xE0155'# -> "\0\0\0\0\5\5VS102\0\0"#+ '\xE0156'# -> "\0\0\0\0\5\5VS103\0\0"#+ '\xE0157'# -> "\0\0\0\0\5\5VS104\0\0"#+ '\xE0158'# -> "\0\0\0\0\5\5VS105\0\0"#+ '\xE0159'# -> "\0\0\0\0\5\5VS106\0\0"#+ '\xE015A'# -> "\0\0\0\0\5\5VS107\0\0"#+ '\xE015B'# -> "\0\0\0\0\5\5VS108\0\0"#+ '\xE015C'# -> "\0\0\0\0\5\5VS109\0\0"#+ '\xE015D'# -> "\0\0\0\0\5\5VS110\0\0"#+ '\xE015E'# -> "\0\0\0\0\5\5VS111\0\0"#+ '\xE015F'# -> "\0\0\0\0\5\5VS112\0\0"#+ '\xE0160'# -> "\0\0\0\0\5\5VS113\0\0"#+ '\xE0161'# -> "\0\0\0\0\5\5VS114\0\0"#+ '\xE0162'# -> "\0\0\0\0\5\5VS115\0\0"#+ '\xE0163'# -> "\0\0\0\0\5\5VS116\0\0"#+ '\xE0164'# -> "\0\0\0\0\5\5VS117\0\0"#+ '\xE0165'# -> "\0\0\0\0\5\5VS118\0\0"#+ '\xE0166'# -> "\0\0\0\0\5\5VS119\0\0"#+ '\xE0167'# -> "\0\0\0\0\5\5VS120\0\0"#+ '\xE0168'# -> "\0\0\0\0\5\5VS121\0\0"#+ '\xE0169'# -> "\0\0\0\0\5\5VS122\0\0"#+ '\xE016A'# -> "\0\0\0\0\5\5VS123\0\0"#+ '\xE016B'# -> "\0\0\0\0\5\5VS124\0\0"#+ '\xE016C'# -> "\0\0\0\0\5\5VS125\0\0"#+ '\xE016D'# -> "\0\0\0\0\5\5VS126\0\0"#+ '\xE016E'# -> "\0\0\0\0\5\5VS127\0\0"#+ '\xE016F'# -> "\0\0\0\0\5\5VS128\0\0"#+ '\xE0170'# -> "\0\0\0\0\5\5VS129\0\0"#+ '\xE0171'# -> "\0\0\0\0\5\5VS130\0\0"#+ '\xE0172'# -> "\0\0\0\0\5\5VS131\0\0"#+ '\xE0173'# -> "\0\0\0\0\5\5VS132\0\0"#+ '\xE0174'# -> "\0\0\0\0\5\5VS133\0\0"#+ '\xE0175'# -> "\0\0\0\0\5\5VS134\0\0"#+ '\xE0176'# -> "\0\0\0\0\5\5VS135\0\0"#+ '\xE0177'# -> "\0\0\0\0\5\5VS136\0\0"#+ '\xE0178'# -> "\0\0\0\0\5\5VS137\0\0"#+ '\xE0179'# -> "\0\0\0\0\5\5VS138\0\0"#+ '\xE017A'# -> "\0\0\0\0\5\5VS139\0\0"#+ '\xE017B'# -> "\0\0\0\0\5\5VS140\0\0"#+ '\xE017C'# -> "\0\0\0\0\5\5VS141\0\0"#+ '\xE017D'# -> "\0\0\0\0\5\5VS142\0\0"#+ '\xE017E'# -> "\0\0\0\0\5\5VS143\0\0"#+ '\xE017F'# -> "\0\0\0\0\5\5VS144\0\0"#+ '\xE0180'# -> "\0\0\0\0\5\5VS145\0\0"#+ '\xE0181'# -> "\0\0\0\0\5\5VS146\0\0"#+ '\xE0182'# -> "\0\0\0\0\5\5VS147\0\0"#+ '\xE0183'# -> "\0\0\0\0\5\5VS148\0\0"#+ '\xE0184'# -> "\0\0\0\0\5\5VS149\0\0"#+ '\xE0185'# -> "\0\0\0\0\5\5VS150\0\0"#+ '\xE0186'# -> "\0\0\0\0\5\5VS151\0\0"#+ '\xE0187'# -> "\0\0\0\0\5\5VS152\0\0"#+ '\xE0188'# -> "\0\0\0\0\5\5VS153\0\0"#+ '\xE0189'# -> "\0\0\0\0\5\5VS154\0\0"#+ '\xE018A'# -> "\0\0\0\0\5\5VS155\0\0"#+ '\xE018B'# -> "\0\0\0\0\5\5VS156\0\0"#+ '\xE018C'# -> "\0\0\0\0\5\5VS157\0\0"#+ '\xE018D'# -> "\0\0\0\0\5\5VS158\0\0"#+ '\xE018E'# -> "\0\0\0\0\5\5VS159\0\0"#+ '\xE018F'# -> "\0\0\0\0\5\5VS160\0\0"#+ '\xE0190'# -> "\0\0\0\0\5\5VS161\0\0"#+ '\xE0191'# -> "\0\0\0\0\5\5VS162\0\0"#+ '\xE0192'# -> "\0\0\0\0\5\5VS163\0\0"#+ '\xE0193'# -> "\0\0\0\0\5\5VS164\0\0"#+ '\xE0194'# -> "\0\0\0\0\5\5VS165\0\0"#+ '\xE0195'# -> "\0\0\0\0\5\5VS166\0\0"#+ '\xE0196'# -> "\0\0\0\0\5\5VS167\0\0"#+ '\xE0197'# -> "\0\0\0\0\5\5VS168\0\0"#+ '\xE0198'# -> "\0\0\0\0\5\5VS169\0\0"#+ '\xE0199'# -> "\0\0\0\0\5\5VS170\0\0"#+ '\xE019A'# -> "\0\0\0\0\5\5VS171\0\0"#+ '\xE019B'# -> "\0\0\0\0\5\5VS172\0\0"#+ '\xE019C'# -> "\0\0\0\0\5\5VS173\0\0"#+ '\xE019D'# -> "\0\0\0\0\5\5VS174\0\0"#+ '\xE019E'# -> "\0\0\0\0\5\5VS175\0\0"#+ '\xE019F'# -> "\0\0\0\0\5\5VS176\0\0"#+ '\xE01A0'# -> "\0\0\0\0\5\5VS177\0\0"#+ '\xE01A1'# -> "\0\0\0\0\5\5VS178\0\0"#+ '\xE01A2'# -> "\0\0\0\0\5\5VS179\0\0"#+ '\xE01A3'# -> "\0\0\0\0\5\5VS180\0\0"#+ '\xE01A4'# -> "\0\0\0\0\5\5VS181\0\0"#+ '\xE01A5'# -> "\0\0\0\0\5\5VS182\0\0"#+ '\xE01A6'# -> "\0\0\0\0\5\5VS183\0\0"#+ '\xE01A7'# -> "\0\0\0\0\5\5VS184\0\0"#+ '\xE01A8'# -> "\0\0\0\0\5\5VS185\0\0"#+ '\xE01A9'# -> "\0\0\0\0\5\5VS186\0\0"#+ '\xE01AA'# -> "\0\0\0\0\5\5VS187\0\0"#+ '\xE01AB'# -> "\0\0\0\0\5\5VS188\0\0"#+ '\xE01AC'# -> "\0\0\0\0\5\5VS189\0\0"#+ '\xE01AD'# -> "\0\0\0\0\5\5VS190\0\0"#+ '\xE01AE'# -> "\0\0\0\0\5\5VS191\0\0"#+ '\xE01AF'# -> "\0\0\0\0\5\5VS192\0\0"#+ '\xE01B0'# -> "\0\0\0\0\5\5VS193\0\0"#+ '\xE01B1'# -> "\0\0\0\0\5\5VS194\0\0"#+ '\xE01B2'# -> "\0\0\0\0\5\5VS195\0\0"#+ '\xE01B3'# -> "\0\0\0\0\5\5VS196\0\0"#+ '\xE01B4'# -> "\0\0\0\0\5\5VS197\0\0"#+ '\xE01B5'# -> "\0\0\0\0\5\5VS198\0\0"#+ '\xE01B6'# -> "\0\0\0\0\5\5VS199\0\0"#+ '\xE01B7'# -> "\0\0\0\0\5\5VS200\0\0"#+ '\xE01B8'# -> "\0\0\0\0\5\5VS201\0\0"#+ '\xE01B9'# -> "\0\0\0\0\5\5VS202\0\0"#+ '\xE01BA'# -> "\0\0\0\0\5\5VS203\0\0"#+ '\xE01BB'# -> "\0\0\0\0\5\5VS204\0\0"#+ '\xE01BC'# -> "\0\0\0\0\5\5VS205\0\0"#+ '\xE01BD'# -> "\0\0\0\0\5\5VS206\0\0"#+ '\xE01BE'# -> "\0\0\0\0\5\5VS207\0\0"#+ '\xE01BF'# -> "\0\0\0\0\5\5VS208\0\0"#+ '\xE01C0'# -> "\0\0\0\0\5\5VS209\0\0"#+ '\xE01C1'# -> "\0\0\0\0\5\5VS210\0\0"#+ '\xE01C2'# -> "\0\0\0\0\5\5VS211\0\0"#+ '\xE01C3'# -> "\0\0\0\0\5\5VS212\0\0"#+ '\xE01C4'# -> "\0\0\0\0\5\5VS213\0\0"#+ '\xE01C5'# -> "\0\0\0\0\5\5VS214\0\0"#+ '\xE01C6'# -> "\0\0\0\0\5\5VS215\0\0"#+ '\xE01C7'# -> "\0\0\0\0\5\5VS216\0\0"#+ '\xE01C8'# -> "\0\0\0\0\5\5VS217\0\0"#+ '\xE01C9'# -> "\0\0\0\0\5\5VS218\0\0"#+ '\xE01CA'# -> "\0\0\0\0\5\5VS219\0\0"#+ '\xE01CB'# -> "\0\0\0\0\5\5VS220\0\0"#+ '\xE01CC'# -> "\0\0\0\0\5\5VS221\0\0"#+ '\xE01CD'# -> "\0\0\0\0\5\5VS222\0\0"#+ '\xE01CE'# -> "\0\0\0\0\5\5VS223\0\0"#+ '\xE01CF'# -> "\0\0\0\0\5\5VS224\0\0"#+ '\xE01D0'# -> "\0\0\0\0\5\5VS225\0\0"#+ '\xE01D1'# -> "\0\0\0\0\5\5VS226\0\0"#+ '\xE01D2'# -> "\0\0\0\0\5\5VS227\0\0"#+ '\xE01D3'# -> "\0\0\0\0\5\5VS228\0\0"#+ '\xE01D4'# -> "\0\0\0\0\5\5VS229\0\0"#+ '\xE01D5'# -> "\0\0\0\0\5\5VS230\0\0"#+ '\xE01D6'# -> "\0\0\0\0\5\5VS231\0\0"#+ '\xE01D7'# -> "\0\0\0\0\5\5VS232\0\0"#+ '\xE01D8'# -> "\0\0\0\0\5\5VS233\0\0"#+ '\xE01D9'# -> "\0\0\0\0\5\5VS234\0\0"#+ '\xE01DA'# -> "\0\0\0\0\5\5VS235\0\0"#+ '\xE01DB'# -> "\0\0\0\0\5\5VS236\0\0"#+ '\xE01DC'# -> "\0\0\0\0\5\5VS237\0\0"#+ '\xE01DD'# -> "\0\0\0\0\5\5VS238\0\0"#+ '\xE01DE'# -> "\0\0\0\0\5\5VS239\0\0"#+ '\xE01DF'# -> "\0\0\0\0\5\5VS240\0\0"#+ '\xE01E0'# -> "\0\0\0\0\5\5VS241\0\0"#+ '\xE01E1'# -> "\0\0\0\0\5\5VS242\0\0"#+ '\xE01E2'# -> "\0\0\0\0\5\5VS243\0\0"#+ '\xE01E3'# -> "\0\0\0\0\5\5VS244\0\0"#+ '\xE01E4'# -> "\0\0\0\0\5\5VS245\0\0"#+ '\xE01E5'# -> "\0\0\0\0\5\5VS246\0\0"#+ '\xE01E6'# -> "\0\0\0\0\5\5VS247\0\0"#+ '\xE01E7'# -> "\0\0\0\0\5\5VS248\0\0"#+ '\xE01E8'# -> "\0\0\0\0\5\5VS249\0\0"#+ '\xE01E9'# -> "\0\0\0\0\5\5VS250\0\0"#+ '\xE01EA'# -> "\0\0\0\0\5\5VS251\0\0"#+ '\xE01EB'# -> "\0\0\0\0\5\5VS252\0\0"#+ '\xE01EC'# -> "\0\0\0\0\5\5VS253\0\0"#+ '\xE01ED'# -> "\0\0\0\0\5\5VS254\0\0"#+ '\xE01EE'# -> "\0\0\0\0\5\5VS255\0\0"#+ '\xE01EF'# -> "\0\0\0\0\5\5VS256\0\0"#+ _ -> "\xff"#
+ test/ICU/NamesSpec.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE CPP, BlockArguments #-}++module ICU.NamesSpec+ ( spec+ ) where++import Control.Applicative (Alternative(..))+import Data.Foldable (traverse_)+import Data.Version (showVersion, versionBranch)+import Numeric (showHex)+import Test.Hspec+ ( describe+ , expectationFailure+ , it+ , pendingWith+ , Spec+ , HasCallStack, SpecWith )++import qualified ICU.Char as ICU+import qualified ICU.Names as ICUString+import qualified Unicode.Char as U+import qualified Unicode.Char.General.Names as String+#ifdef HAS_BYTESTRING+import qualified Data.ByteString.Char8 as B8+import qualified Unicode.Char.General.Names.ByteString as ByteString+#endif+#ifdef HAS_TEXT+import qualified Unicode.Char.General.Names.Text as Text+import qualified ICU.Names.Text as ICUText+#endif++spec :: Spec+spec = do+ describe "name" do+ checkAndGatherErrors "String" String.name ICUString.name+#ifdef HAS_BYTESTRING+ checkAndGatherErrors "ByteString"+ ByteString.name+ (fmap B8.pack . ICUString.name)+#endif+#ifdef HAS_TEXT+ checkAndGatherErrors "Text" Text.name ICUText.name+#endif+ describe "correctedName" do+ checkAndGatherErrors "String"+ String.correctedName+ ICUString.correctedName+#ifdef HAS_BYTESTRING+ checkAndGatherErrors "ByteString"+ ByteString.correctedName+ (fmap B8.pack . ICUString.correctedName)+#endif+#ifdef HAS_TEXT+ checkAndGatherErrors "Text"+ Text.correctedName+ ICUText.correctedName+#endif+ where+ ourUnicodeVersion = versionBranch U.unicodeVersion+ showCodePoint c = ("U+" ++) . fmap U.toUpper . showHex (U.ord c)++ -- There is no feature to display warnings other than `trace`, so+ -- hack our own:+ -- 1. Compare given functions in pure code and gather warning & errors+ -- 2. Create dummy spec that throw an expectation failure, if relevant.+ -- 3. Create pending spec for each Char that raises a Unicode version+ -- mismatch between ICU and unicode-data.+ checkAndGatherErrors+ :: forall a. (HasCallStack, Eq a, Show a)+ => String+ -> (Char -> Maybe a)+ -> (Char -> Maybe a)+ -> SpecWith ()+ checkAndGatherErrors label f fRef = do+ it label (maybe (pure ()) expectationFailure err)+ if null ws+ then pure ()+ else describe (label ++ " (Unicode version conflict)")+ (traverse_ mkWarning ws)+ where+ Acc ws err = foldr check (Acc [] Nothing) [minBound..maxBound]+ check c acc+ -- Test passed+ | n == nRef = acc+ -- Unicode version mismatch: char is not mapped in one of the libs:+ -- add warning.+ | ageMismatch c = acc{warnings=c : warnings acc}+ -- Error+ | otherwise =+ let !msg = mconcat+ [ showCodePoint c ": expected "+ , maybe "\"\"" show nRef+ , ", got ", maybe "\"\"" show n, "" ]+ in acc{firstError = firstError acc <|> Just msg}+ where+ !n = f c+ !nRef = fRef c+ mkWarning c = it (showCodePoint c "") . pendingWith $ mconcat+ [ "Incompatible ICU Unicode version: expected "+ , showVersion U.unicodeVersion+ , ", got: "+ , showVersion ICU.unicodeVersion+ , " (ICU character age is: "+ , showVersion (ICU.charAge c)+ , ")" ]+ ageMismatch c =+ let age = take 3 (versionBranch (ICU.charAge c))+ in age > ourUnicodeVersion || age == [0, 0, 0]++data Acc = Acc { warnings :: ![Char], firstError :: !(Maybe String) }
test/Main.hs view
@@ -1,1 +1,31 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}+{-# LANGUAGE CPP #-}++module Main where++import Test.Hspec ( Spec, hspec, describe )+import qualified Unicode.Char.General.NamesSpec as String+#ifdef HAS_TEXT+import qualified Unicode.Char.General.Names.TextSpec as Text+#endif+#ifdef HAS_BYTESTRING+import qualified Unicode.Char.General.Names.ByteStringSpec as ByteString+#endif+#ifdef HAS_ICU+import qualified ICU.NamesSpec as ICU+#endif++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "Unicode.Char.General.Names" String.spec+#ifdef HAS_BYTESTRING+ describe "Unicode.Char.General.Names.ByteString" ByteString.spec+#endif+#ifdef HAS_TEXT+ describe "Unicode.Char.General.Names.Text" Text.spec+#endif+#ifdef HAS_ICU+ describe "ICU.Names" ICU.spec+#endif
+ test/Unicode/Char/General/Names/ByteStringSpec.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE CPP, BlockArguments #-}++module Unicode.Char.General.Names.ByteStringSpec+ ( spec+ ) where++import Data.Foldable (traverse_)+import qualified Data.ByteString.Char8 as BS8+import qualified Unicode.Char.General.Names as String+import qualified Unicode.Char.General.Names.ByteString as BS+import Test.Hspec ( Spec, it, shouldBe, Expectation )++spec :: Spec+spec = do+ it "name" do+ traverse_ ((fmap BS8.unpack . BS.name) `shouldBeEqualTo` String.name)+ [minBound..maxBound]+ it "nameOrAlias" do+ traverse_+ ((fmap BS8.unpack . BS.nameOrAlias)+ `shouldBeEqualTo` String.nameOrAlias)+ [minBound..maxBound]+ it "correctedName" do+ traverse_+ ((fmap BS8.unpack . BS.correctedName)+ `shouldBeEqualTo` String.correctedName)+ [minBound..maxBound]+ it "nameAliases" do+ traverse_+ ((fmap BS8.unpack . BS.nameAliases)+ `shouldBeEqualTo` String.nameAliases)+ [minBound..maxBound]+ it "nameAliasesByType" do+ let check ty = traverse_+ ((fmap BS8.unpack . BS.nameAliasesByType ty)+ `shouldBeEqualTo` String.nameAliasesByType ty)+ [minBound..maxBound]+ traverse_ check [minBound..maxBound]+ it "nameAliasesWithTypes" do+ traverse_+ ((fmap (fmap (fmap BS8.unpack)) . BS.nameAliasesWithTypes)+ `shouldBeEqualTo` String.nameAliasesWithTypes)+ [minBound..maxBound]+ where+ shouldBeEqualTo+ :: forall a. (Eq a, Show a)+ => (Char -> a)+ -> (Char -> a)+ -> Char+ -> Expectation+ shouldBeEqualTo f fRef c = f c `shouldBe` fRef c
+ test/Unicode/Char/General/Names/TextSpec.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE CPP, BlockArguments #-}++module Unicode.Char.General.Names.TextSpec+ ( spec+ ) where++import Data.Foldable (traverse_)+import qualified Data.Text as T+import qualified Unicode.Char.General.Names as String+import qualified Unicode.Char.General.Names.Text as Text+import Test.Hspec ( Spec, it, shouldBe, Expectation )++spec :: Spec+spec = do+ it "name" do+ traverse_ ((fmap T.unpack . Text.name) `shouldBeEqualTo` String.name)+ [minBound..maxBound]+ it "nameOrAlias" do+ traverse_+ ((fmap T.unpack . Text.nameOrAlias)+ `shouldBeEqualTo` String.nameOrAlias)+ [minBound..maxBound]+ it "correctedName" do+ traverse_+ ((fmap T.unpack . Text.correctedName)+ `shouldBeEqualTo` String.correctedName)+ [minBound..maxBound]+ it "nameAliases" do+ traverse_+ ((fmap T.unpack . Text.nameAliases)+ `shouldBeEqualTo` String.nameAliases)+ [minBound..maxBound]+ it "nameAliasesByType" do+ let check ty = traverse_+ ((fmap T.unpack . Text.nameAliasesByType ty)+ `shouldBeEqualTo` String.nameAliasesByType ty)+ [minBound..maxBound]+ traverse_ check [minBound..maxBound]+ it "nameAliasesWithTypes" do+ traverse_+ ((fmap (fmap (fmap T.unpack)) . Text.nameAliasesWithTypes)+ `shouldBeEqualTo` String.nameAliasesWithTypes)+ [minBound..maxBound]+ where+ shouldBeEqualTo+ :: forall a. (Eq a, Show a)+ => (Char -> a)+ -> (Char -> a)+ -> Char+ -> Expectation+ shouldBeEqualTo f fRef c = f c `shouldBe` fRef c
test/Unicode/Char/General/NamesSpec.hs view
@@ -4,13 +4,27 @@ ( spec ) where +import GHC.Exts (Char(..), isTrue#, (<#), ord#, andI#) import Unicode.Char.General+ ( generalCategory,+ GeneralCategory(NotAssigned, Surrogate, PrivateUse) ) import Unicode.Char.General.Names+ ( NameAliasType (..), correctedName, name, nameOrAlias, nameAliasesWithTypes, nameAliases, nameAliasesByType )+import qualified Unicode.Internal.Char.UnicodeData.DerivedName as DerivedName import Data.Foldable (traverse_)-import Test.Hspec+import Test.Hspec ( Spec, it, shouldBe, shouldSatisfy, describe ) spec :: Spec spec = do+ it "template hex code length is 4 or 5"+ -- Ensure no padding is required for hexadecimal codepoints and+ -- that we the allocation is correct for ByteString & Text APIs.+ let {+ check (C# c#) = case DerivedName.name c# of+ (# _, len# #) ->+ isTrue# (len# <# DerivedName.CjkCompatibilityIdeograph) ||+ isTrue# ((0xFFF# <# ord# c#) `andI#` (ord# c# <# 0x100000#))+ } in traverse_ (`shouldSatisfy` check) [minBound..maxBound] it "name: Test some characters" do name minBound `shouldBe` Nothing name 'A' `shouldBe` Just "LATIN CAPITAL LETTER A"@@ -71,6 +85,44 @@ -- Last name defined, as of Unicode 15.0.0 nameOrAlias '\xe01ef' `shouldBe` Just "VARIATION SELECTOR-256" nameOrAlias maxBound `shouldBe` Nothing+ it "nameAliasesWithTypes: test some characters" do+ nameAliasesWithTypes '\0' `shouldBe`+ [(Control, ["NULL"]), (Abbreviation, ["NUL"])]+ nameAliasesWithTypes '\x0A' `shouldBe`+ [(Control, ["LINE FEED", "NEW LINE", "END OF LINE"])+ ,(Abbreviation, ["LF", "NL", "EOL"])]+ nameAliasesWithTypes '\x80' `shouldBe`+ [(Figment, ["PADDING CHARACTER"]), (Abbreviation, ["PAD"])]+ nameAliasesWithTypes '\x01A2' `shouldBe`+ [(Correction, ["LATIN CAPITAL LETTER GHA"])]+ nameAliasesWithTypes '\xFEFF' `shouldBe`+ [(Alternate, ["BYTE ORDER MARK"]), (Abbreviation, ["BOM", "ZWNBSP"])]+ nameAliasesWithTypes '\xE01EF' `shouldBe`+ [(Abbreviation, ["VS256"])]+ it "nameAliasesByType" do+ let f c = foldr+ (\t -> case nameAliasesByType t c of {[] -> id;xs -> ((t,xs):)})+ mempty+ [minBound..maxBound]+ check c = f c == nameAliasesWithTypes c+ traverse_ (`shouldSatisfy` check) [minBound..maxBound]+ describe "nameAliases" do+ it "test some characters" do+ nameAliases '\0' `shouldBe`+ ["NULL", "NUL"]+ nameAliases '\x0A' `shouldBe`+ ["LINE FEED", "NEW LINE", "END OF LINE", "LF", "NL", "EOL"]+ nameAliases '\x80' `shouldBe`+ ["PADDING CHARACTER", "PAD"]+ nameAliases '\x01A2' `shouldBe`+ ["LATIN CAPITAL LETTER GHA"]+ nameAliases '\xFEFF' `shouldBe`+ ["BYTE ORDER MARK", "BOM", "ZWNBSP"]+ nameAliases '\xE01EF' `shouldBe`+ ["VS256"]+ it "compare to nameAliasesWithTypes" do+ let check c = nameAliases c == mconcat (snd <$> nameAliasesWithTypes c)+ traverse_ (`shouldSatisfy` check) [minBound..maxBound] it "Every defined character has at least a name or an alias" do let checkName c = case nameOrAlias c of Just _ -> True@@ -79,5 +131,4 @@ PrivateUse -> True NotAssigned -> True _ -> False- traverse_ (`shouldSatisfy` checkName)- [minBound..maxBound]+ traverse_ (`shouldSatisfy` checkName) [minBound..maxBound]
test/export_all_chars.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE BlockArguments #-}- ------------------------------------------------------------------------------- -- | -- Description: Export all characters and their properties to a CSV file.@@ -9,11 +7,11 @@ module Main where -import Data.Char-import Data.Foldable-import Data.Version+import Data.Char ( ord )+import Data.Foldable ( traverse_ )+import Data.Version ( showVersion ) import Unicode.Char (unicodeVersion)-import Numeric+import Numeric ( showHex ) import qualified Unicode.Char.General.Names as UNames @@ -39,4 +37,4 @@ addEntry c = do putStr (mkCodePointHex c) putChar ','- putStrLn (show (UNames.name c))+ print (UNames.name c)
unicode-data-names.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: unicode-data-names-version: 0.2.0+version: 0.3.0 synopsis: Unicode characters names and aliases description: @unicode-data-names@ provides Haskell APIs to access the Unicode@@ -26,11 +26,14 @@ , GHC==8.6.5 , GHC==8.8.4 , GHC==8.10.7- , GHC==9.0.1- , GHC==9.2.1- , GHC==9.4.2+ , GHC==9.0.2+ , GHC==9.2.8+ , GHC==9.4.8+ , GHC==9.6.5+ , GHC==9.8.2+ , GHC==9.10.1 -extra-source-files:+extra-doc-files: Changelog.md README.md @@ -38,6 +41,22 @@ type: git location: https://github.com/composewell/unicode-data +flag has-text+ description: Expose an API using the text package+ manual: True+ default: False++flag has-bytestring+ description: Expose an API using the bytestring package+ manual: True+ default: False++flag dev-has-icu+ description:+ Use ICU for test and benchmark. Intended for development on the repository.+ manual: True+ default: False+ flag export-all-chars description: Build the export-all-chars executable manual: True@@ -55,8 +74,6 @@ LambdaCase -- Experimental, may lead to issues- DeriveAnyClass- TemplateHaskell UnboxedTuples common compile-options@@ -69,7 +86,6 @@ library import: default-extensions, compile-options- default-language: Haskell2010 exposed-modules: -- The module structure is derived from -- https://www.unicode.org/reports/tr44/#Property_Index_Table@@ -80,10 +96,28 @@ -- the properties are generated. Unicode.Internal.Char.UnicodeData.DerivedName Unicode.Internal.Char.UnicodeData.NameAliases+ Unicode.Internal.Char.Names.Version+ other-modules:+ -- Internal files+ Unicode.Internal.Bits.Names hs-source-dirs: lib build-depends:- base >= 4.7 && < 4.18+ base >= 4.7 && < 4.21,+ -- Support for raw string literals unpacking is included in base ≥ 4.15+ if impl(ghc < 9.0.0)+ build-depends:+ ghc-prim >= 0.3.1 && < 1.0+ if flag(has-text)+ exposed-modules:+ Unicode.Char.General.Names.Text+ build-depends:+ text >= 2.0 && < 2.2+ if flag(has-bytestring)+ exposed-modules:+ Unicode.Char.General.Names.ByteString+ build-depends:+ bytestring >= 0.11.2 && < 0.13 test-suite test import: default-extensions, compile-options@@ -94,17 +128,31 @@ other-modules: Unicode.Char.General.NamesSpec build-depends:- base >= 4.7 && < 4.18- , hspec >= 2.0 && < 2.11- , unicode-data >= 0.4 && < 0.5+ base >= 4.7 && < 4.21+ , hspec >= 2.0 && < 2.12+ , unicode-data >= 0.5 && < 0.6 , unicode-data-names- build-tool-depends:- hspec-discover:hspec-discover >= 2.0 && < 2.11- default-language: Haskell2010+ if flag(has-text)+ cpp-options: -DHAS_TEXT+ other-modules:+ Unicode.Char.General.Names.TextSpec+ build-depends:+ text >= 2.0 && < 2.2+ if flag(has-bytestring)+ cpp-options: -DHAS_BYTESTRING+ other-modules:+ Unicode.Char.General.Names.ByteStringSpec+ build-depends:+ bytestring >= 0.11.2 && < 0.13+ if flag(dev-has-icu)+ cpp-options: -DHAS_ICU+ other-modules:+ ICU.NamesSpec+ build-depends:+ icu executable export-all-chars import: default-extensions, compile-options- default-language: Haskell2010 ghc-options: -O2 hs-source-dirs: test main-is: export_all_chars.hs@@ -123,9 +171,26 @@ hs-source-dirs: bench main-is: Main.hs build-depends:- base >= 4.7 && < 4.18,- deepseq >= 1.1 && < 1.5,- tasty-bench >= 0.2.5 && < 0.4,- tasty >= 1.4.1,+ base >= 4.7 && < 4.21,+ deepseq >= 1.1 && < 1.6,+ tasty-bench >= 0.2.5 && < 0.4,+ tasty >= 1.4.1 && < 1.6,+ unicode-data >= 0.5 && < 0.6, unicode-data-names- ghc-options: -O2 -fdicts-strict -rtsopts+ if flag(has-text)+ cpp-options: -DHAS_TEXT+ build-depends:+ text >= 2.0 && < 2.2+ if flag(has-bytestring)+ cpp-options: -DHAS_BYTESTRING+ build-depends:+ bytestring >= 0.11.2 && < 0.13+ if flag(dev-has-icu)+ cpp-options: -DHAS_ICU+ build-depends:+ icu+ -- [NOTE] Recommendation of tasty-bench to reduce garbage collection noisiness+ ghc-options: -O2 -fdicts-strict -rtsopts -with-rtsopts=-A32m+ -- [NOTE] Recommendation of tasty-bench for comparison against baseline+ if impl(ghc >= 8.6)+ ghc-options: -fproc-alignment=64