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