git.iko.soy/typeable/attoparsec
on master help sign in
Merge

--HG-- extra : amend_source : 4537d65463b25bd79dfa61bf69561497186c0a08

commit1602eaa7e437f4c9dd9afe67d699d150c38a25e5 authorBryan O'Sullivan <bos@serpentine.com> dateFri 25 Oct 2013, 09:55 (13 years ago) parentfd837013f15e46
7 files changed+80−92
.gitignore+2 Data/Attoparsec/ByteString/Char8.hs+34−44 Data/Attoparsec/Number.hs+1−4 Data/Attoparsec/Text.hs+33−43 attoparsec.cabal+2−1 benchmarks/Benchmarks.hs+7 benchmarks/attoparsec-benchmarks.cabal+1
.gitignore+2
@@ -1,3 +1,5 @@
11*.hi
22*.o
33/dist/
4+.cabal-sandbox
5+cabal.sandbox.config
Data/Attoparsec/ByteString/Char8.hs+34−44
@@ -106,7 +106,7 @@ module Data.Attoparsec.ByteString.Char8
106106 , I.atEnd
107107 ) where
108108
109−import Control.Applicative ((*>), (<*), (<$>), (<|>))
109+import Control.Applicative (pure, (*>), (<*), (<$>), (<|>))
110110import Data.Attoparsec.ByteString.FastSet (charClass, memberChar)
111111import Data.Attoparsec.ByteString.Internal (Parser, (<?>))
112112import Data.Attoparsec.Combinator
@@ -114,8 +114,8 @@ import Data.Attoparsec.Number (Number(..))
114114import Data.Bits (Bits, (.|.), shiftL)
115115import Data.ByteString.Internal (c2w, w2c)
116116import Data.Int (Int8, Int16, Int32, Int64)
117−import Data.Ratio ((%))
118117import Data.String (IsString(..))
118+import Data.Scientific (Scientific, scientific, coefficient, base10Exponent)
119119import Data.Word (Word8, Word16, Word32, Word64, Word)
120120import Prelude hiding (takeWhile)
121121import qualified Data.Attoparsec.ByteString as A
@@ -471,8 +471,8 @@ rational :: Fractional a => Parser a
471471{-# SPECIALIZE rational :: Parser Double #-}
472472{-# SPECIALIZE rational :: Parser Float #-}
473473{-# SPECIALIZE rational :: Parser Rational #-}
474−rational = floaty $ \real frac fracDenom -> fromRational $
475− real % 1 + frac % fracDenom
474+{-# SPECIALIZE rational :: Parser Scientific #-}
475+rational = scientifically realToFrac
476476
477477-- | Parse a rational number.
478478--
@@ -490,12 +490,7 @@ rational = floaty $ \real frac fracDenom -> fromRational $
490490-- This function does not accept string representations of \"NaN\" or
491491-- \"Infinity\".
492492double :: Parser Double
493−double = floaty asDouble
494−
495−asDouble :: Integer -> Integer -> Integer -> Double
496−asDouble real frac fracDenom =
497− fromIntegral real + fromIntegral frac / fromIntegral fracDenom
498−{-# INLINE asDouble #-}
493+double = rational
499494
500495-- | Parse a number, attempting to preserve both speed and precision.
501496--
@@ -507,43 +502,38 @@ asDouble real frac fracDenom =
507502-- 'rational'.
508503--
509504-- This function does not accept string representations of \"NaN\" or
510−-- \"Infinity\".
505+-- \"
511506number :: Parser Number
512−number = floaty $ \real frac fracDenom ->
513− if frac == 0 && fracDenom == 0
514− then I real
515− else D (asDouble real frac fracDenom)
516−{-# INLINE number #-}
517−
518−data T = T !Integer !Int
519−
520−floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a
521−{-# INLINE floaty #-}
522−floaty f = do
507+number = scientifically $ \s ->
508+ let e = base10Exponent s
509+ c = coefficient s
510+ in if e >= 0
511+ then I (c * 10 ^ e)
512+ else D (fromInteger c / 10 ^ negate e)
513+
514+{-# INLINE scientifically #-}
515+scientifically :: (Scientific -> a) -> Parser a
516+scientifically h = do
523517 let minus = 45
524518 plus = 43
525519 !positive <- ((== plus) <$> I.satisfy (\c -> c == minus || c == plus)) <|>
526− return True
527− real <- decimal
528− let tryFraction = do
529− let dot = 46
530− _ <- I.satisfy (==dot)
531− ds <- I.takeWhile isDigit_w8
532− case I.parseOnly decimal ds of
533− Right n -> return $ T n (B.length ds)
534− _ -> fail "no digits after decimal"
535− T fraction fracDigits <- tryFraction <|> return (T 0 0)
520+ pure True
521+
522+ n <- decimal
523+
524+ let f fracDigits = scientific (B8.foldl' step n fracDigits)
525+ (negate $ B8.length fracDigits)
526+ step a w = a * 10 + fromIntegral (w - 48)
527+
528+ s <- let dot = 46 in
529+ (I.satisfy (==dot) *> (f <$> I.takeWhile isDigit_w8)) <|>
530+ pure (scientific n 0)
531+
532+ let !signedCoeff | positive = coefficient s
533+ | otherwise = negate $ coefficient s
534+
536535 let littleE = 101
537536 bigE = 69
538− e w = w == littleE || w == bigE
539− power <- (I.satisfy e *> signed decimal) <|> return (0::Int)
540− let n = if fracDigits == 0
541− then if power == 0
542− then fromIntegral real
543− else fromIntegral real * (10 ^^ power)
544− else if power == 0
545− then f real fraction (10 ^ fracDigits)
546− else f real fraction (10 ^ fracDigits) * (10 ^^ power)
547− return $ if positive
548− then n
549− else -n
537+ (I.satisfy (\c -> c == littleE || c == bigE) *>
538+ fmap (h . scientific signedCoeff . (base10Exponent s +)) (signed decimal)) <|>
539+ return (h $ scientific signedCoeff (base10Exponent s))
Data/Attoparsec/Number.hs+1−4
@@ -10,10 +10,7 @@
1010--
1111-- A simple number type, useful for parsing both exact and inexact
1212-- quantities without losing much precision.
13−module Data.Attoparsec.Number
14− (
15− Number(..)
16− ) where
13+module Data.Attoparsec.Number ( Number(..) ) where
1714
1815import Control.DeepSeq (NFData(rnf))
1916import Data.Data (Data)
Data/Attoparsec/Text.hs+33−43
@@ -103,14 +103,14 @@ module Data.Attoparsec.Text
103103 , I.atEnd
104104 ) where
105105
106−import Control.Applicative ((<$>), (*>), (<*), (<|>))
106+import Control.Applicative (pure, (<$>), (*>), (<*), (<|>))
107107import Data.Attoparsec.Combinator
108108import Data.Attoparsec.Number (Number(..))
109+import Data.Scientific (Scientific, scientific, coefficient, base10Exponent)
109110import Data.Attoparsec.Text.Internal ((<?>), Parser, Result, parse, takeWhile1)
110111import Data.Bits (Bits, (.|.), shiftL)
111112import Data.Char (isAlpha, isDigit, isSpace, ord)
112113import Data.Int (Int8, Int16, Int32, Int64)
113−import Data.Ratio ((%))
114114import Data.Text (Text)
115115import Data.Word (Word8, Word16, Word32, Word64, Word)
116116import qualified Data.Attoparsec.Internal as I
@@ -343,8 +343,8 @@ rational :: Fractional a => Parser a
343343{-# SPECIALIZE rational :: Parser Double #-}
344344{-# SPECIALIZE rational :: Parser Float #-}
345345{-# SPECIALIZE rational :: Parser Rational #-}
346−rational = floaty $ \real frac fracDenom -> fromRational $
347− real % 1 + frac % fracDenom
346+{-# SPECIALIZE rational :: Parser Scientific #-}
347+rational = scientifically realToFrac
348348
349349-- | Parse a rational number.
350350--
@@ -362,12 +362,7 @@ rational = floaty $ \real frac fracDenom -> fromRational $
362362-- This function does not accept string representations of \"NaN\" or
363363-- \"Infinity\".
364364double :: Parser Double
365−double = floaty asDouble
366−
367−asDouble :: Integer -> Integer -> Integer -> Double
368−asDouble real frac fracDenom =
369− fromIntegral real + fromIntegral frac / fromIntegral fracDenom
370−{-# INLINE asDouble #-}
365+double = rational
371366
372367-- | Parse a number, attempting to preserve both speed and precision.
373368--
@@ -381,11 +376,34 @@ asDouble real frac fracDenom =
381376-- This function does not accept string representations of \"NaN\" or
382377-- \"Infinity\".
383378number :: Parser Number
384−number = floaty $ \real frac fracDenom ->
385− if frac == 0 && fracDenom == 0
386− then I real
387− else D (asDouble real frac fracDenom)
388−{-# INLINE number #-}
379+number = scientifically $ \s ->
380+ let e = base10Exponent s
381+ c = coefficient s
382+ in if e >= 0
383+ then I (c * 10 ^ e)
384+ else D (fromInteger c / 10 ^ negate e)
385+
386+{-# INLINE scientifically #-}
387+scientifically :: (Scientific -> a) -> Parser a
388+scientifically h = do
389+ !positive <- ((== '+') <$> I.satisfy (\c -> c == '-' || c == '+')) <|>
390+ pure True
391+
392+ n <- decimal
393+
394+ let f fracDigits = scientific (T.foldl' step n fracDigits)
395+ (negate $ T.length fracDigits)
396+ step a c = a * 10 + fromIntegral (ord c - 48)
397+
398+ s <- (I.satisfy (=='.') *> (f <$> I.takeWhile isDigit)) <|>
399+ pure (scientific n 0)
400+
401+ let !signedCoeff | positive = coefficient s
402+ | otherwise = negate $ coefficient s
403+
404+ (I.satisfy (\c -> c == 'e' || c == 'E') *>
405+ fmap (h . scientific signedCoeff . (base10Exponent s +)) (signed decimal)) <|>
406+ return (h $ scientific signedCoeff (base10Exponent s))
389407
390408-- | Parse a single digit, as recognised by 'isDigit'.
391409digit :: Parser Char
@@ -433,31 +451,3 @@ s .*> f = I.string s *> f
433451-- | Type-specialized version of '<*' for 'Text'.
434452(<*.) :: Parser a -> Text -> Parser a
435453f <*. s = f <* I.string s
436−
437−data T = T !Integer !Int
438−
439−floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a
440−{-# INLINE floaty #-}
441−floaty f = do
442− !positive <- ((== '+') <$> I.satisfy (\c -> c == '-' || c == '+')) <|>
443− return True
444− real <- decimal
445− let tryFraction = do
446− _ <- I.satisfy (=='.')
447− ds <- I.takeWhile isDigit
448− case I.parseOnly decimal ds of
449− Right n -> return $ T n (T.length ds)
450− _ -> fail "no digits after decimal"
451− T fraction fracDigits <- tryFraction <|> return (T 0 0)
452− let e c = c == 'e' || c == 'E'
453− power <- (I.satisfy e *> signed decimal) <|> return (0::Int)
454− let n = if fracDigits == 0
455− then if power == 0
456− then fromIntegral real
457− else fromIntegral real * (10 ^^ power)
458− else if power == 0
459− then f real fraction (10 ^ fracDigits)
460− else f real fraction (10 ^ fracDigits) * (10 ^^ power)
461− return $ if positive
462− then n
463− else -n
attoparsec.cabal+2−1
@@ -43,7 +43,8 @@ library
4343 bytestring,
4444 containers,
4545 deepseq,
46− text >= 0.11.1.5
46+ text >= 0.11.1.5,
47+ scientific >= 0.0 && < 0.1
4748
4849 exposed-modules: Data.Attoparsec
4950 Data.Attoparsec.ByteString
benchmarks/Benchmarks.hs+7
@@ -6,6 +6,7 @@ import Criterion.Main (bench, bgroup, defaultMain, nf, whnf)
66import Data.Bits (unsafeShiftL)
77import Data.ByteString.Internal (ByteString(..))
88import Data.Char
9+import Data.Scientific (Scientific(..))
910import Data.Word (Word32)
1011import Text.Parsec.Text ()
1112import Text.Parsec.Text.Lazy ()
@@ -96,16 +97,19 @@ main = do
9697 [ bench "double" $ nf (AT.parseOnly AT.double) tN
9798 , bench "number" $ nf (AT.parseOnly AT.number) tN
9899 , bench "rational" $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational)) tN
100+ , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tN
99101 ]
100102 , bgroup "positive power"
101103 [ bench "double" $ nf (AT.parseOnly AT.double) tNePos
102104 , bench "number" $ nf (AT.parseOnly AT.number) tNePos
103105 , bench "rational" $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational)) tNePos
106+ , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tNePos
104107 ]
105108 , bgroup "negative power"
106109 [ bench "double" $ nf (AT.parseOnly AT.double) tNeNeg
107110 , bench "number" $ nf (AT.parseOnly AT.number) tNeNeg
108111 , bench "rational" $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational)) tNeNeg
112+ , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tNeNeg
109113 ]
110114 ]
111115 , let !bN = BC.pack strN
@@ -116,16 +120,19 @@ main = do
116120 [ bench "double" $ nf (AC.parseOnly AC.double) bN
117121 , bench "number" $ nf (AC.parseOnly AC.number) bN
118122 , bench "rational" $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational)) bN
123+ , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bN
119124 ]
120125 , bgroup "positive power"
121126 [ bench "double" $ nf (AC.parseOnly AC.double) bNePos
122127 , bench "number" $ nf (AC.parseOnly AC.number) bNePos
123128 , bench "rational" $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational)) bNePos
129+ , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bNePos
124130 ]
125131 , bgroup "negative power"
126132 [ bench "double" $ nf (AC.parseOnly AC.double) bNeNeg
127133 , bench "number" $ nf (AC.parseOnly AC.number) bNeNeg
128134 , bench "rational" $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational)) bNeNeg
135+ , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bNeNeg
129136 ]
130137 ]
131138 ]
benchmarks/attoparsec-benchmarks.cabal+1
@@ -17,4 +17,5 @@ executable attoparsec-benchmarks
1717 criterion >= 0.5,
1818 deepseq >= 1.1,
1919 parsec >= 3.1.2,
20+ scientific,
2021 text