@@ -0,0 +1,186 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+module Data.Yaml.Parser where
6+import Control.Applicative ((<$>), Applicative (..), Alternative (..))
7+import Data.Monoid (Monoid (..))
8+import Control.Monad (MonadPlus (..), liftM, ap)
9+import Control.Monad.Trans.Writer.Strict (tell, WriterT)
10+import Control.Monad.Trans.Class (lift)
11+import qualified Data.Map as Map
13+import Data.Conduit.Lift (runWriterSC)
14+import Data.Text (Text, pack, unpack)
15+import Data.Text.Encoding (decodeUtf8)
16+import Data.ByteString (ByteString)
17+import Control.Exception (Exception)
18+import Data.Typeable (Typeable)
19+import Data.Text.Read (signed, decimal)
21+newtype YamlParser a = YamlParser
22+ { unYamlParser :: AnchorMap -> Either Text a
24+instance Functor YamlParser where
26+instance Applicative YamlParser where
29+instance Alternative YamlParser where
32+instance Monoid (YamlParser a) where
33+ mempty = fail "mempty"
35+instance Monad YamlParser where
36+ return = YamlParser . const . Right
37+ YamlParser f >>= g = YamlParser $ \am ->
40+ Right x -> unYamlParser (g x) am
41+ fail = YamlParser . const . Left . pack
42+instance MonadPlus YamlParser where
44+ mplus a b = YamlParser $ \am ->
45+ case unYamlParser a am of
46+ Left _ -> unYamlParser b am
49+lookupAnchor :: AnchorName -> YamlParser (Maybe YamlValue)
50+lookupAnchor name = YamlParser $ Right . Map.lookup name
52+withAnchor :: AnchorName -> Text -> (YamlValue -> YamlParser a) -> YamlParser a
53+withAnchor name expected f = do
54+ mv <- lookupAnchor name
56+ Nothing -> fail $ unpack expected ++ ": unknown alias " ++ name
59+withMapping :: Text -> ([(Text, YamlValue)] -> YamlParser a) -> YamlValue -> YamlParser a
60+withMapping _ f (Mapping m _) = f m
61+withMapping expected f (Alias an) = withAnchor an expected $ withMapping expected f
62+withMapping expected _ v = typeMismatch expected v
64+withSequence :: Text -> ([YamlValue] -> YamlParser a) -> YamlValue -> YamlParser a
65+withSequence _ f (Sequence s _) = f s
66+withSequence expected f (Alias an) = withAnchor an expected $ withSequence expected f
67+withSequence expected _ v = typeMismatch expected v
69+withText :: Text -> (Text -> YamlParser a) -> YamlValue -> YamlParser a
70+withText _ f (Scalar s _ _ _) = f $ decodeUtf8 s
71+withText expected f (Alias an) = withAnchor an expected $ withText expected f
72+withText expected _ v = typeMismatch expected v
74+typeMismatch :: Text -> YamlValue -> YamlParser a
75+typeMismatch expected v =
84+ Mapping _ _ -> "mapping"
85+ Sequence _ _ -> "sequence"
86+ Scalar _ _ _ _ -> "scalar"
89+class FromYaml a where
90+ fromYaml :: YamlValue -> YamlParser a
91+instance FromYaml YamlValue where
93+instance FromYaml a => FromYaml [a] where
94+ fromYaml = withSequence "[a]" (mapM fromYaml)
95+instance FromYaml Text where
96+ fromYaml = withText "Text" return
97+instance FromYaml Int where
102+ case signed decimal t of
103+ Right (i, "") -> return i
104+ _ -> fail $ "Invalid Int: " ++ unpack t
107+ = Mapping [(Text, YamlValue)] Anchor
108+ | Sequence [YamlValue] Anchor
109+ | Scalar ByteString Tag Style Anchor
113+type AnchorMap = Map.Map AnchorName YamlValue
114+data RawDoc = RawDoc YamlValue AnchorMap
117+parseRawDoc :: (FromYaml a, MonadThrow m) => RawDoc -> m a
118+parseRawDoc (RawDoc val am) =
119+ case unYamlParser (fromYaml val) am of
120+ Left t -> monadThrow $ FromYamlException t
123+(.:) :: FromYaml a => [(Text, YamlValue)] -> Text -> YamlParser a
126+ Nothing -> fail $ "Key not found: " ++ unpack k
127+ Just v -> fromYaml v
129+data YamlParseException
130+ = UnexpectedEndOfEvents
131+ | UnexpectedEvent Event
132+ | FromYamlException Text
133+ deriving (Show, Typeable)
134+instance Exception YamlParseException
136+sinkValue :: MonadThrow m => Consumer Event (WriterT AnchorMap m) YamlValue
140+ start = await >>= maybe (monadThrow UnexpectedEndOfEvents) go
142+ tell' Nothing val = return val
143+ tell' (Just name) val = do
144+ lift $ tell $ Map.singleton name val
147+ go EventStreamStart = start
148+ go EventDocumentStart = start
149+ go (EventAlias a) = return $ Alias a
150+ go (EventScalar a b c d) = tell' d $ Scalar a b c d
151+ go (EventSequenceStart mname) = do
153+ let val = Sequence vals mname
155+ go (EventMappingStart mname) = do
157+ let val = Mapping pairs mname
160+ go e = monadThrow $ UnexpectedEvent e
165+ Nothing -> monadThrow UnexpectedEndOfEvents
166+ Just EventSequenceEnd -> return $ front []
169+ goS (front . (val:))
174+ Nothing -> monadThrow UnexpectedEndOfEvents
175+ Just EventMappingEnd -> return $ front []
176+ Just (EventScalar a b c d) -> do
177+ _ <- tell' d $ Scalar a b c d
178+ let k = decodeUtf8 a
180+ goM (front . ((k, v):))
182+sinkRawDoc :: MonadThrow m => Consumer Event m RawDoc
183+sinkRawDoc = uncurry RawDoc <$> runWriterSC sinkValue
185+readYamlFile :: FromYaml a => FilePath -> IO a
186+readYamlFile fp = runResourceT (decodeFile fp $$ sinkRawDoc) >>= parseRawDoc