@@ -1,8 +1,4 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
4−{-# LANGUAGE DeriveDataTypeable #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE PatternGuards #-}
2{-# LANGUAGE PatternGuards #-}
7{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
@@ -66,37 +62,27 @@ import Data.Aeson
66import Data.Aeson.Types (Pair, parseMaybe, parseEither, Parser)
62import Data.Aeson.Types (Pair, parseMaybe, parseEither, Parser)
67import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile)
63import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile)
68import Data.ByteString (ByteString)
64import Data.ByteString (ByteString)
69−import qualified Data.Map as Map
70import System.IO.Unsafe (unsafePerformIO)
65import System.IO.Unsafe (unsafePerformIO)
71−import Control.Exception (try, throwIO, fromException, Exception, SomeException, AsyncException)
66+import Control.Exception
72−import Control.Monad.Trans.State
73import qualified Data.Conduit as C
67import qualified Data.Conduit as C
74import qualified Data.Conduit.List as CL
68import qualified Data.Conduit.List as CL
75−import Control.Monad.Trans.Class (MonadTrans, lift)
76−import Control.Monad.IO.Class (MonadIO, liftIO)
77−import Control.Monad (liftM, ap)
78−import Control.Applicative (Applicative(..))
79−import Data.Char (toUpper)
80import qualified Data.Vector as V
69import qualified Data.Vector as V
81−import Data.Text (Text, pack)
70+import Data.Text (Text)
82import qualified Data.Text as T
71import qualified Data.Text as T
83−import Data.Text.Encoding (encodeUtf8, decodeUtf8With)
72+import Data.Text.Encoding (encodeUtf8)
84−import Data.Text.Encoding.Error (lenientDecode)
85import qualified Data.HashMap.Strict as M
73import qualified Data.HashMap.Strict as M
87import qualified Data.HashSet as HashSet
74import qualified Data.HashSet as HashSet
89#if MIN_VERSION_aeson(0, 7, 0)
75#if MIN_VERSION_aeson(0, 7, 0)
90−import Data.Scientific (fromFloatDigits)
91import qualified Data.Text.Encoding as TE
76import qualified Data.Text.Encoding as TE
92import qualified Data.Text.Lazy as TL
77import qualified Data.Text.Lazy as TL
93import Data.Text.Lazy.Builder (toLazyText)
78import Data.Text.Lazy.Builder (toLazyText)
94import Data.Aeson.Encode (encodeToTextBuilder)
79import Data.Aeson.Encode (encodeToTextBuilder)
96−import Data.Attoparsec.Number
97import qualified Data.ByteString.Char8 as S8
81import qualified Data.ByteString.Char8 as S8
99−import Control.Monad.Trans.Resource (ResourceT, runResourceT)
83+import Control.Monad.Trans.Resource (runResourceT)
85+import Data.Yaml.Internal
101encode :: ToJSON a => a -> ByteString
87encode :: ToJSON a => a -> ByteString
102encode obj = unsafePerformIO $
88encode obj = unsafePerformIO $
@@ -172,164 +158,12 @@ isNumeric =
172 || c == '.'
158 || c == '.'
173 || c == '-'
159 || c == '-'
177−data ParseException = NonScalarKey
178− | UnknownAlias { _anchorName :: Y.AnchorName }
179− | UnexpectedEvent { _received :: Maybe Event
180− , _expected :: Maybe Event
182− | InvalidYaml (Maybe YamlException)
183− | AesonException String
184− | OtherParseException SomeException
185− | NonStringKeyAlias Y.AnchorName Value
187− deriving (Show, Typeable)
188−instance Exception ParseException
190−newtype PErrorT m a = PErrorT { runPErrorT :: m (Either ParseException a) }
191−instance Monad m => Functor (PErrorT m) where
193−instance Monad m => Applicative (PErrorT m) where
196−instance Monad m => Monad (PErrorT m) where
197− return = PErrorT . return . Right
198− (PErrorT m) >>= f = PErrorT $ do
201− Left e' -> return $ Left e'
202− Right a -> runPErrorT $ f a
203−instance MonadTrans PErrorT where
204− lift = PErrorT . liftM Right
205−instance MonadIO m => MonadIO (PErrorT m) where
206− liftIO = lift . liftIO
208−type Parse = StateT (Map.Map String Value) (ResourceT IO)
210−requireEvent :: Event -> C.Sink Event Parse ()
215− else liftIO $ throwIO $ UnexpectedEvent f $ Just e
217−parse :: C.Sink Event Parse Value
219− requireEvent EventStreamStart
220− requireEvent EventDocumentStart
222− requireEvent EventDocumentEnd
223− requireEvent EventStreamEnd
226−parseScalar :: ByteString -> Anchor -> Style -> Tag
227− -> C.Sink Event Parse Text
228−parseScalar v a style tag = do
229− let res = decodeUtf8With lenientDecode v
231− Nothing -> return res
233− lift $ modify (Map.insert an $ textToValue style tag res)
236−textToValue :: Style -> Tag -> Text -> Value
237−textToValue SingleQuoted _ t = String t
238−textToValue DoubleQuoted _ t = String t
239−textToValue _ StrTag t = String t
240−textToValue Folded _ t = String t
242− | t `elem` ["null", "Null", "NULL", "~", ""] = Null
243− | any (t `isLike`) ["y", "yes", "on", "true"] = Bool True
244− | any (t `isLike`) ["n", "no", "off", "false"] = Bool False
245−#if MIN_VERSION_aeson(0, 7, 0)
246− | Right (x, "") <- signed decimal t = Number $ fromIntegral (x :: Integer)
247− | Right (x, "") <- double t = Number $ fromFloatDigits x
249− | Right (x, "") <- signed decimal t = Number $ I x
250− | Right (x, "") <- double t = Number $ D x
252− | otherwise = String t
253− where x `isLike` ref = x `elem` [ref, T.toUpper ref, titleCased]
254− where titleCased = toUpper (T.head ref) `T.cons` T.tail ref
257−parseO :: C.Sink Event Parse Value
261− Just (EventScalar v tag style a) -> fmap (textToValue style tag) $ parseScalar v a style tag
262− Just (EventSequenceStart a) -> parseS a id
263− Just (EventMappingStart a) -> parseM a M.empty
264− Just (EventAlias an) -> do
266− case Map.lookup an m of
267− Nothing -> liftIO $ throwIO $ UnknownAlias an
269− _ -> liftIO $ throwIO $ UnexpectedEvent me Nothing
272− -> ([Value] -> [Value])
273− -> C.Sink Event Parse Value
277− Just EventSequenceEnd -> do
279− let res = Array $ V.fromList $ front []
281− Nothing -> return res
283− lift $ modify $ Map.insert an res
287− parseS a $ front . (:) o
290− -> M.HashMap Text Value
291− -> C.Sink Event Parse Value
295− Just EventMappingEnd -> do
297− let res = Object front
299− Nothing -> return res
301− lift $ modify $ Map.insert an res
306− Just (EventScalar v tag style a') -> parseScalar v a' style tag
307− Just (EventAlias an) -> do
309− case Map.lookup an m of
310− Nothing -> liftIO $ throwIO $ UnknownAlias an
311− Just (String t) -> return t
312− Just v -> liftIO $ throwIO $ NonStringKeyAlias an v
313− _ -> liftIO $ throwIO $ UnexpectedEvent me Nothing
316− let al = M.insert s o front
317− al' = if s == pack "<<"
319− Object l -> M.union front l
320− Array l -> M.union front $ foldl merge' M.empty $ V.toList l
324− where merge' al (Object om) = M.union al om
327decode :: FromJSON a
161decode :: FromJSON a
328 => ByteString
162 => ByteString
329 -> Maybe a
163 -> Maybe a
330decode bs = unsafePerformIO
164decode bs = unsafePerformIO
331− $ fmap (either (const Nothing) (either (const Nothing) Just))
165+ $ fmap (either (const Nothing) id)
332− $ decodeHelper (Y.decode bs)
166+ $ decodeHelper_ (Y.decode bs)
334decodeFile :: FromJSON a
168decodeFile :: FromJSON a
335 => FilePath
169 => FilePath
@@ -343,24 +177,7 @@ decodeFileEither
343 :: FromJSON a
177 :: FromJSON a
344 => FilePath
178 => FilePath
345 -> IO (Either ParseException a)
179 -> IO (Either ParseException a)
346−decodeFileEither fp = do
180+decodeFileEither = decodeHelper_ . Y.decodeFile
347− x <- try $ runResourceT $ flip evalStateT Map.empty $ Y.decodeFile fp C.$$ parse
350− | Just pe <- fromException e -> return $ Left pe
351− | Just ye <- fromException e -> return $ Left $ InvalidYaml $ Just (ye :: YamlException)
352− | shouldBeCaught e -> return $ Left $ OtherParseException e
353− | otherwise -> throwIO e
355− return $ case parseEither parseJSON y of
356− Left s -> Left $ AesonException s
359− -- FIXME this function needs more thought
361− | Just (_ :: AsyncException) <- fromException e = False
362− -- Would be nice... | Just (_ :: Timeout) <- fromException e = False
365decodeEither :: FromJSON a => ByteString -> Either String a
182decodeEither :: FromJSON a => ByteString -> Either String a
366decodeEither bs = unsafePerformIO
183decodeEither bs = unsafePerformIO
@@ -376,18 +193,6 @@ decodeEither' = either Left (either (Left . AesonException) Right)
376 . decodeHelper
193 . decodeHelper
377 . Y.decode
194 . Y.decode
379−decodeHelper :: FromJSON a
380− => C.Source Parse Y.Event
381− -> IO (Either ParseException (Either String a))
382−decodeHelper src = do
383− x <- try $ runResourceT $ flip evalStateT Map.empty $ src C.$$ parse
386− | Just pe <- fromException e -> return $ Left pe
387− | Just ye <- fromException e -> return $ Left $ InvalidYaml $ Just (ye :: YamlException)
388− | otherwise -> throwIO e
389− Right y -> return $ Right $ parseEither parseJSON y
391array :: [Value] -> Value
196array :: [Value] -> Value
392array = Array . V.fromList
197array = Array . V.fromList