@@ -0,0 +1,353 @@
1+-- | Primitive parsers for input type `DataView`.
2+-- |
3+-- | All of these primitive parsers will consume when they succeed.
4+-- |
5+-- | All of these primitive parsers will not consume and will automatically
6+-- | backtrack when they fail.
7+-- |
8+-- | See the package README for usage examples.
9+-- |
10+-- | ### Mutable ArrayBuffer
11+-- |
12+-- | All of the parsers in this module operate on an input stream of
13+-- | [__Data.ArrayBuffer.Types.DataView__](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:DataView),
14+-- | which represents a range of a mutable
15+-- | [__Data.ArrayBuffer.Types.ArrayBuffer__](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:ArrayBuffer).
16+-- |
17+-- | For operations for working with `DataView`, see
18+-- | module
19+-- | [__Data.ArrayBuffer.DataView__](https://pursuit.purescript.org/packages/purescript-arraybuffer/docs/Data.ArrayBuffer.DataView)
20+-- | in package __arraybuffer__.
21+-- |
22+-- | Reading from an `ArrayBuffer` is an `Effect`ful activity, so
23+-- | all parsers in this module must be run in a
24+-- | `MonadEffect m => ParserT DataView m` context with
25+-- | `Parsing.runParserT`.
26+-- |
27+-- | ### Position
28+-- |
29+-- | In a `DataView` parser, the `Position {index}` counts the number of
30+-- | bytes since the beginning of the input.
31+-- |
32+-- | The `Postion {line,column}` fields are unused and will remain constant *1*.
33+module Parsing.DataView
34+ ( takeN
35+ , takeRest
36+ , eof
37+ , match
38+ , anyTill
39+ , anyPrim
40+ , anyInt8
41+ , anyInt16be
42+ , anyInt16le
43+ , anyInt32be
44+ , anyInt32le
45+ , anyUint8
46+ , anyUint16be
47+ , anyUint16le
48+ , anyUint32be
49+ , anyUint32le
50+ , anyFloat32be
51+ , anyFloat32le
52+ , anyFloat64be
53+ , anyFloat64le
54+ , satisfy
55+ , satisfyInt8
56+ , satisfyInt16be
57+ , satisfyInt16le
58+ , satisfyInt32be
59+ , satisfyInt32le
60+ , satisfyUint8
61+ , satisfyUint16be
62+ , satisfyUint16le
63+ , satisfyUint32be
64+ , satisfyUint32le
65+ , satisfyFloat32be
66+ , satisfyFloat32le
67+ , satisfyFloat64be
68+ , satisfyFloat64le
69+ ) where
70+
71+import Prelude
72+
73+import Control.Monad.Rec.Class (Step(..), tailRecM)
74+import Control.Monad.Trans.Class (lift)
75+import Data.ArrayBuffer.DataView (Endian(LE, BE))
76+import Data.ArrayBuffer.DataView (buffer, byteLength, byteOffset, get, part) as DV
77+import Data.ArrayBuffer.Types (DataView, Int16, Int32, Int8, Uint16, Uint32, Uint8, Float32, Float64, ByteLength)
78+import Data.ArrayBuffer.ValueMapping (class BytesPerType, class BinaryValue, class ShowArrayViewType, byteWidth)
79+import Data.Float32 as Float32
80+import Data.Maybe (Maybe(..))
81+import Data.Symbol (class IsSymbol)
82+import Data.Tuple (Tuple(..))
83+import Data.UInt (UInt)
84+import Effect.Class (class MonadEffect, liftEffect)
85+import Parsing (ParseState(..), ParserT, Position(..), consume, fail, getParserT, stateParserT)
86+import Parsing.Combinators (alt, try, tryRethrow)
87+import Type.Proxy (Proxy(..))
88+
89+-- | Parse one fixed-bit-width `Data.ArrayBuffer.Types.ArrayViewType` primitive
90+-- | of a given endianness.
91+-- |
92+-- | #### Example
93+-- |
94+-- | Parse a little-endian 32-bit two’s-complement signed integer (4 bytes):
95+-- |
96+-- | anyPrim LE (Proxy :: Proxy Int32)
97+-- |
98+-- | or just use the convenience function `anyInt32le`, see below.
99+anyPrim
100+ :: forall a name m t
101+ . BinaryValue a t
102+ => BytesPerType a
103+ => ShowArrayViewType a name
104+ => IsSymbol name
105+ => MonadEffect m
106+ => Endian
107+ -> Proxy a
108+ -> ParserT DataView m t
109+anyPrim endian _ = do
110+ ParseState input (Position { index }) _ <- getParserT
111+ lift (liftEffect (DV.get endian (Proxy :: Proxy a) input index)) >>= case _ of
112+ Nothing -> fail "anyPrim unexpected end of DataView"
113+ Just i -> do
114+ stateParserT \_ -> Tuple i $ ParseState input (Position { line: 1, column: 1, index: index + byteWidth (Proxy :: Proxy a) }) true
115+
116+-- | Parse one 8-bit two’s-complement signed integer (byte).
117+anyInt8 :: forall m. MonadEffect m => ParserT DataView m Int
118+anyInt8 = anyPrim LE (Proxy :: Proxy Int8)
119+
120+-- | Parse one 16-bit big-endian two’s-complement signed integer.
121+anyInt16be :: forall m. MonadEffect m => ParserT DataView m Int
122+anyInt16be = anyPrim BE (Proxy :: Proxy Int16)
123+
124+-- | Parse one 16-bit little-endian two’s-complement signed integer.
125+anyInt16le :: forall m. MonadEffect m => ParserT DataView m Int
126+anyInt16le = anyPrim LE (Proxy :: Proxy Int16)
127+
128+-- | Parse one 32-bit big-endian two’s-complement signed integer.
129+anyInt32be :: forall m. MonadEffect m => ParserT DataView m Int
130+anyInt32be = anyPrim BE (Proxy :: Proxy Int32)
131+
132+-- | Parse one 32-bit little-endian two’s-complement signed integer.
133+anyInt32le :: forall m. MonadEffect m => ParserT DataView m Int
134+anyInt32le = anyPrim LE (Proxy :: Proxy Int32)
135+
136+-- | Parse one 8-bit unsigned integer (octet).
137+anyUint8 :: forall m. MonadEffect m => ParserT DataView m UInt
138+anyUint8 = anyPrim LE (Proxy :: Proxy Uint8)
139+
140+-- | Parse one 16-bit big-endian unsigned integer.
141+anyUint16be :: forall m. MonadEffect m => ParserT DataView m UInt
142+anyUint16be = anyPrim BE (Proxy :: Proxy Uint16)
143+
144+-- | Parse one 16-bit little-endian unsigned integer.
145+anyUint16le :: forall m. MonadEffect m => ParserT DataView m UInt
146+anyUint16le = anyPrim LE (Proxy :: Proxy Uint16)
147+
148+-- | Parse one 32-bit big-endian unsigned integer.
149+anyUint32be :: forall m. MonadEffect m => ParserT DataView m UInt
150+anyUint32be = anyPrim BE (Proxy :: Proxy Uint32)
151+
152+-- | Parse one 32-bit little-endian unsigned integer.
153+anyUint32le :: forall m. MonadEffect m => ParserT DataView m UInt
154+anyUint32le = anyPrim LE (Proxy :: Proxy Uint32)
155+
156+-- | Parse one 32-bit big-endian IEEE 754 floating-point number.
157+anyFloat32be :: forall m. MonadEffect m => ParserT DataView m Float32.Float32
158+anyFloat32be = anyPrim BE (Proxy :: Proxy Float32)
159+
160+-- | Parse one 32-bit little-endian IEEE 754 floating-point number.
161+anyFloat32le :: forall m. MonadEffect m => ParserT DataView m Float32.Float32
162+anyFloat32le = anyPrim LE (Proxy :: Proxy Float32)
163+
164+-- | Parse one 64-bit big-endian IEEE 754 floating-point number.
165+anyFloat64be :: forall m. MonadEffect m => ParserT DataView m Number
166+anyFloat64be = anyPrim BE (Proxy :: Proxy Float64)
167+
168+-- | Parse one 64-bit little-endian IEEE 754 floating-point number.
169+anyFloat64le :: forall m. MonadEffect m => ParserT DataView m Number
170+anyFloat64le = anyPrim LE (Proxy :: Proxy Float64)
171+
172+-- | Parse one fixed-bit-width primitive that satisfies the given predicate.
173+-- |
174+-- | #### Example
175+-- |
176+-- | Parse a little-endian 32-bit signed integer that is equal to *3*:
177+-- |
178+-- | satisfy LE (Proxy :: Proxy Int32) (_ == 3)
179+-- |
180+-- | or just use the convenience function `satisfyInt32le`, see below.
181+satisfy
182+ :: forall a name m t
183+ . BinaryValue a t
184+ => BytesPerType a
185+ => ShowArrayViewType a name
186+ => IsSymbol name
187+ => Show t
188+ => MonadEffect m
189+ => Endian
190+ -> Proxy a
191+ -> (t -> Boolean)
192+ -> ParserT DataView m t
193+satisfy endian proxy f = tryRethrow do
194+ i <- anyPrim endian proxy
195+ if f i then pure i
196+ else fail "satisfy predicate failed"
197+
198+-- | Parse one 8-bit signed integer that satisfies the given predicate.
199+satisfyInt8 :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
200+satisfyInt8 = satisfy LE (Proxy :: Proxy Int8)
201+
202+-- | Parse one 16-bit big-endian signed integer that satisfies the given predicate.
203+satisfyInt16be :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
204+satisfyInt16be = satisfy BE (Proxy :: Proxy Int16)
205+
206+-- | Parse one 16-bit little-endian signed integer that satisfies the given predicate.
207+satisfyInt16le :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
208+satisfyInt16le = satisfy LE (Proxy :: Proxy Int16)
209+
210+-- | Parse one 32-bit big-endian signed integer that satisfies the given predicate.
211+satisfyInt32be :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
212+satisfyInt32be = satisfy BE (Proxy :: Proxy Int32)
213+
214+-- | Parse one 32-bit little-endian signed integer that satisfies the given predicate.
215+satisfyInt32le :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
216+satisfyInt32le = satisfy LE (Proxy :: Proxy Int32)
217+
218+-- | Parse one 8-bit unsigned integer that satisfies the given predicate.
219+satisfyUint8 :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
220+satisfyUint8 = satisfy LE (Proxy :: Proxy Uint8)
221+
222+-- | Parse one 16-bit big-endian unsigned integer that satisfies the given predicate.
223+satisfyUint16be :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
224+satisfyUint16be = satisfy BE (Proxy :: Proxy Uint16)
225+
226+-- | Parse one 16-bit little-endian unsigned integer that satisfies the given predicate.
227+satisfyUint16le :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
228+satisfyUint16le = satisfy LE (Proxy :: Proxy Uint16)
229+
230+-- | Parse one 32-bit big-endian unsigned integer that satisfies the given predicate.
231+satisfyUint32be :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
232+satisfyUint32be = satisfy BE (Proxy :: Proxy Uint32)
233+
234+-- | Parse one 32-bit little-endian unsigned integer that satisfies the given predicate.
235+satisfyUint32le :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
236+satisfyUint32le = satisfy LE (Proxy :: Proxy Uint32)
237+
238+-- | Parse one 32-bit big-endian floating-point number that satisfies the given predicate.
239+satisfyFloat32be :: forall m. MonadEffect m => (Float32.Float32 -> Boolean) -> ParserT DataView m Float32.Float32
240+satisfyFloat32be = satisfy BE (Proxy :: Proxy Float32)
241+
242+-- | Parse one 32-bit little-endian floating-point number that satisfies the given predicate.
243+satisfyFloat32le :: forall m. MonadEffect m => (Float32.Float32 -> Boolean) -> ParserT DataView m Float32.Float32
244+satisfyFloat32le = satisfy LE (Proxy :: Proxy Float32)
245+
246+-- | Parse one 64-bit big-endian floating-point number that satisfies the given predicate.
247+satisfyFloat64be :: forall m. MonadEffect m => (Number -> Boolean) -> ParserT DataView m Number
248+satisfyFloat64be = satisfy BE (Proxy :: Proxy Float64)
249+
250+-- | Parse one 64-bit little-endian floating-point number that satisfies the given predicate.
251+satisfyFloat64le :: forall m. MonadEffect m => (Number -> Boolean) -> ParserT DataView m Number
252+satisfyFloat64le = satisfy LE (Proxy :: Proxy Float64)
253+
254+-- | Take *N* bytes starting from the current parser position. Will fail
255+-- | if not enough bytes remain in the input. Will fail if *N* is negative.
256+-- |
257+-- | #### Example
258+-- |
259+-- | Parse three bytes.
260+-- |
261+-- | takeN 3
262+-- |
263+takeN :: forall m. MonadEffect m => ByteLength -> ParserT DataView m DataView
264+takeN n = do
265+ ParseState input (Position { index }) _ <- getParserT
266+ if (n < 0) then
267+ fail "takeN cannot take negative number of bytes"
268+ else if (index + n > DV.byteLength input) then
269+ fail "takeN expected N bytes"
270+ else do
271+ p <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + index) n
272+ stateParserT \_ -> Tuple p $ ParseState input (Position { line: 1, column: 1, index: index + n }) true
273+
274+-- | Take the rest of the input, however many bytes remain. Always succeeds.
275+takeRest :: forall m. MonadEffect m => ParserT DataView m DataView
276+takeRest = do
277+ ParseState input (Position { index }) _ <- getParserT
278+ p <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + index)
279+ (DV.byteLength input - index)
280+ stateParserT \_ -> Tuple p $ ParseState input (Position { line: 1, column: 1, index: DV.byteLength input + 1 }) true
281+
282+-- | Parse succeeds at the end of the input DataView.
283+eof :: forall m. Monad m => ParserT DataView m Unit
284+eof = do
285+ ParseState input (Position { index }) _ <- getParserT
286+ if (index + 1 > DV.byteLength input) then do
287+ -- We must consume so this combines correctly with notFollowedBy
288+ consume
289+ else do
290+ fail "eof expected end of DataView"
291+
292+-- | The
293+-- | [famous `match`](http://www.serpentine.com/blog/2014/05/31/attoparsec/#from-strings-to-buffers-and-cursors)
294+-- | combinator.
295+-- |
296+-- | Return both the result of a parse and the portion of the input that
297+-- | was consumed while it was being parsed.
298+match :: forall a m. MonadEffect m => ParserT DataView m a -> ParserT DataView m (Tuple DataView a)
299+match p = do
300+ ParseState input (Position { index: index0 }) _ <- getParserT
301+ x <- p
302+ ParseState _ (Position { index: index1 }) _ <- getParserT
303+ part <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + index0) (index1 - index0)
304+ pure $ Tuple part x
305+
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+
341+-- ****************************** Notes ****************************************
342+--
343+-- We cannot have a primitive parser which parses a `DataView` and produces
344+-- an `ArrayView` (a Javascript Typed Array). Javascript DataViews are
345+-- endianess-aware, but Javascript Typed Arrays assume the native endianness
346+-- of the local machine. DataViews are intended to be used for I/O, ArrayViews
347+-- are intended to be used internally for graphics in a process, and they're
348+-- not intended to be both applied to the same ArrayBuffer.
349+-- The exception: `Uint8Array`
350+--
351+-- The failure messages are all constant strings form performance reasons.
352+-- If failure messages were constructed lazily then we could have more
353+-- descriptive messages.