on master help sign in
Refactor Read modules to share code
15034aaBryan O'Sullivan
Data/Text/Encoding.hs−1
@@ -74,7 +74,6 @@ import Control.Monad.ST (unsafeIOToST, unsafeSTToIO)
74import Data.Bits ((.&.))
74import Data.Bits ((.&.))
75import Data.Text.Internal.Unsafe.Char (ord)
75import Data.Text.Internal.Unsafe.Char (ord)
76import qualified Data.ByteString.Builder as B
76import qualified Data.ByteString.Builder as B
77−import qualified Data.ByteString.Builder.Extra as B
78import qualified Data.ByteString.Builder.Internal as B hiding (empty, append)
77import qualified Data.ByteString.Builder.Internal as B hiding (empty, append)
79import qualified Data.ByteString.Builder.Prim as BP
78import qualified Data.ByteString.Builder.Prim as BP
80import qualified Data.ByteString.Builder.Prim.Internal as BP
79import qualified Data.ByteString.Builder.Prim.Internal as BP
Data/Text/Internal/Read.hsnew file+52
@@ -0,0 +1,52 @@
1+-- |
2+-- Module : Data.Text.Internal.Read
3+-- Copyright : (c) 2014 Bryan O'Sullivan
4+--
5+-- License : BSD-style
6+-- Maintainer : bos@serpentine.com
7+-- Stability : experimental
8+-- Portability : GHC
9+--
10+-- Common internal functiopns for reading textual data.
11+module Data.Text.Internal.Read
12+ (
13+ IReader
14+ , IParser(..)
15+ , T(..)
16+ , digitToInt
17+ , hexDigitToInt
18+ , perhaps
19+ ) where
20+
21+import Data.Char (ord)
22+
23+type IReader t a = t -> Either String (a,t)
24+
25+newtype IParser t a = P {
26+ runP :: IReader t a
27+ }
28+
29+instance Monad (IParser t) where
30+ return a = P $ \t -> Right (a,t)
31+ {-# INLINE return #-}
32+ m >>= k = P $ \t -> case runP m t of
33+ Left err -> Left err
34+ Right (a,t') -> runP (k a) t'
35+ {-# INLINE (>>=) #-}
36+ fail msg = P $ \_ -> Left msg
37+
38+data T = T !Integer !Int
39+
40+perhaps :: a -> IParser t a -> IParser t a
41+perhaps def m = P $ \t -> case runP m t of
42+ Left _ -> Right (def,t)
43+ r@(Right _) -> r
44+
45+hexDigitToInt :: Char -> Int
46+hexDigitToInt c
47+ | c >= '0' && c <= '9' = ord c - ord '0'
48+ | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
49+ | otherwise = ord c - (ord 'A' - 10)
50+
51+digitToInt :: Char -> Int
52+digitToInt c = ord c - ord '0'
Data/Text/Lazy/Builder/Int.hs+3−1
@@ -49,7 +49,7 @@ import GHC.Integer
49#endif
49#endif
50
50
51decimal :: Integral a => a -> Builder
51decimal :: Integral a => a -> Builder
52−{-# SPECIALIZE decimal :: Int8 -> Builder #-}
52+{-# RULES "decimal/Int8" decimal = boundedDecimal :: Int8 -> Builder #-}
53{-# RULES "decimal/Int" decimal = boundedDecimal :: Int -> Builder #-}
53{-# RULES "decimal/Int" decimal = boundedDecimal :: Int -> Builder #-}
54{-# RULES "decimal/Int16" decimal = boundedDecimal :: Int16 -> Builder #-}
54{-# RULES "decimal/Int16" decimal = boundedDecimal :: Int16 -> Builder #-}
55{-# RULES "decimal/Int32" decimal = boundedDecimal :: Int32 -> Builder #-}
55{-# RULES "decimal/Int32" decimal = boundedDecimal :: Int32 -> Builder #-}
@@ -61,6 +61,7 @@ decimal :: Integral a => a -> Builder
61{-# RULES "decimal/Word64" decimal = positive :: Word64 -> Builder #-}
61{-# RULES "decimal/Word64" decimal = positive :: Word64 -> Builder #-}
62{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}
62{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}
63decimal i = decimal' (<= -128) i
63decimal i = decimal' (<= -128) i
64+{-# NOINLINE decimal #-}
64
65
65boundedDecimal :: (Integral a, Bounded a) => a -> Builder
66boundedDecimal :: (Integral a, Bounded a) => a -> Builder
66{-# SPECIALIZE boundedDecimal :: Int -> Builder #-}
67{-# SPECIALIZE boundedDecimal :: Int -> Builder #-}
@@ -169,6 +170,7 @@ hexadecimal i
169 where
170 where
170 go n | n < 16 = hexDigit n
171 go n | n < 16 = hexDigit n
171 | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)
172 | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)
173+{-# NOINLINE[0] hexadecimal #-}
172
174
173hexInteger :: Integer -> Builder
175hexInteger :: Integer -> Builder
174hexInteger i
176hexInteger i
Data/Text/Lazy/Read.hs+4−31
@@ -24,15 +24,17 @@ module Data.Text.Lazy.Read
24 ) where
24 ) where
25
25
26import Control.Monad (liftM)
26import Control.Monad (liftM)
27−import Data.Char (isDigit, isHexDigit, ord)
27+import Data.Char (isDigit, isHexDigit)
28import Data.Int (Int8, Int16, Int32, Int64)
28import Data.Int (Int8, Int16, Int32, Int64)
29import Data.Ratio ((%))
29import Data.Ratio ((%))
30+import Data.Text.Internal.Read
30import Data.Text.Lazy as T
31import Data.Text.Lazy as T
31import Data.Word (Word, Word8, Word16, Word32, Word64)
32import Data.Word (Word, Word8, Word16, Word32, Word64)
32
33
33-- | Read some text. If the read succeeds, return its value and the
34-- | Read some text. If the read succeeds, return its value and the
34-- remaining text, otherwise an error message.
35-- remaining text, otherwise an error message.
35−type Reader a = Text -> Either String (a,Text)
36+type Reader a = IReader Text a
37+type Parser = IParser Text
36
38
37-- | Read a decimal integer. The input must begin with at least one
39-- | Read a decimal integer. The input must begin with at least one
38-- decimal digit, and is consumed until a non-digit or end of string
40-- decimal digit, and is consumed until a non-digit or end of string
@@ -101,15 +103,6 @@ hex txt
101 where (h,t) = T.span isHexDigit txt
103 where (h,t) = T.span isHexDigit txt
102 go n d = (n * 16 + fromIntegral (hexDigitToInt d))
104 go n d = (n * 16 + fromIntegral (hexDigitToInt d))
103
105
104−hexDigitToInt :: Char -> Int
105−hexDigitToInt c
106− | c >= '0' && c <= '9' = ord c - ord '0'
107− | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
108− | otherwise = ord c - (ord 'A' - 10)
109−
110−digitToInt :: Char -> Int
111−digitToInt c = ord c - ord '0'
112−
113-- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and
106-- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and
114-- apply it to the result of applying the given reader.
107-- apply it to the result of applying the given reader.
115signed :: Num a => Reader a -> Reader a
108signed :: Num a => Reader a -> Reader a
@@ -169,31 +162,11 @@ signa p = do
169 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
162 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
170 if sign == '+' then p else negate `liftM` p
163 if sign == '+' then p else negate `liftM` p
171
164
172−newtype Parser a = P {
173− runP :: Reader a
174− }
175−
176−instance Monad Parser where
177− return a = P $ \t -> Right (a,t)
178− {-# INLINE return #-}
179− m >>= k = P $ \t -> case runP m t of
180− Left err -> Left err
181− Right (a,t') -> runP (k a) t'
182− {-# INLINE (>>=) #-}
183− fail msg = P $ \_ -> Left msg
184−
185−perhaps :: a -> Parser a -> Parser a
186−perhaps def m = P $ \t -> case runP m t of
187− Left _ -> Right (def,t)
188− r@(Right _) -> r
189−
190char :: (Char -> Bool) -> Parser Char
165char :: (Char -> Bool) -> Parser Char
191char p = P $ \t -> case T.uncons t of
166char p = P $ \t -> case T.uncons t of
192 Just (c,t') | p c -> Right (c,t')
167 Just (c,t') | p c -> Right (c,t')
193 _ -> Left "character does not match"
168 _ -> Left "character does not match"
194
169
195−data T = T !Integer !Int
196−
197floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
170floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
198{-# INLINE floaty #-}
171{-# INLINE floaty #-}
199floaty f = runP $ do
172floaty f = runP $ do
Data/Text/Read.hs+4−31
@@ -24,16 +24,18 @@ module Data.Text.Read
24 ) where
24 ) where
25
25
26import Control.Monad (liftM)
26import Control.Monad (liftM)
27−import Data.Char (isDigit, isHexDigit, ord)
27+import Data.Char (isDigit, isHexDigit)
28import Data.Int (Int8, Int16, Int32, Int64)
28import Data.Int (Int8, Int16, Int32, Int64)
29import Data.Ratio ((%))
29import Data.Ratio ((%))
30import Data.Text as T
30import Data.Text as T
31import Data.Text.Internal.Private (span_)
31import Data.Text.Internal.Private (span_)
32+import Data.Text.Internal.Read
32import Data.Word (Word, Word8, Word16, Word32, Word64)
33import Data.Word (Word, Word8, Word16, Word32, Word64)
33
34
34-- | Read some text. If the read succeeds, return its value and the
35-- | Read some text. If the read succeeds, return its value and the
35-- remaining text, otherwise an error message.
36-- remaining text, otherwise an error message.
36−type Reader a = Text -> Either String (a,Text)
37+type Reader a = IReader Text a
38+type Parser a = IParser Text a
37
39
38-- | Read a decimal integer. The input must begin with at least one
40-- | Read a decimal integer. The input must begin with at least one
39-- decimal digit, and is consumed until a non-digit or end of string
41-- decimal digit, and is consumed until a non-digit or end of string
@@ -111,15 +113,6 @@ hex txt
111 where (# h,t #) = span_ isHexDigit txt
113 where (# h,t #) = span_ isHexDigit txt
112 go n d = (n * 16 + fromIntegral (hexDigitToInt d))
114 go n d = (n * 16 + fromIntegral (hexDigitToInt d))
113
115
114−hexDigitToInt :: Char -> Int
115−hexDigitToInt c
116− | c >= '0' && c <= '9' = ord c - ord '0'
117− | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
118− | otherwise = ord c - (ord 'A' - 10)
119−
120−digitToInt :: Char -> Int
121−digitToInt c = ord c - ord '0'
122−
123-- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and
116-- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and
124-- apply it to the result of applying the given reader.
117-- apply it to the result of applying the given reader.
125signed :: Num a => Reader a -> Reader a
118signed :: Num a => Reader a -> Reader a
@@ -179,31 +172,11 @@ signa p = do
179 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
172 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
180 if sign == '+' then p else negate `liftM` p
173 if sign == '+' then p else negate `liftM` p
181
174
182−newtype Parser a = P {
183− runP :: Reader a
184− }
185−
186−instance Monad Parser where
187− return a = P $ \t -> Right (a,t)
188− {-# INLINE return #-}
189− m >>= k = P $ \t -> case runP m t of
190− Left err -> Left err
191− Right (a,t') -> runP (k a) t'
192− {-# INLINE (>>=) #-}
193− fail msg = P $ \_ -> Left msg
194−
195−perhaps :: a -> Parser a -> Parser a
196−perhaps def m = P $ \t -> case runP m t of
197− Left _ -> Right (def,t)
198− r@(Right _) -> r
199−
200char :: (Char -> Bool) -> Parser Char
175char :: (Char -> Bool) -> Parser Char
201char p = P $ \t -> case T.uncons t of
176char p = P $ \t -> case T.uncons t of
202 Just (c,t') | p c -> Right (c,t')
177 Just (c,t') | p c -> Right (c,t')
203 _ -> Left "character does not match"
178 _ -> Left "character does not match"
204
179
205−data T = T !Integer !Int
206−
207floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
180floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
208{-# INLINE floaty #-}
181{-# INLINE floaty #-}
209floaty f = runP $ do
182floaty f = runP $ do
text.cabal+1
@@ -103,6 +103,7 @@ library
103 Data.Text.Internal.Lazy.Fusion
103 Data.Text.Internal.Lazy.Fusion
104 Data.Text.Internal.Lazy.Search
104 Data.Text.Internal.Lazy.Search
105 Data.Text.Internal.Private
105 Data.Text.Internal.Private
106+ Data.Text.Internal.Read
106 Data.Text.Internal.Search
107 Data.Text.Internal.Search
107 Data.Text.Internal.Unsafe
108 Data.Text.Internal.Unsafe
108 Data.Text.Internal.Unsafe.Char
109 Data.Text.Internal.Unsafe.Char