{-| Module : Data.JustParse.Numeric Description : Numeric parsing Copyright : Copyright Waived License : PublicDomain Maintainer : grantslatton@gmail.com Stability : experimental Portability : portable Parsers for dealing with signed and unsigned 'Int's and 'Float's. -} module Data.JustParse.Numeric ( decDigit, hexDigit, unsignedDecInt, unsignedDecInt_, unsignedHexInt, unsignedHexInt_, decInt, decInt_, hexInt, hexInt_, decFloat, decFloat_, ) where {-# LANGUAGE Safe #-} import Data.JustParse.Combinator import Data.JustParse.Internal import qualified Data.JustParse.Char as C import Control.Monad ( liftM, liftM2 ) import Data.Char ( ord, digitToInt, toUpper, isDigit, isHexDigit ) -- | Parse a single decimal digit into an 'Int'. decDigit :: Stream s Char => Parser s Int decDigit = liftM digitToInt C.digit {-# INLINE decDigit #-} -- | Parse a single hexadecimal digit into an 'Int'. hexDigit :: Stream s Char => Parser s Int hexDigit = liftM digitToInt C.hexDigit {-# INLINE hexDigit #-} -- | Parse a series of decimal digits into an 'Int'. unsignedDecInt :: Stream s Char => Parser s Int unsignedDecInt = decDigit >>= g where g x = do d <- decDigit g (x*10+d) <|> return x {-# INLINE unsignedDecInt #-} -- | Branching version of 'unsignedDecInt'. unsignedDecInt_ :: Stream s Char => Parser s Int unsignedDecInt_ = decDigit >>= g where g x = do d <- decDigit g (x*10+d) <||> return x {-# INLINE unsignedDecInt_ #-} -- | Parse a series of hexadecimal digits into an 'Int'. unsignedHexInt :: Stream s Char => Parser s Int unsignedHexInt = hexDigit >>= g where g x = do d <- hexDigit g (x*16+d) <|> return x {-# INLINE unsignedHexInt #-} -- | Branching version of 'unsignedHexInt'. unsignedHexInt_ :: Stream s Char => Parser s Int unsignedHexInt_ = hexDigit >>= g where g x = do d <- hexDigit g (x*16+d) <||> return x {-# INLINE unsignedHexInt_ #-} -- | Parse a series of decimal digits into an 'Int' with an optional sign. decInt :: Stream s Char => Parser s Int decInt = do sign <- optional (oneOf "-+") num <- unsignedDecInt case sign of Just '-' -> return (-num) _ -> return num {-# INLINE decInt #-} -- | Branching version of 'decInt'. decInt_ :: Stream s Char => Parser s Int decInt_ = do sign <- optional (oneOf "-+") num <- unsignedDecInt_ case sign of Just '-' -> return (-num) _ -> return num {-# INLINE decInt_ #-} -- | Parse a series of hexadecimal digits into an 'Int' with an optional -- sign. hexInt :: Stream s Char => Parser s Int hexInt = do sign <- optional (oneOf "-+") num <- unsignedHexInt case sign of Just '-' -> return (-num) _ -> return num {-# INLINE hexInt #-} -- | Branching versino of 'hexInt'. hexInt_ :: Stream s Char => Parser s Int hexInt_ = do sign <- optional (oneOf "-+") num <- unsignedHexInt_ case sign of Just '-' -> return (-num) _ -> return num {-# INLINE hexInt_ #-} -- | Parse a float. If a decimal point is present, it must have at -- least one digit before and after the decimal point. decFloat :: Stream s Char => Parser s Float decFloat = do sign <- optional (oneOf "-+") whole <- many1 C.digit fractional <- option ".0" (liftM2 (:) (C.char '.') (many1 C.digit)) case sign of Just '-' -> return (-(read (whole ++ fractional))) _ -> return (read (whole ++ fractional)) {-# INLINE decFloat #-} -- | Branching version of decFloat. decFloat_ :: Stream s Char => Parser s Float decFloat_ = do sign <- optional (oneOf "-+") whole <- many1_ C.digit fractional <- option_ ".0" (liftM2 (:) (C.char '.') (many1_ C.digit)) case sign of Just '-' -> return (-(read (whole ++ fractional))) _ -> return (read (whole ++ fractional)) {-# INLINE decFloat_ #-}