ascii-th-1.0.0.0: ASCII/QuasiQuoters.hs
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.IsChar' 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.IsString' 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."