ascii-th 1.0.0.4 → 1.0.0.6
raw patch · 7 files changed
+317/−258 lines, 7 filesdep +ascii-thdep +bytestringdep +textdep ~ascii-chardep ~ascii-supersetdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: ascii-th, bytestring, text
Dependency ranges changed: ascii-char, ascii-superset, base
API changes (from Hackage documentation)
Files
- ASCII/QuasiQuoters.hs +0/−120
- ASCII/TemplateHaskell.hs +0/−135
- ascii-th.cabal +15/−3
- changelog.txt +1/−0
- library/ASCII/QuasiQuoters.hs +105/−0
- library/ASCII/TemplateHaskell.hs +123/−0
- test/test.hs +73/−0
− ASCII/QuasiQuoters.hs
@@ -1,120 +0,0 @@-module ASCII.QuasiQuoters ( char, string ) where--import ASCII.Char ( Char )-import ASCII.Superset ( toCharMaybe, toCharListMaybe )-import ASCII.TemplateHaskell ( isCharExp, isCharPat, isStringExp, isStringPat )-import Control.Monad ( (>=>), return )-import Control.Monad.Fail ( MonadFail, fail )-import Data.Maybe ( Maybe (..) )-import Language.Haskell.TH.Quote ( QuasiQuoter (..) )-import Language.Haskell.TH.Syntax ( Q, Exp, Pat )--import qualified Data.Char as Unicode-import qualified Data.String as Unicode--{- $setup-->>> :set -fno-warn-overlapping-patterns->>> :set -XNoQuasiQuotes->>> :set -XNoViewPatterns->>> import qualified ASCII->>> import qualified Data.String->>> import qualified Data.Text->>> import qualified Data.ByteString.Builder->>> import Data.Word (Word8)->>> import ASCII.Char->>> import ASCII.QuasiQuoters---}--{- | Produces an expression or a pattern corresponding to an ASCII character.--The result will have an 'ASCII.Superset.CharSuperset' constraint; since this is polymorphic, use with a type signature to specify the particular you want is recommended.--The quasi-quoted string must consist of a single character that is within the ASCII character set.-->>> :set -XQuasiQuotes-->>> [char|e|] :: ASCII.Char-SmallLetterE-->>> [char|e|] :: Word8-101--Use in a pattern context requires enabling the @ViewPatterns@ language extension.-->>> :set -XViewPatterns-->>> case Tilde of [char|@|] -> 1; [char|~|] -> 2; _ -> 3-2---}--char :: QuasiQuoter-char = expPatQQ requireOneAscii isCharExp isCharPat--{- | Produces an expression or a pattern corresponding to an ASCII string.--The result will have an 'ASCII.Superset.StringSuperset' constraint; since this is polymorphic, use with a type signature to specify the particular you want is recommended.--The quasi-quoted string must consist only of characters are within the ASCII character set.-->>> :set -XQuasiQuotes-->>> [string|Hello!|] :: [ASCII.Char]-[CapitalLetterH,SmallLetterE,SmallLetterL,SmallLetterL,SmallLetterO,ExclamationMark]-->>> [string|Hello!|] :: Data.String.String-"Hello!"-->>> [string|Hello!|] :: Data.Text.Text-"Hello!"-->>> Data.ByteString.Builder.toLazyByteString [string|Hello!|]-"Hello!"---Use in a pattern context requires enabling the @ViewPatterns@ language extension.-->>> :set -XViewPatterns-->>> case [CapitalLetterH, SmallLetterI] of [string|Bye|] -> 1; [string|Hi|] -> 2; _ -> 3-2---}--string :: QuasiQuoter-string = expPatQQ requireAsciiList isStringExp isStringPat--requireOneAscii :: Unicode.String -> Q Char-requireOneAscii = requireOne >=> requireAscii--oneMaybe :: [a] -> Maybe a-oneMaybe xs = case xs of [x] -> Just x; _ -> Nothing--requireOne :: Unicode.String -> Q Unicode.Char-requireOne = oneMaybe || "Must be exactly one character."--requireAscii :: Unicode.Char -> Q Char-requireAscii = toCharMaybe || "Must be an ASCII character."--requireAsciiList :: Unicode.String -> Q [Char]-requireAsciiList = toCharListMaybe || "Must be only ASCII characters."--(||) :: (a -> Maybe b) -> Unicode.String -> a -> Q b-f || msg = \a -> case f a of Just b -> return b; Nothing -> fail msg--expPatQQ :: (Unicode.String -> Q a) -> (a -> Q Exp) -> (a -> Q Pat) -> QuasiQuoter-expPatQQ f a b =- QuasiQuoter- { quoteExp = f >=> a- , quotePat = f >=> b- , quoteType = notType- , quoteDec = notDec- }--notType :: MonadFail m => a -> m b-notType _ = fail "Cannot be used in a type context."--notDec :: MonadFail m => a -> m b-notDec _ = fail "Cannot be used in a declaration context."
− ASCII/TemplateHaskell.hs
@@ -1,135 +0,0 @@-module ASCII.TemplateHaskell (-- {- * Characters -} charExp, charPat,- {- * Character lists -} charListExp, charListPat,- {- * Character supersets -} isCharExp, isCharPat,- {- * String supersets -} isStringExp, isStringPat-- ) where--import qualified ASCII.Char as ASCII-import qualified ASCII.Superset as S--import Data.Data ( Data )-import Data.Maybe ( Maybe (..) )-import Language.Haskell.TH.Syntax ( Q, Exp, Pat, dataToExpQ, dataToPatQ )--{- $setup-->>> :set -XNoViewPatterns->>> import ASCII.Char (Char (..))->>> import ASCII.Refinement (ASCII)->>> import ASCII.Superset (toCharOrFail)->>> import ASCII.TemplateHaskell (charExp)->>> import Control.Monad ((>>=))->>> import Data.Word (Word8)---}--exp :: Data a => a -> Q Exp-exp = dataToExpQ (\_ -> Nothing)--pat :: Data a => a -> Q Pat-pat = dataToPatQ (\_ -> Nothing)--{- |-->>> $(toCharOrFail 'F' >>= charExp)-CapitalLetterF-->>> $(toCharOrFail '\DEL' >>= charExp)-Delete---}--charExp :: ASCII.Char -> Q Exp-charExp = exp--{- |-->>> :{->>> case SmallLetterS of->>> $(toCharOrFail 'r' >>= charPat) -> 1->>> $(toCharOrFail 's' >>= charPat) -> 2->>> _ -> 3->>> :}-2--This is the same as:-->>> :{->>> case SmallLetterS of->>> SmallLetterR -> 1->>> SmallLetterS -> 2->>> _ -> 3->>> :}-2---}--charPat :: ASCII.Char -> Q Pat-charPat = pat--{- |-->>> $(charListExp [CapitalLetterH, SmallLetterI])-[CapitalLetterH,SmallLetterI]---}--charListExp :: [ASCII.Char] -> Q Exp-charListExp = exp--{- |-->>> :{->>> case [CapitalLetterH, SmallLetterI] of->>> $(charListPat [CapitalLetterH, SmallLetterA]) -> 1->>> $(charListPat [CapitalLetterH, SmallLetterI]) -> 2->>> _ -> 3->>> :}-2---}--charListPat :: [ASCII.Char] -> Q Pat-charListPat = pat--{- |-->>> $(isCharExp CapitalLetterA) :: ASCII.Char-CapitalLetterA-->>> $(isCharExp CapitalLetterA) :: Word8-65-->>> $(isCharExp CapitalLetterA) :: ASCII Word8-asciiUnsafe 65---}--isCharExp :: ASCII.Char -> Q Exp-isCharExp x = [| S.fromChar $(charExp x) |]--{- |-->>> :set -XViewPatterns-->>> :{->>> case (66 :: Word8) of->>> $(isCharPat CapitalLetterA) -> 1->>> $(isCharPat CapitalLetterB) -> 2->>> _ -> 3->>> :}-2---}--isCharPat :: ASCII.Char -> Q Pat-isCharPat x = [p| (S.toCharMaybe -> Just $(charPat x)) |]--isStringExp :: [ASCII.Char] -> Q Exp-isStringExp xs = [| S.fromCharList $(charListExp xs) |]--isStringPat :: [ASCII.Char] -> Q Pat-isStringPat xs = [p| (S.toCharListMaybe -> Just $(charListPat xs)) |]
ascii-th.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.0 name: ascii-th-version: 1.0.0.4+version: 1.0.0.6 synopsis: Template Haskell support for ASCII category: Data, Text @@ -18,8 +18,6 @@ build-type: Simple -tested-with: GHC == 9.0.1, GHC == 8.10.1, GHC == 8.8.1, GHC == 8.6.5, GHC == 8.4.3- extra-source-files: changelog.txt source-repository head@@ -33,6 +31,7 @@ default-extensions: QuasiQuotes default-extensions: ViewPatterns ghc-options: -Wall+ hs-source-dirs: library build-depends: ascii-char ^>= 1.0 build-depends: ascii-superset ^>= 1.0@@ -42,3 +41,16 @@ exposed-modules: ASCII.TemplateHaskell exposed-modules: ASCII.QuasiQuoters++test-suite test+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ default-extensions: NoImplicitPrelude+ default-extensions: OverloadedStrings+ default-extensions: QuasiQuotes+ default-extensions: TemplateHaskell+ default-extensions: ViewPatterns+ ghc-options: -Wall -fno-warn-overlapping-patterns+ hs-source-dirs: test+ main-is: test.hs+ build-depends: ascii-char, ascii-superset, ascii-th, base, bytestring, text
changelog.txt view
@@ -1,3 +1,4 @@ 1.0.0.0 - 2020-05-05 - Initial release 1.0.0.2 - 2020-05-18 - Support GHC 8.10 1.0.0.4 - 2021-02-10 - Support GHC 9.0+1.0.0.6 - 2021-09-26 - Add a test suite
+ library/ASCII/QuasiQuoters.hs view
@@ -0,0 +1,105 @@+module ASCII.QuasiQuoters ( char, string ) where++import ASCII.Char ( Char )+import ASCII.Superset ( toCharMaybe, toCharListMaybe )+import ASCII.TemplateHaskell ( isCharExp, isCharPat, isStringExp, isStringPat )+import Control.Monad ( (>=>), return )+import Control.Monad.Fail ( MonadFail, fail )+import Data.Maybe ( Maybe (..) )+import Language.Haskell.TH.Quote ( QuasiQuoter (..) )+import Language.Haskell.TH.Syntax ( Q, Exp, Pat )++import qualified Data.Char as Unicode+import qualified Data.String as Unicode++{- | Produces an expression or a pattern corresponding to an ASCII character.++The result will have an 'ASCII.Superset.CharSuperset' constraint; since this is polymorphic, use with a type signature to specify the particular you want is recommended.++The quasi-quoted string must consist of a single character that is within the ASCII character set.++>>> :set -XQuasiQuotes++>>> [char|e|] :: ASCII.Char+SmallLetterE++>>> [char|e|] :: Word8+101++Use in a pattern context requires enabling the @ViewPatterns@ language extension.++>>> :set -XViewPatterns++>>> case Tilde of [char|@|] -> 1; [char|~|] -> 2; _ -> 3+2++-}++char :: QuasiQuoter+char = expPatQQ requireOneAscii isCharExp isCharPat++{- | Produces an expression or a pattern corresponding to an ASCII string.++The result will have an 'ASCII.Superset.StringSuperset' constraint; since this is polymorphic, use with a type signature to specify the particular you want is recommended.++The quasi-quoted string must consist only of characters are within the ASCII character set.++>>> :set -XQuasiQuotes++>>> [string|Hello!|] :: [ASCII.Char]+[CapitalLetterH,SmallLetterE,SmallLetterL,SmallLetterL,SmallLetterO,ExclamationMark]++>>> [string|Hello!|] :: Data.String.String+"Hello!"++>>> [string|Hello!|] :: Data.Text.Text+"Hello!"++>>> Data.ByteString.Builder.toLazyByteString [string|Hello!|]+"Hello!"+++Use in a pattern context requires enabling the @ViewPatterns@ language extension.++>>> :set -XViewPatterns++>>> case [CapitalLetterH, SmallLetterI] of [string|Bye|] -> 1; [string|Hi|] -> 2; _ -> 3+2++-}++string :: QuasiQuoter+string = expPatQQ requireAsciiList isStringExp isStringPat++requireOneAscii :: Unicode.String -> Q Char+requireOneAscii = requireOne >=> requireAscii++oneMaybe :: [a] -> Maybe a+oneMaybe xs = case xs of [x] -> Just x; _ -> Nothing++requireOne :: Unicode.String -> Q Unicode.Char+requireOne = oneMaybe || "Must be exactly one character."++requireAscii :: Unicode.Char -> Q Char+requireAscii = toCharMaybe || "Must be an ASCII character."++requireAsciiList :: Unicode.String -> Q [Char]+requireAsciiList = toCharListMaybe || "Must be only ASCII characters."++(||) :: (a -> Maybe b) -> Unicode.String -> a -> Q b+f || msg = \a -> case f a of Just b -> return b; Nothing -> fail msg++expPatQQ :: (Unicode.String -> Q a) -> (a -> Q Exp) -> (a -> Q Pat) -> QuasiQuoter+expPatQQ f a b =+ QuasiQuoter+ { quoteExp = f >=> a+ , quotePat = f >=> b+ , quoteType = notType+ , quoteDec = notDec+ }++notType :: MonadFail m => a -> m b+notType _ = fail "Cannot be used in a type context."++notDec :: MonadFail m => a -> m b+notDec _ = fail "Cannot be used in a declaration context."
+ library/ASCII/TemplateHaskell.hs view
@@ -0,0 +1,123 @@+module ASCII.TemplateHaskell (++ {- * Characters -} charExp, charPat,+ {- * Character lists -} charListExp, charListPat,+ {- * Character supersets -} isCharExp, isCharPat,+ {- * String supersets -} isStringExp, isStringPat++ ) where++import qualified ASCII.Char as ASCII+import qualified ASCII.Superset as S++import Data.Data ( Data )+import Data.Maybe ( Maybe (..) )+import Language.Haskell.TH.Syntax ( Q, Exp, Pat, dataToExpQ, dataToPatQ )++exp :: Data a => a -> Q Exp+exp = dataToExpQ (\_ -> Nothing)++pat :: Data a => a -> Q Pat+pat = dataToPatQ (\_ -> Nothing)++{- |++>>> $(toCharOrFail 'F' >>= charExp)+CapitalLetterF++>>> $(toCharOrFail '\DEL' >>= charExp)+Delete++-}++charExp :: ASCII.Char -> Q Exp+charExp = exp++{- |++>>> :{+>>> case SmallLetterS of+>>> $(toCharOrFail 'r' >>= charPat) -> 1+>>> $(toCharOrFail 's' >>= charPat) -> 2+>>> _ -> 3+>>> :}+2++This is the same as:++>>> :{+>>> case SmallLetterS of+>>> SmallLetterR -> 1+>>> SmallLetterS -> 2+>>> _ -> 3+>>> :}+2++-}++charPat :: ASCII.Char -> Q Pat+charPat = pat++{- |++>>> $(charListExp [CapitalLetterH, SmallLetterI])+[CapitalLetterH,SmallLetterI]++-}++charListExp :: [ASCII.Char] -> Q Exp+charListExp = exp++{- |++>>> :{+>>> case [CapitalLetterH, SmallLetterI] of+>>> $(charListPat [CapitalLetterH, SmallLetterA]) -> 1+>>> $(charListPat [CapitalLetterH, SmallLetterI]) -> 2+>>> _ -> 3+>>> :}+2++-}++charListPat :: [ASCII.Char] -> Q Pat+charListPat = pat++{- |++>>> $(isCharExp CapitalLetterA) :: ASCII.Char+CapitalLetterA++>>> $(isCharExp CapitalLetterA) :: Word8+65++>>> $(isCharExp CapitalLetterA) :: ASCII Word8+asciiUnsafe 65++-}++isCharExp :: ASCII.Char -> Q Exp+isCharExp x = [| S.fromChar $(charExp x) |]++{- |++>>> :set -XViewPatterns++>>> :{+>>> case (66 :: Word8) of+>>> $(isCharPat CapitalLetterA) -> 1+>>> $(isCharPat CapitalLetterB) -> 2+>>> _ -> 3+>>> :}+2++-}++isCharPat :: ASCII.Char -> Q Pat+isCharPat x = [p| (S.toCharMaybe -> Just $(charPat x)) |]++isStringExp :: [ASCII.Char] -> Q Exp+isStringExp xs = [| S.fromCharList $(charListExp xs) |]++isStringPat :: [ASCII.Char] -> Q Pat+isStringPat xs = [p| (S.toCharListMaybe -> Just $(charListPat xs)) |]
+ test/test.hs view
@@ -0,0 +1,73 @@+module Main where++import ASCII.QuasiQuoters+import ASCII.TemplateHaskell++import ASCII.Char (Char (..))+import ASCII.Refinement (ASCII, asciiUnsafe)+import ASCII.Superset (toCharOrFail)++import Control.Applicative (Applicative (..))+import Control.Monad (Monad (..))+import Data.Bool (Bool (..))+import Data.Eq (Eq ((==)))+import Data.Function ((.), ($))+import Data.Functor (Functor (..))+import Data.List (intercalate, map, null)+import Data.Semigroup ((<>))+import Data.String (String)+import Data.Text (Text)+import Data.Word (Word8)+import Numeric.Natural (Natural)+import Prelude (Integer)+import System.Exit (die)+import System.IO (IO, putStrLn)+import Text.Show (show)++import qualified Data.ByteString.Builder as BS.Builder++main :: IO ()+main = dieIfFailures $ do+ test 1 $ ([char|e|] :: Char) == SmallLetterE+ test 2 $ ([char|e|] :: Word8) == 101+ test 3 $ (case Tilde of [char|@|] -> 1 :: Integer; [char|~|] -> 2; _ -> 3) == 2+ test 4 $ ([string|Hello!|] :: [Char]) == [CapitalLetterH, SmallLetterE, SmallLetterL, SmallLetterL, SmallLetterO, ExclamationMark]+ test 5 $ ([string|Hello!|] :: String) == "Hello!"+ test 6 $ ([string|Hello!|] :: Text) == "Hello!"+ test 7 $ (BS.Builder.toLazyByteString [string|Hello!|] == "Hello!")+ test 8 $ (case [CapitalLetterH, SmallLetterI] of [string|Bye|] -> 1 :: Integer; [string|Hi|] -> 2; _ -> 3) == 2+ test 9 $ $(toCharOrFail 'F' >>= charExp) == CapitalLetterF+ test 10 $ $(toCharOrFail '\DEL' >>= charExp) == Delete+ test 11 $ case SmallLetterS of { $(toCharOrFail 'r' >>= charPat) -> 1 :: Integer; $(toCharOrFail 's' >>= charPat) -> 2; _ -> 3 } == 2+ test 12 $ $(charListExp [CapitalLetterH, SmallLetterI]) == [CapitalLetterH, SmallLetterI]+ test 13 $ case [CapitalLetterH, SmallLetterI] of { $(charListPat [CapitalLetterH, SmallLetterA]) -> 1 :: Integer; $(charListPat [CapitalLetterH, SmallLetterI]) -> 2; _ -> 3 } == 2+ test 14 $ ($(isCharExp CapitalLetterA) :: Char) == CapitalLetterA+ test 15 $ ($(isCharExp CapitalLetterA) :: Word8) == 65+ test 16 $ ($(isCharExp CapitalLetterA) :: ASCII Word8) == asciiUnsafe 65+ test 17 $ case (66 :: Word8) of { $(isCharPat CapitalLetterA) -> 1 :: Integer; $(isCharPat CapitalLetterB) -> 2; _ -> 3 } == 2++dieIfFailures :: Failures a -> IO a+dieIfFailures (Failures fs x) =+ if null fs+ then do putStrLn "💯"; return x+ else die $ intercalate " " (map (("🔥" <> ) . show) fs)++type TestNumber = Natural++test :: TestNumber -> Bool -> Failures ()+test n t = Failures (if t then [] else [n]) ()++data Failures a = Failures [TestNumber] a++instance Functor Failures+ where+ fmap f (Failures a x) = Failures a (f x)++instance Applicative Failures+ where+ pure x = Failures [] x+ Failures a f <*> Failures b x = Failures (a <> b) (f x)++instance Monad Failures+ where+ Failures a x >>= f = let Failures b y = f x in Failures (a <> b) y