@@ -1,12 +1,11 @@
1−{-# LANGUAGE OverloadedStrings #-}
1+{-# LANGUAGE OverloadedStrings, UnboxedTuples #-}
4-- Module : Data.Text.Read
4-- Module : Data.Text.Read
5−-- Copyright : (c) 2010 Bryan O'Sullivan
5+-- Copyright : (c) 2010, 2011 Bryan O'Sullivan
7-- License : BSD-style
7-- License : BSD-style
8−-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
8+-- Maintainer : bos@serpentine.com
10-- Stability : experimental
9-- Stability : experimental
11-- Portability : GHC
10-- Portability : GHC
@@ -23,8 +22,11 @@ module Data.Text.Read
24import Control.Monad (liftM)
23import Control.Monad (liftM)
25import Data.Char (isDigit, isHexDigit, ord)
24import Data.Char (isDigit, isHexDigit, ord)
25+import Data.Int (Int8, Int16, Int32, Int64)
26import Data.Ratio ((%))
26import Data.Ratio ((%))
27import Data.Text as T
27import Data.Text as T
28+import Data.Text.Private (span_)
29+import Data.Word (Word, Word8, Word16, Word32, Word64)
29-- | Read some text. If the read succeeds, return its value and the
31-- | Read some text. If the read succeeds, return its value and the
30-- remaining text, otherwise an error message.
32-- remaining text, otherwise an error message.
@@ -43,11 +45,20 @@ type Reader a = Text -> Either String (a,Text)
43-- 'Integer' for your result type.
45-- 'Integer' for your result type.
44decimal :: Integral a => Reader a
46decimal :: Integral a => Reader a
45{-# SPECIALIZE decimal :: Reader Int #-}
47{-# SPECIALIZE decimal :: Reader Int #-}
48+{-# SPECIALIZE decimal :: Reader Int8 #-}
49+{-# SPECIALIZE decimal :: Reader Int16 #-}
50+{-# SPECIALIZE decimal :: Reader Int32 #-}
51+{-# SPECIALIZE decimal :: Reader Int64 #-}
46{-# SPECIALIZE decimal :: Reader Integer #-}
52{-# SPECIALIZE decimal :: Reader Integer #-}
53+{-# SPECIALIZE decimal :: Reader Word #-}
54+{-# SPECIALIZE decimal :: Reader Word8 #-}
55+{-# SPECIALIZE decimal :: Reader Word16 #-}
56+{-# SPECIALIZE decimal :: Reader Word32 #-}
57+{-# SPECIALIZE decimal :: Reader Word64 #-}
47decimal txt
58decimal txt
48 | T.null h = Left "input does not start with a digit"
59 | T.null h = Left "input does not start with a digit"
49 | otherwise = Right (T.foldl' go 0 h, t)
60 | otherwise = Right (T.foldl' go 0 h, t)
50− where (h,t) = T.span isDigit txt
61+ where (# h,t #) = span_ isDigit txt
51 go n d = (n * 10 + fromIntegral (digitToInt d))
62 go n d = (n * 10 + fromIntegral (digitToInt d))
53-- | Read a hexadecimal integer, consisting of an optional leading
64-- | Read a hexadecimal integer, consisting of an optional leading
@@ -64,7 +75,16 @@ decimal txt
64-- 'Integer' for your result type.
75-- 'Integer' for your result type.
65hexadecimal :: Integral a => Reader a
76hexadecimal :: Integral a => Reader a
66{-# SPECIALIZE hexadecimal :: Reader Int #-}
77{-# SPECIALIZE hexadecimal :: Reader Int #-}
78+{-# SPECIALIZE hexadecimal :: Reader Int8 #-}
79+{-# SPECIALIZE hexadecimal :: Reader Int16 #-}
80+{-# SPECIALIZE hexadecimal :: Reader Int32 #-}
81+{-# SPECIALIZE hexadecimal :: Reader Int64 #-}
67{-# SPECIALIZE hexadecimal :: Reader Integer #-}
82{-# SPECIALIZE hexadecimal :: Reader Integer #-}
83+{-# SPECIALIZE hexadecimal :: Reader Word #-}
84+{-# SPECIALIZE hexadecimal :: Reader Word8 #-}
85+{-# SPECIALIZE hexadecimal :: Reader Word16 #-}
86+{-# SPECIALIZE hexadecimal :: Reader Word32 #-}
87+{-# SPECIALIZE hexadecimal :: Reader Word64 #-}
68hexadecimal txt
88hexadecimal txt
69 | h == "0x" || h == "0X" = hex t
89 | h == "0x" || h == "0X" = hex t
70 | otherwise = hex txt
90 | otherwise = hex txt
@@ -72,11 +92,20 @@ hexadecimal txt
73hex :: Integral a => Reader a
93hex :: Integral a => Reader a
74{-# SPECIALIZE hex :: Reader Int #-}
94{-# SPECIALIZE hex :: Reader Int #-}
95+{-# SPECIALIZE hex :: Reader Int8 #-}
96+{-# SPECIALIZE hex :: Reader Int16 #-}
97+{-# SPECIALIZE hex :: Reader Int32 #-}
98+{-# SPECIALIZE hex :: Reader Int64 #-}
75{-# SPECIALIZE hex :: Reader Integer #-}
99{-# SPECIALIZE hex :: Reader Integer #-}
100+{-# SPECIALIZE hex :: Reader Word #-}
101+{-# SPECIALIZE hex :: Reader Word8 #-}
102+{-# SPECIALIZE hex :: Reader Word16 #-}
103+{-# SPECIALIZE hex :: Reader Word32 #-}
104+{-# SPECIALIZE hex :: Reader Word64 #-}
77 | T.null h = Left "input does not start with a hexadecimal digit"
106 | T.null h = Left "input does not start with a hexadecimal digit"
78 | otherwise = Right (T.foldl' go 0 h, t)
107 | otherwise = Right (T.foldl' go 0 h, t)
79− where (h,t) = T.span isHexDigit txt
108+ where (# h,t #) = span_ isHexDigit txt
80 go n d = (n * 16 + fromIntegral (hexDigitToInt d))
109 go n d = (n * 16 + fromIntegral (hexDigitToInt d))
82hexDigitToInt :: Char -> Int
111hexDigitToInt :: Char -> Int
@@ -114,7 +143,7 @@ signed f = runP (signa (P f))
115-- >rational "3.foo" == Right (3.0, ".foo")
144-- >rational "3.foo" == Right (3.0, ".foo")
116-- >rational "3e" == Right (3.0, "e")
145-- >rational "3e" == Right (3.0, "e")
117−rational :: RealFloat a => Reader a
146+rational :: Fractional a => Reader a
118{-# SPECIALIZE rational :: Reader Double #-}
147{-# SPECIALIZE rational :: Reader Double #-}
119rational = floaty $ \real frac fracDenom -> fromRational $
148rational = floaty $ \real frac fracDenom -> fromRational $
120 real % 1 + frac % fracDenom
149 real % 1 + frac % fracDenom
@@ -138,6 +167,10 @@ double = floaty $ \real frac fracDenom ->
139signa :: Num a => Parser a -> Parser a
168signa :: Num a => Parser a -> Parser a
140{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
169{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
170+{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}
171+{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}
172+{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}
173+{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}
141{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
174{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
142signa p = do
175signa p = do
143 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
176 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
@@ -168,7 +201,7 @@ char p = P $ \t -> case T.uncons t of
169data T = T !Integer !Int
202data T = T !Integer !Int
171−floaty :: RealFloat a => (Integer -> Integer -> Integer -> a) -> Reader a
204+floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
172{-# INLINE floaty #-}
205{-# INLINE floaty #-}
173floaty f = runP $ do
206floaty f = runP $ do
174 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
207 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')