git.iko.soy/rowtype-yoga/purescript-parsing-dataview
on master help sign in
New combinator: anyTill
commit1e6a6ced76fcd64a84b2ba70613c43455b6df7df authorJames Brock <jamesbrock@gmail.com> dateFri 2 Dec 2022, 20:22 (4 years ago) parentb6c6a8f
5 files changed+61−5
CHANGELOG.md+4 bower.json+3−2 spago.dhall+1 src/Parsing/DataView.purs+39−2 test/Main.purs+14−1
CHANGELOG.md+4
@@ -1,5 +1,9 @@
11# Changelog
22
3+## Unreleased
4+
5+New combinator: `anyTill`.
6+
37## v3.1.0
48
59Bugfix `takeN`.
bower.json+3−2
@@ -14,13 +14,14 @@
1414 "output"
1515 ],
1616 "dependencies": {
17− "purescript-arraybuffer": "^v13.0.0",
17+ "purescript-arraybuffer": "^v13.1.1",
1818 "purescript-arraybuffer-types": "^v3.0.2",
1919 "purescript-effect": "^v4.0.0",
2020 "purescript-float32": "^v2.0.0",
2121 "purescript-maybe": "^v6.0.0",
22− "purescript-parsing": "^v10.0.0",
22+ "purescript-parsing": "^v10.2.0",
2323 "purescript-prelude": "^v6.0.1",
24+ "purescript-tailrec": "^v6.1.0",
2425 "purescript-transformers": "^v6.0.0",
2526 "purescript-tuples": "^v7.0.0",
2627 "purescript-uint": "^v7.0.0"
spago.dhall+1
@@ -9,6 +9,7 @@
99 , "maybe"
1010 , "parsing"
1111 , "prelude"
12+ , "tailrec"
1213 , "transformers"
1314 , "tuples"
1415 , "uint"
src/Parsing/DataView.purs+39−2
@@ -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
test/Main.purs+14−1
@@ -20,7 +20,7 @@ import Effect.Console (logShow)
2020import Effect.Exception (catchException, message)
2121import Parsing (ParserT, Position(..), fail, liftExceptT, parseErrorPosition, runParserT)
2222import Parsing.Combinators (many, manyTill)
23−import Parsing.DataView (anyInt8)
23+import Parsing.DataView (anyInt8, anyTill, satisfyInt8)
2424import Parsing.DataView as DV
2525import Test.Assert (assert', assertEqual')
2626import Web.Encoding.TextDecoder as TextDecoder
@@ -168,4 +168,17 @@ main = do
168168 assertEqual' "UTF-8 decoding example"
169169 { expected: Right teststring
170170 , actual: result
171+ }
172+
173+ do
174+ result <- runParserT dv do
175+ Tuple pre _ <- anyTill do
176+ _ <- satisfyInt8 (_ == 7)
177+ _ <- satisfyInt8 (_ == 8)
178+ pure unit
179+ pure pre
180+
181+ assertEqual' "anyTill"
182+ { expected: Right 2
183+ , actual: DataView.byteLength <$> result
171184 }