@@ -52,6 +52,7 @@ module Data.Yaml
52 -- ** Better error information
52 -- ** Better error information
53 , decodeEither
53 , decodeEither
54 , decodeEither'
54 , decodeEither'
55 -- ** More control over decoding
56 -- ** More control over decoding
56 , decodeHelper
57 , decodeHelper
@@ -68,7 +69,7 @@ import Data.ByteString (ByteString)
68import qualified Data.ByteString.Char8 as S8
69import qualified Data.ByteString.Char8 as S8
69import qualified Data.Map as Map
70import qualified Data.Map as Map
70import System.IO.Unsafe (unsafePerformIO)
71import System.IO.Unsafe (unsafePerformIO)
71−import Control.Exception (try, throwIO, fromException, Exception)
72+import Control.Exception (try, throwIO, fromException, Exception, SomeException, AsyncException)
72import Control.Monad.Trans.State
73import Control.Monad.Trans.State
73import qualified Data.Conduit as C
74import qualified Data.Conduit as C
74import qualified Data.Conduit.List as CL
75import qualified Data.Conduit.List as CL
@@ -142,6 +143,7 @@ data ParseException = NonScalarKey
143 | InvalidYaml (Maybe YamlException)
144 | InvalidYaml (Maybe YamlException)
144 | AesonException String
145 | AesonException String
146+ | OtherParseException SomeException
145 deriving (Show, Typeable)
147 deriving (Show, Typeable)
146instance Exception ParseException
148instance Exception ParseException
@@ -278,6 +280,32 @@ decodeFile :: FromJSON a
278 -> IO (Maybe a)
280 -> IO (Maybe a)
279decodeFile fp = decodeHelper (Y.decodeFile fp) >>= either throwIO (return . either (const Nothing) id)
281decodeFile fp = decodeHelper (Y.decodeFile fp) >>= either throwIO (return . either (const Nothing) id)
283+-- | A version of 'decodeFile' which should not throw runtime exceptions.
289+ -> IO (Either ParseException a)
290+decodeFileEither fp = do
291+ x <- try $ C.runResourceT $ flip evalStateT Map.empty $ Y.decodeFile fp C.$$ parse
294+ | Just pe <- fromException e -> return $ Left pe
295+ | Just ye <- fromException e -> return $ Left $ InvalidYaml $ Just (ye :: YamlException)
296+ | shouldBeCaught e -> return $ Left $ OtherParseException e
297+ | otherwise -> throwIO e
299+ return $ case parseEither parseJSON y of
300+ Left s -> Left $ AesonException s
303+ -- FIXME this function needs more thought
305+ | Just (_ :: AsyncException) <- fromException e = False
306+ -- Would be nice... | Just (_ :: Timeout) <- fromException e = False
281decodeEither :: FromJSON a => ByteString -> Either String a
309decodeEither :: FromJSON a => ByteString -> Either String a
282decodeEither bs = unsafePerformIO
310decodeEither bs = unsafePerformIO
283 $ fmap (either (Left . show) id)
311 $ fmap (either (Left . show) id)