@@ -1,24 +1,36 @@
1−-- | Primitive parsers for parsing Javascript ArrayBuffers with the
2−-- | [`Text.Parsing.Parser`](https://pursuit.purescript.org/packages/purescript-parsing/docs/Text.Parsing.Parser)
3−-- | module in package __purescript-parsing__.
1+-- | Primitive parsers for JavaScript `ArrayBuffer`s with the
2+-- | `ParserT` type and combinators in package __purescript-parsing__.
43-- | See the package README for usage examples.
54-- |
5+-- | ### Mutable ArrayBuffer
6+-- |
67-- | All of the parsers in this module operate on an input stream of
7−-- | [`Data.ArrayBuffer.Types.DataView`](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:DataView),
8−-- | which represents a range of an
9−-- | `Data.ArrayBuffer.Types.ArrayBuffer`.
8+-- | [__Data.ArrayBuffer.Types.DataView__](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:DataView),
9+-- | which represents a range of a mutable
10+-- | [__Data.ArrayBuffer.Types.ArrayBuffer__](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:ArrayBuffer).
1011-- |
1112-- | For operations for working with `ArrayBuffer` and `DataView`, see
1213-- | module
13−-- | [`Data.ArrayBuffer.DataView`](https://pursuit.purescript.org/packages/purescript-arraybuffer/docs/Data.ArrayBuffer.DataView)
14+-- | [__Data.ArrayBuffer.DataView__](https://pursuit.purescript.org/packages/purescript-arraybuffer/docs/Data.ArrayBuffer.DataView)
1415-- | in package __purescript-arraybuffer__.
1516-- |
1617-- | Reading from an `ArrayBuffer` is an `Effect`ful activity, so
1718-- | all parsers in this module must be run in a
18−-- | `MonadEffect m => ParserT DataView m` context, with
19−-- | `Text.Parsing.Parser.runParserT`.
20−module Text.Parsing.Parser.DataView
21− ( anyPrim
19+-- | `MonadEffect m => ParserT DataView m` context with
20+-- | `Parsing.runParserT`.
21+-- |
22+-- | ### Position
23+-- |
24+-- | In a `DataView` parser, the `Position {index}` counts the number of
25+-- | bytes since the beginning of the input.
26+-- |
27+-- | The `Postion {line,column}` fields are unused and will remain constant *1*.
28+module Parsing.DataView
29+ ( takeN
30+ , takeRest
31+ , eof
32+ , match
33+ , anyPrim
2234 , anyInt8
2335 , anyInt16be
2436 , anyInt16le
@@ -48,96 +60,69 @@ module Text.Parsing.Parser.DataView
4860 , satisfyFloat32le
4961 , satisfyFloat64be
5062 , satisfyFloat64le
51− , takeN
52− , takeRest
53− , eof
54− , match
55− )
56− where
63+ ) where
5764
5865import Prelude
5966
6067import Control.Monad.Trans.Class (lift)
61−import Control.Monad.State (get, put)
68+import Data.ArrayBuffer.DataView (Endian(LE, BE))
69+import Data.ArrayBuffer.DataView (byteLength, byteOffset, get, part, buffer) as DV
70+import Data.ArrayBuffer.Types (DataView, Int16, Int32, Int8, Uint16, Uint32, Uint8, Float32, Float64, ByteLength)
71+import Data.ArrayBuffer.ValueMapping (class BytesPerType, class BinaryValue, class ShowArrayViewType, byteWidth)
72+import Data.Float32 as Float32
6273import Data.Maybe (Maybe(..))
63−import Data.Symbol (SProxy(..), class IsSymbol, reflectSymbol)
64−import Data.Tuple(Tuple(..))
74+import Data.Symbol (class IsSymbol)
75+import Data.Tuple (Tuple(..))
6576import Data.UInt (UInt)
66−import Data.Float32 as Float32
6777import Effect.Class (class MonadEffect, liftEffect)
78+import Parsing (ParseState(..), ParserT, Position(..), consume, fail, getParserT, stateParserT)
79+import Parsing.Combinators (tryRethrow)
6880import Type.Proxy (Proxy(..))
6981
70−import Text.Parsing.Parser (ParserT, ParseState(..), fail)
71−import Text.Parsing.Parser.Pos (Position(..))
72−import Text.Parsing.Parser.Combinators (tryRethrow)
73−import Data.ArrayBuffer.Types
74− ( DataView
75− , Int16
76− , Int32
77− , Int8
78− , Uint16
79− , Uint32
80− , Uint8
81− , Float32
82− , Float64
83− , ByteLength
84− )
85−import Data.ArrayBuffer.ValueMapping
86− ( class BytesPerType
87− , class BinaryValue
88− , class ShowArrayViewType
89− , byteWidth
90− )
91−import Data.ArrayBuffer.DataView
92− ( Endian(LE,BE)
93− )
94−import Data.ArrayBuffer.DataView (byteLength, byteOffset, get, part, buffer) as DV
95−
9682-- | Parse one fixed-bit-width `Data.ArrayBuffer.Types.ArrayViewType` primitive
9783-- | of a given endianness.
9884-- |
9985-- | #### Example
10086-- |
101−-- | Parse a little-endian 32-bit signed integer (4 bytes):
87+-- | Parse a little-endian 32-bit two’s-complement signed integer (4 bytes):
10288-- |
10389-- | anyPrim LE (Proxy :: Proxy Int32)
10490-- |
10591-- | or just use the convenience function `anyInt32le`, see below.
106−anyPrim :: forall a name m t
107− . BinaryValue a t
108− => BytesPerType a
109− => ShowArrayViewType a name
110− => IsSymbol name
111− => MonadEffect m
112− => Endian
113− -> Proxy a
114− -> ParserT DataView m t
92+anyPrim
93+ :: forall a name m t
94+ . BinaryValue a t
95+ => BytesPerType a
96+ => ShowArrayViewType a name
97+ => IsSymbol name
98+ => MonadEffect m
99+ => Endian
100+ -> Proxy a
101+ -> ParserT DataView m t
115102anyPrim endian _ = do
116− ParseState input (Position{line,column}) _ <- get
117− lift (liftEffect (DV.get endian (Proxy :: Proxy a) input (column-1))) >>= case _ of
118− Nothing -> fail $ "Cannot parse " <> reflectSymbol (SProxy :: SProxy name) <>
119− ", unexpected end of DataView"
103+ ParseState input (Position { index }) _ <- getParserT
104+ lift (liftEffect (DV.get endian (Proxy :: Proxy a) input index)) >>= case _ of
105+ Nothing -> fail "anyPrim unexpected end of DataView"
120106 Just i -> do
121− put $ ParseState input (Position {line, column:column + byteWidth (Proxy :: Proxy a) }) true
122− pure i
107+ stateParserT \_ -> Tuple i $ ParseState input (Position { line: 1, column: 1, index: index + byteWidth (Proxy :: Proxy a) }) true
123108
124−-- | Parse one 8-bit signed integer (byte).
109+-- | Parse one 8-bit two’s-complement signed integer (byte).
125110anyInt8 :: forall m. MonadEffect m => ParserT DataView m Int
126111anyInt8 = anyPrim LE (Proxy :: Proxy Int8)
127112
128−-- | Parse one 16-bit big-endian signed integer.
113+-- | Parse one 16-bit big-endian two’s-complement signed integer.
129114anyInt16be :: forall m. MonadEffect m => ParserT DataView m Int
130115anyInt16be = anyPrim BE (Proxy :: Proxy Int16)
131116
132−-- | Parse one 16-bit little-endian signed integer.
117+-- | Parse one 16-bit little-endian two’s-complement signed integer.
133118anyInt16le :: forall m. MonadEffect m => ParserT DataView m Int
134119anyInt16le = anyPrim LE (Proxy :: Proxy Int16)
135120
136−-- | Parse one 32-bit big-endian signed integer.
121+-- | Parse one 32-bit big-endian two’s-complement signed integer.
137122anyInt32be :: forall m. MonadEffect m => ParserT DataView m Int
138123anyInt32be = anyPrim BE (Proxy :: Proxy Int32)
139124
140−-- | Parse one 32-bit little-endian signed integer.
125+-- | Parse one 32-bit little-endian two’s-complement signed integer.
141126anyInt32le :: forall m. MonadEffect m => ParserT DataView m Int
142127anyInt32le = anyPrim LE (Proxy :: Proxy Int32)
143128
@@ -161,19 +146,19 @@ anyUint32be = anyPrim BE (Proxy :: Proxy Uint32)
161146anyUint32le :: forall m. MonadEffect m => ParserT DataView m UInt
162147anyUint32le = anyPrim LE (Proxy :: Proxy Uint32)
163148
164−-- | Parse one 32-bit big-endian floating point number.
149+-- | Parse one 32-bit big-endian IEEE 754 floating-point number.
165150anyFloat32be :: forall m. MonadEffect m => ParserT DataView m Float32.Float32
166151anyFloat32be = anyPrim BE (Proxy :: Proxy Float32)
167152
168−-- | Parse one 32-bit little-endian floating point number.
153+-- | Parse one 32-bit little-endian IEEE 754 floating-point number.
169154anyFloat32le :: forall m. MonadEffect m => ParserT DataView m Float32.Float32
170155anyFloat32le = anyPrim LE (Proxy :: Proxy Float32)
171156
172−-- | Parse one 64-bit big-endian floating point number.
157+-- | Parse one 64-bit big-endian IEEE 754 floating-point number.
173158anyFloat64be :: forall m. MonadEffect m => ParserT DataView m Number
174159anyFloat64be = anyPrim BE (Proxy :: Proxy Float64)
175160
176−-- | Parse one 64-bit little-endian floating point number.
161+-- | Parse one 64-bit little-endian IEEE 754 floating-point number.
177162anyFloat64le :: forall m. MonadEffect m => ParserT DataView m Number
178163anyFloat64le = anyPrim LE (Proxy :: Proxy Float64)
179164
@@ -186,22 +171,22 @@ anyFloat64le = anyPrim LE (Proxy :: Proxy Float64)
186171-- | satisfy LE (Proxy :: Proxy Int32) (_ == 3)
187172-- |
188173-- | or just use the convenience function `satisfyInt32le`, see below.
189−satisfy :: forall a name m t
190− . BinaryValue a t
191− => BytesPerType a
192− => ShowArrayViewType a name
193− => IsSymbol name
194− => Show t
195− => MonadEffect m
196− => Endian
197− -> Proxy a
198− -> (t -> Boolean)
199− -> ParserT DataView m t
174+satisfy
175+ :: forall a name m t
176+ . BinaryValue a t
177+ => BytesPerType a
178+ => ShowArrayViewType a name
179+ => IsSymbol name
180+ => Show t
181+ => MonadEffect m
182+ => Endian
183+ -> Proxy a
184+ -> (t -> Boolean)
185+ -> ParserT DataView m t
200186satisfy endian proxy f = tryRethrow do
201187 i <- anyPrim endian proxy
202188 if f i then pure i
203− else fail $ reflectSymbol (SProxy :: SProxy name) <>
204− " " <> show i <> " did not satisfy predicate."
189+ else fail "satisfy predicate failed"
205190
206191-- | Parse one 8-bit signed integer that satisfies the given predicate.
207192satisfyInt8 :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
@@ -270,29 +255,32 @@ satisfyFloat64le = satisfy LE (Proxy :: Proxy Float64)
270255-- |
271256takeN :: forall m. MonadEffect m => ByteLength -> ParserT DataView m DataView
272257takeN n = do
273− ParseState input (Position {line,column}) _ <- get
274− unless (n >= 0) $ fail $ "Cannot take negative number of bytes."
275− unless (column + n - 1 <= DV.byteLength input) $
276− fail $ "Cannot take " <> show n <> " bytes, only " <>
277− show (DV.byteLength input - column + 1) <> " bytes remain."
278− p <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + (column-1)) n
279− put $ ParseState input (Position {line,column:column+n}) true
280− pure p
258+ ParseState input (Position { index }) _ <- getParserT
259+ if (n < 0) then
260+ fail $ "takeN cannot take negative number of bytes"
261+ else if (index + n + 1 > DV.byteLength input) then
262+ fail "takeN expected N bytes"
263+ else do
264+ p <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + index) n
265+ stateParserT \_ -> Tuple p $ ParseState input (Position { line: 1, column: 1, index: index + n }) true
281266
282267-- | Take the rest of the input, however many bytes remain. Always succeeds.
283268takeRest :: forall m. MonadEffect m => ParserT DataView m DataView
284269takeRest = do
285− ParseState input (Position {line,column}) _ <- get
286− p <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + (column-1))
287− (DV.byteLength input - (column-1))
288− put $ ParseState input (Position {line,column:DV.byteLength input + 1}) true
289− pure p
270+ ParseState input (Position { index }) _ <- getParserT
271+ p <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + index)
272+ (DV.byteLength input - index)
273+ stateParserT \_ -> Tuple p $ ParseState input (Position { line: 1, column: 1, index: DV.byteLength input + 1 }) true
290274
291−-- | Parse succeeds at the end of the input DataView. Consumes no input.
275+-- | Parse succeeds at the end of the input DataView.
292276eof :: forall m. Monad m => ParserT DataView m Unit
293277eof = do
294− ParseState input (Position {column}) _ <- get
295− unless (column > DV.byteLength input) $ fail "Expected end of DataView"
278+ ParseState input (Position { index }) _ <- getParserT
279+ if (index + 1 > DV.byteLength input) then do
280+ -- We must consume so this combines correctly with notFollowedBy
281+ consume
282+ else do
283+ fail "eof expected end of DataView"
296284
297285-- | The
298286-- | [famous `match`](http://www.serpentine.com/blog/2014/05/31/attoparsec/#from-strings-to-buffers-and-cursors)
@@ -302,23 +290,22 @@ eof = do
302290-- | was consumed while it was being parsed.
303291match :: forall a m. MonadEffect m => ParserT DataView m a -> ParserT DataView m (Tuple DataView a)
304292match p = do
305− ParseState input (Position {column:column0}) _ <- get
293+ ParseState input (Position { index: index0 }) _ <- getParserT
306294 x <- p
307− ParseState _ (Position {column:column1}) _ <- get
308− part <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + (column0-1)) (column1-column0)
295+ ParseState _ (Position { index: index1 }) _ <- getParserT
296+ part <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + index0) (index1 - index0)
309297 pure $ Tuple part x
310298
311299-- ****************************** Notes ****************************************
312300--
313−-- The `initialPostion` in a `ParserT` is `Postion{line:1,column:1)`.
314−-- We keep `line` invariant and use `column-1` to denote the offset into the
315−-- `DataView`, that's why there are so many plus 1 and minus 1 operations
316−-- in this module.
317−-- https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html
318−--
319301-- We cannot have a primitive parser which parses a `DataView` and produces
320302-- an `ArrayView` (a Javascript Typed Array). Javascript DataViews are
321303-- endianess-aware, but Javascript Typed Arrays assume the native endianness
322304-- of the local machine. DataViews are intended to be used for I/O, ArrayViews
323305-- are intended to be used internally for graphics in a process, and they're
324306-- not intended to be both applied to the same ArrayBuffer.
307+-- The exception: `Uint8Array`
308+--
309+-- The failure messages are all constant strings form performance reasons.
310+-- If failure messages were constructed lazily then we could have more
311+-- descriptive messages.