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 ) 
69  69  #endif 
70  70  import GHC.Num 
71  71  import GHC.Real 
72   import GHC.Float () 
 72  import GHC.Float 
73  73  import GHC.Show 
 74  import GHC.Enum 
74  75  import GHC.Base 
75  76  import GHC.Arr 
76  77   For defining instances for the generic deriving mechanism 
… 
… 
readNumber convert = 
472  473  convertInt :: Num a => L.Lexeme > ReadPrec a 
473  474  convertInt (L.Int i) = return (fromInteger i) 
474  475  convertInt _ = pfail 
 476  \end{code} 
 477  
 478  In convertFrac we need to watch out to not do exponent on Integer or 
 479  Rational. It is very easy to go out of memory, exponentation needs to 
 480  be done in final floating type. 
475  481  
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} 
 483  convertFrac :: Floating a => L.Lexeme > ReadPrec a 
 484  convertFrac (L.Int i) = return (fromInteger i) 
 485  convertFrac (L.Rat r) = return (fromRational r) 
 486  convertFrac (L.Exp b e) = return (fromInteger b * (10 ** fromInteger e)) 
 487  convertFrac _ = pfail 
480  488  
481  489  instance Read Int where 
482  490  readPrec = readNumber convertInt 
diff git a/Text/Read/Lex.hs b/Text/Read/Lex.hs
index e4563b6..ec03830 100644
a

b

data Lexeme 
67  67   Symbol String  ^ Haskell symbol, e.g. @>>@, @:%@ 
68  68   Int Integer  ^ Integer literal 
69  69   Rat Rational  ^ Floating point literal 
 70   Exp Integer Integer  ^ Floating point literal in exponential form a*10^b 
70  71   EOF 
71  72  deriving (Eq, Show) 
72  73  
… 
… 
lexDecNumber = 
345  346  valueFracExp a Nothing Nothing 
346  347  = Int a  43 
347  348  valueFracExp a Nothing (Just exp) 
348    exp >= 0 = Int (a * (10 ^ exp))  43e7 
349    otherwise = Rat (a % (10 ^ (exp)))  43e7 
 349  = Exp a exp 
350  350  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 
356  352  
357  353  lexFrac :: ReadP (Maybe Digits) 
358  354   Read the fractional part; fail if it doesn't 
… 
… 
val base y (x:xs) = y' `seq` val base y' xs 
404  400   
405  401   frac was never used with anything but Integer and base 10, so 
406  402   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) 
 403  fracExp :: Integer > Integer > Digits > (Integer,Integer) 
 404  fracExp exp mant [] = (mant, exp) 
411  405  fracExp exp mant (d:ds) = exp' `seq` mant' `seq` fracExp exp' mant' ds 
412  406  where 
413  407  exp' = exp  1 