1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE DeriveDataTypeable #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE PatternGuards #-}
7{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE OverloadedStrings #-}
17 -- * Encoding/decoding
24import qualified Text.Libyaml as Y
25import Data.Aeson (Value (..), ToJSON (..), FromJSON (..), object)
26import Data.Aeson.Types (Pair, parseMaybe)
27import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile)
28import Data.ByteString (ByteString)
29import qualified Data.ByteString.Char8 as S8
30import qualified Data.Map as Map
31import System.IO.Unsafe (unsafePerformIO)
32import Control.Exception (try, throwIO, fromException, Exception)
33import Control.Monad.Trans.State
34import qualified Data.Conduit as C
35import qualified Data.Conduit.List as CL
36import Control.Monad.Trans.Class (MonadTrans, lift)
37import Control.Monad.IO.Class (MonadIO, liftIO)
38import Control.Monad (liftM)
39import qualified Data.Vector as V
40import Data.Text (Text, pack)
41import Data.Text.Encoding (encodeUtf8, decodeUtf8With)
42import Data.Text.Encoding.Error (lenientDecode)
43import qualified Data.HashMap.Strict as M
46encode :: ToJSON a => a -> ByteString
47encode obj = unsafePerformIO $
48 C.runResourceT $ CL.sourceList (objToEvents $ toJSON obj)
51encodeFile :: ToJSON a => FilePath -> a -> IO ()
52encodeFile fp obj = C.runResourceT
53 $ CL.sourceList (objToEvents $ toJSON obj)
56objToEvents :: Value -> [Y.Event]
57objToEvents o = (:) EventStreamStart
58 . (:) EventDocumentStart
65scalarToEvent :: YamlScalar -> Event
66scalarToEvent (YamlScalar v t s) = EventScalar v t s Nothing
69objToEvents' :: Value -> [Y.Event] -> [Y.Event]
70--objToEvents' (Scalar s) rest = scalarToEvent s : rest
71objToEvents' (Array list) rest =
72 EventSequenceStart Nothing
73 : foldr ($) (EventSequenceEnd : rest) (map objToEvents' $ V.toList list)
74objToEvents' (Object pairs) rest =
75 EventMappingStart Nothing
76 : foldr ($) (EventMappingEnd : rest) (map pairToEvents $ M.toList pairs)
77objToEvents' (String s) rest = EventScalar (encodeUtf8 s) NoTag Any Nothing : rest
78objToEvents' Null rest = EventScalar "null" NoTag Literal Nothing : rest
79objToEvents' (Bool True) rest = EventScalar "true" NoTag Literal Nothing : rest
80objToEvents' (Bool False) rest = EventScalar "false" NoTag Literal Nothing : rest
81objToEvents' (Number n) rest = EventScalar (S8.pack $ show n) NoTag Literal Nothing : rest
83pairToEvents :: Pair -> [Y.Event] -> [Y.Event]
84pairToEvents (k, v) rest =
85 EventScalar (encodeUtf8 k) NoTag Any Nothing
90data ParseException = NonScalarKey
91 | UnknownAlias { _anchorName :: Y.AnchorName }
92 | UnexpectedEvent { _received :: Maybe Event
93 , _expected :: Maybe Event
95 | InvalidYaml (Maybe String)
96 deriving (Show, Typeable)
97instance Exception ParseException
99newtype PErrorT m a = PErrorT { runPErrorT :: m (Either ParseException a) }
100instance Monad m => Monad (PErrorT m) where
101 return = PErrorT . return . Right
102 (PErrorT m) >>= f = PErrorT $ do
105 Left e' -> return $ Left e'
106 Right a -> runPErrorT $ f a
107instance MonadTrans PErrorT where
108 lift = PErrorT . liftM Right
109instance MonadIO m => MonadIO (PErrorT m) where
110 liftIO = lift . liftIO
112type Parser = StateT (Map.Map String Value) IO
114requireEvent :: Event -> C.Sink Event Parser ()
119 else liftIO $ throwIO $ UnexpectedEvent f $ Just e
121parse :: C.Sink Event Parser Value
123 requireEvent EventStreamStart
124 requireEvent EventDocumentStart
126 requireEvent EventDocumentEnd
127 requireEvent EventStreamEnd
130parseScalar :: ByteString -> Anchor
131 -> C.Sink Event Parser Text
133 let res = decodeUtf8With lenientDecode v
135 Nothing -> return res
137 lift $ modify (Map.insert an $ String res)
140parseO :: C.Sink Event Parser Value
144 Just (EventScalar v _t _s a) -> fmap String $ parseScalar v a
145 Just (EventSequenceStart a) -> parseS a id
146 Just (EventMappingStart a) -> parseM a M.empty
147 Just (EventAlias an) -> do
149 case Map.lookup an m of
150 Nothing -> liftIO $ throwIO $ UnknownAlias an
152 _ -> liftIO $ throwIO $ UnexpectedEvent me Nothing
155 -> ([Value] -> [Value])
156 -> C.Sink Event Parser Value
160 Just EventSequenceEnd -> do
162 let res = Array $ V.fromList $ front []
164 Nothing -> return res
166 lift $ modify $ Map.insert an res
170 parseS a $ front . (:) o
173 -> M.HashMap Text Value
174 -> C.Sink Event Parser Value
178 Just EventMappingEnd -> do
180 let res = Object front
182 Nothing -> return res
184 lift $ modify $ Map.insert an res
189 Just (EventScalar v _ _ a') -> parseScalar v a'
190 _ -> liftIO $ throwIO $ UnexpectedEvent me Nothing
193 let al = M.insert s o front
194 al' = if s == pack "<<"
196 Object l -> M.union al l
197 Array l -> M.union al $ foldl merge' M.empty $ V.toList l
200 parseM a $ M.insert s o al'
201 where merge' al (Object om) = M.union al om
207decode bs = unsafePerformIO $ fmap (either (const Nothing) id) $ decodeHelper (Y.decode bs)
209decodeFile :: FromJSON a
212decodeFile fp = decodeHelper (Y.decodeFile fp) >>= either throwIO return
214decodeHelper :: FromJSON a
215 => C.Source Parser Y.Event
216 -> IO (Either ParseException (Maybe a))
218 x <- try $ flip evalStateT Map.empty $ C.runResourceT $ src C.$$ parse
221 | Just pe <- fromException e -> return $ Left pe
222 | Just ye <- fromException e -> return $ Left $ InvalidYaml $ Just $ show (ye :: YamlException)
223 | otherwise -> throwIO e
224 Right y -> return $ Right $ parseMaybe parseJSON y
226array :: [Value] -> Value
227array = Array . V.fromList
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list