on master help sign in
Converted to enumerator
commit719631676efd677b798195ba58591e61d53971b0 authorMichael Snoyman <michael@snoyman.com> dateMon 27 Sep 2010, 10:32 (16 years ago) parent19f3446
3 files changed+131−153
Text/Libyaml.hs+65−72 runtests.hs+50−63 yaml.cabal+16−18
Text/Libyaml.hs+65−72
@@ -35,19 +35,13 @@ import Foreign.ForeignPtr
3535import Foreign.Marshal.Alloc
3636import Data.Data
3737
38−#if MIN_VERSION_transformers(0,2,0)
39−import "transformers" Control.Monad.IO.Class
40−#else
41−import "transformers" Control.Monad.Trans
42−#endif
38+import Control.Monad.IO.Class
39+import Control.Monad.Trans.Class (lift)
4340
4441import Control.Exception (throwIO, Exception)
45−import Data.Iteratee
46−import qualified Data.Iteratee.Base.StreamChunk as SC
42+import Data.Enumerator
4743import Control.Applicative
48−import Control.Monad.CatchIO (MonadCatchIO, finally)
49−
50−import qualified Data.ListLike as LL
44+import "MonadCatchIO-transformers" Control.Monad.CatchIO (MonadCatchIO, finally)
5145
5246data Event =
5347 EventStreamStart
@@ -457,16 +451,13 @@ newtype ToEventRawException = ToEventRawException CInt
457451 deriving (Show, Typeable)
458452instance Exception ToEventRawException
459453
460−decode :: SC.StreamChunk c Event
461− => MonadCatchIO m
462− => B.ByteString
463− -> EnumeratorGM c Event m a
454+decode :: MonadCatchIO m => B.ByteString -> Enumerator Event m a
464455decode bs i = do
465456 fp <- liftIO $ mallocForeignPtrBytes parserSize
466457 res <- liftIO $ withForeignPtr fp c_yaml_parser_initialize
467− flip finally (liftIO $ withForeignPtr fp c_yaml_parser_delete) $
458+ a <-
468459 if (res == 0)
469− then return $ throwErr $ Err "Yaml out of memory"
460+ then throwError $ YamlException "Yaml out of memory"
470461 else do -- NOTE: can't replace the following with unsafeUseAsCString
471462 -- since it must run in a MonadIO
472463 let (fptr, offset, len) = B.toForeignPtr bs
@@ -476,47 +467,47 @@ decode bs i = do
476467 liftIO $ withForeignPtr fp $ \p ->
477468 c_yaml_parser_set_input_string p ptr' len'
478469 runParser fp i
470+ liftIO $ withForeignPtr fp c_yaml_parser_delete -- FIXME finally
471+ return a
479472
480−decodeFile :: SC.StreamChunk c Event
481− => MonadCatchIO m
482− => FilePath
483− -> EnumeratorGM c Event m a
473+-- FIXME decodeFile :: MonadCatchIO m => FilePath -> Enumerator Event m a
474+decodeFile :: FilePath -> Enumerator Event IO a
484475decodeFile file i = do
485476 fp <- liftIO $ mallocForeignPtrBytes parserSize
486477 res <- liftIO $ withForeignPtr fp c_yaml_parser_initialize
487− flip finally (liftIO $ withForeignPtr fp c_yaml_parser_delete) $
488− if (res == 0)
489− then return $ throwErr $ Err "Yaml out of memory"
478+ a <-
479+ if res == 0
480+ then throwError $ YamlException "Yaml out of memory"
490481 else do
491482 file' <- liftIO
492483 $ withCString file $ \file' -> withCString "r" $ \r' ->
493484 c_fopen file' r'
494485 if (file' == nullPtr)
495− then return $ throwErr $ Err
486+ then throwError $ YamlException
496487 $ "Yaml file not found: " ++ file
497488 else do
498489 liftIO $ withForeignPtr fp $ \p ->
499490 c_yaml_parser_set_input_file p file'
500− finally (runParser fp i) $ liftIO $ do
501− c_fclose file'
502− withForeignPtr fp c_yaml_parser_delete
503−
504−runParser :: SC.StreamChunk c Event
505− => MonadCatchIO m
491+ a <- runParser fp i
492+ -- FIXME finally
493+ liftIO $ c_fclose file'
494+ liftIO $ withForeignPtr fp c_yaml_parser_delete
495+ return a
496+ liftIO $ withForeignPtr fp c_yaml_parser_delete -- FIXME finally
497+ return a
498+
499+runParser :: MonadCatchIO m
506500 => ForeignPtr ParserStruct
507− -> IterateeG c Event m a
508− -> m (IterateeG c Event m a)
509−runParser fp iter = do
501+ -> Enumerator Event m a
502+runParser fp (Continue k) = do
510503 e <- liftIO $ withForeignPtr fp parserParseOne'
511504 case e of
512− Left err -> return $ throwErr $ Err $ show err
513− Right Nothing -> return iter
505+ Left err -> throwError $ YamlException err
506+ Right Nothing -> continue k
514507 Right (Just ev) -> do
515− igv <- runIter iter $ Chunk $ SC.fromList [ev]
516− case igv of
517− Done a _ -> return $ return a
518− Cont iter' Nothing -> runParser fp iter'
519− Cont _ (Just err) -> return $ throwErr err
508+ step' <- lift $ runIteratee $ k $ Chunks [ev]
509+ runParser fp step'
510+runParser _ step = returnI step
520511
521512parserParseOne' :: Parser
522513 -> IO (Either String (Maybe Event))
@@ -539,19 +530,18 @@ parserParseOne' parser = allocaBytes eventSize $ \er -> do
539530 ]
540531 else liftIO $ Right <$> getEvent er
541532
542−encode :: SC.StreamChunk c Event
543− => MonadIO m
544− => IterateeG c Event m B.ByteString
545−encode = joinIM $ liftIO $ do
546− fp <- mallocForeignPtrBytes emitterSize
547− res <- withForeignPtr fp c_yaml_emitter_initialize
548− when (res == 0) $ fail "c_yaml_emitter_initialize failed"
549− buf <- mallocForeignPtrBytes bufferSize
550− withForeignPtr buf c_buffer_init
551− withForeignPtr fp $
533+encode :: MonadIO m => Iteratee Event m B.ByteString
534+encode = do
535+ fp <- liftIO $ mallocForeignPtrBytes emitterSize
536+ res <- liftIO $ withForeignPtr fp c_yaml_emitter_initialize
537+ when (res == 0) $ throwError
538+ $ YamlException "c_yaml_emitter_initialize failed"
539+ buf <- liftIO $ mallocForeignPtrBytes bufferSize
540+ liftIO $ withForeignPtr buf c_buffer_init
541+ liftIO $ withForeignPtr fp $
552542 \emitter -> withForeignPtr buf $
553543 \b -> c_my_emitter_set_output emitter b
554− return $ runEmitter (go buf) fp
544+ runEmitter (go buf) fp
555545 where
556546 go buf = withForeignPtr buf $ \b -> do
557547 ptr' <- c_get_buffer_buff b
@@ -559,34 +549,37 @@ encode = joinIM $ liftIO $ do
559549 fptr <- newForeignPtr_ $ castPtr ptr'
560550 return $ B.fromForeignPtr fptr 0 $ fromIntegral len
561551
562−
563−encodeFile :: SC.StreamChunk c Event
564− => MonadIO m
552+encodeFile :: MonadIO m
565553 => FilePath
566− -> IterateeG c Event m ()
567−encodeFile filePath = joinIM $ liftIO $ do
568− fp <- mallocForeignPtrBytes emitterSize
569− res <- withForeignPtr fp c_yaml_emitter_initialize
570− when (res == 0) $ fail "c_yaml_emitter_initialize failed"
571− file <- withCString filePath $
554+ -> Iteratee Event m ()
555+encodeFile filePath = do
556+ fp <- liftIO $ mallocForeignPtrBytes emitterSize
557+ res <- liftIO $ withForeignPtr fp c_yaml_emitter_initialize
558+ when (res == 0) $ throwError
559+ $ YamlException "c_yaml_emitter_initialize failed"
560+ file <- liftIO $ withCString filePath $
572561 \filePath' -> withCString "w" $
573562 \w' -> c_fopen filePath' w'
574− when (file == nullPtr) $ fail $ "could not open file for write: " ++ filePath
575− withForeignPtr fp $ flip c_yaml_emitter_set_output_file file
576− return $ runEmitter (c_fclose file) fp
563+ when (file == nullPtr) $ throwError
564+ $ YamlException $ "could not open file for write: " ++ filePath
565+ liftIO $ withForeignPtr fp $ flip c_yaml_emitter_set_output_file file
566+ runEmitter (c_fclose file) fp
577567
578−runEmitter :: SC.StreamChunk c Event
579− => MonadIO m
568+runEmitter :: MonadIO m
580569 => IO a
581570 -> ForeignPtr EmitterStruct
582− -> IterateeG c Event m a
583−runEmitter close fp = IterateeG go
571+ -> Iteratee Event m a
572+runEmitter close fp = continue go
584573 where
585− go (EOF x) = do
574+ go EOF = do
586575 liftIO $ withForeignPtr fp c_yaml_emitter_delete
587576 a <- liftIO close
588− return $ Done a $ EOF x
589− go (Chunk c) = do
577+ yield a EOF
578+ go (Chunks c) = do
590579 liftIO $ withForeignPtr fp $ \emitter ->
591− LL.mapM_ (\e -> toEventRaw e $ c_yaml_emitter_emit emitter) c
592− return $ Cont (runEmitter close fp) Nothing
580+ mapM_ (\e -> toEventRaw e $ c_yaml_emitter_emit emitter) c
581+ continue go
582+
583+data YamlException = YamlException String
584+ deriving (Show, Typeable)
585+instance Exception YamlException
runtests.hs+50−63
@@ -8,7 +8,8 @@ import qualified Data.ByteString.Char8 as B8
88import Test.Framework.Providers.HUnit
99import Test.HUnit hiding (Test, path)
1010
11−import Data.Iteratee hiding (filter, length, foldl')
11+import qualified Data.Enumerator as E
12+import Data.Enumerator (($$))
1213import Data.List (foldl')
1314
1415import System.Directory
@@ -28,21 +29,19 @@ main = defaultMain
2829 , testCase "decode invalid document (without segfault)" caseDecodeInvalidDocument
2930 ]
3031
31−counter :: (Event -> Bool) -> Int -> IterateeG [] Event IO Int
32+counter :: (Event -> Bool) -> Int -> E.Step Event IO Int
3233counter pred' acc =
33− IterateeG go
34+ E.Continue go
3435 where
35− go (EOF x) = return $ Done acc $ EOF x
36− go (Chunk c) =
37− let acc' = length (filter pred' c) + acc
38− in return $ Cont (counter pred' acc') Nothing
36+ go E.EOF = E.yield acc E.EOF
37+ go (E.Chunks c) = E.returnI $ counter pred' $ length (filter pred' c) + acc
3938
4039caseHelper :: String
4140 -> (Event -> Bool)
4241 -> Int
4342 -> Assertion
4443caseHelper yamlString pred' expRes = do
45− res <- decode (B8.pack yamlString) (counter pred' 0) >>= run
44+ Right res <- E.run $ decode (B8.pack yamlString) (counter pred' 0)
4645 res @?= expRes
4746
4847caseCountScalarsWithAnchor :: Assertion
@@ -79,36 +78,34 @@ caseCountAliases =
7978
8079caseCountScalars :: Assertion
8180caseCountScalars = do
82− res <- decode yamlBS (counter' accum) >>= run
81+ Right res <- E.run $ decode yamlBS $ counter' accum
8382 res @?= (7, 1, 2)
84− where
85− yamlString = "foo:\n baz: [bin1, bin2, bin3]\nbaz: bazval"
86− yamlBS = B8.pack yamlString
87− counter' acc = IterateeG $ \s ->
88− case s of
89− EOF x -> return $ Done acc $ EOF x
90− Chunk c ->
91− let acc' = foldl' adder acc c
92− in return $ Cont (counter' acc') Nothing
93− adder (s, l, m) (EventScalar{}) = (s + 1, l, m)
94− adder (s, l, m) (EventSequenceStart{}) = (s, l + 1, m)
95− adder (s, l, m) (EventMappingStart{}) = (s, l, m + 1)
96− adder a _ = a
97− accum = (0, 0, 0) :: (Int, Int, Int)
83+ where
84+ yamlString = "foo:\n baz: [bin1, bin2, bin3]\nbaz: bazval"
85+ yamlBS = B8.pack yamlString
86+ counter' acc = E.Continue $ \s ->
87+ case s of
88+ E.EOF -> E.yield acc E.EOF
89+ E.Chunks c -> E.returnI $ counter' $ foldl' adder acc c
90+ adder (s, l, m) (EventScalar{}) = (s + 1, l, m)
91+ adder (s, l, m) (EventSequenceStart{}) = (s, l + 1, m)
92+ adder (s, l, m) (EventMappingStart{}) = (s, l, m + 1)
93+ adder a _ = a
94+ accum = (0, 0, 0) :: (Int, Int, Int)
9895
9996caseLargestString :: Assertion
10097caseLargestString = do
101− res <- decodeFile filePath (dec accum) >>= run
98+ Right res <- E.run $ decodeFile filePath $ dec accum
10299 res @?= (length expected, expected)
103100 where
104101 expected = "this one is just a little bit bigger than the others"
105102 filePath = "test/largest-string.yaml"
106− dec acc = IterateeG $ \s ->
103+ dec acc = E.Continue $ \s ->
107104 case s of
108− EOF x -> return $ Done acc $ EOF x
109− Chunk c ->
105+ E.EOF -> E.yield acc E.EOF
106+ E.Chunks c ->
110107 let acc' = foldl' adder acc c
111− in return $ Cont (dec acc') Nothing
108+ in E.returnI $ dec acc'
112109 adder (i, s) (EventScalar bs _ _ _) =
113110 let s' = B8.unpack bs
114111 i' = length s'
@@ -124,17 +121,13 @@ instance Eq MyEvent where
124121
125122caseEncodeDecode :: Assertion
126123caseEncodeDecode = do
127− eList <- decode yamlBS (dec []) >>= run
128− bs <- enumPure1Chunk eList encode >>= run
129− eList2 <- decode bs (dec []) >>= run
124+ Right eList <- E.run $ decode yamlBS $$ E.consume
125+ Right bs <- E.run $ E.enumList 1 eList $$ encode
126+ Right eList2 <- E.run $ decode bs $$ E.consume
130127 map MyEvent eList @=? map MyEvent eList2
131− where
132− yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
133− yamlBS = B8.pack yamlString
134− dec front = IterateeG $ \s ->
135− case s of
136− EOF x -> return $ Done front $ EOF x
137− Chunk c -> return $ Cont (dec $ front ++ c) Nothing
128+ where
129+ yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
130+ yamlBS = B8.pack yamlString
138131
139132removeFile' :: FilePath -> IO ()
140133removeFile' fp = do
@@ -144,46 +137,40 @@ removeFile' fp = do
144137caseEncodeDecodeFile :: Assertion
145138caseEncodeDecodeFile = do
146139 removeFile' tmpPath
147− eList <- decodeFile filePath (dec []) >>= run
148− enumPure1Chunk eList (encodeFile tmpPath) >>= run
149− eList2 <- decodeFile filePath (dec []) >>= run
140+ Right eList <- E.run $ decodeFile filePath $$ E.consume
141+ E.run $ E.enumList 1 eList $$ encodeFile tmpPath
142+ Right eList2 <- E.run $ decodeFile filePath $$ E.consume
150143 map MyEvent eList @=? map MyEvent eList2
151− where
152− filePath = "test/largest-string.yaml"
153− tmpPath = "tmp.yaml"
154− dec front = IterateeG $ \s ->
155− case s of
156− EOF x -> return $ Done front $ EOF x
157− Chunk c -> return $ Cont (dec $ front ++ c) Nothing
144+ where
145+ filePath = "test/largest-string.yaml"
146+ tmpPath = "tmp.yaml"
158147
159148caseInterleave :: Assertion
160149caseInterleave = do
161150 removeFile' tmpPath
162151 removeFile' tmpPath2
163− decodeFile filePath (encodeFile tmpPath :: IterateeG [] Event IO ()) >>= run
164− decodeFile tmpPath (encodeFile tmpPath2 :: IterateeG [] Event IO ()) >>= run
152+ Right () <- E.run $ decodeFile filePath $$ encodeFile tmpPath
153+ Right () <- E.run $ decodeFile tmpPath $$ encodeFile tmpPath2
165154 f1 <- readFile tmpPath
166155 f2 <- readFile tmpPath2
167156 f1 @=? f2
168− where
169− filePath = "test/largest-string.yaml"
170− tmpPath = "tmp.yaml"
171− tmpPath2 = "tmp2.yaml"
157+ where
158+ filePath = "test/largest-string.yaml"
159+ tmpPath = "tmp.yaml"
160+ tmpPath2 = "tmp2.yaml"
172161
173162caseDecodeInvalidDocument :: Assertion
174163caseDecodeInvalidDocument = do
175− x <- decode yamlBS ignore
176− y <- runIter x $ EOF Nothing
177− case y of
178− Cont _ _ -> return ()
179− _ -> do
164+ x <- E.run $ decode yamlBS ignore
165+ case x of
166+ Left _ -> return ()
167+ Right y -> do
180168 putStrLn $ "bad return value: " ++ show y
181169 assertFailure "expected parsing exception, but got no errors"
182170 where
183171 yamlString = " - foo\n - baz\nbuz"
184172 yamlBS = B8.pack yamlString
185− ignore :: IterateeG [] Event IO ()
186− ignore = IterateeG $ \s ->
173+ ignore = E.Continue $ \s ->
187174 case s of
188− EOF x -> return $ Done () $ EOF x
189− Chunk _c -> return $ Cont ignore Nothing
175+ E.EOF -> E.yield () E.EOF
176+ E.Chunks _-> E.returnI ignore
yaml.cabal+16−18
@@ -1,5 +1,5 @@
11name: yaml
2−version: 0.3.0
2+version: 0.4.0
33license: BSD3
44license-file: LICENSE
55author: Michael Snoyman <michael@snoyman.com>, Anton Ageev <antage@gmail.com>
@@ -27,14 +27,13 @@ library
2727 Buildable: False
2828 else
2929 Buildable: True
30− build-depends: base >= 4 && < 5,
31− transformers >= 0.1 && < 0.3,
32− bytestring >= 0.9.1.4 && < 0.10,
33− iteratee >= 0.3.5 && < 0.4,
34− MonadCatchIO-transformers >= 0.2.2 && < 0.3,
35− ListLike >= 1.0.1 && < 1.1
30+ build-depends: base >= 4 && < 5
31+ , transformers >= 0.1 && < 0.3
32+ , bytestring >= 0.9.1.4 && < 0.10
33+ , enumerator >= 0.4 && < 0.5
34+ , MonadCatchIO-transformers >= 0.2.2 && < 0.3
3635 exposed-modules: Text.Libyaml
37− ghc-options: -Wall -auto-all -caf-all
36+ ghc-options: -Wall
3837 c-sources: c/helper.c,
3938 c/api.c,
4039 c/dumper.c,
@@ -50,16 +49,15 @@ executable runtests
5049 if flag(buildtests)
5150 Buildable: True
5251 cpp-options: -DTEST
53− build-depends: test-framework,
54− test-framework-hunit,
55− HUnit,
56− directory,
57− base >= 4 && < 5,
58− transformers >= 0.1 && < 0.3,
59− bytestring >= 0.9.1.4 && < 0.10,
60− iteratee >= 0.3.5 && < 0.4,
61− MonadCatchIO-transformers >= 0.2.2 && < 0.3,
62− ListLike >= 1.0.1 && < 1.1
52+ build-depends: test-framework
53+ , test-framework-hunit
54+ , HUnit
55+ , directory
56+ , base >= 4 && < 5
57+ , transformers >= 0.1 && < 0.3
58+ , bytestring >= 0.9.1.4 && < 0.10
59+ , enumerator >= 0.4 && < 0.5
60+ , MonadCatchIO-transformers >= 0.2.2 && < 0.3
6361 else
6462 Buildable: False
6563 ghc-options: -Wall