Bryan O'Sullivan avatar Bryan O'Sullivan committed 64dd961

Various bits of doc and code cleanup.

Comments (0)

Files changed (1)

Data/Text/Read.hs

 import Data.Ratio ((%))
 import Data.Text as T
 
--- | Read some text, and if the read succeeds, return its value and
--- the remaining text.
+-- | Read some text.  If the read succeeds, return its value and the
+-- remaining text, otherwise an error message.
 type Reader a = Text -> Either String (a,Text)
 
--- | Read a decimal integer.
+-- | Read a decimal integer.  The input must begin with at least one
+-- decimal digit, and is consumed until a non-digit or end of string
+-- is reached.
 --
 -- This function does not handle leading sign characters.  If you need
 -- to handle signed input, use @'signed' 'decimal'@.
+--
+-- /Note/: For fixed-width integer types, this function does not
+-- attempt to detect overflow, so a sufficiently long input may give
+-- incorrect results.
 decimal :: Integral a => Reader a
 {-# SPECIALIZE decimal :: Reader Int #-}
 {-# SPECIALIZE decimal :: Reader Integer #-}
 decimal txt
-    | T.null h  = Left "no digits in input"
+    | T.null h  = Left "input does not start with a digit"
     | otherwise = Right (T.foldl' go 0 h, t)
   where (h,t)  = T.spanBy isDigit txt
         go n d = (n * 10 + fromIntegral (digitToInt d))
 
--- | Read a hexadecimal number, with optional leading @\"0x\"@.  This
--- function is case insensitive.
+-- | Read a hexadecimal number, consisting of an optional leading
+-- @\"0x\"@ followed by at least one decimal digit. Input is consumed
+-- until a non-hex-digit or end of string is reached.  This function
+-- is case insensitive.
 --
 -- This function does not handle leading sign characters.  If you need
 -- to handle signed input, use @'signed' 'hexadecimal'@.
+--
+-- /Note/: For fixed-width integer types, this function does not
+-- attempt to detect overflow, so a sufficiently long input may give
+-- incorrect results.
 hexadecimal :: Integral a => Reader a
+{-# SPECIALIZE hexadecimal :: Reader Int #-}
+{-# SPECIALIZE hexadecimal :: Reader Integer #-}
+hexadecimal txt
+    | h == "0x" || h == "0X" = hex t
+    | otherwise              = hex txt
+ where (h,t) = T.splitAt 2 txt
+
+hex :: Integral a => Reader a
 {-# SPECIALIZE hex :: Reader Int #-}
 {-# SPECIALIZE hex :: Reader Integer #-}
-hexadecimal txt
-    | T.toLower h == "0x" = hex t
-    | otherwise           = hex txt
- where (h,t) = T.splitAt 2 txt
+hex txt
+    | T.null h  = Left "input does not start with a hexadecimal digit"
+    | otherwise = Right (T.foldl' go 0 h, t)
+  where (h,t)  = T.spanBy isHexDigit txt
+        go n d = (n * 16 + fromIntegral (hexDigitToInt d))
 
 hexDigitToInt :: Char -> Int
 hexDigitToInt c
 
 -- | Read a rational number.
 --
--- This function accepts an optional leading sign character.
+-- This function accepts an optional leading sign character, followed
+-- by at least one decimal digit.  The syntax similar to that accepted
+-- by the 'read' function, with the exception that a trailing @\'.\'@
+-- or @\'e\'@ /not/ followed by a number is not consumed.
+--
+-- Examples:
+--
+-- >rational "3"     == Right (3.0, "")
+-- >rational "3.1"   == Right (3.1, "")
+-- >rational "3e4"   == Right (30000.0, "")
+-- >rational "3.1e4" == Right (31000.0, "")
+-- >rational ".3"    == Left "input does not start with a digit"
+-- >rational "e3"    == Left "input does not start with a digit"
+--
+-- Examples of differences from 'read':
+--
+-- >rational "3.foo" == Right (3.0, ".foo")
+-- >rational "3e"    == Right (3.0, "e")
 rational :: RealFloat a => Reader a
 {-# SPECIALIZE rational :: Reader Double #-}
 rational = floaty $ \real frac fracDenom -> fromRational $
 
 -- | Read a rational number.
 --
--- This function accepts an optional leading sign character.
+-- The syntax accepted by this function is the same as for 'rational'.
 --
 -- /Note/: This function is almost ten times faster than 'rational',
 -- but is slightly less accurate.
                    fromIntegral real +
                    fromIntegral frac / fromIntegral fracDenom
 
-hex :: Integral a => Reader a
-{-# SPECIALIZE hex :: Reader Int #-}
-{-# SPECIALIZE hex :: Reader Integer #-}
-hex txt
-    | T.null h  = Left "no digits in input"
-    | otherwise = Right (T.foldl' go 0 h, t)
-  where (h,t)  = T.spanBy isHexDigit txt
-        go n d = (n * 16 + fromIntegral (hexDigitToInt d))
-
-hexDigitToInt :: Char -> Int
-hexDigitToInt c
-    | c >= '0' && c <= '9' = ord c - ord '0'
-    | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
-    | c >= 'A' && c <= 'F' = ord c - (ord 'A' - 10)
-    | otherwise            = error "Data.Text.Lex.hexDigitToInt: bad input"
-
 signa :: Num a => Parser a -> Parser a
 {-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
 {-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
   if sign == '+' then p else negate `liftM` p
 
 newtype Parser a = P {
-      runP :: Text -> Either String (a,Text)
+      runP :: Reader a
     }
 
 instance Monad Parser where
 char :: (Char -> Bool) -> Parser Char
 char p = P $ \t -> case T.uncons t of
                      Just (c,t') | p c -> Right (c,t')
-                     _                 -> Left "char"
+                     _                 -> Left "character does not match"
 
 data T = T !Integer !Int
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.