on master help sign in
Support hexadecimal and octal number values (fixes #135)
commit6d7187f63e3b58d375585a22507ee157c3bb4560 authorMichael Snoyman <michael@snoyman.com> dateMon 9 Jul 2018, 12:44 (8 years ago) parent5648c22
3 files changed+32−3
ChangeLog.md+1 src/Data/Yaml/Internal.hs+16−2 test/Data/YamlSpec.hs+15−1
ChangeLog.md+1
@@ -3,6 +3,7 @@
33## 0.8.32
44
55* Escape keys as necessary [#137](https://github.com/snoyberg/yaml/issues/137)
6+* Support hexadecimal and octal number values [#135](https://github.com/snoyberg/yaml/issues/135)
67* hpackify
78* src subdir
89
src/Data/Yaml/Internal.hs+16−2
@@ -11,11 +11,13 @@ module Data.Yaml.Internal
1111 , decodeHelper_
1212 , specialStrings
1313 , isNumeric
14+ , textToScientific
1415 ) where
1516
1617#if !MIN_VERSION_base(4,8,0)
1718import Control.Applicative ((<$>), Applicative(..))
1819#endif
20+import Control.Applicative ((<|>))
1921import Control.Exception
2022import Control.Monad (liftM, ap, unless)
2123import Control.Monad.IO.Class (MonadIO, liftIO)
@@ -25,8 +27,9 @@ import Control.Monad.Trans.State
2527import Data.Aeson
2628import Data.Aeson.Types hiding (parse)
2729import qualified Data.Attoparsec.Text as Atto
30+import Data.Bits (shiftL, (.|.))
2831import Data.ByteString (ByteString)
29−import Data.Char (toUpper)
32+import Data.Char (toUpper, ord)
3033import Data.Conduit ((.|), ConduitM, runConduit)
3134import qualified Data.Conduit.List as CL
3235import qualified Data.HashMap.Strict as M
@@ -176,7 +179,16 @@ textToValue _ _ t
176179 where titleCased = toUpper (T.head ref) `T.cons` T.tail ref
177180
178181textToScientific :: Text -> Either String Scientific
179−textToScientific = Atto.parseOnly (Atto.scientific <* Atto.endOfInput)
182+textToScientific = Atto.parseOnly (num <* Atto.endOfInput)
183+ where
184+ num = (fromInteger <$> ("0x" *> Atto.hexadecimal))
185+ <|> (fromInteger <$> ("0o" *> octal))
186+ <|> Atto.scientific
187+
188+ octal = T.foldl' step 0 <$> Atto.takeWhile1 isOctalDigit
189+ where
190+ isOctalDigit c = (c >= '0' && c <= '7')
191+ step a c = (a `shiftL` 3) .|. fromIntegral (ord c - 48)
180192
181193parseO :: ConduitM Event o Parse Value
182194parseO = do
@@ -291,6 +303,8 @@ isNumeric t =
291303 isNumeric' c = isNumber c
292304 || c == 'e'
293305 || c == 'E'
306+ || c == 'o'
307+ || c == 'x'
294308 || c == '.'
295309 || c == '-'
296310 || c == '+'
test/Data/YamlSpec.hs+15−1
@@ -29,8 +29,9 @@ import Data.Maybe
2929import qualified Data.HashMap.Strict as M
3030import qualified Data.Text as T
3131import Data.Aeson.TH
32+import Data.Scientific (Scientific)
3233import Data.Text (Text)
33−import Data.Text.Encoding (decodeUtf8)
34+import Data.Text.Encoding (decodeUtf8, encodeUtf8)
3435import Data.Vector (Vector)
3536import qualified Data.Vector as V
3637import Data.HashMap.Strict (HashMap)
@@ -181,6 +182,19 @@ spec = do
181182 , T.unpack text
182183 ] :: IO ()
183184
185+ describe "non-decimal numbers #135" $ do
186+ let go str val = it str $ encodeUtf8 (T.pack str) `shouldDecode` val
187+ go "12345" (12345 :: Int)
188+ go "+12345" (12345 :: Int)
189+ go "0o14" (12 :: Int)
190+ go "0o123" (83 :: Int)
191+ go "0xC" (12 :: Int)
192+ go "0xc" (12 :: Int)
193+ go "0xdeadBEEF" (3735928559 :: Int)
194+ go "0xDEADBEEF" (3735928559 :: Int)
195+ go "1.23015e+3" (1230.15 :: Scientific)
196+ go "12.3015e+02" (1230.15 :: Scientific)
197+ go "1230.15" (1230.15 :: Scientific)
184198
185199specialStrings :: [T.Text]
186200specialStrings =