@@ -34,7 +34,8 @@ module Data.Aeson.Types.Internal
34 , emptyObject
34 , emptyObject
36 -- * Type conversion
36 -- * Type conversion
37− , Parser
37+ , Parser (Parser)
38 , Result(..)
39 , Result(..)
39 , IResult(..)
40 , IResult(..)
40 , JSONPathElement(..)
41 , JSONPathElement(..)
@@ -46,7 +47,9 @@ module Data.Aeson.Types.Internal
46 , modifyFailure
47 , modifyFailure
47 , parserThrowError
48 , parserThrowError
48 , parserCatchError
49 , parserCatchError
49 , formatError
51 , formatError
51 -- * Constructors and accessors
54 -- * Constructors and accessors
@@ -87,6 +90,7 @@ import Data.Foldable (foldl')
87import Data.HashMap.Strict (HashMap)
90import Data.HashMap.Strict (HashMap)
88import Data.Hashable (Hashable(..))
91import Data.Hashable (Hashable(..))
89import Data.List (intercalate)
92import Data.List (intercalate)
93+import Data.List.NonEmpty (NonEmpty((:|)))
90import Data.Scientific (Scientific)
94import Data.Scientific (Scientific)
91import Data.Semigroup (Semigroup((<>)))
95import Data.Semigroup (Semigroup((<>)))
92import Data.String (IsString(..))
96import Data.String (IsString(..))
@@ -98,6 +102,7 @@ import Data.Vector (Vector)
98import GHC.Generics (Generic)
102import GHC.Generics (Generic)
99import qualified Control.Monad.Fail as Fail
103import qualified Control.Monad.Fail as Fail
100import qualified Data.HashMap.Strict as H
104import qualified Data.HashMap.Strict as H
105+import qualified Data.List.NonEmpty as NonEmpty
101import qualified Data.Scientific as S
106import qualified Data.Scientific as S
102import qualified Data.Vector as V
107import qualified Data.Vector as V
103import qualified Language.Haskell.TH.Syntax as TH
108import qualified Language.Haskell.TH.Syntax as TH
@@ -118,7 +123,7 @@ data JSONPathElement = Key Text
118type JSONPath = [JSONPathElement]
123type JSONPath = [JSONPathElement]
120-- | The internal result of running a 'Parser'.
125-- | The internal result of running a 'Parser'.
121−data IResult a = IError JSONPath String
126+data IResult a = IError (NonEmpty (JSONPath, String))
122 | ISuccess a
127 | ISuccess a
123 deriving (Eq, Show, Typeable)
128 deriving (Eq, Show, Typeable)
@@ -133,15 +138,15 @@ instance NFData JSONPathElement where
134instance (NFData a) => NFData (IResult a) where
139instance (NFData a) => NFData (IResult a) where
135 rnf (ISuccess a) = rnf a
140 rnf (ISuccess a) = rnf a
136− rnf (IError path err) = rnf path `seq` rnf err
141+ rnf (IError err) = rnf err
138instance (NFData a) => NFData (Result a) where
143instance (NFData a) => NFData (Result a) where
139 rnf (Success a) = rnf a
144 rnf (Success a) = rnf a
140 rnf (Error err) = rnf err
145 rnf (Error err) = rnf err
142instance Functor IResult where
147instance Functor IResult where
143− fmap f (ISuccess a) = ISuccess (f a)
148+ fmap f (ISuccess a) = ISuccess (f a)
144− fmap _ (IError path err) = IError path err
149+ fmap _ (IError err) = IError err
145 {-# INLINE fmap #-}
150 {-# INLINE fmap #-}
147instance Functor Result where
152instance Functor Result where
@@ -153,15 +158,15 @@ instance Monad IResult where
153 return = pure
158 return = pure
154 {-# INLINE return #-}
159 {-# INLINE return #-}
156− ISuccess a >>= k = k a
161+ ISuccess a >>= k = k a
157− IError path err >>= _ = IError path err
162+ IError err >>= _ = IError err
158 {-# INLINE (>>=) #-}
163 {-# INLINE (>>=) #-}
160 fail = Fail.fail
165 fail = Fail.fail
161 {-# INLINE fail #-}
166 {-# INLINE fail #-}
163instance Fail.MonadFail IResult where
168instance Fail.MonadFail IResult where
164− fail err = IError [] err
169+ fail err = IError (([], err) :| [])
165 {-# INLINE fail #-}
170 {-# INLINE fail #-}
167instance Monad Result where
172instance Monad Result where
@@ -238,11 +243,11 @@ instance Monoid (Result a) where
238 {-# INLINE mappend #-}
243 {-# INLINE mappend #-}
240instance Foldable IResult where
245instance Foldable IResult where
241− foldMap _ (IError _ _) = mempty
246+ foldMap _ (IError _) = mempty
242 foldMap f (ISuccess y) = f y
247 foldMap f (ISuccess y) = f y
243 {-# INLINE foldMap #-}
248 {-# INLINE foldMap #-}
245− foldr _ z (IError _ _) = z
250+ foldr _ z (IError _) = z
246 foldr f z (ISuccess y) = f y z
251 foldr f z (ISuccess y) = f y z
247 {-# INLINE foldr #-}
252 {-# INLINE foldr #-}
@@ -256,8 +261,8 @@ instance Foldable Result where
256 {-# INLINE foldr #-}
261 {-# INLINE foldr #-}
258instance Traversable IResult where
263instance Traversable IResult where
259− traverse _ (IError path err) = pure (IError path err)
264+ traverse _ (IError err) = pure (IError err)
260− traverse f (ISuccess a) = ISuccess <$> f a
265+ traverse f (ISuccess a) = ISuccess <$> f a
261 {-# INLINE traverse #-}
266 {-# INLINE traverse #-}
263instance Traversable Result where
268instance Traversable Result where
@@ -266,7 +271,7 @@ instance Traversable Result where
266 {-# INLINE traverse #-}
271 {-# INLINE traverse #-}
268-- | Failure continuation.
273-- | Failure continuation.
269−type Failure f r = JSONPath -> String -> f r
274+type Failure f r = NonEmpty (JSONPath, String) -> f r
270-- | Success continuation.
275-- | Success continuation.
271type Success a f r = a -> f r
276type Success a f r = a -> f r
@@ -289,7 +294,7 @@ instance Monad Parser where
289 {-# INLINE fail #-}
294 {-# INLINE fail #-}
291instance Fail.MonadFail Parser where
296instance Fail.MonadFail Parser where
292− fail msg = Parser $ \path kf _ks -> kf (reverse path) msg
297+ fail msg = Parser $ \path kf _ks -> kf ((reverse path, msg) :| [])
293 {-# INLINE fail #-}
298 {-# INLINE fail #-}
295instance Functor Parser where
300instance Functor Parser where
@@ -309,10 +314,11 @@ instance Alternative Parser where
309 (<|>) = mplus
314 (<|>) = mplus
310 {-# INLINE (<|>) #-}
315 {-# INLINE (<|>) #-}
317+{- TODO accumulate errors -}
312instance MonadPlus Parser where
318instance MonadPlus Parser where
313 mzero = fail "mzero"
319 mzero = fail "mzero"
314 {-# INLINE mzero #-}
320 {-# INLINE mzero #-}
315− mplus a b = Parser $ \path kf ks -> let kf' _ _ = runParser b path kf ks
321+ mplus a b = Parser $ \path kf ks -> let kf' _ = runParser b path kf ks
316 in runParser a path kf' ks
322 in runParser a path kf' ks
317 {-# INLINE mplus #-}
323 {-# INLINE mplus #-}
@@ -423,7 +429,7 @@ emptyObject = Object H.empty
424-- | Run a 'Parser'.
430-- | Run a 'Parser'.
425parse :: (a -> Parser b) -> a -> Result b
431parse :: (a -> Parser b) -> a -> Result b
426−parse m v = runParser (m v) [] (const Error) Success
432+parse m v = runParser (m v) [] (Error . snd . NonEmpty.head) Success
427{-# INLINE parse #-}
433{-# INLINE parse #-}
429-- | Run a 'Parser'.
435-- | Run a 'Parser'.
@@ -433,14 +439,14 @@ iparse m v = runParser (m v) [] IError ISuccess
434-- | Run a 'Parser' with a 'Maybe' result type.
440-- | Run a 'Parser' with a 'Maybe' result type.
435parseMaybe :: (a -> Parser b) -> a -> Maybe b
441parseMaybe :: (a -> Parser b) -> a -> Maybe b
436−parseMaybe m v = runParser (m v) [] (\_ _ -> Nothing) Just
442+parseMaybe m v = runParser (m v) [] (const Nothing) Just
437{-# INLINE parseMaybe #-}
443{-# INLINE parseMaybe #-}
439-- | Run a 'Parser' with an 'Either' result type. If the parse fails,
445-- | Run a 'Parser' with an 'Either' result type. If the parse fails,
440-- the 'Left' payload will contain an error message.
446-- the 'Left' payload will contain an error message.
441parseEither :: (a -> Parser b) -> a -> Either String b
447parseEither :: (a -> Parser b) -> a -> Either String b
442parseEither m v = runParser (m v) [] onError Right
448parseEither m v = runParser (m v) [] onError Right
443− where onError path msg = Left (formatError path msg)
449+ where onError ((path, err) :| _) = Left (formatError path err)
444{-# INLINE parseEither #-}
450{-# INLINE parseEither #-}
446-- | Annotate an error message with a
452-- | Annotate an error message with a
@@ -471,6 +477,10 @@ formatError path msg = "Error in " ++ format "$" path ++ ": " ++ msg
471 escapeChar '\\' = "\\\\"
477 escapeChar '\\' = "\\\\"
472 escapeChar c = [c]
478 escapeChar c = [c]
480+-- | Annotate a list of error messages.
481+formatErrors :: Functor f => f (JSONPath, String) -> f String
482+formatErrors = fmap (uncurry formatError)
474-- | A key\/value pair for an 'Object'.
484-- | A key\/value pair for an 'Object'.
475type Pair = (Text, Value)
485type Pair = (Text, Value)
@@ -510,21 +520,26 @@ p <?> pathElem = Parser $ \path kf ks -> runParser p (pathElem:path) kf ks
510-- Since 0.6.2.0
520-- Since 0.6.2.0
511modifyFailure :: (String -> String) -> Parser a -> Parser a
521modifyFailure :: (String -> String) -> Parser a -> Parser a
512modifyFailure f (Parser p) = Parser $ \path kf ks ->
522modifyFailure f (Parser p) = Parser $ \path kf ks ->
513− p path (\p' m -> kf p' (f m)) ks
523+ p path (\m -> kf ((fmap . fmap) f m)) ks
515-- | Throw a parser error with an additional path.
525-- | Throw a parser error with an additional path.
517-- @since 1.2.1.0
527-- @since 1.2.1.0
518parserThrowError :: JSONPath -> String -> Parser a
528parserThrowError :: JSONPath -> String -> Parser a
519parserThrowError path' msg = Parser $ \path kf _ks ->
529parserThrowError path' msg = Parser $ \path kf _ks ->
520− kf (reverse path ++ path') msg
530+ kf ((reverse path ++ path', msg) :| [])
522-- | A handler function to handle previous errors and return to normal execution.
532-- | A handler function to handle previous errors and return to normal execution.
524-- @since 1.2.1.0
534-- @since 1.2.1.0
525parserCatchError :: Parser a -> (JSONPath -> String -> Parser a) -> Parser a
535parserCatchError :: Parser a -> (JSONPath -> String -> Parser a) -> Parser a
536+parserCatchError p handler = parserCatchErrors p (\((e, msg) :| _) -> handler e msg)
538+-- | A handler function to handle multiple previous errors and return to normal
540+parserCatchErrors :: Parser a -> (NonEmpty (JSONPath, String) -> Parser a) -> Parser a
526−parserCatchError (Parser p) handler = Parser $ \path kf ks ->
541+parserCatchErrors (Parser p) handler = Parser $ \path kf ks ->
527− p path (\e msg -> runParser (handler e msg) path kf ks) ks
542+ p path (\es -> runParser (handler es) path kf ks) ks
529--------------------------------------------------------------------------------
544--------------------------------------------------------------------------------
530-- Generic and TH encoding configuration
545-- Generic and TH encoding configuration