on 88ad126 help sign in
Data/Aeson/Parser/Internal.hs+30−5
since splitsnapshots
unifiedsplit
@@ -59,6 +59,7 @@ import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDi
59import Data.Function (fix)
59import Data.Function (fix)
60import Data.Functor.Compat (($>))
60import Data.Functor.Compat (($>))
61import Data.Scientific (Scientific)
61import Data.Scientific (Scientific)
62+import Data.Semigroup ((<>))
62import Data.Text (Text)
63import Data.Text (Text)
63import Data.Vector (Vector)
64import Data.Vector (Vector)
64import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
65import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
@@ -67,6 +68,9 @@ import qualified Data.Attoparsec.Lazy as L
67import qualified Data.ByteString as B
68import qualified Data.ByteString as B
68import qualified Data.ByteString.Unsafe as B
69import qualified Data.ByteString.Unsafe as B
69import qualified Data.ByteString.Lazy as L
70import qualified Data.ByteString.Lazy as L
71+import qualified Data.ByteString.Lazy as BSL
72+import qualified Data.ByteString.Lazy.Char8 as C
73+import qualified Data.ByteString.Builder as B
70import qualified Data.HashMap.Strict as H
74import qualified Data.HashMap.Strict as H
71import qualified Data.Scientific as Sci
75import qualified Data.Scientific as Sci
72import Data.Aeson.Parser.Unescape (unescapeText)
76import Data.Aeson.Parser.Unescape (unescapeText)
@@ -390,14 +394,35 @@ eitherDecodeWith p to s =
390 L.Done _ v -> case to v of
394 L.Done _ v -> case to v of
391 ISuccess a -> Right a
395 ISuccess a -> Right a
392 IError path msg -> Left (path, msg)
396 IError path msg -> Left (path, msg)
393− L.Fail _ ctx msg -> Left ([], buildMsg ctx msg)
397+ L.Fail notparsed ctx msg -> Left ([], buildMsg notparsed ctx msg)
394 where
398 where
395− buildMsg :: [String] -> String -> String
399+ buildMsg :: L.ByteString -> [String] -> String -> String
396− buildMsg [] msg = msg
400+ buildMsg notYetParsed [] msg = msg ++ formatErrorLine notYetParsed
397− buildMsg (expectation:_) msg =
401+ buildMsg notYetParsed (expectation:_) msg =
398− msg ++ ". Expecting " ++ expectation
402+ msg ++ ". Expecting " ++ expectation ++ formatErrorLine notYetParsed
399{-# INLINE eitherDecodeWith #-}
403{-# INLINE eitherDecodeWith #-}
400
404
405+-- | Grab the first 100 bytes from the non parsed portion and
406+-- format to get nicer error messages
407+formatErrorLine :: L.ByteString -> String
408+formatErrorLine bs =
409+ C.unpack .
410+ -- if formatting results in empty ByteString just return that
411+ -- otherwise construct the error message with the bytestring builder
412+ (\bs' ->
413+ if BSL.null bs'
414+ then BSL.empty
415+ else
416+ B.toLazyByteString $
417+ B.stringUtf8 " at '" <> B.lazyByteString bs' <> B.stringUtf8 "'"
418+ ) .
419+ -- if newline is present cut at that position
420+ BSL.takeWhile (10 /=) .
421+ -- remove spaces, CR's, tabs, backslashes and quotes characters
422+ BSL.filter (`notElem` [9, 13, 32, 34, 47, 92]) .
423+ -- take 100 bytes
424+ BSL.take 100 $ bs
425+
401eitherDecodeStrictWith :: Parser Value -> (Value -> IResult a) -> B.ByteString
426eitherDecodeStrictWith :: Parser Value -> (Value -> IResult a) -> B.ByteString
402 -> Either (JSONPath, String) a
427 -> Either (JSONPath, String) a
403eitherDecodeStrictWith p to s =
428eitherDecodeStrictWith p to s =
tests/Instances.hs+1−1
@@ -29,7 +29,7 @@ import Data.Hashable.Time ()
29-- "System" types.
29-- "System" types.
30
30
31instance Arbitrary DotNetTime where
31instance Arbitrary DotNetTime where
32− arbitrary = DotNetTime `liftM` arbitrary
32+ arbitrary = DotNetTime `fmap` arbitrary
33 shrink = map DotNetTime . shrink . fromDotNetTime
33 shrink = map DotNetTime . shrink . fromDotNetTime
34
34
35-- | Compare timezone part only on 'timeZoneMinutes'
35-- | Compare timezone part only on 'timeZoneMinutes'