packages feed

hexpat-iteratee (empty) → 0.1

raw patch · 5 files changed

+349/−0 lines, 5 filesdep +Listdep +basedep +bytestringsetup-changed

Dependencies added: List, base, bytestring, containers, extensible-exceptions, hexpat, iteratee, mtl, parallel

Files

+ LICENSE view
@@ -0,0 +1,23 @@+Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:+* Redistributions of source code must retain the above copyright notice,+  this list of conditions and the following disclaimer.+* Redistributions in binary form must reproduce the above copyright+  notice, this list of conditions and the following disclaimer in the+  documentation and/or other materials provided with the distribution.+* Neither the name of the author nor the names of contributors may be+  used to endorse or promote products derived from this software without+  specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell++> import Distribution.Simple+> main = defaultMain
+ Text/XML/Expat/Chunked.hs view
@@ -0,0 +1,185 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Text.XML.Expat.Chunked where++import Text.XML.Expat.Chunked.Iterator+import qualified Text.XML.Expat.IO as IO+import Text.XML.Expat.SAX+import Text.XML.Expat.Tree++import Control.Monad+import Control.Monad.Trans+import qualified Data.ByteString as B+import Data.IORef+import Data.Iteratee hiding (head)+import qualified Data.Iteratee as It+import Data.Iteratee.WrappedByteString+import Data.List.Class+import Data.Sequence (Seq, (|>), index)+import qualified Data.Sequence as Seq+import Data.Word+++------ Queue ------------------------------------------------------------------++newtype Queue a = Queue (Seq (Maybe a))++emptyQueue :: Queue a+emptyQueue = Queue (Seq.empty)++queuePush :: a -> Queue a -> Queue a+queuePush value (Queue s) = Queue (s |> Just value)++queueEnd :: Queue a -> Queue a+queueEnd (Queue s) = Queue (s |> Nothing)++data QueueValue a+    = Value a+    | End+    | Pending++queueIndex :: Queue a -> Int -> QueueValue a+queueIndex q@(Queue s) i+    | i >= Seq.length s = Pending+    | otherwise = case s `index` i of+        Just value -> Value value+        Nothing    -> End+++------ Stack ------------------------------------------------------------------++newtype Stack a = Stack [a]++emptyStack :: Stack a+emptyStack = Stack []++stackTop :: Stack a -> a+stackTop (Stack s) = head s++stackPop :: Stack a -> Stack a+stackPop (Stack s) = Stack (tail s)++stackPush :: a -> Stack a -> Stack a+stackPush it (Stack s) = Stack (it:s)+++------ Handler ----------------------------------------------------------------++data Result m a = Yield (HandlerT m a) | Result a++data HandlerT m a = HandlerT {+        runHandlerT :: m (Result m a)+    }++instance Monad m => Functor (HandlerT m) where+    fmap = liftM++instance Monad m => Monad (HandlerT m) where+    return a = HandlerT $ return $ Result a+    f >>= g = HandlerT $ do+        res1 <- runHandlerT f+        case res1 of+            Yield c -> return $ Yield (c >>= g)+            Result a  -> runHandlerT (g a)+    fail err = HandlerT $ fail err++instance MonadTrans HandlerT where+    lift m = HandlerT $ do+        r <- m+        return $ Result r++instance MonadIO m => MonadIO (HandlerT m) where+    liftIO m = HandlerT $ do+        r <- liftIO m+        return $ Result r++yield :: Monad m => HandlerT m ()+yield = HandlerT $ return $ Yield (HandlerT $ return $ Result ())++-------------------------------------------------------------------------------++type CNode m tag text = NodeG (Iterator (HandlerT m)) tag text++parse :: forall m a tag text . (+             MonadIO m,+             GenericXMLString tag,+             GenericXMLString text+         ) =>+         ParserOptions tag text+      -> (Maybe (CNode m tag text) -> HandlerT m a)+      -> IterateeG WrappedByteString Word8 m (Either ErrMsg a)+parse opts code = IterateeG $ \str -> do+    let enc = parserEncoding opts++    parser <- liftIO $ IO.newParser enc++    rootRef <- liftIO $ newIORef emptyQueue+    stackRef <- liftIO $ newIORef $ rootRef `stackPush` emptyStack++    liftIO $ IO.setStartElementHandler parser $ \cName cAttrs -> do+        name <- mkText cName+        attrs <- forM cAttrs $ \(cAttrName,cAttrValue) -> do+            attrName <- mkText cAttrName+            attrValue <- mkText cAttrValue+            return (attrName, attrValue)+        --loc <- getParseLocation parser+        stack <- readIORef stackRef+        newRef <- newIORef emptyQueue+        let elt = Element name attrs (Iterator $ iter newRef 0)+        modifyIORef (stackTop stack) (elt `queuePush`)+        modifyIORef stackRef (newRef `stackPush`)+        return True+    liftIO $ IO.setEndElementHandler parser $ \_ -> do+        --name <- mkText cName+        --loc <- getParseLocation parser+        stack <- readIORef stackRef+        modifyIORef (stackTop stack) queueEnd+        writeIORef stackRef (stackPop stack)+        return True+    liftIO $ IO.setCharacterDataHandler parser $ \cText -> do+        txt <- gxFromCStringLen cText+        --loc <- getParseLocation parser+        stack <- readIORef stackRef+        modifyIORef (stackTop stack) (Text txt `queuePush`)+        return True++    let nextIter :: HandlerT m a+                 -> IterateeG WrappedByteString Word8 m (Either ErrMsg a)+        nextIter c = IterateeG $ \str -> do+            case str of+                EOF (Just err) -> return $ Done (Left err) str+                _ -> do+                    mErr <- case str of+                        Chunk (WrapBS blk) -> liftIO $ IO.parseChunk parser blk False+                        EOF _              -> liftIO $ IO.parseChunk parser B.empty True++                    res <- runHandlerT c++                    return $ case res of+                        Yield c' -> do+                            case (str, mErr) of+                                (Chunk _, Just err) -> Cont (nextIter c') (Just $ Err $ show err)+                                (Chunk _, Nothing)  -> Cont (nextIter c') Nothing+                                (EOF _,   Just err) -> Done (Left $ Err $ show err) str+                                (EOF _,   Nothing)  -> Done (Left $ Err "EOF not handled") str+                        Result a -> do+                            case mErr of+                                Just err -> Done (Left $ Err $ show err) str+                                Nothing  -> Done (Right a) str++    let process = do+            elt <- iter rootRef 0+            case elt of+                Nil         -> code Nothing+                Cons node _ -> code (Just node)+    runIter (nextIter process) str++  where+    iter :: IORef (Queue (CNode m tag text)) -> Int -> HandlerT m (ListItem (Iterator (HandlerT m)) (CNode m tag text))+    iter ref i = do+        queue <- liftIO (readIORef ref)+        case queue `queueIndex` i of  -- to do: make it throw away heads we don't have references to+            Pending -> yield >> iter ref i+            End     -> return $ Nil+            Value a -> return $+                let i' = i + 1+                in  Cons a (Iterator $ iter ref i')
+ Text/XML/Expat/Chunked/Iterator.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances,+        StandaloneDeriving, FlexibleInstances, MultiParamTypeClasses #-}+module Text.XML.Expat.Chunked.Iterator (Iterator (..)) where++import Data.List.Class (List(..), ListItem(..), foldrL)++import Control.Applicative (Applicative(..))+import Control.Monad (MonadPlus(..), ap, liftM)+-- import Control.Monad.Cont.Class (MonadCont(..))+import Control.Monad.Error.Class (MonadError(..))+import Control.Monad.Reader.Class (MonadReader(..))+import Control.Monad.State.Class (MonadState(..))+import Control.Monad.Trans (MonadTrans(..), MonadIO(..))+import Data.Monoid (Monoid(..))+++newtype Iterator m a = Iterator { runIterator :: m (ListItem (Iterator m) a) }++deriving instance (Eq (m (ListItem (Iterator m) a))) => Eq (Iterator m a)+deriving instance (Ord (m (ListItem (Iterator m) a))) => Ord (Iterator m a)+deriving instance (Read (m (ListItem (Iterator m) a))) => Read (Iterator m a)+deriving instance (Show (m (ListItem (Iterator m) a))) => Show (Iterator m a)++{-+instance (Monad m, MonadPlus (Iterator m)) => List (Iterator m) where+    type ItemM (Iterator m) = m+    runList = runIterator+    joinL m = Iterator $ do+        it <- m+        runIterator it+-}++-- for mappend, fmap, bind+foldrL' :: List l => (a -> l b -> l b) -> l b -> l a -> l b+foldrL' consFunc nilFunc =+  joinL . foldrL step (return nilFunc)+  where+    step x = return . consFunc x . joinL++-- like generic cons except using that one+-- would cause an infinite loop+cons :: Monad m => a -> Iterator m a -> Iterator m a+cons x = Iterator . return . Cons x++instance Monad m => Monoid (Iterator m a) where+  mempty = Iterator $ return Nil+  mappend = flip (foldrL' cons)++instance Monad m => Functor (Iterator m) where+  fmap func = foldrL' (cons . func) mempty++instance Monad m => Monad (Iterator m) where+  return = Iterator . return . (`Cons` mempty)+  a >>= b = foldrL' mappend mempty (fmap b a)++instance Monad m => Applicative (Iterator m) where+  pure = return+  (<*>) = ap++instance Monad m => MonadPlus (Iterator m) where+  mzero = mempty+  mplus = mappend++instance MonadTrans Iterator where+  lift = Iterator . liftM (`Cons` mempty)++instance Monad m => List (Iterator m) where+  type ItemM (Iterator m) = m+  runList = runIterator+  joinL = Iterator . (>>= runList)++-- YUCK:+-- I can't believe I'm doing this,+-- for compatability with mtl's Iterator.+-- I hate the O(N^2) code length auto-lifts. DRY!!++instance MonadIO m => MonadIO (Iterator m) where+  liftIO = lift . liftIO++{-+-- TODO: understand and verify this instance :)+instance MonadCont m => MonadCont (Iterator m) where+  callCC f =+    Iterator $ callCC thing+    where+      thing c = runIterator . f $ Iterator . c . (`Cons` mempty)+-}++instance MonadError e m => MonadError e (Iterator m) where+  throwError = lift . throwError+  catchError m = Iterator . catchError (runList m) . (runList .)++instance MonadReader s m => MonadReader s (Iterator m) where+  ask = lift ask+  local f = Iterator . local f . runList++instance MonadState s m => MonadState s (Iterator m) where+  get = lift get+  put = lift . put++
+ hexpat-iteratee.cabal view
@@ -0,0 +1,36 @@+Cabal-Version: >= 1.6+Name: hexpat-iteratee+Version: 0.1+Synopsis: chunked XML parsing using iteratees+Description:+  Provides chunked XML parsing using iteratees+Category: XML+License: BSD3+License-File: LICENSE+Author:+  Stephen Blackheath (blackh)+Maintainer: http://blacksapphire.com/antispam/+Copyright:+  (c) 2010 Stephen Blackheath <http://blacksapphire.com/antispam/>+Homepage: http://haskell.org/haskellwiki/Hexpat/+Build-Type: Simple+Stability: prototype+source-repository head+    type:     darcs+    location: http://code.haskell.org/hexpat-iteratee/++Library+  Build-Depends:+    base >= 3 && < 5,+    bytestring,+    mtl,+    parallel,+    containers,+    extensible-exceptions >= 0.1 && < 0.2,+    iteratee >= 0.3,+    hexpat >= 0.13,+    List >= 0.2+  Exposed-Modules:+    Text.XML.Expat.Chunked+    Text.XML.Expat.Chunked.Iterator+  ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-unused-matches -fno-warn-missing-signatures -fno-warn-orphans