Ticket #5688: 0001-Added-new-Exp-constructor-to-Text.Read.Lex.Lexeme-so.patch

File 0001-Added-new-Exp-constructor-to-Text.Read.Lex.Lexeme-so.patch, 3.6 KB (added by gracjan, 4 years ago)
  • GHC/Read.lhs

    From 2797941c7841a09a18904928e9dd47268c712e45 Mon Sep 17 00:00:00 2001
    From: Gracjan Polak <[email protected]>
    Date: Mon, 12 Dec 2011 15:17:55 +0100
    Subject: [PATCH] Added new Exp constructor to Text.Read.Lex.Lexeme so that
     exponential notation can be safely parsed.
    
    Fixes #5688 and #3897
    
    instance Read Integer/Rational/Double readsPrec out of memory and crash due to exponential notation
    
    and
    
    reading a large String as Double takes too long
    ---
     GHC/Read.lhs     |   18 +++++++++++++-----
     Text/Read/Lex.hs |   16 +++++-----------
     2 files changed, 18 insertions(+), 16 deletions(-)
    
    diff --git a/GHC/Read.lhs b/GHC/Read.lhs
    index fcbdb8e..963cb74 100644
    a b import {-# SOURCE #-} GHC.Unicode ( isDigit ) 
    6969#endif
    7070import GHC.Num
    7171import GHC.Real
    72 import GHC.Float ()
     72import GHC.Float
    7373import GHC.Show
     74import GHC.Enum
    7475import GHC.Base
    7576import GHC.Arr
    7677-- For defining instances for the generic deriving mechanism
    readNumber convert = 
    472473convertInt :: Num a => L.Lexeme -> ReadPrec a
    473474convertInt (L.Int i) = return (fromInteger i)
    474475convertInt _         = pfail
     476\end{code}
     477
     478In convertFrac we need to watch out to not do exponent on Integer or
     479Rational. It is very easy to go out of memory, exponentation needs to
     480be done in final floating type.
    475481
    476 convertFrac :: Fractional a => L.Lexeme -> ReadPrec a
    477 convertFrac (L.Int i) = return (fromInteger i)
    478 convertFrac (L.Rat r) = return (fromRational r)
    479 convertFrac _         = pfail
     482\begin{code}
     483convertFrac :: Floating a => L.Lexeme -> ReadPrec a
     484convertFrac (L.Int i)   = return (fromInteger i)
     485convertFrac (L.Rat r)   = return (fromRational r)
     486convertFrac (L.Exp b e) = return (fromInteger b * (10 ** fromInteger e))
     487convertFrac _           = pfail
    480488
    481489instance Read Int where
    482490  readPrec     = readNumber convertInt
  • Text/Read/Lex.hs

    diff --git a/Text/Read/Lex.hs b/Text/Read/Lex.hs
    index e4563b6..ec03830 100644
    a b data Lexeme 
    6767  | Symbol String       -- ^ Haskell symbol, e.g. @>>@, @:%@
    6868  | Int Integer         -- ^ Integer literal
    6969  | Rat Rational        -- ^ Floating point literal
     70  | Exp Integer Integer -- ^ Floating point literal in exponential form a*10^b
    7071  | EOF
    7172 deriving (Eq, Show)
    7273
    lexDecNumber = 
    345346  valueFracExp a Nothing Nothing
    346347    = Int a                                             -- 43
    347348  valueFracExp a Nothing (Just exp)
    348     | exp >= 0  = Int (a * (10 ^ exp))                  -- 43e7
    349     | otherwise = Rat (a % (10 ^ (-exp)))               -- 43e-7
     349    = Exp a exp
    350350  valueFracExp a (Just fs) mExp                         -- 4.3[e2]
    351     = Rat (fracExp (fromMaybe 0 mExp) a fs)
    352     -- Be a bit more efficient in calculating the Rational.
    353     -- Instead of calculating the fractional part alone, then
    354     -- adding the integral part and finally multiplying with
    355     -- 10 ^ exp if an exponent was given, do it all at once.
     351    = let (a,e) = fracExp (fromMaybe 0 mExp) a fs in Exp a e
    356352
    357353lexFrac :: ReadP (Maybe Digits)
    358354-- Read the fractional part; fail if it doesn't
    val base y (x:xs) = y' `seq` val base y' xs 
    404400--
    405401-- frac was never used with anything but Integer and base 10, so
    406402-- those are hardcoded now (trivial to change if necessary).
    407 fracExp :: Integer -> Integer -> Digits -> Rational
    408 fracExp exp mant []
    409   | exp < 0     = mant % (10 ^ (-exp))
    410   | otherwise   = fromInteger (mant * 10 ^ exp)
     403fracExp :: Integer -> Integer -> Digits -> (Integer,Integer)
     404fracExp exp mant [] = (mant, exp)
    411405fracExp exp mant (d:ds) = exp' `seq` mant' `seq` fracExp exp' mant' ds
    412406  where
    413407    exp'  = exp - 1