{-# LANGUAGE CPP #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
module Data.Textual
(
Printable(..)
, maybePrint
, toString
, toText
, toLazyText
, toAscii
, toLazyAscii
, toUtf8
, toLazyUtf8
, Textual(..)
, Parsed(..)
, isParsed
, isMalformed
, maybeParsed
, builtInParser
, parseString
, parseStringAs
, parseText
, parseTextAs
, parseLazyText
, parseLazyTextAs
, parseAscii
, parseAsciiAs
, parseLazyAscii
, parseLazyAsciiAs
, parseUtf8
, parseUtf8As
, parseLazyUtf8
, parseLazyUtf8As
, fromString
, fromStringAs
, fromText
, fromTextAs
, fromLazyText
, fromLazyTextAs
, fromAscii
, fromAsciiAs
, fromLazyAscii
, fromLazyAsciiAs
, fromUtf8
, fromUtf8As
, fromLazyUtf8
, fromLazyUtf8As
) where
import Prelude hiding (print)
import Data.Typeable (Typeable)
import Data.Foldable (Foldable)
import Data.Traversable (Traversable)
import Data.Monoid (mempty)
import Data.Int
import Data.Word
import Data.Ratio (Ratio)
import Data.Fixed (Fixed, HasResolution)
import Data.List (stripPrefix)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BS8
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BL8
import qualified Data.Text as TS
import qualified Data.Text.Lazy as TL
import Data.Text.Lazy.Encoding (decodeUtf8)
import Data.Textual.Integral
import Data.Textual.Fractional
import Control.Applicative
import qualified Text.Printer as TP
import qualified Text.Printer.Integral as TP
import qualified Text.Printer.Fractional as TP
import Text.Parser.Combinators (Parsing, (<?>))
import qualified Text.Parser.Combinators as PC
import Text.Parser.Char (CharParsing)
import qualified Text.Parser.Char as PC
class Printable α where
print ∷ TP.Printer p ⇒ α → p
instance Printable Char where
print = TP.char
{-# INLINE print #-}
instance Printable String where
print = TP.string
{-# INLINE print #-}
instance Printable TS.Text where
print = TP.text
{-# INLINE print #-}
instance Printable TL.Text where
print = TP.lazyText
{-# INLINE print #-}
instance Printable Integer where
print = TP.decimal
{-# INLINE print #-}
instance Printable Int where
print = TP.decimal
{-# INLINE print #-}
instance Printable Int8 where
print = TP.decimal
{-# INLINE print #-}
instance Printable Int16 where
print = TP.decimal
{-# INLINE print #-}
instance Printable Int32 where
print = TP.decimal
{-# INLINE print #-}
instance Printable Int64 where
print = TP.decimal
{-# INLINE print #-}
instance Printable Word where
print = TP.nnDecimal
{-# INLINE print #-}
instance Printable Word8 where
print = TP.nnDecimal
{-# INLINE print #-}
instance Printable Word16 where
print = TP.nnDecimal
{-# INLINE print #-}
instance Printable Word32 where
print = TP.nnDecimal
{-# INLINE print #-}
instance Printable Word64 where
print = TP.nnDecimal
{-# INLINE print #-}
instance Integral α ⇒ Printable (Ratio α) where
print = TP.fraction
{-# INLINE print #-}
instance HasResolution α ⇒ Printable (Fixed α) where
print = TP.string7 . show
{-# INLINE print #-}
instance Printable Float where
print = TP.string7 . show
{-# INLINE print #-}
instance Printable Double where
print = TP.string7 . show
{-# INLINE print #-}
maybePrint ∷ (TP.Printer p, Printable α) ⇒ Maybe α → p
maybePrint = maybe mempty print
{-# INLINE maybePrint #-}
toString ∷ Printable α ⇒ α → String
toString = TP.buildString . print
{-# INLINE[1] toString #-}
toText ∷ Printable α ⇒ α → TS.Text
toText = TP.buildText . print
{-# INLINE[1] toText #-}
toLazyText ∷ Printable α ⇒ α → TL.Text
toLazyText = TP.buildLazyText . print
{-# INLINE[1] toLazyText #-}
toAscii ∷ Printable α ⇒ α → BS.ByteString
toAscii = TP.buildAscii . print
{-# INLINE[1] toAscii #-}
toLazyAscii ∷ Printable α ⇒ α → BL.ByteString
toLazyAscii = TP.buildLazyAscii . print
{-# INLINE[1] toLazyAscii #-}
toUtf8 ∷ Printable α ⇒ α → BS.ByteString
toUtf8 = TP.buildUtf8 . print
{-# INLINE[1] toUtf8 #-}
toLazyUtf8 ∷ Printable α ⇒ α → BL.ByteString
toLazyUtf8 = TP.buildLazyUtf8 . print
{-# INLINE[1] toLazyUtf8 #-}
class Printable α ⇒ Textual α where
textual ∷ (Monad μ, CharParsing μ) ⇒ μ α
instance Textual Char where
textual = PC.anyChar
{-# INLINE textual #-}
instance Textual Integer where
textual = number Decimal
{-# INLINE textual #-}
instance Textual Int where
textual = bounded Decimal
{-# INLINE textual #-}
instance Textual Int8 where
textual = bounded Decimal
{-# INLINE textual #-}
instance Textual Int16 where
textual = bounded Decimal
{-# INLINE textual #-}
instance Textual Int32 where
textual = bounded Decimal
{-# INLINE textual #-}
instance Textual Int64 where
textual = bounded Decimal
{-# INLINE textual #-}
instance Textual Word where
textual = nnBounded Decimal
{-# INLINE textual #-}
instance Textual Word8 where
textual = nnBounded Decimal
{-# INLINE textual #-}
instance Textual Word16 where
textual = nnBounded Decimal
{-# INLINE textual #-}
instance Textual Word32 where
textual = nnBounded Decimal
{-# INLINE textual #-}
instance Textual Word64 where
textual = nnBounded Decimal
{-# INLINE textual #-}
instance Integral α ⇒ Textual (Ratio α) where
textual = fraction
{-# INLINE textual #-}
instance HasResolution α ⇒ Textual (Fixed α) where
textual = fractional
{-# INLINE textual #-}
data Parsed α = Parsed α
| Malformed [String] String
deriving (Typeable, Functor, Foldable, Traversable, Eq, Show)
instance Applicative Parsed where
pure = Parsed
{-# INLINE pure #-}
Parsed f <*> Parsed a = Parsed (f a)
Malformed ls e <*> _ = Malformed ls e
_ <*> Malformed ls e = Malformed ls e
{-# INLINABLE (<*>) #-}
instance Alternative Parsed where
empty = Malformed [] "Alternative.empty"
{-# INLINE empty #-}
p@(Parsed _) <|> _ = p
_ <|> p = p
{-# INLINABLE (<|>) #-}
isParsed ∷ Parsed α → Bool
isParsed (Parsed _) = True
isParsed _ = False
isMalformed ∷ Parsed α → Bool
isMalformed (Malformed _ _) = True
isMalformed _ = False
maybeParsed ∷ Parsed α → Maybe α
maybeParsed (Parsed a) = Just a
maybeParsed _ = Nothing
{-# INLINABLE maybeParsed #-}
data Parser α =
Parser { runParser ∷ ∀ r
. [String] → Word → String
→ ([String] → Word → String → α → Parsed r)
→ ([String] → Word → String → String → Parsed r)
→ Parsed r }
instance Functor Parser where
fmap f p = Parser $ \ls n i c h →
runParser p ls n i (\ls' n' i' a → c ls' n' i' (f a)) h
{-# INLINE fmap #-}
instance Applicative Parser where
pure a = Parser $ \ls n i c _ → c ls n i a
{-# INLINE pure #-}
p <*> p' = Parser $ \ls n i c h →
runParser p ls n i
(\ls' n' i' f →
runParser p' ls' n' i'
(\ls'' n'' i'' a → c ls'' n'' i'' (f a)) h)
h
{-# INLINE (<*>) #-}
p *> p' = Parser $ \ls n i c h →
runParser p ls n i (\ls' n' i' _ → runParser p' ls' n' i' c h) h
{-# INLINE (*>) #-}
p <* p' = Parser $ \ls n i c h →
runParser p ls n i
(\ls' n' i' a →
runParser p' ls' n' i'
(\ls'' n'' i'' _ → c ls'' n'' i'' a) h)
h
{-# INLINE (<*) #-}
instance Alternative Parser where
empty = PC.unexpected "Alternative.empty"
{-# INLINE empty #-}
p <|> p' = Parser $ \ls n i c h →
runParser p ls n i c $ \ls' n' i' e →
if n' == n then runParser p' ls n' i' c h
else h ls' n' i' e
{-# INLINE (<|>) #-}
instance Parsing Parser where
try p = Parser $ \ls n i c h →
runParser p ls n i c (\ls' _ _ e → h ls' n i e)
{-# INLINE try #-}
p <?> l = Parser $ \ls n i c h →
runParser p (l : ls) n i (\_ n' i' a → c ls n' i' a) h
{-# INLINE (<?>) #-}
skipMany p = Parser $ \ls n i c h →
runParser p ls n i
(\ls' n' i' _ → runParser (PC.skipMany p) ls' n' i' c h)
(\ls' n' i' _ → c ls' n' i' ())
skipSome p = p *> PC.skipMany p
{-# INLINE skipSome #-}
unexpected e = Parser $ \ls n i _ h → h ls n i e
{-# INLINE unexpected #-}
eof = Parser $ \ls n i c h → case i of
[] → c ls n i ()
_ → h ls n i "Parsing.eof"
{-# INLINABLE eof #-}
notFollowedBy p = Parser $ \ls n i c h →
runParser p ls n i
(\_ _ _ _ → h ls n i "Parsing.notFollowedBy")
(\_ _ _ _ → c ls n i ())
{-# INLINE notFollowedBy #-}
instance CharParsing Parser where
satisfy f = Parser $ \ls n i c h → case i of
x : xs | f x → c ls n' xs x
where !n' = n + 1
_ → h ls n i "CharParsing.satisfy"
{-# INLINABLE satisfy #-}
string s = Parser $ \ls n i c h → case stripPrefix s i of
Just i' → c ls n' i' s
where !n' = n + fromIntegral (length s)
Nothing → h ls n i "CharParsing.string"
{-# INLINABLE string #-}
instance Monad Parser where
return = pure
{-# INLINE return #-}
p >>= f = Parser $ \ls n i c h →
runParser p ls n i
(\ls' n' i' a → runParser (f a) ls' n' i' c h) h
{-# INLINE (>>=) #-}
(>>) = (*>)
{-# INLINE (>>) #-}
#if !MIN_VERSION_base(4,13,0)
fail = PC.unexpected
{-# INLINE fail #-}
#endif
parse ∷ Parser α → String → Parsed α
parse p i = runParser p [] 0 i (\_ _ _ a → Parsed a)
(\ls _ _ e → Malformed (reverse ls) e)
{-# INLINE parse #-}
builtInParser ∷ (∀ μ . (Monad μ, CharParsing μ) ⇒ μ α) → String → Parsed α
builtInParser p = parse p
{-# INLINE builtInParser #-}
parseString ∷ Textual α ⇒ String → Parsed α
parseString = parse $ textual <* PC.eof
{-# INLINE parseString #-}
parseStringAs ∷ Textual α ⇒ p α → String → Parsed α
parseStringAs _ = parseString
{-# INLINE parseStringAs #-}
parseText ∷ Textual α ⇒ TS.Text → Parsed α
parseText = parseString . TS.unpack
{-# INLINE parseText #-}
parseTextAs ∷ Textual α ⇒ p α → TS.Text → Parsed α
parseTextAs _ = parseText
{-# INLINE parseTextAs #-}
parseLazyText ∷ Textual α ⇒ TL.Text → Parsed α
parseLazyText = parseString . TL.unpack
{-# INLINE parseLazyText #-}
parseLazyTextAs ∷ Textual α ⇒ p α → TL.Text → Parsed α
parseLazyTextAs _ = parseLazyText
{-# INLINE parseLazyTextAs #-}
parseAscii ∷ Textual α ⇒ BS.ByteString → Parsed α
parseAscii = parseString . BS8.unpack
{-# INLINE parseAscii #-}
parseAsciiAs ∷ Textual α ⇒ p α → BS.ByteString → Parsed α
parseAsciiAs _ = parseAscii
{-# INLINE parseAsciiAs #-}
parseLazyAscii ∷ Textual α ⇒ BL.ByteString → Parsed α
parseLazyAscii = parseString . BL8.unpack
{-# INLINE parseLazyAscii #-}
parseLazyAsciiAs ∷ Textual α ⇒ BL.ByteString → Parsed α
parseLazyAsciiAs = parseString . BL8.unpack
{-# INLINE parseLazyAsciiAs #-}
parseUtf8 ∷ Textual α ⇒ BS.ByteString → Parsed α
parseUtf8 = parseLazyText . decodeUtf8 . BL.fromStrict
{-# INLINE parseUtf8 #-}
parseUtf8As ∷ Textual α ⇒ p α → BS.ByteString → Parsed α
parseUtf8As _ = parseUtf8
{-# INLINE parseUtf8As #-}
parseLazyUtf8 ∷ Textual α ⇒ BL.ByteString → Parsed α
parseLazyUtf8 = parseLazyText . decodeUtf8
{-# INLINE parseLazyUtf8 #-}
parseLazyUtf8As ∷ Textual α ⇒ p α → BL.ByteString → Parsed α
parseLazyUtf8As _ = parseLazyUtf8
{-# INLINE parseLazyUtf8As #-}
fromString ∷ Textual α ⇒ String → Maybe α
fromString = maybeParsed . parseString
{-# INLINE fromString #-}
fromStringAs ∷ Textual α ⇒ p α → String → Maybe α
fromStringAs _ = fromString
{-# INLINE fromStringAs #-}
fromText ∷ Textual α ⇒ TS.Text → Maybe α
fromText = maybeParsed . parseText
{-# INLINE fromText #-}
fromTextAs ∷ Textual α ⇒ p α → TS.Text → Maybe α
fromTextAs _ = fromText
{-# INLINE fromTextAs #-}
fromLazyText ∷ Textual α ⇒ TL.Text → Maybe α
fromLazyText = maybeParsed . parseLazyText
{-# INLINE fromLazyText #-}
fromLazyTextAs ∷ Textual α ⇒ p α → TL.Text → Maybe α
fromLazyTextAs _ = fromLazyText
{-# INLINE fromLazyTextAs #-}
fromAscii ∷ Textual α ⇒ BS.ByteString → Maybe α
fromAscii = maybeParsed . parseAscii
{-# INLINE fromAscii #-}
fromAsciiAs ∷ Textual α ⇒ p α → BS.ByteString → Maybe α
fromAsciiAs _ = fromAscii
{-# INLINE fromAsciiAs #-}
fromLazyAscii ∷ Textual α ⇒ BL.ByteString → Maybe α
fromLazyAscii = maybeParsed . parseLazyAscii
{-# INLINE fromLazyAscii #-}
fromLazyAsciiAs ∷ Textual α ⇒ p α → BL.ByteString → Maybe α
fromLazyAsciiAs _ = fromLazyAscii
{-# INLINE fromLazyAsciiAs #-}
fromUtf8 ∷ Textual α ⇒ BS.ByteString → Maybe α
fromUtf8 = maybeParsed . parseUtf8
{-# INLINE fromUtf8 #-}
fromUtf8As ∷ Textual α ⇒ p α → BS.ByteString → Maybe α
fromUtf8As _ = fromUtf8
{-# INLINE fromUtf8As #-}
fromLazyUtf8 ∷ Textual α ⇒ BL.ByteString → Maybe α
fromLazyUtf8 = maybeParsed . parseLazyUtf8
{-# INLINE fromLazyUtf8 #-}
fromLazyUtf8As ∷ Textual α ⇒ p α → BL.ByteString → Maybe α
fromLazyUtf8As _ = fromLazyUtf8
{-# INLINE fromLazyUtf8As #-}