diff options
author | Ian Lynagh <igloo@earth.li> | 2012-03-01 01:26:06 +0000 |
---|---|---|
committer | Ian Lynagh <igloo@earth.li> | 2012-03-01 01:26:06 +0000 |
commit | ba5bea9b7736b83d7ae65f69faaff1a10d83f1d4 (patch) | |
tree | 06daccfa5f46c219c0f335ff768dbe8af6f9c626 /libraries/base/Text/Read | |
parent | f40aa90d44c3962f5995b0c0e72d16dd91d6198d (diff) | |
download | haskell-ba5bea9b7736b83d7ae65f69faaff1a10d83f1d4.tar.gz |
Refactor number lexing; part of #5688
This doesn't change the behaviour yet, but I think it's a step in the
right direction.
Diffstat (limited to 'libraries/base/Text/Read')
-rw-r--r-- | libraries/base/Text/Read/Lex.hs | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/libraries/base/Text/Read/Lex.hs b/libraries/base/Text/Read/Lex.hs index 0af66b7034..fe20a0bcaa 100644 --- a/libraries/base/Text/Read/Lex.hs +++ b/libraries/base/Text/Read/Lex.hs @@ -19,6 +19,8 @@ module Text.Read.Lex -- lexing types ( Lexeme(..) -- :: *; Show, Eq + , numberToInteger, numberToRational + -- lexer , lex -- :: ReadP Lexeme Skips leading spaces , hsLex -- :: ReadP String @@ -64,11 +66,47 @@ data Lexeme | Punc String -- ^ Punctuation or reserved symbol, e.g. @(@, @::@ | Ident String -- ^ Haskell identifier, e.g. @foo@, @Baz@ | Symbol String -- ^ Haskell symbol, e.g. @>>@, @:%@ - | Int Integer -- ^ Integer literal - | Rat Rational -- ^ Floating point literal + | Number Number | EOF deriving (Eq, Show) +data Number = MkNumber Int -- Base + Digits -- Integral part + | MkDecimal Digits -- Integral part + (Maybe Digits) -- Fractional part + (Maybe Integer) -- Exponent + | NotANumber + | Infinity + deriving (Eq, Show) + +numberToInteger :: Number -> Maybe Integer +numberToInteger (MkNumber base iPart) = Just (val (fromIntegral base) 0 iPart) +numberToInteger (MkDecimal iPart Nothing mExp) + = let i = val 10 0 iPart + in case mExp of + Nothing -> Just i + Just exp | exp >= 0 -> Just (i * (10 ^ exp)) + _ -> Nothing +numberToInteger _ = Nothing + +numberToRational :: Number -> Rational +numberToRational NotANumber = notANumber +numberToRational Infinity = infinity +numberToRational (MkNumber base iPart) = val (fromIntegral base) 0 iPart % 1 +numberToRational (MkDecimal iPart mFPart mExp) + = let i = val 10 0 iPart + in case (mFPart, mExp) of + (Nothing, Nothing) -> i % 1 + (Nothing, Just exp) + | exp >= 0 -> (i * (10 ^ exp)) % 1 + | otherwise -> i % (10 ^ (- exp)) + (Just fPart, Nothing) -> fracExp 0 i fPart + (Just fPart, Just exp) -> fracExp exp i fPart + -- fracExp is a bit more efficient in calculating the Rational. + -- Instead of calculating the fractional part alone, then + -- adding the integral part and finally multiplying with + -- 10 ^ exp if an exponent was given, do it all at once. + -- ----------------------------------------------------------------------------- -- Lexing @@ -130,8 +168,8 @@ lexId = lex_nan <++ lex_id where -- NaN and Infinity look like identifiers, so -- we parse them first. - lex_nan = (string "NaN" >> return (Rat notANumber)) +++ - (string "Infinity" >> return (Rat infinity)) + lex_nan = (string "NaN" >> return (Number NotANumber)) +++ + (string "Infinity" >> return (Number Infinity)) lex_id = do c <- satisfy isIdsChar s <- munch isIdfChar @@ -318,7 +356,7 @@ lexHexOct = do _ <- char '0' base <- lexBaseChar digits <- lexDigits base - return (Int (val (fromIntegral base) 0 digits)) + return (Number (MkNumber base digits)) lexBaseChar :: ReadP Int -- Lex a single character indicating the base; fail if not there @@ -335,23 +373,7 @@ lexDecNumber = do xs <- lexDigits 10 mFrac <- lexFrac <++ return Nothing mExp <- lexExp <++ return Nothing - return (value xs mFrac mExp) - where - value xs mFrac mExp = valueFracExp (val 10 0 xs) mFrac mExp - - valueFracExp :: Integer -> Maybe Digits -> Maybe Integer - -> Lexeme - valueFracExp a Nothing Nothing - = Int a -- 43 - valueFracExp a Nothing (Just exp) - | exp >= 0 = Int (a * (10 ^ exp)) -- 43e7 - | otherwise = Rat (a % (10 ^ (-exp))) -- 43e-7 - valueFracExp a (Just fs) mExp -- 4.3[e2] - = Rat (fracExp (fromMaybe 0 mExp) a fs) - -- Be a bit more efficient in calculating the Rational. - -- Instead of calculating the fractional part alone, then - -- adding the integral part and finally multiplying with - -- 10 ^ exp if an exponent was given, do it all at once. + return (Number (MkDecimal xs mFrac mExp)) lexFrac :: ReadP (Maybe Digits) -- Read the fractional part; fail if it doesn't |