on master help sign in
Merge pull request #68 from bitonic/fix-number-parsing
eb8b0c7Michael Snoyman
Data/Yaml/Internal.hs+8−4
@@ -37,10 +37,11 @@ import Data.Text.Encoding (decodeUtf8With)
37import Data.Text.Encoding.Error (lenientDecode)
37import Data.Text.Encoding.Error (lenientDecode)
38import qualified Data.HashMap.Strict as M
38import qualified Data.HashMap.Strict as M
39import Data.Typeable
39import Data.Typeable
40−import Data.Text.Read
41#if MIN_VERSION_aeson(0, 7, 0)
40#if MIN_VERSION_aeson(0, 7, 0)
41+import qualified Data.Attoparsec.Text as Atto
42−import Data.Scientific (fromFloatDigits)
42+import Data.Scientific (Scientific)
43#else
43#else
44+import Data.Text.Read
44import Data.Attoparsec.Number
45import Data.Attoparsec.Number
45#endif
46#endif
46import Control.Monad.Trans.Resource (ResourceT, runResourceT)
47import Control.Monad.Trans.Resource (ResourceT, runResourceT)
@@ -162,8 +163,7 @@ textToValue _ _ t
162 | any (t `isLike`) ["y", "yes", "on", "true"] = Bool True
163 | any (t `isLike`) ["y", "yes", "on", "true"] = Bool True
163 | any (t `isLike`) ["n", "no", "off", "false"] = Bool False
164 | any (t `isLike`) ["n", "no", "off", "false"] = Bool False
164#if MIN_VERSION_aeson(0, 7, 0)
165#if MIN_VERSION_aeson(0, 7, 0)
165− | Right (x, "") <- signed decimal t = Number $ fromIntegral (x :: Integer)
166+ | Right x <- textToScientific t = Number x
166− | Right (x, "") <- double t = Number $ fromFloatDigits x
167#else
167#else
168 | Right (x, "") <- signed decimal t = Number $ I x
168 | Right (x, "") <- signed decimal t = Number $ I x
169 | Right (x, "") <- double t = Number $ D x
169 | Right (x, "") <- double t = Number $ D x
@@ -172,6 +172,10 @@ textToValue _ _ t
172 where x `isLike` ref = x `elem` [ref, T.toUpper ref, titleCased]
172 where x `isLike` ref = x `elem` [ref, T.toUpper ref, titleCased]
173 where titleCased = toUpper (T.head ref) `T.cons` T.tail ref
173 where titleCased = toUpper (T.head ref) `T.cons` T.tail ref
174
174
175+#if MIN_VERSION_aeson(0, 7, 0)
176+textToScientific :: Text -> Either String Scientific
177+textToScientific = Atto.parseOnly (Atto.scientific <* Atto.endOfInput)
178+#endif
175
179
176parseO :: C.Sink Event Parse Value
180parseO :: C.Sink Event Parse Value
177parseO = do
181parseO = do
test/Data/YamlSpec.hs+23
@@ -148,6 +148,10 @@ spec = do
148 it "serialization of +123 #64" $ do
148 it "serialization of +123 #64" $ do
149 D.decode (D.encode ("+123" :: String)) `shouldBe` Just ("+123" :: String)
149 D.decode (D.encode ("+123" :: String)) `shouldBe` Just ("+123" :: String)
150
150
151+#if MIN_VERSION_aeson(0, 7, 0)
152+ it "preserves Scientific precision" casePreservesScientificPrecision
153+#endif
154+
151
155
152specialStrings :: [T.Text]
156specialStrings :: [T.Text]
153specialStrings =
157specialStrings =
@@ -465,3 +469,22 @@ caseIssue49 =
465 ])
469 ])
466 where
470 where
467 src = "---\na:\n &id5 value: 1.0\nb:\n *id5: 1.2"
471 src = "---\na:\n &id5 value: 1.0\nb:\n *id5: 1.2"
472+
473+#if MIN_VERSION_aeson(0, 7, 0)
474+-- | We cannot guarantee this before aeson started using 'Scientific'.
475+casePreservesScientificPrecision :: Assertion
476+casePreservesScientificPrecision = do
477+ D.decodeEither "x: 1e-100000" @?= Right (object
478+ [ "x" .= D.Number (read "1e-100000") ])
479+ -- Note that this ought to work also without 'Scientific', given
480+ -- that @read (show "9.78159610558926e-5") == 9.78159610558926e-5@.
481+ -- However, it didn't work (and still doesn't work with aeson < 0.7)
482+ -- for two reasons:
483+ --
484+ -- * We use 'Data.Text.Read.double', which is not as accurate as it
485+ -- can be;
486+ -- * Even if we used 'Data.Text.Read.rational' we would not get good
487+ -- results, because of <https://github.com/bos/text/issues/34>.
488+ D.decodeEither "x: 9.78159610558926e-5" @?= Right (object
489+ [ "x" .= D.Number (read "9.78159610558926e-5") ])
490+#endif
yaml.cabal+1−1
@@ -48,7 +48,7 @@ library
48 , unordered-containers
48 , unordered-containers
49 , vector
49 , vector
50 , text
50 , text
51− , attoparsec
51+ , attoparsec >= 0.11.3.0
52 , scientific
52 , scientific
53 , filepath
53 , filepath
54 , directory
54 , directory