{-# LANGUAGE OverloadedStrings, UnboxedTuples, CPP #-}
#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
#endif
module Data.Text.Read
(
Reader
, decimal
, hexadecimal
, signed
, rational
, double
) where
import Control.Monad (liftM)
import Data.Char (isDigit, isHexDigit)
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Ratio ((%))
import Data.Text as T
import Data.Text.Internal.Private (span_)
import Data.Text.Internal.Read
import Data.Word (Word, Word8, Word16, Word32, Word64)
type Reader a = IReader Text a
type Parser a = IParser Text a
decimal :: Integral a => Reader a
{-# SPECIALIZE decimal :: Reader Int #-}
{-# SPECIALIZE decimal :: Reader Int8 #-}
{-# SPECIALIZE decimal :: Reader Int16 #-}
{-# SPECIALIZE decimal :: Reader Int32 #-}
{-# SPECIALIZE decimal :: Reader Int64 #-}
{-# SPECIALIZE decimal :: Reader Integer #-}
{-# SPECIALIZE decimal :: Reader Data.Word.Word #-}
{-# SPECIALIZE decimal :: Reader Word8 #-}
{-# SPECIALIZE decimal :: Reader Word16 #-}
{-# SPECIALIZE decimal :: Reader Word32 #-}
{-# SPECIALIZE decimal :: Reader Word64 #-}
decimal :: Reader a
decimal txt :: Text
txt
| Text -> Bool
T.null Text
h = String -> Either String (a, Text)
forall a b. a -> Either a b
Left "input does not start with a digit"
| Bool
otherwise = (a, Text) -> Either String (a, Text)
forall a b. b -> Either a b
Right ((a -> Char -> a) -> a -> Text -> a
forall a. (a -> Char -> a) -> a -> Text -> a
T.foldl' a -> Char -> a
forall a. Num a => a -> Char -> a
go 0 Text
h, Text
t)
where (# h :: Text
h,t :: Text
t #) = (Char -> Bool) -> Text -> (# Text, Text #)
span_ Char -> Bool
isDigit Text
txt
go :: a -> Char -> a
go n :: a
n d :: Char
d = (a
n a -> a -> a
forall a. Num a => a -> a -> a
* 10 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Char -> Int
digitToInt Char
d))
hexadecimal :: Integral a => Reader a
{-# SPECIALIZE hexadecimal :: Reader Int #-}
{-# SPECIALIZE hexadecimal :: Reader Int8 #-}
{-# SPECIALIZE hexadecimal :: Reader Int16 #-}
{-# SPECIALIZE hexadecimal :: Reader Int32 #-}
{-# SPECIALIZE hexadecimal :: Reader Int64 #-}
{-# SPECIALIZE hexadecimal :: Reader Integer #-}
{-# SPECIALIZE hexadecimal :: Reader Word #-}
{-# SPECIALIZE hexadecimal :: Reader Word8 #-}
{-# SPECIALIZE hexadecimal :: Reader Word16 #-}
{-# SPECIALIZE hexadecimal :: Reader Word32 #-}
{-# SPECIALIZE hexadecimal :: Reader Word64 #-}
hexadecimal :: Reader a
hexadecimal txt :: Text
txt
| Text
h Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "0x" Bool -> Bool -> Bool
|| Text
h Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "0X" = Reader a
forall a. Integral a => Reader a
hex Text
t
| Bool
otherwise = Reader a
forall a. Integral a => Reader a
hex Text
txt
where (h :: Text
h,t :: Text
t) = Int -> Text -> (Text, Text)
T.splitAt 2 Text
txt
hex :: Integral a => Reader a
{-# SPECIALIZE hex :: Reader Int #-}
{-# SPECIALIZE hex :: Reader Int8 #-}
{-# SPECIALIZE hex :: Reader Int16 #-}
{-# SPECIALIZE hex :: Reader Int32 #-}
{-# SPECIALIZE hex :: Reader Int64 #-}
{-# SPECIALIZE hex :: Reader Integer #-}
{-# SPECIALIZE hex :: Reader Word #-}
{-# SPECIALIZE hex :: Reader Word8 #-}
{-# SPECIALIZE hex :: Reader Word16 #-}
{-# SPECIALIZE hex :: Reader Word32 #-}
{-# SPECIALIZE hex :: Reader Word64 #-}
hex :: Reader a
hex txt :: Text
txt
| Text -> Bool
T.null Text
h = String -> Either String (a, Text)
forall a b. a -> Either a b
Left "input does not start with a hexadecimal digit"
| Bool
otherwise = (a, Text) -> Either String (a, Text)
forall a b. b -> Either a b
Right ((a -> Char -> a) -> a -> Text -> a
forall a. (a -> Char -> a) -> a -> Text -> a
T.foldl' a -> Char -> a
forall a. Num a => a -> Char -> a
go 0 Text
h, Text
t)
where (# h :: Text
h,t :: Text
t #) = (Char -> Bool) -> Text -> (# Text, Text #)
span_ Char -> Bool
isHexDigit Text
txt
go :: a -> Char -> a
go n :: a
n d :: Char
d = (a
n a -> a -> a
forall a. Num a => a -> a -> a
* 16 a -> a -> a
forall a. Num a => a -> a -> a
+ Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Char -> Int
hexDigitToInt Char
d))
signed :: Num a => Reader a -> Reader a
{-# INLINE signed #-}
signed :: Reader a -> Reader a
signed f :: Reader a
f = IParser Text a -> Reader a
forall t a. IParser t a -> IReader t a
runP (IParser Text a -> IParser Text a
forall a. Num a => Parser a -> Parser a
signa (Reader a -> IParser Text a
forall t a. IReader t a -> IParser t a
P Reader a
f))
rational :: Fractional a => Reader a
{-# SPECIALIZE rational :: Reader Double #-}
rational :: Reader a
rational = (Integer -> Integer -> Integer -> a) -> Reader a
forall a.
Fractional a =>
(Integer -> Integer -> Integer -> a) -> Reader a
floaty ((Integer -> Integer -> Integer -> a) -> Reader a)
-> (Integer -> Integer -> Integer -> a) -> Reader a
forall a b. (a -> b) -> a -> b
$ \real :: Integer
real frac :: Integer
frac fracDenom :: Integer
fracDenom -> Rational -> a
forall a. Fractional a => Rational -> a
fromRational (Rational -> a) -> Rational -> a
forall a b. (a -> b) -> a -> b
$
Integer
real Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% 1 Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Integer
frac Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% Integer
fracDenom
double :: Reader Double
double :: Reader Double
double = (Integer -> Integer -> Integer -> Double) -> Reader Double
forall a.
Fractional a =>
(Integer -> Integer -> Integer -> a) -> Reader a
floaty ((Integer -> Integer -> Integer -> Double) -> Reader Double)
-> (Integer -> Integer -> Integer -> Double) -> Reader Double
forall a b. (a -> b) -> a -> b
$ \real :: Integer
real frac :: Integer
frac fracDenom :: Integer
fracDenom ->
Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
real Double -> Double -> Double
forall a. Num a => a -> a -> a
+
Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
frac Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
fracDenom
signa :: Num a => Parser a -> Parser a
{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}
{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}
{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}
{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}
{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
signa :: Parser a -> Parser a
signa p :: Parser a
p = do
Char
sign <- Char -> IParser Text Char -> IParser Text Char
forall a t. a -> IParser t a -> IParser t a
perhaps '+' (IParser Text Char -> IParser Text Char)
-> IParser Text Char -> IParser Text Char
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> IParser Text Char
char (\c :: Char
c -> Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '-' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '+')
if Char
sign Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '+' then Parser a
p else a -> a
forall a. Num a => a -> a
negate (a -> a) -> Parser a -> Parser a
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
`liftM` Parser a
p
char :: (Char -> Bool) -> Parser Char
char :: (Char -> Bool) -> IParser Text Char
char p :: Char -> Bool
p = IReader Text Char -> IParser Text Char
forall t a. IReader t a -> IParser t a
P (IReader Text Char -> IParser Text Char)
-> IReader Text Char -> IParser Text Char
forall a b. (a -> b) -> a -> b
$ \t :: Text
t -> case Text -> Maybe (Char, Text)
T.uncons Text
t of
Just (c :: Char
c,t' :: Text
t') | Char -> Bool
p Char
c -> (Char, Text) -> Either String (Char, Text)
forall a b. b -> Either a b
Right (Char
c,Text
t')
_ -> String -> Either String (Char, Text)
forall a b. a -> Either a b
Left "character does not match"
floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
{-# INLINE floaty #-}
floaty :: (Integer -> Integer -> Integer -> a) -> Reader a
floaty f :: Integer -> Integer -> Integer -> a
f = IParser Text a -> Reader a
forall t a. IParser t a -> IReader t a
runP (IParser Text a -> Reader a) -> IParser Text a -> Reader a
forall a b. (a -> b) -> a -> b
$ do
Char
sign <- Char -> IParser Text Char -> IParser Text Char
forall a t. a -> IParser t a -> IParser t a
perhaps '+' (IParser Text Char -> IParser Text Char)
-> IParser Text Char -> IParser Text Char
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> IParser Text Char
char (\c :: Char
c -> Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '-' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '+')
Integer
real <- IReader Text Integer -> IParser Text Integer
forall t a. IReader t a -> IParser t a
P IReader Text Integer
forall a. Integral a => Reader a
decimal
T fraction :: Integer
fraction fracDigits :: Int
fracDigits <- T -> IParser Text T -> IParser Text T
forall a t. a -> IParser t a -> IParser t a
perhaps (Integer -> Int -> T
T 0 0) (IParser Text T -> IParser Text T)
-> IParser Text T -> IParser Text T
forall a b. (a -> b) -> a -> b
$ do
Char
_ <- (Char -> Bool) -> IParser Text Char
char (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
=='.')
Int
digits <- IReader Text Int -> IParser Text Int
forall t a. IReader t a -> IParser t a
P (IReader Text Int -> IParser Text Int)
-> IReader Text Int -> IParser Text Int
forall a b. (a -> b) -> a -> b
$ \t :: Text
t -> (Int, Text) -> Either String (Int, Text)
forall a b. b -> Either a b
Right (Text -> Int
T.length (Text -> Int) -> Text -> Int
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Text -> Text
T.takeWhile Char -> Bool
isDigit Text
t, Text
t)
Integer
n <- IReader Text Integer -> IParser Text Integer
forall t a. IReader t a -> IParser t a
P IReader Text Integer
forall a. Integral a => Reader a
decimal
T -> IParser Text T
forall (m :: * -> *) a. Monad m => a -> m a
return (T -> IParser Text T) -> T -> IParser Text T
forall a b. (a -> b) -> a -> b
$ Integer -> Int -> T
T Integer
n Int
digits
let e :: Char -> Bool
e c :: Char
c = Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== 'e' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== 'E'
Int
power <- Int -> IParser Text Int -> IParser Text Int
forall a t. a -> IParser t a -> IParser t a
perhaps 0 ((Char -> Bool) -> IParser Text Char
char Char -> Bool
e IParser Text Char -> IParser Text Int -> IParser Text Int
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IParser Text Int -> IParser Text Int
forall a. Num a => Parser a -> Parser a
signa (IReader Text Int -> IParser Text Int
forall t a. IReader t a -> IParser t a
P IReader Text Int
forall a. Integral a => Reader a
decimal) :: Parser Int)
let n :: a
n = if Int
fracDigits Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0
then if Int
power Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0
then Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
real
else Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
real a -> a -> a
forall a. Num a => a -> a -> a
* (10 a -> Int -> a
forall a b. (Fractional a, Integral b) => a -> b -> a
^^ Int
power)
else if Int
power Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0
then Integer -> Integer -> Integer -> a
f Integer
real Integer
fraction (10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
fracDigits)
else Integer -> Integer -> Integer -> a
f Integer
real Integer
fraction (10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
fracDigits) a -> a -> a
forall a. Num a => a -> a -> a
* (10 a -> Int -> a
forall a b. (Fractional a, Integral b) => a -> b -> a
^^ Int
power)
a -> IParser Text a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> IParser Text a) -> a -> IParser Text a
forall a b. (a -> b) -> a -> b
$! if Char
sign Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '+'
then a
n
else -a
n