git.iko.soy/rowtype-yoga/purescript-parsing-dataview
on master help sign in
15 files changed+810−573
since splitsnapshots
unifiedsplit
.github/workflows/push-build.yml+40−9 CHANGELOG.md+39 DEVELOPMENT.md−43 LICENSE+17−104 LICENSE_THIRDPARTY+87 README.md+53−44 bower.json+15−5 packages.dhall+2−3 shell.nix−26 test.dhall → spago-dev.dhall+6 spago.dhall+14−4 src/Parsing/DataView.Basic.purs+51 src/Parsing/DataView.purs+353 src/Text/Parsing/Parser/DataView.purs−311 test/Main.purs+133−24
.github/workflows/push-build.yml+40−9
@@ -1,17 +1,48 @@
11name: CI
22
3−on: [push]
3+on:
4+ push:
5+ branches: [master]
6+ pull_request:
7+ branches: [master]
48
59jobs:
610 build:
7−
811 runs-on: ubuntu-latest
912
1013 steps:
11− - uses: actions/checkout@v2
12− - uses: actions/setup-node@v1
13− - run: npm install -g purescript
14− - run: npm install -g spago
15− - name: build
16− run: |
17− spago -x test.dhall test
14+ - uses: actions/checkout@v2
15+
16+ - name: Set up a PureScript toolchain
17+ uses: purescript-contrib/setup-purescript@main
18+ with:
19+ purescript: "unstable"
20+ purs-tidy: "latest"
21+
22+ - name: Cache PureScript dependencies
23+ uses: actions/cache@v2
24+ with:
25+ key: ${{ runner.os }}-spago-${{ hashFiles('**/*.dhall') }}
26+ path: |
27+ .spago
28+ output
29+ - name: Install dependencies
30+ run: spago install
31+
32+ - name: Build source
33+ run: spago build --no-install --purs-args '--censor-lib --strict'
34+
35+ - name: Install dev dependencies
36+ run: spago -x spago-dev.dhall install
37+
38+ - name: Run tests
39+ run: spago -x spago-dev.dhall test --no-install
40+
41+ - name: Check formatting
42+ run: purs-tidy check src test
43+
44+ - name: Verify Bower & Pulp
45+ run: |
46+ npm install bower pulp@16.0.0-0
47+ npx bower install
48+ npx pulp build -- --censor-lib --strict
CHANGELOG.mdnew file+39
@@ -0,0 +1,39 @@
1+# Changelog
2+
3+## v3.2.0
4+
5+- Build for PureScript v0.15.4
6+- New combinator: `anyTill`
7+- New parser: `anyCodePointUTF8`
8+- Move to rowtype-yoga org
9+
10+## v3.1.0
11+
12+Bugfix `takeN`.
13+
14+## v3.0.0
15+
16+### Breaking changes
17+
18+- Build for PureScript v0.15.0 with __parsing__ v9.0.0.
19+
20+## v2.1.0 2021-11-24
21+
22+Licensing cleanup.
23+
24+## v2.0.0 2021-07-21
25+
26+Build for PureScript v0.14.0.
27+
28+Added the `match` combinator.
29+
30+### Breaking changes
31+
32+Some typeclass constraints on the public API have changed due to changes
33+in the __arraybuffer__ package v11. For the most part we don’t expect
34+this will require any changes to code which depends on this package. If
35+you are using the `anyPrim` function you might have to change `AProxy` to
36+`Prelude.Proxy`. See for more details:
37+
38+* https://github.com/purescript-contrib/purescript-arraybuffer/blob/main/CHANGELOG.md#v1100
39+
DEVELOPMENT.mddeleted−43
@@ -1,43 +0,0 @@
1−# Development Notes
2−
3−All of the commands needed for development are in the `shell.nix` environment.
4−
5−```
6−$ nix-shell
7−```
8−
9−## Edit
10−
11−The `psc-ide` command is available for the [VS Code Purescript IDE extension](https://github.com/nwolverson/vscode-ide-purescript.git).
12−
13−```
14−[nix-shell:]$ code .
15−```
16−
17−## Build
18−
19−```
20−[nix-shell:]$ spago build
21−```
22−
23−## Test
24−
25−The test dependencies are specified seperately in `test.dhall`.
26−
27−```
28−[nix-shell:]$ spago -x test.dhall test
29−```
30−
31−## Publishing to Pursuit with `spago`
32−
33−[Publishing with `spago`](https://github.com/purescript/spago#publish-my-library).
34−
35−```
36−[nix-shell:]$ spago bump-version --no-dry-run major
37−[nix-shell:]$ npm install pulp
38−[nix-shell:]$ node node_modules/pulp/index.js publish
39−```
40−
41−## Bower
42−
43−The `bower.json` is generated by running `spago bump-version`, do not edit it.
LICENSE+17−104
@@ -3,107 +3,20 @@ Copyright 2020 James Dawson Brock
33Redistribution and use in source and binary forms, with or without
44modification, are permitted provided that the following conditions are met:
55
6−* Redistributions of source code must retain the above copyright notice,
7− this list of conditions and the following disclaimer.
8−* Redistributions in binary form must reproduce the above copyright
9− notice, this list of conditions and the following disclaimer in the
10− documentation and/or other materials provided with the distribution.
11−
12−This software is provided by the copyright holders "as is" and any express or
13−implied warranties, including, but not limited to, the implied warranties of
14−merchantability and fitness for a particular purpose are disclaimed. In no
15−event shall the copyright holders be liable for any direct, indirect,
16−incidental, special, exemplary, or consequential damages (including, but not
17−limited to, procurement of substitute goods or services; loss of use, data,
18−or profits; or business interruption) however caused and on any theory of
19−liability, whether in contract, strict liability, or tort (including
20−negligence or otherwise) arising in any way out of the use of this software,
21−even if advised of the possibility of such damage.
22−
23−This library is based on purescript-parsing, copyright follows.
24−
25−--------------------------------------------------------------------------------
26−
27−Copyright 2014-2016 PureScript
28−
29−Redistribution and use in source and binary forms, with or without
30−modification, are permitted provided that the following conditions are met:
31−
32−* Redistributions of source code must retain the above copyright notice,
33− this list of conditions and the following disclaimer.
34−* Redistributions in binary form must reproduce the above copyright
35− notice, this list of conditions and the following disclaimer in the
36− documentation and/or other materials provided with the distribution.
37−
38−This software is provided by the copyright holders "as is" and any express or
39−implied warranties, including, but not limited to, the implied warranties of
40−merchantability and fitness for a particular purpose are disclaimed. In no
41−event shall the copyright holders be liable for any direct, indirect,
42−incidental, special, exemplary, or consequential damages (including, but not
43−limited to, procurement of substitute goods or services; loss of use, data,
44−or profits; or business interruption) however caused and on any theory of
45−liability, whether in contract, strict liability, or tort (including
46−negligence or otherwise) arising in any way out of the use of this software,
47−even if advised of the possibility of such damage.
48−
49−-------------------------------------------------------------------------------
50−
51−This library uses code adapted from the Haskell libraries parsec and indents.
52−Their licenses are reproduced below:
53−
54−'parsec' license:
55−
56− Copyright 1999-2000, Daan Leijen; 2007, Paolo Martini. All rights reserved.
57−
58− Redistribution and use in source and binary forms, with or without
59− modification, are permitted provided that the following conditions are met:
60−
61− * Redistributions of source code must retain the above copyright notice,
62− this list of conditions and the following disclaimer.
63− * Redistributions in binary form must reproduce the above copyright
64− notice, this list of conditions and the following disclaimer in the
65− documentation and/or other materials provided with the distribution.
66−
67− This software is provided by the copyright holders "as is" and any express or
68− implied warranties, including, but not limited to, the implied warranties of
69− merchantability and fitness for a particular purpose are disclaimed. In no
70− event shall the copyright holders be liable for any direct, indirect,
71− incidental, special, exemplary, or consequential damages (including, but not
72− limited to, procurement of substitute goods or services; loss of use, data,
73− or profits; or business interruption) however caused and on any theory of
74− liability, whether in contract, strict liability, or tort (including
75− negligence or otherwise) arising in any way out of the use of this software,
76− even if advised of the possibility of such damage.
77−
78−'indents' license:
79−
80− Copyright (c)2010, Sam Anklesaria
81−
82− All rights reserved.
83−
84− Redistribution and use in source and binary forms, with or without
85− modification, are permitted provided that the following conditions are met:
86−
87− * Redistributions of source code must retain the above copyright
88− notice, this list of conditions and the following disclaimer.
89−
90− * Redistributions in binary form must reproduce the above
91− copyright notice, this list of conditions and the following
92− disclaimer in the documentation and/or other materials provided
93− with the distribution.
94−
95− * Neither the name of Sam Anklesaria nor the names of other
96− contributors may be used to endorse or promote products derived
97− from this software without specific prior written permission.
98−
99− THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
100− "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
101− LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
102− A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
103− OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
104− SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
105− LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
106− DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
107− THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
108− (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
109− OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6+1. Redistributions of source code must retain the above copyright notice, this
7+ list of conditions and the following disclaimer.
8+
9+2. Redistributions in binary form must reproduce the above copyright notice,
10+ this list of conditions and the following disclaimer in the documentation
11+ and/or other materials provided with the distribution.
12+
13+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LICENSE_THIRDPARTYnew file+87
@@ -0,0 +1,87 @@
1+This library is based on purescript-parsing, copyright follows.
2+
3+--------------------------------------------------------------------------------
4+
5+Copyright 2014-2016 PureScript
6+
7+Redistribution and use in source and binary forms, with or without
8+modification, are permitted provided that the following conditions are met:
9+
10+* Redistributions of source code must retain the above copyright notice,
11+ this list of conditions and the following disclaimer.
12+* Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+This software is provided by the copyright holders "as is" and any express or
17+implied warranties, including, but not limited to, the implied warranties of
18+merchantability and fitness for a particular purpose are disclaimed. In no
19+event shall the copyright holders be liable for any direct, indirect,
20+incidental, special, exemplary, or consequential damages (including, but not
21+limited to, procurement of substitute goods or services; loss of use, data,
22+or profits; or business interruption) however caused and on any theory of
23+liability, whether in contract, strict liability, or tort (including
24+negligence or otherwise) arising in any way out of the use of this software,
25+even if advised of the possibility of such damage.
26+
27+-------------------------------------------------------------------------------
28+
29+This library uses code adapted from the Haskell libraries parsec and indents.
30+Their licenses are reproduced below:
31+
32+'parsec' license:
33+
34+ Copyright 1999-2000, Daan Leijen; 2007, Paolo Martini. All rights reserved.
35+
36+ Redistribution and use in source and binary forms, with or without
37+ modification, are permitted provided that the following conditions are met:
38+
39+ * Redistributions of source code must retain the above copyright notice,
40+ this list of conditions and the following disclaimer.
41+ * Redistributions in binary form must reproduce the above copyright
42+ notice, this list of conditions and the following disclaimer in the
43+ documentation and/or other materials provided with the distribution.
44+
45+ This software is provided by the copyright holders "as is" and any express or
46+ implied warranties, including, but not limited to, the implied warranties of
47+ merchantability and fitness for a particular purpose are disclaimed. In no
48+ event shall the copyright holders be liable for any direct, indirect,
49+ incidental, special, exemplary, or consequential damages (including, but not
50+ limited to, procurement of substitute goods or services; loss of use, data,
51+ or profits; or business interruption) however caused and on any theory of
52+ liability, whether in contract, strict liability, or tort (including
53+ negligence or otherwise) arising in any way out of the use of this software,
54+ even if advised of the possibility of such damage.
55+
56+'indents' license:
57+
58+ Copyright (c)2010, Sam Anklesaria
59+
60+ All rights reserved.
61+
62+ Redistribution and use in source and binary forms, with or without
63+ modification, are permitted provided that the following conditions are met:
64+
65+ * Redistributions of source code must retain the above copyright
66+ notice, this list of conditions and the following disclaimer.
67+
68+ * Redistributions in binary form must reproduce the above
69+ copyright notice, this list of conditions and the following
70+ disclaimer in the documentation and/or other materials provided
71+ with the distribution.
72+
73+ * Neither the name of Sam Anklesaria nor the names of other
74+ contributors may be used to endorse or promote products derived
75+ from this software without specific prior written permission.
76+
77+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
78+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
79+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
80+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
81+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
82+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
83+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
84+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
85+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
86+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
87+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.md+53−44
@@ -1,24 +1,22 @@
11# purescript-parsing-dataview
22
3−[![CI](https://github.com/jamesdbrock/purescript-parsing-dataview/workflows/CI/badge.svg?branch=master)](https://github.com/jamesdbrock/purescript-parsing-dataview/actions)
3+[![CI](https://github.com/rowtype-yoga/purescript-parsing-dataview/workflows/CI/badge.svg?branch=master)](https://github.com/rowtype-yoga/purescript-parsing-dataview/actions)
44[![Pursuit](http://pursuit.purescript.org/packages/purescript-parsing-dataview/badge)](http://pursuit.purescript.org/packages/purescript-parsing-dataview/)
5+[![Maintainer: jamesdbrock](https://img.shields.io/badge/maintainer-jamesdbrock-teal.svg)](https://github.com/jamesdbrock)
56
6−Primitive parsers for parsing
7−`DataView`s on Javascript `ArrayBuffer`s with the package
8−[__purescript-parsing__](https://pursuit.purescript.org/packages/purescript-parsing/).
7+Primitive parsers for
8+`DataView`s on JavaScript `ArrayBuffer`s with the package
9+[__parsing__](https://pursuit.purescript.org/packages/purescript-parsing/).
910
10−With this package, the input stream support of __purescript-parsing__
11−roughly matches the built-in stream support of __Megaparsec__:
11+With this package, the input stream support of __parsing__
12+is similar to the built-in stream support of [__Megaparsec__](https://hackage.haskell.org/package/megaparsec):
1213
13−| Stream type | purescript-parsing | Megaparsec |
14+| Stream type | parsing | Megaparsec |
1415|----|-----|----|
15−| UTF-16 strings | String | Text |
16+| UTF-16 strings | String | Text < v2.0|
17+| UTF-8 strings | __DataView__ | Text ≥ v2.0 |
1618| Listy strings | Token | String |
17−| Binary blobs | __Text.Parsing.Parser.DataView__ | ByteString |
18−
19−Perhaps some day this package can be
20−[merged into __purescript-parsing__](https://github.com/purescript-contrib/purescript-parsing/issues/88),
21−but for now it has too many non-*purescript-contrib* dependencies.
19+| Binary blobs | __DataView__ | ByteString |
2220
2321## Usage examples
2422
@@ -28,11 +26,14 @@ Parse values out of a `dataview :: Data.ArrayBuffer.Types.DataView`. All
2826
2927### Parse two numbers
3028
31−Parse two big-endian IEEE 754 double-precision floats.
29+Parse two big-endian IEEE 754 double-precision `Number`s.
3230
3331```purescript
32+import Parsing (runParserT)
33+import Parsing.DataView (anyFloat64be)
34+
3435do
35− result <- Text.Parsing.Parser.runParserT dataview $ do
36+ result <- runParserT dataview do
3637 float1 <- anyFloat64be
3738 float2 <- anyFloat64be
3839 pure $ Tuple float1 float2
@@ -40,52 +41,52 @@ do
4041
4142### Parse an array
4243
43−Parse an array of `n` 32-bit signed integers.
44+Parse an array of `n` 32-bit big-endian signed `Int`s.
4445
4546```purescript
47+import Parsing (runParserT)
48+import Parsing.DataView (anyUint32be)
49+import Data.Unfoldable (replicateA)
50+
4651do
47− result <- Text.Parsing.Parser.runParserT dataview $ replicateA n anyInt32be
52+ result <- runParserT dataview $ replicateA n anyInt32be
4853```
4954
50−### Parse UTF8
55+### Parse UTF-8
5156
52−Parse a `String` as UTF8 with a length prefix in a
53−way that's compatible with the
54−[`Binary.Put.putStringUtf8`](https://hackage.haskell.org/package/binary/docs/Data-Binary-Put.html#v:putStringUtf8)
55−function from the Haskell
56−[__binary__](https://hackage.haskell.org/package/binary)
57−library.
57+Parse a UTF-8 `String` with a length prefix.
5858
5959We give this as an example, rather than supporting it in the library, because
6060it depends on
61−[`Data.TextDecoding.decodeUtf8`](https://pursuit.purescript.org/packages/purescript-text-encoding/docs/Data.TextDecoding#v:decodeUtf8).
61+[__web-encoding__](https://pursuit.purescript.org/packages/purescript-web-encoding) for UTF-8.
6262
6363```purescript
64+import Control.Monad.Except (ExceptT)
65+import Data.ArrayBuffer.Cast (toUint8Array)
66+import Effect.Exception (catchException, message)
67+import Parsing (runParserT, liftExceptT)
68+import Parsing.DataView (anyInt32be, takeN)
69+import Web.Encoding.TextDecoder as TextDecoder
70+import Web.Encoding.UtfLabel as UtfLabel
71+
6472do
65− result <- Text.Parsing.Parser.runParserT dataview $ do
66− -- Parse 32 bits of the big-endian 64-bit length prefix.
67− _ <- anyUint32be
68− length <- anyUint32be
69− stringview <- takeN $ UInt.toInt length
70− stringarray <- liftEffect $ mkTypedArray stringview
71− case Data.TextDecoding.decodeUtf8 stringarray of
72− Left err -> Data.Parsing.Parser.fail $ show err
73− Right s -> pure s
74−
75−where
76− mkTypedArray :: Data.ArrayBuffer.Types.DataView -> Effect Data.ArrayBuffer.Types.Uint8Array
77− mkTypedArray dv = do
78− let buffer = Data.ArrayBuffer.DataView.buffer dv
79− byteOffset = Data.ArrayBuffer.DataView.byteOffset dv
80− byteLength = Data.ArrayBuffer.DataView.byteLength dv
81− Data.ArrayBuffer.Typed.part buffer byteOffset byteLength
73+ textDecoder <- TextDecoder.new UtfLabel.utf8
74+
75+ result <- runParserT dataview do
76+ -- First parse a 32-bit big-endian length prefix for the length
77+ -- of the UTF-8 string in bytes.
78+ length <- anyInt32be
79+ stringview <- takeN length
80+ stringarray <- lift $ liftEffect $ toUint8Array stringview
81+ liftExceptT $ ExceptT $ catchException (pure <<< Left <<< message) do
82+ Right <$> TextDecoder.decode stringarray textDecoder
8283```
8384
8485## Serialization
8586
8687This package is for reading (`DataView`s on) `ArrayBuffer`s, not writing
8788them. See the package
88−[__purescript-arraybuffer-builder__](https://pursuit.purescript.org/packages/purescript-arraybuffer-builder/)
89+[__arraybuffer-builder__](https://pursuit.purescript.org/packages/purescript-arraybuffer-builder/)
8990for a way to
9091serialize and build `ArrayBuffer`s.
9192
@@ -93,4 +94,12 @@ serialize and build `ArrayBuffer`s.
9394## References
9495
9596* [MDN `ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)
96−* [MDN `DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)
97+* [MDN `DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)
98+
99+## Development
100+
101+Run the tests with the development `spago` file:
102+
103+```
104+spago -x spago-dev.dhall test
105+```
bower.json+15−5
@@ -1,11 +1,11 @@
11{
22 "name": "purescript-parsing-dataview",
33 "license": [
4− "BSD-3-Clause"
4+ "BSD-2-Clause"
55 ],
66 "repository": {
77 "type": "git",
8− "url": "https://github.com/jamesdbrock/purescript-parsing-dataview"
8+ "url": "https://github.com/rowtype-yoga/purescript-parsing-dataview"
99 },
1010 "ignore": [
1111 "**/.*",
@@ -14,8 +14,18 @@
1414 "output"
1515 ],
1616 "dependencies": {
17− "purescript-arraybuffer": "^v10.0.2",
18− "purescript-arraybuffer-types": "^v2.0.0",
19− "purescript-parsing": "^v5.0.3"
17+ "purescript-arraybuffer": "^v13.1.1",
18+ "purescript-arraybuffer-types": "^v3.0.2",
19+ "purescript-effect": "^v4.0.0",
20+ "purescript-enums": "^v6.0.1",
21+ "purescript-float32": "^v2.0.0",
22+ "purescript-maybe": "^v6.0.0",
23+ "purescript-parsing": "^v10.2.0",
24+ "purescript-prelude": "^v6.0.1",
25+ "purescript-strings": "^v6.0.1",
26+ "purescript-tailrec": "^v6.1.0",
27+ "purescript-transformers": "^v6.0.0",
28+ "purescript-tuples": "^v7.0.0",
29+ "purescript-uint": "^v7.0.0"
2030 }
2131}
packages.dhall+2−3
@@ -116,10 +116,9 @@ let additions =
116116 }
117117-------------------------------
118118-}
119−
120−
121119let upstream =
122− https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20200708/packages.dhall sha256:df5b0f1ae92d4401404344f4fb2a7a3089612c9f30066dcddf9eaea4fe780e29
120+ https://github.com/purescript/package-sets/releases/download/psc-0.15.4-20221202/packages.dhall
121+ sha256:4e2f2e060ab73b119eeb55fe9bc75168b380fc5e0696d2cc2941ac674b32cb3c
123122
124123let overrides = {=}
125124
shell.nixdeleted−26
@@ -1,26 +0,0 @@
1−{ pkgs ? import <nixpkgs> { } }:
2−let
3− easy-ps = import
4− (pkgs.fetchFromGitHub {
5− owner = "justinwoo";
6− repo = "easy-purescript-nix";
7− rev = "0ba91d9aa9f7421f6bfe4895677159a8a999bf20";
8− sha256 = "1baq7mmd3vjas87f0gzlq83n2l1h3dlqajjqr7fgaazpa9xgzs7q";
9− }) {
10− inherit pkgs;
11− };
12−in
13−pkgs.mkShell {
14− buildInputs = [
15− easy-ps.purs-0_13_8
16− easy-ps.spago
17− pkgs.nodejs-13_x
18− pkgs.nodePackages.bower
19− # pkgs.nodePackages.pulp
20− #
21− # The pulp nix derivation doesn't work, so to run pulp:
22− # $ npm install pulp
23− # $ node node_modules/pulp/index.js
24− ];
25− LC_ALL = "C.UTF-8"; # https://github.com/purescript/spago/issues/507
26−}
test.dhall → spago-dev.dhallrenamed+6
@@ -15,5 +15,11 @@ in conf //
1515 , dependencies = conf.dependencies #
1616 [ "assert"
1717 , "parsing"
18+ , "console"
19+ , "foldable-traversable"
20+ , "lists"
21+ , "either"
22+ , "web-encoding"
23+ , "exceptions"
1824 ]
1925 }
spago.dhall+14−4
@@ -2,12 +2,22 @@
22-}
33{ name = "parsing-dataview"
44, dependencies =
5− [ "parsing"
5+ [ "arraybuffer"
66 , "arraybuffer-types"
7− , "arraybuffer"
7+ , "effect"
8+ , "enums"
9+ , "float32"
10+ , "maybe"
11+ , "parsing"
12+ , "prelude"
13+ , "strings"
14+ , "tailrec"
15+ , "transformers"
16+ , "tuples"
17+ , "uint"
818 ]
919, packages = ./packages.dhall
1020, sources = [ "src/**/*.purs" ]
11−, license = "BSD-3-Clause"
12−, repository = "https://github.com/jamesdbrock/purescript-parsing-dataview"
21+, license = "BSD-2-Clause"
22+, repository = "https://github.com/rowtype-yoga/purescript-parsing-dataview"
1323}
src/Parsing/DataView.Basic.pursnew file+51
@@ -0,0 +1,51 @@
1+-- | Basic `DataView` parsers derived from primitive `DataView` parsers.
2+-- |
3+-- | All of these parsers will consume when they succeed.
4+-- |
5+-- | All of these parsers will not consume and will automatically
6+-- | backtrack when they fail.
7+module Parsing.DataView.Basic
8+ ( anyCodePointUTF8
9+ ) where
10+
11+import Prelude
12+
13+import Data.ArrayBuffer.Types (DataView)
14+import Data.Enum (toEnum)
15+import Data.String (CodePoint)
16+import Data.UInt (toInt)
17+import Effect.Class (class MonadEffect)
18+import Parsing (ParserT, fail, liftMaybe)
19+import Parsing.Combinators (tryRethrow)
20+import Parsing.DataView (anyUint8)
21+
22+-- | Decode one UTF-8 code point, *1—4* bytes.
23+anyCodePointUTF8
24+ :: forall m
25+ . MonadEffect m
26+ => ParserT DataView m CodePoint
27+anyCodePointUTF8 = tryRethrow do
28+ -- https://en.wikipedia.org/wiki/UTF-8#Encoding
29+ c0 <- toInt <$> anyUint8
30+ if c0 < 128 then do
31+ liftMaybe (\_ -> "Invalid CodePoint " <> show c0) (toEnum c0)
32+ else if c0 < 192 then fail "Invalid UTF-8 encoding"
33+ else if c0 < 224 then do
34+ c1 <- toInt <$> anyUint8
35+ if c1 < 128 || c1 > 191 then fail "Invalid UTF-8 encoding" else pure unit
36+ let codepoint = (64 * (c0 `mod` 32)) + (c1 `mod` 64)
37+ liftMaybe (\_ -> "Invalid CodePoint " <> show codepoint) (toEnum codepoint)
38+ else if c0 < 240 then do
39+ c1 <- toInt <$> anyUint8
40+ c2 <- toInt <$> anyUint8
41+ if c1 < 128 || c1 > 191 || c2 < 128 || c2 > 191 then fail "Invalid UTF-8 encoding" else pure unit
42+ let codepoint = (4096 * (c0 `mod` 16)) + (64 * (c1 `mod` 64)) + (c2 `mod` 64)
43+ liftMaybe (\_ -> "Invalid CodePoint " <> show codepoint) (toEnum codepoint)
44+ else if c0 < 248 then do
45+ c1 <- toInt <$> anyUint8
46+ c2 <- toInt <$> anyUint8
47+ c3 <- toInt <$> anyUint8
48+ if c1 < 128 || c1 > 191 || c2 < 128 || c2 > 191 || c3 < 128 || c3 > 191 then fail "Invalid UTF-8 encoding" else pure unit
49+ let codepoint = (262144 * (c0 `mod` 8)) + (4096 * (c1 `mod` 64)) + (64 * (c2 `mod` 64)) + (c3 `mod` 64)
50+ liftMaybe (\_ -> "Invalid CodePoint " <> show codepoint) (toEnum codepoint)
51+ else fail "Invalid UTF-8 encoding"
src/Parsing/DataView.pursnew file+353
@@ -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.
src/Text/Parsing/Parser/DataView.pursdeleted−311
@@ -1,311 +0,0 @@
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__.
4−-- | See the package README for usage examples.
5−-- |
6−-- | 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`.
10−-- |
11−-- | For operations for working with `ArrayBuffer` and `DataView`, see
12−-- | module
13−-- | [`Data.ArrayBuffer.DataView`](https://pursuit.purescript.org/packages/purescript-arraybuffer/docs/Data.ArrayBuffer.DataView)
14−-- | in package __purescript-arraybuffer__.
15−-- |
16−-- | Reading from an `ArrayBuffer` is an `Effect`ful activity, so
17−-- | 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
22− , anyInt8
23− , anyInt16be
24− , anyInt16le
25− , anyInt32be
26− , anyInt32le
27− , anyUint8
28− , anyUint16be
29− , anyUint16le
30− , anyUint32be
31− , anyUint32le
32− , anyFloat32be
33− , anyFloat32le
34− , anyFloat64be
35− , anyFloat64le
36− , satisfy
37− , satisfyInt8
38− , satisfyInt16be
39− , satisfyInt16le
40− , satisfyInt32be
41− , satisfyInt32le
42− , satisfyUint8
43− , satisfyUint16be
44− , satisfyUint16le
45− , satisfyUint32be
46− , satisfyUint32le
47− , satisfyFloat32be
48− , satisfyFloat32le
49− , satisfyFloat64be
50− , satisfyFloat64le
51− , takeN
52− , takeRest
53− , eof
54− )
55− where
56−
57−import Prelude
58−
59−import Control.Monad.Trans.Class (lift)
60−import Control.Monad.State (get, put)
61−import Data.Maybe (Maybe(..))
62−import Data.Symbol (SProxy(..), class IsSymbol, reflectSymbol)
63−import Data.Typelevel.Num (class Nat, toInt')
64−import Data.UInt (UInt)
65−import Data.Float32 as Float32
66−import Effect.Class (class MonadEffect, liftEffect)
67−import Type.Proxy (Proxy(..))
68−
69−import Text.Parsing.Parser (ParserT, ParseState(..), fail)
70−import Text.Parsing.Parser.Pos (Position(..))
71−import Text.Parsing.Parser.Combinators (tryRethrow)
72−import Data.ArrayBuffer.Types
73− ( DataView
74− , Int16
75− , Int32
76− , Int8
77− , Uint16
78− , Uint32
79− , Uint8
80− , Float32
81− , Float64
82− , ByteLength
83− )
84−import Data.ArrayBuffer.ValueMapping
85− ( class BytesPerValue
86− , class BinaryValue
87− , class ShowArrayViewType
88− )
89−import Data.ArrayBuffer.DataView
90− ( AProxy(..)
91− , Endian(LE,BE)
92− )
93−import Data.ArrayBuffer.DataView (byteLength, byteOffset, get, part, buffer) as DV
94−
95−-- | Parse one fixed-bit-width `Data.ArrayBuffer.Types.ArrayViewType` primitive
96−-- | of a given endianness.
97−-- |
98−-- | #### Example
99−-- |
100−-- | Parse a little-endian 32-bit signed integer (4 bytes):
101−-- |
102−-- | anyPrim LE (AProxy :: AProxy Int32)
103−-- |
104−-- | or just use the convenience function `anyInt32le`, see below.
105−anyPrim :: forall a name b m t
106− . BinaryValue a t
107− => BytesPerValue a b
108− => ShowArrayViewType a name
109− => IsSymbol name
110− => Nat b
111− => MonadEffect m
112− => Endian
113− -> AProxy a
114− -> ParserT DataView m t
115−anyPrim endian aproxy = do
116− ParseState input (Position{line,column}) _ <- get
117− lift (liftEffect (DV.get endian (AProxy :: AProxy a) input (column-1))) >>= case _ of
118− Nothing -> fail $ "Cannot parse " <> reflectSymbol (SProxy :: SProxy name) <>
119− ", unexpected end of DataView"
120− Just i -> do
121− put $ ParseState input (Position {line, column:column + toInt' (Proxy :: Proxy b) }) true
122− pure i
123−
124−-- | Parse one 8-bit signed integer (byte).
125−anyInt8 :: forall m. MonadEffect m => ParserT DataView m Int
126−anyInt8 = anyPrim LE (AProxy :: AProxy Int8)
127−
128−-- | Parse one 16-bit big-endian signed integer.
129−anyInt16be :: forall m. MonadEffect m => ParserT DataView m Int
130−anyInt16be = anyPrim BE (AProxy :: AProxy Int16)
131−
132−-- | Parse one 16-bit little-endian signed integer.
133−anyInt16le :: forall m. MonadEffect m => ParserT DataView m Int
134−anyInt16le = anyPrim LE (AProxy :: AProxy Int16)
135−
136−-- | Parse one 32-bit big-endian signed integer.
137−anyInt32be :: forall m. MonadEffect m => ParserT DataView m Int
138−anyInt32be = anyPrim BE (AProxy :: AProxy Int32)
139−
140−-- | Parse one 32-bit little-endian signed integer.
141−anyInt32le :: forall m. MonadEffect m => ParserT DataView m Int
142−anyInt32le = anyPrim LE (AProxy :: AProxy Int32)
143−
144−-- | Parse one 8-bit unsigned integer (octet).
145−anyUint8 :: forall m. MonadEffect m => ParserT DataView m UInt
146−anyUint8 = anyPrim LE (AProxy :: AProxy Uint8)
147−
148−-- | Parse one 16-bit big-endian unsigned integer.
149−anyUint16be :: forall m. MonadEffect m => ParserT DataView m UInt
150−anyUint16be = anyPrim BE (AProxy :: AProxy Uint16)
151−
152−-- | Parse one 16-bit little-endian unsigned integer.
153−anyUint16le :: forall m. MonadEffect m => ParserT DataView m UInt
154−anyUint16le = anyPrim LE (AProxy :: AProxy Uint16)
155−
156−-- | Parse one 32-bit big-endian unsigned integer.
157−anyUint32be :: forall m. MonadEffect m => ParserT DataView m UInt
158−anyUint32be = anyPrim BE (AProxy :: AProxy Uint32)
159−
160−-- | Parse one 32-bit little-endian unsigned integer.
161−anyUint32le :: forall m. MonadEffect m => ParserT DataView m UInt
162−anyUint32le = anyPrim LE (AProxy :: AProxy Uint32)
163−
164−-- | Parse one 32-bit big-endian floating point number.
165−anyFloat32be :: forall m. MonadEffect m => ParserT DataView m Float32.Float32
166−anyFloat32be = anyPrim BE (AProxy :: AProxy Float32)
167−
168−-- | Parse one 32-bit little-endian floating point number.
169−anyFloat32le :: forall m. MonadEffect m => ParserT DataView m Float32.Float32
170−anyFloat32le = anyPrim LE (AProxy :: AProxy Float32)
171−
172−-- | Parse one 64-bit big-endian floating point number.
173−anyFloat64be :: forall m. MonadEffect m => ParserT DataView m Number
174−anyFloat64be = anyPrim BE (AProxy :: AProxy Float64)
175−
176−-- | Parse one 64-bit little-endian floating point number.
177−anyFloat64le :: forall m. MonadEffect m => ParserT DataView m Number
178−anyFloat64le = anyPrim LE (AProxy :: AProxy Float64)
179−
180−-- | Parse one fixed-bit-width primitive that satisfies the given predicate.
181−-- |
182−-- | #### Example
183−-- |
184−-- | Parse a little-endian 32-bit signed integer that is equal to *3*:
185−-- |
186−-- | satisfy LE (AProxy :: AProxy Int32) (_ == 3)
187−-- |
188−-- | or just use the convenience function `satisfyInt32le`, see below.
189−satisfy :: forall a name b m t
190− . BinaryValue a t
191− => BytesPerValue a b
192− => ShowArrayViewType a name
193− => IsSymbol name
194− => Nat b
195− => Show t
196− => MonadEffect m
197− => Endian
198− -> AProxy a
199− -> (t -> Boolean)
200− -> ParserT DataView m t
201−satisfy endian aproxy f = tryRethrow do
202− i <- anyPrim endian aproxy
203− if f i then pure i
204− else fail $ reflectSymbol (SProxy :: SProxy name) <>
205− " " <> show i <> " did not satisfy predicate."
206−
207−-- | Parse one 8-bit signed integer that satisfies the given predicate.
208−satisfyInt8 :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
209−satisfyInt8 = satisfy LE (AProxy :: AProxy Int8)
210−
211−-- | Parse one 16-bit big-endian signed integer that satisfies the given predicate.
212−satisfyInt16be :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
213−satisfyInt16be = satisfy BE (AProxy :: AProxy Int16)
214−
215−-- | Parse one 16-bit little-endian signed integer that satisfies the given predicate.
216−satisfyInt16le :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
217−satisfyInt16le = satisfy LE (AProxy :: AProxy Int16)
218−
219−-- | Parse one 32-bit big-endian signed integer that satisfies the given predicate.
220−satisfyInt32be :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
221−satisfyInt32be = satisfy BE (AProxy :: AProxy Int32)
222−
223−-- | Parse one 32-bit little-endian signed integer that satisfies the given predicate.
224−satisfyInt32le :: forall m. MonadEffect m => (Int -> Boolean) -> ParserT DataView m Int
225−satisfyInt32le = satisfy LE (AProxy :: AProxy Int32)
226−
227−-- | Parse one 8-bit unsigned integer that satisfies the given predicate.
228−satisfyUint8 :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
229−satisfyUint8 = satisfy LE (AProxy :: AProxy Uint8)
230−
231−-- | Parse one 16-bit big-endian unsigned integer that satisfies the given predicate.
232−satisfyUint16be :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
233−satisfyUint16be = satisfy BE (AProxy :: AProxy Uint16)
234−
235−-- | Parse one 16-bit little-endian unsigned integer that satisfies the given predicate.
236−satisfyUint16le :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
237−satisfyUint16le = satisfy LE (AProxy :: AProxy Uint16)
238−
239−-- | Parse one 32-bit big-endian unsigned integer that satisfies the given predicate.
240−satisfyUint32be :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
241−satisfyUint32be = satisfy BE (AProxy :: AProxy Uint32)
242−
243−-- | Parse one 32-bit little-endian unsigned integer that satisfies the given predicate.
244−satisfyUint32le :: forall m. MonadEffect m => (UInt -> Boolean) -> ParserT DataView m UInt
245−satisfyUint32le = satisfy LE (AProxy :: AProxy Uint32)
246−
247−-- | Parse one 32-bit big-endian floating-point number that satisfies the given predicate.
248−satisfyFloat32be :: forall m. MonadEffect m => (Float32.Float32 -> Boolean) -> ParserT DataView m Float32.Float32
249−satisfyFloat32be = satisfy BE (AProxy :: AProxy Float32)
250−
251−-- | Parse one 32-bit little-endian floating-point number that satisfies the given predicate.
252−satisfyFloat32le :: forall m. MonadEffect m => (Float32.Float32 -> Boolean) -> ParserT DataView m Float32.Float32
253−satisfyFloat32le = satisfy LE (AProxy :: AProxy Float32)
254−
255−-- | Parse one 64-bit big-endian floating-point number that satisfies the given predicate.
256−satisfyFloat64be :: forall m. MonadEffect m => (Number -> Boolean) -> ParserT DataView m Number
257−satisfyFloat64be = satisfy BE (AProxy :: AProxy Float64)
258−
259−-- | Parse one 64-bit little-endian floating-point number that satisfies the given predicate.
260−satisfyFloat64le :: forall m. MonadEffect m => (Number -> Boolean) -> ParserT DataView m Number
261−satisfyFloat64le = satisfy LE (AProxy :: AProxy Float64)
262−
263−-- | Take *N* bytes starting from the current parser position. Will fail
264−-- | if not enough bytes remain in the input. Will fail if *N* is negative.
265−-- |
266−-- | #### Example
267−-- |
268−-- | Parse three bytes.
269−-- |
270−-- | takeN 3
271−-- |
272−takeN :: forall m. MonadEffect m => ByteLength -> ParserT DataView m DataView
273−takeN n = do
274− ParseState input (Position {line,column}) _ <- get
275− unless (n >= 0) $ fail $ "Cannot take negative number of bytes."
276− unless (column + n - 1 <= DV.byteLength input) $
277− fail $ "Cannot take " <> show n <> " bytes, only " <>
278− show (DV.byteLength input - column + 1) <> " bytes remain."
279− p <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + (column-1)) n
280− put $ ParseState input (Position {line,column:column+n}) true
281− pure p
282−
283−-- | Take the rest of the input, however many bytes remain. Always succeeds.
284−takeRest :: forall m. MonadEffect m => ParserT DataView m DataView
285−takeRest = do
286− ParseState input (Position {line,column}) _ <- get
287− p <- lift $ liftEffect $ DV.part (DV.buffer input) (DV.byteOffset input + (column-1))
288− (DV.byteLength input - (column-1))
289− put $ ParseState input (Position {line,column:DV.byteLength input + 1}) true
290− pure p
291−
292−-- | Parse succeeds at the end of the input DataView. Consumes no input.
293−eof :: forall m. Monad m => ParserT DataView m Unit
294−eof = do
295− ParseState input (Position {column}) _ <- get
296− unless (column > DV.byteLength input) $ fail "Expected end of DataView"
297−
298−-- ****************************** Notes ****************************************
299−--
300−-- The `initialPostion` in a `ParserT` is `Postion{line:1,column:1)`.
301−-- We keep `line` invariant and use `column-1` to denote the offset into the
302−-- `DataView`, that's why there are so many plus 1 and minus 1 operations
303−-- in this module.
304−-- https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html
305−--
306−-- We cannot have a primitive parser which parses a `DataView` and produces
307−-- an `ArrayView` (a Javascript Typed Array). Javascript DataViews are
308−-- endianess-aware, but Javascript Typed Arrays assume the native endianness
309−-- of the local machine. DataViews are intended to be used for I/O, ArrayViews
310−-- are intended to be used internally for graphics in a process, and they're
311−-- not intended to be both applied to the same ArrayBuffer.
test/Main.purs+133−24
@@ -2,21 +2,34 @@ module Test.Main where
22
33import Prelude
44
5+import Control.Monad.Except (ExceptT(..))
6+import Control.Monad.Trans.Class (lift)
7+import Data.ArrayBuffer.ArrayBuffer as AB
8+import Data.ArrayBuffer.Cast (fromUint8Array, toUint8Array)
9+import Data.ArrayBuffer.DataView as DataView
10+import Data.ArrayBuffer.Typed (fromArray)
11+import Data.ArrayBuffer.Types (Uint8Array)
512import Data.Either (Either(..))
13+import Data.Enum (fromEnum)
614import Data.List (fromFoldable)
7−import Data.Traversable(for_)
15+import Data.List as List
16+import Data.Maybe (Maybe(..))
17+import Data.Traversable (for_)
818import Data.Tuple (Tuple(..))
919import Data.UInt (fromInt)
1020import Effect (Effect)
21+import Effect.Class (liftEffect)
1122import Effect.Console (logShow)
12−import Control.Monad.Trans.Class (lift)
13−import Test.Assert (assert')
14−import Text.Parsing.Parser (ParserT, runParserT, parseErrorPosition, fail)
15−import Text.Parsing.Parser.Combinators (manyTill)
16−import Text.Parsing.Parser.Pos (Position(..))
17−import Data.ArrayBuffer.ArrayBuffer (empty) as AB
18−import Data.ArrayBuffer.DataView (setInt8, whole) as AB
19−import Text.Parsing.Parser.DataView as DV
23+import Effect.Exception (catchException, message)
24+import Parsing (ParseError(..), ParserT, Position(..), fail, liftExceptT, parseErrorPosition, runParserT)
25+import Parsing.Combinators (many, manyTill)
26+import Parsing.DataView (anyInt8, anyTill, eof, satisfyInt8)
27+import Parsing.DataView as DV
28+import Parsing.DataView.Basic (anyCodePointUTF8)
29+import Test.Assert (assert', assertEqual')
30+import Web.Encoding.TextDecoder as TextDecoder
31+import Web.Encoding.TextEncoder as TextEncoder
32+import Web.Encoding.UtfLabel as UtfLabel
2033
2134parseTestT :: forall s a. Show a => Eq a => s -> a -> ParserT s Effect a -> Effect Unit
2235parseTestT input expected p = do
@@ -31,33 +44,29 @@ parseFailT :: forall s a. s -> Position -> ParserT s Effect a -> Effect Unit
3144parseFailT input failPos p = do
3245 result <- runParserT input p
3346 case result of
34− Right _ -> assert' ("ParseError expected at " <> show failPos) false
47+ Right _ -> assert' ("ParseError expected at " <> show failPos) false
3548 Left err -> do
3649 let pos = parseErrorPosition err
3750 assert' ("ParseError expected at " <> show failPos <> " but parser failed at " <> show pos)
38− (pos == failPos)
51+ (pos == failPos)
3952 logShow $ show failPos
4053
4154mkPos :: Int -> Position
42−mkPos n = mkPos' n 1
43−
44−mkPos' :: Int -> Int -> Position
45−mkPos' column line = Position { column: column, line: line }
46−
55+mkPos n = Position { index: n, line: 1, column: 1 }
4756
4857main :: Effect Unit
4958main = do
5059
51− -- Test input DataView = [5,6,7,8,9]
60+ -- Test input is DataView = [5,6,7,8,9]
5261 ab <- AB.empty 5
53− let dv = AB.whole ab
54− for_ [0,1,2,3,4] $ \i -> AB.setInt8 dv i (i+5)
62+ let dv = DataView.whole ab
63+ for_ [ 0, 1, 2, 3, 4 ] $ \i -> DataView.setInt8 dv i (i + 5)
5564 -- anyInt8
5665 parseTestT dv 5 DV.anyInt8
5766 -- manyTill eof
58− parseTestT dv (fromFoldable [5,6,7,8,9]) $ manyTill DV.anyInt8 DV.eof
67+ parseTestT dv (fromFoldable [ 5, 6, 7, 8, 9 ]) $ manyTill DV.anyInt8 DV.eof
5968 -- manyTill satisfy
60− parseTestT dv (fromFoldable [5,6,7,8]) $ manyTill DV.anyInt8 (DV.satisfyInt8 (_ == 9))
69+ parseTestT dv (fromFoldable [ 5, 6, 7, 8 ]) $ manyTill DV.anyInt8 (DV.satisfyInt8 (_ == 9))
6170 -- anyInt16be
6271 parseTestT dv 0x0506 DV.anyInt16be
6372 -- anyInt16le
@@ -67,7 +76,7 @@ main = do
6776 -- anyUint16le
6877 parseTestT dv (fromInt 0x0605) DV.anyUint16le
6978 -- fail on anyInt16le past end of DataView
70− parseFailT dv (mkPos 5) $ DV.anyInt16le *> DV.anyInt16le *> DV.anyInt16le
79+ parseFailT dv (mkPos 4) $ DV.anyInt16le *> DV.anyInt16le *> DV.anyInt16le
7180 -- anyInt32be and anyInt8
7281 parseTestT dv (Tuple 0x05060708 0x09) $ do
7382 l <- DV.anyInt32be
@@ -104,7 +113,7 @@ main = do
104113 Right actual -> pure actual
105114 Left err -> fail $ show err
106115 -- fail on takeN past end of DataView
107− parseFailT dv (mkPos 1) $ DV.takeN 6
116+ parseFailT dv (mkPos 0) $ DV.takeN 6
108117 -- takeRest then new parse on takeRest then anyInt8
109118 parseTestT dv 0x07 do
110119 _ <- DV.takeN 1
@@ -115,8 +124,108 @@ main = do
115124 Left err -> fail $ show err
116125 Right x -> pure x
117126 -- takeN then a new parse then fail on anyInt16le past end of DataView
118− parseFailT dv (mkPos 2) $ do
127+ parseFailT dv (mkPos 1) $ do
119128 dv2 <- DV.takeN 1
120129 lift (runParserT dv2 DV.anyInt16le) >>= case _ of
121130 Left err -> fail $ show err
122131 Right x -> pure x
132+ parseTestT dv unit $ DV.takeN 5 *> pure unit
133+
134+ -- test match combinator
135+ runParserT dv (DV.match (DV.anyInt8 *> DV.anyInt8)) >>= case _ of
136+ Right (Tuple matchresult _) -> do
137+ r0 <- DataView.getInt8 matchresult 0
138+ r1 <- DataView.getInt8 matchresult 1
139+ assert' ("match failed " <> show r0 <> " " <> show r1) $ r0 == Just 5 && r1 == Just 6
140+ logShow $ show r0 <> " " <> show r1
141+ Left err -> assert' ("match failed " <> show err) false
142+
143+ do
144+ ablarge <- AB.empty 200000
145+ let dvlarge = DataView.whole ablarge
146+ -- forE 0 (AB.byteLength ablarge - 1) \i -> void $ DataView.setInt8 dvlarge i i
147+ x <- map List.length <$> runParserT dvlarge (many anyInt8)
148+ assertEqual' "stack safety"
149+ { actual: x
150+ , expected: Right 200000
151+ }
152+
153+ do
154+ let
155+ teststring = "test string 👓"
156+
157+ textDecoder <- TextDecoder.new UtfLabel.utf8
158+
159+ textEncoder <- TextEncoder.new
160+
161+ let testarray = TextEncoder.encode teststring textEncoder
162+
163+ testview <- fromUint8Array testarray
164+
165+ result <- runParserT testview do
166+ let length = DataView.byteLength testview
167+ stringview <- DV.takeN length
168+ stringarray <- lift $ liftEffect $ toUint8Array stringview
169+ liftExceptT $ ExceptT $ catchException (pure <<< Left <<< message) do
170+ Right <$> TextDecoder.decode stringarray textDecoder
171+
172+ assertEqual' "UTF-8 decoding example"
173+ { expected: Right teststring
174+ , actual: result
175+ }
176+
177+ do
178+ result <- runParserT dv do
179+ Tuple pre _ <- anyTill do
180+ _ <- satisfyInt8 (_ == 7)
181+ _ <- satisfyInt8 (_ == 8)
182+ pure unit
183+ pure pre
184+
185+ assertEqual' "anyTill"
186+ { expected: Right 2
187+ , actual: DataView.byteLength <$> result
188+ }
189+
190+ do
191+ -- Test one code point from each byte group
192+ -- a 97
193+ -- λ 955
194+ -- 月 0x6708
195+ -- 👓 0x1F453
196+ let teststring = "aλ月👓a"
197+ textEncoder <- TextEncoder.new
198+ let testarray = TextEncoder.encode teststring textEncoder
199+ testview <- fromUint8Array testarray
200+
201+ result <- (map <<< map <<< map) fromEnum $ runParserT testview do
202+ c0 <- anyCodePointUTF8
203+ c1 <- anyCodePointUTF8
204+ c2 <- anyCodePointUTF8
205+ c3 <- anyCodePointUTF8
206+ c4 <- anyCodePointUTF8
207+ eof
208+ pure [ c0, c1, c2, c3, c4 ]
209+
210+ assertEqual' "anyCodePointUTF8 basic"
211+ { expected: Right [ 97, 955, 0x6708, 0x1F453, 97 ]
212+ , actual: result
213+ }
214+
215+ do
216+ test :: Uint8Array <- fromArray (map fromInt [ 0x00BF ])
217+ testv <- fromUint8Array test
218+ result <- runParserT testv anyCodePointUTF8
219+ assertEqual' "anyCodePointUTF8 invalid 1"
220+ { expected: Left (ParseError "Invalid UTF-8 encoding" (Position { index: 0, column: 1, line: 1 }))
221+ , actual: result
222+ }
223+
224+ do
225+ test :: Uint8Array <- fromArray (map fromInt [ 0x00C0, 0 ])
226+ testv <- fromUint8Array test
227+ result <- runParserT testv anyCodePointUTF8
228+ assertEqual' "anyCodePointUTF8 invalid 2"
229+ { expected: Left (ParseError "Invalid UTF-8 encoding" (Position { index: 0, column: 1, line: 1 }))
230+ , actual: result
231+ }