{-# LANGUAGE CPP #-}
{-# LANGUAGE PatternGuards #-}
module What4.Protocol.ReadDecimal
( readDecimal
) where
#if !MIN_VERSION_base(4,13,0)
import Control.Monad.Fail( MonadFail )
#endif
import Control.Lens (over, _1)
import Data.Ratio
readDecimal :: MonadFail m => String -> m (Rational, String)
readDecimal ('-':c:r) | Just i <- asDigit c =
return $! over _1 negate $ readDecimal' (toRational i) r
readDecimal (c:r) | Just i <- asDigit c =
return $ readDecimal' (toRational i) r
readDecimal _ = fail "Could not parse string."
readDecimal' :: Rational
-> String
-> (Rational, String)
readDecimal' v (c:r) | Just i <- asDigit c =
let v' = 10 * v + toRational i
in readDecimal' v' r
readDecimal' v ('.':r) = readDigits v r 10
readDecimal' v d = (v,d)
readDigits :: Rational
-> String
-> Integer
-> (Rational, String)
readDigits v (c:r) d
| Just i <- asDigit c =
let v' = v + (toInteger i%d)
in readDigits v' r (10*d)
readDigits v ('?':r) _ = (v,r)
readDigits v r _ = (v,r)
asDigit :: Char -> Maybe Int
asDigit c | fromEnum '0' <= i && i <= fromEnum '9' = Just (i - fromEnum '0')
| otherwise = Nothing
where i = fromEnum c