Bryan O'Sullivan avatar Bryan O'Sullivan committed 51adcf0

Tweaklet

Comments (0)

Files changed (1)

src/Data/ParserCombinators/Attoparsec/Incremental.hs

       Parser
     , Result(..)
     , parse
+    , parseWith
 
     , (<?>)
     , takeWhile
 
 data S = S {-# UNPACK #-} !S.ByteString -- ^ first chunk of input
            L.ByteString                 -- ^ rest of input
-           [S.ByteString]               -- ^ input acquired during backtracks
+           [L.ByteString]               -- ^ input acquired during backtracks
            {-# UNPACK #-} !Int          -- ^ failure depth
 
 -- | The result of a partial parse
               | Done L.ByteString a
                 -- ^ the parse finished and produced the given list of
                 --   results doing so. Any unparsed data is returned.
-              | Partial (S.ByteString -> Result a)
+              | Partial (L.ByteString -> Result a)
                 -- ^ the parse ran out of data before finishing, but produced
                 --   the given list of results before doing so. To continue the
                 --   parse pass more data to the given continuation
 --   type just before giving it to the outside world.
 data IResult a = IFailed S String
                | IDone S a
-               | IPartial (S.ByteString -> IResult a)
+               | IPartial (L.ByteString -> IResult a)
 
 instance Show (IResult a) where
   show (IFailed _ err) = "IFailed " ++ err
     let
       filt f@(IFailed (S _ _ adds' failDepth') _)
         | failDepth' == failDepth + 1 =
-            let lb' = lb `appL` L.fromChunks (reverse adds')
+            let lb' = lb `appL` L.concat (reverse adds')
             in  unParser p2 (S sb lb' (adds' ++ adds) failDepth) k
         | otherwise = f
       filt (IPartial cont) = IPartial (filt . cont)
       IFailed st' _ -> IFailed st' msg
       ok -> ok
 
-initState :: S.ByteString -> S
-initState input = S input L.empty [] 0
+initState :: L.ByteString -> S
+initState (L.Chunk sb lb) = S sb lb [] 0
+initState _               = S S.empty L.empty [] 0
 
-mkState :: L.ByteString -> [S.ByteString] -> Int -> S
+mkState :: L.ByteString -> [L.ByteString] -> Int -> S
 mkState bs adds failDepth =
     case bs of
       L.Empty -> S S.empty L.empty adds failDepth
       L.Chunk sb lb -> S sb lb adds failDepth
 
-toLazy :: S.ByteString -> L.ByteString
-toLazy s | S.null s = L.Empty
-         | otherwise = L.Chunk s L.Empty
-
-addX :: S.ByteString -> [S.ByteString] -> [S.ByteString]
-addX s adds | S.null s = adds
+addX :: L.ByteString -> [L.ByteString] -> [L.ByteString]
+addX s adds | L.null s = adds
             | otherwise = s : adds
 
 yield :: Parser r ()
 yield = Parser $ \(S sb lb adds failDepth) k ->
-  IPartial $ \s -> k () (S sb (lb `appL` toLazy s) (addX s adds) failDepth)
+  IPartial $ \s -> k () (S sb (lb `appL` s) (addX s adds) failDepth)
 
 takeWith :: (L.ByteString -> (L.ByteString, L.ByteString))
          -> Parser r L.ByteString
   let (left,rest) = splitf (sb +: lb)
   in case rest of
        L.Empty -> IPartial $ \s ->
-                  let s' = S s L.empty (addX s adds) failDepth
+                  let s' = mkState s (addX s adds) failDepth
                       k' a = k (appL left a)
                   in unParser (takeWith splitf) s' k'
        L.Chunk h t -> k left (S h t adds failDepth)
            in if L.length h == n
               then k h (mkState t adds failDepth)
               else IPartial $ \s ->
-                   let st = S s L.empty (addX s adds) failDepth
+                   let st = mkState s (addX s adds) failDepth
                        k' a = k (appL h a)
                    in unParser (tc (n - l)) st k'
 
       (h,L.Empty)
         | h `L.isPrefixOf` s ->
             IPartial $ \s' ->
-            let st'  = S s' L.empty (addX s' adds) failDepth
+            let st'  = mkState s' (addX s' adds) failDepth
                 k' a = k (appL h a)
                 r'   = L.drop (L.length h) s
             in unParser (string r') st' k'
       _ -> IFailed st "string failed to match"
 
+emptyState = S S.empty L.empty
+
 satisfy :: (Word8 -> Bool) -> Parser r Word8
 satisfy p =
   Parser $ \st@(S sb lb adds failDepth) k ->
-    case L.uncons (sb +: lb) of
-      Just (w, lb') | p w -> k w (mkState lb' adds failDepth)
+    case S.uncons sb of
+      Just (w, sb') | p w -> k w (S sb' lb adds failDepth)
                     | otherwise -> IFailed st "failed to match"
-      Nothing -> IPartial $ \s ->
-                 let st' = S s L.empty (addX s adds) failDepth
-                 in unParser (satisfy p) st' k
+      Nothing -> case L.uncons lb of
+                   Just (w, lb') | p w -> k w (mkState lb' adds failDepth)
+                                 | otherwise -> IFailed st "failed to match"
+                   Nothing -> IPartial $ \s ->
+                              let st' = emptyState adds failDepth
+                              in if L.null s
+                                 then IFailed st "barf"
+                                 else unParser (satisfy p) st' k
 
 pushBack :: L.ByteString -> Parser r ()
 pushBack bs =
 terminalContinuation :: a -> S -> IResult a
 terminalContinuation v s = IDone s v
 
-parse :: Parser r r -> S.ByteString -> Result r
+parse :: Parser r r -> L.ByteString -> Result r
 parse m input =
   toplevelTranslate $ unParser m (initState input) terminalContinuation
 
+parseWith :: Applicative f => f L.ByteString -> Parser r r -> L.ByteString
+          -> f (Result r)
+parseWith refill p s =
+  case parse p s of
+    Partial k -> k <$> refill
+    ok        -> pure ok
+
 #define PARSER Parser r
 #include "Word8Boilerplate.h"
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.