on master help sign in
Bring lazy Read up to speed with strict.
commit376f921b1ab3c58ae32bfeaac94b5727183d9595 authorBryan O'Sullivan <bos@serpentine.com> dateThu 21 Oct 2010, 22:00 (16 years ago) parent614b60d
2 files changed+64−33
Data/Text/Lazy/Read.hs+63−32 Data/Text/Read.hs+1−1
Data/Text/Lazy/Read.hs+63−32
@@ -22,18 +22,24 @@ module Data.Text.Lazy.Read
2222 ) where
2323
2424import Control.Monad (liftM)
25−import Data.Char (digitToInt, isDigit, isHexDigit, ord)
26−import Data.Ratio
25+import Data.Char (isDigit, isHexDigit, ord)
26+import Data.Ratio ((%))
2727import Data.Text.Lazy as T
2828
29−-- | Read some text, and if the read succeeds, return its value and
30−-- the remaining text.
29+-- | Read some text. If the read succeeds, return its value and the
30+-- remaining text, otherwise an error message.
3131type Reader a = Text -> Either String (a,Text)
3232
33−-- | Read a decimal integer.
33+-- | Read a decimal integer. The input must begin with at least one
34+-- decimal digit, and is consumed until a non-digit or end of string
35+-- is reached.
3436--
3537-- This function does not handle leading sign characters. If you need
3638-- to handle signed input, use @'signed' 'decimal'@.
39+--
40+-- /Note/: For fixed-width integer types, this function does not
41+-- attempt to detect overflow, so a sufficiently long input may give
42+-- incorrect results.
3743decimal :: Integral a => Reader a
3844{-# SPECIALIZE decimal :: Reader Int #-}
3945{-# SPECIALIZE decimal :: Reader Integer #-}
@@ -43,28 +49,69 @@ decimal txt
4349 where (h,t) = T.spanBy isDigit txt
4450 go n d = (n * 10 + fromIntegral (digitToInt d))
4551
46−-- | Read a hexadecimal number, with optional leading @\"0x\"@. This
47−-- function is case insensitive.
52+-- | Read a hexadecimal integer, consisting of an optional leading
53+-- @\"0x\"@ followed by at least one decimal digit. Input is consumed
54+-- until a non-hex-digit or end of string is reached. This function
55+-- is case insensitive.
4856--
4957-- This function does not handle leading sign characters. If you need
5058-- to handle signed input, use @'signed' 'hexadecimal'@.
59+--
60+-- /Note/: For fixed-width integer types, this function does not
61+-- attempt to detect overflow, so a sufficiently long input may give
62+-- incorrect results.
5163hexadecimal :: Integral a => Reader a
52−{-# SPECIALIZE hex :: Reader Int #-}
53−{-# SPECIALIZE hex :: Reader Integer #-}
64+{-# SPECIALIZE hexadecimal :: Reader Int #-}
65+{-# SPECIALIZE hexadecimal :: Reader Integer #-}
5466hexadecimal txt
55− | T.toLower h == "0x" = hex t
56− | otherwise = hex txt
67+ | h == "0x" || h == "0X" = hex t
68+ | otherwise = hex txt
5769 where (h,t) = T.splitAt 2 txt
5870
59−-- | Read a leading sign character (@\'-\'@ or @\'+\'@) and apply it
60−-- to the result of applying the given reader.
71+hex :: Integral a => Reader a
72+{-# SPECIALIZE hex :: Reader Int #-}
73+{-# SPECIALIZE hex :: Reader Integer #-}
74+hex txt
75+ | T.null h = Left "input does not start with a hexadecimal digit"
76+ | otherwise = Right (T.foldl' go 0 h, t)
77+ where (h,t) = T.spanBy isHexDigit txt
78+ go n d = (n * 16 + fromIntegral (hexDigitToInt d))
79+
80+hexDigitToInt :: Char -> Int
81+hexDigitToInt c
82+ | c >= '0' && c <= '9' = ord c - ord '0'
83+ | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
84+ | otherwise = ord c - (ord 'A' - 10)
85+
86+digitToInt :: Char -> Int
87+digitToInt c = ord c - ord '0'
88+
89+-- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and
90+-- apply it to the result of applying the given reader.
6191signed :: Num a => Reader a -> Reader a
6292{-# INLINE signed #-}
6393signed f = runP (signa (P f))
6494
6595-- | Read a rational number.
6696--
67−-- This function accepts an optional leading sign character.
97+-- This function accepts an optional leading sign character, followed
98+-- by at least one decimal digit. The syntax similar to that accepted
99+-- by the 'read' function, with the exception that a trailing @\'.\'@
100+-- or @\'e\'@ /not/ followed by a number is not consumed.
101+--
102+-- Examples:
103+--
104+-- >rational "3" == Right (3.0, "")
105+-- >rational "3.1" == Right (3.1, "")
106+-- >rational "3e4" == Right (30000.0, "")
107+-- >rational "3.1e4" == Right (31000.0, "")
108+-- >rational ".3" == Left "input does not start with a digit"
109+-- >rational "e3" == Left "input does not start with a digit"
110+--
111+-- Examples of differences from 'read':
112+--
113+-- >rational "3.foo" == Right (3.0, ".foo")
114+-- >rational "3e" == Right (3.0, "e")
68115rational :: RealFloat a => Reader a
69116{-# SPECIALIZE rational :: Reader Double #-}
70117rational = floaty $ \real frac fracDenom -> fromRational $
@@ -72,7 +119,7 @@ rational = floaty $ \real frac fracDenom -> fromRational $
72119
73120-- | Read a rational number.
74121--
75−-- This function accepts an optional leading sign character.
122+-- The syntax accepted by this function is the same as for 'rational'.
76123--
77124-- /Note/: This function is almost ten times faster than 'rational',
78125-- but is slightly less accurate.
@@ -87,22 +134,6 @@ double = floaty $ \real frac fracDenom ->
87134 fromIntegral real +
88135 fromIntegral frac / fromIntegral fracDenom
89136
90−hex :: Integral a => Reader a
91−{-# SPECIALIZE hex :: Reader Int #-}
92−{-# SPECIALIZE hex :: Reader Integer #-}
93−hex txt
94− | T.null h = Left "input does not start with a hexadecimal digit"
95− | otherwise = Right (T.foldl' go 0 h, t)
96− where (h,t) = T.spanBy isHexDigit txt
97− go n d = (n * 16 + fromIntegral (hexDigitToInt d))
98−
99−hexDigitToInt :: Char -> Int
100−hexDigitToInt c
101− | c >= '0' && c <= '9' = ord c - ord '0'
102− | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
103− | c >= 'A' && c <= 'F' = ord c - (ord 'A' - 10)
104− | otherwise = error "Data.Text.Lex.hexDigitToInt: bad input"
105−
106137signa :: Num a => Parser a -> Parser a
107138{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
108139{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
@@ -111,7 +142,7 @@ signa p = do
111142 if sign == '+' then p else negate `liftM` p
112143
113144newtype Parser a = P {
114− runP :: Text -> Either String (a,Text)
145+ runP :: Reader a
115146 }
116147
117148instance Monad Parser where
Data/Text/Read.hs+1−1
@@ -49,7 +49,7 @@ decimal txt
4949 where (h,t) = T.spanBy isDigit txt
5050 go n d = (n * 10 + fromIntegral (digitToInt d))
5151
52−-- | Read a hexadecimal number, consisting of an optional leading
52+-- | Read a hexadecimal integer, consisting of an optional leading
5353-- @\"0x\"@ followed by at least one decimal digit. Input is consumed
5454-- until a non-hex-digit or end of string is reached. This function
5555-- is case insensitive.