2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE OverloadedStrings #-}
4-- | NOTE: This module is a highly experimental preview release. It may change
5-- drastically, or be entirely removed, in a future release.
6module Data.Yaml.Parser where
8import Control.Applicative
9import Control.Exception (Exception)
10import Control.Monad (MonadPlus (..), liftM, ap)
11import Control.Monad.Trans.Class (lift)
12import Control.Monad.Trans.Resource (MonadThrow, throwM)
13import Control.Monad.Trans.Writer.Strict (tell, WriterT)
14import Data.ByteString (ByteString)
16import Data.Conduit.Lift (runWriterC)
17import qualified Data.Map as Map
18#if !MIN_VERSION_base(4,8,0)
19import Data.Monoid (Monoid (..))
21#if !MIN_VERSION_base(4,11,0)
22import Data.Semigroup (Semigroup(..))
24import Data.Text (Text, pack, unpack)
25import Data.Text.Encoding (decodeUtf8)
26import Data.Text.Read (signed, decimal)
27import Data.Typeable (Typeable)
31newtype YamlParser a = YamlParser
32 { unYamlParser :: AnchorMap -> Either Text a
34instance Functor YamlParser where
36instance Applicative YamlParser where
37 pure = YamlParser . const . Right
39instance Alternative YamlParser where
42instance Semigroup (YamlParser a) where
44instance Monoid (YamlParser a) where
45 mempty = fail "mempty"
46#if !MIN_VERSION_base(4,11,0)
49instance Monad YamlParser where
51 YamlParser f >>= g = YamlParser $ \am ->
54 Right x -> unYamlParser (g x) am
55 fail = YamlParser . const . Left . pack
56instance MonadPlus YamlParser where
58 mplus a b = YamlParser $ \am ->
59 case unYamlParser a am of
60 Left _ -> unYamlParser b am
63lookupAnchor :: AnchorName -> YamlParser (Maybe YamlValue)
64lookupAnchor name = YamlParser $ Right . Map.lookup name
66withAnchor :: AnchorName -> Text -> (YamlValue -> YamlParser a) -> YamlParser a
67withAnchor name expected f = do
68 mv <- lookupAnchor name
70 Nothing -> fail $ unpack expected ++ ": unknown alias " ++ name
73withMapping :: Text -> ([(Text, YamlValue)] -> YamlParser a) -> YamlValue -> YamlParser a
74withMapping _ f (Mapping m _) = f m
75withMapping expected f (Alias an) = withAnchor an expected $ withMapping expected f
76withMapping expected _ v = typeMismatch expected v
78withSequence :: Text -> ([YamlValue] -> YamlParser a) -> YamlValue -> YamlParser a
79withSequence _ f (Sequence s _) = f s
80withSequence expected f (Alias an) = withAnchor an expected $ withSequence expected f
81withSequence expected _ v = typeMismatch expected v
83withText :: Text -> (Text -> YamlParser a) -> YamlValue -> YamlParser a
84withText _ f (Scalar s _ _ _) = f $ decodeUtf8 s
85withText expected f (Alias an) = withAnchor an expected $ withText expected f
86withText expected _ v = typeMismatch expected v
88typeMismatch :: Text -> YamlValue -> YamlParser a
89typeMismatch expected v =
98 Mapping _ _ -> "mapping"
99 Sequence _ _ -> "sequence"
100 Scalar _ _ _ _ -> "scalar"
103class FromYaml a where
104 fromYaml :: YamlValue -> YamlParser a
105instance FromYaml YamlValue where
107instance FromYaml a => FromYaml [a] where
108 fromYaml = withSequence "[a]" (mapM fromYaml)
109instance FromYaml Text where
110 fromYaml = withText "Text" return
111instance FromYaml Int where
116 case signed decimal t of
117 Right (i, "") -> return i
118 _ -> fail $ "Invalid Int: " ++ unpack t
121 = Mapping [(Text, YamlValue)] Anchor
122 | Sequence [YamlValue] Anchor
123 | Scalar ByteString Tag Style Anchor
127type AnchorMap = Map.Map AnchorName YamlValue
128data RawDoc = RawDoc YamlValue AnchorMap
131parseRawDoc :: (FromYaml a, MonadThrow m) => RawDoc -> m a
132parseRawDoc (RawDoc val am) =
133 case unYamlParser (fromYaml val) am of
134 Left t -> throwM $ FromYamlException t
137(.:) :: FromYaml a => [(Text, YamlValue)] -> Text -> YamlParser a
140 Nothing -> fail $ "Key not found: " ++ unpack k
143data YamlParseException
144 = UnexpectedEndOfEvents
145 | UnexpectedEvent Event
146 | FromYamlException Text
147 deriving (Show, Typeable)
148instance Exception YamlParseException
150sinkValue :: MonadThrow m => ConduitM Event o (WriterT AnchorMap m) YamlValue
154 start = await >>= maybe (throwM UnexpectedEndOfEvents) go
156 tell' Nothing val = return val
157 tell' (Just name) val = do
158 lift $ tell $ Map.singleton name val
161 go EventStreamStart = start
162 go EventDocumentStart = start
163 go (EventAlias a) = return $ Alias a
164 go (EventScalar a b c d) = tell' d $ Scalar a b c d
165 go (EventSequenceStart _tag _style mname) = do
167 let val = Sequence vals mname
169 go (EventMappingStart _tag _style mname) = do
171 let val = Mapping pairs mname
174 go e = throwM $ UnexpectedEvent e
179 Nothing -> throwM UnexpectedEndOfEvents
180 Just EventSequenceEnd -> return $ front []
188 Nothing -> throwM UnexpectedEndOfEvents
189 Just EventMappingEnd -> return $ front []
190 Just (EventScalar a b c d) -> do
191 _ <- tell' d $ Scalar a b c d
194 goM (front . ((k, v):))
195 Just e -> throwM $ UnexpectedEvent e
197sinkRawDoc :: MonadThrow m => ConduitM Event o m RawDoc
198sinkRawDoc = uncurry RawDoc <$> runWriterC sinkValue
200readYamlFile :: FromYaml a => FilePath -> IO a
201readYamlFile fp = runConduitRes (decodeFile fp .| sinkRawDoc) >>= parseRawDoc
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