@@ -35,6 +35,7 @@ module Parsing.DataView
3535 , takeRest
3636 , eof
3737 , match
38+ , anyTill
3839 , anyPrim
3940 , anyInt8
4041 , anyInt16be
@@ -69,9 +70,10 @@ module Parsing.DataView
6970
7071import Prelude
7172
73+import Control.Monad.Rec.Class (Step(..), tailRecM)
7274import Control.Monad.Trans.Class (lift)
7375import Data.ArrayBuffer.DataView (Endian(LE, BE))
74−import Data.ArrayBuffer.DataView (byteLength, byteOffset, get, part, buffer) as DV
76+import Data.ArrayBuffer.DataView (buffer, byteLength, byteOffset, get, part) as DV
7577import Data.ArrayBuffer.Types (DataView, Int16, Int32, Int8, Uint16, Uint32, Uint8, Float32, Float64, ByteLength)
7678import Data.ArrayBuffer.ValueMapping (class BytesPerType, class BinaryValue, class ShowArrayViewType, byteWidth)
7779import Data.Float32 as Float32
@@ -81,7 +83,7 @@ import Data.Tuple (Tuple(..))
8183import Data.UInt (UInt)
8284import Effect.Class (class MonadEffect, liftEffect)
8385import Parsing (ParseState(..), ParserT, Position(..), consume, fail, getParserT, stateParserT)
84−import Parsing.Combinators (tryRethrow)
86+import Parsing.Combinators (alt, try, tryRethrow)
8587import Type.Proxy (Proxy(..))
8688
8789-- | Parse one fixed-bit-width `Data.ArrayBuffer.Types.ArrayViewType` primitive
@@ -301,6 +303,41 @@ match p = do
301303 part <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + index0) (index1 - index0)
302304 pure $ Tuple part x
303305
306+-- | Combinator which finds the first position in the input `DataView` where the
307+-- | phrase can parse. Returns both the
308+-- | parsed result and the unparsable input section searched before the parse.
309+-- | Will fail if no section of the input is parseable. To backtrack the input
310+-- | stream on failure, combine with `tryRethrow`.
311+-- |
312+-- | This combinator is equivalent to `manyTill_ anyInt8`, but it will be
313+-- | faster because it returns a slice of the input `DataView` for the
314+-- | section preceding the parse instead of a `List Int`.
315+-- |
316+-- | Be careful not to look too far
317+-- | ahead; if the phrase parser looks to the end of the input then `anyTill`
318+-- | could be *O(n²)*.
319+anyTill
320+ :: forall m a
321+ . MonadEffect m
322+ => ParserT DataView m a
323+ -> ParserT DataView m (Tuple DataView a)
324+anyTill p = do
325+ ParseState input1 (Position { index: index0 }) _ <- getParserT
326+ Tuple index1 t <- tailRecM go unit
327+ part <- lift $ liftEffect $ DV.part (DV.buffer input1) (DV.byteOffset input1 + index0) (index1 - index0)
328+ pure $ Tuple part t
329+ where
330+ go unit = alt
331+ ( do
332+ ParseState _ (Position { index: index1 }) _ <- getParserT
333+ t <- try p
334+ pure $ Done $ Tuple index1 t
335+ )
336+ ( do
337+ _ <- anyInt8
338+ pure $ Loop unit
339+ )
340+
304341-- ****************************** Notes ****************************************
305342--
306343-- We cannot have a primitive parser which parses a `DataView` and produces