-- |
-- Module      : Data.Text.Internal.Read
-- Copyright   : (c) 2014 Bryan O'Sullivan
--
-- License     : BSD-style
-- Maintainer  : bos@serpentine.com
-- Stability   : experimental
-- Portability : GHC
--
-- Common internal functions for reading textual data.
module Data.Text.Internal.Read
    (
      IReader
    , IParser(..)
    , T(..)
    , digitToInt
    , hexDigitToInt
    , perhaps
    ) where

import Control.Applicative as App (Applicative(..))
import Control.Arrow (first)
import Control.Monad (ap)
import Data.Char (ord)

type IReader t a = t -> Either String (a,t)

newtype IParser t a = P {
      forall t a. IParser t a -> IReader t a
runP :: IReader t a
    }

instance Functor (IParser t) where
    fmap :: forall a b. (a -> b) -> IParser t a -> IParser t b
fmap a -> b
f IParser t a
m = forall t a. IReader t a -> IParser t a
P forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first a -> b
f) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t a. IParser t a -> IReader t a
runP IParser t a
m

instance Applicative (IParser t) where
    pure :: forall a. a -> IParser t a
pure a
a = forall t a. IReader t a -> IParser t a
P forall a b. (a -> b) -> a -> b
$ \t
t -> forall a b. b -> Either a b
Right (a
a,t
t)
    {-# INLINE pure #-}
    <*> :: forall a b. IParser t (a -> b) -> IParser t a -> IParser t b
(<*>) = forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap

instance Monad (IParser t) where
    return :: forall a. a -> IParser t a
return = forall (f :: * -> *) a. Applicative f => a -> f a
App.pure
    IParser t a
m >>= :: forall a b. IParser t a -> (a -> IParser t b) -> IParser t b
>>= a -> IParser t b
k  = forall t a. IReader t a -> IParser t a
P forall a b. (a -> b) -> a -> b
$ \t
t -> case forall t a. IParser t a -> IReader t a
runP IParser t a
m t
t of
                           Left String
err     -> forall a b. a -> Either a b
Left String
err
                           Right (a
a,t
t') -> forall t a. IParser t a -> IReader t a
runP (a -> IParser t b
k a
a) t
t'
    {-# INLINE (>>=) #-}

-- If we ever need a `MonadFail` instance the definition below can be used
--
-- > instance MonadFail (IParser t) where
-- >   fail msg = P $ \_ -> Left msg
--
-- But given the code compiles fine with a post-MFP GHC 8.6+ we don't need
-- one just yet.

data T = T !Integer !Int

perhaps :: a -> IParser t a -> IParser t a
perhaps :: forall a t. a -> IParser t a -> IParser t a
perhaps a
def IParser t a
m = forall t a. IReader t a -> IParser t a
P forall a b. (a -> b) -> a -> b
$ \t
t -> case forall t a. IParser t a -> IReader t a
runP IParser t a
m t
t of
                            Left String
_      -> forall a b. b -> Either a b
Right (a
def,t
t)
                            r :: Either String (a, t)
r@(Right (a, t)
_) -> Either String (a, t)
r

hexDigitToInt :: Char -> Int
hexDigitToInt :: Char -> Int
hexDigitToInt Char
c
    | Word
to0 forall a. Ord a => a -> a -> Bool
< Word
10  = Word -> Int
wordToInt Word
to0
    | Word
toa forall a. Ord a => a -> a -> Bool
< Word
6   = Word -> Int
wordToInt Word
toa forall a. Num a => a -> a -> a
+ Int
10
    | Bool
otherwise = Word -> Int
wordToInt Word
toA forall a. Num a => a -> a -> a
+ Int
10
    where
        ordW :: Word
ordW = Int -> Word
intToWord (Char -> Int
ord Char
c)
        to0 :: Word
to0 = Word
ordW forall a. Num a => a -> a -> a
- Int -> Word
intToWord (Char -> Int
ord Char
'0')
        toa :: Word
toa = Word
ordW forall a. Num a => a -> a -> a
- Int -> Word
intToWord (Char -> Int
ord Char
'a')
        toA :: Word
toA = Word
ordW forall a. Num a => a -> a -> a
- Int -> Word
intToWord (Char -> Int
ord Char
'A')

digitToInt :: Char -> Int
digitToInt :: Char -> Int
digitToInt Char
c = Char -> Int
ord Char
c forall a. Num a => a -> a -> a
- Char -> Int
ord Char
'0'

intToWord :: Int -> Word
intToWord :: Int -> Word
intToWord = forall a b. (Integral a, Num b) => a -> b
fromIntegral

wordToInt :: Word -> Int
wordToInt :: Word -> Int
wordToInt = forall a b. (Integral a, Num b) => a -> b
fromIntegral