aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-10-14 18:53:44 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-10-14 18:53:44 +0000
commit0570be5d9d4f1fdfa570f7af6b884cdcfd1ae261 (patch)
treea93ddce82b1f939de7017c5f19ef6ad61a5fee00
parent9eac2f42d0429011e784967cc7f270fe8184af54 (diff)
parent5492d0ac8220239408785c8cabe6fa370dc75f49 (diff)
downloadnom-0570be5d9d4f1fdfa570f7af6b884cdcfd1ae261.tar.gz
Merge "Upgrade rust/crates/nom to 7.0.0" am: ce8e318dab am: 4c1a992a52 am: 5492d0ac82
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/nom/+/1840445 Change-Id: Ie3df7b18a7ae302636306c2d470d502b5ebf34b6
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.travis.yml110
-rw-r--r--Android.bp9
-rw-r--r--CHANGELOG.md130
-rw-r--r--Cargo.toml67
-rw-r--r--Cargo.toml.orig54
-rw-r--r--METADATA8
-rw-r--r--README.md31
-rw-r--r--doc/nom_recipes.md100
-rw-r--r--patches/bitvec_dep.patch29
-rw-r--r--src/bits/complete.rs67
-rw-r--r--src/bits/macros.rs265
-rw-r--r--src/bits/mod.rs27
-rw-r--r--src/branch/macros.rs954
-rw-r--r--src/branch/mod.rs28
-rw-r--r--src/branch/tests.rs142
-rw-r--r--src/bytes/complete.rs131
-rw-r--r--src/bytes/macros.rs994
-rw-r--r--src/bytes/mod.rs4
-rw-r--r--src/bytes/streaming.rs101
-rw-r--r--src/bytes/tests.rs636
-rw-r--r--src/character/complete.rs210
-rw-r--r--src/character/macros.rs112
-rw-r--r--src/character/mod.rs4
-rw-r--r--src/character/streaming.rs209
-rw-r--r--src/character/tests.rs62
-rw-r--r--src/combinator/macros.rs1226
-rw-r--r--src/combinator/mod.rs413
-rw-r--r--src/combinator/tests.rs275
-rw-r--r--src/error.rs142
-rw-r--r--src/internal.rs58
-rw-r--r--src/lib.rs66
-rw-r--r--src/multi/macros.rs1079
-rw-r--r--src/multi/mod.rs277
-rw-r--r--src/multi/tests.rs544
-rw-r--r--src/number/complete.rs345
-rw-r--r--src/number/macros.rs265
-rw-r--r--src/number/mod.rs3
-rw-r--r--src/number/streaming.rs363
-rw-r--r--src/regexp/macros.rs409
-rw-r--r--src/regexp/mod.rs675
-rw-r--r--src/sequence/macros.rs920
-rw-r--r--src/sequence/mod.rs96
-rw-r--r--src/sequence/tests.rs274
-rw-r--r--src/str.rs89
-rw-r--r--src/traits.rs463
-rw-r--r--src/util.rs218
-rw-r--r--tests/arithmetic.rs6
-rw-r--r--tests/arithmetic_ast.rs6
-rw-r--r--tests/bitstream.rs32
-rw-r--r--tests/css.rs2
-rw-r--r--tests/custom_errors.rs19
-rw-r--r--tests/float.rs49
-rw-r--r--tests/fnmut.rs2
-rw-r--r--tests/inference.rs54
-rw-r--r--tests/ini.rs87
-rw-r--r--tests/ini_str.rs45
-rw-r--r--tests/issues.rs276
-rw-r--r--tests/json.rs3
-rw-r--r--tests/mp4.rs308
-rw-r--r--tests/multiline.rs2
-rw-r--r--tests/named_args.rs122
-rw-r--r--tests/overflow.rs76
-rw-r--r--tests/reborrow_fold.rs39
-rw-r--r--tests/test1.rs44
65 files changed, 4113 insertions, 9745 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index fc0f2a7..a624533 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "b7b7edb401edb49fd52a8ca09730c4f2d8d1910f"
+ "sha1": "9678b061d3ed0a6b8e31ce569e024ec25f3dd354"
}
}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 3c19181..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,110 +0,0 @@
-language: rust
-# sudo is required to enable kcov to use the personality syscall
-sudo: required
-dist: trusty
-cache: cargo
-
-rust:
- - nightly
- - beta
- - stable
- - 1.44.0
-
-env:
- matrix:
- - FEATURES='--features "regexp"'
-
-before_script:
- - eval git pull --rebase https://github.com/Geal/nom master
- - eval git log --pretty=oneline HEAD~5..HEAD
-
-matrix:
- include:
- - rust: stable
- env: FEATURES='--features "std lexical regexp"'
- before_script:
- - export PATH=$HOME/.cargo/bin:$PATH
- - cargo install cargo-update || echo "cargo-update already installed"
- - cargo install cargo-tarpaulin || echo "cargo tarpaulin already installed"
- - cargo install-update -a
- script:
- cargo tarpaulin --ciserver travis-ci --coveralls $TRAVIS_JOB_ID
- - rust: stable
- env: FEATURES=''
- - rust: stable
- env: FEATURES='--no-default-features'
- # still compatible with 1.36.0 if not using lexical-core
- - rust: 1.37.0
- env: FEATURES='--no-default-features --features "regexp lexical"'
- - rust: stable
- env: FEATURES='--no-default-features --features "alloc"'
- - rust: nightly
- env: FEATURES=''
- - rust: nightly
- env: FEATURES='--no-default-features'
- - rust: nightly
- env: FEATURES='--no-default-features --features "alloc"'
- - rust: nightly
- env: DOC_FEATURES='--features "std lexical regexp" --no-default-features'
- before_script:
- - export PATH=$HOME/.cargo/bin:$PATH
- script:
- - eval cargo doc --verbose $DOC_FEATURES
-
- allow_failures:
- - rust: stable
- env: FEATURES=''
- before_script:
- - export PATH=$HOME/.cargo/bin:$PATH
- - rustup component add rustfmt-preview
- script:
- - eval cargo fmt -- --write-mode=diff
-
-notifications:
- webhooks:
- urls:
- - https://webhooks.gitter.im/e/9c035a194ac4fd4cc061
- on_success: change
- on_failure: always
- on_start: false
-
-
-addons:
- apt:
- packages:
- - libcurl4-openssl-dev
- - libelf-dev
- - libdw-dev
- - binutils-dev
- - cmake
- sources:
- - kalakris-cmake
-
-cache:
- directories:
- - /home/travis/.cargo
-
-before_cache:
- - rm -rf /home/travis/.cargo/registry
-
-script:
- - eval cargo build --verbose $FEATURES
- - eval cargo test --verbose $FEATURES
-
-after_success: |
- case "$TRAVIS_RUST_VERSION" in
- nightly)
- if [ "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}" != "master" ]; then
- git fetch &&
- git checkout master &&
- cargo bench --verbose
- fi
-
- if [ "$FEATURES" == '--features "regexp"' ]; then
- cargo bench --verbose
- fi
- ;;
-
- *)
- ;;
- esac
diff --git a/Android.bp b/Android.bp
index 3bda730..1b78f58 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --run --device --dependencies --features=alloc,std.
+// This file is generated by cargo2android.py --run --device --features=alloc,std.
// Do not modify this file as changes will be overridden on upgrade.
package {
@@ -22,6 +22,8 @@ rust_library {
name: "libnom",
host_supported: true,
crate_name: "nom",
+ cargo_env_compat: true,
+ cargo_pkg_version: "7.0.0",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
@@ -31,9 +33,6 @@ rust_library {
cfgs: ["stable_i128"],
rustlibs: [
"libmemchr",
+ "libminimal_lexical",
],
}
-
-// dependent_library ["feature_list"]
-// memchr-2.3.4 "std,use_std"
-// version_check-0.9.3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 328a95a..49ef3f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,126 @@
### Changed
+## 7.0.0 - 2021-08-21
+
+This release fixes dependency compilation issues and strengthen the minimum supported Rust version (MSRV) policy. This is also the first release without the macros that were used since nom's beginning.
+
+### Thanks
+
+- @djc
+- @homersimpsons
+- @lo48576
+- @myrrlyn
+- @RalXYZ
+- @nickelc
+- @cenodis
+
+### Added
+
+- `take_until1` combinator
+- more `to_owned` implementations
+- `fail`: a parser that always fail, useful as default condition in other combinators
+- text to number parsers: in the `character::streaming` and `character::complete` modules, there are parsers named `i8, u16, u32, u64, u128` and `u8 ,u16, u32, u64, u128` that recognize decimal digits and directly convert to a number in the target size (checking for max int size)
+
+### Removed
+
+- now that function combinators are the main way to write parsers, the old macro combinators are confusing newcomers. THey have been removed
+- the `BitSlice` input type from bitvec has been moved into the [nom-bitvec](https://crates.io/crates/nom-bitvec) crate. nom does not depend on bitvec now
+- regex parsers have been moved into the [nom-regex](https://crates.io/crates/nom-regex) crate. nom does not depend on regex now
+- `ErrorKind::PArseTo` was not needed anymore
+
+### Changed
+
+- relax trait bounds
+- some performance fixes
+- `split_at_position*` functions should now be guaranteed panic free
+- the `lexical-core` crate used for float parsing has now been replaced with `minimal-lexical`: the new crate is faster to compile, faster to parse, and has no dependencies
+
+### Fixed
+
+- infinite loop in `escaped` combinator
+- `many_m_n` now fails if min > max
+
+
+## 6.2.1 - 2021-06-23
+
+### Thanks
+
+This release was done thanks to the hard work of (by order of appearance in the commit list):
+
+- @homersimpsons
+
+### Fixed
+
+- fix documentation building
+
+## 6.2.0 - 2021-02-15
+
+### Thanks
+
+This release was done thanks to the hard work of (by order of appearance in the commit list):
+
+- @DavidKorczynski
+- @homersimpsons
+- @kornelski
+- @lf-
+- @lewisbelcher
+- @ronan-d
+- @weirane
+- @heymind
+- @marcianx
+- @Nukesor
+
+### Added
+
+- nom is now regularly fuzzed through the OSSFuzz project
+
+### Changed
+
+- lots of documentation fixes
+- relax trait bounds
+- workarounds for depenency issues with bitvec and memchr
+
+## 6.1.2 - 2021-02-15
+
+### Changed
+
+- Fix cargo feature usage in previous release
+
+## 6.1.1 - 2021-02-15
+
+### Thanks
+
+This release was done thanks to the hard work of (by order of appearance in the commit list):
+
+- @nickelc
+
+### Changed
+
+- Fix dependenciy incompatibilities: Restrict the bitvec->funty dependency to <=1.1
+
+## 6.1.0 - 2021-01-23
+
+### Thanks
+
+This release was done thanks to the hard work of (by order of appearance in the commit list):
+
+- @sachaarbonel
+- @vallentin
+- @Lucretiel
+- @meiomorphism
+- @jufajardini
+- @neithernut
+- @drwilco
+
+### Changed
+
+- readme and documentation fixes
+- rewrite of fold_many_m_n
+- relax trait bounds on some parsers
+- implement `std::error::Error` on `VerboseError`
+
+
## 6.0.1 - 2020-11-24
### Thanks
@@ -1268,8 +1388,14 @@ Considering the number of changes since the last release, this version can conta
## Compare code
-* [unreleased](https://github.com/Geal/nom/compare/6.0.1...HEAD)
-* [6.0.0](https://github.com/Geal/nom/compare/6.0.0...6.0.1)
+* [unreleased](https://github.com/Geal/nom/compare/7.0.0...HEAD)
+* [7.0.0](https://github.com/Geal/nom/compare/6.2.1...7.0.0)
+* [6.2.1](https://github.com/Geal/nom/compare/6.2.0...6.2.1)
+* [6.2.0](https://github.com/Geal/nom/compare/6.1.2...6.2.0)
+* [6.1.2](https://github.com/Geal/nom/compare/6.1.1...6.1.2)
+* [6.1.1](https://github.com/Geal/nom/compare/6.1.0...6.1.1)
+* [6.1.0](https://github.com/Geal/nom/compare/6.0.1...6.1.0)
+* [6.0.1](https://github.com/Geal/nom/compare/6.0.0...6.0.1)
* [6.0.0](https://github.com/Geal/nom/compare/5.1.1...6.0.0)
* [5.1.1](https://github.com/Geal/nom/compare/5.1.0...5.1.1)
* [5.1.0](https://github.com/Geal/nom/compare/5.0.1...5.1.0)
diff --git a/Cargo.toml b/Cargo.toml
index ec03c01..1a14020 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,19 +3,18 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "nom"
-version = "6.2.1"
+version = "7.0.0"
authors = ["contact@geoffroycouprie.com"]
-include = ["CHANGELOG.md", "LICENSE", "README.md", ".gitignore", ".travis.yml", "Cargo.toml", "src/*.rs", "src/*/*.rs", "tests/*.rs", "doc/nom_recipes.md", "build.rs"]
+include = ["CHANGELOG.md", "LICENSE", "README.md", ".gitignore", "Cargo.toml", "src/*.rs", "src/*/*.rs", "tests/*.rs", "doc/nom_recipes.md", "build.rs"]
autoexamples = false
description = "A byte-oriented, zero-copy, parser combinators library"
documentation = "https://docs.rs/nom"
@@ -26,7 +25,7 @@ license = "MIT"
repository = "https://github.com/Geal/nom"
[package.metadata.docs.rs]
all-features = true
-features = ["alloc", "std", "regexp", "lexical", "docsrs"]
+features = ["alloc", "std", "docsrs"]
[profile.bench]
lto = true
codegen-units = 1
@@ -70,9 +69,6 @@ name = "custom_errors"
name = "float"
[[test]]
-name = "inference"
-
-[[test]]
name = "ini"
required-features = ["alloc"]
@@ -96,18 +92,12 @@ name = "multiline"
required-features = ["alloc"]
[[test]]
-name = "named_args"
-
-[[test]]
name = "overflow"
[[test]]
name = "reborrow_fold"
[[test]]
-name = "test1"
-
-[[test]]
name = "fnmut"
required-features = ["alloc"]
@@ -132,11 +122,6 @@ path = "benches/ini.rs"
harness = false
[[bench]]
-name = "ini_complete"
-path = "benches/ini_complete.rs"
-harness = false
-
-[[bench]]
name = "ini_str"
path = "benches/ini_str.rs"
harness = false
@@ -145,31 +130,12 @@ harness = false
name = "json"
path = "benches/json.rs"
harness = false
-[dependencies.bitvec]
-version = "0.19.3"
-optional = true
-default-features = false
-
-[dependencies.funty]
-version = ">1.0, <=1.1"
-optional = true
-default-features = false
-
-[dependencies.lazy_static]
-version = "^1.0"
-optional = true
-
-[dependencies.lexical-core]
-version = ">= 0.6, < 0.8"
-optional = true
-
[dependencies.memchr]
-version = ">=2.0, <2.4"
+version = "2.0"
default-features = false
-[dependencies.regex]
-version = "^1.0"
-optional = true
+[dependencies.minimal-lexical]
+version = "0.1.2"
[dev-dependencies.criterion]
version = "0.3"
@@ -178,20 +144,17 @@ version = "0.3"
[dev-dependencies.jemallocator]
version = "^0.3"
+
+[dev-dependencies.proptest]
+version = "1.0.0"
[build-dependencies.version_check]
version = "0.9"
[features]
alloc = []
-std = ["alloc", "memchr/use_std"]
-bitvec-base = ["bitvec"]
-bitvec-alloc = ["bitvec/alloc", "funty"]
-bitvec-std = ["bitvec/std"]
-default = ["std", "lexical"]
+default = ["std"]
docsrs = []
-lexical = ["lexical-core"]
-regexp = ["regex"]
-
+std = ["alloc", "memchr/use_std"]
[badges.coveralls]
branch = "master"
repository = "Geal/nom"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 0cc06c7..b2e176a 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
[package]
name = "nom"
-version = "6.2.1"
+version = "7.0.0"
authors = [ "contact@geoffroycouprie.com" ]
description = "A byte-oriented, zero-copy, parser combinators library"
license = "MIT"
@@ -18,7 +18,6 @@ include = [
"LICENSE",
"README.md",
".gitignore",
- ".travis.yml",
"Cargo.toml",
"src/*.rs",
"src/*/*.rs",
@@ -28,50 +27,29 @@ include = [
]
[features]
-alloc = ["bitvec/alloc", "funty"]
-std = ["alloc", "bitvec/std", "memchr/use_std"]
-default = ["std", "bitvec", "lexical"]
-regexp = ["regex"]
-lexical = ["lexical-core"]
+alloc = []
+std = ["alloc", "memchr/use_std"]
+default = ["std"]
docsrs = []
-[dependencies.bitvec]
-version = "0.19.3"
-optional = true
-default-features = false
-
-# we need to restrict funty's version, until we can update bitvec to 0.21
-[dependencies.funty]
-version = ">1.0, <=1.1"
-optional = true
-default-features = false
-
-[dependencies.regex]
-version = "^1.0"
-optional = true
-
-[dependencies.lazy_static]
-version = "^1.0"
-optional = true
+[dependencies]
+minimal-lexical = "0.1.2"
[dependencies.memchr]
-version = ">=2.0, <2.4"
+version = "2.0"
default-features = false
-[dependencies.lexical-core]
-version = ">= 0.6, < 0.8"
-optional = true
-
[dev-dependencies]
criterion = "0.3"
jemallocator = "^0.3"
doc-comment = "0.3"
+proptest = "1.0.0"
[build-dependencies]
version_check = "0.9"
[package.metadata.docs.rs]
-features = [ "alloc", "std", "regexp", "lexical", "docsrs"]
+features = ["alloc", "std", "docsrs"]
all-features = true
[profile.bench]
@@ -102,9 +80,6 @@ name = "custom_errors"
name = "float"
[[test]]
-name = "inference"
-
-[[test]]
name = "ini"
required-features = ["alloc"]
@@ -128,18 +103,12 @@ name = "multiline"
required-features = ["alloc"]
[[test]]
-name = "named_args"
-
-[[test]]
name = "overflow"
[[test]]
name = "reborrow_fold"
[[test]]
-name = "test1"
-
-[[test]]
name = "fnmut"
required-features = ["alloc"]
@@ -164,11 +133,6 @@ path = "benches/ini.rs"
harness = false
[[bench]]
-name = "ini_complete"
-path = "benches/ini_complete.rs"
-harness = false
-
-[[bench]]
name = "ini_str"
path = "benches/ini_str.rs"
harness = false
diff --git a/METADATA b/METADATA
index c3f4a24..c61aba3 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/nom/nom-6.2.1.crate"
+ value: "https://static.crates.io/crates/nom/nom-7.0.0.crate"
}
- version: "6.2.1"
+ version: "7.0.0"
license_type: NOTICE
last_upgrade_date {
year: 2021
- month: 8
- day: 9
+ month: 9
+ day: 23
}
}
diff --git a/README.md b/README.md
index 1710caa..e1bf4a8 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[![Build Status](https://travis-ci.org/Geal/nom.svg?branch=master)](https://travis-ci.org/Geal/nom)
[![Coverage Status](https://coveralls.io/repos/Geal/nom/badge.svg?branch=master)](https://coveralls.io/r/Geal/nom?branch=master)
[![Crates.io Version](https://img.shields.io/crates/v/nom.svg)](https://crates.io/crates/nom)
-[![Minimum rustc version](https://img.shields.io/badge/rustc-1.44.0+-lightgray.svg)](#rust-version-requirements)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.48.0+-lightgray.svg)](#rust-version-requirements)
nom is a parser combinators library written in Rust. Its goal is to provide tools
to build safe parsers without compromising the speed or memory consumption. To
@@ -77,7 +77,7 @@ fn parse_color() {
- [Various design documents and tutorials](https://github.com/Geal/nom/tree/master/doc)
- [List of combinators and their behaviour](https://github.com/Geal/nom/blob/master/doc/choosing_a_combinator.md)
-If you need any help developing your parsers, please ping `geal` on IRC (freenode, geeknode, oftc), go to `#nom-parsers` on Freenode IRC, or on the [Gitter chat room](https://gitter.im/Geal/nom).
+If you need any help developing your parsers, please ping `geal` on IRC (libera, geeknode, oftc), go to `#nom-parsers` on Libera IRC, or on the [Gitter chat room](https://gitter.im/Geal/nom).
## Why use nom
@@ -188,9 +188,8 @@ Some benchmarks are available on [Github](https://github.com/Geal/nom_benchmarks
## Rust version requirements
-The 6.0 series of nom requires **Rustc version 1.44 or greater** (compatible with 1.37 if building without the `alloc` or `std` features, ie `--no-default-features --features="regex,lexical"`).
+The 7.0 series of nom supports **Rustc version 1.48 or greater**. It is known to work properly on Rust 1.41.1 but there is no guarantee it will stay the case through this major release.
-Travis CI always has a build with a pinned version of Rustc matching the oldest supported Rust release.
The current policy is that this will only be updated in the next major nom release.
## Installation
@@ -199,31 +198,21 @@ nom is available on [crates.io](https://crates.io/crates/nom) and can be include
```toml
[dependencies]
-nom = "6"
+nom = "7"
```
-Then include it in your code like this:
-
-```rust,ignore
-#[macro_use]
-extern crate nom;
-```
-
-**NOTE: If you have existing code using nom below the 5.0 version, please take a look
-at the [upgrade documentation](https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_5.md)
-to handle the breaking changes.**
-
There are a few compilation features:
-* `std`: (activated by default) if disabled, nom can work in `no_std` builds
-* `regexp`: Enables regular expression parsers with the `regex` crate
+* `alloc`: (activated by default) if disabled, nom can work in `no_std` builds without memory allocators. If enabled, combinators that allocate (like `many0`) will be available
+* `std`: (activated by default, activates `alloc` too) if disabled, nom can work in `no_std` builds
-You can activate those features like this:
+You can configure those features like this:
```toml
[dependencies.nom]
-version = "6"
-features = ["regexp"]
+version = "7"
+default-features = false
+features = ["alloc"]
```
# Related projects
diff --git a/doc/nom_recipes.md b/doc/nom_recipes.md
index 3507e88..8899485 100644
--- a/doc/nom_recipes.md
+++ b/doc/nom_recipes.md
@@ -25,6 +25,14 @@ These are short recipes for accomplishing common tasks with nom.
### Wrapper combinators that eat whitespace before and after a parser
```rust
+use nom::{
+ IResult,
+ error::ParseError,
+ combinator::value,
+ sequence::delimited,
+ character::complete::multispace0,
+};
+
/// A combinator that takes a parser `inner` and produces a parser that also consumes both leading and
/// trailing whitespace, returning the output of `inner`.
fn ws<'a, F: 'a, O, E: ParseError<&'a str>>(inner: F) -> impl FnMut(&'a str) -> IResult<&'a str, O, E>
@@ -52,6 +60,15 @@ This version uses `%` to start a comment, does not consume the newline character
output of `()`.
```rust
+use nom::{
+ IResult,
+ error::ParseError,
+ combinator::value,
+ sequence::pair,
+ bytes::complete::is_not,
+ character::complete::char,
+};
+
pub fn peol_comment<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (), E>
{
value(
@@ -67,6 +84,14 @@ Inline comments surrounded with sentinel tags `(*` and `*)`. This version return
and does not handle nested comments.
```rust
+use nom::{
+ IResult,
+ error::ParseError,
+ combinator::value,
+ sequence::tuple,
+ bytes::complete::{tag, take_until},
+};
+
pub fn pinline_comment<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (), E> {
value(
(), // Output is thrown away.
@@ -87,6 +112,16 @@ Parsing identifiers that may start with a letter (or underscore) and may contain
letters and numbers may be parsed like this:
```rust
+use nom::{
+ IResult,
+ branch::alt,
+ multi::many0,
+ combinator::recognize,
+ sequence::pair,
+ character::complete::{alpha1, alphanumeric1},
+ bytes::complete::tag,
+};
+
pub fn identifier(input: &str) -> IResult<&str, &str> {
recognize(
pair(
@@ -128,6 +163,16 @@ If you wish to limit the number of digits in a valid integer literal, replace `m
The parser outputs the string slice of the digits without the leading `0x`/`0X`.
```rust
+use nom::{
+ IResult,
+ branch::alt,
+ multi::{many0, many1},
+ combinator::recognize,
+ sequence::{preceded, terminated},
+ character::complete::{char, one_of},
+ bytes::complete::tag,
+};
+
fn hexadecimal(input: &str) -> IResult<&str, &str> { // <'a, E: ParseError<&'a str>>
preceded(
alt((tag("0x"), tag("0X"))),
@@ -143,6 +188,16 @@ fn hexadecimal(input: &str) -> IResult<&str, &str> { // <'a, E: ParseError<&'a s
If you want it to return the integer value instead, use map:
```rust
+use nom::{
+ IResult,
+ branch::alt,
+ multi::{many0, many1},
+ combinator::{map_res, recognize},
+ sequence::{preceded, terminated},
+ character::complete::{char, one_of},
+ bytes::complete::tag,
+};
+
fn hexadecimal_value(input: &str) -> IResult<&str, i64> {
map_res(
preceded(
@@ -161,6 +216,16 @@ fn hexadecimal_value(input: &str) -> IResult<&str, i64> {
#### Octal
```rust
+use nom::{
+ IResult,
+ branch::alt,
+ multi::{many0, many1},
+ combinator::recognize,
+ sequence::{preceded, terminated},
+ character::complete::{char, one_of},
+ bytes::complete::tag,
+};
+
fn octal(input: &str) -> IResult<&str, &str> {
preceded(
alt((tag("0o"), tag("0O"))),
@@ -176,6 +241,16 @@ fn octal(input: &str) -> IResult<&str, &str> {
#### Binary
```rust
+use nom::{
+ IResult,
+ branch::alt,
+ multi::{many0, many1},
+ combinator::recognize,
+ sequence::{preceded, terminated},
+ character::complete::{char, one_of},
+ bytes::complete::tag,
+};
+
fn binary(input: &str) -> IResult<&str, &str> {
preceded(
alt((tag("0b"), tag("0B"))),
@@ -191,6 +266,14 @@ fn binary(input: &str) -> IResult<&str, &str> {
#### Decimal
```rust
+use nom::{
+ IResult,
+ multi::{many0, many1},
+ combinator::recognize,
+ sequence::terminated,
+ character::complete::{char, one_of},
+};
+
fn decimal(input: &str) -> IResult<&str, &str> {
recognize(
many1(
@@ -205,6 +288,15 @@ fn decimal(input: &str) -> IResult<&str, &str> {
The following is adapted from [the Python parser by Valentin Lorentz (ProgVal)](https://github.com/ProgVal/rust-python-parser/blob/master/src/numbers.rs).
```rust
+use nom::{
+ IResult,
+ branch::alt,
+ multi::{many0, many1},
+ combinator::{opt, recognize},
+ sequence::{preceded, terminated, tuple},
+ character::complete::{char, one_of},
+};
+
fn float(input: &str) -> IResult<&str, &str> {
alt((
// Case one: .42
@@ -242,6 +334,14 @@ fn float(input: &str) -> IResult<&str, &str> {
)
))(input)
}
+
+fn decimal(input: &str) -> IResult<&str, &str> {
+ recognize(
+ many1(
+ terminated(one_of("0123456789"), many0(char('_')))
+ )
+ )(input)
+}
```
# implementing FromStr
diff --git a/patches/bitvec_dep.patch b/patches/bitvec_dep.patch
deleted file mode 100644
index 5f66f02..0000000
--- a/patches/bitvec_dep.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From: Dirkjan Ochtman <dirkjan@ochtman.nl>
-Date: Mon, 21 Jun 2021 11:33:39 +0200
-Subject: [PATCH] Remove bitvec from default features
-
----
-diff --git a/Cargo.toml b/Cargo.toml
-index c12e163..4d81557 100644
---- a/Cargo.toml
-+++ b/Cargo.toml
-@@ -182,12 +182,16 @@ version = "^0.3"
- version = "0.9"
-
- [features]
--alloc = ["bitvec/alloc", "funty"]
--default = ["std", "bitvec", "lexical"]
-+alloc = []
-+std = ["alloc", "memchr/use_std"]
-+bitvec-base = ["bitvec"]
-+bitvec-alloc = ["bitvec/alloc", "funty"]
-+bitvec-std = ["bitvec/std"]
-+default = ["std", "lexical"]
- docsrs = []
- lexical = ["lexical-core"]
- regexp = ["regex"]
--std = ["alloc", "bitvec/std", "memchr/use_std"]
-+
- [badges.coveralls]
- branch = "master"
- repository = "Geal/nom"
diff --git a/src/bits/complete.rs b/src/bits/complete.rs
index bce4df4..e9ad81a 100644
--- a/src/bits/complete.rs
+++ b/src/bits/complete.rs
@@ -7,6 +7,29 @@ use crate::lib::std::ops::{AddAssign, Div, RangeFrom, Shl, Shr};
use crate::traits::{InputIter, InputLength, Slice, ToUsize};
/// Generates a parser taking `count` bits
+///
+/// # Example
+/// ```rust
+/// # use nom::bits::complete::take;
+/// # use nom::IResult;
+/// # use nom::error::{Error, ErrorKind};
+/// // Input is a tuple of (input: I, bit_offset: usize)
+/// fn parser(input: (&[u8], usize), count: usize)-> IResult<(&[u8], usize), u8> {
+/// take(count)(input)
+/// }
+///
+/// // Consumes 0 bits, returns 0
+/// assert_eq!(parser(([0b00010010].as_ref(), 0), 0), Ok((([0b00010010].as_ref(), 0), 0)));
+///
+/// // Consumes 4 bits, returns their values and increase offset to 4
+/// assert_eq!(parser(([0b00010010].as_ref(), 0), 4), Ok((([0b00010010].as_ref(), 4), 0b00000001)));
+///
+/// // Consumes 4 bits, offset is 4, returns their values and increase offset to 0 of next byte
+/// assert_eq!(parser(([0b00010010].as_ref(), 4), 4), Ok((([].as_ref(), 0), 0b00000010)));
+///
+/// // Tries to consume 12 bits but only 8 are available
+/// assert_eq!(parser(([0b00010010].as_ref(), 0), 12), Err(nom::Err::Error(Error{input: ([0b00010010].as_ref(), 0), code: ErrorKind::Eof })));
+/// ```
pub fn take<I, O, C, E: ParseError<(I, usize)>>(
count: C,
) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
@@ -81,3 +104,47 @@ where
})
}
}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_take_0() {
+ let input = [0b00010010].as_ref();
+ let count = 0usize;
+ assert_eq!(count, 0usize);
+ let offset = 0usize;
+
+ let result: crate::IResult<(&[u8], usize), usize> = take(count)((input, offset));
+
+ assert_eq!(result, Ok(((input, offset), 0)));
+ }
+
+ #[test]
+ fn test_take_eof() {
+ let input = [0b00010010].as_ref();
+
+ let result: crate::IResult<(&[u8], usize), usize> = take(1usize)((input, 8));
+
+ assert_eq!(
+ result,
+ Err(crate::Err::Error(crate::error::Error {
+ input: (input, 8),
+ code: ErrorKind::Eof
+ }))
+ )
+ }
+
+ #[test]
+ fn test_take_span_over_multiple_bytes() {
+ let input = [0b00010010, 0b00110100, 0b11111111, 0b11111111].as_ref();
+
+ let result: crate::IResult<(&[u8], usize), usize> = take(24usize)((input, 4));
+
+ assert_eq!(
+ result,
+ Ok((([0b11111111].as_ref(), 4), 0b1000110100111111111111))
+ );
+ }
+}
diff --git a/src/bits/macros.rs b/src/bits/macros.rs
deleted file mode 100644
index d39f457..0000000
--- a/src/bits/macros.rs
+++ /dev/null
@@ -1,265 +0,0 @@
-//! Bit level parsers and combinators
-//!
-//! Bit parsing is handled by tweaking the input in most macros.
-//! In byte level parsing, the input is generally a `&[u8]` passed from combinator
-//! to combinator as the slices are manipulated.
-//!
-//! Bit parsers take a `(&[u8], usize)` as input. The first part of the tuple is a byte slice,
-//! the second part is a bit offset in the first byte of the slice.
-//!
-//! By passing a pair like this, we can leverage most of the existing combinators, and avoid
-//! transforming the whole slice to a vector of booleans. This should make it easy
-//! to see a byte slice as a bit stream, and parse code points of arbitrary bit length.
-//!
-
-/// Transforms its byte slice input into a bit stream for the underlying parser. This allows the
-/// given bit stream parser to work on a byte slice input.
-///
-/// Signature:
-/// `bits!( parser ) => ( &[u8], (&[u8], usize) -> IResult<(&[u8], usize), T> ) -> IResult<&[u8], T>`
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// # fn main() {
-/// named!( take_4_bits<u8>, bits!( take_bits!( 4u8 ) ) );
-///
-/// let input = vec![0xAB, 0xCD, 0xEF, 0x12];
-/// let sl = &input[..];
-///
-/// assert_eq!(take_4_bits( sl ), Ok( (&sl[1..], 0xA) ));
-/// assert_eq!(take_4_bits( &b""[..] ), Err(Err::Incomplete(Needed::new(1))));
-/// # }
-#[macro_export(local_inner_macros)]
-macro_rules! bits (
- ($i:expr, $submac:ident!( $($args:tt)* )) => ({
- $crate::bits::bitsc($i, move |i| { $submac!(i, $($args)*) })
- });
- ($i:expr, $f:expr) => (
- bits!($i, call!($f))
- );
-);
-
-/// Counterpart to `bits`, `bytes!` transforms its bit stream input into a byte slice for the underlying
-/// parser, allowing byte-slice parsers to work on bit streams.
-///
-/// Signature:
-/// `bytes!( parser ) => ( (&[u8], usize), &[u8] -> IResult<&[u8], T> ) -> IResult<(&[u8], usize), T>`,
-///
-/// A partial byte remaining in the input will be ignored and the given parser will start parsing
-/// at the next full byte.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::combinator::rest;
-/// # use nom::error::{Error, ErrorKind};
-/// # fn main() {
-///
-/// named!( parse<(u8, u8, &[u8])>, bits!( tuple!(
-/// take_bits!(4u8),
-/// take_bits!(8u8),
-/// bytes!(rest::<_, Error<_>>)
-/// )));
-///
-/// let input = &[0xde, 0xad, 0xbe, 0xaf];
-///
-/// assert_eq!(parse( input ), Ok(( &[][..], (0xd, 0xea, &[0xbe, 0xaf][..]) )));
-/// # }
-#[macro_export(local_inner_macros)]
-macro_rules! bytes (
- ($i:expr, $submac:ident!( $($args:tt)* )) => ({
- $crate::bits::bytesc($i, move |i| { $submac!(i, $($args)*) })
- });
- ($i:expr, $f:expr) => (
- bytes!($i, call!($f))
- );
-);
-
-/// Consumes the specified number of bits and returns them as the specified type.
-///
-/// Signature:
-/// `take_bits!(type, count) => ( (&[T], usize), U, usize) -> IResult<(&[T], usize), U>`
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(bits_pair<(&[u8], usize), (u8, u8)>, pair!( take_bits!(4u8), take_bits!(4u8) ) );
-/// named!( take_pair<(u8, u8)>, bits!( bits_pair ) );
-///
-/// let input = vec![0xAB, 0xCD, 0xEF];
-/// let sl = &input[..];
-///
-/// assert_eq!(take_pair( sl ), Ok((&sl[1..], (0xA, 0xB))) );
-/// assert_eq!(take_pair( &sl[1..] ), Ok((&sl[2..], (0xC, 0xD))) );
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_bits (
- ($i:expr, $count:expr) => (
- {
- let res: $crate::IResult<_, _> = $crate::bits::streaming::take($count)($i);
- res
- }
- );
-);
-
-/// Matches the given bit pattern.
-///
-/// Signature:
-/// `tag_bits!(type, count, pattern) => ( (&[T], usize), U, usize, U) -> IResult<(&[T], usize), U>`
-///
-/// The caller must specify the number of bits to consume. The matched value is included in the
-/// result on success.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!( take_a<u8>, bits!( tag_bits!(4usize, 0xA) ) );
-///
-/// let input = vec![0xAB, 0xCD, 0xEF];
-/// let sl = &input[..];
-///
-/// assert_eq!(take_a( sl ), Ok((&sl[1..], 0xA)) );
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! tag_bits (
- ($i:expr, $count:expr, $p: expr) => (
- {
- let res: $crate::IResult<_, _> = $crate::bits::streaming::tag($p, $count)($i);
- res
- }
- )
-);
-
-#[cfg(test)]
-mod tests {
- use crate::error::ErrorKind;
- use crate::internal::{Err, IResult, Needed};
- use crate::lib::std::ops::{AddAssign, Shl, Shr};
-
- #[test]
- fn take_bits() {
- let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
- let sl = &input[..];
-
- assert_eq!(take_bits!((sl, 0), 0u8), Ok(((sl, 0), 0)));
- assert_eq!(take_bits!((sl, 0), 8u8), Ok(((&sl[1..], 0), 170)));
- assert_eq!(take_bits!((sl, 0), 3u8), Ok(((&sl[0..], 3), 5)));
- assert_eq!(take_bits!((sl, 0), 6u8), Ok(((&sl[0..], 6), 42)));
- assert_eq!(take_bits!((sl, 1), 1u8), Ok(((&sl[0..], 2), 0)));
- assert_eq!(take_bits!((sl, 1), 2u8), Ok(((&sl[0..], 3), 1)));
- assert_eq!(take_bits!((sl, 1), 3u8), Ok(((&sl[0..], 4), 2)));
- assert_eq!(take_bits!((sl, 6), 3u8), Ok(((&sl[1..], 1), 5)));
- assert_eq!(take_bits!((sl, 0), 10u8), Ok(((&sl[1..], 2), 683)));
- assert_eq!(take_bits!((sl, 0), 8u8), Ok(((&sl[1..], 0), 170)));
- assert_eq!(take_bits!((sl, 6), 10u8), Ok(((&sl[2..], 0), 752)));
- assert_eq!(take_bits!((sl, 6), 11u8), Ok(((&sl[2..], 1), 1504)));
- assert_eq!(take_bits!((sl, 0), 20u8), Ok(((&sl[2..], 4), 700_163)));
- assert_eq!(take_bits!((sl, 4), 20u8), Ok(((&sl[3..], 0), 716_851)));
- let r: IResult<_, u32> = take_bits!((sl, 4), 22u8);
- assert_eq!(r, Err(Err::Incomplete(Needed::new(22))));
- }
-
- #[test]
- fn tag_bits() {
- let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
- let sl = &input[..];
-
- assert_eq!(tag_bits!((sl, 0), 3u8, 0b101), Ok(((&sl[0..], 3), 5)));
- assert_eq!(tag_bits!((sl, 0), 4u8, 0b1010), Ok(((&sl[0..], 4), 10)));
- }
-
- named!(ch<(&[u8],usize),(u8,u8)>,
- do_parse!(
- tag_bits!(3u8, 0b101) >>
- x: take_bits!(4u8) >>
- y: take_bits!(5u8) >>
- (x,y)
- )
- );
-
- #[test]
- fn chain_bits() {
- let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
- let sl = &input[..];
- assert_eq!(ch((&input[..], 0)), Ok(((&sl[1..], 4), (5, 15))));
- assert_eq!(ch((&input[..], 4)), Ok(((&sl[2..], 0), (7, 16))));
- assert_eq!(ch((&input[..1], 0)), Err(Err::Incomplete(Needed::new(5))));
- }
-
- named!(ch_bytes<(u8, u8)>, bits!(ch));
- #[test]
- fn bits_to_bytes() {
- let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
- assert_eq!(ch_bytes(&input[..]), Ok((&input[2..], (5, 15))));
- assert_eq!(ch_bytes(&input[..1]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(
- ch_bytes(&input[1..]),
- Err(Err::Error(error_position!(&input[1..], ErrorKind::TagBits)))
- );
- }
-
- named!(
- bits_bytes_bs,
- bits!(bytes!(
- crate::combinator::rest::<_, crate::error::Error<&[u8]>>
- ))
- );
- #[test]
- fn bits_bytes() {
- let input = [0b10_10_10_10];
- assert_eq!(
- bits_bytes_bs(&input[..]),
- Ok((&[][..], &[0b10_10_10_10][..]))
- );
- }
-
- #[derive(PartialEq, Debug)]
- struct FakeUint(u32);
-
- impl AddAssign for FakeUint {
- fn add_assign(&mut self, other: FakeUint) {
- *self = FakeUint(self.0 + other.0);
- }
- }
-
- impl Shr<usize> for FakeUint {
- type Output = FakeUint;
-
- fn shr(self, shift: usize) -> FakeUint {
- FakeUint(self.0 >> shift)
- }
- }
-
- impl Shl<usize> for FakeUint {
- type Output = FakeUint;
-
- fn shl(self, shift: usize) -> FakeUint {
- FakeUint(self.0 << shift)
- }
- }
-
- impl From<u8> for FakeUint {
- fn from(i: u8) -> FakeUint {
- FakeUint(u32::from(i))
- }
- }
-
- #[test]
- fn non_privitive_type() {
- let input = [0b10_10_10_10, 0b11_11_00_00, 0b00_11_00_11];
- let sl = &input[..];
-
- assert_eq!(
- take_bits!((sl, 0), 20u8),
- Ok(((&sl[2..], 4), FakeUint(700_163)))
- );
- assert_eq!(
- take_bits!((sl, 4), 20u8),
- Ok(((&sl[3..], 0), FakeUint(716_851)))
- );
- let r3: IResult<_, FakeUint> = take_bits!((sl, 4), 22u8);
- assert_eq!(r3, Err(Err::Incomplete(Needed::new(22))));
- }
-}
diff --git a/src/bits/mod.rs b/src/bits/mod.rs
index c5d1ac7..235b797 100644
--- a/src/bits/mod.rs
+++ b/src/bits/mod.rs
@@ -1,9 +1,6 @@
//! Bit level parsers
//!
-#[macro_use]
-mod macros;
-
pub mod complete;
pub mod streaming;
@@ -61,18 +58,6 @@ where
}
}
-#[doc(hidden)]
-pub fn bitsc<I, O, E1: ParseError<(I, usize)> + ErrorConvert<E2>, E2: ParseError<I>, P>(
- input: I,
- parser: P,
-) -> IResult<I, O, E2>
-where
- I: Slice<RangeFrom<usize>>,
- P: FnMut((I, usize)) -> IResult<(I, usize), O, E1>,
-{
- bits(parser)(input)
-}
-
/// Counterpart to `bits`, `bytes` transforms its bit stream input into a byte slice for the underlying
/// parser, allowing byte-slice parsers to work on bit streams.
///
@@ -125,18 +110,6 @@ where
}
}
-#[doc(hidden)]
-pub fn bytesc<I, O, E1: ParseError<I> + ErrorConvert<E2>, E2: ParseError<(I, usize)>, P>(
- input: (I, usize),
- parser: P,
-) -> IResult<(I, usize), O, E2>
-where
- I: Slice<RangeFrom<usize>> + Clone,
- P: FnMut(I) -> IResult<I, O, E1>,
-{
- bytes(parser)(input)
-}
-
#[cfg(test)]
mod test {
use super::*;
diff --git a/src/branch/macros.rs b/src/branch/macros.rs
deleted file mode 100644
index a9a3a33..0000000
--- a/src/branch/macros.rs
+++ /dev/null
@@ -1,954 +0,0 @@
-/// Try a list of parsers and return the result of the first successful one
-///
-/// ```rust,ignore
-/// alt!(I -> IResult<I,O> | I -> IResult<I,O> | ... | I -> IResult<I,O> ) => I -> IResult<I, O>
-/// ```
-/// All the parsers must have the same return type.
-///
-/// If one of the parsers returns `Incomplete`, `alt!` will return `Incomplete`, to retry
-/// once you get more input. Note that it is better for performance to know the
-/// minimum size of data you need before you get into `alt!`.
-///
-/// The `alt!` combinator is used in the following way:
-///
-/// ```rust,ignore
-/// alt!(parser_1 | parser_2 | ... | parser_n)
-/// ```
-///
-/// # Basic example
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// // Create a parser that will match either "dragon" or "beast"
-/// named!( dragon_or_beast, alt!( tag!( "dragon" ) | tag!( "beast" ) ) );
-///
-/// // Given the input "dragon slayer", the parser will match "dragon"
-/// // and the rest will be " slayer"
-/// let (rest, result) = dragon_or_beast(b"dragon slayer").unwrap();
-/// assert_eq!(result, b"dragon");
-/// assert_eq!(rest, b" slayer");
-///
-/// // Given the input "beast of Gevaudan", the parser will match "beast"
-/// // and the rest will be " of Gevaudan"
-/// let (rest, result) = dragon_or_beast(&b"beast of Gevaudan"[..]).unwrap();
-/// assert_eq!(result, b"beast");
-/// assert_eq!(rest, b" of Gevaudan");
-/// # }
-/// ```
-///
-/// # Manipulate results
-///
-/// There exists another syntax for `alt!` that gives you the ability to
-/// manipulate the result from each parser:
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// #
-/// // We create an enum to represent our creatures
-/// #[derive(Debug,PartialEq,Eq)]
-/// enum Creature {
-/// Dragon,
-/// Beast,
-/// Unknown(usize)
-/// }
-///
-/// // Let's make a helper function that returns true when not a space
-/// // we are required to do this because the `take_while!` macro is limited
-/// // to idents, so we can't negate `ìs_space` at the call site
-/// fn is_not_space(c: u8) -> bool { ! nom::character::is_space(c) }
-///
-/// // Our parser will return the `Dragon` variant when matching "dragon",
-/// // the `Beast` variant when matching "beast" and otherwise it will consume
-/// // the input until a space is found and return an `Unknown` creature with
-/// // the size of it's name.
-/// named!(creature<Creature>, alt!(
-/// tag!("dragon") => { |_| Creature::Dragon } |
-/// tag!("beast") => { |_| Creature::Beast } |
-/// take_while!(is_not_space) => { |r: &[u8]| Creature::Unknown(r.len()) }
-/// // the closure takes the result as argument if the parser is successful
-/// ));
-///
-/// // Given the input "dragon slayer" the parser will return `Creature::Dragon`
-/// // and the rest will be " slayer"
-/// let (rest, result) = creature(b"dragon slayer").unwrap();
-/// assert_eq!(result, Creature::Dragon);
-/// assert_eq!(rest, b" slayer");
-///
-/// // Given the input "beast of Gevaudan" the parser will return `Creature::Beast`
-/// // and the rest will be " of Gevaudan"
-/// let (rest, result) = creature(b"beast of Gevaudan").unwrap();
-/// assert_eq!(result, Creature::Beast);
-/// assert_eq!(rest, b" of Gevaudan");
-///
-/// // Given the input "demon hunter" the parser will return `Creature::Unknown(5)`
-/// // and the rest will be " hunter"
-/// let (rest, result) = creature(b"demon hunter").unwrap();
-/// assert_eq!(result, Creature::Unknown(5));
-/// assert_eq!(rest, b" hunter");
-/// # }
-/// ```
-///
-/// # Behaviour of `alt!`
-///
-/// **BE CAREFUL** there is a case where the behaviour of `alt!` can be confusing:
-///
-/// When the alternatives have different lengths, like this case:
-///
-/// ```ignore
-/// named!( test, alt!( tag!( "abcd" ) | tag!( "ef" ) | tag!( "ghi" ) | tag!( "kl" ) ) );
-/// ```
-///
-/// With this parser, if you pass `"abcd"` as input, the first alternative parses it correctly,
-/// but if you pass `"efg"`, the first alternative will return `Incomplete`, since it needs an input
-/// of 4 bytes. This behaviour of `alt!` is expected: if you get a partial input that isn't matched
-/// by the first alternative, but would match if the input was complete, you want `alt!` to indicate
-/// that it cannot decide with limited information.
-///
-/// There are two ways to fix this behaviour. The first one consists in ordering the alternatives
-/// by size, like this:
-///
-/// ```ignore
-/// named!( test, alt!( tag!( "ef" ) | tag!( "kl") | tag!( "ghi" ) | tag!( "abcd" ) ) );
-/// ```
-///
-/// With this solution, the largest alternative will be tested last.
-///
-/// The other solution uses the `complete!` combinator, which transforms an `Incomplete` in an
-/// `Error`. If one of the alternatives returns `Incomplete` but is wrapped by `complete!`,
-/// `alt!` will try the next alternative. This is useful when you know that
-/// you will not get partial input:
-///
-/// ```ignore
-/// named!( test,
-/// alt!(
-/// complete!( tag!( "abcd" ) ) |
-/// complete!( tag!( "ef" ) ) |
-/// complete!( tag!( "ghi" ) ) |
-/// complete!( tag!( "kl" ) )
-/// )
-/// );
-/// ```
-///
-/// This behaviour of `alt!` can get especially confusing if multiple alternatives have different
-/// sizes but a common prefix, like this:
-///
-/// ```ignore
-/// named!( test, alt!( tag!( "abcd" ) | tag!( "ab" ) | tag!( "ef" ) ) );
-/// ```
-///
-/// In that case, if you order by size, passing `"abcd"` as input will always be matched by the
-/// smallest parser, so the solution using `complete!` is better suited.
-///
-/// You can also nest multiple `alt!`, like this:
-///
-/// ```ignore
-/// named!( test,
-/// alt!(
-/// preceded!(
-/// tag!("ab"),
-/// alt!(
-/// tag!( "cd" ) |
-/// eof!()
-/// )
-/// )
-/// | tag!( "ef" )
-/// )
-/// );
-/// ```
-///
-/// `preceded!` will first parse `"ab"` then, if successful, try the alternatives "cd",
-/// or empty input (End Of File). If none of them work, `preceded!` will fail and
-/// "ef" will be tested.
-///
-#[macro_export(local_inner_macros)]
-macro_rules! alt (
- (__impl $i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)* ) => (
- nom_compile_error!("alt uses '|' as separator, not ',':
-
- alt!(
- tag!(\"abcd\") |
- tag!(\"efgh\") |
- tag!(\"ijkl\")
- )
- ");
- );
- (__impl $i:expr, $e:path, $($rest:tt)* ) => (
- alt!(__impl $i, call!($e) , $($rest)*);
- );
- (__impl $i:expr, $e:path | $($rest:tt)*) => (
- alt!(__impl $i, call!($e) | $($rest)*);
- );
-
- (__impl $i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::Err;
-
- let i_ = $i.clone();
- let res = $subrule!(i_, $($args)*);
- match res {
- Ok(o) => Ok(o),
- Err(Err::Error(e)) => {
- let out = alt!(__impl $i, $($rest)*);
-
- // Compile-time hack to ensure that res's E type is not under-specified.
- // This all has no effect at runtime.
- #[allow(dead_code)]
- fn unify_types<T>(_: &T, _: &T) {}
- if let Err(Err::Error(ref e2)) = out {
- unify_types(&e, e2);
- }
-
- out
- },
- Err(e) => Err(e),
- }
- }
- );
-
- (__impl $i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)*) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::Err;
-
- let i_ = $i.clone();
- match $subrule!(i_, $($args)* ) {
- Ok((i,o)) => Ok((i,$gen(o))),
- Err(Err::Error(e)) => {
- let out = alt!(__impl $i, $($rest)*);
-
- // Compile-time hack to ensure that res's E type is not under-specified.
- // This all has no effect at runtime.
- fn unify_types<T>(_: &T, _: &T) {}
- if let Err(Err::Error(ref e2)) = out {
- unify_types(&e, e2);
- }
-
- out
- },
- Err(e) => Err(e),
- }
- }
- );
-
- (__impl $i:expr, $e:path => { $gen:expr } | $($rest:tt)*) => (
- alt!(__impl $i, call!($e) => { $gen } | $($rest)*);
- );
-
- (__impl $i:expr, __end) => (
- {
- use $crate::{Err,error::ErrorKind};
- let e2 = ErrorKind::Alt;
- let err = Err::Error(error_position!($i, e2));
-
- Err(err)
- }
- );
-
- ($i:expr, $($rest:tt)*) => (
- {
- alt!(__impl $i, $($rest)* | __end)
- }
- );
-);
-
-/// `switch!(I -> IResult<I,P>, P => I -> IResult<I,O> | ... | P => I -> IResult<I,O> ) => I -> IResult<I, O>`
-/// choose the next parser depending on the result of the first one, if successful,
-/// and returns the result of the second parser
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(sw,
-/// switch!(take!(4),
-/// b"abcd" => tag!("XYZ") |
-/// b"efgh" => tag!("123")
-/// )
-/// );
-///
-/// let a = b"abcdXYZ123";
-/// let b = b"abcdef";
-/// let c = b"efgh123";
-/// let d = b"blah";
-///
-/// assert_eq!(sw(&a[..]), Ok((&b"123"[..], &b"XYZ"[..])));
-/// assert_eq!(sw(&b[..]), Err(Err::Error(error_node_position!(&b"abcdef"[..], ErrorKind::Switch,
-/// error_position!(&b"ef"[..], ErrorKind::Tag)))));
-/// assert_eq!(sw(&c[..]), Ok((&b""[..], &b"123"[..])));
-/// assert_eq!(sw(&d[..]), Err(Err::Error(error_position!(&b"blah"[..], ErrorKind::Switch))));
-/// # }
-/// ```
-///
-/// You can specify a default case like with a normal match, using `_`
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(sw,
-/// switch!(take!(4),
-/// b"abcd" => tag!("XYZ") |
-/// _ => value!(&b"default"[..])
-/// )
-/// );
-///
-/// let a = b"abcdXYZ123";
-/// let b = b"blah";
-///
-/// assert_eq!(sw(&a[..]), Ok((&b"123"[..], &b"XYZ"[..])));
-/// assert_eq!(sw(&b[..]), Ok((&b""[..], &b"default"[..])));
-/// # }
-/// ```
-///
-/// Due to limitations in Rust macros, it is not possible to have simple functions on the right hand
-/// side of pattern, like this:
-///
-/// ```ignore
-/// named!(xyz, tag!("XYZ"));
-/// named!(num, tag!("123"));
-/// named!(sw,
-/// switch!(take!(4),
-/// b"abcd" => xyz |
-/// b"efgh" => 123
-/// )
-/// );
-/// ```
-///
-/// If you want to pass your own functions instead, you can use the `call!` combinator as follows:
-///
-/// ```ignore
-/// named!(xyz, tag!("XYZ"));
-/// named!(num, tag!("123"));
-/// named!(sw,
-/// switch!(take!(4),
-/// b"abcd" => call!(xyz) |
-/// b"efgh" => call!(num)
-/// )
-/// );
-/// ```
-///
-#[macro_export(local_inner_macros)]
-macro_rules! switch (
- (__impl $i:expr, $submac:ident!( $($args:tt)* ), $( $($p:pat)|+ => $subrule:ident!( $($args2:tt)* ))|* ) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::lib::std::option::Option::*;
- use $crate::{Err,error::ErrorKind};
-
- let i_ = $i.clone();
- match map!(i_, $submac!($($args)*), Some) {
- Err(Err::Error(err)) => {
- fn unify_types<T>(_: &T, _: &T) {}
- let e1 = ErrorKind::Switch;
- let e2 = error_position!($i, e1.clone());
- unify_types(&err, &e2);
-
- Err(Err::Error(error_node_position!($i, e1, err)))
- },
- Err(e) => Err(e),
- Ok((i, o)) => {
-
- match o {
- $($(Some($p) )|+ => match $subrule!(i, $($args2)*) {
- Err(Err::Error(err)) => {
- fn unify_types<T>(_: &T, _: &T) {}
- let e1 = ErrorKind::Switch;
- let e2 = error_position!($i, e1.clone());
- unify_types(&err, &e2);
-
- Err(Err::Error(error_node_position!($i, e1, err)))
- },
- Ok(o) => Ok(o),
- Err(e) => Err(e),
- }),*,
- _ => Err(Err::convert(Err::Error(error_position!($i, ErrorKind::Switch))))
- }
- }
- }
- }
- );
- ($i:expr, $submac:ident!( $($args:tt)*), $($rest:tt)*) => (
- {
- switch!(__impl $i, $submac!($($args)*), $($rest)*)
- }
- );
- ($i:expr, $e:path, $($rest:tt)*) => (
- {
- switch!(__impl $i, call!($e), $($rest)*)
- }
- );
-);
-
-/// `permutation!(I -> IResult<I,A>, I -> IResult<I,B>, ... I -> IResult<I,X> ) => I -> IResult<I, (A,B,...X)>`
-/// applies its sub parsers in a sequence, but independent from their order
-/// this parser will only succeed if all of its sub parsers succeed.
-///
-/// The tuple of results is in the same order as the parsers are declared
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::ErrorKind,Needed};
-/// # fn main() {
-/// named!(perm<(&[u8], &[u8], &[u8])>,
-/// permutation!(tag!("abcd"), tag!("efg"), tag!("hi"))
-/// );
-///
-/// // whatever the order, if the parser succeeds, each
-/// // tag should have matched correctly
-/// let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]);
-///
-/// let a = &b"abcdefghijk"[..];
-/// assert_eq!(perm(a), Ok((&b"jk"[..], expected)));
-/// let b = &b"efgabcdhijkl"[..];
-/// assert_eq!(perm(b), Ok((&b"jkl"[..], expected)));
-/// let c = &b"hiefgabcdjklm"[..];
-/// assert_eq!(perm(c), Ok((&b"jklm"[..], expected)));
-///
-/// let d = &b"efgxyzabcdefghi"[..];
-/// assert_eq!(perm(d), Err(Err::Error(error_node_position!(&b"efgxyzabcdefghi"[..], ErrorKind::Permutation,
-/// error_position!(&b"xyzabcdefghi"[..], ErrorKind::Permutation)))));
-///
-/// let e = &b"efgabc"[..];
-/// assert_eq!(perm(e), Err(Err::Incomplete(Needed::new(1))));
-/// # }
-/// ```
-///
-/// If one of the child parsers is followed by a `?`, that parser is now
-/// optional:
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::ErrorKind,Needed};
-/// # fn main() {
-/// named!(perm<&str, (Option<&str>, &str, &str)>,
-/// permutation!(tag!("abcd")?, tag!("efg"), tag!("hi"))
-/// );
-///
-/// // whatever the order, if the parser succeeds, each
-/// // tag should have matched correctly
-/// let expected = (Some("abcd"), "efg", "hi");
-///
-/// let a = "abcdefghijk";
-/// assert_eq!(perm(a), Ok(("jk", expected)));
-/// let b = "efgabcdhijkl";
-/// assert_eq!(perm(b), Ok(("jkl", expected)));
-/// let c = "hiefgabcdjklm";
-/// assert_eq!(perm(c), Ok(("jklm", expected)));
-///
-/// // if `abcd` is missing:
-/// let expected = (None, "efg", "hi");
-///
-/// let a = "efghijk";
-/// assert_eq!(perm(a), Ok(("jk", expected)));
-/// let b = "efghijkl";
-/// assert_eq!(perm(b), Ok(("jkl", expected)));
-/// let c = "hiefgjklm";
-/// assert_eq!(perm(c), Ok(("jklm", expected)));
-///
-/// let e = "efgabc";
-/// assert_eq!(perm(e), Err(Err::Incomplete(Needed::new(1))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! permutation (
- ($i:expr, $($rest:tt)*) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::lib::std::option::Option::*;
- use $crate::{Err,error::ErrorKind};
-
- let mut res = permutation_init!((), $($rest)*);
- let mut input = $i;
- let mut error = None;
- let mut needed = None;
-
- loop {
- let mut all_done = true;
- permutation_iterator!(0, input, all_done, needed, res, $($rest)*);
-
- //if we reach that part, it means none of the parsers were able to read anything
- if !all_done {
- //FIXME: should wrap the error returned by the child parser
- error = Some(error_position!(input, ErrorKind::Permutation));
- }
- break;
- }
-
- if let Some(need) = needed {
- Err(Err::convert(need))
- } else {
- if let Some(unwrapped_res) = { permutation_unwrap!(0, (), res, $($rest)*) } {
- Ok((input, unwrapped_res))
- } else {
- if let Some(e) = error {
- Err(Err::Error(error_node_position!($i, ErrorKind::Permutation, e)))
- } else {
- Err(Err::Error(error_position!($i, ErrorKind::Permutation)))
- }
- }
- }
- }
- );
-);
-
-#[doc(hidden)]
-#[macro_export(local_inner_macros)]
-macro_rules! permutation_init (
- ((), $e:ident?, $($rest:tt)*) => (
- permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
- );
- ((), $e:ident, $($rest:tt)*) => (
- permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
- );
-
- ((), $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
- permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
- );
- ((), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
- permutation_init!(($crate::lib::std::option::Option::None), $($rest)*)
- );
-
- (($($parsed:expr),*), $e:ident?, $($rest:tt)*) => (
- permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
- );
- (($($parsed:expr),*), $e:ident, $($rest:tt)*) => (
- permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
- );
-
- (($($parsed:expr),*), $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
- permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
- );
- (($($parsed:expr),*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
- permutation_init!(($($parsed),* , $crate::lib::std::option::Option::None), $($rest)*);
- );
-
- (($($parsed:expr),*), $e:ident) => (
- ($($parsed),* , $crate::lib::std::option::Option::None)
- );
- (($($parsed:expr),*), $e:ident?) => (
- ($($parsed),* , $crate::lib::std::option::Option::None)
- );
-
- (($($parsed:expr),*), $submac:ident!( $($args:tt)* )?) => (
- ($($parsed),* , $crate::lib::std::option::Option::None)
- );
- (($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => (
- ($($parsed),* , $crate::lib::std::option::Option::None)
- );
- (($($parsed:expr),*),) => (
- ($($parsed),*)
- );
-);
-
-#[doc(hidden)]
-#[macro_export(local_inner_macros)]
-macro_rules! succ (
- (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
- (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
- (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
- (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
- (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
- (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
- (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
- (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
- (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
- (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
- (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
- (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
- (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
- (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
- (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
- (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
- (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
- (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
- (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
- (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
- (20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
-);
-
-#[doc(hidden)]
-#[macro_export(local_inner_macros)]
-macro_rules! permutation_unwrap (
- ($it:tt, (), $res:ident, $e:ident?, $($rest:tt)*) => (
- succ!($it, permutation_unwrap!(($res.$it), $res, $($rest)*));
- );
- ($it:tt, (), $res:ident, $e:ident, $($rest:tt)*) => ({
- let res = $res.$it;
- if res.is_some() {
- succ!($it, permutation_unwrap!((res.unwrap()), $res, $($rest)*))
- } else {
- $crate::lib::std::option::Option::None
- }
- });
-
- ($it:tt, (), $res:ident, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
- succ!($it, permutation_unwrap!(($res.$it), $res, $($rest)*));
- );
- ($it:tt, (), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
- let res = $res.$it;
- if res.is_some() {
- succ!($it, permutation_unwrap!((res.unwrap()), $res, $($rest)*))
- } else {
- $crate::lib::std::option::Option::None
- }
- });
-
- ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident?, $($rest:tt)*) => (
- succ!($it, permutation_unwrap!(($($parsed),* , $res.$it), $res, $($rest)*));
- );
- ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident, $($rest:tt)*) => ({
- let res = $res.$it;
- if res.is_some() {
- succ!($it, permutation_unwrap!(($($parsed),* , res.unwrap()), $res, $($rest)*))
- } else {
- $crate::lib::std::option::Option::None
- }
- });
-
- ($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => (
- succ!($it, permutation_unwrap!(($($parsed),* , $res.$it), $res, $($rest)*));
- );
- ($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
- let res = $res.$it;
- if res.is_some() {
- succ!($it, permutation_unwrap!(($($parsed),* , res.unwrap()), $res, $($rest)*))
- } else {
- $crate::lib::std::option::Option::None
- }
- });
-
- ($it:tt, ($($parsed:expr),*), $res:ident?, $e:ident) => (
- $crate::lib::std::option::Option::Some(($($parsed),* , { $res.$it }))
- );
- ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident) => ({
- let res = $res.$it;
- if res.is_some() {
- $crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
- } else {
- $crate::lib::std::option::Option::None
- }
- });
-
- ($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )?) => (
- $crate::lib::std::option::Option::Some(($($parsed),* , { $res.$it }))
- );
- ($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )) => ({
- let res = $res.$it;
- if res.is_some() {
- $crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
- } else {
- $crate::lib::std::option::Option::None
- }
- });
-);
-
-#[doc(hidden)]
-#[macro_export(local_inner_macros)]
-macro_rules! permutation_iterator (
- ($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident?, $($rest:tt)*) => (
- permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e), $($rest)*);
- );
- ($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident, $($rest:tt)*) => (
- permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e), $($rest)*);
- );
-
- ($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => {
- permutation_iterator!($it, $i, $all_done, $needed, $res, $submac!($($args)*) , $($rest)*);
- };
- ($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({
- use $crate::lib::std::result::Result::*;
- use $crate::lib::std::option::Option::*;
- use $crate::Err;
-
- if $res.$it.is_none() {
- match $submac!($i, $($args)*) {
- Ok((i,o)) => {
- $i = i;
- $res.$it = Some(o);
- continue;
- },
- Err(Err::Error(_)) => {
- $all_done = false;
- },
- Err(e) => {
- $needed = Some(e);
- break;
- }
- };
- }
- succ!($it, permutation_iterator!($i, $all_done, $needed, $res, $($rest)*));
- });
-
- ($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident?) => (
- permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e));
- );
- ($it:tt,$i:expr, $all_done:expr, $needed:expr, $res:expr, $e:ident) => (
- permutation_iterator!($it, $i, $all_done, $needed, $res, call!($e));
- );
-
- ($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?) => {
- permutation_iterator!($it, $i, $all_done, $needed, $res, $submac!($($args)*));
- };
- ($it:tt, $i:expr, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )) => ({
- use $crate::lib::std::result::Result::*;
- use $crate::lib::std::option::Option::*;
- use $crate::Err;
-
- if $res.$it.is_none() {
- match $submac!($i, $($args)*) {
- Ok((i,o)) => {
- $i = i;
- $res.$it = Some(o);
- continue;
- },
- Err(Err::Error(_)) => {
- $all_done = false;
- },
- Err(e) => {
- $needed = Some(e);
- break;
- }
- };
- }
- });
-);
-
-#[cfg(test)]
-mod tests {
- use crate::error::ErrorKind;
- use crate::internal::{Err, IResult, Needed};
- #[cfg(feature = "alloc")]
- use crate::{
- error::ParseError,
- lib::std::{
- fmt::Debug,
- string::{String, ToString},
- },
- };
-
- // reproduce the tag and take macros, because of module import order
- macro_rules! tag (
- ($i:expr, $inp: expr) => (
- {
- #[inline(always)]
- fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
- b.as_bytes()
- }
-
- let expected = $inp;
- let bytes = as_bytes(&expected);
-
- tag_bytes!($i,bytes)
- }
- );
- );
-
- macro_rules! tag_bytes (
- ($i:expr, $bytes: expr) => (
- {
- use $crate::lib::std::cmp::min;
-
- let len = $i.len();
- let blen = $bytes.len();
- let m = min(len, blen);
- let reduced = &$i[..m];
- let b = &$bytes[..m];
-
- let res: IResult<_,_,_> = if reduced != b {
- let e: ErrorKind = ErrorKind::Tag;
- Err(Err::Error(error_position!($i, e)))
- } else if m < blen {
- Err(Err::Incomplete(Needed::new(blen)))
- } else {
- Ok((&$i[blen..], reduced))
- };
- res
- }
- );
- );
-
- macro_rules! take(
- ($i:expr, $count:expr) => (
- {
- let cnt = $count as usize;
- let res:IResult<&[u8],&[u8],_> = if $i.len() < cnt {
- Err(Err::Incomplete(Needed::new(cnt)))
- } else {
- Ok((&$i[cnt..],&$i[0..cnt]))
- };
- res
- }
- );
- );
-
- #[cfg(feature = "alloc")]
- #[derive(Debug, Clone, PartialEq)]
- pub struct ErrorStr(String);
-
- #[cfg(feature = "alloc")]
- impl From<u32> for ErrorStr {
- fn from(i: u32) -> Self {
- ErrorStr(format!("custom error code: {}", i))
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<'a> From<&'a str> for ErrorStr {
- fn from(i: &'a str) -> Self {
- ErrorStr(format!("custom error message: {}", i))
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<I: Debug> ParseError<I> for ErrorStr {
- fn from_error_kind(input: I, kind: ErrorKind) -> Self {
- ErrorStr(format!("custom error message: ({:?}, {:?})", input, kind))
- }
-
- fn append(input: I, kind: ErrorKind, other: Self) -> Self {
- ErrorStr(format!(
- "custom error message: ({:?}, {:?}) - {:?}",
- input, kind, other
- ))
- }
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn alt() {
- fn work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
- Ok((&b""[..], input))
- }
-
- #[allow(unused_variables)]
- fn dont_work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
- Err(Err::Error(ErrorStr("abcd".to_string())))
- }
-
- fn work2(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
- Ok((input, &b""[..]))
- }
-
- fn alt1(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
- alt!(i, dont_work | dont_work)
- }
- fn alt2(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
- alt!(i, dont_work | work)
- }
- fn alt3(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
- alt!(i, dont_work | dont_work | work2 | dont_work)
- }
- //named!(alt1, alt!(dont_work | dont_work));
- //named!(alt2, alt!(dont_work | work));
- //named!(alt3, alt!(dont_work | dont_work | work2 | dont_work));
-
- let a = &b"abcd"[..];
- assert_eq!(alt1(a), Err(Err::Error(error_position!(a, ErrorKind::Alt))));
- assert_eq!(alt2(a), Ok((&b""[..], a)));
- assert_eq!(alt3(a), Ok((a, &b""[..])));
-
- named!(alt4, alt!(tag!("abcd") | tag!("efgh")));
- let b = &b"efgh"[..];
- assert_eq!(alt4(a), Ok((&b""[..], a)));
- assert_eq!(alt4(b), Ok((&b""[..], b)));
-
- // test the alternative syntax
- named!(
- alt5<bool>,
- alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true })
- );
- assert_eq!(alt5(a), Ok((&b""[..], false)));
- assert_eq!(alt5(b), Ok((&b""[..], true)));
-
- // compile-time test guarding against an underspecified E generic type (#474)
- named!(alt_eof1, alt!(eof!() | eof!()));
- named!(alt_eof2, alt!(eof!() => {|x| x} | eof!() => {|x| x}));
- let _ = (alt_eof1, alt_eof2);
- }
-
- #[test]
- fn alt_incomplete() {
- named!(alt1, alt!(tag!("a") | tag!("bc") | tag!("def")));
-
- let a = &b""[..];
- assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(1))));
- let a = &b"b"[..];
- assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(2))));
- let a = &b"bcd"[..];
- assert_eq!(alt1(a), Ok((&b"d"[..], &b"bc"[..])));
- let a = &b"cde"[..];
- assert_eq!(alt1(a), Err(Err::Error(error_position!(a, ErrorKind::Alt))));
- let a = &b"de"[..];
- assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(3))));
- let a = &b"defg"[..];
- assert_eq!(alt1(a), Ok((&b"g"[..], &b"def"[..])));
- }
-
- #[allow(unused_variables)]
- #[test]
- fn switch() {
- named!(
- sw,
- switch!(take!(4),
- b"abcd" | b"xxxx" => take!(2) |
- b"efgh" => take!(4)
- )
- );
-
- let a = &b"abcdefgh"[..];
- assert_eq!(sw(a), Ok((&b"gh"[..], &b"ef"[..])));
-
- let b = &b"efghijkl"[..];
- assert_eq!(sw(b), Ok((&b""[..], &b"ijkl"[..])));
- let c = &b"afghijkl"[..];
- assert_eq!(
- sw(c),
- Err(Err::Error(error_position!(
- &b"afghijkl"[..],
- ErrorKind::Switch
- )))
- );
-
- let a = &b"xxxxefgh"[..];
- assert_eq!(sw(a), Ok((&b"gh"[..], &b"ef"[..])));
- }
-
- #[test]
- fn permutation() {
- named!(
- perm<(&[u8], &[u8], &[u8])>,
- permutation!(tag!("abcd"), tag!("efg"), tag!("hi"))
- );
-
- let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]);
-
- let a = &b"abcdefghijk"[..];
- assert_eq!(perm(a), Ok((&b"jk"[..], expected)));
- let b = &b"efgabcdhijk"[..];
- assert_eq!(perm(b), Ok((&b"jk"[..], expected)));
- let c = &b"hiefgabcdjk"[..];
- assert_eq!(perm(c), Ok((&b"jk"[..], expected)));
-
- let d = &b"efgxyzabcdefghi"[..];
- assert_eq!(
- perm(d),
- Err(Err::Error(error_node_position!(
- &b"efgxyzabcdefghi"[..],
- ErrorKind::Permutation,
- error_position!(&b"xyzabcdefghi"[..], ErrorKind::Permutation)
- )))
- );
-
- let e = &b"efgabc"[..];
- assert_eq!(perm(e), Err(Err::Incomplete(Needed::new(4))));
- }
-
- /*
- named!(does_not_compile,
- alt!(tag!("abcd"), tag!("efgh"))
- );
- */
-}
diff --git a/src/branch/mod.rs b/src/branch/mod.rs
index 6c0adc7..902d4e8 100644
--- a/src/branch/mod.rs
+++ b/src/branch/mod.rs
@@ -1,7 +1,31 @@
//! Choice combinators
-#[macro_use]
-mod macros;
+macro_rules! succ (
+ (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
+ (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
+ (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
+ (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
+ (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
+ (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
+ (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
+ (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
+ (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
+ (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
+ (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
+ (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
+ (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
+ (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
+ (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
+ (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
+ (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
+ (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
+ (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
+ (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
+ (20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
+);
+
+#[cfg(test)]
+mod tests;
use crate::error::ErrorKind;
use crate::error::ParseError;
diff --git a/src/branch/tests.rs b/src/branch/tests.rs
new file mode 100644
index 0000000..ecd4440
--- /dev/null
+++ b/src/branch/tests.rs
@@ -0,0 +1,142 @@
+use crate::branch::{alt, permutation};
+use crate::bytes::streaming::tag;
+use crate::error::ErrorKind;
+use crate::internal::{Err, IResult, Needed};
+#[cfg(feature = "alloc")]
+use crate::{
+ error::ParseError,
+ lib::std::{
+ fmt::Debug,
+ string::{String, ToString},
+ },
+};
+
+#[cfg(feature = "alloc")]
+#[derive(Debug, Clone, PartialEq)]
+pub struct ErrorStr(String);
+
+#[cfg(feature = "alloc")]
+impl From<u32> for ErrorStr {
+ fn from(i: u32) -> Self {
+ ErrorStr(format!("custom error code: {}", i))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a> From<&'a str> for ErrorStr {
+ fn from(i: &'a str) -> Self {
+ ErrorStr(format!("custom error message: {}", i))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<I: Debug> ParseError<I> for ErrorStr {
+ fn from_error_kind(input: I, kind: ErrorKind) -> Self {
+ ErrorStr(format!("custom error message: ({:?}, {:?})", input, kind))
+ }
+
+ fn append(input: I, kind: ErrorKind, other: Self) -> Self {
+ ErrorStr(format!(
+ "custom error message: ({:?}, {:?}) - {:?}",
+ input, kind, other
+ ))
+ }
+}
+
+#[cfg(feature = "alloc")]
+#[test]
+fn alt_test() {
+ fn work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
+ Ok((&b""[..], input))
+ }
+
+ #[allow(unused_variables)]
+ fn dont_work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
+ Err(Err::Error(ErrorStr("abcd".to_string())))
+ }
+
+ fn work2(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
+ Ok((input, &b""[..]))
+ }
+
+ fn alt1(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
+ alt((dont_work, dont_work))(i)
+ }
+ fn alt2(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
+ alt((dont_work, work))(i)
+ }
+ fn alt3(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> {
+ alt((dont_work, dont_work, work2, dont_work))(i)
+ }
+ //named!(alt1, alt!(dont_work | dont_work));
+ //named!(alt2, alt!(dont_work | work));
+ //named!(alt3, alt!(dont_work | dont_work | work2 | dont_work));
+
+ let a = &b"abcd"[..];
+ assert_eq!(
+ alt1(a),
+ Err(Err::Error(error_node_position!(
+ a,
+ ErrorKind::Alt,
+ ErrorStr("abcd".to_string())
+ )))
+ );
+ assert_eq!(alt2(a), Ok((&b""[..], a)));
+ assert_eq!(alt3(a), Ok((a, &b""[..])));
+
+ fn alt4(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ alt((tag("abcd"), tag("efgh")))(i)
+ }
+ let b = &b"efgh"[..];
+ assert_eq!(alt4(a), Ok((&b""[..], a)));
+ assert_eq!(alt4(b), Ok((&b""[..], b)));
+}
+
+#[test]
+fn alt_incomplete() {
+ fn alt1(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ alt((tag("a"), tag("bc"), tag("def")))(i)
+ }
+
+ let a = &b""[..];
+ assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(1))));
+ let a = &b"b"[..];
+ assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(1))));
+ let a = &b"bcd"[..];
+ assert_eq!(alt1(a), Ok((&b"d"[..], &b"bc"[..])));
+ let a = &b"cde"[..];
+ assert_eq!(alt1(a), Err(Err::Error(error_position!(a, ErrorKind::Tag))));
+ let a = &b"de"[..];
+ assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(1))));
+ let a = &b"defg"[..];
+ assert_eq!(alt1(a), Ok((&b"g"[..], &b"def"[..])));
+}
+
+#[test]
+fn permutation_test() {
+ fn perm(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8], &[u8])> {
+ permutation((tag("abcd"), tag("efg"), tag("hi")))(i)
+ }
+
+ let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]);
+
+ let a = &b"abcdefghijk"[..];
+ assert_eq!(perm(a), Ok((&b"jk"[..], expected)));
+ let b = &b"efgabcdhijk"[..];
+ assert_eq!(perm(b), Ok((&b"jk"[..], expected)));
+ let c = &b"hiefgabcdjk"[..];
+ assert_eq!(perm(c), Ok((&b"jk"[..], expected)));
+
+ let d = &b"efgxyzabcdefghi"[..];
+ assert_eq!(
+ perm(d),
+ Err(Err::Error(error_node_position!(
+ &b"efgxyzabcdefghi"[..],
+ ErrorKind::Permutation,
+ error_position!(&b"xyzabcdefghi"[..], ErrorKind::Tag)
+ )))
+ );
+
+ let e = &b"efgabc"[..];
+ assert_eq!(perm(e), Err(Err::Incomplete(Needed::new(1))));
+}
diff --git a/src/bytes/complete.rs b/src/bytes/complete.rs
index 37824da..8a0c88b 100644
--- a/src/bytes/complete.rs
+++ b/src/bytes/complete.rs
@@ -448,6 +448,44 @@ where
}
}
+/// Returns the non empty input slice up to the first occurrence of the pattern.
+///
+/// It doesn't consume the pattern. It will return `Err(Err::Error((_, ErrorKind::TakeUntil)))`
+/// if the pattern wasn't met.
+/// # Example
+/// ```rust
+/// # #[macro_use] extern crate nom;
+/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
+/// use nom::bytes::complete::take_until1;
+///
+/// fn until_eof(s: &str) -> IResult<&str, &str> {
+/// take_until1("eof")(s)
+/// }
+///
+/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world")));
+/// assert_eq!(until_eof("hello, world"), Err(Err::Error(Error::new("hello, world", ErrorKind::TakeUntil))));
+/// assert_eq!(until_eof(""), Err(Err::Error(Error::new("", ErrorKind::TakeUntil))));
+/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1")));
+/// assert_eq!(until_eof("eof"), Err(Err::Error(Error::new("eof", ErrorKind::TakeUntil))));
+/// ```
+pub fn take_until1<T, Input, Error: ParseError<Input>>(
+ tag: T,
+) -> impl Fn(Input) -> IResult<Input, Input, Error>
+where
+ Input: InputTake + FindSubstring<T>,
+ T: InputLength + Clone,
+{
+ move |i: Input| {
+ let t = tag.clone();
+ let res: IResult<_, _, Error> = match i.find_substring(t) {
+ None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))),
+ Some(0) => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))),
+ Some(index) => Ok(i.take_split(index)),
+ };
+ res
+ }
+}
+
/// Matches a byte string with escaped characters.
///
/// * The first argument matches the normal characters (it must not accept the control character)
@@ -493,10 +531,17 @@ where
let mut i = input.clone();
while i.input_len() > 0 {
+ let current_len = i.input_len();
+
match normal.parse(i.clone()) {
Ok((i2, _)) => {
+ // return if we consumed everything or if the normal parser
+ // does not consume anything
if i2.input_len() == 0 {
return Ok((input.slice(input.input_len()..), input));
+ } else if i2.input_len() == current_len {
+ let index = input.offset(&i2);
+ return Ok(input.take_split(index));
} else {
i = i2;
}
@@ -543,29 +588,6 @@ where
}
}
-#[doc(hidden)]
-pub fn escapedc<Input, Error, F, G, O1, O2>(
- i: Input,
- normal: F,
- control_char: char,
- escapable: G,
-) -> IResult<Input, Input, Error>
-where
- Input: Clone
- + crate::traits::Offset
- + InputLength
- + InputTake
- + InputTakeAtPosition
- + Slice<RangeFrom<usize>>
- + InputIter,
- <Input as InputIter>::Item: crate::traits::AsChar,
- F: Fn(Input) -> IResult<Input, O1, Error>,
- G: Fn(Input) -> IResult<Input, O2, Error>,
- Error: ParseError<Input>,
-{
- escaped(normal, control_char, escapable)(i)
-}
-
/// Matches a byte string with escaped characters.
///
/// * The first argument matches the normal characters (it must not match the control character)
@@ -630,12 +652,15 @@ where
let i = input.clone();
while index < i.input_len() {
+ let current_len = i.input_len();
let remainder = i.slice(index..);
match normal.parse(remainder.clone()) {
Ok((i2, o)) => {
o.extend_into(&mut res);
if i2.input_len() == 0 {
return Ok((i.slice(i.input_len()..), res));
+ } else if i2.input_len() == current_len {
+ return Ok((remainder, res));
} else {
index = input.offset(&i2);
}
@@ -681,34 +706,6 @@ where
}
}
-#[doc(hidden)]
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-pub fn escaped_transformc<Input, Error, F, G, O1, O2, ExtendItem, Output>(
- i: Input,
- normal: F,
- control_char: char,
- transform: G,
-) -> IResult<Input, Output, Error>
-where
- Input: Clone
- + crate::traits::Offset
- + InputLength
- + InputTake
- + InputTakeAtPosition
- + Slice<RangeFrom<usize>>
- + InputIter,
- Input: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>,
- O1: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>,
- O2: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>,
- <Input as InputIter>::Item: crate::traits::AsChar,
- F: Fn(Input) -> IResult<Input, O1, Error>,
- G: Fn(Input) -> IResult<Input, O2, Error>,
- Error: ParseError<Input>,
-{
- escaped_transform(normal, control_char, transform)(i)
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -726,4 +723,36 @@ mod tests {
super::take_while_m_n(1, 1, |c: char| c.is_alphabetic())("øn");
assert_eq!(result, Ok(("n", "ø")));
}
+
+ // issue #1336 "escaped hangs if normal parser accepts empty"
+ fn escaped_string(input: &str) -> IResult<&str, &str> {
+ use crate::character::complete::{alpha0, one_of};
+ escaped(alpha0, '\\', one_of("n"))(input)
+ }
+
+ // issue #1336 "escaped hangs if normal parser accepts empty"
+ #[test]
+ fn escaped_hang() {
+ escaped_string("7").unwrap();
+ escaped_string("a7").unwrap();
+ }
+
+ // issue ##1118 escaped does not work with empty string
+ fn unquote<'a>(input: &'a str) -> IResult<&'a str, &'a str> {
+ use crate::bytes::complete::*;
+ use crate::character::complete::*;
+ use crate::combinator::opt;
+ use crate::sequence::delimited;
+
+ delimited(
+ char('"'),
+ escaped(opt(none_of(r#"\""#)), '\\', one_of(r#"\"rnt"#)),
+ char('"'),
+ )(input)
+ }
+
+ #[test]
+ fn escaped_hang_1118() {
+ assert_eq!(unquote(r#""""#), Ok(("", "")));
+ }
}
diff --git a/src/bytes/macros.rs b/src/bytes/macros.rs
deleted file mode 100644
index eedb040..0000000
--- a/src/bytes/macros.rs
+++ /dev/null
@@ -1,994 +0,0 @@
-//! Byte level parsers and combinators
-//!
-#[allow(unused_variables)]
-
-/// `tag!(&[T]: nom::AsBytes) => &[T] -> IResult<&[T], &[T]>`
-/// declares a byte array as a suite to recognize.
-///
-/// Consumes the recognized characters.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(x, tag!("abcd"));
-/// let r = x(&b"abcdefgh"[..]);
-/// assert_eq!(r, Ok((&b"efgh"[..], &b"abcd"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! tag (
- ($i:expr, $tag: expr) => ({
- $crate::bytes::streaming::tag($tag)($i)
- });
-);
-
-/// `tag_no_case!(&[T]) => &[T] -> IResult<&[T], &[T]>`
-/// declares a case insensitive ascii string as a suite to recognize.
-///
-/// Consumes the recognized characters.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(test, tag_no_case!("ABcd"));
-///
-/// let r = test(&b"aBCdefgh"[..]);
-/// assert_eq!(r, Ok((&b"efgh"[..], &b"aBCd"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! tag_no_case (
- ($i:expr, $tag: expr) => ({
- $crate::bytes::streaming::tag_no_case($tag)($i)
- });
-);
-
-/// `is_not!(&[T:AsBytes]) => &[T] -> IResult<&[T], &[T]>`
-/// returns the longest list of bytes that do not appear in the provided array.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!( not_space, is_not!( " \t\r\n" ) );
-///
-/// let r = not_space(&b"abcdefgh\nijkl"[..]);
-/// assert_eq!(r, Ok((&b"\nijkl"[..], &b"abcdefgh"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! is_not (
- ($input:expr, $arr:expr) => ({
- $crate::bytes::streaming::is_not($arr)($input)
- });
-);
-
-/// `is_a!(&[T]) => &[T] -> IResult<&[T], &[T]>`
-/// returns the longest list of bytes that appear in the provided array.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(abcd, is_a!( "abcd" ));
-///
-/// let r1 = abcd(&b"aaaaefgh"[..]);
-/// assert_eq!(r1, Ok((&b"efgh"[..], &b"aaaa"[..])));
-///
-/// let r2 = abcd(&b"dcbaefgh"[..]);
-/// assert_eq!(r2, Ok((&b"efgh"[..], &b"dcba"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! is_a (
- ($input:expr, $arr:expr) => ({
- $crate::bytes::streaming::is_a($arr)($input)
- });
-);
-
-/// `escaped!(T -> IResult<T, T>, U, T -> IResult<T, T>) => T -> IResult<T, T> where T: InputIter,
-/// U: AsChar`
-/// matches a byte string with escaped characters.
-///
-/// * The first argument matches the normal characters (it must not accept the control character)
-/// * The second argument is the control character (like `\` in most languages)
-/// * The third argument matches the escaped characters
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::character::complete::digit1;
-/// # fn main() {
-/// named!(esc, escaped!(call!(digit1), '\\', one_of!("\"n\\")));
-/// assert_eq!(esc(&b"123;"[..]), Ok((&b";"[..], &b"123"[..])));
-/// assert_eq!(esc(&b"12\\\"34;"[..]), Ok((&b";"[..], &b"12\\\"34"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! escaped (
- ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => (
- {
- escaped!($i, |i| $submac1!(i, $($args)*), $control_char, |i| $submac2!(i, $($args2)*))
- }
- );
- ($i:expr, $normal:expr, $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => (
- {
- escaped!($i, $normal, $control_char, |i| $submac2!(i, $($args2)*))
- }
- );
- ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $escapable:expr ) => (
- {
- escaped!($i, |i| $submac1!(i, $($args)*), $control_char, $escapable)
- }
- );
- ($i:expr, $normal:expr, $control_char: expr, $escapable:expr) => (
- {
- $crate::bytes::complete::escapedc($i, $normal, $control_char, $escapable)
- }
- );
-);
-
-/// `escaped_transform!(&[T] -> IResult<&[T], &[T]>, T, &[T] -> IResult<&[T], &[T]>) => &[T] -> IResult<&[T], Vec<T>>`
-/// matches a byte string with escaped characters.
-///
-/// * The first argument matches the normal characters (it must not match the control character)
-/// * The second argument is the control character (like `\` in most languages)
-/// * The third argument matches the escaped characters and transforms them
-///
-/// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character).
-/// # Example
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::character::complete::alpha1;
-/// # use nom::lib::std::str::from_utf8;
-/// # fn main() {
-/// fn to_s(i:Vec<u8>) -> String {
-/// String::from_utf8_lossy(&i).into_owned()
-/// }
-///
-/// named!(transform < String >,
-/// map!(
-/// escaped_transform!(call!(alpha1), '\\',
-/// alt!(
-/// tag!("\\") => { |_| &b"\\"[..] }
-/// | tag!("\"") => { |_| &b"\""[..] }
-/// | tag!("n") => { |_| &b"\n"[..] }
-/// )
-/// ), to_s
-/// )
-/// );
-/// assert_eq!(transform(&b"ab\\\"cd"[..]), Ok((&b""[..], String::from("ab\"cd"))));
-/// # }
-/// ```
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-#[macro_export(local_inner_macros)]
-macro_rules! escaped_transform (
- ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => (
- {
- escaped_transform!($i, |i| $submac1!(i, $($args)*), $control_char, |i| $submac2!(i, $($args2)*))
- }
- );
- ($i:expr, $normal:expr, $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => (
- {
- escaped_transform!($i, $normal, $control_char, |i| $submac2!(i, $($args2)*))
- }
- );
- ($i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $transform:expr ) => (
- {
- escaped_transform!($i, |i| $submac1!(i, $($args)*), $control_char, $transform)
- }
- );
- ($i:expr, $normal:expr, $control_char: expr, $transform:expr) => (
- {
- $crate::bytes::complete::escaped_transformc($i, $normal, $control_char, $transform)
- }
- );
-);
-
-/// `take_while!(T -> bool) => &[T] -> IResult<&[T], &[T]>`
-/// returns the longest list of bytes until the provided function fails.
-///
-/// The argument is either a function `T -> bool` or a macro returning a `bool`.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::character::is_alphanumeric;
-/// # fn main() {
-/// named!( alpha, take_while!( is_alphanumeric ) );
-///
-/// let r = alpha(&b"abcd\nefgh"[..]);
-/// assert_eq!(r, Ok((&b"\nefgh"[..], &b"abcd"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_while (
- ($input:expr, $submac:ident!( $($args:tt)* )) => ({
- let res: $crate::IResult<_, _, _> = take_while!($input, (|c| $submac!(c, $($args)*)));
- res
- });
- ($input:expr, $f:expr) => (
- $crate::bytes::streaming::take_while($f)($input)
- );
-);
-
-/// `take_while1!(T -> bool) => &[T] -> IResult<&[T], &[T]>`
-/// returns the longest (non empty) list of bytes until the provided function fails.
-///
-/// The argument is either a function `&[T] -> bool` or a macro returning a `bool`.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::ErrorKind};
-/// # use nom::character::is_alphanumeric;
-/// # fn main() {
-/// named!( alpha, take_while1!( is_alphanumeric ) );
-///
-/// let r = alpha(&b"abcd\nefgh"[..]);
-/// assert_eq!(r, Ok((&b"\nefgh"[..], &b"abcd"[..])));
-/// let r = alpha(&b"\nefgh"[..]);
-/// assert_eq!(r, Err(Err::Error(error_position!(&b"\nefgh"[..], ErrorKind::TakeWhile1))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_while1 (
- ($input:expr, $submac:ident!( $($args:tt)* )) => ({
- let res: $crate::IResult<_, _, _> = take_while1!($input, (|c| $submac!(c, $($args)*)));
- res
- });
- ($input:expr, $f:expr) => (
- $crate::bytes::streaming::take_while1($f)($input)
- );
-);
-
-/// `take_while_m_n!(m: usize, n: usize, T -> bool) => &[T] -> IResult<&[T], &[T]>`
-/// returns a list of bytes or characters for which the provided function returns true.
-/// The returned list's size will be at least m, and at most n.
-///
-/// The argument is either a function `T -> bool` or a macro returning a `bool`.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::character::is_alphanumeric;
-/// # fn main() {
-/// named!( alpha, take_while_m_n!(3, 6, is_alphanumeric ) );
-///
-/// let r = alpha(&b"abcd\nefgh"[..]);
-/// assert_eq!(r, Ok((&b"\nefgh"[..], &b"abcd"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_while_m_n (
- ($input:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* )) => ({
- let res: $crate::IResult<_, _, _> = take_while_m_n!($input, $m, $n, (|c| $submac!(c, $($args)*)));
- res
- });
- ($input:expr, $m:expr, $n:expr, $f:expr) => (
- $crate::bytes::streaming::take_while_m_n($m, $n, $f)($input)
- );
-);
-
-/// `take_till!(T -> bool) => &[T] -> IResult<&[T], &[T]>`
-/// returns the longest list of bytes until the provided function succeeds.
-///
-/// The argument is either a function `&[T] -> bool` or a macro returning a `bool`.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!( till_colon, take_till!(|ch| ch == b':') );
-///
-/// let r = till_colon(&b"abcd:efgh"[..]);
-/// assert_eq!(r, Ok((&b":efgh"[..], &b"abcd"[..])));
-/// let r2 = till_colon(&b":abcdefgh"[..]); // empty match is allowed
-/// assert_eq!(r2, Ok((&b":abcdefgh"[..], &b""[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_till (
- ($input:expr, $submac:ident!( $($args:tt)* )) => ({
- let res: $crate::IResult<_, _, _> = take_till!($input, (|c| $submac!(c, $($args)*)));
- res
- });
- ($input:expr, $f:expr) => (
- $crate::bytes::streaming::take_till($f)($input)
- );
-);
-
-/// `take_till1!(T -> bool) => &[T] -> IResult<&[T], &[T]>`
-/// returns the longest non empty list of bytes until the provided function succeeds.
-///
-/// The argument is either a function `&[T] -> bool` or a macro returning a `bool`.
-///
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, error::ErrorKind};
-/// # fn main() {
-/// named!( till1_colon, take_till1!(|ch| ch == b':') );
-///
-/// let r = till1_colon(&b"abcd:efgh"[..]);
-/// assert_eq!(r, Ok((&b":efgh"[..], &b"abcd"[..])));
-///
-/// let r2 = till1_colon(&b":abcdefgh"[..]); // empty match is error
-/// assert_eq!(r2, Err(Err::Error(error_position!(&b":abcdefgh"[..], ErrorKind::TakeTill1))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_till1 (
- ($input:expr, $submac:ident!( $($args:tt)* )) => ({
- let res: $crate::IResult<_, _, _> = take_till1!($input, (|c| $submac!(c, $($args)*)));
- res
- });
- ($input:expr, $f:expr) => (
- $crate::bytes::streaming::take_till1($f)($input)
- );
-);
-
-/// `take!(nb) => &[T] -> IResult<&[T], &[T]>`
-/// generates a parser consuming the specified number of bytes.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// // Desmond parser
-/// named!(take5, take!( 5 ) );
-///
-/// let a = b"abcdefgh";
-///
-/// assert_eq!(take5(&a[..]), Ok((&b"fgh"[..], &b"abcde"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take (
- ($i:expr, $count:expr) => ({
- let c = $count as usize;
- let res: $crate::IResult<_,_,_> = $crate::bytes::streaming::take(c)($i);
- res
- });
-);
-
-/// `take_str!(nb) => &[T] -> IResult<&[T], &str>`
-/// same as `take!` but returning a `&str`.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(take5( &[u8] ) -> &str, take_str!( 5 ) );
-///
-/// let a = b"abcdefgh";
-///
-/// assert_eq!(take5(&a[..]), Ok((&b"fgh"[..], "abcde")));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_str (
- ( $i:expr, $size:expr ) => (
- {
- let input: &[u8] = $i;
-
- map_res!(input, take!($size), $crate::lib::std::str::from_utf8)
- }
- );
-);
-
-/// `take_until!(tag) => &[T] -> IResult<&[T], &[T]>`
-/// consumes data until it finds the specified tag.
-///
-/// The remainder still contains the tag.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(x, take_until!("foo"));
-/// let r = x(&b"abcd foo efgh"[..]);
-/// assert_eq!(r, Ok((&b"foo efgh"[..], &b"abcd "[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_until (
- ($i:expr, $substr:expr) => ({
- let res: $crate::IResult<_,_,_> = $crate::bytes::streaming::take_until($substr)($i);
- res
- });
-);
-
-/// `take_until1!(tag) => &[T] -> IResult<&[T], &[T]>`
-/// consumes data (at least one byte) until it finds the specified tag.
-///
-/// The remainder still contains the tag.
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(x, take_until1!("foo"));
-///
-/// let r = x(&b"abcd foo efgh"[..]);
-///
-/// assert_eq!(r, Ok((&b"foo efgh"[..], &b"abcd "[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! take_until1 (
- ($i:expr, $substr:expr) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::lib::std::option::Option::*;
- use $crate::{Err,Needed,IResult,error::ErrorKind};
- use $crate::InputLength;
- use $crate::FindSubstring;
- use $crate::InputTake;
- let input = $i;
-
- let res: IResult<_,_> = match input.find_substring($substr) {
- None => {
- Err(Err::Incomplete(Needed::new(1 + $substr.input_len())))
- },
- Some(0) => {
- let e = ErrorKind::TakeUntil;
- Err(Err::Error(error_position!($i, e)))
- },
- Some(index) => {
- Ok($i.take_split(index))
- },
- };
- res
- }
- );
-);
-
-#[cfg(test)]
-mod tests {
- use crate::character::is_alphabetic;
- use crate::character::streaming::{
- alpha1 as alpha, alphanumeric1 as alphanumeric, digit1 as digit, hex_digit1 as hex_digit,
- multispace1 as multispace, oct_digit1 as oct_digit, space1 as space,
- };
- use crate::error::ErrorKind;
- use crate::internal::{Err, IResult, Needed};
- #[cfg(feature = "alloc")]
- use crate::lib::std::string::String;
- #[cfg(feature = "alloc")]
- use crate::lib::std::vec::Vec;
-
- #[cfg(feature = "alloc")]
- macro_rules! one_of (
- ($i:expr, $inp: expr) => (
- {
- use $crate::Err;
- use $crate::Slice;
- use $crate::AsChar;
- use $crate::FindToken;
- use $crate::InputIter;
-
- match ($i).iter_elements().next().map(|c| {
- $inp.find_token(c)
- }) {
- None => Err::<_,_>(Err::Incomplete(Needed::new(1))),
- Some(false) => Err(Err::Error(error_position!($i, ErrorKind::OneOf))),
- //the unwrap should be safe here
- Some(true) => Ok(($i.slice(1..), $i.iter_elements().next().unwrap().as_char()))
- }
- }
- );
- );
-
- #[test]
- fn is_a() {
- named!(a_or_b, is_a!(&b"ab"[..]));
-
- let a = &b"abcd"[..];
- assert_eq!(a_or_b(a), Ok((&b"cd"[..], &b"ab"[..])));
-
- let b = &b"bcde"[..];
- assert_eq!(a_or_b(b), Ok((&b"cde"[..], &b"b"[..])));
-
- let c = &b"cdef"[..];
- assert_eq!(
- a_or_b(c),
- Err(Err::Error(error_position!(c, ErrorKind::IsA)))
- );
-
- let d = &b"bacdef"[..];
- assert_eq!(a_or_b(d), Ok((&b"cdef"[..], &b"ba"[..])));
- }
-
- #[test]
- fn is_not() {
- named!(a_or_b, is_not!(&b"ab"[..]));
-
- let a = &b"cdab"[..];
- assert_eq!(a_or_b(a), Ok((&b"ab"[..], &b"cd"[..])));
-
- let b = &b"cbde"[..];
- assert_eq!(a_or_b(b), Ok((&b"bde"[..], &b"c"[..])));
-
- let c = &b"abab"[..];
- assert_eq!(
- a_or_b(c),
- Err(Err::Error(error_position!(c, ErrorKind::IsNot)))
- );
-
- let d = &b"cdefba"[..];
- assert_eq!(a_or_b(d), Ok((&b"ba"[..], &b"cdef"[..])));
-
- let e = &b"e"[..];
- assert_eq!(a_or_b(e), Err(Err::Incomplete(Needed::new(1))));
- }
-
- #[cfg(feature = "alloc")]
- #[allow(unused_variables)]
- #[test]
- fn escaping() {
- named!(esc, escaped!(call!(alpha), '\\', one_of!("\"n\\")));
- assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], &b"abcd"[..])));
- assert_eq!(esc(&b"ab\\\"cd;"[..]), Ok((&b";"[..], &b"ab\\\"cd"[..])));
- assert_eq!(esc(&b"\\\"abcd;"[..]), Ok((&b";"[..], &b"\\\"abcd"[..])));
- assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], &b"\\n"[..])));
- assert_eq!(esc(&b"ab\\\"12"[..]), Ok((&b"12"[..], &b"ab\\\""[..])));
- assert_eq!(
- esc(&b"AB\\"[..]),
- Err(Err::Error(error_position!(
- &b"AB\\"[..],
- ErrorKind::Escaped
- )))
- );
- assert_eq!(
- esc(&b"AB\\A"[..]),
- Err(Err::Error(error_node_position!(
- &b"AB\\A"[..],
- ErrorKind::Escaped,
- error_position!(&b"A"[..], ErrorKind::OneOf)
- )))
- );
-
- named!(esc2, escaped!(call!(digit), '\\', one_of!("\"n\\")));
- assert_eq!(esc2(&b"12\\nnn34"[..]), Ok((&b"nn34"[..], &b"12\\n"[..])));
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn escaping_str() {
- named!(esc<&str, &str>, escaped!(call!(alpha), '\\', one_of!("\"n\\")));
- assert_eq!(esc("abcd;"), Ok((";", "abcd")));
- assert_eq!(esc("ab\\\"cd;"), Ok((";", "ab\\\"cd")));
- assert_eq!(esc("\\\"abcd;"), Ok((";", "\\\"abcd")));
- assert_eq!(esc("\\n;"), Ok((";", "\\n")));
- assert_eq!(esc("ab\\\"12"), Ok(("12", "ab\\\"")));
- assert_eq!(
- esc("AB\\"),
- Err(Err::Error(error_position!("AB\\", ErrorKind::Escaped)))
- );
- assert_eq!(
- esc("AB\\A"),
- Err(Err::Error(error_node_position!(
- "AB\\A",
- ErrorKind::Escaped,
- error_position!("A", ErrorKind::OneOf)
- )))
- );
-
- named!(esc2<&str, &str>, escaped!(call!(digit), '\\', one_of!("\"n\\")));
- assert_eq!(esc2("12\\nnn34"), Ok(("nn34", "12\\n")));
-
- named!(esc3<&str, &str>, escaped!(call!(alpha), '\u{241b}', one_of!("\"n")));
- assert_eq!(esc3("ab␛ncd;"), Ok((";", "ab␛ncd")));
- }
-
- #[cfg(feature = "alloc")]
- fn to_s(i: Vec<u8>) -> String {
- String::from_utf8_lossy(&i).into_owned()
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn escape_transform() {
- use crate::lib::std::str;
-
- named!(
- esc<String>,
- map!(
- escaped_transform!(
- alpha,
- '\\',
- alt!(
- tag!("\\") => { |_| &b"\\"[..] }
- | tag!("\"") => { |_| &b"\""[..] }
- | tag!("n") => { |_| &b"\n"[..] }
- )
- ),
- to_s
- )
- );
-
- assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], String::from("abcd"))));
- assert_eq!(
- esc(&b"ab\\\"cd;"[..]),
- Ok((&b";"[..], String::from("ab\"cd")))
- );
- assert_eq!(
- esc(&b"\\\"abcd;"[..]),
- Ok((&b";"[..], String::from("\"abcd")))
- );
- assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], String::from("\n"))));
- assert_eq!(
- esc(&b"ab\\\"12"[..]),
- Ok((&b"12"[..], String::from("ab\"")))
- );
- assert_eq!(
- esc(&b"AB\\"[..]),
- Err(Err::Error(error_position!(
- &b"\\"[..],
- ErrorKind::EscapedTransform
- )))
- );
- assert_eq!(
- esc(&b"AB\\A"[..]),
- Err(Err::Error(error_node_position!(
- &b"AB\\A"[..],
- ErrorKind::EscapedTransform,
- error_position!(&b"A"[..], ErrorKind::Alt)
- )))
- );
-
- named!(
- esc2<String>,
- map!(
- escaped_transform!(
- call!(alpha),
- '&',
- alt!(
- tag!("egrave;") => { |_| str::as_bytes("è") }
- | tag!("agrave;") => { |_| str::as_bytes("à") }
- )
- ),
- to_s
- )
- );
- assert_eq!(
- esc2(&b"ab&egrave;DEF;"[..]),
- Ok((&b";"[..], String::from("abèDEF")))
- );
- assert_eq!(
- esc2(&b"ab&egrave;D&agrave;EF;"[..]),
- Ok((&b";"[..], String::from("abèDàEF")))
- );
- }
-
- #[cfg(feature = "std")]
- #[test]
- fn escape_transform_str() {
- named!(esc<&str, String>, escaped_transform!(alpha, '\\',
- alt!(
- tag!("\\") => { |_| "\\" }
- | tag!("\"") => { |_| "\"" }
- | tag!("n") => { |_| "\n" }
- ))
- );
-
- assert_eq!(esc("abcd;"), Ok((";", String::from("abcd"))));
- assert_eq!(esc("ab\\\"cd;"), Ok((";", String::from("ab\"cd"))));
- assert_eq!(esc("\\\"abcd;"), Ok((";", String::from("\"abcd"))));
- assert_eq!(esc("\\n;"), Ok((";", String::from("\n"))));
- assert_eq!(esc("ab\\\"12"), Ok(("12", String::from("ab\""))));
- assert_eq!(
- esc("AB\\"),
- Err(Err::Error(error_position!(
- "\\",
- ErrorKind::EscapedTransform
- )))
- );
- assert_eq!(
- esc("AB\\A"),
- Err(Err::Error(error_node_position!(
- "AB\\A",
- ErrorKind::EscapedTransform,
- error_position!("A", ErrorKind::Alt)
- )))
- );
-
- named!(esc2<&str, String>, escaped_transform!(alpha, '&',
- alt!(
- tag!("egrave;") => { |_| "è" }
- | tag!("agrave;") => { |_| "à" }
- ))
- );
- assert_eq!(esc2("ab&egrave;DEF;"), Ok((";", String::from("abèDEF"))));
- assert_eq!(
- esc2("ab&egrave;D&agrave;EF;"),
- Ok((";", String::from("abèDàEF")))
- );
-
- named!(esc3<&str, String>, escaped_transform!(alpha, '␛',
- alt!(
- tag!("0") => { |_| "\0" } |
- tag!("n") => { |_| "\n" })));
- assert_eq!(esc3("a␛0bc␛n"), Ok(("", String::from("a\0bc\n"))));
- }
-
- #[test]
- fn take_str_test() {
- let a = b"omnomnom";
-
- let res: IResult<_, _, (&[u8], ErrorKind)> = take_str!(&a[..], 5u32);
- assert_eq!(res, Ok((&b"nom"[..], "omnom")));
-
- let res: IResult<_, _, (&[u8], ErrorKind)> = take_str!(&a[..], 9u32);
- assert_eq!(res, Err(Err::Incomplete(Needed::new(1))));
- }
-
- #[test]
- fn take_until_incomplete() {
- named!(y, take_until!("end"));
- assert_eq!(y(&b"nd"[..]), Err(Err::Incomplete(Needed::Unknown)));
- assert_eq!(y(&b"123"[..]), Err(Err::Incomplete(Needed::Unknown)));
- assert_eq!(y(&b"123en"[..]), Err(Err::Incomplete(Needed::Unknown)));
- }
-
- #[test]
- fn take_until_incomplete_s() {
- named!(ys<&str, &str>, take_until!("end"));
- assert_eq!(ys("123en"), Err(Err::Incomplete(Needed::Unknown)));
- }
-
- #[test]
- fn recognize() {
- named!(
- x,
- recognize!(delimited!(tag!("<!--"), take!(5usize), tag!("-->")))
- );
- let r = x(&b"<!-- abc --> aaa"[..]);
- assert_eq!(r, Ok((&b" aaa"[..], &b"<!-- abc -->"[..])));
-
- let semicolon = &b";"[..];
-
- named!(ya, recognize!(alpha));
- let ra = ya(&b"abc;"[..]);
- assert_eq!(ra, Ok((semicolon, &b"abc"[..])));
-
- named!(yd, recognize!(digit));
- let rd = yd(&b"123;"[..]);
- assert_eq!(rd, Ok((semicolon, &b"123"[..])));
-
- named!(yhd, recognize!(hex_digit));
- let rhd = yhd(&b"123abcDEF;"[..]);
- assert_eq!(rhd, Ok((semicolon, &b"123abcDEF"[..])));
-
- named!(yod, recognize!(oct_digit));
- let rod = yod(&b"1234567;"[..]);
- assert_eq!(rod, Ok((semicolon, &b"1234567"[..])));
-
- named!(yan, recognize!(alphanumeric));
- let ran = yan(&b"123abc;"[..]);
- assert_eq!(ran, Ok((semicolon, &b"123abc"[..])));
-
- named!(ys, recognize!(space));
- let rs = ys(&b" \t;"[..]);
- assert_eq!(rs, Ok((semicolon, &b" \t"[..])));
-
- named!(yms, recognize!(multispace));
- let rms = yms(&b" \t\r\n;"[..]);
- assert_eq!(rms, Ok((semicolon, &b" \t\r\n"[..])));
- }
-
- #[test]
- fn take_while() {
- named!(f, take_while!(is_alphabetic));
- let a = b"";
- let b = b"abcd";
- let c = b"abcd123";
- let d = b"123";
-
- assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f(&c[..]), Ok((&d[..], &b[..])));
- assert_eq!(f(&d[..]), Ok((&d[..], &a[..])));
- }
-
- #[test]
- fn take_while1() {
- named!(f, take_while1!(is_alphabetic));
- let a = b"";
- let b = b"abcd";
- let c = b"abcd123";
- let d = b"123";
-
- assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f(&c[..]), Ok((&b"123"[..], &b[..])));
- assert_eq!(
- f(&d[..]),
- Err(Err::Error(error_position!(&d[..], ErrorKind::TakeWhile1)))
- );
- }
-
- #[test]
- fn take_while_m_n() {
- named!(x, take_while_m_n!(2, 4, is_alphabetic));
- let a = b"";
- let b = b"a";
- let c = b"abc";
- let d = b"abc123";
- let e = b"abcde";
- let f = b"123";
-
- assert_eq!(x(&a[..]), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(x(&b[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(x(&c[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(x(&d[..]), Ok((&b"123"[..], &c[..])));
- assert_eq!(x(&e[..]), Ok((&b"e"[..], &b"abcd"[..])));
- assert_eq!(
- x(&f[..]),
- Err(Err::Error(error_position!(&f[..], ErrorKind::TakeWhileMN)))
- );
- }
-
- #[test]
- fn take_till() {
- named!(f, take_till!(is_alphabetic));
- let a = b"";
- let b = b"abcd";
- let c = b"123abcd";
- let d = b"123";
-
- assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f(&b[..]), Ok((&b"abcd"[..], &b""[..])));
- assert_eq!(f(&c[..]), Ok((&b"abcd"[..], &b"123"[..])));
- assert_eq!(f(&d[..]), Err(Err::Incomplete(Needed::new(1))));
- }
-
- #[test]
- fn take_till1() {
- named!(f, take_till1!(is_alphabetic));
- let a = b"";
- let b = b"abcd";
- let c = b"123abcd";
- let d = b"123";
-
- assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(
- f(&b[..]),
- Err(Err::Error(error_position!(&b[..], ErrorKind::TakeTill1)))
- );
- assert_eq!(f(&c[..]), Ok((&b"abcd"[..], &b"123"[..])));
- assert_eq!(f(&d[..]), Err(Err::Incomplete(Needed::new(1))));
- }
-
- #[test]
- fn take_while_utf8() {
- named!(f<&str,&str>, take_while!(|c:char| { c != '點' }));
-
- assert_eq!(f(""), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f("abcd"), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f("abcd點"), Ok(("點", "abcd")));
- assert_eq!(f("abcd點a"), Ok(("點a", "abcd")));
-
- named!(g<&str,&str>, take_while!(|c:char| { c == '點' }));
-
- assert_eq!(g(""), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(g("點abcd"), Ok(("abcd", "點")));
- assert_eq!(g("點點點a"), Ok(("a", "點點點")));
- }
-
- #[test]
- fn take_till_utf8() {
- named!(f<&str,&str>, take_till!(|c:char| { c == '點' }));
-
- assert_eq!(f(""), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f("abcd"), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(f("abcd點"), Ok(("點", "abcd")));
- assert_eq!(f("abcd點a"), Ok(("點a", "abcd")));
-
- named!(g<&str,&str>, take_till!(|c:char| { c != '點' }));
-
- assert_eq!(g(""), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(g("點abcd"), Ok(("abcd", "點")));
- assert_eq!(g("點點點a"), Ok(("a", "點點點")));
- }
-
- #[test]
- fn take_utf8() {
- named!(f<&str,&str>, take!(3));
-
- assert_eq!(f(""), Err(Err::Incomplete(Needed::Unknown)));
- assert_eq!(f("ab"), Err(Err::Incomplete(Needed::Unknown)));
- assert_eq!(f("點"), Err(Err::Incomplete(Needed::Unknown)));
- assert_eq!(f("ab點cd"), Ok(("cd", "ab點")));
- assert_eq!(f("a點bcd"), Ok(("cd", "a點b")));
- assert_eq!(f("a點b"), Ok(("", "a點b")));
-
- named!(g<&str,&str>, take_while!(|c:char| { c == '點' }));
-
- assert_eq!(g(""), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(g("點abcd"), Ok(("abcd", "點")));
- assert_eq!(g("點點點a"), Ok(("a", "點點點")));
- }
-
- #[test]
- fn take_while_m_n_utf8() {
- named!(parser<&str, &str>, take_while_m_n!(1, 1, |c| c == 'A' || c == '😃'));
- assert_eq!(parser("A!"), Ok(("!", "A")));
- assert_eq!(parser("😃!"), Ok(("!", "😃")));
- }
-
- #[test]
- fn take_while_m_n_utf8_full_match() {
- named!(parser<&str, &str>, take_while_m_n!(1, 1, |c: char| c.is_alphabetic()));
- assert_eq!(parser("øn"), Ok(("n", "ø")));
- }
-
- #[cfg(nightly)]
- use test::Bencher;
-
- #[cfg(nightly)]
- #[bench]
- fn take_while_bench(b: &mut Bencher) {
- named!(f, take_while!(is_alphabetic));
- b.iter(|| f(&b"abcdefghijklABCDEejfrfrjgro12aa"[..]));
- }
-
- #[test]
- #[cfg(feature = "std")]
- fn recognize_take_while() {
- use crate::character::is_alphanumeric;
- named!(x, take_while!(is_alphanumeric));
- named!(y, recognize!(x));
- assert_eq!(x(&b"ab."[..]), Ok((&b"."[..], &b"ab"[..])));
- println!("X: {:?}", x(&b"ab"[..]));
- assert_eq!(y(&b"ab."[..]), Ok((&b"."[..], &b"ab"[..])));
- }
-
- #[test]
- fn length_bytes() {
- use crate::number::streaming::le_u8;
- named!(x, length_data!(le_u8));
- assert_eq!(x(b"\x02..>>"), Ok((&b">>"[..], &b".."[..])));
- assert_eq!(x(b"\x02.."), Ok((&[][..], &b".."[..])));
- assert_eq!(x(b"\x02."), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(x(b"\x02"), Err(Err::Incomplete(Needed::new(2))));
-
- named!(y, do_parse!(tag!("magic") >> b: length_data!(le_u8) >> (b)));
- assert_eq!(y(b"magic\x02..>>"), Ok((&b">>"[..], &b".."[..])));
- assert_eq!(y(b"magic\x02.."), Ok((&[][..], &b".."[..])));
- assert_eq!(y(b"magic\x02."), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(y(b"magic\x02"), Err(Err::Incomplete(Needed::new(2))));
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn case_insensitive() {
- named!(test, tag_no_case!("ABcd"));
- assert_eq!(test(&b"aBCdefgh"[..]), Ok((&b"efgh"[..], &b"aBCd"[..])));
- assert_eq!(test(&b"abcdefgh"[..]), Ok((&b"efgh"[..], &b"abcd"[..])));
- assert_eq!(test(&b"ABCDefgh"[..]), Ok((&b"efgh"[..], &b"ABCD"[..])));
- assert_eq!(test(&b"ab"[..]), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(
- test(&b"Hello"[..]),
- Err(Err::Error(error_position!(&b"Hello"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- test(&b"Hel"[..]),
- Err(Err::Error(error_position!(&b"Hel"[..], ErrorKind::Tag)))
- );
-
- named!(test2<&str, &str>, tag_no_case!("ABcd"));
- assert_eq!(test2("aBCdefgh"), Ok(("efgh", "aBCd")));
- assert_eq!(test2("abcdefgh"), Ok(("efgh", "abcd")));
- assert_eq!(test2("ABCDefgh"), Ok(("efgh", "ABCD")));
- assert_eq!(test2("ab"), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(
- test2("Hello"),
- Err(Err::Error(error_position!(&"Hello"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- test2("Hel"),
- Err(Err::Error(error_position!(&"Hel"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn tag_fixed_size_array() {
- named!(test, tag!([0x42]));
- named!(test2, tag!(&[0x42]));
- let input = [0x42, 0x00];
- assert_eq!(test(&input), Ok((&b"\x00"[..], &b"\x42"[..])));
- assert_eq!(test2(&input), Ok((&b"\x00"[..], &b"\x42"[..])));
- }
-}
diff --git a/src/bytes/mod.rs b/src/bytes/mod.rs
index 64fb00d..7bc2d15 100644
--- a/src/bytes/mod.rs
+++ b/src/bytes/mod.rs
@@ -1,6 +1,6 @@
//! Parsers recognizing bytes streams
-#[macro_use]
-mod macros;
pub mod complete;
pub mod streaming;
+#[cfg(test)]
+mod tests;
diff --git a/src/bytes/streaming.rs b/src/bytes/streaming.rs
index f3f8b2c..8deac13 100644
--- a/src/bytes/streaming.rs
+++ b/src/bytes/streaming.rs
@@ -472,6 +472,48 @@ where
}
}
+/// Returns the non empty input slice up to the first occurrence of the pattern.
+///
+/// It doesn't consume the pattern.
+///
+/// # Streaming Specific
+/// *Streaming version* will return a `Err::Incomplete(Needed::new(N))` if the input doesn't
+/// contain the pattern or if the input is smaller than the pattern.
+/// # Example
+/// ```rust
+/// # #[macro_use] extern crate nom;
+/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
+/// use nom::bytes::streaming::take_until1;
+///
+/// fn until_eof(s: &str) -> IResult<&str, &str> {
+/// take_until1("eof")(s)
+/// }
+///
+/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world")));
+/// assert_eq!(until_eof("hello, world"), Err(Err::Incomplete(Needed::Unknown)));
+/// assert_eq!(until_eof("hello, worldeo"), Err(Err::Incomplete(Needed::Unknown)));
+/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1")));
+/// assert_eq!(until_eof("eof"), Err(Err::Error(Error::new("eof", ErrorKind::TakeUntil))));
+/// ```
+pub fn take_until1<T, Input, Error: ParseError<Input>>(
+ tag: T,
+) -> impl Fn(Input) -> IResult<Input, Input, Error>
+where
+ Input: InputTake + InputLength + FindSubstring<T>,
+ T: Clone,
+{
+ move |i: Input| {
+ let t = tag.clone();
+
+ let res: IResult<_, _, Error> = match i.find_substring(t) {
+ None => Err(Err::Incomplete(Needed::Unknown)),
+ Some(0) => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))),
+ Some(index) => Ok(i.take_split(index)),
+ };
+ res
+ }
+}
+
/// Matches a byte string with escaped characters.
///
/// * The first argument matches the normal characters (it must not accept the control character)
@@ -517,10 +559,15 @@ where
let mut i = input.clone();
while i.input_len() > 0 {
+ let current_len = i.input_len();
+
match normal.parse(i.clone()) {
Ok((i2, _)) => {
if i2.input_len() == 0 {
return Err(Err::Incomplete(Needed::Unknown));
+ } else if i2.input_len() == current_len {
+ let index = input.offset(&i2);
+ return Ok(input.take_split(index));
} else {
i = i2;
}
@@ -558,29 +605,6 @@ where
}
}
-#[doc(hidden)]
-pub fn escapedc<Input, Error, F, G, O1, O2>(
- i: Input,
- normal: F,
- control_char: char,
- escapable: G,
-) -> IResult<Input, Input, Error>
-where
- Input: Clone
- + crate::traits::Offset
- + InputLength
- + InputTake
- + InputTakeAtPosition
- + Slice<RangeFrom<usize>>
- + InputIter,
- <Input as InputIter>::Item: crate::traits::AsChar,
- F: Fn(Input) -> IResult<Input, O1, Error>,
- G: Fn(Input) -> IResult<Input, O2, Error>,
- Error: ParseError<Input>,
-{
- escaped(normal, control_char, escapable)(i)
-}
-
/// Matches a byte string with escaped characters.
///
/// * The first argument matches the normal characters (it must not match the control character)
@@ -644,12 +668,15 @@ where
let i = input.clone();
while index < i.input_len() {
+ let current_len = i.input_len();
let remainder = i.slice(index..);
match normal.parse(remainder.clone()) {
Ok((i2, o)) => {
o.extend_into(&mut res);
if i2.input_len() == 0 {
return Err(Err::Incomplete(Needed::Unknown));
+ } else if i2.input_len() == current_len {
+ return Ok((remainder, res));
} else {
index = input.offset(&i2);
}
@@ -685,31 +712,3 @@ where
Err(Err::Incomplete(Needed::Unknown))
}
}
-
-#[doc(hidden)]
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-pub fn escaped_transformc<Input, Error, F, G, O1, O2, ExtendItem, Output>(
- i: Input,
- normal: F,
- control_char: char,
- transform: G,
-) -> IResult<Input, Output, Error>
-where
- Input: Clone
- + crate::traits::Offset
- + InputLength
- + InputTake
- + InputTakeAtPosition
- + Slice<RangeFrom<usize>>
- + InputIter,
- Input: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>,
- O1: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>,
- O2: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>,
- <Input as InputIter>::Item: crate::traits::AsChar,
- F: Fn(Input) -> IResult<Input, O1, Error>,
- G: Fn(Input) -> IResult<Input, O2, Error>,
- Error: ParseError<Input>,
-{
- escaped_transform(normal, control_char, transform)(i)
-}
diff --git a/src/bytes/tests.rs b/src/bytes/tests.rs
new file mode 100644
index 0000000..159c4b4
--- /dev/null
+++ b/src/bytes/tests.rs
@@ -0,0 +1,636 @@
+use crate::character::is_alphabetic;
+use crate::character::streaming::{
+ alpha1 as alpha, alphanumeric1 as alphanumeric, digit1 as digit, hex_digit1 as hex_digit,
+ multispace1 as multispace, oct_digit1 as oct_digit, space1 as space,
+};
+use crate::error::ErrorKind;
+use crate::internal::{Err, IResult, Needed};
+#[cfg(feature = "alloc")]
+use crate::{
+ branch::alt,
+ bytes::complete::{escaped, escaped_transform, tag},
+ combinator::{map, value},
+ lib::std::string::String,
+ lib::std::vec::Vec,
+};
+
+#[test]
+fn is_a() {
+ use crate::bytes::streaming::is_a;
+
+ fn a_or_b(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ is_a("ab")(i)
+ }
+
+ let a = &b"abcd"[..];
+ assert_eq!(a_or_b(a), Ok((&b"cd"[..], &b"ab"[..])));
+
+ let b = &b"bcde"[..];
+ assert_eq!(a_or_b(b), Ok((&b"cde"[..], &b"b"[..])));
+
+ let c = &b"cdef"[..];
+ assert_eq!(
+ a_or_b(c),
+ Err(Err::Error(error_position!(c, ErrorKind::IsA)))
+ );
+
+ let d = &b"bacdef"[..];
+ assert_eq!(a_or_b(d), Ok((&b"cdef"[..], &b"ba"[..])));
+}
+
+#[test]
+fn is_not() {
+ use crate::bytes::streaming::is_not;
+
+ fn a_or_b(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ is_not("ab")(i)
+ }
+
+ let a = &b"cdab"[..];
+ assert_eq!(a_or_b(a), Ok((&b"ab"[..], &b"cd"[..])));
+
+ let b = &b"cbde"[..];
+ assert_eq!(a_or_b(b), Ok((&b"bde"[..], &b"c"[..])));
+
+ let c = &b"abab"[..];
+ assert_eq!(
+ a_or_b(c),
+ Err(Err::Error(error_position!(c, ErrorKind::IsNot)))
+ );
+
+ let d = &b"cdefba"[..];
+ assert_eq!(a_or_b(d), Ok((&b"ba"[..], &b"cdef"[..])));
+
+ let e = &b"e"[..];
+ assert_eq!(a_or_b(e), Err(Err::Incomplete(Needed::new(1))));
+}
+
+#[cfg(feature = "alloc")]
+#[allow(unused_variables)]
+#[test]
+fn escaping() {
+ use crate::character::streaming::one_of;
+
+ fn esc(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ escaped(alpha, '\\', one_of("\"n\\"))(i)
+ }
+ assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], &b"abcd"[..])));
+ assert_eq!(esc(&b"ab\\\"cd;"[..]), Ok((&b";"[..], &b"ab\\\"cd"[..])));
+ assert_eq!(esc(&b"\\\"abcd;"[..]), Ok((&b";"[..], &b"\\\"abcd"[..])));
+ assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], &b"\\n"[..])));
+ assert_eq!(esc(&b"ab\\\"12"[..]), Ok((&b"12"[..], &b"ab\\\""[..])));
+ assert_eq!(
+ esc(&b"AB\\"[..]),
+ Err(Err::Error(error_position!(
+ &b"AB\\"[..],
+ ErrorKind::Escaped
+ )))
+ );
+ assert_eq!(
+ esc(&b"AB\\A"[..]),
+ Err(Err::Error(error_node_position!(
+ &b"AB\\A"[..],
+ ErrorKind::Escaped,
+ error_position!(&b"A"[..], ErrorKind::OneOf)
+ )))
+ );
+
+ fn esc2(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ escaped(digit, '\\', one_of("\"n\\"))(i)
+ }
+ assert_eq!(esc2(&b"12\\nnn34"[..]), Ok((&b"nn34"[..], &b"12\\n"[..])));
+}
+
+#[cfg(feature = "alloc")]
+#[test]
+fn escaping_str() {
+ use crate::character::streaming::one_of;
+
+ fn esc(i: &str) -> IResult<&str, &str> {
+ escaped(alpha, '\\', one_of("\"n\\"))(i)
+ }
+ assert_eq!(esc("abcd;"), Ok((";", "abcd")));
+ assert_eq!(esc("ab\\\"cd;"), Ok((";", "ab\\\"cd")));
+ assert_eq!(esc("\\\"abcd;"), Ok((";", "\\\"abcd")));
+ assert_eq!(esc("\\n;"), Ok((";", "\\n")));
+ assert_eq!(esc("ab\\\"12"), Ok(("12", "ab\\\"")));
+ assert_eq!(
+ esc("AB\\"),
+ Err(Err::Error(error_position!("AB\\", ErrorKind::Escaped)))
+ );
+ assert_eq!(
+ esc("AB\\A"),
+ Err(Err::Error(error_node_position!(
+ "AB\\A",
+ ErrorKind::Escaped,
+ error_position!("A", ErrorKind::OneOf)
+ )))
+ );
+
+ fn esc2(i: &str) -> IResult<&str, &str> {
+ escaped(digit, '\\', one_of("\"n\\"))(i)
+ }
+ assert_eq!(esc2("12\\nnn34"), Ok(("nn34", "12\\n")));
+
+ fn esc3(i: &str) -> IResult<&str, &str> {
+ escaped(alpha, '\u{241b}', one_of("\"n"))(i)
+ }
+ assert_eq!(esc3("ab␛ncd;"), Ok((";", "ab␛ncd")));
+}
+
+#[cfg(feature = "alloc")]
+fn to_s(i: Vec<u8>) -> String {
+ String::from_utf8_lossy(&i).into_owned()
+}
+
+#[cfg(feature = "alloc")]
+#[test]
+fn escape_transform() {
+ fn esc(i: &[u8]) -> IResult<&[u8], String> {
+ map(
+ escaped_transform(
+ alpha,
+ '\\',
+ alt((
+ value(&b"\\"[..], tag("\\")),
+ value(&b"\""[..], tag("\"")),
+ value(&b"\n"[..], tag("n")),
+ )),
+ ),
+ to_s,
+ )(i)
+ }
+
+ assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], String::from("abcd"))));
+ assert_eq!(
+ esc(&b"ab\\\"cd;"[..]),
+ Ok((&b";"[..], String::from("ab\"cd")))
+ );
+ assert_eq!(
+ esc(&b"\\\"abcd;"[..]),
+ Ok((&b";"[..], String::from("\"abcd")))
+ );
+ assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], String::from("\n"))));
+ assert_eq!(
+ esc(&b"ab\\\"12"[..]),
+ Ok((&b"12"[..], String::from("ab\"")))
+ );
+ assert_eq!(
+ esc(&b"AB\\"[..]),
+ Err(Err::Error(error_position!(
+ &b"\\"[..],
+ ErrorKind::EscapedTransform
+ )))
+ );
+ assert_eq!(
+ esc(&b"AB\\A"[..]),
+ Err(Err::Error(error_node_position!(
+ &b"AB\\A"[..],
+ ErrorKind::EscapedTransform,
+ error_position!(&b"A"[..], ErrorKind::Tag)
+ )))
+ );
+
+ fn esc2(i: &[u8]) -> IResult<&[u8], String> {
+ map(
+ escaped_transform(
+ alpha,
+ '&',
+ alt((
+ value("è".as_bytes(), tag("egrave;")),
+ value("à".as_bytes(), tag("agrave;")),
+ )),
+ ),
+ to_s,
+ )(i)
+ }
+ assert_eq!(
+ esc2(&b"ab&egrave;DEF;"[..]),
+ Ok((&b";"[..], String::from("abèDEF")))
+ );
+ assert_eq!(
+ esc2(&b"ab&egrave;D&agrave;EF;"[..]),
+ Ok((&b";"[..], String::from("abèDàEF")))
+ );
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn escape_transform_str() {
+ fn esc(i: &str) -> IResult<&str, String> {
+ escaped_transform(
+ alpha,
+ '\\',
+ alt((
+ value("\\", tag("\\")),
+ value("\"", tag("\"")),
+ value("\n", tag("n")),
+ )),
+ )(i)
+ }
+
+ assert_eq!(esc("abcd;"), Ok((";", String::from("abcd"))));
+ assert_eq!(esc("ab\\\"cd;"), Ok((";", String::from("ab\"cd"))));
+ assert_eq!(esc("\\\"abcd;"), Ok((";", String::from("\"abcd"))));
+ assert_eq!(esc("\\n;"), Ok((";", String::from("\n"))));
+ assert_eq!(esc("ab\\\"12"), Ok(("12", String::from("ab\""))));
+ assert_eq!(
+ esc("AB\\"),
+ Err(Err::Error(error_position!(
+ "\\",
+ ErrorKind::EscapedTransform
+ )))
+ );
+ assert_eq!(
+ esc("AB\\A"),
+ Err(Err::Error(error_node_position!(
+ "AB\\A",
+ ErrorKind::EscapedTransform,
+ error_position!("A", ErrorKind::Tag)
+ )))
+ );
+
+ fn esc2(i: &str) -> IResult<&str, String> {
+ escaped_transform(
+ alpha,
+ '&',
+ alt((value("è", tag("egrave;")), value("à", tag("agrave;")))),
+ )(i)
+ }
+ assert_eq!(esc2("ab&egrave;DEF;"), Ok((";", String::from("abèDEF"))));
+ assert_eq!(
+ esc2("ab&egrave;D&agrave;EF;"),
+ Ok((";", String::from("abèDàEF")))
+ );
+
+ fn esc3(i: &str) -> IResult<&str, String> {
+ escaped_transform(
+ alpha,
+ '␛',
+ alt((value("\0", tag("0")), value("\n", tag("n")))),
+ )(i)
+ }
+ assert_eq!(esc3("a␛0bc␛n"), Ok(("", String::from("a\0bc\n"))));
+}
+
+#[test]
+fn take_until_incomplete() {
+ use crate::bytes::streaming::take_until;
+ fn y(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ take_until("end")(i)
+ }
+ assert_eq!(y(&b"nd"[..]), Err(Err::Incomplete(Needed::Unknown)));
+ assert_eq!(y(&b"123"[..]), Err(Err::Incomplete(Needed::Unknown)));
+ assert_eq!(y(&b"123en"[..]), Err(Err::Incomplete(Needed::Unknown)));
+}
+
+#[test]
+fn take_until_incomplete_s() {
+ use crate::bytes::streaming::take_until;
+ fn ys(i: &str) -> IResult<&str, &str> {
+ take_until("end")(i)
+ }
+ assert_eq!(ys("123en"), Err(Err::Incomplete(Needed::Unknown)));
+}
+
+#[test]
+fn recognize() {
+ use crate::bytes::streaming::{tag, take};
+ use crate::combinator::recognize;
+ use crate::sequence::delimited;
+
+ fn x(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(delimited(tag("<!--"), take(5_usize), tag("-->")))(i)
+ }
+ let r = x(&b"<!-- abc --> aaa"[..]);
+ assert_eq!(r, Ok((&b" aaa"[..], &b"<!-- abc -->"[..])));
+
+ let semicolon = &b";"[..];
+
+ fn ya(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(alpha)(i)
+ }
+ let ra = ya(&b"abc;"[..]);
+ assert_eq!(ra, Ok((semicolon, &b"abc"[..])));
+
+ fn yd(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(digit)(i)
+ }
+ let rd = yd(&b"123;"[..]);
+ assert_eq!(rd, Ok((semicolon, &b"123"[..])));
+
+ fn yhd(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(hex_digit)(i)
+ }
+ let rhd = yhd(&b"123abcDEF;"[..]);
+ assert_eq!(rhd, Ok((semicolon, &b"123abcDEF"[..])));
+
+ fn yod(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(oct_digit)(i)
+ }
+ let rod = yod(&b"1234567;"[..]);
+ assert_eq!(rod, Ok((semicolon, &b"1234567"[..])));
+
+ fn yan(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(alphanumeric)(i)
+ }
+ let ran = yan(&b"123abc;"[..]);
+ assert_eq!(ran, Ok((semicolon, &b"123abc"[..])));
+
+ fn ys(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(space)(i)
+ }
+ let rs = ys(&b" \t;"[..]);
+ assert_eq!(rs, Ok((semicolon, &b" \t"[..])));
+
+ fn yms(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(multispace)(i)
+ }
+ let rms = yms(&b" \t\r\n;"[..]);
+ assert_eq!(rms, Ok((semicolon, &b" \t\r\n"[..])));
+}
+
+#[test]
+fn take_while() {
+ use crate::bytes::streaming::take_while;
+
+ fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ take_while(is_alphabetic)(i)
+ }
+ let a = b"";
+ let b = b"abcd";
+ let c = b"abcd123";
+ let d = b"123";
+
+ assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f(&c[..]), Ok((&d[..], &b[..])));
+ assert_eq!(f(&d[..]), Ok((&d[..], &a[..])));
+}
+
+#[test]
+fn take_while1() {
+ use crate::bytes::streaming::take_while1;
+
+ fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ take_while1(is_alphabetic)(i)
+ }
+ let a = b"";
+ let b = b"abcd";
+ let c = b"abcd123";
+ let d = b"123";
+
+ assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f(&c[..]), Ok((&b"123"[..], &b[..])));
+ assert_eq!(
+ f(&d[..]),
+ Err(Err::Error(error_position!(&d[..], ErrorKind::TakeWhile1)))
+ );
+}
+
+#[test]
+fn take_while_m_n() {
+ use crate::bytes::streaming::take_while_m_n;
+
+ fn x(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ take_while_m_n(2, 4, is_alphabetic)(i)
+ }
+ let a = b"";
+ let b = b"a";
+ let c = b"abc";
+ let d = b"abc123";
+ let e = b"abcde";
+ let f = b"123";
+
+ assert_eq!(x(&a[..]), Err(Err::Incomplete(Needed::new(2))));
+ assert_eq!(x(&b[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(x(&c[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(x(&d[..]), Ok((&b"123"[..], &c[..])));
+ assert_eq!(x(&e[..]), Ok((&b"e"[..], &b"abcd"[..])));
+ assert_eq!(
+ x(&f[..]),
+ Err(Err::Error(error_position!(&f[..], ErrorKind::TakeWhileMN)))
+ );
+}
+
+#[test]
+fn take_till() {
+ use crate::bytes::streaming::take_till;
+
+ fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ take_till(is_alphabetic)(i)
+ }
+ let a = b"";
+ let b = b"abcd";
+ let c = b"123abcd";
+ let d = b"123";
+
+ assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f(&b[..]), Ok((&b"abcd"[..], &b""[..])));
+ assert_eq!(f(&c[..]), Ok((&b"abcd"[..], &b"123"[..])));
+ assert_eq!(f(&d[..]), Err(Err::Incomplete(Needed::new(1))));
+}
+
+#[test]
+fn take_till1() {
+ use crate::bytes::streaming::take_till1;
+
+ fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ take_till1(is_alphabetic)(i)
+ }
+ let a = b"";
+ let b = b"abcd";
+ let c = b"123abcd";
+ let d = b"123";
+
+ assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(
+ f(&b[..]),
+ Err(Err::Error(error_position!(&b[..], ErrorKind::TakeTill1)))
+ );
+ assert_eq!(f(&c[..]), Ok((&b"abcd"[..], &b"123"[..])));
+ assert_eq!(f(&d[..]), Err(Err::Incomplete(Needed::new(1))));
+}
+
+#[test]
+fn take_while_utf8() {
+ use crate::bytes::streaming::take_while;
+
+ fn f(i: &str) -> IResult<&str, &str> {
+ take_while(|c| c != '點')(i)
+ }
+
+ assert_eq!(f(""), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f("abcd"), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f("abcd點"), Ok(("點", "abcd")));
+ assert_eq!(f("abcd點a"), Ok(("點a", "abcd")));
+
+ fn g(i: &str) -> IResult<&str, &str> {
+ take_while(|c| c == '點')(i)
+ }
+
+ assert_eq!(g(""), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(g("點abcd"), Ok(("abcd", "點")));
+ assert_eq!(g("點點點a"), Ok(("a", "點點點")));
+}
+
+#[test]
+fn take_till_utf8() {
+ use crate::bytes::streaming::take_till;
+
+ fn f(i: &str) -> IResult<&str, &str> {
+ take_till(|c| c == '點')(i)
+ }
+
+ assert_eq!(f(""), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f("abcd"), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(f("abcd點"), Ok(("點", "abcd")));
+ assert_eq!(f("abcd點a"), Ok(("點a", "abcd")));
+
+ fn g(i: &str) -> IResult<&str, &str> {
+ take_till(|c| c != '點')(i)
+ }
+
+ assert_eq!(g(""), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(g("點abcd"), Ok(("abcd", "點")));
+ assert_eq!(g("點點點a"), Ok(("a", "點點點")));
+}
+
+#[test]
+fn take_utf8() {
+ use crate::bytes::streaming::{take, take_while};
+
+ fn f(i: &str) -> IResult<&str, &str> {
+ take(3_usize)(i)
+ }
+
+ assert_eq!(f(""), Err(Err::Incomplete(Needed::Unknown)));
+ assert_eq!(f("ab"), Err(Err::Incomplete(Needed::Unknown)));
+ assert_eq!(f("點"), Err(Err::Incomplete(Needed::Unknown)));
+ assert_eq!(f("ab點cd"), Ok(("cd", "ab點")));
+ assert_eq!(f("a點bcd"), Ok(("cd", "a點b")));
+ assert_eq!(f("a點b"), Ok(("", "a點b")));
+
+ fn g(i: &str) -> IResult<&str, &str> {
+ take_while(|c| c == '點')(i)
+ }
+
+ assert_eq!(g(""), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(g("點abcd"), Ok(("abcd", "點")));
+ assert_eq!(g("點點點a"), Ok(("a", "點點點")));
+}
+
+#[test]
+fn take_while_m_n_utf8() {
+ use crate::bytes::streaming::take_while_m_n;
+
+ fn parser(i: &str) -> IResult<&str, &str> {
+ take_while_m_n(1, 1, |c| c == 'A' || c == '😃')(i)
+ }
+ assert_eq!(parser("A!"), Ok(("!", "A")));
+ assert_eq!(parser("😃!"), Ok(("!", "😃")));
+}
+
+#[test]
+fn take_while_m_n_utf8_full_match() {
+ use crate::bytes::streaming::take_while_m_n;
+
+ fn parser(i: &str) -> IResult<&str, &str> {
+ take_while_m_n(1, 1, |c: char| c.is_alphabetic())(i)
+ }
+ assert_eq!(parser("øn"), Ok(("n", "ø")));
+}
+
+#[test]
+#[cfg(feature = "std")]
+fn recognize_take_while() {
+ use crate::bytes::streaming::take_while;
+ use crate::character::is_alphanumeric;
+ use crate::combinator::recognize;
+
+ fn x(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ take_while(is_alphanumeric)(i)
+ }
+ fn y(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ recognize(x)(i)
+ }
+ assert_eq!(x(&b"ab."[..]), Ok((&b"."[..], &b"ab"[..])));
+ println!("X: {:?}", x(&b"ab"[..]));
+ assert_eq!(y(&b"ab."[..]), Ok((&b"."[..], &b"ab"[..])));
+}
+
+#[test]
+fn length_bytes() {
+ use crate::{bytes::streaming::tag, multi::length_data, number::streaming::le_u8};
+
+ fn x(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ length_data(le_u8)(i)
+ }
+ assert_eq!(x(b"\x02..>>"), Ok((&b">>"[..], &b".."[..])));
+ assert_eq!(x(b"\x02.."), Ok((&[][..], &b".."[..])));
+ assert_eq!(x(b"\x02."), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(x(b"\x02"), Err(Err::Incomplete(Needed::new(2))));
+
+ fn y(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ let (i, _) = tag("magic")(i)?;
+ length_data(le_u8)(i)
+ }
+ assert_eq!(y(b"magic\x02..>>"), Ok((&b">>"[..], &b".."[..])));
+ assert_eq!(y(b"magic\x02.."), Ok((&[][..], &b".."[..])));
+ assert_eq!(y(b"magic\x02."), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(y(b"magic\x02"), Err(Err::Incomplete(Needed::new(2))));
+}
+
+#[cfg(feature = "alloc")]
+#[test]
+fn case_insensitive() {
+ use crate::bytes::streaming::tag_no_case;
+
+ fn test(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ tag_no_case("ABcd")(i)
+ }
+ assert_eq!(test(&b"aBCdefgh"[..]), Ok((&b"efgh"[..], &b"aBCd"[..])));
+ assert_eq!(test(&b"abcdefgh"[..]), Ok((&b"efgh"[..], &b"abcd"[..])));
+ assert_eq!(test(&b"ABCDefgh"[..]), Ok((&b"efgh"[..], &b"ABCD"[..])));
+ assert_eq!(test(&b"ab"[..]), Err(Err::Incomplete(Needed::new(2))));
+ assert_eq!(
+ test(&b"Hello"[..]),
+ Err(Err::Error(error_position!(&b"Hello"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ test(&b"Hel"[..]),
+ Err(Err::Error(error_position!(&b"Hel"[..], ErrorKind::Tag)))
+ );
+
+ fn test2(i: &str) -> IResult<&str, &str> {
+ tag_no_case("ABcd")(i)
+ }
+ assert_eq!(test2("aBCdefgh"), Ok(("efgh", "aBCd")));
+ assert_eq!(test2("abcdefgh"), Ok(("efgh", "abcd")));
+ assert_eq!(test2("ABCDefgh"), Ok(("efgh", "ABCD")));
+ assert_eq!(test2("ab"), Err(Err::Incomplete(Needed::new(2))));
+ assert_eq!(
+ test2("Hello"),
+ Err(Err::Error(error_position!(&"Hello"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ test2("Hel"),
+ Err(Err::Error(error_position!(&"Hel"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn tag_fixed_size_array() {
+ use crate::bytes::streaming::tag;
+
+ fn test(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ tag([0x42])(i)
+ }
+ fn test2(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ tag(&[0x42])(i)
+ }
+ let input = [0x42, 0x00];
+ assert_eq!(test(&input), Ok((&b"\x00"[..], &b"\x42"[..])));
+ assert_eq!(test2(&input), Ok((&b"\x00"[..], &b"\x42"[..])));
+}
diff --git a/src/character/complete.rs b/src/character/complete.rs
index cbcff46..5b73c14 100644
--- a/src/character/complete.rs
+++ b/src/character/complete.rs
@@ -2,11 +2,15 @@
//!
//! Functions recognizing specific characters.
+use crate::branch::alt;
+use crate::combinator::opt;
use crate::error::ErrorKind;
use crate::error::ParseError;
use crate::internal::{Err, IResult};
use crate::lib::std::ops::{Range, RangeFrom, RangeTo};
-use crate::traits::{AsChar, FindToken, InputIter, InputLength, InputTakeAtPosition, Slice};
+use crate::traits::{
+ AsChar, FindToken, InputIter, InputLength, InputTake, InputTakeAtPosition, Slice,
+};
use crate::traits::{Compare, CompareResult};
/// Recognizes one character.
@@ -684,10 +688,134 @@ where
)
}
+pub(crate) fn sign<T, E: ParseError<T>>(input: T) -> IResult<T, bool, E>
+where
+ T: Clone + InputTake,
+ T: for<'a> Compare<&'a [u8]>,
+{
+ use crate::bytes::complete::tag;
+ use crate::combinator::value;
+
+ let (i, opt_sign) = opt(alt((
+ value(false, tag(&b"-"[..])),
+ value(true, tag(&b"+"[..])),
+ )))(input)?;
+ let sign = opt_sign.unwrap_or(true);
+
+ Ok((i, sign))
+}
+
+#[doc(hidden)]
+macro_rules! ints {
+ ($($t:tt)+) => {
+ $(
+ /// will parse a number in text form to a number
+ ///
+ /// *Complete version*: can parse until the end of input.
+ pub fn $t<T, E: ParseError<T>>(input: T) -> IResult<T, $t, E>
+ where
+ T: InputIter + Slice<RangeFrom<usize>> + InputLength + InputTake + Clone,
+ <T as InputIter>::Item: AsChar,
+ T: for <'a> Compare<&'a[u8]>,
+ {
+ let (i, sign) = sign(input.clone())?;
+
+ if i.input_len() == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit)));
+ }
+
+ let mut value: $t = 0;
+ if sign {
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_add(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+ } else {
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_sub(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+ }
+
+ Ok((i.slice(i.input_len()..), value))
+ }
+ )+
+ }
+}
+
+ints! { i8 i16 i32 i64 i128 }
+
+#[doc(hidden)]
+macro_rules! uints {
+ ($($t:tt)+) => {
+ $(
+ /// will parse a number in text form to a number
+ ///
+ /// *Complete version*: can parse until the end of input.
+ pub fn $t<T, E: ParseError<T>>(input: T) -> IResult<T, $t, E>
+ where
+ T: InputIter + Slice<RangeFrom<usize>> + InputLength,
+ <T as InputIter>::Item: AsChar,
+ {
+ let i = input;
+
+ if i.input_len() == 0 {
+ return Err(Err::Error(E::from_error_kind(i, ErrorKind::Digit)));
+ }
+
+ let mut value: $t = 0;
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(i, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_add(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(i, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+
+ Ok((i.slice(i.input_len()..), value))
+ }
+ )+
+ }
+}
+
+uints! { u8 u16 u32 u64 u128 }
+
#[cfg(test)]
mod tests {
use super::*;
use crate::internal::Err;
+ use crate::traits::ParseTo;
+ use proptest::prelude::*;
macro_rules! assert_parse(
($left: expr, $right: expr) => {
@@ -936,12 +1064,10 @@ mod tests {
#[test]
fn full_line_windows() {
- //let not_line_ending = |i:&[u8]| take_while(|c| c != b'\r' && c != b'\n')(i);
-
- named!(
- take_full_line<(&[u8], &[u8])>,
- tuple!(not_line_ending, line_ending)
- );
+ use crate::sequence::pair;
+ fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ pair(not_line_ending, line_ending)(i)
+ }
let input = b"abc\r\n";
let output = take_full_line(input);
assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\r\n"[..]))));
@@ -949,11 +1075,10 @@ mod tests {
#[test]
fn full_line_unix() {
- //let not_line_ending = |i:&[u8]| take_while(|c| c != b'\n')(i);
- named!(
- take_full_line<(&[u8], &[u8])>,
- tuple!(not_line_ending, line_ending)
- );
+ use crate::sequence::pair;
+ fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ pair(not_line_ending, line_ending)(i)
+ }
let input = b"abc\n";
let output = take_full_line(input);
assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\n"[..]))));
@@ -1020,4 +1145,65 @@ mod tests {
Err(Err::Error(error_position!("\ra", ErrorKind::CrLf)))
);
}
+
+ fn digit_to_i16(input: &str) -> IResult<&str, i16> {
+ let i = input;
+ let (i, opt_sign) = opt(alt((char('+'), char('-'))))(i)?;
+ let sign = match opt_sign {
+ Some('+') => true,
+ Some('-') => false,
+ _ => true,
+ };
+
+ let (i, s) = match digit1::<_, crate::error::Error<_>>(i) {
+ Ok((i, s)) => (i, s),
+ Err(_) => {
+ return Err(Err::Error(crate::error::Error::from_error_kind(
+ input,
+ ErrorKind::Digit,
+ )))
+ }
+ };
+
+ match s.parse_to() {
+ Some(n) => {
+ if sign {
+ Ok((i, n))
+ } else {
+ Ok((i, -n))
+ }
+ }
+ None => Err(Err::Error(crate::error::Error::from_error_kind(
+ i,
+ ErrorKind::Digit,
+ ))),
+ }
+ }
+
+ fn digit_to_u32(i: &str) -> IResult<&str, u32> {
+ let (i, s) = digit1(i)?;
+ match s.parse_to() {
+ Some(n) => Ok((i, n)),
+ None => Err(Err::Error(crate::error::Error::from_error_kind(
+ i,
+ ErrorKind::Digit,
+ ))),
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn ints(s in "\\PC*") {
+ let res1 = digit_to_i16(&s);
+ let res2 = i16(s.as_str());
+ assert_eq!(res1, res2);
+ }
+
+ #[test]
+ fn uints(s in "\\PC*") {
+ let res1 = digit_to_u32(&s);
+ let res2 = u32(s.as_str());
+ assert_eq!(res1, res2);
+ }
+ }
}
diff --git a/src/character/macros.rs b/src/character/macros.rs
deleted file mode 100644
index ba99645..0000000
--- a/src/character/macros.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-/// Character level parsers
-
-/// Matches one of the provided characters.
-///
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(simple<char>, one_of!(&b"abc"[..]));
-/// assert_eq!(simple(b"a123"), Ok((&b"123"[..], 'a')));
-///
-/// named!(a_or_b<&str, char>, one_of!("ab汉"));
-/// assert_eq!(a_or_b("汉jiosfe"), Ok(("jiosfe", '汉')));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! one_of (
- ($i:expr, $inp: expr) => ( $crate::character::streaming::one_of($inp)($i) );
-);
-
-/// Matches anything but the provided characters.
-///
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::ErrorKind};
-/// # fn main() {
-/// named!(no_letter_a<char>, none_of!(&b"abc"[..]));
-/// assert_eq!(no_letter_a(b"123"), Ok((&b"23"[..], '1')));
-///
-/// named!(err_on_single_quote<char>, none_of!(&b"'"[..]));
-/// assert_eq!(err_on_single_quote(b"'jiosfe"), Err(Err::Error(error_position!(&b"'jiosfe"[..], ErrorKind::NoneOf))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! none_of (
- ($i:expr, $inp: expr) => ( $crate::character::streaming::none_of($inp)($i) );
-);
-
-/// Matches one character: `char!(char) => &[u8] -> IResult<&[u8], char>`.
-///
-/// # Example
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::ErrorKind};
-/// # fn main() {
-/// named!(match_letter_a<char>, char!('a'));
-/// assert_eq!(match_letter_a(b"abc"), Ok((&b"bc"[..],'a')));
-///
-/// assert_eq!(match_letter_a(b"123cdef"), Err(Err::Error(error_position!(&b"123cdef"[..], ErrorKind::Char))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! char (
- ($i:expr, $c: expr) => ( $crate::character::streaming::char($c)($i) );
-);
-
-#[cfg(test)]
-mod tests {
- use crate::error::ErrorKind;
- use crate::internal::Err;
-
- #[test]
- fn one_of() {
- named!(f<char>, one_of!("ab"));
-
- let a = &b"abcd"[..];
- assert_eq!(f(a), Ok((&b"bcd"[..], 'a')));
-
- let b = &b"cde"[..];
- assert_eq!(f(b), Err(Err::Error(error_position!(b, ErrorKind::OneOf))));
-
- named!(utf8(&str) -> char,
- one_of!("+\u{FF0B}"));
-
- assert!(utf8("+").is_ok());
- assert!(utf8("\u{FF0B}").is_ok());
- }
-
- #[test]
- fn none_of() {
- named!(f<char>, none_of!("ab"));
-
- let a = &b"abcd"[..];
- assert_eq!(f(a), Err(Err::Error(error_position!(a, ErrorKind::NoneOf))));
-
- let b = &b"cde"[..];
- assert_eq!(f(b), Ok((&b"de"[..], 'c')));
- }
-
- #[test]
- fn char() {
- named!(f<char>, char!('c'));
-
- let a = &b"abcd"[..];
- assert_eq!(f(a), Err(Err::Error(error_position!(a, ErrorKind::Char))));
-
- let b = &b"cde"[..];
- assert_eq!(f(b), Ok((&b"de"[..], 'c')));
- }
-
- #[test]
- fn char_str() {
- named!(f<&str, char>, char!('c'));
-
- let a = &"abcd"[..];
- assert_eq!(f(a), Err(Err::Error(error_position!(a, ErrorKind::Char))));
-
- let b = &"cde"[..];
- assert_eq!(f(b), Ok((&"de"[..], 'c')));
- }
-}
diff --git a/src/character/mod.rs b/src/character/mod.rs
index 4c70f6e..2c5d3bc 100644
--- a/src/character/mod.rs
+++ b/src/character/mod.rs
@@ -2,8 +2,8 @@
//!
//! Functions recognizing specific characters
-#[macro_use]
-mod macros;
+#[cfg(test)]
+mod tests;
pub mod complete;
pub mod streaming;
diff --git a/src/character/streaming.rs b/src/character/streaming.rs
index 4c33ee9..88aabba 100644
--- a/src/character/streaming.rs
+++ b/src/character/streaming.rs
@@ -2,14 +2,17 @@
//!
//! Functions recognizing specific characters
+use crate::branch::alt;
+use crate::combinator::opt;
+use crate::error::ErrorKind;
use crate::error::ParseError;
use crate::internal::{Err, IResult, Needed};
use crate::lib::std::ops::{Range, RangeFrom, RangeTo};
-use crate::traits::{AsChar, FindToken, InputIter, InputLength, InputTakeAtPosition, Slice};
+use crate::traits::{
+ AsChar, FindToken, InputIter, InputLength, InputTake, InputTakeAtPosition, Slice,
+};
use crate::traits::{Compare, CompareResult};
-use crate::error::ErrorKind;
-
/// Recognizes one character.
///
/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there's not enough input data.
@@ -609,11 +612,136 @@ where
)
}
+pub(crate) fn sign<T, E: ParseError<T>>(input: T) -> IResult<T, bool, E>
+where
+ T: Clone + InputTake + InputLength,
+ T: for<'a> Compare<&'a [u8]>,
+{
+ use crate::bytes::streaming::tag;
+ use crate::combinator::value;
+
+ let (i, opt_sign) = opt(alt((
+ value(false, tag(&b"-"[..])),
+ value(true, tag(&b"+"[..])),
+ )))(input)?;
+ let sign = opt_sign.unwrap_or(true);
+
+ Ok((i, sign))
+}
+
+#[doc(hidden)]
+macro_rules! ints {
+ ($($t:tt)+) => {
+ $(
+ /// will parse a number in text form to a number
+ ///
+ /// *Complete version*: can parse until the end of input.
+ pub fn $t<T, E: ParseError<T>>(input: T) -> IResult<T, $t, E>
+ where
+ T: InputIter + Slice<RangeFrom<usize>> + InputLength + InputTake + Clone,
+ <T as InputIter>::Item: AsChar,
+ T: for <'a> Compare<&'a[u8]>,
+ {
+ let (i, sign) = sign(input.clone())?;
+
+ if i.input_len() == 0 {
+ return Err(Err::Incomplete(Needed::new(1)));
+ }
+
+ let mut value: $t = 0;
+ if sign {
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_add(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+ } else {
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_sub(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+ }
+
+ Err(Err::Incomplete(Needed::new(1)))
+ }
+ )+
+ }
+}
+
+ints! { i8 i16 i32 i64 i128 }
+
+#[doc(hidden)]
+macro_rules! uints {
+ ($($t:tt)+) => {
+ $(
+ /// will parse a number in text form to a number
+ ///
+ /// *Complete version*: can parse until the end of input.
+ pub fn $t<T, E: ParseError<T>>(input: T) -> IResult<T, $t, E>
+ where
+ T: InputIter + Slice<RangeFrom<usize>> + InputLength,
+ <T as InputIter>::Item: AsChar,
+ {
+ let i = input;
+
+ if i.input_len() == 0 {
+ return Err(Err::Incomplete(Needed::new(1)));
+ }
+
+ let mut value: $t = 0;
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(i, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_add(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(i, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+
+ Err(Err::Incomplete(Needed::new(1)))
+ }
+ )+
+ }
+}
+
+uints! { u8 u16 u32 u64 u128 }
+
#[cfg(test)]
mod tests {
use super::*;
use crate::error::ErrorKind;
use crate::internal::{Err, Needed};
+ use crate::sequence::pair;
+ use crate::traits::ParseTo;
+ use proptest::prelude::*;
macro_rules! assert_parse(
($left: expr, $right: expr) => {
@@ -920,10 +1048,9 @@ mod tests {
#[test]
fn full_line_windows() {
- named!(
- take_full_line<(&[u8], &[u8])>,
- tuple!(not_line_ending, line_ending)
- );
+ fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ pair(not_line_ending, line_ending)(i)
+ }
let input = b"abc\r\n";
let output = take_full_line(input);
assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\r\n"[..]))));
@@ -931,10 +1058,9 @@ mod tests {
#[test]
fn full_line_unix() {
- named!(
- take_full_line<(&[u8], &[u8])>,
- tuple!(not_line_ending, line_ending)
- );
+ fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ pair(not_line_ending, line_ending)(i)
+ }
let input = b"abc\n";
let output = take_full_line(input);
assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\n"[..]))));
@@ -992,4 +1118,65 @@ mod tests {
Err(Err::Error(error_position!("\ra", ErrorKind::CrLf)))
);
}
+
+ fn digit_to_i16(input: &str) -> IResult<&str, i16> {
+ let i = input;
+ let (i, opt_sign) = opt(alt((char('+'), char('-'))))(i)?;
+ let sign = match opt_sign {
+ Some('+') => true,
+ Some('-') => false,
+ _ => true,
+ };
+
+ let (i, s) = match digit1::<_, crate::error::Error<_>>(i) {
+ Ok((i, s)) => (i, s),
+ Err(Err::Incomplete(i)) => return Err(Err::Incomplete(i)),
+ Err(_) => {
+ return Err(Err::Error(crate::error::Error::from_error_kind(
+ input,
+ ErrorKind::Digit,
+ )))
+ }
+ };
+ match s.parse_to() {
+ Some(n) => {
+ if sign {
+ Ok((i, n))
+ } else {
+ Ok((i, -n))
+ }
+ }
+ None => Err(Err::Error(crate::error::Error::from_error_kind(
+ i,
+ ErrorKind::Digit,
+ ))),
+ }
+ }
+
+ fn digit_to_u32(i: &str) -> IResult<&str, u32> {
+ let (i, s) = digit1(i)?;
+ match s.parse_to() {
+ Some(n) => Ok((i, n)),
+ None => Err(Err::Error(crate::error::Error::from_error_kind(
+ i,
+ ErrorKind::Digit,
+ ))),
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn ints(s in "\\PC*") {
+ let res1 = digit_to_i16(&s);
+ let res2 = i16(s.as_str());
+ assert_eq!(res1, res2);
+ }
+
+ #[test]
+ fn uints(s in "\\PC*") {
+ let res1 = digit_to_u32(&s);
+ let res2 = u32(s.as_str());
+ assert_eq!(res1, res2);
+ }
+ }
}
diff --git a/src/character/tests.rs b/src/character/tests.rs
new file mode 100644
index 0000000..64c2a1c
--- /dev/null
+++ b/src/character/tests.rs
@@ -0,0 +1,62 @@
+use super::streaming::*;
+use crate::error::ErrorKind;
+use crate::internal::{Err, IResult};
+
+#[test]
+fn one_of_test() {
+ fn f(i: &[u8]) -> IResult<&[u8], char> {
+ one_of("ab")(i)
+ }
+
+ let a = &b"abcd"[..];
+ assert_eq!(f(a), Ok((&b"bcd"[..], 'a')));
+
+ let b = &b"cde"[..];
+ assert_eq!(f(b), Err(Err::Error(error_position!(b, ErrorKind::OneOf))));
+
+ fn utf8(i: &str) -> IResult<&str, char> {
+ one_of("+\u{FF0B}")(i)
+ }
+
+ assert!(utf8("+").is_ok());
+ assert!(utf8("\u{FF0B}").is_ok());
+}
+
+#[test]
+fn none_of_test() {
+ fn f(i: &[u8]) -> IResult<&[u8], char> {
+ none_of("ab")(i)
+ }
+
+ let a = &b"abcd"[..];
+ assert_eq!(f(a), Err(Err::Error(error_position!(a, ErrorKind::NoneOf))));
+
+ let b = &b"cde"[..];
+ assert_eq!(f(b), Ok((&b"de"[..], 'c')));
+}
+
+#[test]
+fn char_byteslice() {
+ fn f(i: &[u8]) -> IResult<&[u8], char> {
+ char('c')(i)
+ }
+
+ let a = &b"abcd"[..];
+ assert_eq!(f(a), Err(Err::Error(error_position!(a, ErrorKind::Char))));
+
+ let b = &b"cde"[..];
+ assert_eq!(f(b), Ok((&b"de"[..], 'c')));
+}
+
+#[test]
+fn char_str() {
+ fn f(i: &str) -> IResult<&str, char> {
+ char('c')(i)
+ }
+
+ let a = &"abcd"[..];
+ assert_eq!(f(a), Err(Err::Error(error_position!(a, ErrorKind::Char))));
+
+ let b = &"cde"[..];
+ assert_eq!(f(b), Ok((&"de"[..], 'c')));
+}
diff --git a/src/combinator/macros.rs b/src/combinator/macros.rs
deleted file mode 100644
index 11ece16..0000000
--- a/src/combinator/macros.rs
+++ /dev/null
@@ -1,1226 +0,0 @@
-//! Macro combinators
-//!
-//! Macros are used to make combination easier,
-//! since they often do not depend on the type
-//! of the data they manipulate or return.
-//!
-//! There is a trick to make them easier to assemble,
-//! combinators are defined like this:
-//!
-//! ```ignore
-//! macro_rules! tag (
-//! ($i:expr, $inp: expr) => (
-//! {
-//! ...
-//! }
-//! );
-//! );
-//! ```
-//!
-//! But when used in other combinators, are used
-//! like this:
-//!
-//! ```ignore
-//! named!(my_function, tag!("abcd"));
-//! ```
-//!
-//! Internally, other combinators will rewrite
-//! that call to pass the input as first argument:
-//!
-//! ```ignore
-//! macro_rules! named (
-//! ($name:ident, $submac:ident!( $($args:tt)* )) => (
-//! fn $name<'a>( i: &'a [u8] ) -> IResult<'a,&[u8], &[u8]> {
-//! $submac!(i, $($args)*)
-//! }
-//! );
-//! );
-//! ```
-//!
-//! If you want to call a combinator directly, you can
-//! do it like this:
-//!
-//! ```ignore
-//! let res = { tag!(input, "abcd"); }
-//! ```
-//!
-//! Combinators must have a specific variant for
-//! non-macro arguments. Example: Passing a function
-//! to `take_while!` instead of another combinator.
-//!
-//! ```ignore
-//! macro_rules! take_while(
-//! ($input:expr, $submac:ident!( $($args:tt)* )) => (
-//! {
-//! ...
-//! }
-//! );
-//!
-//! // wrap the function in a macro to pass it to the main implementation
-//! ($input:expr, $f:expr) => (
-//! take_while!($input, call!($f));
-//! );
-//! );
-//! ```
-#[allow(unused_variables)]
-
-/// Makes a function from a parser combination
-///
-/// The type can be set up if the compiler needs
-/// more information.
-///
-/// Function-like declaration:
-/// ```
-/// # use nom::{named, tag};
-/// named!(my_function( &[u8] ) -> &[u8], tag!("abcd"));
-/// ```
-/// Alternative declaration. First type parameter is input, second is output:
-/// ```
-/// # use nom::{named, tag};
-/// named!(my_function<&[u8], &[u8]>, tag!("abcd"));
-/// ```
-/// This one will have `&[u8]` as input type, `&[u8]` as output type:
-/// ```
-/// # use nom::{named, tag};
-/// named!(my_function, tag!("abcd"));
-/// ```
-/// Will use `&[u8]` as output type:
-/// ```
-/// # use nom::{named, tag};
-/// named!(my_function<&[u8]>, tag!("abcd"));
-/// ```
-/// Prefix them with 'pub' to make the functions public:
-/// ```
-/// # use nom::{named, tag};
-/// named!(pub my_function, tag!("abcd"));
-/// ```
-/// Prefix them with 'pub(crate)' to make the functions public within the crate:
-/// ```
-/// # use nom::{named, tag};
-/// named!(pub(crate) my_function, tag!("abcd"));
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! named (
- (#$($args:tt)*) => (
- named_attr!(#$($args)*);
- );
- ($vis:vis $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => (
- $vis fn $name( i: $i ) -> $crate::IResult<$i, $o, $crate::error::Error<$i>> {
- $submac!(i, $($args)*)
- }
- );
- ($vis:vis $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => (
- $vis fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> {
- $submac!(i, $($args)*)
- }
- );
- ($vis:vis $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => (
- $vis fn $name( i: $i ) -> $crate::IResult<$i, $o, $crate::error::Error<$i>> {
- $submac!(i, $($args)*)
- }
- );
- ($vis:vis $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
- $vis fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, $crate::error::Error<&[u8]>> {
- $submac!(i, $($args)*)
- }
- );
- ($vis:vis $name:ident, $submac:ident!( $($args:tt)* )) => (
- $vis fn $name( i: &[u8] ) -> $crate::IResult<&[u8], &[u8], $crate::error::Error<&[u8]>> {
- $submac!(i, $($args)*)
- }
- );
-);
-
-/// Makes a function from a parser combination with arguments.
-///
-/// ```ignore
-/// //takes [`&[u8]`] as input
-/// named_args!(tagged(open_tag: &[u8], close_tag: &[u8])<&str>,
-/// delimited!(tag!(open_tag), map_res!(take!(4), str::from_utf8), tag!(close_tag))
-/// );
-
-/// //takes `&str` as input
-/// named_args!(tagged(open_tag: &str, close_tag: &str)<&str, &str>,
-/// delimited!(tag!(open_tag), take!(4), tag!(close_tag))
-/// );
-/// ```
-///
-/// Note: If using arguments that way gets hard to read, it is always
-/// possible to write the equivalent parser definition manually, like
-/// this:
-///
-/// ```ignore
-/// fn tagged(input: &[u8], open_tag: &[u8], close_tag: &[u8]) -> IResult<&[u8], &str> {
-/// // the first combinator in the tree gets the input as argument. It is then
-/// // passed from one combinator to the next through macro rewriting
-/// delimited!(input,
-/// tag!(open_tag), take!(4), tag!(close_tag)
-/// )
-/// );
-/// ```
-///
-#[macro_export(local_inner_macros)]
-macro_rules! named_args {
- ($vis:vis $func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => {
- $vis fn $func_name(input: &[u8], $( $arg : $typ ),*) -> $crate::IResult<&[u8], $return_type> {
- $submac!(input, $($args)*)
- }
- };
-
- ($vis:vis $func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => {
- $vis fn $func_name<'this_is_probably_unique_i_hope_please, 'a>(
- input: &'this_is_probably_unique_i_hope_please [u8], $( $arg : $typ ),*) ->
- $crate::IResult<&'this_is_probably_unique_i_hope_please [u8], $return_type>
- {
- $submac!(input, $($args)*)
- }
- };
-
- ($vis:vis $func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $input_type:ty, $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => {
- $vis fn $func_name(input: $input_type, $( $arg : $typ ),*) -> $crate::IResult<$input_type, $return_type> {
- $submac!(input, $($args)*)
- }
- };
-
- ($vis:vis $func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $input_type:ty, $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => {
- $vis fn $func_name<'a>(
- input: $input_type, $( $arg : $typ ),*)
- -> $crate::IResult<$input_type, $return_type>
- {
- $submac!(input, $($args)*)
- }
- };
-}
-
-/// Makes a function from a parser combination, with attributes.
-///
-/// The usage of this macro is almost identical to `named!`, except that
-/// you also pass attributes to be attached to the generated function.
-/// This is ideal for adding documentation to your parser.
-///
-/// Create my_function as if you wrote it with the doc comment /// My Func:
-/// ```
-/// # use nom::{named_attr, tag};
-/// named_attr!(#[doc = "My Func"], my_function( &[u8] ) -> &[u8], tag!("abcd"));
-/// ```
-/// Also works for pub functions, and multiple lines:
-/// ```
-/// # use nom::{named_attr, tag};
-/// named_attr!(#[doc = "My Func\nRecognise abcd"], pub my_function, tag!("abcd"));
-/// ```
-/// Multiple attributes can be passed if required:
-/// ```
-/// # use nom::{named_attr, tag};
-/// named_attr!(#[doc = "My Func"] #[inline(always)], pub my_function, tag!("abcd"));
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! named_attr (
- ($(#[$attr:meta])*, $vis:vis $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => (
- $(#[$attr])*
- $vis fn $name( i: $i ) -> $crate::IResult<$i,$o, $crate::error::Error<$i>> {
- $submac!(i, $($args)*)
- }
- );
- ($(#[$attr:meta])*, $vis:vis $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => (
- $(#[$attr])*
- $vis fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> {
- $submac!(i, $($args)*)
- }
- );
- ($(#[$attr:meta])*, $vis:vis $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => (
- $(#[$attr])*
- $vis fn $name( i: $i ) -> $crate::IResult<$i, $o, $crate::error::Error<$i>> {
- $submac!(i, $($args)*)
- }
- );
- ($(#[$attr:meta])*, $vis:vis $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
- $(#[$attr])*
- $vis fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, $crate::error::Error<&[u8]>> {
- $submac!(i, $($args)*)
- }
- );
- ($(#[$attr:meta])*, $vis:vis $name:ident, $submac:ident!( $($args:tt)* )) => (
- $(#[$attr])*
- $vis fn $name<'a>( i: &'a [u8] ) -> $crate::IResult<&[u8], &[u8], $crate::error::Error<&[u8]>> {
- $submac!(i, $($args)*)
- }
- );
-);
-
-/// Used to wrap common expressions and function as macros.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::IResult;
-/// # fn main() {
-/// fn take_wrapper(input: &[u8], i: u8) -> IResult<&[u8], &[u8]> { take!(input, i * 10) }
-///
-/// // will make a parser taking 20 bytes
-/// named!(parser, call!(take_wrapper, 2));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! call (
- ($i:expr, $fun:expr) => ( $fun( $i ) );
- ($i:expr, $fun:expr, $($args:expr),* ) => ( $fun( $i, $($args),* ) );
-);
-
-//FIXME: error rewrite
-/// Prevents backtracking if the child parser fails.
-///
-/// This parser will do an early return instead of sending
-/// its result to the parent parser.
-///
-/// If another `return_error!` combinator is present in the parent
-/// chain, the error will be wrapped and another early
-/// return will be made.
-///
-/// This makes it easy to build report on which parser failed,
-/// where it failed in the input, and the chain of parsers
-/// that led it there.
-///
-/// Additionally, the error chain contains number identifiers
-/// that can be matched to provide useful error messages.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(err_test<&[u8], &[u8]>, alt!(
-/// tag!("abcd") |
-/// preceded!(tag!("efgh"), return_error!(ErrorKind::Eof,
-/// do_parse!(
-/// tag!("ijkl") >>
-/// res: return_error!(ErrorKind::Tag, tag!("mnop")) >>
-/// (res)
-/// )
-/// )
-/// )
-/// ));
-/// let a = &b"efghblah"[..];
-/// let b = &b"efghijklblah"[..];
-/// let c = &b"efghijklmnop"[..];
-///
-/// let blah = &b"blah"[..];
-///
-/// let res_a = err_test(a);
-/// let res_b = err_test(b);
-/// let res_c = err_test(c);
-/// assert_eq!(res_a, Err(Err::Failure(error_node_position!(blah, ErrorKind::Eof, error_position!(blah, ErrorKind::Tag)))));
-/// assert_eq!(res_b, Err(Err::Failure(error_node_position!(&b"ijklblah"[..], ErrorKind::Eof,
-/// error_node_position!(blah, ErrorKind::Tag, error_position!(blah, ErrorKind::Tag))))
-/// ));
-/// # }
-/// ```
-///
-#[macro_export(local_inner_macros)]
-macro_rules! return_error (
- ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::Err;
-
- let i_ = $i.clone();
- let cl = || {
- $submac!(i_, $($args)*)
- };
-
- match cl() {
- Err(Err::Incomplete(x)) => Err(Err::Incomplete(x)),
- Ok((i, o)) => Ok((i, o)),
- Err(Err::Error(e)) | Err(Err::Failure(e)) => {
- return Err(Err::Failure($crate::error::append_error($i, $code, e)))
- }
- }
- }
- );
- ($i:expr, $code:expr, $f:expr) => (
- return_error!($i, $code, call!($f));
- );
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::Err;
-
- let i_ = $i.clone();
- let cl = || {
- $submac!(i_, $($args)*)
- };
-
- match cl() {
- Err(Err::Incomplete(x)) => Err(Err::Incomplete(x)),
- Ok((i, o)) => Ok((i, o)),
- Err(Err::Error(e)) | Err(Err::Failure(e)) => {
- return Err(Err::Failure(e))
- }
- }
- }
- );
- ($i:expr, $f:expr) => (
- return_error!($i, call!($f));
- );
-);
-
-//FIXME: error rewrite
-/// Add an error if the child parser fails.
-///
-/// While `return_error!` does an early return and avoids backtracking,
-/// `add_return_error!` backtracks normally. It just provides more context
-/// for an error.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use std::collections;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(err_test, add_return_error!(ErrorKind::Tag, tag!("abcd")));
-///
-/// let a = &b"efghblah"[..];
-/// let res_a = err_test(a);
-/// assert_eq!(res_a, Err(Err::Error(error_node_position!(a, ErrorKind::Tag, error_position!(a, ErrorKind::Tag)))));
-/// # }
-/// ```
-///
-#[macro_export(local_inner_macros)]
-macro_rules! add_return_error (
- ($i:expr, $code:expr, $submac:ident!( $($args:tt)* )) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::{Err,error::ErrorKind};
-
- match $submac!($i, $($args)*) {
- Ok((i, o)) => Ok((i, o)),
- Err(Err::Error(e)) => {
- Err(Err::Error(error_node_position!($i, $code, e)))
- },
- Err(Err::Failure(e)) => {
- Err(Err::Failure(error_node_position!($i, $code, e)))
- },
- Err(e) => Err(e),
- }
- }
- );
- ($i:expr, $code:expr, $f:expr) => (
- add_return_error!($i, $code, call!($f));
- );
-);
-
-/// Replaces a `Incomplete` returned by the child parser
-/// with an `Error`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use std::collections;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(take_5, complete!(take!(5)));
-///
-/// let a = &b"abcd"[..];
-/// let res_a = take_5(a);
-/// assert_eq!(res_a, Err(Err::Error(error_position!(a, ErrorKind::Complete))));
-/// # }
-/// ```
-///
-#[macro_export(local_inner_macros)]
-macro_rules! complete (
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::combinator::completec($i, move |i| { $submac!(i, $($args)*) })
- );
- ($i:expr, $f:expr) => (
- complete!($i, call!($f));
- );
-);
-
-/// A bit like `std::try!`, this macro will return the remaining input and
-/// parsed value if the child parser returned `Ok`, and will do an early
-/// return for the `Err` side.
-///
-/// This can provide more flexibility than `do_parse!` if needed.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # use nom::IResult;
-///
-/// fn take_add(input:&[u8], size: u8) -> IResult<&[u8], &[u8]> {
-/// let (i1, length) = try_parse!(input, map_opt!(nom::number::streaming::be_u8, |sz| size.checked_add(sz)));
-/// let (i2, data) = try_parse!(i1, take!(length));
-/// return Ok((i2, data));
-/// }
-/// # fn main() {
-/// let arr1 = [1, 2, 3, 4, 5];
-/// let r1 = take_add(&arr1[..], 1);
-/// assert_eq!(r1, Ok((&[4,5][..], &[2,3][..])));
-///
-/// let arr2 = [0xFE, 2, 3, 4, 5];
-/// // size is overflowing
-/// let r1 = take_add(&arr2[..], 42);
-/// assert_eq!(r1, Err(Err::Error(error_position!(&[254, 2,3,4,5][..], ErrorKind::MapOpt))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! try_parse (
- ($i:expr, $submac:ident!( $($args:tt)* )) => ({
- use $crate::lib::std::result::Result::*;
-
- match $submac!($i, $($args)*) {
- Ok((i,o)) => (i,o),
- Err(e) => return Err(e),
- }
- });
- ($i:expr, $f:expr) => (
- try_parse!($i, call!($f))
- );
-);
-
-/// `map!(I -> IResult<I, O>, O -> P) => I -> IResult<I, P>`
-///
-/// Maps a function on the result of a parser.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::ErrorKind, IResult};
-/// use nom::character::complete::digit1;
-/// # fn main() {
-///
-/// named!(parse<&str, usize>, map!(digit1, |s| s.len()));
-///
-/// // the parser will count how many characters were returned by digit1
-/// assert_eq!(parse("123456"), Ok(("", 6)));
-///
-/// // this will fail if digit1 fails
-/// assert_eq!(parse("abc"), Err(Err::Error(error_position!("abc", ErrorKind::Digit))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! map(
- // Internal parser, do not use directly
- (__impl $i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- $crate::combinator::mapc($i, move |i| {$submac!(i, $($args)*)}, $g)
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- map!(__impl $i, $submac!($($args)*), $g);
- );
- ($i:expr, $f:expr, $g:expr) => (
- map!(__impl $i, call!($f), $g);
- );
-);
-
-/// `map_res!(I -> IResult<I, O>, O -> Result<P>) => I -> IResult<I, P>`
-/// maps a function returning a `Result` on the output of a parser.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::ErrorKind, IResult};
-/// use nom::character::complete::digit1;
-/// # fn main() {
-///
-/// named!(parse<&str, u8>, map_res!(digit1, |s: &str| s.parse::<u8>()));
-///
-/// // the parser will convert the result of digit1 to a number
-/// assert_eq!(parse("123"), Ok(("", 123)));
-///
-/// // this will fail if digit1 fails
-/// assert_eq!(parse("abc"), Err(Err::Error(error_position!("abc", ErrorKind::Digit))));
-///
-/// // this will fail if the mapped function fails (a `u8` is too small to hold `123456`)
-/// assert_eq!(parse("123456"), Err(Err::Error(error_position!("123456", ErrorKind::MapRes))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! map_res (
- // Internal parser, do not use directly
- (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- $crate::combinator::map_resc($i, move |i| {$submac!(i, $($args)*)}, move |i| {$submac2!(i, $($args2)*)})
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- map_res!(__impl $i, $submac!($($args)*), call!($g));
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- map_res!(__impl $i, $submac!($($args)*), $submac2!($($args2)*));
- );
- ($i:expr, $f:expr, $g:expr) => (
- map_res!(__impl $i, call!($f), call!($g));
- );
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- map_res!(__impl $i, call!($f), $submac!($($args)*));
- );
-);
-
-/// `map_opt!(I -> IResult<I, O>, O -> Option<P>) => I -> IResult<I, P>`
-/// maps a function returning an `Option` on the output of a parser.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::{Error, ErrorKind}, IResult};
-/// use nom::character::complete::digit1;
-/// # fn main() {
-///
-/// named!(parser<&str, u8>, map_opt!(digit1, |s: &str| s.parse::<u8>().ok()));
-///
-/// // the parser will convert the result of digit1 to a number
-/// assert_eq!(parser("123"), Ok(("", 123)));
-///
-/// // this will fail if digit1 fails
-/// assert_eq!(parser("abc"), Err(Err::Error(Error::new("abc", ErrorKind::Digit))));
-///
-/// // this will fail if the mapped function fails (a `u8` is too small to hold `123456`)
-/// assert_eq!(parser("123456"), Err(Err::Error(Error::new("123456", ErrorKind::MapOpt))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! map_opt (
- // Internal parser, do not use directly
- (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- $crate::combinator::map_optc($i, move |i| {$submac!(i, $($args)*)}, move |i| {$submac2!(i, $($args2)*)})
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- map_opt!(__impl $i, $submac!($($args)*), call!($g));
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- map_opt!(__impl $i, $submac!($($args)*), $submac2!($($args2)*));
- );
- ($i:expr, $f:expr, $g:expr) => (
- map_opt!(__impl $i, call!($f), call!($g));
- );
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- map_opt!(__impl $i, call!($f), $submac!($($args)*));
- );
-);
-
-/// `parse_to!(O) => I -> IResult<I, O>`
-/// Uses the `parse` method from `std::str::FromStr` to convert the current
-/// input to the specified type.
-///
-/// This will completely consume the input.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,error::{Error, ErrorKind}, IResult};
-/// use nom::character::complete::digit1;
-/// # fn main() {
-///
-/// named!(parser<&str, u8>, parse_to!(u8));
-///
-/// assert_eq!(parser("123"), Ok(("", 123)));
-///
-/// assert_eq!(parser("abc"), Err(Err::Error(Error::new("abc", ErrorKind::ParseTo))));
-///
-/// // this will fail if the mapped function fails (a `u8` is too small to hold `123456`)
-/// assert_eq!(parser("123456"), Err(Err::Error(Error::new("123456", ErrorKind::ParseTo))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! parse_to (
- ($i:expr, $t:ty ) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::lib::std::option::Option;
- use $crate::lib::std::option::Option::*;
- use $crate::{Err,error::ErrorKind};
-
- use $crate::ParseTo;
- use $crate::Slice;
- use $crate::InputLength;
-
- let res: Option<$t> = ($i).parse_to();
- match res {
- Some(output) => Ok(($i.slice($i.input_len()..), output)),
- None => Err(Err::Error($crate::error::make_error($i, ErrorKind::ParseTo)))
- }
- }
- );
-);
-
-/// `verify!(I -> IResult<I, O>, O -> bool) => I -> IResult<I, O>`
-/// returns the result of the child parser if it satisfies a verification function.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(check<u32>, verify!(nom::number::streaming::be_u32, |val: &u32| *val < 3));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! verify (
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- $crate::combinator::verifyc($i, |i| $submac!(i, $($args)*), $g)
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- $crate::combinator::verifyc($i, |i| $submac!(i, $($args)*), |&o| $submac2!(o, $($args2)*))
- );
- ($i:expr, $f:expr, $g:expr) => (
- $crate::combinator::verify($f, $g)($i)
- );
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::combinator::verify($f, |&o| $submac!(o, $($args)*))($i)
- );
-);
-
-/// `value!(T, R -> IResult<R, S> ) => R -> IResult<R, T>`
-///
-/// or `value!(T) => R -> IResult<R, T>`
-///
-/// If the child parser was successful, return the value.
-/// If no child parser is provided, always return the value.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(x<u8>, value!(42, delimited!(tag!("<!--"), take!(5), tag!("-->"))));
-/// named!(y<u8>, delimited!(tag!("<!--"), value!(42), tag!("-->")));
-/// let r = x(&b"<!-- abc --> aaa"[..]);
-/// assert_eq!(r, Ok((&b" aaa"[..], 42)));
-///
-/// let r2 = y(&b"<!----> aaa"[..]);
-/// assert_eq!(r2, Ok((&b" aaa"[..], 42)));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! value (
- ($i:expr, $res:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::combinator::valuec($i, $res, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $res:expr, $f:expr) => (
- $crate::combinator::valuec($i, $res, $f)
- );
- ($i:expr, $res:expr) => (
- Ok(($i, $res))
- );
-);
-
-/// `opt!(I -> IResult<I,O>) => I -> IResult<I, Option<O>>`
-/// make the underlying parser optional.
-///
-/// Returns an `Option` of the returned type. This parser returns `Some(result)` if the child parser
-/// succeeds, `None` if it fails, and `Incomplete` if it did not have enough data to decide.
-///
-/// *Warning*: if you are using `opt` for some kind of optional ending token (like an end of line),
-/// you should combine it with `complete` to make sure it works.
-///
-/// As an example, `opt!(tag!("\r\n"))` will return `Incomplete` if it receives an empty input,
-/// because `tag` does not have enough input to decide.
-/// On the contrary, `opt!(complete!(tag!("\r\n")))` would return `None` as produced value,
-/// since `complete!` transforms an `Incomplete` in an `Error`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!( o<&[u8], Option<&[u8]> >, opt!( tag!( "abcd" ) ) );
-///
-/// let a = b"abcdef";
-/// let b = b"bcdefg";
-/// assert_eq!(o(&a[..]), Ok((&b"ef"[..], Some(&b"abcd"[..]))));
-/// assert_eq!(o(&b[..]), Ok((&b"bcdefg"[..], None)));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! opt(
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- {
- $crate::combinator::optc($i, |i| $submac!(i, $($args)*))
- }
- );
- ($i:expr, $f:expr) => (
- $crate::combinator::opt($f)($i)
- );
-);
-
-/// `opt_res!(I -> IResult<I,O>) => I -> IResult<I, Result<nom::Err,O>>`
-/// make the underlying parser optional.
-///
-/// Returns a `Result`, with `Err` containing the parsing error.
-///
-/// ```ignore
-/// # #[macro_use] extern crate nom;
-/// # use nom::ErrorKind;
-/// # fn main() {
-/// named!( o<&[u8], Result<&[u8], nom::Err<&[u8]> > >, opt_res!( tag!( "abcd" ) ) );
-///
-/// let a = b"abcdef";
-/// let b = b"bcdefg";
-/// assert_eq!(o(&a[..]), Ok((&b"ef"[..], Ok(&b"abcd"[..])));
-/// assert_eq!(o(&b[..]), Ok((&b"bcdefg"[..], Err(error_position!(&b[..], ErrorKind::Tag))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! opt_res (
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::Err;
-
- let i_ = $i.clone();
- match $submac!(i_, $($args)*) {
- Ok((i,o)) => Ok((i, Ok(o))),
- Err(Err::Error(e)) => Ok(($i, Err(Err::Error(e)))),
- // in case of failure, we return a real error
- Err(e) => Err(e)
- }
- }
- );
- ($i:expr, $f:expr) => (
- opt_res!($i, call!($f));
- );
-);
-
-/// `cond!(bool, I -> IResult<I,O>) => I -> IResult<I, Option<O>>`
-/// Conditional combinator
-///
-/// Wraps another parser and calls it if the
-/// condition is met. This combinator returns
-/// an Option of the return type of the child
-/// parser.
-///
-/// This is especially useful if a parser depends
-/// on the value returned by a preceding parser in
-/// a `do_parse!`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::IResult;
-/// # fn main() {
-/// fn f_true(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
-/// cond!(i, true, tag!("abcd"))
-/// }
-///
-/// fn f_false(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
-/// cond!(i, false, tag!("abcd"))
-/// }
-///
-/// let a = b"abcdef";
-/// assert_eq!(f_true(&a[..]), Ok((&b"ef"[..], Some(&b"abcd"[..]))));
-///
-/// assert_eq!(f_false(&a[..]), Ok((&b"abcdef"[..], None)));
-/// # }
-/// ```
-///
-#[macro_export(local_inner_macros)]
-macro_rules! cond(
- ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::combinator::condc($i, $cond, |i| $submac!(i, $($args)*) )
- );
- ($i:expr, $cond:expr, $f:expr) => (
- $crate::combinator::cond($cond, $f)($i)
- );
-);
-
-/// `peek!(I -> IResult<I,O>) => I -> IResult<I, O>`
-/// returns a result without consuming the input.
-///
-/// The embedded parser may return `Err(Err::Incomplete)`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(ptag, peek!( tag!( "abcd" ) ) );
-///
-/// let r = ptag(&b"abcdefgh"[..]);
-/// assert_eq!(r, Ok((&b"abcdefgh"[..], &b"abcd"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! peek(
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::combinator::peekc($i, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $f:expr) => (
- $crate::combinator::peek($f)($i)
- );
-);
-
-/// `not!(I -> IResult<I,O>) => I -> IResult<I, ()>`
-/// returns a result only if the embedded parser returns `Error` or `Err(Err::Incomplete)`.
-/// Does not consume the input.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(not_e, do_parse!(
-/// res: tag!("abc") >>
-/// not!(char!('e')) >>
-/// (res)
-/// ));
-///
-/// let r = not_e(&b"abcd"[..]);
-/// assert_eq!(r, Ok((&b"d"[..], &b"abc"[..])));
-///
-/// let r2 = not_e(&b"abce"[..]);
-/// assert_eq!(r2, Err(Err::Error(error_position!(&b"e"[..], ErrorKind::Not))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! not(
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::combinator::notc($i, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $f:expr) => (
- $crate::combinator::not($f)($i)
- );
-);
-
-/// `tap!(name: I -> IResult<I,O> => { block }) => I -> IResult<I, O>`
-/// allows access to the parser's result without affecting it.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use std::str;
-/// # fn main() {
-/// named!(ptag, tap!(res: tag!( "abcd" ) => { println!("recognized {}", str::from_utf8(res).unwrap()) } ) );
-///
-/// let r = ptag(&b"abcdefgh"[..]);
-/// assert_eq!(r, Ok((&b"efgh"[..], &b"abcd"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! tap (
- ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::{Err,Needed,IResult};
-
- match $submac!($i, $($args)*) {
- Ok((i,o)) => {
- let $name = o;
- $e;
- Ok((i, $name))
- },
- Err(e) => Err(Err::convert(e)),
- }
- }
- );
- ($i:expr, $name: ident: $f:expr => $e:expr) => (
- tap!($i, $name: call!($f) => $e);
- );
-);
-
-/// `eof!()` returns its input if it is at the end of input data.
-///
-/// When we're at the end of the data, this combinator
-/// will succeed.
-///
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use std::str;
-/// # use nom::{Err, error::{Error ,ErrorKind}};
-/// # fn main() {
-/// named!(parser, eof!());
-///
-/// assert_eq!(parser(&b"abc"[..]), Err(Err::Error(Error::new(&b"abc"[..], ErrorKind::Eof))));
-/// assert_eq!(parser(&b""[..]), Ok((&b""[..], &b""[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! eof (
- ($i:expr,) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::{Err,error::ErrorKind};
-
- use $crate::InputLength;
- if ($i).input_len() == 0 {
- let clone = $i.clone();
- Ok(($i, clone))
- } else {
- Err(Err::Error(error_position!($i, ErrorKind::Eof)))
- }
- }
- );
-);
-
-/// `exact!()` will fail if the child parser does not consume the whole data.
-///
-/// TODO: example
-#[macro_export(local_inner_macros)]
-macro_rules! exact (
- ($i:expr, $submac:ident!( $($args:tt)* )) => ({
- terminated!($i, $submac!( $($args)*), eof!())
- });
- ($i:expr, $f:expr) => (
- exact!($i, call!($f));
- );
-);
-
-/// `recognize!(I -> IResult<I, O> ) => I -> IResult<I, I>`
-/// if the child parser was successful, return the consumed input as produced value.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(x, recognize!(delimited!(tag!("<!--"), take!(5), tag!("-->"))));
-/// let r = x(&b"<!-- abc --> aaa"[..]);
-/// assert_eq!(r, Ok((&b" aaa"[..], &b"<!-- abc -->"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! recognize (
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::combinator::recognizec($i, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $f:expr) => (
- $crate::combinator::recognize($f)($i)
- );
-);
-
-/// `into!(I -> IResult<I, O1, E1>) => I -> IResult<I, O2, E2>`
-/// automatically converts the child parser's result to another type
-///
-/// it will be able to convert the output value and the error value
-/// as long as the `Into` implementations are available
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::IResult;
-/// # fn main() {
-/// named!(parse_to_str<&str, &str>, take!(4));
-/// named!(parse_to_vec<&str, Vec<u8>>, into!(parse_to_str));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! into (
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::combinator::intoc($i, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $f:expr) => (
- $crate::combinator::intoc($i, $f)
- );
-);
-
-#[cfg(test)]
-mod tests {
- use crate::error::ErrorKind;
- use crate::error::ParseError;
- use crate::internal::{Err, IResult, Needed};
- #[cfg(feature = "alloc")]
- use crate::lib::std::boxed::Box;
-
- // reproduce the tag and take macros, because of module import order
- macro_rules! tag (
- ($i:expr, $tag: expr) => ({
- use $crate::lib::std::result::Result::*;
- use $crate::{Err,Needed,IResult,error::ErrorKind};
- use $crate::{Compare,CompareResult,InputLength,Slice};
-
- let res: IResult<_,_> = match ($i).compare($tag) {
- CompareResult::Ok => {
- let blen = $tag.input_len();
- Ok(($i.slice(blen..), $i.slice(..blen)))
- },
- CompareResult::Incomplete => {
- Err(Err::Incomplete(Needed::new($tag.input_len() - $i.input_len())))
- },
- CompareResult::Error => {
- let e:ErrorKind = ErrorKind::Tag;
- Err(Err::Error($crate::error::make_error($i, e)))
- }
- };
- res
- });
- );
-
- macro_rules! take(
- ($i:expr, $count:expr) => (
- {
- let cnt = $count as usize;
- let res:IResult<&[u8],&[u8]> = if $i.len() < cnt {
- Err($crate::Err::Incomplete($crate::Needed::new(cnt - $i.len())))
- } else {
- Ok((&$i[cnt..],&$i[0..cnt]))
- };
- res
- }
- );
- );
-
- mod pub_named_mod {
- named!(pub tst, tag!("abcd"));
- }
-
- #[test]
- fn pub_named_test() {
- let a = &b"abcd"[..];
- let res = pub_named_mod::tst(a);
- assert_eq!(res, Ok((&b""[..], a)));
- }
-
- mod pub_crate_named_mod {
- named!(pub(crate) tst, tag!("abcd"));
- }
-
- #[test]
- fn pub_crate_named_test() {
- let a = &b"abcd"[..];
- let res = pub_crate_named_mod::tst(a);
- assert_eq!(res, Ok((&b""[..], a)));
- }
-
- #[test]
- fn apply_test() {
- fn sum2(a: u8, b: u8) -> u8 {
- a + b
- }
- fn sum3(a: u8, b: u8, c: u8) -> u8 {
- a + b + c
- }
- let a = call!(1, sum2, 2);
- let b = call!(1, sum3, 2, 3);
-
- assert_eq!(a, 3);
- assert_eq!(b, 6);
- }
-
- #[test]
- fn opt() {
- named!(opt_abcd<&[u8],Option<&[u8]> >, opt!(tag!("abcd")));
-
- let a = &b"abcdef"[..];
- let b = &b"bcdefg"[..];
- let c = &b"ab"[..];
- assert_eq!(opt_abcd(a), Ok((&b"ef"[..], Some(&b"abcd"[..]))));
- assert_eq!(opt_abcd(b), Ok((&b"bcdefg"[..], None)));
- assert_eq!(opt_abcd(c), Err(Err::Incomplete(Needed::new(2))));
- }
-
- #[test]
- fn opt_res() {
- named!(opt_res_abcd<&[u8], Result<&[u8], Err<crate::error::Error<&[u8]>>> >, opt_res!(tag!("abcd")));
-
- let a = &b"abcdef"[..];
- let b = &b"bcdefg"[..];
- let c = &b"ab"[..];
- assert_eq!(opt_res_abcd(a), Ok((&b"ef"[..], Ok(&b"abcd"[..]))));
- assert_eq!(
- opt_res_abcd(b),
- Ok((
- &b"bcdefg"[..],
- Err(Err::Error(error_position!(b, ErrorKind::Tag)))
- ))
- );
- assert_eq!(opt_res_abcd(c), Err(Err::Incomplete(Needed::new(2))));
- }
-
- use crate::lib::std::convert::From;
- #[derive(Debug, PartialEq)]
- pub struct CustomError(&'static str);
- impl<I> From<(I, ErrorKind)> for CustomError {
- fn from(_: (I, ErrorKind)) -> Self {
- CustomError("test")
- }
- }
- impl<I> From<crate::error::Error<I>> for CustomError {
- fn from(_: crate::error::Error<I>) -> Self {
- CustomError("test")
- }
- }
-
- impl<I> ParseError<I> for CustomError {
- fn from_error_kind(_: I, _: ErrorKind) -> Self {
- CustomError("from_error_kind")
- }
-
- fn append(_: I, _: ErrorKind, _: CustomError) -> Self {
- CustomError("append")
- }
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn cond() {
- fn f_true(i: &[u8]) -> IResult<&[u8], Option<&[u8]>, CustomError> {
- fix_error!(i, CustomError, cond!(true, tag!("abcd")))
- }
-
- fn f_false(i: &[u8]) -> IResult<&[u8], Option<&[u8]>, CustomError> {
- fix_error!(i, CustomError, cond!(false, tag!("abcd")))
- }
-
- assert_eq!(f_true(&b"abcdef"[..]), Ok((&b"ef"[..], Some(&b"abcd"[..]))));
- assert_eq!(f_true(&b"ab"[..]), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(f_true(&b"xxx"[..]), Err(Err::Error(CustomError("test"))));
-
- assert_eq!(f_false(&b"abcdef"[..]), Ok((&b"abcdef"[..], None)));
- assert_eq!(f_false(&b"ab"[..]), Ok((&b"ab"[..], None)));
- assert_eq!(f_false(&b"xxx"[..]), Ok((&b"xxx"[..], None)));
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn cond_wrapping() {
- // Test that cond!() will wrap a given identifier in the call!() macro.
- named!(tag_abcd, tag!("abcd"));
- fn f_true(i: &[u8]) -> IResult<&[u8], Option<&[u8]>, CustomError> {
- fix_error!(i, CustomError, cond!(true, tag_abcd))
- }
-
- fn f_false(i: &[u8]) -> IResult<&[u8], Option<&[u8]>, CustomError> {
- fix_error!(i, CustomError, cond!(false, tag_abcd))
- }
-
- assert_eq!(f_true(&b"abcdef"[..]), Ok((&b"ef"[..], Some(&b"abcd"[..]))));
- assert_eq!(f_true(&b"ab"[..]), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(f_true(&b"xxx"[..]), Err(Err::Error(CustomError("test"))));
-
- assert_eq!(f_false(&b"abcdef"[..]), Ok((&b"abcdef"[..], None)));
- assert_eq!(f_false(&b"ab"[..]), Ok((&b"ab"[..], None)));
- assert_eq!(f_false(&b"xxx"[..]), Ok((&b"xxx"[..], None)));
- }
-
- #[test]
- fn peek() {
- named!(peek_tag<&[u8],&[u8]>, peek!(tag!("abcd")));
-
- assert_eq!(peek_tag(&b"abcdef"[..]), Ok((&b"abcdef"[..], &b"abcd"[..])));
- assert_eq!(peek_tag(&b"ab"[..]), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(
- peek_tag(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn not() {
- named!(not_aaa<()>, not!(tag!("aaa")));
- assert_eq!(
- not_aaa(&b"aaa"[..]),
- Err(Err::Error(error_position!(&b"aaa"[..], ErrorKind::Not)))
- );
- assert_eq!(not_aaa(&b"aa"[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(not_aaa(&b"abcd"[..]), Ok((&b"abcd"[..], ())));
- }
-
- #[test]
- fn verify() {
- named!(test, verify!(take!(5), |slice: &[u8]| slice[0] == b'a'));
- assert_eq!(test(&b"bcd"[..]), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(
- test(&b"bcdefg"[..]),
- Err(Err::Error(error_position!(
- &b"bcdefg"[..],
- ErrorKind::Verify
- )))
- );
- assert_eq!(test(&b"abcdefg"[..]), Ok((&b"fg"[..], &b"abcde"[..])));
- }
-
- #[test]
- fn parse_to() {
- let res: IResult<_, _, (&str, ErrorKind)> = parse_to!("ab", usize);
-
- assert_eq!(
- res,
- Err(Err::Error(error_position!("ab", ErrorKind::ParseTo)))
- );
-
- let res: IResult<_, _, (&str, ErrorKind)> = parse_to!("42", usize);
-
- assert_eq!(res, Ok(("", 42)));
- //assert_eq!(ErrorKind::convert(ErrorKind::ParseTo), ErrorKind::ParseTo::<u64>);
- }
-}
diff --git a/src/combinator/mod.rs b/src/combinator/mod.rs
index 4792d0b..a2e59fb 100644
--- a/src/combinator/mod.rs
+++ b/src/combinator/mod.rs
@@ -16,8 +16,8 @@ use crate::lib::std::ops::{Range, RangeFrom, RangeTo};
use crate::traits::{AsChar, InputIter, InputLength, InputTakeAtPosition, ParseTo};
use crate::traits::{Compare, CompareResult, Offset, Slice};
-#[macro_use]
-mod macros;
+#[cfg(test)]
+mod tests;
/// Return the remaining input.
///
@@ -71,26 +71,17 @@ where
/// assert_eq!(parser.parse("abc"), Err(Err::Error(("abc", ErrorKind::Digit))));
/// # }
/// ```
-pub fn map<I, O1, O2, E, F, G>(mut first: F, mut second: G) -> impl FnMut(I) -> IResult<I, O2, E>
+pub fn map<I, O1, O2, E, F, G>(mut parser: F, mut f: G) -> impl FnMut(I) -> IResult<I, O2, E>
where
F: Parser<I, O1, E>,
G: FnMut(O1) -> O2,
{
move |input: I| {
- let (input, o1) = first.parse(input)?;
- Ok((input, second(o1)))
+ let (input, o1) = parser.parse(input)?;
+ Ok((input, f(o1)))
}
}
-#[doc(hidden)]
-pub fn mapc<I, O1, O2, E, F, G>(input: I, first: F, second: G) -> IResult<I, O2, E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(O1) -> O2,
-{
- map(first, second).parse(input)
-}
-
/// Applies a function returning a `Result` over the result of a parser.
///
/// ```rust
@@ -113,8 +104,8 @@ where
/// # }
/// ```
pub fn map_res<I: Clone, O1, O2, E: FromExternalError<I, E2>, E2, F, G>(
- mut first: F,
- mut second: G,
+ mut parser: F,
+ mut f: G,
) -> impl FnMut(I) -> IResult<I, O2, E>
where
F: Parser<I, O1, E>,
@@ -122,27 +113,14 @@ where
{
move |input: I| {
let i = input.clone();
- let (input, o1) = first.parse(input)?;
- match second(o1) {
+ let (input, o1) = parser.parse(input)?;
+ match f(o1) {
Ok(o2) => Ok((input, o2)),
Err(e) => Err(Err::Error(E::from_external_error(i, ErrorKind::MapRes, e))),
}
}
}
-#[doc(hidden)]
-pub fn map_resc<I: Clone, O1, O2, E: FromExternalError<I, E2>, E2, F, G>(
- input: I,
- first: F,
- second: G,
-) -> IResult<I, O2, E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(O1) -> Result<O2, E2>,
-{
- map_res(first, second)(input)
-}
-
/// Applies a function returning an `Option` over the result of a parser.
///
/// ```rust
@@ -165,8 +143,8 @@ where
/// # }
/// ```
pub fn map_opt<I: Clone, O1, O2, E: ParseError<I>, F, G>(
- mut first: F,
- mut second: G,
+ mut parser: F,
+ mut f: G,
) -> impl FnMut(I) -> IResult<I, O2, E>
where
F: Parser<I, O1, E>,
@@ -174,27 +152,14 @@ where
{
move |input: I| {
let i = input.clone();
- let (input, o1) = first.parse(input)?;
- match second(o1) {
+ let (input, o1) = parser.parse(input)?;
+ match f(o1) {
Some(o2) => Ok((input, o2)),
None => Err(Err::Error(E::from_error_kind(i, ErrorKind::MapOpt))),
}
}
}
-#[doc(hidden)]
-pub fn map_optc<I: Clone, O1, O2, E: ParseError<I>, F, G>(
- input: I,
- first: F,
- second: G,
-) -> IResult<I, O2, E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(O1) -> Option<O2>,
-{
- map_opt(first, second)(input)
-}
-
/// Applies a parser over the result of another one.
///
/// ```rust
@@ -213,33 +178,20 @@ where
/// # }
/// ```
pub fn map_parser<I, O1, O2, E: ParseError<I>, F, G>(
- mut first: F,
- mut second: G,
+ mut parser: F,
+ mut applied_parser: G,
) -> impl FnMut(I) -> IResult<I, O2, E>
where
F: Parser<I, O1, E>,
G: Parser<O1, O2, E>,
{
move |input: I| {
- let (input, o1) = first.parse(input)?;
- let (_, o2) = second.parse(o1)?;
+ let (input, o1) = parser.parse(input)?;
+ let (_, o2) = applied_parser.parse(o1)?;
Ok((input, o2))
}
}
-#[doc(hidden)]
-pub fn map_parserc<I, O1, O2, E: ParseError<I>, F, G>(
- input: I,
- first: F,
- second: G,
-) -> IResult<I, O2, E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(O1) -> IResult<O1, O2, E>,
-{
- map_parser(first, second)(input)
-}
-
/// Creates a new parser from the output of the first parser, then apply that parser over the rest of the input.
///
/// ```rust
@@ -257,8 +209,8 @@ where
/// # }
/// ```
pub fn flat_map<I, O1, O2, E: ParseError<I>, F, G, H>(
- mut first: F,
- second: G,
+ mut parser: F,
+ applied_parser: G,
) -> impl FnMut(I) -> IResult<I, O2, E>
where
F: Parser<I, O1, E>,
@@ -266,8 +218,8 @@ where
H: Parser<I, O2, E>,
{
move |input: I| {
- let (input, o1) = first.parse(input)?;
- second(o1).parse(input)
+ let (input, o1) = parser.parse(input)?;
+ applied_parser(o1).parse(input)
}
}
@@ -302,14 +254,6 @@ where
}
}
-#[doc(hidden)]
-pub fn optc<I: Clone, O, E: ParseError<I>, F>(input: I, f: F) -> IResult<I, Option<O>, E>
-where
- F: Fn(I) -> IResult<I, O, E>,
-{
- opt(f)(input)
-}
-
/// Calls the parser if the condition is met.
///
/// ```rust
@@ -348,14 +292,6 @@ where
}
}
-#[doc(hidden)]
-pub fn condc<I, O, E: ParseError<I>, F>(input: I, b: bool, f: F) -> IResult<I, Option<O>, E>
-where
- F: Fn(I) -> IResult<I, O, E>,
-{
- cond(b, f)(input)
-}
-
/// Tries to apply its parser without consuming the input.
///
/// ```rust
@@ -384,14 +320,6 @@ where
}
}
-#[doc(hidden)]
-pub fn peekc<I: Clone, O, E: ParseError<I>, F>(input: I, f: F) -> IResult<I, O, E>
-where
- F: Fn(I) -> IResult<I, O, E>,
-{
- peek(f)(input)
-}
-
/// returns its input if it is at the end of input data
///
/// When we're at the end of the data, this combinator
@@ -446,14 +374,6 @@ where
}
}
-#[doc(hidden)]
-pub fn completec<I: Clone, O, E: ParseError<I>, F>(input: I, f: F) -> IResult<I, O, E>
-where
- F: Fn(I) -> IResult<I, O, E>,
-{
- complete(f)(input)
-}
-
/// Succeeds if all the input has been consumed by its child parser.
///
/// ```rust
@@ -526,21 +446,6 @@ where
}
}
-#[doc(hidden)]
-pub fn verifyc<I: Clone, O1, O2, E: ParseError<I>, F, G>(
- input: I,
- first: F,
- second: G,
-) -> IResult<I, O1, E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(&O2) -> bool,
- O1: Borrow<O2>,
- O2: ?Sized,
-{
- verify(first, second)(input)
-}
-
/// Returns the provided value if the child parser succeeds.
///
/// ```rust
@@ -566,18 +471,6 @@ where
move |input: I| parser.parse(input).map(|(i, _)| (i, val.clone()))
}
-#[doc(hidden)]
-pub fn valuec<I, O1: Clone, O2, E: ParseError<I>, F>(
- input: I,
- val: O1,
- parser: F,
-) -> IResult<I, O1, E>
-where
- F: Fn(I) -> IResult<I, O2, E>,
-{
- value(val, parser)(input)
-}
-
/// Succeeds if the child parser returns an error.
///
/// ```rust
@@ -607,14 +500,6 @@ where
}
}
-#[doc(hidden)]
-pub fn notc<I: Clone, O, E: ParseError<I>, F>(input: I, parser: F) -> IResult<I, (), E>
-where
- F: Fn(I) -> IResult<I, O, E>,
-{
- not(parser)(input)
-}
-
/// If the child parser was successful, return the consumed input as produced value.
///
/// ```rust
@@ -649,17 +534,6 @@ where
}
}
-#[doc(hidden)]
-pub fn recognizec<I: Clone + Offset + Slice<RangeTo<usize>>, O, E: ParseError<I>, F>(
- input: I,
- parser: F,
-) -> IResult<I, I, E>
-where
- F: Fn(I) -> IResult<I, O, E>,
-{
- recognize(parser)(input)
-}
-
/// if the child parser was successful, return the consumed input with the output
/// as a tuple. Functions similarly to [recognize](fn.recognize.html) except it
/// returns the parser output as well.
@@ -717,16 +591,6 @@ where
}
}
-#[doc(hidden)]
-pub fn consumedc<I, O, E: ParseError<I>, F>(input: I, parser: F) -> IResult<I, (I, O), E>
-where
- I: Clone + Offset + Slice<RangeTo<usize>>,
- E: ParseError<E>,
- F: Fn(I) -> IResult<I, O, E>,
-{
- consumed(parser)(input)
-}
-
/// transforms an error to failure
///
/// ```rust
@@ -752,14 +616,6 @@ where
}
}
-#[doc(hidden)]
-pub fn cutc<I, O, E: ParseError<I>, F>(input: I, parser: F) -> IResult<I, O, E>
-where
- F: Fn(I) -> IResult<I, O, E>,
-{
- cut(parser)(input)
-}
-
/// automatically converts the child parser's result to another type
///
/// it will be able to convert the output value and the error value
@@ -800,18 +656,6 @@ where
}
}
-#[doc(hidden)]
-pub fn intoc<I, O1, O2, E1, E2, F>(input: I, parser: F) -> IResult<I, O2, E2>
-where
- O1: Into<O2>,
- E1: Into<E2>,
- E1: ParseError<I>,
- E2: ParseError<I>,
- F: Parser<I, O1, E1>,
-{
- into(parser)(input)
-}
-
/// Creates an iterator from input data and a parser.
///
/// Call the iterator's [ParserIterator::finish] method to get the remaining input if successful,
@@ -929,208 +773,15 @@ pub fn success<I, O: Clone, E: ParseError<I>>(val: O) -> impl Fn(I) -> IResult<I
move |input: I| Ok((input, val.clone()))
}
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::bytes::complete::take;
- use crate::error::ParseError;
- use crate::internal::{Err, IResult, Needed};
- use crate::number::complete::u8;
-
- macro_rules! assert_parse(
- ($left: expr, $right: expr) => {
- let res: $crate::IResult<_, _, (_, ErrorKind)> = $left;
- assert_eq!(res, $right);
- };
- );
-
- /*#[test]
- fn t1() {
- let v1:Vec<u8> = vec![1,2,3];
- let v2:Vec<u8> = vec![4,5,6];
- let d = Ok((&v1[..], &v2[..]));
- let res = d.flat_map(print);
- assert_eq!(res, Ok((&v2[..], ())));
- }*/
-
- #[test]
- fn eof_on_slices() {
- let not_over: &[u8] = &b"Hello, world!"[..];
- let is_over: &[u8] = &b""[..];
-
- let res_not_over = eof(not_over);
- assert_parse!(
- res_not_over,
- Err(Err::Error(error_position!(not_over, ErrorKind::Eof)))
- );
-
- let res_over = eof(is_over);
- assert_parse!(res_over, Ok((is_over, is_over)));
- }
-
- #[test]
- fn eof_on_strs() {
- let not_over: &str = "Hello, world!";
- let is_over: &str = "";
-
- let res_not_over = eof(not_over);
- assert_parse!(
- res_not_over,
- Err(Err::Error(error_position!(not_over, ErrorKind::Eof)))
- );
-
- let res_over = eof(is_over);
- assert_parse!(res_over, Ok((is_over, is_over)));
- }
-
- /*
- #[test]
- fn end_of_input() {
- let not_over = &b"Hello, world!"[..];
- let is_over = &b""[..];
- named!(eof_test, eof!());
-
- let res_not_over = eof_test(not_over);
- assert_eq!(res_not_over, Err(Err::Error(error_position!(not_over, ErrorKind::Eof))));
-
- let res_over = eof_test(is_over);
- assert_eq!(res_over, Ok((is_over, is_over)));
- }
- */
-
- #[test]
- fn rest_on_slices() {
- let input: &[u8] = &b"Hello, world!"[..];
- let empty: &[u8] = &b""[..];
- assert_parse!(rest(input), Ok((empty, input)));
- }
-
- #[test]
- fn rest_on_strs() {
- let input: &str = "Hello, world!";
- let empty: &str = "";
- assert_parse!(rest(input), Ok((empty, input)));
- }
-
- #[test]
- fn rest_len_on_slices() {
- let input: &[u8] = &b"Hello, world!"[..];
- assert_parse!(rest_len(input), Ok((input, input.len())));
- }
-
- use crate::lib::std::convert::From;
- impl From<u32> for CustomError {
- fn from(_: u32) -> Self {
- CustomError
- }
- }
-
- impl<I> ParseError<I> for CustomError {
- fn from_error_kind(_: I, _: ErrorKind) -> Self {
- CustomError
- }
-
- fn append(_: I, _: ErrorKind, _: CustomError) -> Self {
- CustomError
- }
- }
-
- struct CustomError;
- #[allow(dead_code)]
- fn custom_error(input: &[u8]) -> IResult<&[u8], &[u8], CustomError> {
- //fix_error!(input, CustomError, alphanumeric)
- crate::character::streaming::alphanumeric1(input)
- }
-
- #[test]
- fn test_flat_map() {
- let input: &[u8] = &[3, 100, 101, 102, 103, 104][..];
- assert_parse!(
- flat_map(u8, take)(input),
- Ok((&[103, 104][..], &[100, 101, 102][..]))
- );
- }
-
- #[test]
- fn test_map_opt() {
- let input: &[u8] = &[50][..];
- assert_parse!(
- map_opt(u8, |u| if u < 20 { Some(u) } else { None })(input),
- Err(Err::Error((&[50][..], ErrorKind::MapOpt)))
- );
- assert_parse!(
- map_opt(u8, |u| if u > 20 { Some(u) } else { None })(input),
- Ok((&[][..], 50))
- );
- }
-
- #[test]
- fn test_map_parser() {
- let input: &[u8] = &[100, 101, 102, 103, 104][..];
- assert_parse!(
- map_parser(take(4usize), take(2usize))(input),
- Ok((&[104][..], &[100, 101][..]))
- );
- }
-
- #[test]
- fn test_all_consuming() {
- let input: &[u8] = &[100, 101, 102][..];
- assert_parse!(
- all_consuming(take(2usize))(input),
- Err(Err::Error((&[102][..], ErrorKind::Eof)))
- );
- assert_parse!(
- all_consuming(take(3usize))(input),
- Ok((&[][..], &[100, 101, 102][..]))
- );
- }
-
- #[test]
- #[allow(unused)]
- fn test_verify_ref() {
- use crate::bytes::complete::take;
-
- let mut parser1 = verify(take(3u8), |s: &[u8]| s == &b"abc"[..]);
-
- assert_eq!(parser1(&b"abcd"[..]), Ok((&b"d"[..], &b"abc"[..])));
- assert_eq!(
- parser1(&b"defg"[..]),
- Err(Err::Error((&b"defg"[..], ErrorKind::Verify)))
- );
-
- fn parser2(i: &[u8]) -> IResult<&[u8], u32> {
- verify(crate::number::streaming::be_u32, |val: &u32| *val < 3)(i)
- }
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn test_verify_alloc() {
- use crate::bytes::complete::take;
- let mut parser1 = verify(map(take(3u8), |s: &[u8]| s.to_vec()), |s: &[u8]| {
- s == &b"abc"[..]
- });
-
- assert_eq!(parser1(&b"abcd"[..]), Ok((&b"d"[..], (&b"abc").to_vec())));
- assert_eq!(
- parser1(&b"defg"[..]),
- Err(Err::Error((&b"defg"[..], ErrorKind::Verify)))
- );
- }
-
- #[test]
- #[cfg(feature = "std")]
- fn test_into() {
- use crate::bytes::complete::take;
- use crate::{
- error::{Error, ParseError},
- Err,
- };
-
- let mut parser = into(take::<_, _, Error<_>>(3u8));
- let result: IResult<&[u8], Vec<u8>> = parser(&b"abcdefg"[..]);
-
- assert_eq!(result, Ok((&b"defg"[..], vec![97, 98, 99])));
- }
+/// A parser which always fails.
+///
+/// ```rust
+/// # use nom::{Err, error::ErrorKind, IResult};
+/// use nom::combinator::fail;
+///
+/// let s = "string";
+/// assert_eq!(fail::<_, &str, _>(s), Err(Err::Error((s, ErrorKind::Fail))));
+/// ```
+pub fn fail<I, O, E: ParseError<I>>(i: I) -> IResult<I, O, E> {
+ Err(Err::Error(E::from_error_kind(i, ErrorKind::Fail)))
}
diff --git a/src/combinator/tests.rs b/src/combinator/tests.rs
new file mode 100644
index 0000000..15d32b8
--- /dev/null
+++ b/src/combinator/tests.rs
@@ -0,0 +1,275 @@
+use super::*;
+use crate::bytes::complete::take;
+use crate::bytes::streaming::tag;
+use crate::error::ErrorKind;
+use crate::error::ParseError;
+use crate::internal::{Err, IResult, Needed};
+#[cfg(feature = "alloc")]
+use crate::lib::std::boxed::Box;
+use crate::number::complete::u8;
+
+macro_rules! assert_parse(
+ ($left: expr, $right: expr) => {
+ let res: $crate::IResult<_, _, (_, ErrorKind)> = $left;
+ assert_eq!(res, $right);
+ };
+);
+
+/*#[test]
+fn t1() {
+ let v1:Vec<u8> = vec![1,2,3];
+ let v2:Vec<u8> = vec![4,5,6];
+ let d = Ok((&v1[..], &v2[..]));
+ let res = d.flat_map(print);
+ assert_eq!(res, Ok((&v2[..], ())));
+}*/
+
+#[test]
+fn eof_on_slices() {
+ let not_over: &[u8] = &b"Hello, world!"[..];
+ let is_over: &[u8] = &b""[..];
+
+ let res_not_over = eof(not_over);
+ assert_parse!(
+ res_not_over,
+ Err(Err::Error(error_position!(not_over, ErrorKind::Eof)))
+ );
+
+ let res_over = eof(is_over);
+ assert_parse!(res_over, Ok((is_over, is_over)));
+}
+
+#[test]
+fn eof_on_strs() {
+ let not_over: &str = "Hello, world!";
+ let is_over: &str = "";
+
+ let res_not_over = eof(not_over);
+ assert_parse!(
+ res_not_over,
+ Err(Err::Error(error_position!(not_over, ErrorKind::Eof)))
+ );
+
+ let res_over = eof(is_over);
+ assert_parse!(res_over, Ok((is_over, is_over)));
+}
+
+/*
+#[test]
+fn end_of_input() {
+ let not_over = &b"Hello, world!"[..];
+ let is_over = &b""[..];
+ named!(eof_test, eof!());
+
+ let res_not_over = eof_test(not_over);
+ assert_eq!(res_not_over, Err(Err::Error(error_position!(not_over, ErrorKind::Eof))));
+
+ let res_over = eof_test(is_over);
+ assert_eq!(res_over, Ok((is_over, is_over)));
+}
+*/
+
+#[test]
+fn rest_on_slices() {
+ let input: &[u8] = &b"Hello, world!"[..];
+ let empty: &[u8] = &b""[..];
+ assert_parse!(rest(input), Ok((empty, input)));
+}
+
+#[test]
+fn rest_on_strs() {
+ let input: &str = "Hello, world!";
+ let empty: &str = "";
+ assert_parse!(rest(input), Ok((empty, input)));
+}
+
+#[test]
+fn rest_len_on_slices() {
+ let input: &[u8] = &b"Hello, world!"[..];
+ assert_parse!(rest_len(input), Ok((input, input.len())));
+}
+
+use crate::lib::std::convert::From;
+impl From<u32> for CustomError {
+ fn from(_: u32) -> Self {
+ CustomError
+ }
+}
+
+impl<I> ParseError<I> for CustomError {
+ fn from_error_kind(_: I, _: ErrorKind) -> Self {
+ CustomError
+ }
+
+ fn append(_: I, _: ErrorKind, _: CustomError) -> Self {
+ CustomError
+ }
+}
+
+struct CustomError;
+#[allow(dead_code)]
+fn custom_error(input: &[u8]) -> IResult<&[u8], &[u8], CustomError> {
+ //fix_error!(input, CustomError, alphanumeric)
+ crate::character::streaming::alphanumeric1(input)
+}
+
+#[test]
+fn test_flat_map() {
+ let input: &[u8] = &[3, 100, 101, 102, 103, 104][..];
+ assert_parse!(
+ flat_map(u8, take)(input),
+ Ok((&[103, 104][..], &[100, 101, 102][..]))
+ );
+}
+
+#[test]
+fn test_map_opt() {
+ let input: &[u8] = &[50][..];
+ assert_parse!(
+ map_opt(u8, |u| if u < 20 { Some(u) } else { None })(input),
+ Err(Err::Error((&[50][..], ErrorKind::MapOpt)))
+ );
+ assert_parse!(
+ map_opt(u8, |u| if u > 20 { Some(u) } else { None })(input),
+ Ok((&[][..], 50))
+ );
+}
+
+#[test]
+fn test_map_parser() {
+ let input: &[u8] = &[100, 101, 102, 103, 104][..];
+ assert_parse!(
+ map_parser(take(4usize), take(2usize))(input),
+ Ok((&[104][..], &[100, 101][..]))
+ );
+}
+
+#[test]
+fn test_all_consuming() {
+ let input: &[u8] = &[100, 101, 102][..];
+ assert_parse!(
+ all_consuming(take(2usize))(input),
+ Err(Err::Error((&[102][..], ErrorKind::Eof)))
+ );
+ assert_parse!(
+ all_consuming(take(3usize))(input),
+ Ok((&[][..], &[100, 101, 102][..]))
+ );
+}
+
+#[test]
+#[allow(unused)]
+fn test_verify_ref() {
+ use crate::bytes::complete::take;
+
+ let mut parser1 = verify(take(3u8), |s: &[u8]| s == &b"abc"[..]);
+
+ assert_eq!(parser1(&b"abcd"[..]), Ok((&b"d"[..], &b"abc"[..])));
+ assert_eq!(
+ parser1(&b"defg"[..]),
+ Err(Err::Error((&b"defg"[..], ErrorKind::Verify)))
+ );
+
+ fn parser2(i: &[u8]) -> IResult<&[u8], u32> {
+ verify(crate::number::streaming::be_u32, |val: &u32| *val < 3)(i)
+ }
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn test_verify_alloc() {
+ use crate::bytes::complete::take;
+ let mut parser1 = verify(map(take(3u8), |s: &[u8]| s.to_vec()), |s: &[u8]| {
+ s == &b"abc"[..]
+ });
+
+ assert_eq!(parser1(&b"abcd"[..]), Ok((&b"d"[..], (&b"abc").to_vec())));
+ assert_eq!(
+ parser1(&b"defg"[..]),
+ Err(Err::Error((&b"defg"[..], ErrorKind::Verify)))
+ );
+}
+
+#[test]
+#[cfg(feature = "std")]
+fn test_into() {
+ use crate::bytes::complete::take;
+ use crate::{
+ error::{Error, ParseError},
+ Err,
+ };
+
+ let mut parser = into(take::<_, _, Error<_>>(3u8));
+ let result: IResult<&[u8], Vec<u8>> = parser(&b"abcdefg"[..]);
+
+ assert_eq!(result, Ok((&b"defg"[..], vec![97, 98, 99])));
+}
+
+#[test]
+fn opt_test() {
+ fn opt_abcd(i: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
+ opt(tag("abcd"))(i)
+ }
+
+ let a = &b"abcdef"[..];
+ let b = &b"bcdefg"[..];
+ let c = &b"ab"[..];
+ assert_eq!(opt_abcd(a), Ok((&b"ef"[..], Some(&b"abcd"[..]))));
+ assert_eq!(opt_abcd(b), Ok((&b"bcdefg"[..], None)));
+ assert_eq!(opt_abcd(c), Err(Err::Incomplete(Needed::new(2))));
+}
+
+#[test]
+fn peek_test() {
+ fn peek_tag(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ peek(tag("abcd"))(i)
+ }
+
+ assert_eq!(peek_tag(&b"abcdef"[..]), Ok((&b"abcdef"[..], &b"abcd"[..])));
+ assert_eq!(peek_tag(&b"ab"[..]), Err(Err::Incomplete(Needed::new(2))));
+ assert_eq!(
+ peek_tag(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn not_test() {
+ fn not_aaa(i: &[u8]) -> IResult<&[u8], ()> {
+ not(tag("aaa"))(i)
+ }
+
+ assert_eq!(
+ not_aaa(&b"aaa"[..]),
+ Err(Err::Error(error_position!(&b"aaa"[..], ErrorKind::Not)))
+ );
+ assert_eq!(not_aaa(&b"aa"[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(not_aaa(&b"abcd"[..]), Ok((&b"abcd"[..], ())));
+}
+
+#[test]
+fn verify_test() {
+ use crate::bytes::streaming::take;
+
+ fn test(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ verify(take(5u8), |slice: &[u8]| slice[0] == b'a')(i)
+ }
+ assert_eq!(test(&b"bcd"[..]), Err(Err::Incomplete(Needed::new(2))));
+ assert_eq!(
+ test(&b"bcdefg"[..]),
+ Err(Err::Error(error_position!(
+ &b"bcdefg"[..],
+ ErrorKind::Verify
+ )))
+ );
+ assert_eq!(test(&b"abcdefg"[..]), Ok((&b"fg"[..], &b"abcde"[..])));
+}
+
+#[test]
+fn fail_test() {
+ let a = "string";
+ let b = "another string";
+
+ assert_eq!(fail::<_, &str, _>(a), Err(Err::Error((a, ErrorKind::Fail))));
+ assert_eq!(fail::<_, &str, _>(b), Err(Err::Error((b, ErrorKind::Fail))));
+}
diff --git a/src/error.rs b/src/error.rs
index a5aa678..498b5e1 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -28,7 +28,7 @@ pub trait ParseError<I>: Sized {
}
/// Combines two existing errors. This function is used to compare errors
- /// generated in various branches of [alt]
+ /// generated in various branches of `alt`.
fn or(self, other: Self) -> Self {
other
}
@@ -45,7 +45,7 @@ pub trait ContextError<I>: Sized {
}
}
-/// This trait is required by the [map_res] combinator to integrate
+/// This trait is required by the `map_res` combinator to integrate
/// error types from external functions, like [std::str::FromStr]
pub trait FromExternalError<I, E> {
/// Creates a new error from an input position, an [ErrorKind] indicating the
@@ -411,12 +411,12 @@ pub enum ErrorKind {
Verify,
TakeTill1,
TakeWhileMN,
- ParseTo,
TooLarge,
Many0Count,
Many1Count,
Float,
Satisfy,
+ Fail,
}
#[rustfmt::skip]
@@ -471,12 +471,12 @@ pub fn error_to_u32(e: &ErrorKind) -> u32 {
ErrorKind::Verify => 66,
ErrorKind::TakeTill1 => 67,
ErrorKind::TakeWhileMN => 69,
- ErrorKind::ParseTo => 70,
- ErrorKind::TooLarge => 71,
- ErrorKind::Many0Count => 72,
- ErrorKind::Many1Count => 73,
- ErrorKind::Float => 74,
- ErrorKind::Satisfy => 75,
+ ErrorKind::TooLarge => 70,
+ ErrorKind::Many0Count => 71,
+ ErrorKind::Many1Count => 72,
+ ErrorKind::Float => 73,
+ ErrorKind::Satisfy => 74,
+ ErrorKind::Fail => 75,
}
}
@@ -533,12 +533,12 @@ impl ErrorKind {
ErrorKind::Verify => "predicate verification",
ErrorKind::TakeTill1 => "TakeTill1",
ErrorKind::TakeWhileMN => "TakeWhileMN",
- ErrorKind::ParseTo => "Parse string to the specified type",
ErrorKind::TooLarge => "Needed data size is too large",
ErrorKind::Many0Count => "Count occurrence of >=0 patterns",
ErrorKind::Many1Count => "Count occurrence of >=1 patterns",
ErrorKind::Float => "Float",
ErrorKind::Satisfy => "Satisfy",
+ ErrorKind::Fail => "Fail",
}
}
}
@@ -564,103 +564,45 @@ macro_rules! error_node_position(
});
);
-//FIXME: error rewrite
-/// translate parser result from IResult<I,O,u32> to IResult<I,O,E> with a custom type
+/// Prints a message and the input if the parser fails.
///
-/// ```
-/// # //FIXME
-/// # #[macro_use] extern crate nom;
-/// # use nom::IResult;
-/// # use std::convert::From;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// # /*
-/// # // will add a Custom(42) error to the error chain
-/// # named!(err_test, add_return_error!(ErrorKind::Custom(42u32), tag!("abcd")));
-/// #
-/// # #[derive(Debug,Clone,PartialEq)]
-/// # pub struct ErrorStr(String);
-/// #
-/// # // Convert to IResult<&[u8], &[u8], ErrorStr>
-/// # impl From<u32> for ErrorStr {
-/// # fn from(i: u32) -> Self {
-/// # ErrorStr(format!("custom error code: {}", i))
-/// # }
-/// # }
-/// #
-/// # named!(parser<&[u8], &[u8], ErrorStr>,
-/// # fix_error!(ErrorStr, err_test)
-/// # );
-/// #
-/// # let a = &b"efghblah"[..];
-/// # assert_eq!(parser(a), Err(Err::Error(Context::Code(a, ErrorKind::Custom(ErrorStr("custom error code: 42".to_string()))))));
-/// # */
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! fix_error (
- ($i:expr, $t:ty, $submac:ident!( $($args:tt)* )) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::Err;
-
- match $submac!($i, $($args)*) {
- Ok((i,o)) => Ok((i,o)),
- Err(e) => {
- let e2 = match e {
- Err::Error(err) => {
- Err::Error(err.into())
- },
- Err::Failure(err) => {
- Err::Failure(err.into())
- },
- Err::Incomplete(e) => Err::Incomplete(e),
- };
- Err(e2)
- }
- }
- }
- );
- ($i:expr, $t:ty, $f:expr) => (
- fix_error!($i, $t, call!($f));
- );
-);
-
-/// `flat_map!(R -> IResult<R,S>, S -> IResult<S,T>) => R -> IResult<R, T>`
+/// The message prints the `Error` or `Incomplete`
+/// and the parser's calling code.
///
-/// Combines a parser `R -> IResult<R,S>` and
-/// a parser `S -> IResult<S,T>` to return another
-/// parser `R -> IResult<R,T>`
+/// It also displays the input in hexdump format
///
/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, error::{Error, ErrorKind}};
-/// use nom::number::complete::recognize_float;
+/// use nom::{IResult, error::dbg_dmp, bytes::complete::tag};
+///
+/// fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
+/// dbg_dmp(tag("abcd"), "tag")(i)
+/// }
///
-/// named!(parser<&str, f64>, flat_map!(recognize_float, parse_to!(f64)));
+/// let a = &b"efghijkl"[..];
///
-/// assert_eq!(parser("123.45;"), Ok((";", 123.45)));
-/// assert_eq!(parser("abc"), Err(Err::Error(Error::new("abc", ErrorKind::Char))));
+/// // Will print the following message:
+/// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) '
+/// // 00000000 65 66 67 68 69 6a 6b 6c efghijkl
+/// f(a);
/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! flat_map(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- flat_map!(__impl $i, $submac!($($args)*), $submac2!($($args2)*));
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- flat_map!(__impl $i, $submac!($($args)*), call!($g));
- );
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- flat_map!(__impl $i, call!($f), $submac!($($args)*));
- );
- ($i:expr, $f:expr, $g:expr) => (
- flat_map!(__impl $i, call!($f), call!($g));
- );
- (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- $crate::combinator::map_parserc($i, move |i| {$submac!(i, $($args)*)}, move |i| {$submac2!(i, $($args2)*)})
- );
-);
+#[cfg(feature = "std")]
+#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
+pub fn dbg_dmp<'a, F, O, E: std::fmt::Debug>(
+ f: F,
+ context: &'static str,
+) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E>
+where
+ F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
+{
+ use crate::HexDisplay;
+ move |i: &'a [u8]| match f(i) {
+ Err(e) => {
+ println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8));
+ Err(e)
+ }
+ a => a,
+ }
+}
#[cfg(test)]
#[cfg(feature = "alloc")]
diff --git a/src/internal.rs b/src/internal.rs
index fd683c0..762f3d8 100644
--- a/src/internal.rs
+++ b/src/internal.rs
@@ -46,7 +46,7 @@ impl<I, O, E> Finish<I, O, E> for IResult<I, O, E> {
/// Contains information on needed data if a parser returned `Incomplete`
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub enum Needed {
/// Needs more data, but we do not know how much
Unknown,
@@ -93,7 +93,7 @@ impl Needed {
/// to try other parsers, you were already in the right branch, so the data is invalid
///
#[derive(Debug, Clone, PartialEq)]
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub enum Err<E> {
/// There was not enough data
Incomplete(Needed),
@@ -150,6 +150,26 @@ impl<T> Err<(T, ErrorKind)> {
}
}
+impl<T> Err<error::Error<T>> {
+ /// Maps `Err<error::Error<T>>` to `Err<error::Error<U>>` with the given `F: T -> U`
+ pub fn map_input<U, F>(self, f: F) -> Err<error::Error<U>>
+ where
+ F: FnOnce(T) -> U,
+ {
+ match self {
+ Err::Incomplete(n) => Err::Incomplete(n),
+ Err::Failure(error::Error { input, code }) => Err::Failure(error::Error {
+ input: f(input),
+ code,
+ }),
+ Err::Error(error::Error { input, code }) => Err::Error(error::Error {
+ input: f(input),
+ code,
+ }),
+ }
+ }
+}
+
#[cfg(feature = "alloc")]
use crate::lib::std::{borrow::ToOwned, string::String, vec::Vec};
#[cfg(feature = "alloc")]
@@ -163,20 +183,38 @@ impl Err<(&[u8], ErrorKind)> {
#[cfg(feature = "alloc")]
impl Err<(&str, ErrorKind)> {
- /// Automatically converts between errors if the underlying type supports it
+ /// Obtaining ownership
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
pub fn to_owned(self) -> Err<(String, ErrorKind)> {
self.map_input(ToOwned::to_owned)
}
}
+#[cfg(feature = "alloc")]
+impl Err<error::Error<&[u8]>> {
+ /// Obtaining ownership
+ #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
+ pub fn to_owned(self) -> Err<error::Error<Vec<u8>>> {
+ self.map_input(ToOwned::to_owned)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl Err<error::Error<&str>> {
+ /// Obtaining ownership
+ #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
+ pub fn to_owned(self) -> Err<error::Error<String>> {
+ self.map_input(ToOwned::to_owned)
+ }
+}
+
impl<E: Eq> Eq for Err<E> {}
impl<E> fmt::Display for Err<E>
where
E: fmt::Debug,
{
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Err::Incomplete(Needed::Size(u)) => write!(f, "Parsing requires {} bytes/chars", u),
Err::Incomplete(Needed::Unknown) => write!(f, "Parsing requires more data"),
@@ -299,7 +337,7 @@ impl<'a, I, O, E> Parser<I, O, E> for Box<dyn Parser<I, O, E> + 'a> {
}
/// Implementation of `Parser::map`
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub struct Map<F, G, O1> {
f: F,
g: G,
@@ -316,7 +354,7 @@ impl<'a, I, O1, O2, E, F: Parser<I, O1, E>, G: Fn(O1) -> O2> Parser<I, O2, E> fo
}
/// Implementation of `Parser::flat_map`
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub struct FlatMap<F, G, O1> {
f: F,
g: G,
@@ -333,7 +371,7 @@ impl<'a, I, O1, O2, E, F: Parser<I, O1, E>, G: Fn(O1) -> H, H: Parser<I, O2, E>>
}
/// Implementation of `Parser::and_then`
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub struct AndThen<F, G, O1> {
f: F,
g: G,
@@ -351,7 +389,7 @@ impl<'a, I, O1, O2, E, F: Parser<I, O1, E>, G: Parser<O1, O2, E>> Parser<I, O2,
}
/// Implementation of `Parser::and`
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub struct And<F, G> {
f: F,
g: G,
@@ -368,7 +406,7 @@ impl<'a, I, O1, O2, E, F: Parser<I, O1, E>, G: Parser<I, O2, E>> Parser<I, (O1,
}
/// Implementation of `Parser::or`
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub struct Or<F, G> {
f: F,
g: G,
@@ -389,7 +427,7 @@ impl<'a, I: Clone, O, E: crate::error::ParseError<I>, F: Parser<I, O, E>, G: Par
}
/// Implementation of `Parser::into`
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub struct Into<F, O1, O2: From<O1>, E1, E2: From<E1>> {
f: F,
phantom_out1: core::marker::PhantomData<O1>,
diff --git a/src/lib.rs b/src/lib.rs
index c0eeb5d..98cd585 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,8 +6,6 @@
//! ## Example
//!
//! ```rust
-//! extern crate nom;
-//!
//! use nom::{
//! IResult,
//! bytes::complete::{tag, take_while_m_n},
@@ -55,8 +53,7 @@
//! The code is available on [Github](https://github.com/Geal/nom)
//!
//! There are a few [guides](https://github.com/Geal/nom/tree/master/doc) with more details
-//! about [the design of nom macros](https://github.com/Geal/nom/blob/master/doc/how_nom_macros_work.md),
-//! [how to write parsers](https://github.com/Geal/nom/blob/master/doc/making_a_new_parser_from_scratch.md),
+//! about [how to write parsers](https://github.com/Geal/nom/blob/master/doc/making_a_new_parser_from_scratch.md),
//! or the [error management system](https://github.com/Geal/nom/blob/master/doc/error_management.md).
//! You can also check out the [recipes] module that contains examples of common patterns.
//!
@@ -66,8 +63,6 @@
//! If you are upgrading to nom 5.0, please read the
//! [migration document](https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_5.md).
//!
-//! See also the [FAQ](https://github.com/Geal/nom/blob/master/doc/FAQ.md).
-//!
//! ## Parser combinators
//!
//! Parser combinators are an approach to parsers that is very different from
@@ -111,9 +106,6 @@
//! Here is another parser, written without using nom's combinators this time:
//!
//! ```rust
-//! #[macro_use]
-//! extern crate nom;
-//!
//! use nom::{IResult, Err, Needed};
//!
//! # fn main() {
@@ -130,7 +122,7 @@
//! This function takes a byte array as input, and tries to consume 4 bytes.
//! Writing all the parsers manually, like this, is dangerous, despite Rust's
//! safety features. There are still a lot of mistakes one can make. That's why
-//! nom provides a list of function and macros to help in developing parsers.
+//! nom provides a list of functions to help in developing parsers.
//!
//! With functions, you would write it like this:
//!
@@ -141,24 +133,6 @@
//! }
//! ```
//!
-//! With macros, you would write it like this:
-//!
-//! ```rust
-//! #[macro_use]
-//! extern crate nom;
-//!
-//! # fn main() {
-//! named!(take4, take!(4));
-//! # }
-//! ```
-//!
-//! nom has used macros for combinators from versions 1 to 4, and from version
-//! 5, it proposes new combinators as functions, but still allows the macros style
-//! (macros have been rewritten to use the functions under the hood).
-//! For new parsers, we recommend using the functions instead of macros, since
-//! rustc messages will be much easier to understand.
-//!
-//!
//! A parser in nom is a function which, for an input type `I`, an output type `O`
//! and an optional error type `E`, will have the following signature:
//!
@@ -253,7 +227,6 @@
//! **`many0`** applies a parser 0 or more times, and returns a vector of the aggregated results:
//!
//! ```rust
-//! # #[macro_use] extern crate nom;
//! # #[cfg(feature = "alloc")]
//! # fn main() {
//! use nom::{IResult, multi::many0, bytes::complete::tag};
@@ -274,7 +247,7 @@
//! # fn main() {}
//! ```
//!
-//! Here are some basic combining macros available:
+//! Here are some basic combinators available:
//!
//! - **`opt`**: Will make the parser optional (if it returns the `O` type, the new parser returns `Option<O>`)
//! - **`many0`**: Will apply the parser 0 or more times (if it returns the `O` type, the new parser returns `Vec<O>`)
@@ -286,7 +259,6 @@
//! Example with `tuple`:
//!
//! ```rust
-//! # #[macro_use] extern crate nom;
//! # fn main() {
//! use nom::{error::ErrorKind, Needed,
//! number::streaming::be_u16,
@@ -312,7 +284,6 @@
//! thanks to the `?` operator:
//!
//! ```rust
-//! # #[macro_use] extern crate nom;
//! # fn main() {
//! use nom::{IResult, bytes::complete::tag};
//!
@@ -406,20 +377,13 @@
#![cfg_attr(feature = "docsrs", feature(doc_cfg))]
#![cfg_attr(feature = "docsrs", feature(extended_key_value_attributes))]
#![deny(missing_docs)]
-#![warn(missing_doc_code_examples)]
-
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;
-#[cfg(feature = "bitvec")]
-pub extern crate bitvec;
#[cfg(doctest)]
extern crate doc_comment;
-#[cfg(feature = "lexical")]
-extern crate lexical_core;
-extern crate memchr;
-#[cfg(feature = "regexp")]
-pub extern crate regex;
+
#[cfg(nightly)]
extern crate test;
@@ -428,12 +392,12 @@ doc_comment::doctest!("../README.md");
/// Lib module to re-export everything needed from `std` or `core`/`alloc`. This is how `serde` does
/// it, albeit there it is not public.
-#[allow(missing_doc_code_examples)]
+#[cfg_attr(nightly, allow(rustdoc::missing_doc_code_examples))]
pub mod lib {
/// `std` facade allowing `std`/`core` to be interchangeable. Reexports `alloc` crate optionally,
/// as well as `core` or `std`
#[cfg(not(feature = "std"))]
- #[allow(missing_doc_code_examples)]
+ #[cfg_attr(nightly, allow(rustdoc::missing_doc_code_examples))]
/// internal std exports for no_std compatibility
pub mod std {
#[doc(hidden)]
@@ -455,7 +419,7 @@ pub mod lib {
}
#[cfg(feature = "std")]
- #[allow(missing_doc_code_examples)]
+ #[cfg_attr(nightly, allow(rustdoc::missing_doc_code_examples))]
/// internal std exports for no_std compatibility
pub mod std {
#[doc(hidden)]
@@ -470,24 +434,15 @@ pub mod lib {
pub use std::prelude as v1;
}
}
-
- #[cfg(feature = "regexp")]
- pub use regex;
}
pub use self::bits::*;
pub use self::internal::*;
pub use self::traits::*;
-pub use self::util::*;
-#[cfg(feature = "regexp")]
-pub use self::regexp::*;
pub use self::str::*;
#[macro_use]
-mod util;
-
-#[macro_use]
pub mod error;
#[macro_use]
@@ -510,11 +465,6 @@ pub mod bits;
#[macro_use]
pub mod character;
-#[cfg(feature = "regexp")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "regexp")))]
-#[macro_use]
-pub mod regexp;
-
mod str;
#[macro_use]
diff --git a/src/multi/macros.rs b/src/multi/macros.rs
deleted file mode 100644
index c03de3a..0000000
--- a/src/multi/macros.rs
+++ /dev/null
@@ -1,1079 +0,0 @@
-//! Parsers for applying parsers multiple times
-
-/// `separated_list0!(I -> IResult<I,T>, I -> IResult<I,O>) => I -> IResult<I, Vec<O>>`
-/// `separated_list0(sep, X)` returns a `Vec<X>`.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, error::ErrorKind, Needed, IResult};
-/// use nom::multi::separated_list0;
-/// use nom::bytes::complete::tag;
-///
-/// # fn main() {
-/// named!(parser<&str, Vec<&str>>, separated_list0!(tag("|"), tag("abc")));
-///
-/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"])));
-/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"])));
-/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"])));
-/// assert_eq!(parser(""), Ok(("", vec![])));
-/// assert_eq!(parser("def|abc"), Ok(("def|abc", vec![])));
-/// # }
-/// ```
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-#[macro_export(local_inner_macros)]
-macro_rules! separated_list0(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- separated_list0!($i, |i| $submac!(i, $($args)*), |i| $submac2!(i, $($args2)*))
- );
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- separated_list0!($i, |i| $submac!(i, $($args)*), $g);
- );
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- separated_list0!($i, $f, |i| $submac!(i, $($args)*));
- );
-
- ($i:expr, $f:expr, $g:expr) => (
- $crate::multi::separated_list0c($i, $f, $g)
- );
-);
-
-/// `separated_list1!(I -> IResult<I,T>, I -> IResult<I,O>) => I -> IResult<I, Vec<O>>`
-/// `separated_list1(sep, X)` returns a `Vec<X>`.
-///
-/// It will return an error if there is no element in the list.
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
-/// use nom::multi::separated_list1;
-/// use nom::bytes::complete::tag;
-///
-/// # fn main() {
-/// named!(parser<&str, Vec<&str>>, separated_list1!(tag("|"), tag("abc")));
-///
-/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"])));
-/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"])));
-/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"])));
-/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Tag))));
-/// assert_eq!(parser("def|abc"), Err(Err::Error(Error::new("def|abc", ErrorKind::Tag))));
-/// # }
-/// ```
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-#[macro_export(local_inner_macros)]
-macro_rules! separated_list1(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- separated_list1!($i, |i| $submac!(i, $($args)*), |i| $submac2!(i, $($args2)*))
- );
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- separated_list1!($i, |i| $submac!(i, $($args)*), $g);
- );
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- separated_list1!($i, $f, |i| $submac!(i, $($args)*));
- );
-
- ($i:expr, $f:expr, $g:expr) => (
- $crate::multi::separated_list1c($i, $f, $g)
- );
-);
-
-/// `many0!(I -> IResult<I,O>) => I -> IResult<I, Vec<O>>`
-/// Applies the parser 0 or more times and returns the list of results in a `Vec`.
-///
-/// The embedded parser may return `Incomplete`.
-///
-/// `many0` will only return `Error` if the embedded parser does not consume any input
-/// (to avoid infinite loops).
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(multi<&[u8], Vec<&[u8]> >, many0!( tag!( "abcd" ) ) );
-///
-/// let a = b"abcdabcdefgh";
-/// let b = b"azerty";
-///
-/// let res = vec![&b"abcd"[..], &b"abcd"[..]];
-/// assert_eq!(multi(&a[..]),Ok((&b"efgh"[..], res)));
-/// assert_eq!(multi(&b[..]),Ok((&b"azerty"[..], Vec::new())));
-/// # }
-/// ```
-///
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-#[macro_export(local_inner_macros)]
-macro_rules! many0(
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- many0!($i, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $f:expr) => (
- $crate::multi::many0c($i, $f)
- );
-);
-
-/// `many1!(I -> IResult<I,O>) => I -> IResult<I, Vec<O>>`
-/// Applies the parser 1 or more times and returns the list of results in a `Vec`.
-///
-/// The embedded parser may return `Incomplete`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(multi<&[u8], Vec<&[u8]> >, many1!( tag!( "abcd" ) ) );
-///
-/// let a = b"abcdabcdefgh";
-/// let b = b"azerty";
-///
-/// let res = vec![&b"abcd"[..], &b"abcd"[..]];
-/// assert_eq!(multi(&a[..]), Ok((&b"efgh"[..], res)));
-/// assert_eq!(multi(&b[..]), Err(Err::Error(error_position!(&b[..], ErrorKind::Tag))));
-/// # }
-/// ```
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-#[macro_export(local_inner_macros)]
-macro_rules! many1(
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- many1!($i, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $f:expr) => (
- $crate::multi::many1c($i, $f)
- );
-);
-
-/// `many_till!(I -> IResult<I,O>, I -> IResult<I,P>) => I -> IResult<I, (Vec<O>, P)>`
-/// Applies the first parser until the second applies. Returns a tuple containing the list
-/// of results from the first in a Vec and the result of the second.
-///
-/// The first embedded parser may return `Incomplete`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(multi<&[u8], (Vec<&[u8]>, &[u8]) >, many_till!( tag!( "abcd" ), tag!( "efgh" ) ) );
-///
-/// let a = b"abcdabcdefghabcd";
-/// let b = b"efghabcd";
-/// let c = b"azerty";
-///
-/// let res_a = (vec![&b"abcd"[..], &b"abcd"[..]], &b"efgh"[..]);
-/// let res_b: (Vec<&[u8]>, &[u8]) = (Vec::new(), &b"efgh"[..]);
-/// assert_eq!(multi(&a[..]),Ok((&b"abcd"[..], res_a)));
-/// assert_eq!(multi(&b[..]),Ok((&b"abcd"[..], res_b)));
-/// assert_eq!(multi(&c[..]), Err(Err::Error(error_node_position!(&c[..], ErrorKind::ManyTill,
-/// error_position!(&c[..], ErrorKind::Tag)))));
-/// # }
-/// ```
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-#[macro_export(local_inner_macros)]
-macro_rules! many_till(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- many_till!($i, |i| $submac!(i, $($args)*), |i| $submac2!(i, $($args2)*))
- );
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- many_till!($i, |i| $submac!(i, $($args)*), $g);
- );
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- many_till!($i, $f, |i| $submac!(i, $($args)*));
- );
-
- ($i:expr, $f:expr, $g:expr) => (
- $crate::multi::many_tillc($i, $f, $g)
- );
-);
-
-/// `many_m_n!(usize, usize, I -> IResult<I,O>) => I -> IResult<I, Vec<O>>`
-/// Applies the parser between m and n times (n included) and returns the list of
-/// results in a `Vec`.
-///
-/// the embedded parser may return Incomplete
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(multi<&[u8], Vec<&[u8]> >, many_m_n!(2, 4, tag!( "abcd" ) ) );
-///
-/// let a = b"abcdefgh";
-/// let b = b"abcdabcdefgh";
-/// let c = b"abcdabcdabcdabcdabcdefgh";
-///
-/// assert_eq!(multi(&a[..]), Err(Err::Error(error_position!(&b"efgh"[..], ErrorKind::Tag))));
-/// let res = vec![&b"abcd"[..], &b"abcd"[..]];
-/// assert_eq!(multi(&b[..]),Ok((&b"efgh"[..], res)));
-/// let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]];
-/// assert_eq!(multi(&c[..]),Ok((&b"abcdefgh"[..], res2)));
-/// # }
-/// ```
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-#[macro_export(local_inner_macros)]
-macro_rules! many_m_n(
- ($i:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* )) => (
- many_m_n!($i, $m, $n, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $m:expr, $n: expr, $f:expr) => (
- $crate::multi::many_m_nc($i, $m, $n, $f)
- );
-);
-
-/// `many0_count!(I -> IResult<I,O>) => I -> IResult<I, usize>`
-/// Applies the parser 0 or more times and returns the number of times the parser was applied.
-///
-/// `many0_count` will only return `Error` if the embedded parser does not consume any input
-/// (to avoid infinite loops).
-///
-/// ```
-/// #[macro_use] extern crate nom;
-/// use nom::character::streaming::digit1;
-///
-/// named!(number<&[u8], usize>, many0_count!(pair!(digit1, tag!(","))));
-///
-/// fn main() {
-/// assert_eq!(number(&b"123,45,abc"[..]), Ok((&b"abc"[..], 2)));
-/// }
-/// ```
-///
-#[macro_export]
-macro_rules! many0_count {
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::multi::many0_countc($i, |i| $submac!(i, $($args)*))
- );
-
- ($i:expr, $f:expr) => (
- $crate::multi::many0_countc($i, $f)
- );
-}
-
-/// `many1_count!(I -> IResult<I,O>) => I -> IResult<I, usize>`
-/// Applies the parser 1 or more times and returns the number of times the parser was applied.
-///
-/// ```
-/// #[macro_use] extern crate nom;
-/// use nom::character::streaming::digit1;
-///
-/// named!(number<&[u8], usize>, many1_count!(pair!(digit1, tag!(","))));
-///
-/// fn main() {
-/// assert_eq!(number(&b"123,45,abc"[..]), Ok((&b"abc"[..], 2)));
-/// }
-/// ```
-///
-#[macro_export]
-macro_rules! many1_count {
- ($i:expr, $submac:ident!( $($args:tt)* )) => (
- $crate::multi::many1_countc($i, |i| $submac!(i, $($args)*))
- );
-
- ($i:expr, $f:expr) => (
- $crate::multi::many1_countc($i, $f)
- );
-}
-
-/// `count!(I -> IResult<I,O>, nb) => I -> IResult<I, Vec<O>>`
-/// Applies the child parser a specified number of times.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(counter< Vec<&[u8]> >, count!( tag!( "abcd" ), 2 ) );
-///
-/// let a = b"abcdabcdabcdef";
-/// let b = b"abcdefgh";
-/// let res = vec![&b"abcd"[..], &b"abcd"[..]];
-///
-/// assert_eq!(counter(&a[..]),Ok((&b"abcdef"[..], res)));
-/// assert_eq!(counter(&b[..]), Err(Err::Error(error_position!(&b"efgh"[..], ErrorKind::Tag))));
-/// # }
-/// ```
-///
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-#[macro_export(local_inner_macros)]
-macro_rules! count(
- ($i:expr, $submac:ident!( $($args:tt)* ), $count: expr) => (
- count!($i, |i| $submac!(i, $($args)*), $count)
- );
- ($i:expr, $f:expr, $count: expr) => (
- $crate::multi::count($f, $count)($i)
- );
-);
-
-/// `length_count!(I -> IResult<I, nb>, I -> IResult<I,O>) => I -> IResult<I, Vec<O>>`
-/// Gets a number from the first parser, then applies the second parser that many times.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// # use nom::error::ErrorKind;
-/// use nom::number::complete::be_u8;
-/// # fn main() {
-/// named!(parser<Vec<&[u8]>>, length_count!(be_u8, tag!("abc")));
-///
-/// assert_eq!(parser(&b"\x02abcabcabc"[..]), Ok(((&b"abc"[..], vec![&b"abc"[..], &b"abc"[..]]))));
-/// assert_eq!(parser(&b"\x04abcabcabc"[..]), Err(Err::Incomplete(Needed::new(3))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-macro_rules! length_count(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- {
- use $crate::lib::std::result::Result::*;
- use $crate::Err;
-
- match $submac!($i, $($args)*) {
- Err(e) => Err(Err::convert(e)),
- Ok((i, o)) => {
- match count!(i, $submac2!($($args2)*), o as usize) {
- Err(e) => Err(Err::convert(e)),
- Ok((i2, o2)) => Ok((i2, o2))
- }
- }
- }
- }
- );
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- length_count!($i, $submac!($($args)*), call!($g));
- );
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- length_count!($i, call!($f), $submac!($($args)*));
- );
-
- ($i:expr, $f:expr, $g:expr) => (
- length_count!($i, call!($f), call!($g));
- );
-);
-
-/// `length_data!(I -> IResult<I, nb>) => O`
-///
-/// `length_data` gets a number from the first parser, then takes a subslice of the input
-/// of that size and returns that subslice.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// # use nom::error::ErrorKind;
-/// use nom::number::complete::be_u8;
-/// # fn main() {
-/// named!(parser, length_data!(be_u8));
-///
-/// assert_eq!(parser(&b"\x06abcabcabc"[..]), Ok((&b"abc"[..], &b"abcabc"[..])));
-/// assert_eq!(parser(&b"\x06abc"[..]), Err(Err::Incomplete(Needed::new(3))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! length_data(
- ($i:expr, $submac:ident!( $($args:tt)* )) => ({
- $crate::multi::length_data(|i| $submac!(i, $($args)*))($i)
- });
-
- ($i:expr, $f:expr) => (
- $crate::multi::length_data($f)($i)
- );
-);
-
-/// `length_value!(I -> IResult<I, nb>, I -> IResult<I,O>) => I -> IResult<I, O>`
-///
-/// Gets a number from the first parser, takes a subslice of the input of that size,
-/// then applies the second parser on that subslice. If the second parser returns
-/// `Incomplete`, `length_value` will return an error.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// # use nom::error::ErrorKind;
-/// use nom::number::complete::be_u8;
-/// use nom::character::complete::alpha0;
-/// use nom::bytes::complete::tag;
-/// # fn main() {
-/// named!(parser, length_value!(be_u8, alpha0));
-///
-/// assert_eq!(parser(&b"\x06abcabcabc"[..]), Ok((&b"abc"[..], &b"abcabc"[..])));
-/// assert_eq!(parser(&b"\x06abc"[..]), Err(Err::Incomplete(Needed::new(3))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! length_value(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- length_value!($i, |i| $submac!(i, $($args)*), |i| $submac2!(i, $($args2)*))
- );
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- length_value!($i, |i| $submac!(i, $($args)*), $g);
- );
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- length_value!($i, $f, |i| $submac!(i, $($args)*));
- );
-
- ($i:expr, $f:expr, $g:expr) => (
- $crate::multi::length_valuec($i, $f, $g);
- );
-);
-
-/// `fold_many0!(I -> IResult<I,O>, R, Fn(R, O) -> R) => I -> IResult<I, R>`
-/// Applies the parser 0 or more times and folds the list of return values.
-///
-/// The embedded parser may return `Incomplete`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(multi<&[u8], Vec<&[u8]> >,
-/// fold_many0!( tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| {
-/// acc.push(item);
-/// acc
-/// }));
-///
-/// let a = b"abcdabcdefgh";
-/// let b = b"azerty";
-///
-/// let res = vec![&b"abcd"[..], &b"abcd"[..]];
-/// assert_eq!(multi(&a[..]),Ok((&b"efgh"[..], res)));
-/// assert_eq!(multi(&b[..]),Ok((&b"azerty"[..], Vec::new())));
-/// # }
-/// ```
-/// 0 or more
-#[macro_export(local_inner_macros)]
-macro_rules! fold_many0(
- ($i:expr, $submac:ident!( $($args:tt)* ), $init:expr, $fold_f:expr) => (
- fold_many0!($i, |i| $submac!(i, $($args)*), $init, $fold_f)
- );
- ($i:expr, $f:expr, $init:expr, $fold_f:expr) => (
- $crate::multi::fold_many0c($i, $f, $init, $fold_f)
- );
-);
-
-/// `fold_many1!(I -> IResult<I,O>, R, Fn(R, O) -> R) => I -> IResult<I, R>`
-/// Applies the parser 1 or more times and folds the list of return values.
-///
-/// The embedded parser may return `Incomplete`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(multi<&[u8], Vec<&[u8]> >,
-/// fold_many1!( tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| {
-/// acc.push(item);
-/// acc
-/// }));
-///
-/// let a = b"abcdabcdefgh";
-/// let b = b"azerty";
-///
-/// let res = vec![&b"abcd"[..], &b"abcd"[..]];
-/// assert_eq!(multi(&a[..]),Ok((&b"efgh"[..], res)));
-/// assert_eq!(multi(&b[..]), Err(Err::Error(error_position!(&b[..], ErrorKind::Many1))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! fold_many1(
- ($i:expr, $submac:ident!( $($args:tt)* ), $init:expr, $fold_f:expr) => (
- fold_many1!($i, |i| $submac!(i, $($args)*), $init, $fold_f)
- );
- ($i:expr, $f:expr, $init:expr, $fold_f:expr) => (
- $crate::multi::fold_many1c($i, $f, $init, $fold_f)
- );
- ($i:expr, $f:expr, $init:expr, $fold_f:expr) => (
- fold_many1!($i, call!($f), $init, $fold_f);
- );
-);
-
-/// `fold_many_m_n!(usize, usize, I -> IResult<I,O>, R, Fn(R, O) -> R) => I -> IResult<I, R>`
-/// Applies the parser between m and n times (n included) and folds the list of return value.
-///
-/// The embedded parser may return `Incomplete`.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::ErrorKind;
-/// # fn main() {
-/// named!(multi<&[u8], Vec<&[u8]> >,
-/// fold_many_m_n!(2, 4, tag!( "abcd" ), Vec::new(), |mut acc: Vec<_>, item| {
-/// acc.push(item);
-/// acc
-/// }));
-///
-/// let a = b"abcdefgh";
-/// let b = b"abcdabcdefgh";
-/// let c = b"abcdabcdabcdabcdabcdefgh";
-///
-/// assert_eq!(multi(&a[..]), Err(Err::Error(error_position!(&b"efgh"[..], ErrorKind::Tag))));
-/// let res = vec![&b"abcd"[..], &b"abcd"[..]];
-/// assert_eq!(multi(&b[..]),Ok((&b"efgh"[..], res)));
-/// let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]];
-/// assert_eq!(multi(&c[..]),Ok((&b"abcdefgh"[..], res2)));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! fold_many_m_n(
- ($i:expr, $m:expr, $n:expr, $submac:ident!( $($args:tt)* ), $init:expr, $fold_f:expr) => (
- fold_many_m_n!($i, $m, $n, |i| $submac!(i, $($args)*), $init, $fold_f)
- );
- ($i:expr, $m:expr, $n:expr, $f:expr, $init:expr, $fold_f:expr) => (
- $crate::multi::fold_many_m_nc($i, $m, $n, $f, $init, $fold_f)
- );
-);
-
-#[cfg(test)]
-mod tests {
- use crate::character::streaming::digit1 as digit;
- use crate::error::ErrorKind;
- use crate::error::ParseError;
- use crate::internal::{Err, IResult, Needed};
- use crate::lib::std::str::{self, FromStr};
- #[cfg(feature = "alloc")]
- use crate::lib::std::vec::Vec;
- use crate::number::streaming::{be_u16, be_u8};
-
- // reproduce the tag and take macros, because of module import order
- macro_rules! tag (
- ($i:expr, $inp: expr) => (
- {
- #[inline(always)]
- fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
- b.as_bytes()
- }
-
- let expected = $inp;
- let bytes = as_bytes(&expected);
-
- tag_bytes!($i,bytes)
- }
- );
- );
-
- macro_rules! tag_bytes (
- ($i:expr, $bytes: expr) => (
- {
- use $crate::lib::std::cmp::min;
- let len = $i.len();
- let blen = $bytes.len();
- let m = min(len, blen);
- let reduced = &$i[..m];
- let b = &$bytes[..m];
-
- let res: IResult<_,_,_> = if reduced != b {
- Err($crate::Err::Error($crate::error::make_error($i, $crate::error::ErrorKind::Tag)))
- } else if m < blen {
- Err($crate::Err::Incomplete(Needed::new(blen)))
- } else {
- Ok((&$i[blen..], reduced))
- };
- res
- }
- );
- );
-
- #[test]
- #[cfg(feature = "alloc")]
- fn separated_list0() {
- named!(multi<&[u8],Vec<&[u8]> >, separated_list0!(tag!(","), tag!("abcd")));
- named!(multi_empty<&[u8],Vec<&[u8]> >, separated_list0!(tag!(","), tag!("")));
- named!(empty_sep<&[u8],Vec<&[u8]> >, separated_list0!(tag!(""), tag!("abc")));
- named!(multi_longsep<&[u8],Vec<&[u8]> >, separated_list0!(tag!(".."), tag!("abcd")));
-
- let a = &b"abcdef"[..];
- let b = &b"abcd,abcdef"[..];
- let c = &b"azerty"[..];
- let d = &b",,abc"[..];
- let e = &b"abcd,abcd,ef"[..];
- let f = &b"abc"[..];
- let g = &b"abcd."[..];
- let h = &b"abcd,abc"[..];
- let i = &b"abcabc"[..];
-
- let res1 = vec![&b"abcd"[..]];
- assert_eq!(multi(a), Ok((&b"ef"[..], res1)));
- let res2 = vec![&b"abcd"[..], &b"abcd"[..]];
- assert_eq!(multi(b), Ok((&b"ef"[..], res2)));
- assert_eq!(multi(c), Ok((&b"azerty"[..], Vec::new())));
- let res3 = vec![&b""[..], &b""[..], &b""[..]];
- assert_eq!(multi_empty(d), Ok((&b"abc"[..], res3)));
- let i_err_pos = &i[3..];
- assert_eq!(
- empty_sep(i),
- Err(Err::Error(error_position!(
- i_err_pos,
- ErrorKind::SeparatedList
- )))
- );
- let res4 = vec![&b"abcd"[..], &b"abcd"[..]];
- assert_eq!(multi(e), Ok((&b",ef"[..], res4)));
-
- assert_eq!(multi(f), Err(Err::Incomplete(Needed::new(4))));
- assert_eq!(multi_longsep(g), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(multi(h), Err(Err::Incomplete(Needed::new(4))));
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn separated_list1() {
- named!(multi<&[u8],Vec<&[u8]> >, separated_list1!(tag!(","), tag!("abcd")));
- named!(multi_longsep<&[u8],Vec<&[u8]> >, separated_list1!(tag!(".."), tag!("abcd")));
-
- let a = &b"abcdef"[..];
- let b = &b"abcd,abcdef"[..];
- let c = &b"azerty"[..];
- let d = &b"abcd,abcd,ef"[..];
-
- let f = &b"abc"[..];
- let g = &b"abcd."[..];
- let h = &b"abcd,abc"[..];
-
- let res1 = vec![&b"abcd"[..]];
- assert_eq!(multi(a), Ok((&b"ef"[..], res1)));
- let res2 = vec![&b"abcd"[..], &b"abcd"[..]];
- assert_eq!(multi(b), Ok((&b"ef"[..], res2)));
- assert_eq!(
- multi(c),
- Err(Err::Error(error_position!(c, ErrorKind::Tag)))
- );
- let res3 = vec![&b"abcd"[..], &b"abcd"[..]];
- assert_eq!(multi(d), Ok((&b",ef"[..], res3)));
-
- assert_eq!(multi(f), Err(Err::Incomplete(Needed::new(4))));
- assert_eq!(multi_longsep(g), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(multi(h), Err(Err::Incomplete(Needed::new(4))));
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn many0() {
- named!(tag_abcd, tag!("abcd"));
- named!(tag_empty, tag!(""));
- named!( multi<&[u8],Vec<&[u8]> >, many0!(tag_abcd) );
- named!( multi_empty<&[u8],Vec<&[u8]> >, many0!(tag_empty) );
-
- assert_eq!(multi(&b"abcdef"[..]), Ok((&b"ef"[..], vec![&b"abcd"[..]])));
- assert_eq!(
- multi(&b"abcdabcdefgh"[..]),
- Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]]))
- );
- assert_eq!(multi(&b"azerty"[..]), Ok((&b"azerty"[..], Vec::new())));
- assert_eq!(multi(&b"abcdab"[..]), Err(Err::Incomplete(Needed::new(4))));
- assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(4))));
- assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::new(4))));
- assert_eq!(
- multi_empty(&b"abcdef"[..]),
- Err(Err::Error(error_position!(
- &b"abcdef"[..],
- ErrorKind::Many0
- )))
- );
- }
-
- #[cfg(nightly)]
- use test::Bencher;
-
- #[cfg(nightly)]
- #[bench]
- fn many0_bench(b: &mut Bencher) {
- named!(multi<&[u8],Vec<&[u8]> >, many0!(tag!("abcd")));
- b.iter(|| multi(&b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"[..]));
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn many1() {
- named!(multi<&[u8],Vec<&[u8]> >, many1!(tag!("abcd")));
-
- let a = &b"abcdef"[..];
- let b = &b"abcdabcdefgh"[..];
- let c = &b"azerty"[..];
- let d = &b"abcdab"[..];
-
- let res1 = vec![&b"abcd"[..]];
- assert_eq!(multi(a), Ok((&b"ef"[..], res1)));
- let res2 = vec![&b"abcd"[..], &b"abcd"[..]];
- assert_eq!(multi(b), Ok((&b"efgh"[..], res2)));
- assert_eq!(
- multi(c),
- Err(Err::Error(error_position!(c, ErrorKind::Tag)))
- );
- assert_eq!(multi(d), Err(Err::Incomplete(Needed::new(4))));
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn many_till() {
- named!(multi<&[u8], (Vec<&[u8]>, &[u8]) >, many_till!( tag!( "abcd" ), tag!( "efgh" ) ) );
-
- let a = b"abcdabcdefghabcd";
- let b = b"efghabcd";
- let c = b"azerty";
-
- let res_a = (vec![&b"abcd"[..], &b"abcd"[..]], &b"efgh"[..]);
- let res_b: (Vec<&[u8]>, &[u8]) = (Vec::new(), &b"efgh"[..]);
- assert_eq!(multi(&a[..]), Ok((&b"abcd"[..], res_a)));
- assert_eq!(multi(&b[..]), Ok((&b"abcd"[..], res_b)));
- assert_eq!(
- multi(&c[..]),
- Err(Err::Error(error_node_position!(
- &c[..],
- ErrorKind::ManyTill,
- error_position!(&c[..], ErrorKind::Tag)
- )))
- );
- }
-
- #[test]
- #[cfg(feature = "std")]
- fn infinite_many() {
- fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> {
- println!("input: {:?}", input);
- Err(Err::Error(error_position!(input, ErrorKind::Tag)))
- }
-
- // should not go into an infinite loop
- named!(multi0<&[u8],Vec<&[u8]> >, many0!(tst));
- let a = &b"abcdef"[..];
- assert_eq!(multi0(a), Ok((a, Vec::new())));
-
- named!(multi1<&[u8],Vec<&[u8]> >, many1!(tst));
- let a = &b"abcdef"[..];
- assert_eq!(
- multi1(a),
- Err(Err::Error(error_position!(a, ErrorKind::Tag)))
- );
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn many_m_n() {
- named!(multi<&[u8],Vec<&[u8]> >, many_m_n!(2, 4, tag!("Abcd")));
-
- let a = &b"Abcdef"[..];
- let b = &b"AbcdAbcdefgh"[..];
- let c = &b"AbcdAbcdAbcdAbcdefgh"[..];
- let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..];
- let e = &b"AbcdAb"[..];
-
- assert_eq!(
- multi(a),
- Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag)))
- );
- let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]];
- assert_eq!(multi(b), Ok((&b"efgh"[..], res1)));
- let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]];
- assert_eq!(multi(c), Ok((&b"efgh"[..], res2)));
- let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]];
- assert_eq!(multi(d), Ok((&b"Abcdefgh"[..], res3)));
- assert_eq!(multi(e), Err(Err::Incomplete(Needed::new(4))));
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn count() {
- const TIMES: usize = 2;
- named!(tag_abc, tag!("abc"));
- named!( cnt_2<&[u8], Vec<&[u8]> >, count!(tag_abc, TIMES ) );
-
- assert_eq!(
- cnt_2(&b"abcabcabcdef"[..]),
- Ok((&b"abcdef"[..], vec![&b"abc"[..], &b"abc"[..]]))
- );
- assert_eq!(cnt_2(&b"ab"[..]), Err(Err::Incomplete(Needed::new(3))));
- assert_eq!(cnt_2(&b"abcab"[..]), Err(Err::Incomplete(Needed::new(3))));
- assert_eq!(
- cnt_2(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- cnt_2(&b"xxxabcabcdef"[..]),
- Err(Err::Error(error_position!(
- &b"xxxabcabcdef"[..],
- ErrorKind::Tag
- )))
- );
- assert_eq!(
- cnt_2(&b"abcxxxabcdef"[..]),
- Err(Err::Error(error_position!(
- &b"xxxabcdef"[..],
- ErrorKind::Tag
- )))
- );
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn count_zero() {
- const TIMES: usize = 0;
- named!(tag_abc, tag!("abc"));
- named!( counter_2<&[u8], Vec<&[u8]> >, count!(tag_abc, TIMES ) );
-
- let done = &b"abcabcabcdef"[..];
- let parsed_done = Vec::new();
- let rest = done;
- let incomplete_1 = &b"ab"[..];
- let parsed_incompl_1 = Vec::new();
- let incomplete_2 = &b"abcab"[..];
- let parsed_incompl_2 = Vec::new();
- let error = &b"xxx"[..];
- let error_remain = &b"xxx"[..];
- let parsed_err = Vec::new();
- let error_1 = &b"xxxabcabcdef"[..];
- let parsed_err_1 = Vec::new();
- let error_1_remain = &b"xxxabcabcdef"[..];
- let error_2 = &b"abcxxxabcdef"[..];
- let parsed_err_2 = Vec::new();
- let error_2_remain = &b"abcxxxabcdef"[..];
-
- assert_eq!(counter_2(done), Ok((rest, parsed_done)));
- assert_eq!(
- counter_2(incomplete_1),
- Ok((incomplete_1, parsed_incompl_1))
- );
- assert_eq!(
- counter_2(incomplete_2),
- Ok((incomplete_2, parsed_incompl_2))
- );
- assert_eq!(counter_2(error), Ok((error_remain, parsed_err)));
- assert_eq!(counter_2(error_1), Ok((error_1_remain, parsed_err_1)));
- assert_eq!(counter_2(error_2), Ok((error_2_remain, parsed_err_2)));
- }
-
- #[derive(Debug, Clone, PartialEq)]
- pub struct NilError;
-
- impl<I> From<(I, ErrorKind)> for NilError {
- fn from(_: (I, ErrorKind)) -> Self {
- NilError
- }
- }
-
- impl<I> ParseError<I> for NilError {
- fn from_error_kind(_: I, _: ErrorKind) -> NilError {
- NilError
- }
- fn append(_: I, _: ErrorKind, _: NilError) -> NilError {
- NilError
- }
- }
-
- named!(pub number<u32>, map_res!(
- map_res!(
- digit,
- str::from_utf8
- ),
- FromStr::from_str
- ));
-
- #[test]
- #[cfg(feature = "alloc")]
- fn length_count() {
- named!(tag_abc, tag!(&b"abc"[..]));
- named!( cnt<&[u8], Vec<&[u8]> >, length_count!(number, tag_abc) );
-
- assert_eq!(
- cnt(&b"2abcabcabcdef"[..]),
- Ok((&b"abcdef"[..], vec![&b"abc"[..], &b"abc"[..]]))
- );
- assert_eq!(cnt(&b"2ab"[..]), Err(Err::Incomplete(Needed::new(3))));
- assert_eq!(cnt(&b"3abcab"[..]), Err(Err::Incomplete(Needed::new(3))));
- assert_eq!(
- cnt(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Digit)))
- );
- assert_eq!(
- cnt(&b"2abcxxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn length_data() {
- named!( take<&[u8], &[u8]>, length_data!(number) );
-
- assert_eq!(
- take(&b"6abcabcabcdef"[..]),
- Ok((&b"abcdef"[..], &b"abcabc"[..]))
- );
- assert_eq!(take(&b"3ab"[..]), Err(Err::Incomplete(Needed::new(1))));
- assert_eq!(
- take(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Digit)))
- );
- assert_eq!(take(&b"2abcxxx"[..]), Ok((&b"cxxx"[..], &b"ab"[..])));
- }
-
- #[test]
- fn length_value_test() {
- named!(length_value_1<&[u8], u16 >, length_value!(be_u8, be_u16));
- named!(length_value_2<&[u8], (u8, u8) >, length_value!(be_u8, tuple!(be_u8, be_u8)));
-
- let i1 = [0, 5, 6];
- assert_eq!(
- length_value_1(&i1),
- Err(Err::Error(error_position!(&b""[..], ErrorKind::Complete)))
- );
- assert_eq!(
- length_value_2(&i1),
- Err(Err::Error(error_position!(&b""[..], ErrorKind::Complete)))
- );
-
- let i2 = [1, 5, 6, 3];
- assert_eq!(
- length_value_1(&i2),
- Err(Err::Error(error_position!(&i2[1..2], ErrorKind::Complete)))
- );
- assert_eq!(
- length_value_2(&i2),
- Err(Err::Error(error_position!(&i2[1..2], ErrorKind::Complete)))
- );
-
- let i3 = [2, 5, 6, 3, 4, 5, 7];
- assert_eq!(length_value_1(&i3), Ok((&i3[3..], 1286)));
- assert_eq!(length_value_2(&i3), Ok((&i3[3..], (5, 6))));
-
- let i4 = [3, 5, 6, 3, 4, 5];
- assert_eq!(length_value_1(&i4), Ok((&i4[4..], 1286)));
- assert_eq!(length_value_2(&i4), Ok((&i4[4..], (5, 6))));
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn fold_many0() {
- fn fold_into_vec<T>(mut acc: Vec<T>, item: T) -> Vec<T> {
- acc.push(item);
- acc
- }
- named!(tag_abcd, tag!("abcd"));
- named!(tag_empty, tag!(""));
- named!( multi<&[u8],Vec<&[u8]> >, fold_many0!(tag_abcd, Vec::new(), fold_into_vec) );
- named!( multi_empty<&[u8],Vec<&[u8]> >, fold_many0!(tag_empty, Vec::new(), fold_into_vec) );
-
- assert_eq!(multi(&b"abcdef"[..]), Ok((&b"ef"[..], vec![&b"abcd"[..]])));
- assert_eq!(
- multi(&b"abcdabcdefgh"[..]),
- Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]]))
- );
- assert_eq!(multi(&b"azerty"[..]), Ok((&b"azerty"[..], Vec::new())));
- assert_eq!(multi(&b"abcdab"[..]), Err(Err::Incomplete(Needed::new(4))));
- assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(4))));
- assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::new(4))));
- assert_eq!(
- multi_empty(&b"abcdef"[..]),
- Err(Err::Error(error_position!(
- &b"abcdef"[..],
- ErrorKind::Many0
- )))
- );
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn fold_many1() {
- fn fold_into_vec<T>(mut acc: Vec<T>, item: T) -> Vec<T> {
- acc.push(item);
- acc
- }
- named!(multi<&[u8],Vec<&[u8]> >, fold_many1!(tag!("abcd"), Vec::new(), fold_into_vec));
-
- let a = &b"abcdef"[..];
- let b = &b"abcdabcdefgh"[..];
- let c = &b"azerty"[..];
- let d = &b"abcdab"[..];
-
- let res1 = vec![&b"abcd"[..]];
- assert_eq!(multi(a), Ok((&b"ef"[..], res1)));
- let res2 = vec![&b"abcd"[..], &b"abcd"[..]];
- assert_eq!(multi(b), Ok((&b"efgh"[..], res2)));
- assert_eq!(
- multi(c),
- Err(Err::Error(error_position!(c, ErrorKind::Many1)))
- );
- assert_eq!(multi(d), Err(Err::Incomplete(Needed::new(4))));
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn fold_many_m_n() {
- fn fold_into_vec<T>(mut acc: Vec<T>, item: T) -> Vec<T> {
- acc.push(item);
- acc
- }
- named!(multi<&[u8],Vec<&[u8]> >, fold_many_m_n!(2, 4, tag!("Abcd"), Vec::new(), fold_into_vec));
-
- let a = &b"Abcdef"[..];
- let b = &b"AbcdAbcdefgh"[..];
- let c = &b"AbcdAbcdAbcdAbcdefgh"[..];
- let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..];
- let e = &b"AbcdAb"[..];
-
- assert_eq!(
- multi(a),
- Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag)))
- );
- let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]];
- assert_eq!(multi(b), Ok((&b"efgh"[..], res1)));
- let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]];
- assert_eq!(multi(c), Ok((&b"efgh"[..], res2)));
- let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]];
- assert_eq!(multi(d), Ok((&b"Abcdefgh"[..], res3)));
- assert_eq!(multi(e), Err(Err::Incomplete(Needed::new(4))));
- }
-
- #[test]
- fn many0_count() {
- named!(
- count0_nums(&[u8]) -> usize,
- many0_count!(pair!(digit, tag!(",")))
- );
-
- assert_eq!(count0_nums(&b"123,junk"[..]), Ok((&b"junk"[..], 1)));
-
- assert_eq!(count0_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2)));
-
- assert_eq!(
- count0_nums(&b"1,2,3,4,5,6,7,8,9,0,junk"[..]),
- Ok((&b"junk"[..], 10))
- );
-
- assert_eq!(count0_nums(&b"hello"[..]), Ok((&b"hello"[..], 0)));
- }
-
- #[test]
- fn many1_count() {
- named!(
- count1_nums(&[u8]) -> usize,
- many1_count!(pair!(digit, tag!(",")))
- );
-
- assert_eq!(count1_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2)));
-
- assert_eq!(
- count1_nums(&b"1,2,3,4,5,6,7,8,9,0,junk"[..]),
- Ok((&b"junk"[..], 10))
- );
-
- assert_eq!(
- count1_nums(&b"hello"[..]),
- Err(Err::Error(error_position!(
- &b"hello"[..],
- ErrorKind::Many1Count
- )))
- );
- }
-}
diff --git a/src/multi/mod.rs b/src/multi/mod.rs
index 46a59ed..9f72888 100644
--- a/src/multi/mod.rs
+++ b/src/multi/mod.rs
@@ -1,7 +1,7 @@
//! Combinators applying their child parser multiple times
-#[macro_use]
-mod macros;
+#[cfg(test)]
+mod tests;
use crate::error::ErrorKind;
use crate::error::ParseError;
@@ -39,18 +39,20 @@ use core::num::NonZeroUsize;
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
pub fn many0<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
E: ParseError<I>,
{
move |mut i: I| {
let mut acc = crate::lib::std::vec::Vec::with_capacity(4);
loop {
+ let len = i.input_len();
match f.parse(i.clone()) {
Err(Err::Error(_)) => return Ok((i, acc)),
Err(e) => return Err(e),
Ok((i1, o)) => {
- if i1 == i {
+ // infinite loop check: the parser must always consume
+ if i1.input_len() == len {
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many0)));
}
@@ -61,18 +63,6 @@ where
}
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-pub fn many0c<I, O, E, F>(input: I, f: F) -> IResult<I, Vec<O>, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- E: ParseError<I>,
-{
- many0(f)(input)
-}
/// Runs the embedded parser until it fails and
/// returns the results in a `Vec`. Fails if
@@ -104,7 +94,7 @@ where
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
pub fn many1<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
E: ParseError<I>,
{
@@ -117,11 +107,13 @@ where
i = i1;
loop {
+ let len = i.input_len();
match f.parse(i.clone()) {
Err(Err::Error(_)) => return Ok((i, acc)),
Err(e) => return Err(e),
Ok((i1, o)) => {
- if i1 == i {
+ // infinite loop check: the parser must always consume
+ if i1.input_len() == len {
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many1)));
}
@@ -134,19 +126,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-pub fn many1c<I, O, E, F>(input: I, f: F) -> IResult<I, Vec<O>, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- E: ParseError<I>,
-{
- many1(f)(input)
-}
-
/// Applies the parser `f` until the parser `g` produces
/// a result. Returns a pair consisting of the results of
/// `f` in a `Vec` and the result of `g`.
@@ -172,7 +151,7 @@ pub fn many_till<I, O, P, E, F, G>(
mut g: G,
) -> impl FnMut(I) -> IResult<I, (Vec<O>, P), E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
G: Parser<I, P, E>,
E: ParseError<I>,
@@ -180,6 +159,7 @@ where
move |mut i: I| {
let mut res = crate::lib::std::vec::Vec::new();
loop {
+ let len = i.input_len();
match g.parse(i.clone()) {
Ok((i1, o)) => return Ok((i1, (res, o))),
Err(Err::Error(_)) => {
@@ -187,8 +167,8 @@ where
Err(Err::Error(err)) => return Err(Err::Error(E::append(i, ErrorKind::ManyTill, err))),
Err(e) => return Err(e),
Ok((i1, o)) => {
- // loop trip must always consume (otherwise infinite loops)
- if i1 == i {
+ // infinite loop check: the parser must always consume
+ if i1.input_len() == len {
return Err(Err::Error(E::from_error_kind(i1, ErrorKind::ManyTill)));
}
@@ -203,20 +183,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-pub fn many_tillc<I, O, P, E, F, G>(i: I, f: F, g: G) -> IResult<I, (Vec<O>, P), E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- G: Fn(I) -> IResult<I, P, E>,
- E: ParseError<I>,
-{
- many_till(f, g)(i)
-}
-
/// Alternates between two parsers to produce
/// a list of elements.
/// # Arguments
@@ -245,7 +211,7 @@ pub fn separated_list0<I, O, O2, E, F, G>(
mut f: F,
) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
G: Parser<I, O2, E>,
E: ParseError<I>,
@@ -263,11 +229,13 @@ where
}
loop {
+ let len = i.input_len();
match sep.parse(i.clone()) {
Err(Err::Error(_)) => return Ok((i, res)),
Err(e) => return Err(e),
Ok((i1, _)) => {
- if i1 == i {
+ // infinite loop check: the parser must always consume
+ if i1.input_len() == len {
return Err(Err::Error(E::from_error_kind(i1, ErrorKind::SeparatedList)));
}
@@ -285,20 +253,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-pub fn separated_list0c<I, O, O2, E, F, G>(i: I, sep: G, f: F) -> IResult<I, Vec<O>, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- G: Fn(I) -> IResult<I, O2, E>,
- E: ParseError<I>,
-{
- separated_list0(sep, f)(i)
-}
-
/// Alternates between two parsers to produce
/// a list of elements. Fails if the element
/// parser does not produce at least one element.
@@ -328,7 +282,7 @@ pub fn separated_list1<I, O, O2, E, F, G>(
mut f: F,
) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
G: Parser<I, O2, E>,
E: ParseError<I>,
@@ -346,11 +300,13 @@ where
}
loop {
+ let len = i.input_len();
match sep.parse(i.clone()) {
Err(Err::Error(_)) => return Ok((i, res)),
Err(e) => return Err(e),
Ok((i1, _)) => {
- if i1 == i {
+ // infinite loop check: the parser must always consume
+ if i1.input_len() == len {
return Err(Err::Error(E::from_error_kind(i1, ErrorKind::SeparatedList)));
}
@@ -368,20 +324,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-#[cfg(feature = "alloc")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
-pub fn separated_list1c<I, O, O2, E, F, G>(i: I, sep: G, f: F) -> IResult<I, Vec<O>, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- G: Fn(I) -> IResult<I, O2, E>,
- E: ParseError<I>,
-{
- separated_list1(sep, f)(i)
-}
-
/// Repeats the embedded parser `n` times or until it fails
/// and returns the results in a `Vec`. Fails if the
/// embedded parser does not succeed at least `m` times.
@@ -413,18 +355,22 @@ pub fn many_m_n<I, O, E, F>(
mut parse: F,
) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
E: ParseError<I>,
{
move |mut input: I| {
- let mut res = crate::lib::std::vec::Vec::with_capacity(min);
+ if min > max {
+ return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN)));
+ }
+ let mut res = crate::lib::std::vec::Vec::with_capacity(min);
for count in 0..max {
+ let len = input.input_len();
match parse.parse(input.clone()) {
Ok((tail, value)) => {
- // do not allow parsers that do not consume input (causes infinite loops)
- if tail == input {
+ // infinite loop check: the parser must always consume
+ if tail.input_len() == len {
return Err(Err::Error(E::from_error_kind(input, ErrorKind::ManyMN)));
}
@@ -448,18 +394,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-#[cfg(feature = "alloc")]
-pub fn many_m_nc<I, O, E, F>(i: I, m: usize, n: usize, f: F) -> IResult<I, Vec<O>, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- E: ParseError<I>,
-{
- many_m_n(m, n, f)(i)
-}
-
/// Repeats the embedded parser until it fails
/// and returns the number of successful iterations.
/// # Arguments
@@ -481,7 +415,7 @@ where
/// ```
pub fn many0_count<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, usize, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
E: ParseError<I>,
{
@@ -491,10 +425,11 @@ where
loop {
let input_ = input.clone();
+ let len = input.input_len();
match f.parse(input_) {
Ok((i, _)) => {
- // loop trip must always consume (otherwise infinite loops)
- if i == input {
+ // infinite loop check: the parser must always consume
+ if i.input_len() == len {
return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many0Count)));
}
@@ -510,16 +445,6 @@ where
}
}
-#[doc(hidden)]
-pub fn many0_countc<I, O, E, F>(i: I, f: F) -> IResult<I, usize, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- E: ParseError<I>,
-{
- many0_count(f)(i)
-}
-
/// Repeats the embedded parser until it fails
/// and returns the number of successful iterations.
/// Fails if the embedded parser does not succeed
@@ -543,7 +468,7 @@ where
/// ```
pub fn many1_count<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, usize, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
E: ParseError<I>,
{
@@ -557,12 +482,14 @@ where
let mut input = i1;
loop {
+ let len = input.input_len();
let input_ = input.clone();
match f.parse(input_) {
Err(Err::Error(_)) => return Ok((input, count)),
Err(e) => return Err(e),
Ok((i, _)) => {
- if i == input {
+ // infinite loop check: the parser must always consume
+ if i.input_len() == len {
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many1Count)));
}
@@ -576,16 +503,6 @@ where
}
}
-#[doc(hidden)]
-pub fn many1_countc<I, O, E, F>(i: I, f: F) -> IResult<I, usize, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- E: ParseError<I>,
-{
- many1_count(f)(i)
-}
-
/// Runs the embedded parser a specified number
/// of times. Returns the results in a `Vec`.
/// # Arguments
@@ -695,7 +612,7 @@ where
/// the results using a given function and initial value.
/// # Arguments
/// * `f` The parser to apply.
-/// * `init` The initial value.
+/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
/// ```rust
@@ -707,7 +624,7 @@ where
/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
/// fold_many0(
/// tag("abc"),
-/// Vec::new(),
+/// Vec::new,
/// |mut acc: Vec<_>, item| {
/// acc.push(item);
/// acc
@@ -720,28 +637,29 @@ where
/// assert_eq!(parser("123123"), Ok(("123123", vec![])));
/// assert_eq!(parser(""), Ok(("", vec![])));
/// ```
-pub fn fold_many0<I, O, E, F, G, R>(
+pub fn fold_many0<I, O, E, F, G, H, R>(
mut f: F,
- init: R,
+ mut init: H,
mut g: G,
) -> impl FnMut(I) -> IResult<I, R, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
G: FnMut(R, O) -> R,
+ H: FnMut() -> R,
E: ParseError<I>,
- R: Clone,
{
move |i: I| {
- let mut res = init.clone();
+ let mut res = init();
let mut input = i;
loop {
let i_ = input.clone();
+ let len = input.input_len();
match f.parse(i_) {
Ok((i, o)) => {
- // loop trip must always consume (otherwise infinite loops)
- if i == input {
+ // infinite loop check: the parser must always consume
+ if i.input_len() == len {
return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many0)));
}
@@ -759,25 +677,13 @@ where
}
}
-#[doc(hidden)]
-pub fn fold_many0c<I, O, E, F, G, R>(i: I, f: F, init: R, g: G) -> IResult<I, R, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- G: FnMut(R, O) -> R,
- E: ParseError<I>,
- R: Clone,
-{
- fold_many0(f, init, g)(i)
-}
-
/// Applies a parser until it fails and accumulates
/// the results using a given function and initial value.
/// Fails if the embedded parser does not succeed at least
/// once.
/// # Arguments
/// * `f` The parser to apply.
-/// * `init` The initial value.
+/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
/// ```rust
@@ -789,7 +695,7 @@ where
/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
/// fold_many1(
/// tag("abc"),
-/// Vec::new(),
+/// Vec::new,
/// |mut acc: Vec<_>, item| {
/// acc.push(item);
/// acc
@@ -802,21 +708,21 @@ where
/// assert_eq!(parser("123123"), Err(Err::Error(Error::new("123123", ErrorKind::Many1))));
/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Many1))));
/// ```
-pub fn fold_many1<I, O, E, F, G, R>(
+pub fn fold_many1<I, O, E, F, G, H, R>(
mut f: F,
- init: R,
+ mut init: H,
mut g: G,
) -> impl FnMut(I) -> IResult<I, R, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
G: FnMut(R, O) -> R,
+ H: FnMut() -> R,
E: ParseError<I>,
- R: Clone,
{
move |i: I| {
let _i = i.clone();
- let init = init.clone();
+ let init = init();
match f.parse(_i) {
Err(Err::Error(_)) => Err(Err::Error(E::from_error_kind(i, ErrorKind::Many1))),
Err(e) => Err(e),
@@ -826,13 +732,15 @@ where
loop {
let _input = input.clone();
+ let len = input.input_len();
match f.parse(_input) {
Err(Err::Error(_)) => {
break;
}
Err(e) => return Err(e),
Ok((i, o)) => {
- if i == input {
+ // infinite loop check: the parser must always consume
+ if i.input_len() == len {
return Err(Err::Failure(E::from_error_kind(i, ErrorKind::Many1)));
}
@@ -848,18 +756,6 @@ where
}
}
-#[doc(hidden)]
-pub fn fold_many1c<I, O, E, F, G, R>(i: I, f: F, init: R, g: G) -> IResult<I, R, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- G: FnMut(R, O) -> R,
- E: ParseError<I>,
- R: Clone,
-{
- fold_many1(f, init, g)(i)
-}
-
/// Applies a parser `n` times or until it fails and accumulates
/// the results using a given function and initial value.
/// Fails if the embedded parser does not succeed at least `m`
@@ -868,7 +764,7 @@ where
/// * `m` The minimum number of iterations.
/// * `n` The maximum number of iterations.
/// * `f` The parser to apply.
-/// * `init` The initial value.
+/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
/// ```rust
@@ -882,7 +778,7 @@ where
/// 0,
/// 2,
/// tag("abc"),
-/// Vec::new(),
+/// Vec::new,
/// |mut acc: Vec<_>, item| {
/// acc.push(item);
/// acc
@@ -896,27 +792,32 @@ where
/// assert_eq!(parser(""), Ok(("", vec![])));
/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"])));
/// ```
-pub fn fold_many_m_n<I, O, E, F, G, R>(
+pub fn fold_many_m_n<I, O, E, F, G, H, R>(
min: usize,
max: usize,
mut parse: F,
- init: R,
+ mut init: H,
mut fold: G,
) -> impl FnMut(I) -> IResult<I, R, E>
where
- I: Clone + PartialEq,
+ I: Clone + InputLength,
F: Parser<I, O, E>,
G: FnMut(R, O) -> R,
+ H: FnMut() -> R,
E: ParseError<I>,
- R: Clone,
{
move |mut input: I| {
- let mut acc = init.clone();
+ if min > max {
+ return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN)));
+ }
+
+ let mut acc = init();
for count in 0..max {
+ let len = input.input_len();
match parse.parse(input.clone()) {
Ok((tail, value)) => {
- // do not allow parsers that do not consume input (causes infinite loops)
- if tail == input {
+ // infinite loop check: the parser must always consume
+ if tail.input_len() == len {
return Err(Err::Error(E::from_error_kind(tail, ErrorKind::ManyMN)));
}
@@ -939,25 +840,6 @@ where
}
}
-#[doc(hidden)]
-pub fn fold_many_m_nc<I, O, E, F, G, R>(
- input: I,
- min: usize,
- max: usize,
- parse: F,
- init: R,
- fold: G,
-) -> IResult<I, R, E>
-where
- I: Clone + PartialEq,
- F: Fn(I) -> IResult<I, O, E>,
- G: Fn(R, O) -> R,
- E: ParseError<I>,
- R: Clone,
-{
- fold_many_m_n(min, max, parse, init, fold)(input)
-}
-
/// Gets a number from the parser and returns a
/// subslice of the input of that size.
/// If the parser returns `Incomplete`,
@@ -1008,6 +890,7 @@ where
/// `length_value` will return an error.
/// # Arguments
/// * `f` The parser to apply.
+/// * `g` The parser to apply on the subslice.
/// ```rust
/// # #[macro_use] extern crate nom;
/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
@@ -1052,21 +935,9 @@ where
}
}
-#[doc(hidden)]
-pub fn length_valuec<I, O, N, E, F, G>(i: I, f: F, g: G) -> IResult<I, O, E>
-where
- I: Clone + InputLength + InputTake,
- N: ToUsize,
- F: Fn(I) -> IResult<I, N, E>,
- G: Fn(I) -> IResult<I, O, E>,
- E: ParseError<I>,
-{
- length_value(f, g)(i)
-}
-
/// Gets a number from the first parser,
/// then applies the second parser that many times.
-/// Arguments
+/// # Arguments
/// * `f` The parser to apply to obtain the count.
/// * `g` The parser to apply repeatedly.
/// ```rust
diff --git a/src/multi/tests.rs b/src/multi/tests.rs
new file mode 100644
index 0000000..2a96f84
--- /dev/null
+++ b/src/multi/tests.rs
@@ -0,0 +1,544 @@
+use super::{length_data, length_value, many0_count, many1_count};
+use crate::{
+ bytes::streaming::tag,
+ character::streaming::digit1 as digit,
+ error::{ErrorKind, ParseError},
+ internal::{Err, IResult, Needed},
+ lib::std::str::{self, FromStr},
+ number::streaming::{be_u16, be_u8},
+ sequence::{pair, tuple},
+};
+#[cfg(feature = "alloc")]
+use crate::{
+ lib::std::vec::Vec,
+ multi::{
+ count, fold_many0, fold_many1, fold_many_m_n, length_count, many0, many1, many_m_n, many_till,
+ separated_list0, separated_list1,
+ },
+};
+
+#[test]
+#[cfg(feature = "alloc")]
+fn separated_list0_test() {
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ separated_list0(tag(","), tag("abcd"))(i)
+ }
+ fn multi_empty(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ separated_list0(tag(","), tag(""))(i)
+ }
+ fn empty_sep(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ separated_list0(tag(""), tag("abc"))(i)
+ }
+ fn multi_longsep(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ separated_list0(tag(".."), tag("abcd"))(i)
+ }
+
+ let a = &b"abcdef"[..];
+ let b = &b"abcd,abcdef"[..];
+ let c = &b"azerty"[..];
+ let d = &b",,abc"[..];
+ let e = &b"abcd,abcd,ef"[..];
+ let f = &b"abc"[..];
+ let g = &b"abcd."[..];
+ let h = &b"abcd,abc"[..];
+ let i = &b"abcabc"[..];
+
+ let res1 = vec![&b"abcd"[..]];
+ assert_eq!(multi(a), Ok((&b"ef"[..], res1)));
+ let res2 = vec![&b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(multi(b), Ok((&b"ef"[..], res2)));
+ assert_eq!(multi(c), Ok((&b"azerty"[..], Vec::new())));
+ let res3 = vec![&b""[..], &b""[..], &b""[..]];
+ assert_eq!(multi_empty(d), Ok((&b"abc"[..], res3)));
+ let i_err_pos = &i[3..];
+ assert_eq!(
+ empty_sep(i),
+ Err(Err::Error(error_position!(
+ i_err_pos,
+ ErrorKind::SeparatedList
+ )))
+ );
+ let res4 = vec![&b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(multi(e), Ok((&b",ef"[..], res4)));
+
+ assert_eq!(multi(f), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(multi_longsep(g), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(multi(h), Err(Err::Incomplete(Needed::new(1))));
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn separated_list1_test() {
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ separated_list1(tag(","), tag("abcd"))(i)
+ }
+ fn multi_longsep(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ separated_list1(tag(".."), tag("abcd"))(i)
+ }
+
+ let a = &b"abcdef"[..];
+ let b = &b"abcd,abcdef"[..];
+ let c = &b"azerty"[..];
+ let d = &b"abcd,abcd,ef"[..];
+
+ let f = &b"abc"[..];
+ let g = &b"abcd."[..];
+ let h = &b"abcd,abc"[..];
+
+ let res1 = vec![&b"abcd"[..]];
+ assert_eq!(multi(a), Ok((&b"ef"[..], res1)));
+ let res2 = vec![&b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(multi(b), Ok((&b"ef"[..], res2)));
+ assert_eq!(
+ multi(c),
+ Err(Err::Error(error_position!(c, ErrorKind::Tag)))
+ );
+ let res3 = vec![&b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(multi(d), Ok((&b",ef"[..], res3)));
+
+ assert_eq!(multi(f), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(multi_longsep(g), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(multi(h), Err(Err::Incomplete(Needed::new(1))));
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn many0_test() {
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many0(tag("abcd"))(i)
+ }
+ fn multi_empty(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many0(tag(""))(i)
+ }
+
+ assert_eq!(multi(&b"abcdef"[..]), Ok((&b"ef"[..], vec![&b"abcd"[..]])));
+ assert_eq!(
+ multi(&b"abcdabcdefgh"[..]),
+ Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]]))
+ );
+ assert_eq!(multi(&b"azerty"[..]), Ok((&b"azerty"[..], Vec::new())));
+ assert_eq!(multi(&b"abcdab"[..]), Err(Err::Incomplete(Needed::new(2))));
+ assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(4))));
+ assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::new(4))));
+ assert_eq!(
+ multi_empty(&b"abcdef"[..]),
+ Err(Err::Error(error_position!(
+ &b"abcdef"[..],
+ ErrorKind::Many0
+ )))
+ );
+}
+
+#[cfg(nightly)]
+use test::Bencher;
+
+#[cfg(nightly)]
+#[bench]
+fn many0_bench(b: &mut Bencher) {
+ named!(multi<&[u8],Vec<&[u8]> >, many0!(tag!("abcd")));
+ b.iter(|| multi(&b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"[..]));
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn many1_test() {
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many1(tag("abcd"))(i)
+ }
+
+ let a = &b"abcdef"[..];
+ let b = &b"abcdabcdefgh"[..];
+ let c = &b"azerty"[..];
+ let d = &b"abcdab"[..];
+
+ let res1 = vec![&b"abcd"[..]];
+ assert_eq!(multi(a), Ok((&b"ef"[..], res1)));
+ let res2 = vec![&b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(multi(b), Ok((&b"efgh"[..], res2)));
+ assert_eq!(
+ multi(c),
+ Err(Err::Error(error_position!(c, ErrorKind::Tag)))
+ );
+ assert_eq!(multi(d), Err(Err::Incomplete(Needed::new(2))));
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn many_till_test() {
+ fn multi(i: &[u8]) -> IResult<&[u8], (Vec<&[u8]>, &[u8])> {
+ many_till(tag("abcd"), tag("efgh"))(i)
+ }
+
+ let a = b"abcdabcdefghabcd";
+ let b = b"efghabcd";
+ let c = b"azerty";
+
+ let res_a = (vec![&b"abcd"[..], &b"abcd"[..]], &b"efgh"[..]);
+ let res_b: (Vec<&[u8]>, &[u8]) = (Vec::new(), &b"efgh"[..]);
+ assert_eq!(multi(&a[..]), Ok((&b"abcd"[..], res_a)));
+ assert_eq!(multi(&b[..]), Ok((&b"abcd"[..], res_b)));
+ assert_eq!(
+ multi(&c[..]),
+ Err(Err::Error(error_node_position!(
+ &c[..],
+ ErrorKind::ManyTill,
+ error_position!(&c[..], ErrorKind::Tag)
+ )))
+ );
+}
+
+#[test]
+#[cfg(feature = "std")]
+fn infinite_many() {
+ fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> {
+ println!("input: {:?}", input);
+ Err(Err::Error(error_position!(input, ErrorKind::Tag)))
+ }
+
+ // should not go into an infinite loop
+ fn multi0(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many0(tst)(i)
+ }
+ let a = &b"abcdef"[..];
+ assert_eq!(multi0(a), Ok((a, Vec::new())));
+
+ fn multi1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many1(tst)(i)
+ }
+ let a = &b"abcdef"[..];
+ assert_eq!(
+ multi1(a),
+ Err(Err::Error(error_position!(a, ErrorKind::Tag)))
+ );
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn many_m_n_test() {
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many_m_n(2, 4, tag("Abcd"))(i)
+ }
+
+ let a = &b"Abcdef"[..];
+ let b = &b"AbcdAbcdefgh"[..];
+ let c = &b"AbcdAbcdAbcdAbcdefgh"[..];
+ let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..];
+ let e = &b"AbcdAb"[..];
+
+ assert_eq!(
+ multi(a),
+ Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag)))
+ );
+ let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]];
+ assert_eq!(multi(b), Ok((&b"efgh"[..], res1)));
+ let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]];
+ assert_eq!(multi(c), Ok((&b"efgh"[..], res2)));
+ let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]];
+ assert_eq!(multi(d), Ok((&b"Abcdefgh"[..], res3)));
+ assert_eq!(multi(e), Err(Err::Incomplete(Needed::new(2))));
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn count_test() {
+ const TIMES: usize = 2;
+ fn cnt_2(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ count(tag("abc"), TIMES)(i)
+ }
+
+ assert_eq!(
+ cnt_2(&b"abcabcabcdef"[..]),
+ Ok((&b"abcdef"[..], vec![&b"abc"[..], &b"abc"[..]]))
+ );
+ assert_eq!(cnt_2(&b"ab"[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(cnt_2(&b"abcab"[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(
+ cnt_2(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ cnt_2(&b"xxxabcabcdef"[..]),
+ Err(Err::Error(error_position!(
+ &b"xxxabcabcdef"[..],
+ ErrorKind::Tag
+ )))
+ );
+ assert_eq!(
+ cnt_2(&b"abcxxxabcdef"[..]),
+ Err(Err::Error(error_position!(
+ &b"xxxabcdef"[..],
+ ErrorKind::Tag
+ )))
+ );
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn count_zero() {
+ const TIMES: usize = 0;
+ fn counter_2(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ count(tag("abc"), TIMES)(i)
+ }
+
+ let done = &b"abcabcabcdef"[..];
+ let parsed_done = Vec::new();
+ let rest = done;
+ let incomplete_1 = &b"ab"[..];
+ let parsed_incompl_1 = Vec::new();
+ let incomplete_2 = &b"abcab"[..];
+ let parsed_incompl_2 = Vec::new();
+ let error = &b"xxx"[..];
+ let error_remain = &b"xxx"[..];
+ let parsed_err = Vec::new();
+ let error_1 = &b"xxxabcabcdef"[..];
+ let parsed_err_1 = Vec::new();
+ let error_1_remain = &b"xxxabcabcdef"[..];
+ let error_2 = &b"abcxxxabcdef"[..];
+ let parsed_err_2 = Vec::new();
+ let error_2_remain = &b"abcxxxabcdef"[..];
+
+ assert_eq!(counter_2(done), Ok((rest, parsed_done)));
+ assert_eq!(
+ counter_2(incomplete_1),
+ Ok((incomplete_1, parsed_incompl_1))
+ );
+ assert_eq!(
+ counter_2(incomplete_2),
+ Ok((incomplete_2, parsed_incompl_2))
+ );
+ assert_eq!(counter_2(error), Ok((error_remain, parsed_err)));
+ assert_eq!(counter_2(error_1), Ok((error_1_remain, parsed_err_1)));
+ assert_eq!(counter_2(error_2), Ok((error_2_remain, parsed_err_2)));
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct NilError;
+
+impl<I> From<(I, ErrorKind)> for NilError {
+ fn from(_: (I, ErrorKind)) -> Self {
+ NilError
+ }
+}
+
+impl<I> ParseError<I> for NilError {
+ fn from_error_kind(_: I, _: ErrorKind) -> NilError {
+ NilError
+ }
+ fn append(_: I, _: ErrorKind, _: NilError) -> NilError {
+ NilError
+ }
+}
+
+fn number(i: &[u8]) -> IResult<&[u8], u32> {
+ use crate::combinator::map_res;
+
+ map_res(map_res(digit, str::from_utf8), FromStr::from_str)(i)
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn length_count_test() {
+ fn cnt(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ length_count(number, tag("abc"))(i)
+ }
+
+ assert_eq!(
+ cnt(&b"2abcabcabcdef"[..]),
+ Ok((&b"abcdef"[..], vec![&b"abc"[..], &b"abc"[..]]))
+ );
+ assert_eq!(cnt(&b"2ab"[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(cnt(&b"3abcab"[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(
+ cnt(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Digit)))
+ );
+ assert_eq!(
+ cnt(&b"2abcxxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn length_data_test() {
+ fn take(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ length_data(number)(i)
+ }
+
+ assert_eq!(
+ take(&b"6abcabcabcdef"[..]),
+ Ok((&b"abcdef"[..], &b"abcabc"[..]))
+ );
+ assert_eq!(take(&b"3ab"[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(
+ take(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Digit)))
+ );
+ assert_eq!(take(&b"2abcxxx"[..]), Ok((&b"cxxx"[..], &b"ab"[..])));
+}
+
+#[test]
+fn length_value_test() {
+ fn length_value_1(i: &[u8]) -> IResult<&[u8], u16> {
+ length_value(be_u8, be_u16)(i)
+ }
+ fn length_value_2(i: &[u8]) -> IResult<&[u8], (u8, u8)> {
+ length_value(be_u8, tuple((be_u8, be_u8)))(i)
+ }
+
+ let i1 = [0, 5, 6];
+ assert_eq!(
+ length_value_1(&i1),
+ Err(Err::Error(error_position!(&b""[..], ErrorKind::Complete)))
+ );
+ assert_eq!(
+ length_value_2(&i1),
+ Err(Err::Error(error_position!(&b""[..], ErrorKind::Complete)))
+ );
+
+ let i2 = [1, 5, 6, 3];
+ assert_eq!(
+ length_value_1(&i2),
+ Err(Err::Error(error_position!(&i2[1..2], ErrorKind::Complete)))
+ );
+ assert_eq!(
+ length_value_2(&i2),
+ Err(Err::Error(error_position!(&i2[1..2], ErrorKind::Complete)))
+ );
+
+ let i3 = [2, 5, 6, 3, 4, 5, 7];
+ assert_eq!(length_value_1(&i3), Ok((&i3[3..], 1286)));
+ assert_eq!(length_value_2(&i3), Ok((&i3[3..], (5, 6))));
+
+ let i4 = [3, 5, 6, 3, 4, 5];
+ assert_eq!(length_value_1(&i4), Ok((&i4[4..], 1286)));
+ assert_eq!(length_value_2(&i4), Ok((&i4[4..], (5, 6))));
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn fold_many0_test() {
+ fn fold_into_vec<T>(mut acc: Vec<T>, item: T) -> Vec<T> {
+ acc.push(item);
+ acc
+ }
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ fold_many0(tag("abcd"), Vec::new, fold_into_vec)(i)
+ }
+ fn multi_empty(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ fold_many0(tag(""), Vec::new, fold_into_vec)(i)
+ }
+
+ assert_eq!(multi(&b"abcdef"[..]), Ok((&b"ef"[..], vec![&b"abcd"[..]])));
+ assert_eq!(
+ multi(&b"abcdabcdefgh"[..]),
+ Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]]))
+ );
+ assert_eq!(multi(&b"azerty"[..]), Ok((&b"azerty"[..], Vec::new())));
+ assert_eq!(multi(&b"abcdab"[..]), Err(Err::Incomplete(Needed::new(2))));
+ assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(4))));
+ assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::new(4))));
+ assert_eq!(
+ multi_empty(&b"abcdef"[..]),
+ Err(Err::Error(error_position!(
+ &b"abcdef"[..],
+ ErrorKind::Many0
+ )))
+ );
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn fold_many1_test() {
+ fn fold_into_vec<T>(mut acc: Vec<T>, item: T) -> Vec<T> {
+ acc.push(item);
+ acc
+ }
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ fold_many1(tag("abcd"), Vec::new, fold_into_vec)(i)
+ }
+
+ let a = &b"abcdef"[..];
+ let b = &b"abcdabcdefgh"[..];
+ let c = &b"azerty"[..];
+ let d = &b"abcdab"[..];
+
+ let res1 = vec![&b"abcd"[..]];
+ assert_eq!(multi(a), Ok((&b"ef"[..], res1)));
+ let res2 = vec![&b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(multi(b), Ok((&b"efgh"[..], res2)));
+ assert_eq!(
+ multi(c),
+ Err(Err::Error(error_position!(c, ErrorKind::Many1)))
+ );
+ assert_eq!(multi(d), Err(Err::Incomplete(Needed::new(2))));
+}
+
+#[test]
+#[cfg(feature = "alloc")]
+fn fold_many_m_n_test() {
+ fn fold_into_vec<T>(mut acc: Vec<T>, item: T) -> Vec<T> {
+ acc.push(item);
+ acc
+ }
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ fold_many_m_n(2, 4, tag("Abcd"), Vec::new, fold_into_vec)(i)
+ }
+
+ let a = &b"Abcdef"[..];
+ let b = &b"AbcdAbcdefgh"[..];
+ let c = &b"AbcdAbcdAbcdAbcdefgh"[..];
+ let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..];
+ let e = &b"AbcdAb"[..];
+
+ assert_eq!(
+ multi(a),
+ Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag)))
+ );
+ let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]];
+ assert_eq!(multi(b), Ok((&b"efgh"[..], res1)));
+ let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]];
+ assert_eq!(multi(c), Ok((&b"efgh"[..], res2)));
+ let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]];
+ assert_eq!(multi(d), Ok((&b"Abcdefgh"[..], res3)));
+ assert_eq!(multi(e), Err(Err::Incomplete(Needed::new(2))));
+}
+
+#[test]
+fn many0_count_test() {
+ fn count0_nums(i: &[u8]) -> IResult<&[u8], usize> {
+ many0_count(pair(digit, tag(",")))(i)
+ }
+
+ assert_eq!(count0_nums(&b"123,junk"[..]), Ok((&b"junk"[..], 1)));
+
+ assert_eq!(count0_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2)));
+
+ assert_eq!(
+ count0_nums(&b"1,2,3,4,5,6,7,8,9,0,junk"[..]),
+ Ok((&b"junk"[..], 10))
+ );
+
+ assert_eq!(count0_nums(&b"hello"[..]), Ok((&b"hello"[..], 0)));
+}
+
+#[test]
+fn many1_count_test() {
+ fn count1_nums(i: &[u8]) -> IResult<&[u8], usize> {
+ many1_count(pair(digit, tag(",")))(i)
+ }
+
+ assert_eq!(count1_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2)));
+
+ assert_eq!(
+ count1_nums(&b"1,2,3,4,5,6,7,8,9,0,junk"[..]),
+ Ok((&b"junk"[..], 10))
+ );
+
+ assert_eq!(
+ count1_nums(&b"hello"[..]),
+ Err(Err::Error(error_position!(
+ &b"hello"[..],
+ ErrorKind::Many1Count
+ )))
+ );
+}
diff --git a/src/number/complete.rs b/src/number/complete.rs
index ffebf23..c5553a4 100644
--- a/src/number/complete.rs
+++ b/src/number/complete.rs
@@ -1,15 +1,37 @@
//! Parsers recognizing numbers, complete input version
use crate::branch::alt;
-use crate::character::complete::{char, digit1};
+use crate::bytes::complete::tag;
+use crate::character::complete::{char, digit1, sign};
use crate::combinator::{cut, map, opt, recognize};
use crate::error::ParseError;
use crate::error::{make_error, ErrorKind};
use crate::internal::*;
-use crate::lib::std::ops::{RangeFrom, RangeTo};
+use crate::lib::std::ops::{Range, RangeFrom, RangeTo};
use crate::sequence::{pair, tuple};
-use crate::traits::{AsChar, InputIter, InputLength, InputTakeAtPosition};
-use crate::traits::{Offset, Slice};
+use crate::traits::{
+ AsBytes, AsChar, Compare, InputIter, InputLength, InputTake, InputTakeAtPosition, Offset, Slice,
+};
+
+#[doc(hidden)]
+macro_rules! map(
+ // Internal parser, do not use directly
+ (__impl $i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
+ $crate::combinator::map(move |i| {$submac!(i, $($args)*)}, $g).parse($i)
+ );
+ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
+ map!(__impl $i, $submac!($($args)*), $g)
+ );
+ ($i:expr, $f:expr, $g:expr) => (
+ map!(__impl $i, call!($f), $g)
+ );
+);
+
+#[doc(hidden)]
+macro_rules! call (
+ ($i:expr, $fun:expr) => ( $fun( $i ) );
+ ($i:expr, $fun:expr, $($args:expr),* ) => ( $fun( $i, $($args),* ) );
+);
/// Recognizes an unsigned 1 byte integer.
///
@@ -1378,7 +1400,6 @@ pub fn hex_u32<'a, E: ParseError<&'a [u8]>>(input: &'a [u8]) -> IResult<&'a [u8]
/// assert_eq!(parser("123K-01"), Ok(("K-01", "123")));
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Char))));
/// ```
-#[allow(unused_imports)]
#[rustfmt::skip]
pub fn recognize_float<T, E:ParseError<T>>(input: T) -> IResult<T, T, E>
where
@@ -1405,48 +1426,100 @@ where
)(input)
}
-/// Recognizes floating point number in a byte string and returns a f32.
+/// Recognizes a floating point number in text format and returns the integer, fraction and exponent parts of the input data
///
/// *Complete version*: Can parse until the end of input.
-/// ```rust
-/// # use nom::{Err, error::ErrorKind, Needed};
-/// # use nom::Needed::Size;
-/// use nom::number::complete::float;
///
-/// let parser = |s| {
-/// float(s)
-/// };
-///
-/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
-/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
-/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
-/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Char))));
-/// ```
-#[cfg(not(feature = "lexical"))]
-pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
+pub fn recognize_float_parts<T, E: ParseError<T>>(input: T) -> IResult<T, (bool, T, T, i32), E>
where
- T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
+ T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
T: Clone + Offset,
- T: InputIter + InputLength + crate::traits::ParseTo<f32>,
- <T as InputIter>::Item: AsChar,
- T: InputTakeAtPosition,
+ T: InputIter + InputTake,
+ <T as InputIter>::Item: AsChar + Copy,
+ T: InputTakeAtPosition + InputLength,
<T as InputTakeAtPosition>::Item: AsChar,
+ T: for<'a> Compare<&'a [u8]>,
+ T: AsBytes,
{
- match recognize_float(input) {
- Err(e) => Err(e),
- Ok((i, s)) => match s.parse_to() {
- Some(n) => Ok((i, n)),
- None => Err(Err::Error(E::from_error_kind(i, ErrorKind::Float))),
- },
+ let (i, sign) = sign(input.clone())?;
+
+ //let (i, zeroes) = take_while(|c: <T as InputTakeAtPosition>::Item| c.as_char() == '0')(i)?;
+ let (i, zeroes) = match i.as_bytes().iter().position(|c| *c != b'0' as u8) {
+ Some(index) => i.take_split(index),
+ None => i.take_split(i.input_len()),
+ };
+ //let (i, mut integer) = digit0(i)?;
+ let (i, mut integer) = match i
+ .as_bytes()
+ .iter()
+ .position(|c| !(*c >= b'0' as u8 && *c <= b'9' as u8))
+ {
+ Some(index) => i.take_split(index),
+ None => i.take_split(i.input_len()),
+ };
+
+ if integer.input_len() == 0 && zeroes.input_len() > 0 {
+ // keep the last zero if integer is empty
+ integer = zeroes.slice(zeroes.input_len() - 1..);
}
+
+ let (i, opt_dot) = opt(tag(&b"."[..]))(i)?;
+ let (i, fraction) = if opt_dot.is_none() {
+ let i2 = i.clone();
+ (i2, i.slice(..0))
+ } else {
+ // match number, trim right zeroes
+ let mut zero_count = 0usize;
+ let mut position = None;
+ for (pos, c) in i.as_bytes().iter().enumerate() {
+ if *c >= b'0' as u8 && *c <= b'9' as u8 {
+ if *c == b'0' as u8 {
+ zero_count += 1;
+ } else {
+ zero_count = 0;
+ }
+ } else {
+ position = Some(pos);
+ break;
+ }
+ }
+
+ let position = position.unwrap_or(i.input_len());
+
+ let index = if zero_count == 0 {
+ position
+ } else if zero_count == position {
+ position - zero_count + 1
+ } else {
+ position - zero_count
+ };
+
+ (i.slice(position..), i.slice(..index))
+ };
+
+ if integer.input_len() == 0 && fraction.input_len() == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)));
+ }
+
+ let i2 = i.clone();
+ let (i, e) = match i.as_bytes().iter().next() {
+ Some(b'e') => (i.slice(1..), true),
+ Some(b'E') => (i.slice(1..), true),
+ _ => (i, false),
+ };
+
+ let (i, exp) = if e {
+ cut(crate::character::complete::i32)(i)?
+ } else {
+ (i2, 0)
+ };
+
+ Ok((i, (sign, integer, fraction, exp)))
}
-/// Recognizes floating point number in a byte string and returns a f32.
+/// Recognizes floating point number in text format and returns a f32.
///
/// *Complete version*: Can parse until the end of input.
-///
-/// This function uses the `lexical-core` crate for float parsing by default, you
-/// can deactivate it by removing the "lexical" feature.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
@@ -1456,87 +1529,78 @@ where
/// float(s)
/// };
///
-/// assert_eq!(parser("1.1"), Ok(("", 1.1)));
+/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
/// ```
-#[cfg(feature = "lexical")]
pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
where
- T: crate::traits::AsBytes + InputLength + Slice<RangeFrom<usize>>,
+ T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
+ T: Clone + Offset,
+ T: InputIter + InputLength + InputTake,
+ <T as InputIter>::Item: AsChar + Copy,
+ <T as InputIter>::IterElem: Clone,
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+ T: AsBytes,
+ T: for<'a> Compare<&'a [u8]>,
{
- match ::lexical_core::parse_partial(input.as_bytes()) {
- Ok((value, processed)) => Ok((input.slice(processed..), value)),
- Err(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float))),
+ let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?;
+
+ let mut float: f32 = minimal_lexical::parse_float(
+ integer.as_bytes().iter(),
+ fraction.as_bytes().iter(),
+ exponent,
+ );
+ if !sign {
+ float = -float;
}
+
+ Ok((i, float))
}
-/// Recognizes floating point number in a byte string and returns a f64.
+/// Recognizes floating point number in text format and returns a f32.
///
/// *Complete version*: Can parse until the end of input.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
-/// use nom::number::complete::double;
+/// use nom::number::complete::float;
///
/// let parser = |s| {
-/// double(s)
+/// float(s)
/// };
///
/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
-/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Char))));
+/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
/// ```
-#[cfg(not(feature = "lexical"))]
pub fn double<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
where
- T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
+ T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Slice<Range<usize>>,
T: Clone + Offset,
- T: InputIter + InputLength + crate::traits::ParseTo<f64>,
- <T as InputIter>::Item: AsChar,
+ T: InputIter + InputLength + InputTake,
+ <T as InputIter>::Item: AsChar + Copy,
+ <T as InputIter>::IterElem: Clone,
T: InputTakeAtPosition,
<T as InputTakeAtPosition>::Item: AsChar,
+ T: AsBytes,
+ T: for<'a> Compare<&'a [u8]>,
{
- match recognize_float(input) {
- Err(e) => Err(e),
- Ok((i, s)) => match s.parse_to() {
- Some(n) => Ok((i, n)),
- None => Err(Err::Error(E::from_error_kind(i, ErrorKind::Float))),
- },
- }
-}
+ let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?;
-/// Recognizes floating point number in a byte string and returns a f64.
-///
-/// *Complete version*: Can parse until the end of input.
-///
-/// This function uses the `lexical-core` crate for float parsing by default, you
-/// can deactivate it by removing the "lexical" feature.
-/// ```rust
-/// # use nom::{Err, error::ErrorKind, Needed};
-/// # use nom::Needed::Size;
-/// use nom::number::complete::double;
-///
-/// let parser = |s| {
-/// double(s)
-/// };
-///
-/// assert_eq!(parser("1.1"), Ok(("", 1.1)));
-/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
-/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
-/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
-/// ```
-#[cfg(feature = "lexical")]
-pub fn double<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
-where
- T: crate::traits::AsBytes + InputLength + Slice<RangeFrom<usize>>,
-{
- match ::lexical_core::parse_partial(input.as_bytes()) {
- Ok((value, processed)) => Ok((input.slice(processed..), value)),
- Err(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float))),
+ let mut float: f64 = minimal_lexical::parse_float(
+ integer.as_bytes().iter(),
+ fraction.as_bytes().iter(),
+ exponent,
+ );
+ if !sign {
+ float = -float;
}
+
+ Ok((i, float))
}
#[cfg(test)]
@@ -1544,6 +1608,8 @@ mod tests {
use super::*;
use crate::error::ErrorKind;
use crate::internal::Err;
+ use crate::traits::ParseTo;
+ use proptest::prelude::*;
macro_rules! assert_parse(
($left: expr, $right: expr) => {
@@ -1900,4 +1966,113 @@ mod tests {
Err(Err::Failure(("", ErrorKind::Digit)))
);
}
+
+ #[test]
+ fn configurable_endianness() {
+ use crate::number::Endianness;
+
+ fn be_tst16(i: &[u8]) -> IResult<&[u8], u16> {
+ u16(Endianness::Big)(i)
+ }
+ fn le_tst16(i: &[u8]) -> IResult<&[u8], u16> {
+ u16(Endianness::Little)(i)
+ }
+ assert_eq!(be_tst16(&[0x80, 0x00]), Ok((&b""[..], 32_768_u16)));
+ assert_eq!(le_tst16(&[0x80, 0x00]), Ok((&b""[..], 128_u16)));
+
+ fn be_tst32(i: &[u8]) -> IResult<&[u8], u32> {
+ u32(Endianness::Big)(i)
+ }
+ fn le_tst32(i: &[u8]) -> IResult<&[u8], u32> {
+ u32(Endianness::Little)(i)
+ }
+ assert_eq!(
+ be_tst32(&[0x12, 0x00, 0x60, 0x00]),
+ Ok((&b""[..], 302_014_464_u32))
+ );
+ assert_eq!(
+ le_tst32(&[0x12, 0x00, 0x60, 0x00]),
+ Ok((&b""[..], 6_291_474_u32))
+ );
+
+ fn be_tst64(i: &[u8]) -> IResult<&[u8], u64> {
+ u64(Endianness::Big)(i)
+ }
+ fn le_tst64(i: &[u8]) -> IResult<&[u8], u64> {
+ u64(Endianness::Little)(i)
+ }
+ assert_eq!(
+ be_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
+ Ok((&b""[..], 1_297_142_246_100_992_000_u64))
+ );
+ assert_eq!(
+ le_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
+ Ok((&b""[..], 36_028_874_334_666_770_u64))
+ );
+
+ fn be_tsti16(i: &[u8]) -> IResult<&[u8], i16> {
+ i16(Endianness::Big)(i)
+ }
+ fn le_tsti16(i: &[u8]) -> IResult<&[u8], i16> {
+ i16(Endianness::Little)(i)
+ }
+ assert_eq!(be_tsti16(&[0x00, 0x80]), Ok((&b""[..], 128_i16)));
+ assert_eq!(le_tsti16(&[0x00, 0x80]), Ok((&b""[..], -32_768_i16)));
+
+ fn be_tsti32(i: &[u8]) -> IResult<&[u8], i32> {
+ i32(Endianness::Big)(i)
+ }
+ fn le_tsti32(i: &[u8]) -> IResult<&[u8], i32> {
+ i32(Endianness::Little)(i)
+ }
+ assert_eq!(
+ be_tsti32(&[0x00, 0x12, 0x60, 0x00]),
+ Ok((&b""[..], 1_204_224_i32))
+ );
+ assert_eq!(
+ le_tsti32(&[0x00, 0x12, 0x60, 0x00]),
+ Ok((&b""[..], 6_296_064_i32))
+ );
+
+ fn be_tsti64(i: &[u8]) -> IResult<&[u8], i64> {
+ i64(Endianness::Big)(i)
+ }
+ fn le_tsti64(i: &[u8]) -> IResult<&[u8], i64> {
+ i64(Endianness::Little)(i)
+ }
+ assert_eq!(
+ be_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
+ Ok((&b""[..], 71_881_672_479_506_432_i64))
+ );
+ assert_eq!(
+ le_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
+ Ok((&b""[..], 36_028_874_334_732_032_i64))
+ );
+ }
+
+ fn parse_f64(i: &str) -> IResult<&str, f64, ()> {
+ match recognize_float(i) {
+ Err(e) => Err(e),
+ Ok((i, s)) => {
+ if s.is_empty() {
+ return Err(Err::Error(()));
+ }
+ match s.parse_to() {
+ Some(n) => Ok((i, n)),
+ None => Err(Err::Error(())),
+ }
+ }
+ }
+ }
+
+ proptest! {
+ #[test]
+ #[cfg(feature = "std")]
+ fn floats(s in "\\PC*") {
+ println!("testing {}", s);
+ let res1 = parse_f64(&s);
+ let res2 = double::<_, ()>(s.as_str());
+ assert_eq!(res1, res2);
+ }
+ }
}
diff --git a/src/number/macros.rs b/src/number/macros.rs
deleted file mode 100644
index 27fdcce..0000000
--- a/src/number/macros.rs
+++ /dev/null
@@ -1,265 +0,0 @@
-//! Parsers recognizing numbers
-
-/// If the parameter is `nom::number::Endianness::Big`, parse a big endian u16 integer,
-/// otherwise a little endian u16 integer.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// use nom::number::Endianness;
-///
-/// # fn main() {
-/// named!(be<u16>, u16!(Endianness::Big));
-///
-/// assert_eq!(be(b"\x00\x01abcd"), Ok((&b"abcd"[..], 0x0001)));
-/// assert_eq!(be(b"\x01"), Err(Err::Incomplete(Needed::new(1))));
-///
-/// named!(le<u16>, u16!(Endianness::Little));
-///
-/// assert_eq!(le(b"\x00\x01abcd"), Ok((&b"abcd"[..], 0x0100)));
-/// assert_eq!(le(b"\x01"), Err(Err::Incomplete(Needed::new(1))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! u16 ( ($i:expr, $e:expr) => ( {if $crate::number::Endianness::Big == $e { $crate::number::streaming::be_u16($i) } else { $crate::number::streaming::le_u16($i) } } ););
-
-/// If the parameter is `nom::number::Endianness::Big`, parse a big endian u32 integer,
-/// otherwise a little endian u32 integer.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// use nom::number::Endianness;
-///
-/// # fn main() {
-/// named!(be<u32>, u32!(Endianness::Big));
-///
-/// assert_eq!(be(b"\x00\x01\x02\x03abcd"), Ok((&b"abcd"[..], 0x00010203)));
-/// assert_eq!(be(b"\x01"), Err(Err::Incomplete(Needed::new(3))));
-///
-/// named!(le<u32>, u32!(Endianness::Little));
-///
-/// assert_eq!(le(b"\x00\x01\x02\x03abcd"), Ok((&b"abcd"[..], 0x03020100)));
-/// assert_eq!(le(b"\x01"), Err(Err::Incomplete(Needed::new(3))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! u32 ( ($i:expr, $e:expr) => ( {if $crate::number::Endianness::Big == $e { $crate::number::streaming::be_u32($i) } else { $crate::number::streaming::le_u32($i) } } ););
-
-/// If the parameter is `nom::number::Endianness::Big`, parse a big endian u64 integer,
-/// otherwise a little endian u64 integer.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// use nom::number::Endianness;
-///
-/// # fn main() {
-/// named!(be<u64>, u64!(Endianness::Big));
-///
-/// assert_eq!(be(b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"), Ok((&b"abcd"[..], 0x0001020304050607)));
-/// assert_eq!(be(b"\x01"), Err(Err::Incomplete(Needed::new(7))));
-///
-/// named!(le<u64>, u64!(Endianness::Little));
-///
-/// assert_eq!(le(b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"), Ok((&b"abcd"[..], 0x0706050403020100)));
-/// assert_eq!(le(b"\x01"), Err(Err::Incomplete(Needed::new(7))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! u64 ( ($i:expr, $e:expr) => ( {if $crate::number::Endianness::Big == $e { $crate::number::streaming::be_u64($i) } else { $crate::number::streaming::le_u64($i) } } ););
-
-/// If the parameter is `nom::number::Endianness::Big`, parse a big endian u128 integer,
-/// otherwise a little endian u128 integer.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// use nom::number::Endianness;
-///
-/// # fn main() {
-/// named!(be<u128>, u128!(Endianness::Big));
-///
-/// assert_eq!(be(b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"), Ok((&b"abcd"[..], 0x00010203040506070809101112131415)));
-/// assert_eq!(be(b"\x01"), Err(Err::Incomplete(Needed::new(15))));
-///
-/// named!(le<u128>, u128!(Endianness::Little));
-///
-/// assert_eq!(le(b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"), Ok((&b"abcd"[..], 0x15141312111009080706050403020100)));
-/// assert_eq!(le(b"\x01"), Err(Err::Incomplete(Needed::new(15))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-#[cfg(stable_i128)]
-macro_rules! u128 ( ($i:expr, $e:expr) => ( {if $crate::number::Endianness::Big == $e { $crate::number::streaming::be_u128($i) } else { $crate::number::streaming::le_u128($i) } } ););
-
-/// If the parameter is `nom::number::Endianness::Big`, parse a big endian i16 integer,
-/// otherwise a little endian i16 integer.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// use nom::number::Endianness;
-///
-/// # fn main() {
-/// named!(be<i16>, i16!(Endianness::Big));
-///
-/// assert_eq!(be(b"\x00\x01abcd"), Ok((&b"abcd"[..], 0x0001)));
-/// assert_eq!(be(b"\x01"), Err(Err::Incomplete(Needed::new(1))));
-///
-/// named!(le<i16>, i16!(Endianness::Little));
-///
-/// assert_eq!(le(b"\x00\x01abcd"), Ok((&b"abcd"[..], 0x0100)));
-/// assert_eq!(le(b"\x01"), Err(Err::Incomplete(Needed::new(1))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! i16 ( ($i:expr, $e:expr) => ( {if $crate::number::Endianness::Big == $e { $crate::number::streaming::be_i16($i) } else { $crate::number::streaming::le_i16($i) } } ););
-
-/// If the parameter is `nom::number::Endianness::Big`, parse a big endian i32 integer,
-/// otherwise a little endian i32 integer.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// use nom::number::Endianness;
-///
-/// # fn main() {
-/// named!(be<i32>, i32!(Endianness::Big));
-///
-/// assert_eq!(be(b"\x00\x01\x02\x03abcd"), Ok((&b"abcd"[..], 0x00010203)));
-/// assert_eq!(be(b"\x01"), Err(Err::Incomplete(Needed::new(3))));
-///
-/// named!(le<i32>, i32!(Endianness::Little));
-///
-/// assert_eq!(le(b"\x00\x01\x02\x03abcd"), Ok((&b"abcd"[..], 0x03020100)));
-/// assert_eq!(le(b"\x01"), Err(Err::Incomplete(Needed::new(3))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! i32 ( ($i:expr, $e:expr) => ( {if $crate::number::Endianness::Big == $e { $crate::number::streaming::be_i32($i) } else { $crate::number::streaming::le_i32($i) } } ););
-
-/// If the parameter is `nom::number::Endianness::Big`, parse a big endian i64 integer,
-/// otherwise a little endian i64 integer.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// use nom::number::Endianness;
-///
-/// # fn main() {
-/// named!(be<i64>, i64!(Endianness::Big));
-///
-/// assert_eq!(be(b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"), Ok((&b"abcd"[..], 0x0001020304050607)));
-/// assert_eq!(be(b"\x01"), Err(Err::Incomplete(Needed::new(7))));
-///
-/// named!(le<i64>, i64!(Endianness::Little));
-///
-/// assert_eq!(le(b"\x00\x01\x02\x03\x04\x05\x06\x07abcd"), Ok((&b"abcd"[..], 0x0706050403020100)));
-/// assert_eq!(le(b"\x01"), Err(Err::Incomplete(Needed::new(7))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! i64 ( ($i:expr, $e:expr) => ( {if $crate::number::Endianness::Big == $e { $crate::number::streaming::be_i64($i) } else { $crate::number::streaming::le_i64($i) } } ););
-
-/// If the parameter is `nom::number::Endianness::Big`, parse a big endian i64 integer,
-/// otherwise a little endian i64 integer.
-///
-/// ```rust
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err, Needed};
-/// use nom::number::Endianness;
-///
-/// # fn main() {
-/// named!(be<i128>, i128!(Endianness::Big));
-///
-/// assert_eq!(be(b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"), Ok((&b"abcd"[..], 0x00010203040506070809101112131415)));
-/// assert_eq!(be(b"\x01"), Err(Err::Incomplete(Needed::new(15))));
-///
-/// named!(le<i128>, i128!(Endianness::Little));
-///
-/// assert_eq!(le(b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15abcd"), Ok((&b"abcd"[..], 0x15141312111009080706050403020100)));
-/// assert_eq!(le(b"\x01"), Err(Err::Incomplete(Needed::new(15))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-#[cfg(stable_i128)]
-macro_rules! i128 ( ($i:expr, $e:expr) => ( {if $crate::number::Endianness::Big == $e { $crate::number::streaming::be_i128($i) } else { $crate::number::streaming::le_i128($i) } } ););
-
-#[cfg(test)]
-mod tests {
- use crate::number::Endianness;
-
- #[test]
- fn configurable_endianness() {
- named!(be_tst16<u16>, u16!(Endianness::Big));
- named!(le_tst16<u16>, u16!(Endianness::Little));
- assert_eq!(be_tst16(&[0x80, 0x00]), Ok((&b""[..], 32_768_u16)));
- assert_eq!(le_tst16(&[0x80, 0x00]), Ok((&b""[..], 128_u16)));
-
- named!(be_tst32<u32>, u32!(Endianness::Big));
- named!(le_tst32<u32>, u32!(Endianness::Little));
- assert_eq!(
- be_tst32(&[0x12, 0x00, 0x60, 0x00]),
- Ok((&b""[..], 302_014_464_u32))
- );
- assert_eq!(
- le_tst32(&[0x12, 0x00, 0x60, 0x00]),
- Ok((&b""[..], 6_291_474_u32))
- );
-
- named!(be_tst64<u64>, u64!(Endianness::Big));
- named!(le_tst64<u64>, u64!(Endianness::Little));
- assert_eq!(
- be_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
- Ok((&b""[..], 1_297_142_246_100_992_000_u64))
- );
- assert_eq!(
- le_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
- Ok((&b""[..], 36_028_874_334_666_770_u64))
- );
-
- named!(be_tsti16<i16>, i16!(Endianness::Big));
- named!(le_tsti16<i16>, i16!(Endianness::Little));
- assert_eq!(be_tsti16(&[0x00, 0x80]), Ok((&b""[..], 128_i16)));
- assert_eq!(le_tsti16(&[0x00, 0x80]), Ok((&b""[..], -32_768_i16)));
-
- named!(be_tsti32<i32>, i32!(Endianness::Big));
- named!(le_tsti32<i32>, i32!(Endianness::Little));
- assert_eq!(
- be_tsti32(&[0x00, 0x12, 0x60, 0x00]),
- Ok((&b""[..], 1_204_224_i32))
- );
- assert_eq!(
- le_tsti32(&[0x00, 0x12, 0x60, 0x00]),
- Ok((&b""[..], 6_296_064_i32))
- );
-
- named!(be_tsti64<i64>, i64!(Endianness::Big));
- named!(le_tsti64<i64>, i64!(Endianness::Little));
- assert_eq!(
- be_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
- Ok((&b""[..], 71_881_672_479_506_432_i64))
- );
- assert_eq!(
- le_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
- Ok((&b""[..], 36_028_874_334_732_032_i64))
- );
- }
-
- //FIXME
- /*
- #[test]
- #[cfg(feature = "std")]
- fn manual_configurable_endianness_test() {
- let x = 1;
- let int_parse: Box<Fn(&[u8]) -> IResult<&[u8], u16, (&[u8], ErrorKind)>> = if x == 2 {
- Box::new(be_u16)
- } else {
- Box::new(le_u16)
- };
- println!("{:?}", int_parse(&b"3"[..]));
- assert_eq!(int_parse(&[0x80, 0x00]), Ok((&b""[..], 128_u16)));
- }
- */
-}
diff --git a/src/number/mod.rs b/src/number/mod.rs
index 6ab2cd5..58c3d51 100644
--- a/src/number/mod.rs
+++ b/src/number/mod.rs
@@ -1,8 +1,5 @@
//! Parsers recognizing numbers
-#[macro_use]
-mod macros;
-
pub mod complete;
pub mod streaming;
diff --git a/src/number/streaming.rs b/src/number/streaming.rs
index f502519..3ca445f 100644
--- a/src/number/streaming.rs
+++ b/src/number/streaming.rs
@@ -1,14 +1,36 @@
//! Parsers recognizing numbers, streaming version
use crate::branch::alt;
-use crate::character::streaming::{char, digit1};
+use crate::bytes::streaming::tag;
+use crate::character::streaming::{char, digit1, sign};
use crate::combinator::{cut, map, opt, recognize};
use crate::error::{ErrorKind, ParseError};
use crate::internal::*;
use crate::lib::std::ops::{RangeFrom, RangeTo};
use crate::sequence::{pair, tuple};
-use crate::traits::{AsChar, InputIter, InputLength, InputTakeAtPosition};
-use crate::traits::{Offset, Slice};
+use crate::traits::{
+ AsBytes, AsChar, Compare, InputIter, InputLength, InputTake, InputTakeAtPosition, Offset, Slice,
+};
+
+#[doc(hidden)]
+macro_rules! map(
+ // Internal parser, do not use directly
+ (__impl $i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
+ $crate::combinator::map(move |i| {$submac!(i, $($args)*)}, $g).parse($i)
+ );
+ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
+ map!(__impl $i, $submac!($($args)*), $g)
+ );
+ ($i:expr, $f:expr, $g:expr) => (
+ map!(__impl $i, call!($f), $g)
+ );
+);
+
+#[doc(hidden)]
+macro_rules! call (
+ ($i:expr, $fun:expr) => ( $fun( $i ) );
+ ($i:expr, $fun:expr, $($args:expr),* ) => ( $fun( $i, $($args),* ) );
+);
/// Recognizes an unsigned 1 byte integer.
///
@@ -1347,7 +1369,6 @@ pub fn hex_u32<'a, E: ParseError<&'a [u8]>>(input: &'a [u8]) -> IResult<&'a [u8]
/// assert_eq!(parser("123K-01"), Ok(("K-01", "123")));
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Char))));
/// ```
-#[allow(unused_imports)]
#[rustfmt::skip]
pub fn recognize_float<T, E:ParseError<T>>(input: T) -> IResult<T, T, E>
where
@@ -1374,146 +1395,187 @@ where
)(input)
}
-/// Recognizes floating point number in a byte string and returns a `f32`.
-///
-/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if it reaches the end of input.
-/// ```rust
-/// # use nom::{Err, error::ErrorKind, Needed};
-/// use nom::number::streaming::float;
+/// Recognizes a floating point number in text format and returns the integer, fraction and exponent parts of the input data
///
-/// let parser = |s| {
-/// float(s)
-/// };
+/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there is not enough data.
///
-/// assert_eq!(parser("11e-1;"), Ok((";", 1.1)));
-/// assert_eq!(parser("123E-02;"), Ok((";", 1.23)));
-/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
-/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Char))));
-/// ```
-#[cfg(not(feature = "lexical"))]
-pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
+pub fn recognize_float_parts<T, E: ParseError<T>>(input: T) -> IResult<T, (bool, T, T, i32), E>
where
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
T: Clone + Offset,
- T: InputIter + InputLength + crate::traits::ParseTo<f32>,
+ T: InputIter + crate::traits::ParseTo<i32>,
<T as InputIter>::Item: AsChar,
- T: InputTakeAtPosition,
+ T: InputTakeAtPosition + InputTake + InputLength,
<T as InputTakeAtPosition>::Item: AsChar,
+ T: for<'a> Compare<&'a [u8]>,
+ T: AsBytes,
{
- match recognize_float(input) {
- Err(e) => Err(e),
- Ok((i, s)) => match s.parse_to() {
- Some(n) => Ok((i, n)),
- None => Err(Err::Error(E::from_error_kind(i, ErrorKind::Float))),
- },
+ let (i, sign) = sign(input.clone())?;
+
+ //let (i, zeroes) = take_while(|c: <T as InputTakeAtPosition>::Item| c.as_char() == '0')(i)?;
+ let (i, zeroes) = match i.as_bytes().iter().position(|c| *c != b'0' as u8) {
+ Some(index) => i.take_split(index),
+ None => i.take_split(i.input_len()),
+ };
+
+ //let (i, mut integer) = digit0(i)?;
+ let (i, mut integer) = match i
+ .as_bytes()
+ .iter()
+ .position(|c| !(*c >= b'0' as u8 && *c <= b'9' as u8))
+ {
+ Some(index) => i.take_split(index),
+ None => i.take_split(i.input_len()),
+ };
+
+ if integer.input_len() == 0 && zeroes.input_len() > 0 {
+ // keep the last zero if integer is empty
+ integer = zeroes.slice(zeroes.input_len() - 1..);
}
-}
-/// Recognizes floating point number in a byte string and returns a `f32`.
-///
-/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if it reaches the end of input.
-/// ```rust
-/// # use nom::{Err, error::ErrorKind, Needed};
-/// use nom::number::streaming::float;
-///
-/// let parser = |s| {
-/// float(s)
-/// };
-///
-/// assert_eq!(parser("11e-1;"), Ok((";", 1.1)));
-/// assert_eq!(parser("123E-02;"), Ok((";", 1.23)));
-/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
-/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
-/// ```
-///
-/// this function uses the lexical-core crate for float parsing by default, you
-/// can deactivate it by removing the "lexical" feature
-#[cfg(feature = "lexical")]
-pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
-where
- T: crate::traits::AsBytes + InputLength + Slice<RangeFrom<usize>>,
-{
- match ::lexical_core::parse_partial(input.as_bytes()) {
- Ok((value, processed)) => {
- if processed == input.input_len() {
- Err(Err::Incomplete(Needed::Unknown))
+ let (i, opt_dot) = opt(tag(&b"."[..]))(i)?;
+ let (i, fraction) = if opt_dot.is_none() {
+ let i2 = i.clone();
+ (i2, i.slice(..0))
+ } else {
+ // match number, trim right zeroes
+ let mut zero_count = 0usize;
+ let mut position = None;
+ for (pos, c) in i.as_bytes().iter().enumerate() {
+ if *c >= b'0' as u8 && *c <= b'9' as u8 {
+ if *c == b'0' as u8 {
+ zero_count += 1;
+ } else {
+ zero_count = 0;
+ }
} else {
- Ok((input.slice(processed..), value))
+ position = Some(pos);
+ break;
}
}
- Err(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float))),
+
+ let position = match position {
+ Some(p) => p,
+ None => return Err(Err::Incomplete(Needed::new(1))),
+ };
+
+ let index = if zero_count == 0 {
+ position
+ } else if zero_count == position {
+ position - zero_count + 1
+ } else {
+ position - zero_count
+ };
+
+ (i.slice(position..), i.slice(..index))
+ };
+
+ if integer.input_len() == 0 && fraction.input_len() == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)));
}
+
+ let i2 = i.clone();
+ let (i, e) = match i.as_bytes().iter().next() {
+ Some(b'e') => (i.slice(1..), true),
+ Some(b'E') => (i.slice(1..), true),
+ _ => (i, false),
+ };
+
+ let (i, exp) = if e {
+ cut(crate::character::streaming::i32)(i)?
+ } else {
+ (i2, 0)
+ };
+
+ Ok((i, (sign, integer, fraction, exp)))
}
-/// Recognizes floating point number in a byte string and returns a `f64`.
+/// Recognizes floating point number in text format and returns a f32.
+///
+/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there is not enough data.
///
-/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if it reaches the end of input.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
-/// use nom::number::streaming::double;
+/// # use nom::Needed::Size;
+/// use nom::number::complete::float;
///
/// let parser = |s| {
-/// double(s)
+/// float(s)
/// };
///
-/// assert_eq!(parser("11e-1;"), Ok((";", 1.1)));
-/// assert_eq!(parser("123E-02;"), Ok((";", 1.23)));
+/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
+/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
-/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Char))));
+/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
/// ```
-#[cfg(not(feature = "lexical"))]
-pub fn double<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
+pub fn float<T, E: ParseError<T>>(input: T) -> IResult<T, f32, E>
where
T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
T: Clone + Offset,
- T: InputIter + InputLength + crate::traits::ParseTo<f64>,
+ T: InputIter + InputLength + InputTake + crate::traits::ParseTo<i32>,
<T as InputIter>::Item: AsChar,
+ <T as InputIter>::IterElem: Clone,
T: InputTakeAtPosition,
<T as InputTakeAtPosition>::Item: AsChar,
+ T: AsBytes,
+ T: for<'a> Compare<&'a [u8]>,
{
- match recognize_float(input) {
- Err(e) => Err(e),
- Ok((i, s)) => match s.parse_to() {
- Some(n) => Ok((i, n)),
- None => Err(Err::Error(E::from_error_kind(i, ErrorKind::Float))),
- },
+ let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?;
+
+ let mut float: f32 = minimal_lexical::parse_float(
+ integer.as_bytes().iter(),
+ fraction.as_bytes().iter(),
+ exponent,
+ );
+ if !sign {
+ float = -float;
}
+
+ Ok((i, float))
}
-/// Recognizes floating point number in a byte string and returns a `f64`.
+/// Recognizes floating point number in text format and returns a f32.
+///
+/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there is not enough data.
///
-/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if it reaches the end of input.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
-/// use nom::number::streaming::double;
+/// # use nom::Needed::Size;
+/// use nom::number::complete::float;
///
/// let parser = |s| {
-/// double(s)
+/// float(s)
/// };
///
-/// assert_eq!(parser("11e-1;"), Ok((";", 1.1)));
-/// assert_eq!(parser("123E-02;"), Ok((";", 1.23)));
+/// assert_eq!(parser("11e-1"), Ok(("", 1.1)));
+/// assert_eq!(parser("123E-02"), Ok(("", 1.23)));
/// assert_eq!(parser("123K-01"), Ok(("K-01", 123.0)));
/// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::Float))));
/// ```
-///
-/// this function uses the lexical-core crate for float parsing by default, you
-/// can deactivate it by removing the "lexical" feature
-#[cfg(feature = "lexical")]
pub fn double<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
where
- T: crate::traits::AsBytes + InputLength + Slice<RangeFrom<usize>>,
+ T: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
+ T: Clone + Offset,
+ T: InputIter + InputLength + InputTake + crate::traits::ParseTo<i32>,
+ <T as InputIter>::Item: AsChar,
+ <T as InputIter>::IterElem: Clone,
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+ T: AsBytes,
+ T: for<'a> Compare<&'a [u8]>,
{
- match ::lexical_core::parse_partial(input.as_bytes()) {
- Ok((value, processed)) => {
- if processed == input.input_len() {
- Err(Err::Incomplete(Needed::Unknown))
- } else {
- Ok((input.slice(processed..), value))
- }
- }
- Err(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float))),
+ let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?;
+
+ let mut float: f64 = minimal_lexical::parse_float(
+ integer.as_bytes().iter(),
+ fraction.as_bytes().iter(),
+ exponent,
+ );
+ if !sign {
+ float = -float;
}
+
+ Ok((i, float))
}
#[cfg(test)]
@@ -1521,6 +1583,8 @@ mod tests {
use super::*;
use crate::error::ErrorKind;
use crate::internal::{Err, Needed};
+ use crate::traits::ParseTo;
+ use proptest::prelude::*;
macro_rules! assert_parse(
($left: expr, $right: expr) => {
@@ -1983,4 +2047,113 @@ mod tests {
Err(Err::Incomplete(Needed::new(1)))
);
}
+
+ #[test]
+ fn configurable_endianness() {
+ use crate::number::Endianness;
+
+ fn be_tst16(i: &[u8]) -> IResult<&[u8], u16> {
+ u16(Endianness::Big)(i)
+ }
+ fn le_tst16(i: &[u8]) -> IResult<&[u8], u16> {
+ u16(Endianness::Little)(i)
+ }
+ assert_eq!(be_tst16(&[0x80, 0x00]), Ok((&b""[..], 32_768_u16)));
+ assert_eq!(le_tst16(&[0x80, 0x00]), Ok((&b""[..], 128_u16)));
+
+ fn be_tst32(i: &[u8]) -> IResult<&[u8], u32> {
+ u32(Endianness::Big)(i)
+ }
+ fn le_tst32(i: &[u8]) -> IResult<&[u8], u32> {
+ u32(Endianness::Little)(i)
+ }
+ assert_eq!(
+ be_tst32(&[0x12, 0x00, 0x60, 0x00]),
+ Ok((&b""[..], 302_014_464_u32))
+ );
+ assert_eq!(
+ le_tst32(&[0x12, 0x00, 0x60, 0x00]),
+ Ok((&b""[..], 6_291_474_u32))
+ );
+
+ fn be_tst64(i: &[u8]) -> IResult<&[u8], u64> {
+ u64(Endianness::Big)(i)
+ }
+ fn le_tst64(i: &[u8]) -> IResult<&[u8], u64> {
+ u64(Endianness::Little)(i)
+ }
+ assert_eq!(
+ be_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
+ Ok((&b""[..], 1_297_142_246_100_992_000_u64))
+ );
+ assert_eq!(
+ le_tst64(&[0x12, 0x00, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
+ Ok((&b""[..], 36_028_874_334_666_770_u64))
+ );
+
+ fn be_tsti16(i: &[u8]) -> IResult<&[u8], i16> {
+ i16(Endianness::Big)(i)
+ }
+ fn le_tsti16(i: &[u8]) -> IResult<&[u8], i16> {
+ i16(Endianness::Little)(i)
+ }
+ assert_eq!(be_tsti16(&[0x00, 0x80]), Ok((&b""[..], 128_i16)));
+ assert_eq!(le_tsti16(&[0x00, 0x80]), Ok((&b""[..], -32_768_i16)));
+
+ fn be_tsti32(i: &[u8]) -> IResult<&[u8], i32> {
+ i32(Endianness::Big)(i)
+ }
+ fn le_tsti32(i: &[u8]) -> IResult<&[u8], i32> {
+ i32(Endianness::Little)(i)
+ }
+ assert_eq!(
+ be_tsti32(&[0x00, 0x12, 0x60, 0x00]),
+ Ok((&b""[..], 1_204_224_i32))
+ );
+ assert_eq!(
+ le_tsti32(&[0x00, 0x12, 0x60, 0x00]),
+ Ok((&b""[..], 6_296_064_i32))
+ );
+
+ fn be_tsti64(i: &[u8]) -> IResult<&[u8], i64> {
+ i64(Endianness::Big)(i)
+ }
+ fn le_tsti64(i: &[u8]) -> IResult<&[u8], i64> {
+ i64(Endianness::Little)(i)
+ }
+ assert_eq!(
+ be_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
+ Ok((&b""[..], 71_881_672_479_506_432_i64))
+ );
+ assert_eq!(
+ le_tsti64(&[0x00, 0xFF, 0x60, 0x00, 0x12, 0x00, 0x80, 0x00]),
+ Ok((&b""[..], 36_028_874_334_732_032_i64))
+ );
+ }
+
+ fn parse_f64(i: &str) -> IResult<&str, f64, ()> {
+ match recognize_float(i) {
+ Err(e) => Err(e),
+ Ok((i, s)) => {
+ if s.is_empty() {
+ return Err(Err::Error(()));
+ }
+ match s.parse_to() {
+ Some(n) => Ok((i, n)),
+ None => Err(Err::Error(())),
+ }
+ }
+ }
+ }
+
+ proptest! {
+ #[test]
+ #[cfg(feature = "std")]
+ fn floats(s in "\\PC*") {
+ println!("testing {}", s);
+ let res1 = parse_f64(&s);
+ let res2 = double::<_, ()>(s.as_str());
+ assert_eq!(res1, res2);
+ }
+ }
}
diff --git a/src/regexp/macros.rs b/src/regexp/macros.rs
deleted file mode 100644
index ff84787..0000000
--- a/src/regexp/macros.rs
+++ /dev/null
@@ -1,409 +0,0 @@
-/// `re_match!(regexp) => &[T] -> IResult<&[T], &[T]>`
-/// Returns the whole input if a match is found.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "regexp")))]
-macro_rules! re_match (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::Regex::new($re).unwrap();
- $crate::regexp::str::re_match(r)($i)
- } )
-);
-
-/// `re_bytes_match!(regexp) => &[T] -> IResult<&[T], &[T]>`
-/// Returns the whole input if a match is found.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "regexp")))]
-macro_rules! re_bytes_match (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::bytes::Regex::new($re).unwrap();
- $crate::regexp::bytes::re_match(r)($i)
- } )
-);
-
-/// `re_find!(regexp) => &[T] -> IResult<&[T], &[T]>`
-/// Returns the first match.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "regexp")))]
-macro_rules! re_find (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::Regex::new($re).unwrap();
- $crate::regexp::str::re_find(r)($i)
- } )
-);
-
-/// `re_bytes_find!(regexp) => &[T] -> IResult<&[T], &[T]>`
-/// Returns the first match.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "regexp")))]
-macro_rules! re_bytes_find (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::bytes::Regex::new($re).unwrap();
- $crate::regexp::bytes::re_find(r)($i)
- } )
-);
-
-/// `re_matches!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>`
-/// Returns all the matched parts.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
-)]
-macro_rules! re_matches (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::Regex::new($re).unwrap();
- $crate::regexp::str::re_matches(r)($i)
- } )
-);
-
-/// `re_bytes_matches!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>`
-/// Returns all the matched parts.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
-)]
-macro_rules! re_bytes_matches (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::bytes::Regex::new($re).unwrap();
- $crate::regexp::bytes::re_matches(r)($i)
- } )
-);
-
-/// `re_capture!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>`
-/// Returns the capture groups of the first match.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
-)]
-macro_rules! re_capture (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::Regex::new($re).unwrap();
- $crate::regexp::str::re_capture(r)($i)
- } )
-);
-
-/// `re_bytes_capture!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>`
-/// Returns the capture groups of the first match.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
-)]
-macro_rules! re_bytes_capture (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::bytes::Regex::new($re).unwrap();
- $crate::regexp::bytes::re_capture(r)($i)
- }
- )
-);
-
-/// `re_captures!(regexp) => &[T] -> IResult<&[T], Vec<Vec<&[T]>>>`
-/// Returns the capture groups of all matches.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
-)]
-macro_rules! re_captures (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::Regex::new($re).unwrap();
- $crate::regexp::str::re_captures(r)($i)
- } )
-);
-
-/// `re_bytes_captures!(regexp) => &[T] -> IResult<&[T], Vec<Vec<&[T]>>>`
-/// Returns the capture groups of all matches.
-///
-/// Requires the `regexp` feature.
-#[macro_export(local_inner_macros)]
-#[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
-)]
-macro_rules! re_bytes_captures (
- ($i:expr, $re:expr) => ( {
- let r = $crate::lib::regex::bytes::Regex::new($re).unwrap();
- $crate::regexp::bytes::re_captures(r)($i)
- } )
-);
-
-#[cfg(test)]
-mod tests {
- use crate::error::ErrorKind;
- use crate::internal::Err;
- #[cfg(feature = "alloc")]
- use crate::lib::std::vec::Vec;
-
- #[test]
- fn re_match() {
- named!(rm<&str,&str>, re_match!(r"^\d{4}-\d{2}-\d{2}"));
- assert_eq!(rm("2015-09-07"), Ok(("", "2015-09-07")));
- assert_eq!(
- rm("blah"),
- Err(Err::Error(error_position!(
- &"blah"[..],
- ErrorKind::RegexpMatch
- ),))
- );
- assert_eq!(rm("2015-09-07blah"), Ok(("", "2015-09-07blah")));
- }
-
- #[test]
- fn re_find() {
- named!(rm<&str,&str>, re_find!(r"^\d{4}-\d{2}-\d{2}"));
- assert_eq!(rm("2015-09-07"), Ok(("", "2015-09-07")));
- assert_eq!(
- rm("blah"),
- Err(Err::Error(error_position!(
- &"blah"[..],
- ErrorKind::RegexpFind
- ),))
- );
- assert_eq!(rm("2015-09-07blah"), Ok(("blah", "2015-09-07")));
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_matches() {
- named!(rm< &str,Vec<&str> >, re_matches!(r"\d{4}-\d{2}-\d{2}"));
- assert_eq!(rm("2015-09-07"), Ok(("", vec!["2015-09-07"])));
- assert_eq!(
- rm("blah"),
- Err(Err::Error(error_position!(
- &"blah"[..],
- ErrorKind::RegexpMatches
- )))
- );
- assert_eq!(
- rm("aaa2015-09-07blah2015-09-09pouet"),
- Ok(("pouet", vec!["2015-09-07", "2015-09-09"]))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_capture() {
- named!(rm< &str,Vec<&str> >, re_capture!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))"));
- assert_eq!(
- rm("blah nom 0.3.11pouet"),
- Ok(("pouet", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]))
- );
- assert_eq!(
- rm("blah"),
- Err(Err::Error(error_position!(
- &"blah"[..],
- ErrorKind::RegexpCapture
- )))
- );
- assert_eq!(
- rm("hello nom 0.3.11 world regex 0.1.41"),
- Ok((
- " world regex 0.1.41",
- vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]
- ))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_captures() {
- named!(rm< &str,Vec<Vec<&str>> >, re_captures!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))"));
- assert_eq!(
- rm("blah nom 0.3.11pouet"),
- Ok((
- "pouet",
- vec![vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]]
- ))
- );
- assert_eq!(
- rm("blah"),
- Err(Err::Error(error_position!(
- &"blah"[..],
- ErrorKind::RegexpCapture
- )))
- );
- assert_eq!(
- rm("hello nom 0.3.11 world regex 0.1.41 aaa"),
- Ok((
- " aaa",
- vec![
- vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"],
- vec!["regex 0.1.41", "regex", "0.1.41", "0", "1", "41"],
- ]
- ))
- );
- }
-
- #[test]
- fn re_bytes_match() {
- named!(rm, re_bytes_match!(r"^\d{4}-\d{2}-\d{2}"));
- assert_eq!(rm(&b"2015-09-07"[..]), Ok((&b""[..], &b"2015-09-07"[..])));
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error(error_position!(
- &b"blah"[..],
- ErrorKind::RegexpMatch
- )))
- );
- assert_eq!(
- rm(&b"2015-09-07blah"[..]),
- Ok((&b""[..], &b"2015-09-07blah"[..]))
- );
- }
-
- #[test]
- fn re_bytes_find() {
- named!(rm, re_bytes_find!(r"^\d{4}-\d{2}-\d{2}"));
- assert_eq!(rm(&b"2015-09-07"[..]), Ok((&b""[..], &b"2015-09-07"[..])));
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error(error_position!(
- &b"blah"[..],
- ErrorKind::RegexpFind
- )))
- );
- assert_eq!(
- rm(&b"2015-09-07blah"[..]),
- Ok((&b"blah"[..], &b"2015-09-07"[..]))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_bytes_matches() {
- named!(rm<Vec<&[u8]>>, re_bytes_matches!(r"\d{4}-\d{2}-\d{2}"));
- assert_eq!(
- rm(&b"2015-09-07"[..]),
- Ok((&b""[..], vec![&b"2015-09-07"[..]]))
- );
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error(error_position!(
- &b"blah"[..],
- ErrorKind::RegexpMatches
- )))
- );
- assert_eq!(
- rm(&b"aaa2015-09-07blah2015-09-09pouet"[..]),
- Ok((&b"pouet"[..], vec![&b"2015-09-07"[..], &b"2015-09-09"[..]]))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_bytes_capture() {
- named!(
- rm<Vec<&[u8]>>,
- re_bytes_capture!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")
- );
- assert_eq!(
- rm(&b"blah nom 0.3.11pouet"[..]),
- Ok((
- &b"pouet"[..],
- vec![
- &b"nom 0.3.11"[..],
- &b"nom"[..],
- &b"0.3.11"[..],
- &b"0"[..],
- &b"3"[..],
- &b"11"[..],
- ]
- ))
- );
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error(error_position!(
- &b"blah"[..],
- ErrorKind::RegexpCapture
- )))
- );
- assert_eq!(
- rm(&b"hello nom 0.3.11 world regex 0.1.41"[..]),
- Ok((
- &b" world regex 0.1.41"[..],
- vec![
- &b"nom 0.3.11"[..],
- &b"nom"[..],
- &b"0.3.11"[..],
- &b"0"[..],
- &b"3"[..],
- &b"11"[..],
- ]
- ))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_bytes_captures() {
- named!(
- rm<Vec<Vec<&[u8]>>>,
- re_bytes_captures!(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))")
- );
- assert_eq!(
- rm(&b"blah nom 0.3.11pouet"[..]),
- Ok((
- &b"pouet"[..],
- vec![vec![
- &b"nom 0.3.11"[..],
- &b"nom"[..],
- &b"0.3.11"[..],
- &b"0"[..],
- &b"3"[..],
- &b"11"[..],
- ],]
- ))
- );
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error(error_position!(
- &b"blah"[..],
- ErrorKind::RegexpCapture
- )))
- );
- assert_eq!(
- rm(&b"hello nom 0.3.11 world regex 0.1.41 aaa"[..]),
- Ok((
- &b" aaa"[..],
- vec![
- vec![
- &b"nom 0.3.11"[..],
- &b"nom"[..],
- &b"0.3.11"[..],
- &b"0"[..],
- &b"3"[..],
- &b"11"[..],
- ],
- vec![
- &b"regex 0.1.41"[..],
- &b"regex"[..],
- &b"0.1.41"[..],
- &b"0"[..],
- &b"1"[..],
- &b"41"[..],
- ],
- ]
- ))
- );
- }
-}
diff --git a/src/regexp/mod.rs b/src/regexp/mod.rs
deleted file mode 100644
index b1b856c..0000000
--- a/src/regexp/mod.rs
+++ /dev/null
@@ -1,675 +0,0 @@
-//! Parser combinators that use regular expressions.
-
-mod macros;
-
-///Regular expression parser combinators for strings.
-pub mod str {
- use crate::error::{ErrorKind, ParseError};
- use crate::lib::regex::Regex;
- #[cfg(feature = "alloc")]
- use crate::lib::std::vec::Vec;
- use crate::traits::{InputLength, Slice};
- use crate::{Err, IResult};
-
- /// Compares the input with a regular expression and returns the
- /// whole input if a match is found.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::str::re_match;
- /// # fn main() {
- /// let re = regex::Regex::new(r"^\d{4}").unwrap();
- /// let parser = re_match::<(&str, ErrorKind)>(re);
- /// assert_eq!(parser("2019"), Ok(("", "2019")));
- /// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::RegexpMatch))));
- /// assert_eq!(parser("2019-10"), Ok(("", "2019-10")));
- /// # }
- /// ```
- #[cfg(feature = "regexp")]
- #[cfg_attr(feature = "docsrs", doc(cfg(feature = "regexp")))]
- pub fn re_match<'a, E>(re: Regex) -> impl Fn(&'a str) -> IResult<&'a str, &'a str, E>
- where
- E: ParseError<&'a str>,
- {
- move |i| {
- if re.is_match(i) {
- Ok((i.slice(i.input_len()..), i))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpMatch)))
- }
- }
- }
-
- /// Compares the input with a regular expression and returns all matches in a `Vec`.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::str::re_matches;
- /// # fn main() {
- /// let re = regex::Regex::new(r"a\d").unwrap();
- /// let parser = re_matches::<(&str, ErrorKind)>(re);
- /// assert_eq!(parser("a1ba2"), Ok(("", vec!["a1", "a2"])));
- /// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::RegexpMatches))));
- /// # }
- /// ```
- #[cfg(all(feature = "regexp", feature = "alloc"))]
- #[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
- )]
- pub fn re_matches<'a, E>(re: Regex) -> impl Fn(&'a str) -> IResult<&'a str, Vec<&'a str>, E>
- where
- E: ParseError<&'a str>,
- {
- move |i| {
- let v: Vec<_> = re
- .find_iter(i)
- .map(|m| i.slice(m.start()..m.end()))
- .collect();
- if !v.is_empty() {
- let offset = {
- let end = v.last().unwrap();
- end.as_ptr() as usize + end.len() - i.as_ptr() as usize
- };
- Ok((i.slice(offset..), v))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpMatches)))
- }
- }
- }
-
- /// Compares the input with a regular expression and returns the
- /// first match.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::str::re_find;
- /// # fn main() {
- /// let re = regex::Regex::new(r"\d{4}").unwrap();
- /// let parser = re_find::<(&str, ErrorKind)>(re);
- /// assert_eq!(parser("abc2019"), Ok(("", "2019")));
- /// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::RegexpFind))));
- /// assert_eq!(parser("2019-10"), Ok(("-10", "2019")));
- /// # }
- /// ```
- #[cfg(feature = "regexp")]
- #[cfg_attr(feature = "docsrs", doc(cfg(feature = "regexp")))]
- pub fn re_find<'a, E>(re: Regex) -> impl Fn(&'a str) -> IResult<&'a str, &'a str, E>
- where
- E: ParseError<&'a str>,
- {
- move |i| {
- if let Some(m) = re.find(i) {
- Ok((i.slice(m.end()..), i.slice(m.start()..m.end())))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpFind)))
- }
- }
- }
-
- /// Compares the input with a regular expression and returns
- /// the capture groups of the first match in a `Vec`.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::str::re_capture;
- /// # fn main() {
- /// let re = regex::Regex::new(r"(a)(\d)").unwrap();
- /// let parser = re_capture::<(&str, ErrorKind)>(re);
- /// assert_eq!(parser("a1ba2"), Ok(("ba2", vec!["a1", "a", "1"])));
- /// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::RegexpCapture))));
- /// # }
- /// ```
- #[cfg(all(feature = "regexp", feature = "alloc"))]
- #[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
- )]
- pub fn re_capture<'a, E>(re: Regex) -> impl Fn(&'a str) -> IResult<&'a str, Vec<&'a str>, E>
- where
- E: ParseError<&'a str>,
- {
- move |i| {
- if let Some(c) = re.captures(i) {
- let v: Vec<_> = c
- .iter()
- .filter(|el| el.is_some())
- .map(|el| el.unwrap())
- .map(|m| i.slice(m.start()..m.end()))
- .collect();
- let offset = {
- let end = v.last().unwrap();
- end.as_ptr() as usize + end.len() - i.as_ptr() as usize
- };
- Ok((i.slice(offset..), v))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpCapture)))
- }
- }
- }
-
- /// Compares the input with a regular expression and returns
- /// the capture groups of all matches in a nested `Vec`.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::str::re_captures;
- /// # fn main() {
- /// let re = regex::Regex::new(r"(a)(\d)").unwrap();
- /// let parser = re_captures::<(&str, ErrorKind)>(re);
- /// assert_eq!(parser("a1ba2"), Ok(("", vec![vec!["a1", "a", "1"], vec!["a2", "a", "2"]])));
- /// assert_eq!(parser("abc"), Err(Err::Error(("abc", ErrorKind::RegexpCapture))));
- /// # }
- /// ```
- #[cfg(all(feature = "regexp", feature = "alloc"))]
- #[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
- )]
- pub fn re_captures<'a, E>(re: Regex) -> impl Fn(&'a str) -> IResult<&'a str, Vec<Vec<&'a str>>, E>
- where
- E: ParseError<&'a str>,
- {
- move |i| {
- let v: Vec<Vec<_>> = re
- .captures_iter(i)
- .map(|c| {
- c.iter()
- .filter(|el| el.is_some())
- .map(|el| el.unwrap())
- .map(|m| i.slice(m.start()..m.end()))
- .collect()
- })
- .collect();
- if !v.is_empty() {
- let offset = {
- let end = v.last().unwrap().last().unwrap();
- end.as_ptr() as usize + end.len() - i.as_ptr() as usize
- };
- Ok((i.slice(offset..), v))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpCapture)))
- }
- }
- }
-
- #[cfg(test)]
- mod tests {
- use super::*;
- use crate::error::ErrorKind;
- use crate::internal::Err;
- use crate::lib::regex::Regex;
-
- macro_rules! assert_parse(
- ($left: expr, $right: expr) => {
- let res: $crate::IResult<_, _, (_, ErrorKind)> = $left;
- assert_eq!(res, $right);
- };
- );
-
- #[test]
- fn re_match_str() {
- let re = Regex::new(r"^\d{4}-\d{2}-\d{2}").unwrap();
- let rm = re_match(re);
- assert_parse!(rm("2015-09-07"), Ok(("", "2015-09-07")));
- assert_eq!(
- rm("blah"),
- Err(Err::Error((&"blah"[..], ErrorKind::RegexpMatch)))
- );
- assert_eq!(rm("2015-09-07blah"), Ok(("", "2015-09-07blah")));
- }
-
- #[test]
- fn re_find_str() {
- let re = Regex::new(r"^\d{4}-\d{2}-\d{2}").unwrap();
- let rm = re_find(re);
- assert_parse!(rm("2015-09-07"), Ok(("", "2015-09-07")));
- assert_eq!(
- rm("blah"),
- Err(Err::Error((&"blah"[..], ErrorKind::RegexpFind)))
- );
- assert_eq!(rm("2015-09-07blah"), Ok(("blah", "2015-09-07")));
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_matches_str() {
- let re = Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap();
- let rm = re_matches(re);
- assert_parse!(rm("2015-09-07"), Ok(("", vec!["2015-09-07"])));
- assert_eq!(
- rm("blah"),
- Err(Err::Error((&"blah"[..], ErrorKind::RegexpMatches)))
- );
- assert_eq!(
- rm("aaa2015-09-07blah2015-09-09pouet"),
- Ok(("pouet", vec!["2015-09-07", "2015-09-09"]))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_capture_str() {
- let re = Regex::new(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))").unwrap();
- let rm = re_capture(re);
- assert_parse!(
- rm("blah nom 0.3.11pouet"),
- Ok(("pouet", vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]))
- );
- assert_eq!(
- rm("blah"),
- Err(Err::Error(("blah", ErrorKind::RegexpCapture)))
- );
- assert_eq!(
- rm("hello nom 0.3.11 world regex 0.1.41"),
- Ok((
- " world regex 0.1.41",
- vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]
- ))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_captures_str() {
- let re = Regex::new(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))").unwrap();
- let rm = re_captures(re);
- assert_parse!(
- rm("blah nom 0.3.11pouet"),
- Ok((
- "pouet",
- vec![vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"]]
- ))
- );
- assert_eq!(
- rm("blah"),
- Err(Err::Error((&"blah"[..], ErrorKind::RegexpCapture)))
- );
- assert_eq!(
- rm("hello nom 0.3.11 world regex 0.1.41 aaa"),
- Ok((
- " aaa",
- vec![
- vec!["nom 0.3.11", "nom", "0.3.11", "0", "3", "11"],
- vec!["regex 0.1.41", "regex", "0.1.41", "0", "1", "41"],
- ]
- ))
- );
- }
- }
-}
-
-///Regular expression parser combinators for bytes.
-pub mod bytes {
- use crate::error::{ErrorKind, ParseError};
- use crate::lib::regex::bytes::Regex;
- #[cfg(feature = "alloc")]
- use crate::lib::std::vec::Vec;
- use crate::traits::{InputLength, Slice};
- use crate::{Err, IResult};
-
- /// Compares the input with a regular expression and returns the
- /// whole input if a match is found.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::bytes::re_match;
- /// # fn main() {
- /// let re = regex::bytes::Regex::new(r"^\d{4}").unwrap();
- /// let parser = re_match::<(&[u8], ErrorKind)>(re);
- /// assert_eq!(parser(&b"2019"[..]), Ok((&b""[..], &b"2019"[..])));
- /// assert_eq!(parser(&b"abc"[..]), Err(Err::Error((&b"abc"[..], ErrorKind::RegexpMatch))));
- /// assert_eq!(parser(&b"2019-10"[..]), Ok((&b""[..], &b"2019-10"[..])));
- /// # }
- /// ```
- #[cfg(feature = "regexp")]
- pub fn re_match<'a, E>(re: Regex) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8], E>
- where
- E: ParseError<&'a [u8]>,
- {
- move |i| {
- if re.is_match(i) {
- Ok((i.slice(i.input_len()..), i))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpMatch)))
- }
- }
- }
-
- /// Compares the input with a regular expression and returns all matches in a `Vec`.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::bytes::re_matches;
- /// # fn main() {
- /// let re = regex::bytes::Regex::new(r"a\d").unwrap();
- /// let parser = re_matches::<(&[u8], ErrorKind)>(re);
- /// assert_eq!(parser(&b"a1ba2"[..]), Ok((&b""[..], vec![&b"a1"[..], &b"a2"[..]])));
- /// assert_eq!(parser(&b"abc"[..]), Err(Err::Error((&b"abc"[..], ErrorKind::RegexpMatches))));
- /// # }
- /// ```
- #[cfg(all(feature = "regexp", feature = "alloc"))]
- #[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
- )]
- pub fn re_matches<'a, E>(re: Regex) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<&'a [u8]>, E>
- where
- E: ParseError<&'a [u8]>,
- {
- move |i| {
- let v: Vec<_> = re
- .find_iter(i)
- .map(|m| i.slice(m.start()..m.end()))
- .collect();
- if !v.is_empty() {
- let offset = {
- let end = v.last().unwrap();
- end.as_ptr() as usize + end.len() - i.as_ptr() as usize
- };
- Ok((i.slice(offset..), v))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpMatches)))
- }
- }
- }
-
- /// Compares the input with a regular expression and returns the
- /// first match.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::bytes::re_find;
- /// # fn main() {
- /// let re = regex::bytes::Regex::new(r"\d{4}").unwrap();
- /// let parser = re_find::<(&[u8], ErrorKind)>(re);
- /// assert_eq!(parser(&b"abc2019"[..]), Ok((&b""[..], &b"2019"[..])));
- /// assert_eq!(parser(&b"abc"[..]), Err(Err::Error((&b"abc"[..], ErrorKind::RegexpFind))));
- /// assert_eq!(parser(&b"2019-10"[..]), Ok((&b"-10"[..], &b"2019"[..])));
- /// # }
- /// ```
- #[cfg(feature = "regexp")]
- pub fn re_find<'a, E>(re: Regex) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8], E>
- where
- E: ParseError<&'a [u8]>,
- {
- move |i| {
- if let Some(m) = re.find(i) {
- Ok((i.slice(m.end()..), i.slice(m.start()..m.end())))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpFind)))
- }
- }
- }
-
- /// Compares the input with a regular expression and returns
- /// the capture groups of the first match in a `Vec`.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::bytes::re_capture;
- /// # fn main() {
- /// let re = regex::bytes::Regex::new(r"(a)(\d)").unwrap();
- /// let parser = re_capture::<(&[u8], ErrorKind)>(re);
- /// assert_eq!(parser(&b"a1ba2"[..]), Ok((&b"ba2"[..], vec![&b"a1"[..], &b"a"[..], &b"1"[..]])));
- /// assert_eq!(parser(&b"abc"[..]), Err(Err::Error((&b"abc"[..], ErrorKind::RegexpCapture))));
- /// # }
- /// ```
- #[cfg(all(feature = "regexp", feature = "alloc"))]
- #[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
- )]
- pub fn re_capture<'a, E>(re: Regex) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<&'a [u8]>, E>
- where
- E: ParseError<&'a [u8]>,
- {
- move |i| {
- if let Some(c) = re.captures(i) {
- let v: Vec<_> = c
- .iter()
- .filter(|el| el.is_some())
- .map(|el| el.unwrap())
- .map(|m| i.slice(m.start()..m.end()))
- .collect();
- let offset = {
- let end = v.last().unwrap();
- end.as_ptr() as usize + end.len() - i.as_ptr() as usize
- };
- Ok((i.slice(offset..), v))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpCapture)))
- }
- }
- }
-
- /// Compares the input with a regular expression and returns
- /// the capture groups of all matches in a nested `Vec`.
- ///
- /// Requires the `regexp` feature.
- /// # Example
- ///
- /// ```
- /// # use nom::{Err, error::ErrorKind};
- /// # use nom::regexp::bytes::re_captures;
- /// # fn main() {
- /// let re = regex::bytes::Regex::new(r"(a)(\d)").unwrap();
- /// let parser = re_captures::<(&[u8], ErrorKind)>(re);
- /// assert_eq!(parser(&b"a1ba2"[..]), Ok((&b""[..], vec![vec![&b"a1"[..], &b"a"[..], &b"1"[..]], vec![&b"a2"[..], &b"a"[..], &b"2"[..]]])));
- /// assert_eq!(parser(&b"abc"[..]), Err(Err::Error((&b"abc"[..], ErrorKind::RegexpCapture))));
- /// # }
- /// ```
- #[cfg(all(feature = "regexp", feature = "alloc"))]
- #[cfg_attr(
- feature = "docsrs",
- doc(cfg(all(feature = "regexp", feature = "alloc")))
- )]
- pub fn re_captures<'a, E>(
- re: Regex,
- ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec<Vec<&'a [u8]>>, E>
- where
- E: ParseError<&'a [u8]>,
- {
- move |i| {
- let v: Vec<Vec<_>> = re
- .captures_iter(i)
- .map(|c| {
- c.iter()
- .filter(|el| el.is_some())
- .map(|el| el.unwrap())
- .map(|m| i.slice(m.start()..m.end()))
- .collect()
- })
- .collect();
- if !v.is_empty() {
- let offset = {
- let end = v.last().unwrap().last().unwrap();
- end.as_ptr() as usize + end.len() - i.as_ptr() as usize
- };
- Ok((i.slice(offset..), v))
- } else {
- Err(Err::Error(E::from_error_kind(i, ErrorKind::RegexpCapture)))
- }
- }
- }
-
- #[cfg(test)]
- mod tests {
- use super::*;
- use crate::error::ErrorKind;
- use crate::internal::Err;
- use crate::lib::regex::bytes::Regex;
-
- macro_rules! assert_parse(
- ($left: expr, $right: expr) => {
- let res: $crate::IResult<_, _, (_, ErrorKind)> = $left;
- assert_eq!(res, $right);
- };
- );
-
- #[test]
- fn re_match_bytes() {
- let re = Regex::new(r"^\d{4}-\d{2}-\d{2}").unwrap();
- let rm = re_match(re);
- assert_parse!(rm(&b"2015-09-07"[..]), Ok((&b""[..], &b"2015-09-07"[..])));
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error((&b"blah"[..], ErrorKind::RegexpMatch)))
- );
- assert_eq!(
- rm(&b"2015-09-07blah"[..]),
- Ok((&b""[..], &b"2015-09-07blah"[..]))
- );
- }
-
- #[test]
- fn re_find_bytes() {
- let re = Regex::new(r"^\d{4}-\d{2}-\d{2}").unwrap();
- let rm = re_find(re);
- assert_parse!(rm(&b"2015-09-07"[..]), Ok((&b""[..], &b"2015-09-07"[..])));
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error((&b"blah"[..], ErrorKind::RegexpFind)))
- );
- assert_eq!(
- rm(&b"2015-09-07blah"[..]),
- Ok((&b"blah"[..], &b"2015-09-07"[..]))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_matches_bytes() {
- let re = Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap();
- let rm = re_matches(re);
- assert_parse!(
- rm(&b"2015-09-07"[..]),
- Ok((&b""[..], vec![&b"2015-09-07"[..]]))
- );
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error((&b"blah"[..], ErrorKind::RegexpMatches)))
- );
- assert_eq!(
- rm(&b"aaa2015-09-07blah2015-09-09pouet"[..]),
- Ok((&b"pouet"[..], vec![&b"2015-09-07"[..], &b"2015-09-09"[..]]))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_capture_bytes() {
- let re = Regex::new(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))").unwrap();
- let rm = re_capture(re);
- assert_parse!(
- rm(&b"blah nom 0.3.11pouet"[..]),
- Ok((
- &b"pouet"[..],
- vec![
- &b"nom 0.3.11"[..],
- &b"nom"[..],
- &b"0.3.11"[..],
- &b"0"[..],
- &b"3"[..],
- &b"11"[..]
- ]
- ))
- );
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error((&b"blah"[..], ErrorKind::RegexpCapture)))
- );
- assert_eq!(
- rm(&b"hello nom 0.3.11 world regex 0.1.41"[..]),
- Ok((
- &b" world regex 0.1.41"[..],
- vec![
- &b"nom 0.3.11"[..],
- &b"nom"[..],
- &b"0.3.11"[..],
- &b"0"[..],
- &b"3"[..],
- &b"11"[..]
- ]
- ))
- );
- }
-
- #[cfg(feature = "alloc")]
- #[test]
- fn re_captures_bytes() {
- let re = Regex::new(r"([[:alpha:]]+)\s+((\d+).(\d+).(\d+))").unwrap();
- let rm = re_captures(re);
- assert_parse!(
- rm(&b"blah nom 0.3.11pouet"[..]),
- Ok((
- &b"pouet"[..],
- vec![vec![
- &b"nom 0.3.11"[..],
- &b"nom"[..],
- &b"0.3.11"[..],
- &b"0"[..],
- &b"3"[..],
- &b"11"[..]
- ]]
- ))
- );
-
- assert_eq!(
- rm(&b"blah"[..]),
- Err(Err::Error((&b"blah"[..], ErrorKind::RegexpCapture)))
- );
- assert_eq!(
- rm(&b"hello nom 0.3.11 world regex 0.1.41 aaa"[..]),
- Ok((
- &b" aaa"[..],
- vec![
- vec![
- &b"nom 0.3.11"[..],
- &b"nom"[..],
- &b"0.3.11"[..],
- &b"0"[..],
- &b"3"[..],
- &b"11"[..]
- ],
- vec![
- &b"regex 0.1.41"[..],
- &b"regex"[..],
- &b"0.1.41"[..],
- &b"0"[..],
- &b"1"[..],
- &b"41"[..]
- ],
- ]
- ))
- );
- }
- }
-}
diff --git a/src/sequence/macros.rs b/src/sequence/macros.rs
deleted file mode 100644
index a2bfb2c..0000000
--- a/src/sequence/macros.rs
+++ /dev/null
@@ -1,920 +0,0 @@
-/// `tuple!(I->IResult<I,A>, I->IResult<I,B>, ... I->IResult<I,X>) => I -> IResult<I, (A, B, ..., X)>`
-/// chains parsers and assemble the sub results in a tuple.
-///
-/// The input type `I` must implement `nom::InputLength`.
-///
-/// This combinator will count how much data is consumed by every child parser
-/// and take it into account if there is not enough data.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::error::ErrorKind;
-/// # use nom::number::streaming::be_u16;
-/// // the return type depends of the children parsers
-/// named!(parser<&[u8], (u16, &[u8], &[u8]) >,
-/// tuple!(
-/// be_u16 ,
-/// take!(3),
-/// tag!("fg")
-/// )
-/// );
-///
-/// # fn main() {
-/// assert_eq!(
-/// parser(&b"abcdefgh"[..]),
-/// Ok((
-/// &b"h"[..],
-/// (0x6162u16, &b"cde"[..], &b"fg"[..])
-/// ))
-/// );
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! tuple (
- ($i:expr, $($rest:tt)*) => (
- {
- tuple_parser!($i, (), $($rest)*)
- }
- );
-);
-
-/// Internal parser, do not use directly.
-#[doc(hidden)]
-#[macro_export(local_inner_macros)]
-macro_rules! tuple_parser (
- ($i:expr, ($($parsed:tt),*), $e:path, $($rest:tt)*) => (
- tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*);
- );
- ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
- {
- let i_ = $i.clone();
-
- ( $submac!(i_, $($args)*) ).and_then(|(i,o)| {
- let i_ = i.clone();
- tuple_parser!(i_, (o), $($rest)*)
- })
- }
- );
- ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
- {
- let i_ = $i.clone();
-
- ( $submac!(i_, $($args)*) ).and_then(|(i,o)| {
- let i_ = i.clone();
- tuple_parser!(i_, ($($parsed)* , o), $($rest)*)
- })
- }
- );
- ($i:expr, ($($parsed:tt),*), $e:path) => (
- tuple_parser!($i, ($($parsed),*), call!($e));
- );
- ($i:expr, (), $submac:ident!( $($args:tt)* )) => (
- {
- let i_ = $i.clone();
- ( $submac!(i_, $($args)*) ).map(|(i,o)| (i, (o)))
- }
- );
- ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => (
- {
- let i_ = $i.clone();
- ( $submac!(i_, $($args)*) ).map(|(i,o)| (i, ($($parsed),* , o)))
- }
- );
- ($i:expr, ($($parsed:expr),*)) => (
- {
- $crate::lib::std::result::Result::Ok(($i, ($($parsed),*)))
- }
- );
-);
-
-/// `pair!(I -> IResult<I,O>, I -> IResult<I,P>) => I -> IResult<I, (O,P)>`
-/// `pair` returns a tuple of the results of its two child parsers if both succeed.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::{Error, ErrorKind};
-/// # use nom::character::complete::{alpha1, digit1};
-/// named!(parser<&str, (&str, &str)>, pair!(alpha1, digit1));
-///
-/// # fn main() {
-/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123"))));
-/// assert_eq!(parser("123abc"), Err(Err::Error(Error::new("123abc", ErrorKind::Alpha))));
-/// assert_eq!(parser("abc;123"), Err(Err::Error(Error::new(";123", ErrorKind::Digit))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! pair(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- pair!($i, |i| $submac!(i, $($args)*), |i| $submac2!(i, $($args2)*))
- );
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- pair!($i, |i| $submac!(i, $($args)*), $g);
- );
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- pair!($i, $f, |i| $submac!(i, $($args)*));
- );
-
- ($i:expr, $f:expr, $g:expr) => (
- $crate::sequence::pairc($i, $f, $g)
- );
-);
-
-/// `separated_pair!(I -> IResult<I,O>, I -> IResult<I, T>, I -> IResult<I,P>) => I -> IResult<I, (O,P)>`
-/// `separated_pair(X,sep,Y)` returns a tuple of its first and third child parsers
-/// if all 3 succeed.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::{Error, ErrorKind};
-/// # use nom::character::complete::{alpha1, digit1};
-/// named!(parser<&str, (&str, &str)>, separated_pair!(alpha1, char!(','), digit1));
-///
-/// # fn main() {
-/// assert_eq!(parser("abc,123"), Ok(("", ("abc", "123"))));
-/// assert_eq!(parser("123,abc"), Err(Err::Error(Error::new("123,abc", ErrorKind::Alpha))));
-/// assert_eq!(parser("abc;123"), Err(Err::Error(Error::new(";123", ErrorKind::Char))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! separated_pair(
- ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
- separated_pair!($i, |i| $submac!(i, $($args)*), $($rest)*)
- );
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
- separated_pair!($i, $f, |i| $submac!(i, $($args)*), $($rest)*)
- );
- ($i:expr, $f:expr, $g:expr, $submac:ident!( $($args:tt)* )) => (
- separated_pair!($i, $f, $g, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $f:expr, $g:expr, $h:expr) => (
- $crate::sequence::separated_pairc($i, $f, $g, $h)
- );
-);
-
-/// `preceded!(I -> IResult<I,T>, I -> IResult<I,O>) => I -> IResult<I, O>`
-/// `preceded` returns the result of its second parser if both succeed.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::{Error, ErrorKind};
-/// # use nom::character::complete::{alpha1};
-/// named!(parser<&str, &str>, preceded!(char!('-'), alpha1));
-///
-/// # fn main() {
-/// assert_eq!(parser("-abc"), Ok(("", "abc")));
-/// assert_eq!(parser("abc"), Err(Err::Error(Error::new("abc", ErrorKind::Char))));
-/// assert_eq!(parser("-123"), Err(Err::Error(Error::new("123", ErrorKind::Alpha))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! preceded(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- preceded!($i, |i| $submac!(i, $($args)*), |i| $submac2!(i, $($args2)*))
- );
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- preceded!($i, |i| $submac!(i, $($args)*), $g);
- );
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- preceded!($i, $f, |i| $submac!(i, $($args)*));
- );
-
- ($i:expr, $f:expr, $g:expr) => (
- $crate::sequence::precededc($i, $f, $g)
- );
-);
-
-/// `terminated!(I -> IResult<I,O>, I -> IResult<I,T>) => I -> IResult<I, O>`
-/// `terminated` returns the result of its first parser if both succeed.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::Err;
-/// # use nom::error::{Error, ErrorKind};
-/// # use nom::character::complete::{alpha1};
-/// named!(parser<&str, &str>, terminated!(alpha1, char!(';')));
-///
-/// # fn main() {
-/// assert_eq!(parser("abc;"), Ok(("", "abc")));
-/// assert_eq!(parser("abc,"), Err(Err::Error(Error::new(",", ErrorKind::Char))));
-/// assert_eq!(parser("123;"), Err(Err::Error(Error::new("123;", ErrorKind::Alpha))));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! terminated(
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
- terminated!($i, |i| $submac!(i, $($args)*), |i| $submac2!(i, $($args2)*))
- );
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- terminated!($i, |i| $submac!(i, $($args)*), $g);
- );
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
- terminated!($i, $f, |i| $submac!(i, $($args)*));
- );
-
- ($i:expr, $f:expr, $g:expr) => (
- $crate::sequence::terminatedc($i, $f, $g)
- );
-);
-
-/// `delimited!(I -> IResult<I,T>, I -> IResult<I,O>, I -> IResult<I,U>) => I -> IResult<I, O>`
-/// `delimited(opening, X, closing)` returns X.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::character::complete::{alpha1};
-/// named!(parens,
-/// delimited!(
-/// tag!("("),
-/// alpha1,
-/// tag!(")")
-/// )
-/// );
-///
-/// # fn main() {
-/// let input = &b"(test)"[..];
-/// assert_eq!(parens(input), Ok((&b""[..], &b"test"[..])));
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! delimited(
- ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
- delimited!($i, |i| $submac!(i, $($args)*), $($rest)*)
- );
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
- delimited!($i, $f, |i| $submac!(i, $($args)*), $($rest)*)
- );
- ($i:expr, $f:expr, $g:expr, $submac:ident!( $($args:tt)* )) => (
- delimited!($i, $f, $g, |i| $submac!(i, $($args)*))
- );
- ($i:expr, $f:expr, $g:expr, $h:expr) => (
- $crate::sequence::delimitedc($i, $f, $g, $h)
- );
-);
-
-/// `do_parse!(I->IResult<I,A> >> I->IResult<I,B> >> ... I->IResult<I,X> , ( O ) ) => I -> IResult<I, O>`
-/// `do_parse` applies sub parsers in a sequence.
-/// It can store intermediary results and make them available
-/// for later parsers.
-///
-/// The input type `I` must implement `nom::InputLength`.
-///
-/// This combinator will count how much data is consumed by every child parser
-/// and take it into account if there is not enough data.
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # use nom::{Err,Needed};
-/// use nom::number::streaming::be_u8;
-///
-/// // this parser implements a common pattern in binary formats,
-/// // the TAG-LENGTH-VALUE, where you first recognize a specific
-/// // byte slice, then the next bytes indicate the length of
-/// // the data, then you take that slice and return it
-/// //
-/// // here, we match the tag 42, take the length in the next byte
-/// // and store it in `length`, then use `take!` with `length`
-/// // to obtain the subslice that we store in `bytes`, then return
-/// // `bytes`
-/// // you can use other macro combinators inside do_parse (like the `tag`
-/// // one here), or a function (like `be_u8` here), but you cannot use a
-/// // module path (like `nom::be_u8`) there, because of limitations in macros
-/// named!(tag_length_value,
-/// do_parse!(
-/// tag!( &[ 42u8 ][..] ) >>
-/// length: be_u8 >>
-/// bytes: take!(length) >>
-/// (bytes)
-/// )
-/// );
-///
-/// # fn main() {
-/// let a: Vec<u8> = vec!(42, 2, 3, 4, 5);
-/// let result_a: Vec<u8> = vec!(3, 4);
-/// let rest_a: Vec<u8> = vec!(5);
-/// assert_eq!(tag_length_value(&a[..]), Ok((&rest_a[..], &result_a[..])));
-///
-/// // here, the length is 5, but there are only 3 bytes afterwards (3, 4 and 5),
-/// // so the parser will tell you that you need 7 bytes: one for the tag,
-/// // one for the length, then 5 bytes
-/// let b: Vec<u8> = vec!(42, 5, 3, 4, 5);
-/// assert_eq!(tag_length_value(&b[..]), Err(Err::Incomplete(Needed::new(2))));
-/// # }
-/// ```
-///
-/// the result is a tuple, so you can return multiple sub results, like
-/// this:
-/// `do_parse!(I->IResult<I,A> >> I->IResult<I,B> >> ... I->IResult<I,X> , ( O, P ) ) => I -> IResult<I, (O,P)>`
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// use nom::number::streaming::be_u8;
-/// named!(tag_length_value<(u8, &[u8])>,
-/// do_parse!(
-/// tag!( &[ 42u8 ][..] ) >>
-/// length: be_u8 >>
-/// bytes: take!(length) >>
-/// (length, bytes)
-/// )
-/// );
-///
-/// # fn main() {
-/// # }
-/// ```
-///
-#[macro_export(local_inner_macros)]
-macro_rules! do_parse (
- (__impl $i:expr, ( $($rest:expr),* )) => (
- $crate::lib::std::result::Result::Ok(($i, ( $($rest),* )))
- );
-
- (__impl $i:expr, $field:ident : $submac:ident!( $($args:tt)* ) ) => (
- do_parse!(__impl $i, $submac!( $($args)* ))
- );
-
- (__impl $i:expr, $submac:ident!( $($args:tt)* ) ) => (
- nom_compile_error!("do_parse is missing the return value. A do_parse call must end
- with a return value between parenthesis, as follows:
-
- do_parse!(
- a: tag!(\"abcd\") >>
- b: tag!(\"efgh\") >>
-
- ( Value { a: a, b: b } )
- ");
- );
-
- (__impl $i:expr, $field:ident : $submac:ident!( $($args:tt)* ) ~ $($rest:tt)* ) => (
- nom_compile_error!("do_parse uses >> as separator, not ~");
- );
- (__impl $i:expr, $submac:ident!( $($args:tt)* ) ~ $($rest:tt)* ) => (
- nom_compile_error!("do_parse uses >> as separator, not ~");
- );
- (__impl $i:expr, $field:ident : $e:ident ~ $($rest:tt)*) => (
- do_parse!(__impl $i, $field: call!($e) ~ $($rest)*);
- );
- (__impl $i:expr, $e:ident ~ $($rest:tt)*) => (
- do_parse!(__impl $i, call!($e) ~ $($rest)*);
- );
-
- (__impl $i:expr, $e:ident >> $($rest:tt)*) => (
- do_parse!(__impl $i, call!($e) >> $($rest)*);
- );
- (__impl $i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => (
- {
- use $crate::lib::std::result::Result::*;
-
- let i_ = $i.clone();
- match $submac!(i_, $($args)*) {
- Err(e) => Err(e),
- Ok((i,_)) => {
- let i_ = i.clone();
- do_parse!(__impl i_, $($rest)*)
- },
- }
- }
- );
-
- (__impl $i:expr, $field:ident : $e:ident >> $($rest:tt)*) => (
- do_parse!(__impl $i, $field: call!($e) >> $($rest)*);
- );
-
- (__impl $i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => (
- {
- use $crate::lib::std::result::Result::*;
-
- let i_ = $i.clone();
- match $submac!(i_, $($args)*) {
- Err(e) => Err(e),
- Ok((i,o)) => {
- let $field = o;
- let i_ = i.clone();
- do_parse!(__impl i_, $($rest)*)
- },
- }
- }
- );
-
- // ending the chain
- (__impl $i:expr, $e:ident >> ( $($rest:tt)* )) => (
- do_parse!(__impl $i, call!($e) >> ( $($rest)* ));
- );
-
- (__impl $i:expr, $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ({
- use $crate::lib::std::result::Result::*;
-
- match $submac!($i, $($args)*) {
- Err(e) => Err(e),
- Ok((i,_)) => {
- do_parse!(__finalize i, $($rest)*)
- },
- }
- });
-
- (__impl $i:expr, $field:ident : $e:ident >> ( $($rest:tt)* )) => (
- do_parse!(__impl $i, $field: call!($e) >> ( $($rest)* ) );
- );
-
- (__impl $i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ({
- use $crate::lib::std::result::Result::*;
-
- match $submac!($i, $($args)*) {
- Err(e) => Err(e),
- Ok((i,o)) => {
- let $field = o;
- do_parse!(__finalize i, $($rest)*)
- },
- }
- });
-
- (__finalize $i:expr, ( $o: expr )) => ({
- use $crate::lib::std::result::Result::Ok;
- Ok(($i, $o))
- });
-
- (__finalize $i:expr, ( $($rest:tt)* )) => ({
- use $crate::lib::std::result::Result::Ok;
- Ok(($i, ( $($rest)* )))
- });
-
- ($i:expr, $($rest:tt)*) => (
- {
- do_parse!(__impl $i, $($rest)*)
- }
- );
- ($submac:ident!( $($args:tt)* ) >> $($rest:tt)* ) => (
- nom_compile_error!("if you are using do_parse outside of a named! macro, you must
- pass the input data as first argument, like this:
-
- let res = do_parse!(input,
- a: tag!(\"abcd\") >>
- b: tag!(\"efgh\") >>
- ( Value { a: a, b: b } )
- );");
- );
- ($e:ident! >> $($rest:tt)* ) => (
- do_parse!( call!($e) >> $($rest)*);
- );
-);
-
-#[doc(hidden)]
-#[macro_export]
-macro_rules! nom_compile_error (
- (( $($args:tt)* )) => ( compile_error!($($args)*) );
-);
-
-#[cfg(test)]
-mod tests {
- use crate::error::ErrorKind;
- use crate::internal::{Err, IResult, Needed};
- use crate::number::streaming::be_u16;
-
- // reproduce the tag and take macros, because of module import order
- macro_rules! tag (
- ($i:expr, $inp: expr) => (
- {
- #[inline(always)]
- fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
- b.as_bytes()
- }
-
- let expected = $inp;
- let bytes = as_bytes(&expected);
-
- tag_bytes!($i,bytes)
- }
- );
- );
-
- macro_rules! tag_bytes (
- ($i:expr, $bytes: expr) => (
- {
- use $crate::lib::std::cmp::min;
-
- let len = $i.len();
- let blen = $bytes.len();
- let m = min(len, blen);
- let reduced = &$i[..m];
- let b = &$bytes[..m];
-
- let res: IResult<_,_,_> = if reduced != b {
- Err($crate::Err::Error(error_position!($i, $crate::error::ErrorKind::Tag)))
- } else if m < blen {
- Err($crate::Err::Incomplete(Needed::new(blen)))
- } else {
- Ok((&$i[blen..], reduced))
- };
- res
- }
- );
- );
-
- macro_rules! take (
- ($i:expr, $count:expr) => (
- {
- let cnt = $count as usize;
- let res:IResult<&[u8],&[u8],_> = if $i.len() < cnt {
- Err($crate::Err::Incomplete(Needed::new(cnt)))
- } else {
- Ok((&$i[cnt..],&$i[0..cnt]))
- };
- res
- }
- );
- );
-
- #[derive(PartialEq, Eq, Debug)]
- struct B {
- a: u8,
- b: u8,
- }
-
- #[derive(PartialEq, Eq, Debug)]
- struct C {
- a: u8,
- b: Option<u8>,
- }
-
- /*FIXME: convert code examples to new error management
- use util::{add_error_pattern, error_to_list, print_error};
-
- #[cfg(feature = "std")]
- #[rustfmt::skip]
- fn error_to_string<P: Clone + PartialEq>(e: &Context<P, u32>) -> &'static str {
- let v: Vec<(P, ErrorKind<u32>)> = error_to_list(e);
- // do it this way if you can use slice patterns
- //match &v[..] {
- // [ErrorKind::Custom(42), ErrorKind::Tag] => "missing `ijkl` tag",
- // [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] => "missing `mnop` tag after `ijkl`",
- // _ => "unrecognized error"
- //}
-
- let collected: Vec<ErrorKind<u32>> = v.iter().map(|&(_, ref e)| e.clone()).collect();
- if &collected[..] == [ErrorKind::Custom(42), ErrorKind::Tag] {
- "missing `ijkl` tag"
- } else if &collected[..] == [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] {
- "missing `mnop` tag after `ijkl`"
- } else {
- "unrecognized error"
- }
- }
-
- // do it this way if you can use box patterns
- //use $crate::lib::std::str;
- //fn error_to_string(e:Err) -> String
- // match e {
- // NodePosition(ErrorKind::Custom(42), i1, box Position(ErrorKind::Tag, i2)) => {
- // format!("missing `ijkl` tag, found '{}' instead", str::from_utf8(i2).unwrap())
- // },
- // NodePosition(ErrorKind::Custom(42), i1, box NodePosition(ErrorKind::Custom(128), i2, box Position(ErrorKind::Tag, i3))) => {
- // format!("missing `mnop` tag after `ijkl`, found '{}' instead", str::from_utf8(i3).unwrap())
- // },
- // _ => "unrecognized error".to_string()
- // }
- //}
- */
-
- #[rustfmt::skip]
- #[allow(unused_variables)]
- #[test]
- fn add_err() {
- named!(err_test,
- preceded!(
- tag!("efgh"),
- add_return_error!(
- //ErrorKind::Custom(42u32),
- ErrorKind::Char,
- do_parse!(
- tag!("ijkl") >>
- //res: add_return_error!(ErrorKind::Custom(128u32), tag!("mnop")) >>
- res: add_return_error!(ErrorKind::Eof, tag!("mnop")) >>
- (res)
- )
- )
- )
- );
- let a = &b"efghblah"[..];
- let b = &b"efghijklblah"[..];
- let c = &b"efghijklmnop"[..];
-
- let blah = &b"blah"[..];
-
- let res_a = err_test(a);
- let res_b = err_test(b);
- let res_c = err_test(c);
- assert_eq!(res_a,
- Err(Err::Error(error_node_position!(blah,
- //ErrorKind::Custom(42u32),
- ErrorKind::Eof,
- error_position!(blah, ErrorKind::Tag)))));
- //assert_eq!(res_b, Err(Err::Error(error_node_position!(&b"ijklblah"[..], ErrorKind::Custom(42u32),
- // error_node_position!(blah, ErrorKind::Custom(128u32), error_position!(blah, ErrorKind::Tag))))));
- assert_eq!(res_b, Err(Err::Error(error_node_position!(&b"ijklblah"[..], ErrorKind::Eof,
- error_node_position!(blah, ErrorKind::Eof, error_position!(blah, ErrorKind::Tag))))));
- assert_eq!(res_c, Ok((&b""[..], &b"mnop"[..])));
- }
-
- #[rustfmt::skip]
- #[test]
- fn complete() {
- named!(err_test,
- do_parse!(
- tag!("ijkl") >>
- res: complete!(tag!("mnop")) >>
- (res)
- )
- );
- let a = &b"ijklmn"[..];
-
- let res_a = err_test(a);
- assert_eq!(res_a,
- Err(Err::Error(error_position!(&b"mn"[..], ErrorKind::Complete))));
- }
-
- #[test]
- fn pair() {
- named!(tag_abc, tag!("abc"));
- named!(tag_def, tag!("def"));
- named!( pair_abc_def<&[u8],(&[u8], &[u8])>, pair!(tag_abc, tag_def) );
-
- assert_eq!(
- pair_abc_def(&b"abcdefghijkl"[..]),
- Ok((&b"ghijkl"[..], (&b"abc"[..], &b"def"[..])))
- );
- assert_eq!(
- pair_abc_def(&b"ab"[..]),
- Err(Err::Incomplete(Needed::new(3)))
- );
- assert_eq!(
- pair_abc_def(&b"abcd"[..]),
- Err(Err::Incomplete(Needed::new(3)))
- );
- assert_eq!(
- pair_abc_def(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- pair_abc_def(&b"xxxdef"[..]),
- Err(Err::Error(error_position!(&b"xxxdef"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- pair_abc_def(&b"abcxxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn separated_pair() {
- named!(tag_abc, tag!("abc"));
- named!(tag_def, tag!("def"));
- named!(tag_separator, tag!(","));
- named!( sep_pair_abc_def<&[u8],(&[u8], &[u8])>, separated_pair!(tag_abc, tag_separator, tag_def) );
-
- assert_eq!(
- sep_pair_abc_def(&b"abc,defghijkl"[..]),
- Ok((&b"ghijkl"[..], (&b"abc"[..], &b"def"[..])))
- );
- assert_eq!(
- sep_pair_abc_def(&b"ab"[..]),
- Err(Err::Incomplete(Needed::new(3)))
- );
- assert_eq!(
- sep_pair_abc_def(&b"abc,d"[..]),
- Err(Err::Incomplete(Needed::new(3)))
- );
- assert_eq!(
- sep_pair_abc_def(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- sep_pair_abc_def(&b"xxx,def"[..]),
- Err(Err::Error(error_position!(&b"xxx,def"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- sep_pair_abc_def(&b"abc,xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn preceded() {
- named!(tag_abcd, tag!("abcd"));
- named!(tag_efgh, tag!("efgh"));
- named!( preceded_abcd_efgh<&[u8], &[u8]>, preceded!(tag_abcd, tag_efgh) );
-
- assert_eq!(
- preceded_abcd_efgh(&b"abcdefghijkl"[..]),
- Ok((&b"ijkl"[..], &b"efgh"[..]))
- );
- assert_eq!(
- preceded_abcd_efgh(&b"ab"[..]),
- Err(Err::Incomplete(Needed::new(4)))
- );
- assert_eq!(
- preceded_abcd_efgh(&b"abcde"[..]),
- Err(Err::Incomplete(Needed::new(4)))
- );
- assert_eq!(
- preceded_abcd_efgh(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- preceded_abcd_efgh(&b"xxxxdef"[..]),
- Err(Err::Error(error_position!(&b"xxxxdef"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- preceded_abcd_efgh(&b"abcdxxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn terminated() {
- named!(tag_abcd, tag!("abcd"));
- named!(tag_efgh, tag!("efgh"));
- named!( terminated_abcd_efgh<&[u8], &[u8]>, terminated!(tag_abcd, tag_efgh) );
-
- assert_eq!(
- terminated_abcd_efgh(&b"abcdefghijkl"[..]),
- Ok((&b"ijkl"[..], &b"abcd"[..]))
- );
- assert_eq!(
- terminated_abcd_efgh(&b"ab"[..]),
- Err(Err::Incomplete(Needed::new(4)))
- );
- assert_eq!(
- terminated_abcd_efgh(&b"abcde"[..]),
- Err(Err::Incomplete(Needed::new(4)))
- );
- assert_eq!(
- terminated_abcd_efgh(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- terminated_abcd_efgh(&b"xxxxdef"[..]),
- Err(Err::Error(error_position!(&b"xxxxdef"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- terminated_abcd_efgh(&b"abcdxxxx"[..]),
- Err(Err::Error(error_position!(&b"xxxx"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn delimited() {
- named!(tag_abc, tag!("abc"));
- named!(tag_def, tag!("def"));
- named!(tag_ghi, tag!("ghi"));
- named!( delimited_abc_def_ghi<&[u8], &[u8]>, delimited!(tag_abc, tag_def, tag_ghi) );
-
- assert_eq!(
- delimited_abc_def_ghi(&b"abcdefghijkl"[..]),
- Ok((&b"jkl"[..], &b"def"[..]))
- );
- assert_eq!(
- delimited_abc_def_ghi(&b"ab"[..]),
- Err(Err::Incomplete(Needed::new(3)))
- );
- assert_eq!(
- delimited_abc_def_ghi(&b"abcde"[..]),
- Err(Err::Incomplete(Needed::new(3)))
- );
- assert_eq!(
- delimited_abc_def_ghi(&b"abcdefgh"[..]),
- Err(Err::Incomplete(Needed::new(3)))
- );
- assert_eq!(
- delimited_abc_def_ghi(&b"xxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- delimited_abc_def_ghi(&b"xxxdefghi"[..]),
- Err(Err::Error(error_position!(
- &b"xxxdefghi"[..],
- ErrorKind::Tag
- ),))
- );
- assert_eq!(
- delimited_abc_def_ghi(&b"abcxxxghi"[..]),
- Err(Err::Error(error_position!(&b"xxxghi"[..], ErrorKind::Tag)))
- );
- assert_eq!(
- delimited_abc_def_ghi(&b"abcdefxxx"[..]),
- Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn tuple_test() {
- named!(tuple_3<&[u8], (u16, &[u8], &[u8]) >,
- tuple!( be_u16 , take!(3), tag!("fg") ) );
-
- assert_eq!(
- tuple_3(&b"abcdefgh"[..]),
- Ok((&b"h"[..], (0x6162u16, &b"cde"[..], &b"fg"[..])))
- );
- assert_eq!(tuple_3(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(3))));
- assert_eq!(tuple_3(&b"abcde"[..]), Err(Err::Incomplete(Needed::new(2))));
- assert_eq!(
- tuple_3(&b"abcdejk"[..]),
- Err(Err::Error(error_position!(&b"jk"[..], ErrorKind::Tag)))
- );
- }
-
- #[test]
- fn do_parse() {
- fn ret_int1(i: &[u8]) -> IResult<&[u8], u8> {
- Ok((i, 1))
- }
- fn ret_int2(i: &[u8]) -> IResult<&[u8], u8> {
- Ok((i, 2))
- }
-
- //trace_macros!(true);
- named!(do_parser<&[u8], (u8, u8)>,
- do_parse!(
- tag!("abcd") >>
- opt!(tag!("abcd")) >>
- aa: ret_int1 >>
- tag!("efgh") >>
- bb: ret_int2 >>
- tag!("efgh") >>
- (aa, bb)
- )
- );
- //named!(do_parser<&[u8], (u8, u8)>,
- // do_parse!(
- // tag!("abcd") >> aa: ret_int1 >> tag!("efgh") >> bb: ret_int2 >> tag!("efgh") >> (aa, bb)
- // )
- //);
-
- //trace_macros!(false);
-
- assert_eq!(
- do_parser(&b"abcdabcdefghefghX"[..]),
- Ok((&b"X"[..], (1, 2)))
- );
- assert_eq!(do_parser(&b"abcdefghefghX"[..]), Ok((&b"X"[..], (1, 2))));
- assert_eq!(
- do_parser(&b"abcdab"[..]),
- Err(Err::Incomplete(Needed::new(4)))
- );
- assert_eq!(
- do_parser(&b"abcdefghef"[..]),
- Err(Err::Incomplete(Needed::new(4)))
- );
- }
-
- #[rustfmt::skip]
- #[test]
- fn do_parse_dependency() {
- use crate::number::streaming::be_u8;
-
- named!(length_value,
- do_parse!(
- length: be_u8 >>
- bytes: take!(length) >>
- (bytes)
- )
- );
-
- let a = [2u8, 3, 4, 5];
- let res_a = [3u8, 4];
- assert_eq!(length_value(&a[..]), Ok((&a[3..], &res_a[..])));
- let b = [5u8, 3, 4, 5];
- assert_eq!(length_value(&b[..]), Err(Err::Incomplete(Needed::new(5))));
- }
-
- /*
- named!(does_not_compile,
- do_parse!(
- length: be_u8 >>
- bytes: take!(length)
- )
- );
- named!(does_not_compile_either,
- do_parse!(
- length: be_u8 ~
- bytes: take!(length) ~
- ( () )
- )
- );
- fn still_does_not_compile() {
- let data = b"abcd";
-
- let res = do_parse!(
- tag!("abcd") >>
- tag!("efgh") >>
- ( () )
- );
- }
- */
-}
diff --git a/src/sequence/mod.rs b/src/sequence/mod.rs
index 3d76725..bf5dcfd 100644
--- a/src/sequence/mod.rs
+++ b/src/sequence/mod.rs
@@ -1,7 +1,7 @@
//! Combinators applying parsers in sequence
-#[macro_use]
-mod macros;
+#[cfg(test)]
+mod tests;
use crate::error::ParseError;
use crate::internal::{IResult, Parser};
@@ -39,20 +39,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-pub fn pairc<I, O1, O2, E: ParseError<I>, F, G>(
- input: I,
- first: F,
- second: G,
-) -> IResult<I, (O1, O2), E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(I) -> IResult<I, O2, E>,
-{
- pair(first, second)(input)
-}
-
/// Matches an object from the first parser and discards it,
/// then gets an object from the second parser.
///
@@ -86,20 +72,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-pub fn precededc<I, O1, O2, E: ParseError<I>, F, G>(
- input: I,
- first: F,
- second: G,
-) -> IResult<I, O2, E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(I) -> IResult<I, O2, E>,
-{
- preceded(first, second)(input)
-}
-
/// Gets an object from the first parser,
/// then matches an object from the second parser and discards it.
///
@@ -133,20 +105,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-pub fn terminatedc<I, O1, O2, E: ParseError<I>, F, G>(
- input: I,
- first: F,
- second: G,
-) -> IResult<I, O1, E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(I) -> IResult<I, O2, E>,
-{
- terminated(first, second)(input)
-}
-
/// Gets an object from the first parser,
/// then matches an object from the sep_parser and discards it,
/// then gets another object from the second parser.
@@ -185,22 +143,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-pub fn separated_pairc<I, O1, O2, O3, E: ParseError<I>, F, G, H>(
- input: I,
- first: F,
- sep: G,
- second: H,
-) -> IResult<I, (O1, O3), E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(I) -> IResult<I, O2, E>,
- H: Fn(I) -> IResult<I, O3, E>,
-{
- separated_pair(first, sep, second)(input)
-}
-
/// Matches an object from the first parser and discards it,
/// then gets an object from the second parser,
/// and finally matches an object from the third parser and discards it.
@@ -239,22 +181,6 @@ where
}
}
-// this implementation is used for type inference issues in macros
-#[doc(hidden)]
-pub fn delimitedc<I, O1, O2, O3, E: ParseError<I>, F, G, H>(
- input: I,
- first: F,
- second: G,
- third: H,
-) -> IResult<I, O2, E>
-where
- F: Fn(I) -> IResult<I, O1, E>,
- G: Fn(I) -> IResult<I, O2, E>,
- H: Fn(I) -> IResult<I, O3, E>,
-{
- delimited(first, second, third)(input)
-}
-
/// Helper trait for the tuple combinator.
///
/// This trait is implemented for tuples of parsers of up to 21 elements.
@@ -337,21 +263,3 @@ pub fn tuple<I, O, E: ParseError<I>, List: Tuple<I, O, E>>(
) -> impl FnMut(I) -> IResult<I, O, E> {
move |i: I| l.parse(i)
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn single_element_tuples() {
- use crate::character::complete::alpha1;
- use crate::{error::ErrorKind, Err};
-
- let mut parser = tuple((alpha1,));
- assert_eq!(parser("abc123def"), Ok(("123def", ("abc",))));
- assert_eq!(
- parser("123def"),
- Err(Err::Error(("123def", ErrorKind::Alpha)))
- );
- }
-}
diff --git a/src/sequence/tests.rs b/src/sequence/tests.rs
new file mode 100644
index 0000000..201579b
--- /dev/null
+++ b/src/sequence/tests.rs
@@ -0,0 +1,274 @@
+use super::*;
+use crate::bytes::streaming::{tag, take};
+use crate::error::ErrorKind;
+use crate::internal::{Err, IResult, Needed};
+use crate::number::streaming::be_u16;
+
+#[test]
+fn single_element_tuples() {
+ use crate::character::complete::alpha1;
+ use crate::{error::ErrorKind, Err};
+
+ let mut parser = tuple((alpha1,));
+ assert_eq!(parser("abc123def"), Ok(("123def", ("abc",))));
+ assert_eq!(
+ parser("123def"),
+ Err(Err::Error(("123def", ErrorKind::Alpha)))
+ );
+}
+
+#[derive(PartialEq, Eq, Debug)]
+struct B {
+ a: u8,
+ b: u8,
+}
+
+#[derive(PartialEq, Eq, Debug)]
+struct C {
+ a: u8,
+ b: Option<u8>,
+}
+
+/*FIXME: convert code examples to new error management
+use util::{add_error_pattern, error_to_list, print_error};
+
+#[cfg(feature = "std")]
+#[rustfmt::skip]
+fn error_to_string<P: Clone + PartialEq>(e: &Context<P, u32>) -> &'static str {
+ let v: Vec<(P, ErrorKind<u32>)> = error_to_list(e);
+ // do it this way if you can use slice patterns
+ //match &v[..] {
+ // [ErrorKind::Custom(42), ErrorKind::Tag] => "missing `ijkl` tag",
+ // [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] => "missing `mnop` tag after `ijkl`",
+ // _ => "unrecognized error"
+ //}
+
+ let collected: Vec<ErrorKind<u32>> = v.iter().map(|&(_, ref e)| e.clone()).collect();
+ if &collected[..] == [ErrorKind::Custom(42), ErrorKind::Tag] {
+ "missing `ijkl` tag"
+ } else if &collected[..] == [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag] {
+ "missing `mnop` tag after `ijkl`"
+ } else {
+ "unrecognized error"
+ }
+}
+
+// do it this way if you can use box patterns
+//use $crate::lib::std::str;
+//fn error_to_string(e:Err) -> String
+// match e {
+// NodePosition(ErrorKind::Custom(42), i1, box Position(ErrorKind::Tag, i2)) => {
+// format!("missing `ijkl` tag, found '{}' instead", str::from_utf8(i2).unwrap())
+// },
+// NodePosition(ErrorKind::Custom(42), i1, box NodePosition(ErrorKind::Custom(128), i2, box Position(ErrorKind::Tag, i3))) => {
+// format!("missing `mnop` tag after `ijkl`, found '{}' instead", str::from_utf8(i3).unwrap())
+// },
+// _ => "unrecognized error".to_string()
+// }
+//}
+*/
+
+#[test]
+fn complete() {
+ use crate::bytes::complete::tag;
+ fn err_test(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ let (i, _) = tag("ijkl")(i)?;
+ tag("mnop")(i)
+ }
+ let a = &b"ijklmn"[..];
+
+ let res_a = err_test(a);
+ assert_eq!(
+ res_a,
+ Err(Err::Error(error_position!(&b"mn"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn pair_test() {
+ fn pair_abc_def(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ pair(tag("abc"), tag("def"))(i)
+ }
+
+ assert_eq!(
+ pair_abc_def(&b"abcdefghijkl"[..]),
+ Ok((&b"ghijkl"[..], (&b"abc"[..], &b"def"[..])))
+ );
+ assert_eq!(
+ pair_abc_def(&b"ab"[..]),
+ Err(Err::Incomplete(Needed::new(1)))
+ );
+ assert_eq!(
+ pair_abc_def(&b"abcd"[..]),
+ Err(Err::Incomplete(Needed::new(2)))
+ );
+ assert_eq!(
+ pair_abc_def(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ pair_abc_def(&b"xxxdef"[..]),
+ Err(Err::Error(error_position!(&b"xxxdef"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ pair_abc_def(&b"abcxxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn separated_pair_test() {
+ fn sep_pair_abc_def(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ separated_pair(tag("abc"), tag(","), tag("def"))(i)
+ }
+
+ assert_eq!(
+ sep_pair_abc_def(&b"abc,defghijkl"[..]),
+ Ok((&b"ghijkl"[..], (&b"abc"[..], &b"def"[..])))
+ );
+ assert_eq!(
+ sep_pair_abc_def(&b"ab"[..]),
+ Err(Err::Incomplete(Needed::new(1)))
+ );
+ assert_eq!(
+ sep_pair_abc_def(&b"abc,d"[..]),
+ Err(Err::Incomplete(Needed::new(2)))
+ );
+ assert_eq!(
+ sep_pair_abc_def(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ sep_pair_abc_def(&b"xxx,def"[..]),
+ Err(Err::Error(error_position!(&b"xxx,def"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ sep_pair_abc_def(&b"abc,xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn preceded_test() {
+ fn preceded_abcd_efgh(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ preceded(tag("abcd"), tag("efgh"))(i)
+ }
+
+ assert_eq!(
+ preceded_abcd_efgh(&b"abcdefghijkl"[..]),
+ Ok((&b"ijkl"[..], &b"efgh"[..]))
+ );
+ assert_eq!(
+ preceded_abcd_efgh(&b"ab"[..]),
+ Err(Err::Incomplete(Needed::new(2)))
+ );
+ assert_eq!(
+ preceded_abcd_efgh(&b"abcde"[..]),
+ Err(Err::Incomplete(Needed::new(3)))
+ );
+ assert_eq!(
+ preceded_abcd_efgh(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ preceded_abcd_efgh(&b"xxxxdef"[..]),
+ Err(Err::Error(error_position!(&b"xxxxdef"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ preceded_abcd_efgh(&b"abcdxxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn terminated_test() {
+ fn terminated_abcd_efgh(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ terminated(tag("abcd"), tag("efgh"))(i)
+ }
+
+ assert_eq!(
+ terminated_abcd_efgh(&b"abcdefghijkl"[..]),
+ Ok((&b"ijkl"[..], &b"abcd"[..]))
+ );
+ assert_eq!(
+ terminated_abcd_efgh(&b"ab"[..]),
+ Err(Err::Incomplete(Needed::new(2)))
+ );
+ assert_eq!(
+ terminated_abcd_efgh(&b"abcde"[..]),
+ Err(Err::Incomplete(Needed::new(3)))
+ );
+ assert_eq!(
+ terminated_abcd_efgh(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ terminated_abcd_efgh(&b"xxxxdef"[..]),
+ Err(Err::Error(error_position!(&b"xxxxdef"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ terminated_abcd_efgh(&b"abcdxxxx"[..]),
+ Err(Err::Error(error_position!(&b"xxxx"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn delimited_test() {
+ fn delimited_abc_def_ghi(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ delimited(tag("abc"), tag("def"), tag("ghi"))(i)
+ }
+
+ assert_eq!(
+ delimited_abc_def_ghi(&b"abcdefghijkl"[..]),
+ Ok((&b"jkl"[..], &b"def"[..]))
+ );
+ assert_eq!(
+ delimited_abc_def_ghi(&b"ab"[..]),
+ Err(Err::Incomplete(Needed::new(1)))
+ );
+ assert_eq!(
+ delimited_abc_def_ghi(&b"abcde"[..]),
+ Err(Err::Incomplete(Needed::new(1)))
+ );
+ assert_eq!(
+ delimited_abc_def_ghi(&b"abcdefgh"[..]),
+ Err(Err::Incomplete(Needed::new(1)))
+ );
+ assert_eq!(
+ delimited_abc_def_ghi(&b"xxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ delimited_abc_def_ghi(&b"xxxdefghi"[..]),
+ Err(Err::Error(error_position!(
+ &b"xxxdefghi"[..],
+ ErrorKind::Tag
+ ),))
+ );
+ assert_eq!(
+ delimited_abc_def_ghi(&b"abcxxxghi"[..]),
+ Err(Err::Error(error_position!(&b"xxxghi"[..], ErrorKind::Tag)))
+ );
+ assert_eq!(
+ delimited_abc_def_ghi(&b"abcdefxxx"[..]),
+ Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag)))
+ );
+}
+
+#[test]
+fn tuple_test() {
+ fn tuple_3(i: &[u8]) -> IResult<&[u8], (u16, &[u8], &[u8])> {
+ tuple((be_u16, take(3u8), tag("fg")))(i)
+ }
+
+ assert_eq!(
+ tuple_3(&b"abcdefgh"[..]),
+ Ok((&b"h"[..], (0x6162u16, &b"cde"[..], &b"fg"[..])))
+ );
+ assert_eq!(tuple_3(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(1))));
+ assert_eq!(tuple_3(&b"abcde"[..]), Err(Err::Incomplete(Needed::new(2))));
+ assert_eq!(
+ tuple_3(&b"abcdejk"[..]),
+ Err(Err::Error(error_position!(&b"jk"[..], ErrorKind::Tag)))
+ );
+}
diff --git a/src/str.rs b/src/str.rs
index a554521..e8d38c6 100644
--- a/src/str.rs
+++ b/src/str.rs
@@ -1,13 +1,19 @@
#[cfg(test)]
mod test {
- use crate::{error, error::ErrorKind, Err, IResult};
+ #[cfg(feature = "alloc")]
+ use crate::{branch::alt, bytes::complete::tag_no_case, combinator::recognize, multi::many1};
+ use crate::{
+ bytes::complete::{is_a, is_not, tag, take, take_till, take_until},
+ error::{self, ErrorKind},
+ Err, IResult,
+ };
#[test]
fn tagtr_succeed() {
const INPUT: &str = "Hello World!";
const TAG: &str = "Hello";
fn test(input: &str) -> IResult<&str, &str> {
- tag!(input, TAG)
+ tag(TAG)(input)
}
match test(INPUT) {
@@ -31,10 +37,12 @@ mod test {
#[test]
fn tagtr_incomplete() {
+ use crate::bytes::streaming::tag;
+
const INPUT: &str = "Hello";
const TAG: &str = "Hello World!";
- let res: IResult<_, _, error::Error<_>> = tag!(INPUT, TAG);
+ let res: IResult<_, _, error::Error<_>> = tag(TAG)(INPUT);
match res {
Err(Err::Incomplete(_)) => (),
other => {
@@ -52,7 +60,7 @@ mod test {
const INPUT: &str = "Hello World!";
const TAG: &str = "Random"; // TAG must be closer than INPUT.
- let res: IResult<_, _, error::Error<_>> = tag!(INPUT, TAG);
+ let res: IResult<_, _, error::Error<_>> = tag(TAG)(INPUT);
match res {
Err(Err::Error(_)) => (),
other => {
@@ -70,7 +78,7 @@ mod test {
const CONSUMED: &str = "βèƒôřèÂßÇ";
const LEFTOVER: &str = "áƒƭèř";
- let res: IResult<_, _, error::Error<_>> = take!(INPUT, 9);
+ let res: IResult<_, _, error::Error<_>> = take(9_usize)(INPUT);
match res {
Ok((extra, output)) => {
assert!(
@@ -100,7 +108,7 @@ mod test {
const CONSUMED: &str = "βèƒôřè";
const LEFTOVER: &str = "ÂßÇ∂áƒƭèř";
- let res: IResult<_, _, (_, ErrorKind)> = take_until!(INPUT, FIND);
+ let res: IResult<_, _, (_, ErrorKind)> = take_until(FIND)(INPUT);
match res {
Ok((extra, output)) => {
assert!(
@@ -127,9 +135,11 @@ mod test {
#[test]
fn take_s_incomplete() {
+ use crate::bytes::streaming::take;
+
const INPUT: &str = "βèƒôřèÂßÇá";
- let res: IResult<_, _, (_, ErrorKind)> = take!(INPUT, 13);
+ let res: IResult<_, _, (_, ErrorKind)> = take(13_usize)(INPUT);
match res {
Err(Err::Incomplete(_)) => (),
other => panic!(
@@ -148,7 +158,11 @@ mod test {
#[test]
fn take_while() {
- named!(f<&str,&str>, take_while!(is_alphabetic));
+ use crate::bytes::streaming::take_while;
+
+ fn f(i: &str) -> IResult<&str, &str> {
+ take_while(is_alphabetic)(i)
+ }
let a = "";
let b = "abcd";
let c = "abcd123";
@@ -162,7 +176,11 @@ mod test {
#[test]
fn take_while1() {
- named!(f<&str,&str>, take_while1!(is_alphabetic));
+ use crate::bytes::streaming::take_while1;
+
+ fn f(i: &str) -> IResult<&str, &str> {
+ take_while1(is_alphabetic)(i)
+ }
let a = "";
let b = "abcd";
let c = "abcd123";
@@ -186,7 +204,7 @@ mod test {
c == 'á'
}
fn test(input: &str) -> IResult<&str, &str> {
- take_till!(input, till_s)
+ take_till(till_s)(input)
}
match test(INPUT) {
Ok((extra, output)) => {
@@ -212,6 +230,8 @@ mod test {
#[test]
fn take_while_succeed_none() {
+ use crate::bytes::complete::take_while;
+
const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
const CONSUMED: &str = "";
const LEFTOVER: &str = "βèƒôřèÂßÇáƒƭèř";
@@ -219,7 +239,7 @@ mod test {
c == '9'
}
fn test(input: &str) -> IResult<&str, &str> {
- take_while!(input, while_s)
+ take_while(while_s)(input)
}
match test(INPUT) {
Ok((extra, output)) => {
@@ -250,7 +270,7 @@ mod test {
const CONSUMED: &str = "βèƒôřèÂßÇ";
const LEFTOVER: &str = "áƒƭèř";
fn test(input: &str) -> IResult<&str, &str> {
- is_not!(input, AVOID)
+ is_not(AVOID)(input)
}
match test(INPUT) {
Ok((extra, output)) => {
@@ -276,6 +296,8 @@ mod test {
#[test]
fn take_while_succeed_some() {
+ use crate::bytes::complete::take_while;
+
const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
const CONSUMED: &str = "βèƒôřèÂßÇ";
const LEFTOVER: &str = "áƒƭèř";
@@ -291,7 +313,7 @@ mod test {
|| c == 'Ç'
}
fn test(input: &str) -> IResult<&str, &str> {
- take_while!(input, while_s)
+ take_while(while_s)(input)
}
match test(INPUT) {
Ok((extra, output)) => {
@@ -320,7 +342,7 @@ mod test {
const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
const AVOID: &str = "βúçƙ¥";
fn test(input: &str) -> IResult<&str, &str> {
- is_not!(input, AVOID)
+ is_not(AVOID)(input)
}
match test(INPUT) {
Err(Err::Error(_)) => (),
@@ -333,6 +355,8 @@ mod test {
#[test]
fn take_while1_succeed() {
+ use crate::bytes::complete::take_while1;
+
const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
const CONSUMED: &str = "βèƒôřèÂßÇ";
const LEFTOVER: &str = "áƒƭèř";
@@ -348,7 +372,7 @@ mod test {
|| c == 'Ç'
}
fn test(input: &str) -> IResult<&str, &str> {
- take_while1!(input, while1_s)
+ take_while1(while1_s)(input)
}
match test(INPUT) {
Ok((extra, output)) => {
@@ -374,10 +398,12 @@ mod test {
#[test]
fn take_until_incomplete() {
+ use crate::bytes::streaming::take_until;
+
const INPUT: &str = "βèƒôřè";
const FIND: &str = "βèƒôřèÂßÇ";
- let res: IResult<_, _, (_, ErrorKind)> = take_until!(INPUT, FIND);
+ let res: IResult<_, _, (_, ErrorKind)> = take_until(FIND)(INPUT);
match res {
Err(Err::Incomplete(_)) => (),
other => panic!(
@@ -395,7 +421,7 @@ mod test {
const CONSUMED: &str = "βèƒôřèÂßÇ";
const LEFTOVER: &str = "áƒƭèř";
fn test(input: &str) -> IResult<&str, &str> {
- is_a!(input, MATCH)
+ is_a(MATCH)(input)
}
match test(INPUT) {
Ok((extra, output)) => {
@@ -421,12 +447,14 @@ mod test {
#[test]
fn take_while1_fail() {
+ use crate::bytes::complete::take_while1;
+
const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
fn while1_s(c: char) -> bool {
c == '9'
}
fn test(input: &str) -> IResult<&str, &str> {
- take_while1!(input, while1_s)
+ take_while1(while1_s)(input)
}
match test(INPUT) {
Err(Err::Error(_)) => (),
@@ -443,7 +471,7 @@ mod test {
const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
const MATCH: &str = "Ûñℓúçƙ¥";
fn test(input: &str) -> IResult<&str, &str> {
- is_a!(input, MATCH)
+ is_a(MATCH)(input)
}
match test(INPUT) {
Err(Err::Error(_)) => (),
@@ -456,10 +484,12 @@ mod test {
#[test]
fn take_until_error() {
+ use crate::bytes::streaming::take_until;
+
const INPUT: &str = "βèƒôřèÂßÇáƒƭèř";
const FIND: &str = "Ráñδô₥";
- let res: IResult<_, _, (_, ErrorKind)> = take_until!(INPUT, FIND);
+ let res: IResult<_, _, (_, ErrorKind)> = take_until(FIND)(INPUT);
match res {
Err(Err::Incomplete(_)) => (),
other => panic!(
@@ -476,7 +506,9 @@ mod test {
let a = "aabbab";
let b = "ababcd";
- named!(f <&str,&str>, recognize!(many1!(complete!(alt!( tag!("a") | tag!("b") )))));
+ fn f(i: &str) -> IResult<&str, &str> {
+ recognize(many1(alt((tag("a"), tag("b")))))(i)
+ }
assert_eq!(f(&a[..]), Ok((&a[6..], &a[..])));
assert_eq!(f(&b[..]), Ok((&b[4..], &b[..4])));
@@ -484,9 +516,9 @@ mod test {
#[test]
fn utf8_indexing() {
- named!(dot(&str) -> &str,
- tag!(".")
- );
+ fn dot(i: &str) -> IResult<&str, &str> {
+ tag(".")(i)
+ }
let _ = dot("點");
}
@@ -494,14 +526,11 @@ mod test {
#[cfg(feature = "alloc")]
#[test]
fn case_insensitive() {
- named!(test<&str,&str>, tag_no_case!("ABcd"));
+ fn test(i: &str) -> IResult<&str, &str> {
+ tag_no_case("ABcd")(i)
+ }
assert_eq!(test("aBCdefgh"), Ok(("efgh", "aBCd")));
assert_eq!(test("abcdefgh"), Ok(("efgh", "abcd")));
assert_eq!(test("ABCDefgh"), Ok(("efgh", "ABCD")));
-
- named!(test2<&str,&str>, tag_no_case!("ABcd"));
- assert_eq!(test2("aBCdefgh"), Ok(("efgh", "aBCd")));
- assert_eq!(test2("abcdefgh"), Ok(("efgh", "abcd")));
- assert_eq!(test2("ABCDefgh"), Ok(("efgh", "ABCD")));
}
}
diff --git a/src/traits.rs b/src/traits.rs
index 553b244..a073fd3 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -14,9 +14,6 @@ use crate::lib::std::string::String;
#[cfg(feature = "alloc")]
use crate::lib::std::vec::Vec;
-#[cfg(feature = "bitvec")]
-use bitvec::prelude::*;
-
/// Abstract method to calculate the input length
pub trait InputLength {
/// Calculates the input length, as indicated by its name,
@@ -47,18 +44,6 @@ impl<'a> InputLength for (&'a [u8], usize) {
}
}
-#[cfg(feature = "bitvec")]
-impl<'a, O, T> InputLength for &'a BitSlice<O, T>
-where
- O: BitOrder,
- T: 'a + BitStore,
-{
- #[inline]
- fn input_len(&self) -> usize {
- self.len()
- }
-}
-
/// Useful functions to calculate the offset between slices and show a hexdump of a slice
pub trait Offset {
/// Offset between the first byte of self and the first byte of the argument
@@ -101,30 +86,6 @@ impl<'a> Offset for &'a str {
}
}
-#[cfg(feature = "bitvec")]
-impl<O, T> Offset for BitSlice<O, T>
-where
- O: BitOrder,
- T: BitStore,
-{
- #[inline(always)]
- fn offset(&self, second: &Self) -> usize {
- second.offset_from(self) as usize
- }
-}
-
-#[cfg(feature = "bitvec")]
-impl<'a, O, T> Offset for &'a BitSlice<O, T>
-where
- O: BitOrder,
- T: 'a + BitStore,
-{
- #[inline(always)]
- fn offset(&self, second: &Self) -> usize {
- second.offset_from(self) as usize
- }
-}
-
/// Helper trait for types that can be viewed as a byte slice
pub trait AsBytes {
/// Casts the input type to a byte slice
@@ -159,28 +120,6 @@ impl AsBytes for [u8] {
}
}
-#[cfg(feature = "bitvec")]
-impl<'a, O> AsBytes for &'a BitSlice<O, u8>
-where
- O: BitOrder,
-{
- #[inline(always)]
- fn as_bytes(&self) -> &[u8] {
- self.as_slice()
- }
-}
-
-#[cfg(feature = "bitvec")]
-impl<O> AsBytes for BitSlice<O, u8>
-where
- O: BitOrder,
-{
- #[inline(always)]
- fn as_bytes(&self) -> &[u8] {
- self.as_slice()
- }
-}
-
macro_rules! as_bytes_array_impls {
($($N:expr)+) => {
$(
@@ -197,24 +136,6 @@ macro_rules! as_bytes_array_impls {
self
}
}
-
- #[cfg(feature = "bitvec")]
- impl<'a, O> AsBytes for &'a BitArray<O, [u8; $N]>
- where O: BitOrder {
- #[inline(always)]
- fn as_bytes(&self) -> &[u8] {
- self.as_slice()
- }
- }
-
- #[cfg(feature = "bitvec")]
- impl<O> AsBytes for BitArray<O, [u8; $N]>
- where O: BitOrder {
- #[inline(always)]
- fn as_bytes(&self) -> &[u8] {
- self.as_slice()
- }
- }
)+
};
}
@@ -501,63 +422,8 @@ impl<'a> InputTake for &'a str {
// return byte index
#[inline]
fn take_split(&self, count: usize) -> (Self, Self) {
- (&self[count..], &self[..count])
- }
-}
-
-#[cfg(feature = "bitvec")]
-impl<'a, O, T> InputIter for &'a BitSlice<O, T>
-where
- O: BitOrder,
- T: 'a + BitStore,
-{
- type Item = bool;
- type Iter = Enumerate<Self::IterElem>;
- type IterElem = Copied<bitvec::slice::Iter<'a, O, T>>;
-
- #[inline]
- fn iter_indices(&self) -> Self::Iter {
- self.iter_elements().enumerate()
- }
-
- #[inline]
- fn iter_elements(&self) -> Self::IterElem {
- self.iter().copied()
- }
-
- #[inline]
- fn position<P>(&self, predicate: P) -> Option<usize>
- where
- P: Fn(Self::Item) -> bool,
- {
- self.iter_elements().position(predicate)
- }
-
- #[inline]
- fn slice_index(&self, count: usize) -> Result<usize, Needed> {
- if self.len() >= count {
- Ok(count)
- } else {
- Err(Needed::new(count - self.len()))
- }
- }
-}
-
-#[cfg(feature = "bitvec")]
-impl<'a, O, T> InputTake for &'a BitSlice<O, T>
-where
- O: BitOrder,
- T: 'a + BitStore,
-{
- #[inline]
- fn take(&self, count: usize) -> Self {
- &self[..count]
- }
-
- #[inline]
- fn take_split(&self, count: usize) -> (Self, Self) {
- let (a, b) = self.split_at(count);
- (b, a)
+ let (prefix, suffix) = self.split_at(count);
+ (suffix, prefix)
}
}
@@ -700,8 +566,8 @@ impl<'a> InputTakeAtPosition for &'a [u8] {
where
P: Fn(Self::Item) -> bool,
{
- match (0..self.len()).find(|b| predicate(self[*b])) {
- Some(i) => Ok((&self[i..], &self[..i])),
+ match self.iter().position(|c| predicate(*c)) {
+ Some(i) => Ok(self.take_split(i)),
None => Err(Err::Incomplete(Needed::new(1))),
}
}
@@ -714,9 +580,9 @@ impl<'a> InputTakeAtPosition for &'a [u8] {
where
P: Fn(Self::Item) -> bool,
{
- match (0..self.len()).find(|b| predicate(self[*b])) {
+ match self.iter().position(|c| predicate(*c)) {
Some(0) => Err(Err::Error(E::from_error_kind(self, e))),
- Some(i) => Ok((&self[i..], &self[..i])),
+ Some(i) => Ok(self.take_split(i)),
None => Err(Err::Incomplete(Needed::new(1))),
}
}
@@ -728,8 +594,8 @@ impl<'a> InputTakeAtPosition for &'a [u8] {
where
P: Fn(Self::Item) -> bool,
{
- match (0..self.len()).find(|b| predicate(self[*b])) {
- Some(i) => Ok((&self[i..], &self[..i])),
+ match self.iter().position(|c| predicate(*c)) {
+ Some(i) => Ok(self.take_split(i)),
None => Ok(self.take_split(self.input_len())),
}
}
@@ -742,9 +608,9 @@ impl<'a> InputTakeAtPosition for &'a [u8] {
where
P: Fn(Self::Item) -> bool,
{
- match (0..self.len()).find(|b| predicate(self[*b])) {
+ match self.iter().position(|c| predicate(*c)) {
Some(0) => Err(Err::Error(E::from_error_kind(self, e))),
- Some(i) => Ok((&self[i..], &self[..i])),
+ Some(i) => Ok(self.take_split(i)),
None => {
if self.is_empty() {
Err(Err::Error(E::from_error_kind(self, e)))
@@ -764,7 +630,8 @@ impl<'a> InputTakeAtPosition for &'a str {
P: Fn(Self::Item) -> bool,
{
match self.find(predicate) {
- Some(i) => Ok((&self[i..], &self[..i])),
+ // find() returns a byte index that is already in the slice at a char boundary
+ Some(i) => unsafe { Ok((self.get_unchecked(i..), self.get_unchecked(..i))) },
None => Err(Err::Incomplete(Needed::new(1))),
}
}
@@ -779,7 +646,8 @@ impl<'a> InputTakeAtPosition for &'a str {
{
match self.find(predicate) {
Some(0) => Err(Err::Error(E::from_error_kind(self, e))),
- Some(i) => Ok((&self[i..], &self[..i])),
+ // find() returns a byte index that is already in the slice at a char boundary
+ Some(i) => unsafe { Ok((self.get_unchecked(i..), self.get_unchecked(..i))) },
None => Err(Err::Incomplete(Needed::new(1))),
}
}
@@ -792,8 +660,15 @@ impl<'a> InputTakeAtPosition for &'a str {
P: Fn(Self::Item) -> bool,
{
match self.find(predicate) {
- Some(i) => Ok((&self[i..], &self[..i])),
- None => Ok(self.take_split(self.input_len())),
+ // find() returns a byte index that is already in the slice at a char boundary
+ Some(i) => unsafe { Ok((self.get_unchecked(i..), self.get_unchecked(..i))) },
+ // the end of slice is a char boundary
+ None => unsafe {
+ Ok((
+ self.get_unchecked(self.len()..),
+ self.get_unchecked(..self.len()),
+ ))
+ },
}
}
@@ -807,84 +682,19 @@ impl<'a> InputTakeAtPosition for &'a str {
{
match self.find(predicate) {
Some(0) => Err(Err::Error(E::from_error_kind(self, e))),
- Some(i) => Ok((&self[i..], &self[..i])),
+ // find() returns a byte index that is already in the slice at a char boundary
+ Some(i) => unsafe { Ok((self.get_unchecked(i..), self.get_unchecked(..i))) },
None => {
if self.is_empty() {
Err(Err::Error(E::from_error_kind(self, e)))
} else {
- Ok(self.take_split(self.input_len()))
- }
- }
- }
- }
-}
-
-#[cfg(feature = "bitvec")]
-impl<'a, O, T> InputTakeAtPosition for &'a BitSlice<O, T>
-where
- O: BitOrder,
- T: 'a + BitStore,
-{
- type Item = bool;
-
- fn split_at_position<P, E: ParseError<Self>>(&self, predicate: P) -> IResult<Self, Self, E>
- where
- P: Fn(Self::Item) -> bool,
- {
- self
- .iter()
- .copied()
- .position(predicate)
- .map(|i| self.split_at(i))
- .ok_or_else(|| Err::Incomplete(Needed::new(1)))
- }
-
- fn split_at_position1<P, E: ParseError<Self>>(
- &self,
- predicate: P,
- e: ErrorKind,
- ) -> IResult<Self, Self, E>
- where
- P: Fn(Self::Item) -> bool,
- {
- match self.iter().copied().position(predicate) {
- Some(0) => Err(Err::Error(E::from_error_kind(self, e))),
- Some(i) => Ok(self.split_at(i)),
- None => Err(Err::Incomplete(Needed::new(1))),
- }
- }
-
- fn split_at_position_complete<P, E: ParseError<Self>>(
- &self,
- predicate: P,
- ) -> IResult<Self, Self, E>
- where
- P: Fn(Self::Item) -> bool,
- {
- self
- .iter()
- .position(|b| predicate(*b))
- .map(|i| self.split_at(i))
- .or_else(|| Some((self, Self::default())))
- .ok_or_else(|| unreachable!())
- }
-
- fn split_at_position1_complete<P, E: ParseError<Self>>(
- &self,
- predicate: P,
- e: ErrorKind,
- ) -> IResult<Self, Self, E>
- where
- P: Fn(Self::Item) -> bool,
- {
- match self.iter().copied().position(predicate) {
- Some(0) => Err(Err::Error(E::from_error_kind(self, e))),
- Some(i) => Ok(self.split_at(i)),
- None => {
- if self.is_empty() {
- Err(Err::Error(E::from_error_kind(self, e)))
- } else {
- Ok((self, Self::default()))
+ // the end of slice is a char boundary
+ unsafe {
+ Ok((
+ self.get_unchecked(self.len()..),
+ self.get_unchecked(..self.len()),
+ ))
+ }
}
}
}
@@ -1051,31 +861,14 @@ impl<'a, 'b> Compare<&'b str> for &'a str {
}
}
-#[cfg(feature = "bitvec")]
-impl<'a, 'b, O1, O2, T1, T2> Compare<&'b BitSlice<O2, T2>> for &'a BitSlice<O1, T1>
-where
- O1: BitOrder,
- O2: BitOrder,
- T1: 'a + BitStore,
- T2: 'a + BitStore,
-{
- #[inline]
- fn compare(&self, other: &'b BitSlice<O2, T2>) -> CompareResult {
- match self.iter().zip(other.iter()).position(|(a, b)| a != b) {
- Some(_) => CompareResult::Error,
- None => {
- if self.len() >= other.len() {
- CompareResult::Ok
- } else {
- CompareResult::Incomplete
- }
- }
- }
+impl<'a, 'b> Compare<&'b [u8]> for &'a str {
+ #[inline(always)]
+ fn compare(&self, t: &'b [u8]) -> CompareResult {
+ AsBytes::as_bytes(self).compare(t)
}
-
#[inline(always)]
- fn compare_no_case(&self, other: &'b BitSlice<O2, T2>) -> CompareResult {
- self.compare(other)
+ fn compare_no_case(&self, t: &'b [u8]) -> CompareResult {
+ AsBytes::as_bytes(self).compare_no_case(t)
}
}
@@ -1121,28 +914,6 @@ impl<'a> FindToken<char> for &'a str {
}
}
-#[cfg(feature = "bitvec")]
-impl<'a, O, T> FindToken<bool> for &'a BitSlice<O, T>
-where
- O: BitOrder,
- T: 'a + BitStore,
-{
- fn find_token(&self, token: bool) -> bool {
- self.iter().copied().any(|i| i == token)
- }
-}
-
-#[cfg(feature = "bitvec")]
-impl<'a, O, T> FindToken<(usize, bool)> for &'a BitSlice<O, T>
-where
- O: BitOrder,
- T: 'a + BitStore,
-{
- fn find_token(&self, token: (usize, bool)) -> bool {
- self.iter().copied().enumerate().any(|i| i == token)
- }
-}
-
/// Look for a substring in self
pub trait FindSubstring<T> {
/// Returns the byte position of the substring if it is found
@@ -1196,29 +967,6 @@ impl<'a, 'b> FindSubstring<&'b str> for &'a str {
}
}
-#[cfg(feature = "bitvec")]
-impl<'a, 'b, O1, O2, T1, T2> FindSubstring<&'b BitSlice<O2, T2>> for &'a BitSlice<O1, T1>
-where
- O1: BitOrder,
- O2: BitOrder,
- T1: 'a + BitStore,
- T2: 'b + BitStore,
-{
- fn find_substring(&self, substr: &'b BitSlice<O2, T2>) -> Option<usize> {
- if substr.len() > self.len() {
- return None;
- }
-
- if substr.is_empty() {
- return Some(0);
- }
-
- self
- .windows(substr.len())
- .position(|window| window == substr)
- }
-}
-
/// Used to integrate `str`'s `parse()` method
pub trait ParseTo<R> {
/// Succeeds if `parse()` succeeded. The byte slice implementation
@@ -1257,15 +1005,6 @@ macro_rules! impl_fn_slice {
}
macro_rules! slice_range_impl {
- ( BitSlice, $ty:ty ) => {
- impl<'a, O, T> Slice<$ty> for &'a BitSlice<O, T>
- where
- O: BitOrder,
- T: BitStore,
- {
- impl_fn_slice!($ty);
- }
- };
( [ $for_type:ident ], $ty:ty ) => {
impl<'a, $for_type> Slice<$ty> for &'a [$for_type] {
impl_fn_slice!($ty);
@@ -1279,12 +1018,6 @@ macro_rules! slice_range_impl {
}
macro_rules! slice_ranges_impl {
- ( BitSlice ) => {
- slice_range_impl! {BitSlice, Range<usize>}
- slice_range_impl! {BitSlice, RangeTo<usize>}
- slice_range_impl! {BitSlice, RangeFrom<usize>}
- slice_range_impl! {BitSlice, RangeFull}
- };
( [ $for_type:ident ] ) => {
slice_range_impl! {[$for_type], Range<usize>}
slice_range_impl! {[$for_type], RangeTo<usize>}
@@ -1302,9 +1035,6 @@ macro_rules! slice_ranges_impl {
slice_ranges_impl! {str}
slice_ranges_impl! {[T]}
-#[cfg(feature = "bitvec")]
-slice_ranges_impl! {BitSlice}
-
macro_rules! array_impls {
($($N:expr)+) => {
$(
@@ -1483,46 +1213,6 @@ impl ExtendInto for char {
}
}
-#[cfg(all(feature = "alloc", feature = "bitvec"))]
-impl<O, T> ExtendInto for BitSlice<O, T>
-where
- O: BitOrder,
- T: BitStore,
-{
- type Item = bool;
- type Extender = BitVec<O, T>;
-
- #[inline]
- fn new_builder(&self) -> BitVec<O, T> {
- BitVec::new()
- }
-
- #[inline]
- fn extend_into(&self, acc: &mut Self::Extender) {
- acc.extend(self.iter());
- }
-}
-
-#[cfg(all(feature = "alloc", feature = "bitvec"))]
-impl<'a, O, T> ExtendInto for &'a BitSlice<O, T>
-where
- O: BitOrder,
- T: 'a + BitStore,
-{
- type Item = bool;
- type Extender = BitVec<O, T>;
-
- #[inline]
- fn new_builder(&self) -> BitVec<O, T> {
- BitVec::new()
- }
-
- #[inline]
- fn extend_into(&self, acc: &mut Self::Extender) {
- acc.extend(self.iter());
- }
-}
-
/// Helper trait to convert numbers to usize.
///
/// By default, usize implements `From<u8>` and `From<u16>` but not
@@ -1628,6 +1318,83 @@ impl<I> ErrorConvert<error::VerboseError<(I, usize)>> for error::VerboseError<I>
}
}
+#[cfg(feature = "std")]
+#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
+/// Helper trait to show a byte slice as a hex dump
+pub trait HexDisplay {
+ /// Converts the value of `self` to a hex dump, returning the owned
+ /// `String`.
+ fn to_hex(&self, chunk_size: usize) -> String;
+
+ /// Converts the value of `self` to a hex dump beginning at `from` address, returning the owned
+ /// `String`.
+ fn to_hex_from(&self, chunk_size: usize, from: usize) -> String;
+}
+
+#[cfg(feature = "std")]
+static CHARS: &[u8] = b"0123456789abcdef";
+
+#[cfg(feature = "std")]
+impl HexDisplay for [u8] {
+ #[allow(unused_variables)]
+ fn to_hex(&self, chunk_size: usize) -> String {
+ self.to_hex_from(chunk_size, 0)
+ }
+
+ #[allow(unused_variables)]
+ fn to_hex_from(&self, chunk_size: usize, from: usize) -> String {
+ let mut v = Vec::with_capacity(self.len() * 3);
+ let mut i = from;
+ for chunk in self.chunks(chunk_size) {
+ let s = format!("{:08x}", i);
+ for &ch in s.as_bytes().iter() {
+ v.push(ch);
+ }
+ v.push(b'\t');
+
+ i += chunk_size;
+
+ for &byte in chunk {
+ v.push(CHARS[(byte >> 4) as usize]);
+ v.push(CHARS[(byte & 0xf) as usize]);
+ v.push(b' ');
+ }
+ if chunk_size > chunk.len() {
+ for j in 0..(chunk_size - chunk.len()) {
+ v.push(b' ');
+ v.push(b' ');
+ v.push(b' ');
+ }
+ }
+ v.push(b'\t');
+
+ for &byte in chunk {
+ if (byte >= 32 && byte <= 126) || byte >= 128 {
+ v.push(byte);
+ } else {
+ v.push(b'.');
+ }
+ }
+ v.push(b'\n');
+ }
+
+ String::from_utf8_lossy(&v[..]).into_owned()
+ }
+}
+
+#[cfg(feature = "std")]
+impl HexDisplay for str {
+ #[allow(unused_variables)]
+ fn to_hex(&self, chunk_size: usize) -> String {
+ self.to_hex_from(chunk_size, 0)
+ }
+
+ #[allow(unused_variables)]
+ fn to_hex_from(&self, chunk_size: usize, from: usize) -> String {
+ self.as_bytes().to_hex_from(chunk_size, from)
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/util.rs b/src/util.rs
deleted file mode 100644
index c48f808..0000000
--- a/src/util.rs
+++ /dev/null
@@ -1,218 +0,0 @@
-#[cfg(feature = "std")]
-use crate::internal::IResult;
-#[cfg(feature = "std")]
-use std::fmt::Debug;
-
-#[cfg(feature = "std")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
-/// Helper trait to show a byte slice as a hex dump
-pub trait HexDisplay {
- /// Converts the value of `self` to a hex dump, returning the owned
- /// `String`.
- fn to_hex(&self, chunk_size: usize) -> String;
-
- /// Converts the value of `self` to a hex dump beginning at `from` address, returning the owned
- /// `String`.
- fn to_hex_from(&self, chunk_size: usize, from: usize) -> String;
-}
-
-#[cfg(feature = "std")]
-static CHARS: &[u8] = b"0123456789abcdef";
-
-#[cfg(feature = "std")]
-impl HexDisplay for [u8] {
- #[allow(unused_variables)]
- fn to_hex(&self, chunk_size: usize) -> String {
- self.to_hex_from(chunk_size, 0)
- }
-
- #[allow(unused_variables)]
- fn to_hex_from(&self, chunk_size: usize, from: usize) -> String {
- let mut v = Vec::with_capacity(self.len() * 3);
- let mut i = from;
- for chunk in self.chunks(chunk_size) {
- let s = format!("{:08x}", i);
- for &ch in s.as_bytes().iter() {
- v.push(ch);
- }
- v.push(b'\t');
-
- i += chunk_size;
-
- for &byte in chunk {
- v.push(CHARS[(byte >> 4) as usize]);
- v.push(CHARS[(byte & 0xf) as usize]);
- v.push(b' ');
- }
- if chunk_size > chunk.len() {
- for j in 0..(chunk_size - chunk.len()) {
- v.push(b' ');
- v.push(b' ');
- v.push(b' ');
- }
- }
- v.push(b'\t');
-
- for &byte in chunk {
- if (byte >= 32 && byte <= 126) || byte >= 128 {
- v.push(byte);
- } else {
- v.push(b'.');
- }
- }
- v.push(b'\n');
- }
-
- String::from_utf8_lossy(&v[..]).into_owned()
- }
-}
-
-#[cfg(feature = "std")]
-impl HexDisplay for str {
- #[allow(unused_variables)]
- fn to_hex(&self, chunk_size: usize) -> String {
- self.to_hex_from(chunk_size, 0)
- }
-
- #[allow(unused_variables)]
- fn to_hex_from(&self, chunk_size: usize, from: usize) -> String {
- self.as_bytes().to_hex_from(chunk_size, from)
- }
-}
-
-#[doc(hidden)]
-#[macro_export]
-macro_rules! nom_line (
- () => (line!());
-);
-
-#[doc(hidden)]
-#[macro_export]
-macro_rules! nom_println (
- ($($args:tt)*) => (println!($($args)*));
-);
-
-#[doc(hidden)]
-#[macro_export]
-macro_rules! nom_stringify (
- ($($args:tt)*) => (stringify!($($args)*));
-);
-
-/// Prints a message if the parser fails.
-///
-/// The message prints the `Error` or `Incomplete`
-/// and the parser's calling code
-///
-/// ```
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(f, dbg_basic!( tag!( "abcd" ) ) );
-///
-/// let a = &b"efgh"[..];
-///
-/// // Will print the following message:
-/// // Error(Position(0, [101, 102, 103, 104])) at l.5 by ' tag ! ( "abcd" ) '
-/// f(a);
-/// # }
-/// ```
-#[macro_export(local_inner_macros)]
-macro_rules! dbg_basic (
- ($i: expr, $submac:ident!( $($args:tt)* )) => (
- {
- use $crate::lib::std::result::Result::*;
- let l = nom_line!();
- match $submac!($i, $($args)*) {
- Err(e) => {
- nom_println!("Err({:?}) at l.{} by ' {} '", e, l, nom_stringify!($submac!($($args)*)));
- Err(e)
- },
- a => a,
- }
- }
- );
-
- ($i:expr, $f:ident) => (
- dbg_basic!($i, call!($f));
- );
-);
-
-/// Prints a message and the input if the parser fails.
-///
-/// The message prints the `Error` or `Incomplete`
-/// and the parser's calling code.
-///
-/// It also displays the input in hexdump format
-///
-/// ```rust
-/// use nom::{IResult, dbg_dmp, bytes::complete::tag};
-///
-/// fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
-/// dbg_dmp(tag("abcd"), "tag")(i)
-/// }
-///
-/// let a = &b"efghijkl"[..];
-///
-/// // Will print the following message:
-/// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) '
-/// // 00000000 65 66 67 68 69 6a 6b 6c efghijkl
-/// f(a);
-/// ```
-#[cfg(feature = "std")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
-pub fn dbg_dmp<'a, F, O, E: Debug>(
- f: F,
- context: &'static str,
-) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E>
-where
- F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
-{
- move |i: &'a [u8]| match f(i) {
- Err(e) => {
- println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8));
- Err(e)
- }
- a => a,
- }
-}
-
-/// Prints a message and the input if the parser fails.
-///
-/// The message prints the `Error` or `Incomplete`
-/// and the parser's calling code.
-///
-/// It also displays the input in hexdump format
-///
-/// ```ignore
-/// # #[macro_use] extern crate nom;
-/// # fn main() {
-/// named!(f, dbg_dmp!( tag!( "abcd" ) ) );
-///
-/// let a = &b"efghijkl"[..];
-///
-/// // Will print the following message:
-/// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) '
-/// // 00000000 65 66 67 68 69 6a 6b 6c efghijkl
-/// f(a);
-/// # }
-#[macro_export(local_inner_macros)]
-#[cfg(feature = "std")]
-#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
-macro_rules! dbg_dmp (
- ($i: expr, $submac:ident!( $($args:tt)* )) => (
- {
- use $crate::HexDisplay;
- let l = nom_line!();
- match $submac!($i, $($args)*) {
- Err(e) => {
- nom_println!("Error({:?}) at l.{} by ' {} '\n{}", e, l, nom_stringify!($submac!($($args)*)), $i.to_hex(8));
- Err(e)
- },
- a => a,
- }
- }
- );
-
- ($i:expr, $f:ident) => (
- dbg_dmp!($i, call!($f));
- );
-);
diff --git a/tests/arithmetic.rs b/tests/arithmetic.rs
index 393c7e7..5b627a9 100644
--- a/tests/arithmetic.rs
+++ b/tests/arithmetic.rs
@@ -1,5 +1,3 @@
-extern crate nom;
-
use nom::{
branch::alt,
bytes::complete::tag,
@@ -39,7 +37,7 @@ fn term(i: &str) -> IResult<&str, i64> {
fold_many0(
pair(alt((char('*'), char('/'))), factor),
- init,
+ move || init,
|acc, (op, val): (char, i64)| {
if op == '*' {
acc * val
@@ -55,7 +53,7 @@ fn expr(i: &str) -> IResult<&str, i64> {
fold_many0(
pair(alt((char('+'), char('-'))), term),
- init,
+ move || init,
|acc, (op, val): (char, i64)| {
if op == '+' {
acc + val
diff --git a/tests/arithmetic_ast.rs b/tests/arithmetic_ast.rs
index 9852f6c..ca15110 100644
--- a/tests/arithmetic_ast.rs
+++ b/tests/arithmetic_ast.rs
@@ -1,5 +1,3 @@
-extern crate nom;
-
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
@@ -33,7 +31,7 @@ pub enum Oper {
}
impl Display for Expr {
- fn fmt(&self, format: &mut Formatter) -> fmt::Result {
+ fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result {
use self::Expr::*;
match *self {
Value(val) => write!(format, "{}", val),
@@ -47,7 +45,7 @@ impl Display for Expr {
}
impl Debug for Expr {
- fn fmt(&self, format: &mut Formatter) -> fmt::Result {
+ fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result {
use self::Expr::*;
match *self {
Value(val) => write!(format, "{}", val),
diff --git a/tests/bitstream.rs b/tests/bitstream.rs
deleted file mode 100644
index 46aae94..0000000
--- a/tests/bitstream.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-#![cfg(feature = "bitvec")]
-
-use bitvec::prelude::*;
-use nom::{
- bytes::complete::{tag, take},
- combinator::map,
- IResult,
-};
-
-#[test]
-fn parse_bitstream() {
- let data = [0xA5u8, 0x69, 0xF0, 0xC3];
- let bits = data.view_bits::<Msb0>();
-
- fn parser(bits: &BitSlice<Msb0, u8>) -> IResult<&BitSlice<Msb0, u8>, &BitSlice<Msb0, u8>> {
- tag(bits![1, 0, 1, 0])(bits)
- }
-
- assert_eq!(parser(bits), Ok((&bits[4..], &bits[..4])));
-}
-
-#[test]
-fn parse_bitstream_map() {
- let data = [0b1000_0000];
- let bits = data.view_bits::<Msb0>();
-
- fn parser(bits: &BitSlice<Msb0, u8>) -> IResult<&BitSlice<Msb0, u8>, bool> {
- map(take(1_u8), |val: &BitSlice<Msb0, u8>| val[0])(bits)
- }
-
- assert_eq!(parser(bits), Ok((&bits[1..], true)));
-}
diff --git a/tests/css.rs b/tests/css.rs
index 5b1e79a..ad3d72b 100644
--- a/tests/css.rs
+++ b/tests/css.rs
@@ -1,5 +1,3 @@
-extern crate nom;
-
use nom::bytes::complete::{tag, take_while_m_n};
use nom::combinator::map_res;
use nom::sequence::tuple;
diff --git a/tests/custom_errors.rs b/tests/custom_errors.rs
index ad14ee5..2021713 100644
--- a/tests/custom_errors.rs
+++ b/tests/custom_errors.rs
@@ -1,15 +1,14 @@
#![allow(dead_code)]
-#![cfg_attr(feature = "cargo-clippy", allow(block_in_if_condition_stmt))]
-
-#[macro_use]
-extern crate nom;
+use nom::bytes::streaming::tag;
use nom::character::streaming::digit1 as digit;
+use nom::combinator::verify;
use nom::error::{ErrorKind, ParseError};
+#[cfg(feature = "alloc")]
+use nom::multi::count;
+use nom::sequence::terminated;
use nom::IResult;
-use std::convert::From;
-
#[derive(Debug)]
pub struct CustomError(String);
@@ -31,19 +30,19 @@ impl<'a> ParseError<&'a str> for CustomError {
fn test1(input: &str) -> IResult<&str, &str, CustomError> {
//fix_error!(input, CustomError, tag!("abcd"))
- tag!(input, "abcd")
+ tag("abcd")(input)
}
fn test2(input: &str) -> IResult<&str, &str, CustomError> {
//terminated!(input, test1, fix_error!(CustomError, digit))
- terminated!(input, test1, digit)
+ terminated(test1, digit)(input)
}
fn test3(input: &str) -> IResult<&str, &str, CustomError> {
- verify!(input, test1, |s: &str| { s.starts_with("abcd") })
+ verify(test1, |s: &str| s.starts_with("abcd"))(input)
}
#[cfg(feature = "alloc")]
fn test4(input: &str) -> IResult<&str, Vec<&str>, CustomError> {
- count!(input, test1, 4)
+ count(test1, 4)(input)
}
diff --git a/tests/float.rs b/tests/float.rs
index 6593f9e..634b189 100644
--- a/tests/float.rs
+++ b/tests/float.rs
@@ -1,34 +1,33 @@
-#[macro_use]
-extern crate nom;
-
+use nom::branch::alt;
+use nom::bytes::complete::tag;
use nom::character::streaming::digit1 as digit;
+use nom::combinator::{map, map_res, opt, recognize};
+use nom::sequence::{delimited, pair};
+use nom::IResult;
use std::str;
use std::str::FromStr;
-named!(
- unsigned_float<f32>,
- map_res!(
- map_res!(
- recognize!(alt!(
- delimited!(digit, tag!("."), opt!(digit)) | delimited!(opt!(digit), tag!("."), digit)
- )),
- str::from_utf8
- ),
- FromStr::from_str
- )
-);
+fn unsigned_float(i: &[u8]) -> IResult<&[u8], f32> {
+ let float_bytes = recognize(alt((
+ delimited(digit, tag("."), opt(digit)),
+ delimited(opt(digit), tag("."), digit),
+ )));
+ let float_str = map_res(float_bytes, str::from_utf8);
+ map_res(float_str, FromStr::from_str)(i)
+}
-named!(
- float<f32>,
- map!(
- pair!(opt!(alt!(tag!("+") | tag!("-"))), unsigned_float),
- |(sign, value): (Option<&[u8]>, f32)| sign
- .and_then(|s| if s[0] == b'-' { Some(-1f32) } else { None })
- .unwrap_or(1f32)
- * value
- )
-);
+fn float(i: &[u8]) -> IResult<&[u8], f32> {
+ map(
+ pair(opt(alt((tag("+"), tag("-")))), unsigned_float),
+ |(sign, value)| {
+ sign
+ .and_then(|s| if s[0] == b'-' { Some(-1f32) } else { None })
+ .unwrap_or(1f32)
+ * value
+ },
+ )(i)
+}
#[test]
fn unsigned_float_test() {
diff --git a/tests/fnmut.rs b/tests/fnmut.rs
index 1314967..b1486cb 100644
--- a/tests/fnmut.rs
+++ b/tests/fnmut.rs
@@ -1,5 +1,3 @@
-extern crate nom;
-
use nom::{
bytes::complete::tag,
multi::{many0, many0_count},
diff --git a/tests/inference.rs b/tests/inference.rs
deleted file mode 100644
index 4555d7a..0000000
--- a/tests/inference.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-//! test type inference issues in parsee compilation
-//#![feature(trace_macros)]
-#![allow(dead_code)]
-#![allow(unused_comparisons)]
-#![allow(unused_variables)]
-#![allow(unused_imports)]
-
-#[macro_use]
-extern crate nom;
-
-use nom::character::{is_digit, streaming::alpha1 as alpha};
-use std::str;
-
-// issue #617
-named!(multi<&[u8], () >, fold_many0!( take_while1!( is_digit ), (), |_, _| {}));
-
-// issue #561
-#[cfg(feature = "alloc")]
-named!(
- value<Vec<Vec<&str>>>,
- do_parse!(
- first_line: map_res!(is_not!("\n"), std::str::from_utf8)
- >> rest:
- many_m_n!(
- 0,
- 1,
- separated_list0!(
- tag!("\n\t"),
- map_res!(take_while!(call!(|c| c != b'\n')), std::str::from_utf8)
- )
- )
- >> (rest)
- )
-);
-
-// issue #534
-#[cfg(feature = "alloc")]
-fn wrap_suffix(input: &Option<Vec<&[u8]>>) -> Option<String> {
- if input.is_some() {
- // I've tried both of the lines below individually and get the same error.
- Some("hello".to_string())
- //Some(str::from_utf8(u).expect("Found invalid UTF-8").to_string())
- } else {
- None
- }
-}
-
-#[cfg(feature = "alloc")]
-named!(parse_suffix<&[u8],Option<String>>,do_parse!(
- u: opt!(many1!(alt!(
- complete!(tag!("%")) | complete!(tag!("#")) | complete!(tag!("@")) | complete!(alpha)
- ))) >>
- (wrap_suffix(&u))
-));
diff --git a/tests/ini.rs b/tests/ini.rs
index 3bcec87..e556f44 100644
--- a/tests/ini.rs
+++ b/tests/ini.rs
@@ -1,13 +1,11 @@
-#[macro_use]
-extern crate nom;
-
use nom::{
bytes::complete::take_while,
character::complete::{
alphanumeric1 as alphanumeric, char, multispace0 as multispace, space0 as space,
},
- combinator::map_res,
- sequence::delimited,
+ combinator::{map, map_res, opt},
+ multi::many0,
+ sequence::{delimited, pair, separated_pair, terminated, tuple},
IResult,
};
@@ -21,56 +19,39 @@ fn category(i: &[u8]) -> IResult<&[u8], &str> {
)(i)
}
-fn complete_byte_slice_to_str<'a>(s: &'a [u8]) -> Result<&'a str, str::Utf8Error> {
- str::from_utf8(s)
+fn key_value(i: &[u8]) -> IResult<&[u8], (&str, &str)> {
+ let (i, key) = map_res(alphanumeric, str::from_utf8)(i)?;
+ let (i, _) = tuple((opt(space), char('='), opt(space)))(i)?;
+ let (i, val) = map_res(take_while(|c| c != b'\n' && c != b';'), str::from_utf8)(i)?;
+ let (i, _) = opt(pair(char(';'), take_while(|c| c != b'\n')))(i)?;
+ Ok((i, (key, val)))
+}
+
+fn keys_and_values(i: &[u8]) -> IResult<&[u8], HashMap<&str, &str>> {
+ map(many0(terminated(key_value, opt(multispace))), |vec| {
+ vec.into_iter().collect()
+ })(i)
}
-named!(key_value <&[u8],(&str,&str)>,
- do_parse!(
- key: map_res!(alphanumeric, complete_byte_slice_to_str)
- >> opt!(space)
- >> char!('=')
- >> opt!(space)
- >> val: map_res!(
- take_while!(call!(|c| c != b'\n' && c != b';')),
- complete_byte_slice_to_str
- )
- >> opt!(pair!(char!(';'), take_while!(call!(|c| c != b'\n'))))
- >> (key, val)
- )
-);
-
-named!(keys_and_values<&[u8], HashMap<&str, &str> >,
- map!(
- many0!(terminated!(key_value, opt!(multispace))),
- |vec: Vec<_>| vec.into_iter().collect()
- )
-);
-
-named!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,
- do_parse!(
- category: category >>
- opt!(multispace) >>
- keys: keys_and_values >>
- (category, keys)
- )
-);
-
-named!(categories<&[u8], HashMap<&str, HashMap<&str,&str> > >,
- map!(
- many0!(
- separated_pair!(
- category,
- opt!(multispace),
- map!(
- many0!(terminated!(key_value, opt!(multispace))),
- |vec: Vec<_>| vec.into_iter().collect()
- )
- )
- ),
- |vec: Vec<_>| vec.into_iter().collect()
- )
-);
+fn category_and_keys(i: &[u8]) -> IResult<&[u8], (&str, HashMap<&str, &str>)> {
+ let (i, category) = terminated(category, opt(multispace))(i)?;
+ let (i, keys) = keys_and_values(i)?;
+ Ok((i, (category, keys)))
+}
+
+fn categories(i: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str>>> {
+ map(
+ many0(separated_pair(
+ category,
+ opt(multispace),
+ map(
+ many0(terminated(key_value, opt(multispace))),
+ |vec: Vec<_>| vec.into_iter().collect(),
+ ),
+ )),
+ |vec: Vec<_>| vec.into_iter().collect(),
+ )(i)
+}
#[test]
fn parse_category_test() {
diff --git a/tests/ini_str.rs b/tests/ini_str.rs
index 15b8623..3702303 100644
--- a/tests/ini_str.rs
+++ b/tests/ini_str.rs
@@ -1,11 +1,9 @@
-#[macro_use]
-extern crate nom;
-
use nom::{
- bytes::complete::{is_a, take_while},
+ bytes::complete::{is_a, tag, take_till, take_while},
character::complete::{alphanumeric1 as alphanumeric, char, space0 as space},
combinator::opt,
- sequence::{delimited, terminated},
+ multi::many0,
+ sequence::{delimited, pair, terminated, tuple},
IResult,
};
@@ -30,21 +28,20 @@ fn category(i: &str) -> IResult<&str, &str> {
)(i)
}
-named!(key_value <&str,(&str,&str)>,
- do_parse!(
- key: alphanumeric >>
- opt!(space) >>
- tag!("=") >>
- opt!(space) >>
- val: take_till!(is_line_ending_or_comment) >>
- opt!(space) >>
- opt!(pair!(tag!(";"), not_line_ending)) >>
- opt!(space_or_line_ending) >>
- (key, val)
- )
-);
+fn key_value(i: &str) -> IResult<&str, (&str, &str)> {
+ let (i, key) = alphanumeric(i)?;
+ let (i, _) = tuple((opt(space), tag("="), opt(space)))(i)?;
+ let (i, val) = take_till(is_line_ending_or_comment)(i)?;
+ let (i, _) = opt(space)(i)?;
+ let (i, _) = opt(pair(tag(";"), not_line_ending))(i)?;
+ let (i, _) = opt(space_or_line_ending)(i)?;
+
+ Ok((i, (key, val)))
+}
-named!(keys_and_values_aggregator<&str, Vec<(&str, &str)> >, many0!(key_value));
+fn keys_and_values_aggregator(i: &str) -> IResult<&str, Vec<(&str, &str)>> {
+ many0(key_value)(i)
+}
fn keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>> {
match keys_and_values_aggregator(input) {
@@ -53,11 +50,13 @@ fn keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>> {
}
}
-named!(category_and_keys<&str,(&str,HashMap<&str,&str>)>,
- pair!(category, keys_and_values)
-);
+fn category_and_keys(i: &str) -> IResult<&str, (&str, HashMap<&str, &str>)> {
+ pair(category, keys_and_values)(i)
+}
-named!(categories_aggregator<&str, Vec<(&str, HashMap<&str,&str>)> >, many0!(category_and_keys));
+fn categories_aggregator(i: &str) -> IResult<&str, Vec<(&str, HashMap<&str, &str>)>> {
+ many0(category_and_keys)(i)
+}
fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str>>> {
match categories_aggregator(input) {
diff --git a/tests/issues.rs b/tests/issues.rs
index 3ffc271..79c3493 100644
--- a/tests/issues.rs
+++ b/tests/issues.rs
@@ -2,15 +2,7 @@
#![allow(dead_code)]
#![cfg_attr(feature = "cargo-clippy", allow(redundant_closure))]
-#[macro_use]
-extern crate nom;
-
-use nom::{
- character::{is_digit, streaming::space1 as space},
- error::ErrorKind,
- number::streaming::le_u64,
- Err, IResult, Needed,
-};
+use nom::{error::ErrorKind, Err, IResult, Needed};
#[allow(dead_code)]
struct Range {
@@ -26,78 +18,36 @@ pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
}
}
-//trace_macros!(true);
-
-#[allow(dead_code)]
-named!(range<&[u8], Range>,
- alt!(
- do_parse!(
- start: take_char >>
- tag!("-") >>
- end: take_char >>
- (Range {
- start: start,
- end: end,
- })
- ) |
- map!(
- take_char,
- |c| {
- Range {
- start: c,
- end: c,
- }
- }
- )
- )
-);
-
-#[allow(dead_code)]
-named!(literal<&[u8], Vec<char> >,
- map!(
- many1!(take_char),
- |cs| {
- cs
- }
- )
-);
-
-#[test]
-fn issue_58() {
- let _ = range(&b"abcd"[..]);
- let _ = literal(&b"abcd"[..]);
-}
-
-//trace_macros!(false);
-
#[cfg(feature = "std")]
mod parse_int {
use nom::HexDisplay;
use nom::{
character::streaming::{digit1 as digit, space1 as space},
+ combinator::{complete, map, opt},
+ multi::many0,
IResult,
};
use std::str;
- named!(parse_ints<Vec<i32>>, many0!(spaces_or_int));
+ fn parse_ints(input: &[u8]) -> IResult<&[u8], Vec<i32>> {
+ many0(spaces_or_int)(input)
+ }
fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32> {
println!("{}", input.to_hex(8));
- do_parse!(
- input,
- opt!(complete!(space))
- >> res: map!(complete!(digit), |x| {
- println!("x: {:?}", x);
- let result = str::from_utf8(x).unwrap();
- println!("Result: {}", result);
- println!("int is empty?: {}", x.is_empty());
- match result.parse() {
- Ok(i) => i,
- Err(e) => panic!("UH OH! NOT A DIGIT! {:?}", e),
- }
- })
- >> (res)
- )
+ let (i, _) = opt(complete(space))(input)?;
+ let (i, res) = map(complete(digit), |x| {
+ println!("x: {:?}", x);
+ let result = str::from_utf8(x).unwrap();
+ println!("Result: {}", result);
+ println!("int is empty?: {}", x.is_empty());
+ match result.parse() {
+ Ok(i) => i,
+ Err(e) => panic!("UH OH! NOT A DIGIT! {:?}", e),
+ }
+ })(i)?;
+
+ Ok((i, res))
}
#[test]
@@ -114,67 +64,34 @@ mod parse_int {
#[test]
fn usize_length_bytes_issue() {
+ use nom::multi::length_data;
use nom::number::streaming::be_u16;
- let _: IResult<&[u8], &[u8], (&[u8], ErrorKind)> = length_data!(b"012346", be_u16);
-}
-
-/*
- DOES NOT COMPILE
-#[test]
-fn issue_152() {
- named!(take4, take!(4));
- named!(xyz, tag!("XYZ"));
- named!(abc, tag!("abc"));
-
-
- named!(sw,
- switch!(take4,
- b"abcd" => xyz |
- b"efgh" => abc
- )
- );
+ let _: IResult<&[u8], &[u8], (&[u8], ErrorKind)> = length_data(be_u16)(b"012346");
}
-*/
#[test]
fn take_till_issue() {
- named!(nothing, take_till!(call!(|_| true)));
+ use nom::bytes::streaming::take_till;
+
+ fn nothing(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ take_till(|_| true)(i)
+ }
assert_eq!(nothing(b""), Err(Err::Incomplete(Needed::new(1))));
assert_eq!(nothing(b"abc"), Ok((&b"abc"[..], &b""[..])));
}
-named!(
- issue_498<Vec<&[u8]>>,
- separated_list1!(opt!(space), tag!("abcd"))
-);
-
-named!(issue_308(&str) -> bool,
- do_parse! (
- tag! ("foo") >>
- b: alt! (
- complete!(map! (tag! ("1"), |_: &str|->bool {true})) |
- value! (false)
- ) >>
- (b) ));
-
-#[cfg(feature = "alloc")]
-fn issue_302(input: &[u8]) -> IResult<&[u8], Option<Vec<u64>>> {
- do_parse!(input, entries: cond!(true, count!(le_u64, 3)) >> (entries))
-}
-
#[test]
fn issue_655() {
use nom::character::streaming::{line_ending, not_line_ending};
- named!(twolines(&str) -> (&str, &str),
- do_parse!(
- l1 : not_line_ending >>
- line_ending >>
- l2 : not_line_ending >>
- line_ending >>
- ((l1, l2))
- )
- );
+ fn twolines(i: &str) -> IResult<&str, (&str, &str)> {
+ let (i, l1) = not_line_ending(i)?;
+ let (i, _) = line_ending(i)?;
+ let (i, l2) = not_line_ending(i)?;
+ let (i, _) = line_ending(i)?;
+
+ Ok((i, (l1, l2)))
+ }
assert_eq!(twolines("foo\nbar\n"), Ok(("", ("foo", "bar"))));
assert_eq!(twolines("féo\nbar\n"), Ok(("", ("féo", "bar"))));
@@ -182,79 +99,19 @@ fn issue_655() {
assert_eq!(twolines("foé\r\nbar\n"), Ok(("", ("foé", "bar"))));
}
-#[test]
-fn issue_721() {
- named!(f1<&str, u16>, parse_to!(u16));
- named!(f2<&str, String>, parse_to!(String));
- assert_eq!(f1("1234"), Ok(("", 1234)));
- assert_eq!(f2("foo"), Ok(("", "foo".to_string())));
- //assert_eq!(parse_to!("1234", u16), Ok(("", 1234)));
- //assert_eq!(parse_to!("foo", String), Ok(("", "foo".to_string())));
-}
-
#[cfg(feature = "alloc")]
-named!(issue_717<&[u8], Vec<&[u8]> >,
- separated_list0!(tag!([0x0]), is_not!([0x0u8]))
-);
-
-struct NoPartialEq {
- value: i32,
-}
-
-named!(issue_724<&str, i32>,
- do_parse!(
- metadata: permutation!(
- map!(tag!("hello"), |_| NoPartialEq { value: 1 }),
- map!(tag!("world"), |_| NoPartialEq { value: 2 })
- ) >>
- (metadata.0.value + metadata.1.value)
- )
-);
-
-#[test]
-fn issue_752() {
- assert_eq!(
- Err::Error(("ab", nom::error::ErrorKind::ParseTo)),
- parse_to!("ab", usize).unwrap_err()
- )
-}
-
-fn atom_specials(c: u8) -> bool {
- c == b'q'
-}
-
-named!(
- capability<&str>,
- do_parse!(tag!(" ") >> _atom: map_res!(take_till1!(atom_specials), std::str::from_utf8) >> ("a"))
-);
+fn issue_717(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ use nom::bytes::complete::{is_not, tag};
+ use nom::multi::separated_list0;
-#[test]
-fn issue_759() {
- assert_eq!(capability(b" abcqd"), Ok((&b"qd"[..], "a")));
+ separated_list0(tag([0x0]), is_not([0x0u8]))(i)
}
-named_args!(issue_771(count: usize)<Vec<u32>>,
- length_count!(value!(count), call!(nom::number::streaming::be_u32))
-);
-
-/// This test is in a separate module to check that all required symbols are imported in
-/// `escaped_transform!()`. Without the module, the `use`-es of the current module would
-/// mask the error ('"Use of undeclared type or module `Needed`" in escaped_transform!').
-mod issue_780 {
- named!(issue_780<&str, String>,
- escaped_transform!(call!(::nom::character::streaming::alpha1), '\\', tag!("n"))
- );
-}
-
-// issue 617
-named!(digits, take_while1!(is_digit));
-named!(multi_617<&[u8], () >, fold_many0!( digits, (), |_, _| {}));
-
-// Sad :(
-named!(multi_617_fails<&[u8], () >, fold_many0!( take_while1!( is_digit ), (), |_, _| {}));
-
mod issue_647 {
- use nom::{error::Error, number::streaming::be_f64, Err};
+ use nom::bytes::streaming::tag;
+ use nom::combinator::complete;
+ use nom::multi::separated_list0;
+ use nom::{error::Error, number::streaming::be_f64, Err, IResult};
pub type Input<'a> = &'a [u8];
#[derive(PartialEq, Debug, Clone)]
@@ -267,33 +124,34 @@ mod issue_647 {
input: Input<'a>,
_cs: &'b f64,
) -> Result<(Input<'a>, Vec<f64>), Err<Error<&'a [u8]>>> {
- separated_list0!(input, complete!(tag!(",")), complete!(be_f64))
+ separated_list0(complete(tag(",")), complete(be_f64))(input)
}
- named!(data<Input,Data>, map!(
- do_parse!(
- c: be_f64 >>
- tag!("\n") >>
- v: call!(list,&c) >>
- (c,v)
- ), |(c,v)| {
- Data {
- c: c,
- v: v
- }
- }
- ));
+ fn data(input: Input<'_>) -> IResult<Input<'_>, Data> {
+ let (i, c) = be_f64(input)?;
+ let (i, _) = tag("\n")(i)?;
+ let (i, v) = list(i, &c)?;
+ Ok((i, Data { c, v }))
+ }
}
-named!(issue_775, take_till1!(|_| true));
-
#[test]
fn issue_848_overflow_incomplete_bits_to_bytes() {
- named!(take, take!(0x2000000000000000));
- named!(parser<&[u8], &[u8]>, bits!(bytes!(take)));
+ fn take(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ use nom::bytes::streaming::take;
+ take(0x2000000000000000_usize)(i)
+ }
+ fn parser(i: &[u8]) -> IResult<&[u8], &[u8]> {
+ use nom::bits::{bits, bytes};
+
+ bits(bytes(take))(i)
+ }
assert_eq!(
parser(&b""[..]),
- Err(Err::Failure(error_position!(&b""[..], ErrorKind::TooLarge)))
+ Err(Err::Failure(nom::error_position!(
+ &b""[..],
+ ErrorKind::TooLarge
+ )))
);
}
@@ -338,16 +196,6 @@ fn issue_1027_convert_error_panic_nonempty() {
);
}
-named!(issue_962<&[u8], Vec<&[u8]>>,
- fold_many0!(
- alt!(tag!("aaaa") | tag!("bbbb")),
- Vec::new(), |mut acc: Vec<_>, item| {
- acc.push(item);
- acc
- }
- )
-);
-
#[test]
fn issue_1231_bits_expect_fn_closure() {
use nom::bits::{bits, complete::take};
diff --git a/tests/json.rs b/tests/json.rs
index 5b30c74..e8a06fd 100644
--- a/tests/json.rs
+++ b/tests/json.rs
@@ -1,5 +1,4 @@
#![cfg(feature = "alloc")]
-extern crate nom;
use nom::{
branch::alt,
@@ -83,7 +82,7 @@ fn character(input: &str) -> IResult<&str, char> {
fn string(input: &str) -> IResult<&str, String> {
delimited(
char('"'),
- fold_many0(character, String::new(), |mut string, c| {
+ fold_many0(character, String::new, |mut string, c| {
string.push(c);
string
}),
diff --git a/tests/mp4.rs b/tests/mp4.rs
index c4cee1c..852bf29 100644
--- a/tests/mp4.rs
+++ b/tests/mp4.rs
@@ -1,10 +1,11 @@
#![allow(dead_code)]
-#[macro_use]
-extern crate nom;
-
use nom::{
+ branch::alt,
+ bytes::streaming::{tag, take},
+ combinator::{map, map_res},
error::ErrorKind,
+ multi::many0,
number::streaming::{be_f32, be_u16, be_u32, be_u64},
Err, IResult, Needed,
};
@@ -93,109 +94,109 @@ pub struct Mvhd64 {
track_id: u32
}
-#[allow(non_snake_case)]
-named!(mvhd32 <&[u8], MvhdBox>,
- do_parse!(
- version_flags: be_u32 >>
- created_date: be_u32 >>
- modified_date: be_u32 >>
- scale: be_u32 >>
- duration: be_u32 >>
- speed: be_f32 >>
- volume: be_u16 >> // actually a 2 bytes decimal
- take!(10) >>
- scale_a: be_f32 >>
- rotate_b: be_f32 >>
- angle_u: be_f32 >>
- rotate_c: be_f32 >>
- scale_d: be_f32 >>
- angle_v: be_f32 >>
- position_x: be_f32 >>
- position_y: be_f32 >>
- scale_w: be_f32 >>
- preview: be_u64 >>
- poster: be_u32 >>
- selection: be_u64 >>
- current_time: be_u32 >>
- track_id: be_u32 >>
- (
- MvhdBox::M32(Mvhd32 {
- version_flags: version_flags,
- created_date: created_date,
- modified_date: modified_date,
- scale: scale,
- duration: duration,
- speed: speed,
- volume: volume,
- scaleA: scale_a,
- rotateB: rotate_b,
- angleU: angle_u,
- rotateC: rotate_c,
- scaleD: scale_d,
- angleV: angle_v,
- positionX: position_x,
- positionY: position_y,
- scaleW: scale_w,
- preview: preview,
- poster: poster,
- selection: selection,
- current_time: current_time,
- track_id: track_id
- })
- ))
-);
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn mvhd32(i: &[u8]) -> IResult<&[u8], MvhdBox> {
+ let (i, version_flags) = be_u32(i)?;
+ let (i, created_date) = be_u32(i)?;
+ let (i, modified_date) = be_u32(i)?;
+ let (i, scale) = be_u32(i)?;
+ let (i, duration) = be_u32(i)?;
+ let (i, speed) = be_f32(i)?;
+ let (i, volume) = be_u16(i)?; // actually a 2 bytes decimal
+ let (i, _) = take(10_usize)(i)?;
+ let (i, scale_a) = be_f32(i)?;
+ let (i, rotate_b) = be_f32(i)?;
+ let (i, angle_u) = be_f32(i)?;
+ let (i, rotate_c) = be_f32(i)?;
+ let (i, scale_d) = be_f32(i)?;
+ let (i, angle_v) = be_f32(i)?;
+ let (i, position_x) = be_f32(i)?;
+ let (i, position_y) = be_f32(i)?;
+ let (i, scale_w) = be_f32(i)?;
+ let (i, preview) = be_u64(i)?;
+ let (i, poster) = be_u32(i)?;
+ let (i, selection) = be_u64(i)?;
+ let (i, current_time) = be_u32(i)?;
+ let (i, track_id) = be_u32(i)?;
-#[allow(non_snake_case)]
-named!(mvhd64 <&[u8], MvhdBox>,
- do_parse!(
- version_flags: be_u32 >>
- created_date: be_u64 >>
- modified_date: be_u64 >>
- scale: be_u32 >>
- duration: be_u64 >>
- speed: be_f32 >>
- volume: be_u16 >> // actually a 2 bytes decimal
- take!(10) >>
- scale_a: be_f32 >>
- rotate_b: be_f32 >>
- angle_u: be_f32 >>
- rotate_c: be_f32 >>
- scale_d: be_f32 >>
- angle_v: be_f32 >>
- position_x: be_f32 >>
- position_y: be_f32 >>
- scale_w: be_f32 >>
- preview: be_u64 >>
- poster: be_u32 >>
- selection: be_u64 >>
- current_time: be_u32 >>
- track_id: be_u32 >>
- (
- MvhdBox::M64(Mvhd64 {
- version_flags: version_flags,
- created_date: created_date,
- modified_date: modified_date,
- scale: scale,
- duration: duration,
- speed: speed,
- volume: volume,
- scaleA: scale_a,
- rotateB: rotate_b,
- angleU: angle_u,
- rotateC: rotate_c,
- scaleD: scale_d,
- angleV: angle_v,
- positionX: position_x,
- positionY: position_y,
- scaleW: scale_w,
- preview: preview,
- poster: poster,
- selection: selection,
- current_time: current_time,
- track_id: track_id
- })
- ))
-);
+ let mvhd_box = MvhdBox::M32(Mvhd32 {
+ version_flags,
+ created_date,
+ modified_date,
+ scale,
+ duration,
+ speed,
+ volume,
+ scaleA: scale_a,
+ rotateB: rotate_b,
+ angleU: angle_u,
+ rotateC: rotate_c,
+ scaleD: scale_d,
+ angleV: angle_v,
+ positionX: position_x,
+ positionY: position_y,
+ scaleW: scale_w,
+ preview,
+ poster,
+ selection,
+ current_time,
+ track_id,
+ });
+
+ Ok((i, mvhd_box))
+}
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn mvhd64(i: &[u8]) -> IResult<&[u8], MvhdBox> {
+ let (i, version_flags) = be_u32(i)?;
+ let (i, created_date) = be_u64(i)?;
+ let (i, modified_date) = be_u64(i)?;
+ let (i, scale) = be_u32(i)?;
+ let (i, duration) = be_u64(i)?;
+ let (i, speed) = be_f32(i)?;
+ let (i, volume) = be_u16(i)?; // actually a 2 bytes decimal
+ let (i, _) = take(10_usize)(i)?;
+ let (i, scale_a) = be_f32(i)?;
+ let (i, rotate_b) = be_f32(i)?;
+ let (i, angle_u) = be_f32(i)?;
+ let (i, rotate_c) = be_f32(i)?;
+ let (i, scale_d) = be_f32(i)?;
+ let (i, angle_v) = be_f32(i)?;
+ let (i, position_x) = be_f32(i)?;
+ let (i, position_y) = be_f32(i)?;
+ let (i, scale_w) = be_f32(i)?;
+ let (i, preview) = be_u64(i)?;
+ let (i, poster) = be_u32(i)?;
+ let (i, selection) = be_u64(i)?;
+ let (i, current_time) = be_u32(i)?;
+ let (i, track_id) = be_u32(i)?;
+
+ let mvhd_box = MvhdBox::M64(Mvhd64 {
+ version_flags,
+ created_date,
+ modified_date,
+ scale,
+ duration,
+ speed,
+ volume,
+ scaleA: scale_a,
+ rotateB: rotate_b,
+ angleU: angle_u,
+ rotateC: rotate_c,
+ scaleD: scale_d,
+ angleV: angle_v,
+ positionX: position_x,
+ positionY: position_y,
+ scaleW: scale_w,
+ preview,
+ poster,
+ selection,
+ current_time,
+ track_id,
+ });
+
+ Ok((i, mvhd_box))
+}
#[derive(Debug, Clone)]
pub enum MvhdBox {
@@ -242,16 +243,22 @@ struct MP4BoxHeader {
tag: MP4BoxType,
}
-named!(brand_name<&[u8],&str>, map_res!(take!(4), str::from_utf8));
+fn brand_name(input: &[u8]) -> IResult<&[u8], &str> {
+ map_res(take(4_usize), str::from_utf8)(input)
+}
-named!(filetype_parser<&[u8], FileType>,
- do_parse!(
- m: brand_name >>
- v: take!(4) >>
- c: many0!(brand_name) >>
- (FileType{ major_brand: m, major_brand_version:v, compatible_brands: c })
- )
-);
+fn filetype_parser(input: &[u8]) -> IResult<&[u8], FileType<'_>> {
+ let (i, name) = brand_name(input)?;
+ let (i, version) = take(4_usize)(i)?;
+ let (i, brands) = many0(brand_name)(i)?;
+
+ let ft = FileType {
+ major_brand: name,
+ major_brand_version: version,
+ compatible_brands: brands,
+ };
+ Ok((i, ft))
+}
fn mvhd_box(input: &[u8]) -> IResult<&[u8], MvhdBox> {
let res = if input.len() < 100 {
@@ -261,7 +268,7 @@ fn mvhd_box(input: &[u8]) -> IResult<&[u8], MvhdBox> {
} else if input.len() == 112 {
mvhd64(input)
} else {
- Err(Err::Error(error_position!(input, ErrorKind::TooLarge)))
+ Err(Err::Error(nom::error_position!(input, ErrorKind::TooLarge)))
};
println!("res: {:?}", res);
res
@@ -271,48 +278,43 @@ fn unknown_box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> {
Ok((input, MP4BoxType::Unknown))
}
-//named!(box_type<&[u8], MP4BoxType>,
fn box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> {
- alt!(input,
- tag!("ftyp") => { |_| MP4BoxType::Ftyp } |
- tag!("moov") => { |_| MP4BoxType::Moov } |
- tag!("mdat") => { |_| MP4BoxType::Mdat } |
- tag!("free") => { |_| MP4BoxType::Free } |
- tag!("skip") => { |_| MP4BoxType::Skip } |
- tag!("wide") => { |_| MP4BoxType::Wide } |
- unknown_box_type
- )
+ alt((
+ map(tag("ftyp"), |_| MP4BoxType::Ftyp),
+ map(tag("moov"), |_| MP4BoxType::Moov),
+ map(tag("mdat"), |_| MP4BoxType::Mdat),
+ map(tag("free"), |_| MP4BoxType::Free),
+ map(tag("skip"), |_| MP4BoxType::Skip),
+ map(tag("wide"), |_| MP4BoxType::Wide),
+ unknown_box_type,
+ ))(input)
}
// warning, an alt combinator with 9 branches containing a tag combinator
// can make the compilation very slow. Use functions as sub parsers,
-// or split into multiple alt! parsers if it gets slow
-named!(moov_type<&[u8], MP4BoxType>,
- alt!(
- tag!("mdra") => { |_| MP4BoxType::Mdra } |
- tag!("dref") => { |_| MP4BoxType::Dref } |
- tag!("cmov") => { |_| MP4BoxType::Cmov } |
- tag!("rmra") => { |_| MP4BoxType::Rmra } |
- tag!("iods") => { |_| MP4BoxType::Iods } |
- tag!("mvhd") => { |_| MP4BoxType::Mvhd } |
- tag!("clip") => { |_| MP4BoxType::Clip } |
- tag!("trak") => { |_| MP4BoxType::Trak } |
- tag!("udta") => { |_| MP4BoxType::Udta }
- )
-);
+// or split into multiple alt parsers if it gets slow
+fn moov_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> {
+ alt((
+ map(tag("mdra"), |_| MP4BoxType::Mdra),
+ map(tag("dref"), |_| MP4BoxType::Dref),
+ map(tag("cmov"), |_| MP4BoxType::Cmov),
+ map(tag("rmra"), |_| MP4BoxType::Rmra),
+ map(tag("iods"), |_| MP4BoxType::Iods),
+ map(tag("mvhd"), |_| MP4BoxType::Mvhd),
+ map(tag("clip"), |_| MP4BoxType::Clip),
+ map(tag("trak"), |_| MP4BoxType::Trak),
+ map(tag("udta"), |_| MP4BoxType::Udta),
+ ))(input)
+}
-named!(box_header<&[u8],MP4BoxHeader>,
- do_parse!(
- length: be_u32 >>
- tag: box_type >>
- (MP4BoxHeader{ length: length, tag: tag})
- )
-);
+fn box_header(input: &[u8]) -> IResult<&[u8], MP4BoxHeader> {
+ let (i, length) = be_u32(input)?;
+ let (i, tag) = box_type(i)?;
+ Ok((i, MP4BoxHeader { length, tag }))
+}
-named!(moov_header<&[u8],MP4BoxHeader>,
- do_parse!(
- length: be_u32 >>
- tag: moov_type >>
- (MP4BoxHeader{ length: length, tag: tag})
- )
-);
+fn moov_header(input: &[u8]) -> IResult<&[u8], MP4BoxHeader> {
+ let (i, length) = be_u32(input)?;
+ let (i, tag) = moov_type(i)?;
+ Ok((i, MP4BoxHeader { length, tag }))
+}
diff --git a/tests/multiline.rs b/tests/multiline.rs
index fa8cbf4..7378b9e 100644
--- a/tests/multiline.rs
+++ b/tests/multiline.rs
@@ -1,5 +1,3 @@
-extern crate nom;
-
use nom::{
character::complete::{alphanumeric1 as alphanumeric, line_ending as eol},
multi::many0,
diff --git a/tests/named_args.rs b/tests/named_args.rs
deleted file mode 100644
index 9ba4b3a..0000000
--- a/tests/named_args.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-#[macro_use]
-extern crate nom;
-
-use nom::{
- branch::alt,
- bytes::complete::tag,
- character::complete::{digit1 as digit, space0 as space},
- sequence::{delimited, pair, preceded},
-};
-
-// Parser definition
-
-use std::str;
-use std::str::FromStr;
-
-use self::Operator::*;
-
-enum Operator {
- Slash,
- Star,
-}
-
-impl Operator {
- fn to_str(&self) -> &'static str {
- match *self {
- Slash => "/",
- Star => "*",
- }
- }
-}
-
-// Parse the specified `Operator`.
-named_args!(operator(op: Operator) <&[u8], &[u8]>,
- call!(tag(op.to_str()))
-);
-
-// We parse any expr surrounded by the tags `open_tag` and `close_tag`, ignoring all whitespaces around those
-named_args!(brackets<'a>(open_tag: &str, close_tag: &str) <&'a[u8], i64>,
- call!(delimited(
- space,
- delimited(tag(open_tag), preceded(space, expr), preceded(space, tag(close_tag))),
- space
- ))
-);
-
-fn byte_slice_to_str<'a>(s: &'a [u8]) -> Result<&'a str, str::Utf8Error> {
- str::from_utf8(s)
-}
-
-// We transform an integer string into a i64, ignoring surrounding whitespaces
-// We look for a digit suite, and try to convert it.
-// If either str::from_utf8 or FromStr::from_str fail,
-// we fallback to the brackets parser defined above
-named!(factor<&[u8], i64>, alt!(
- map_res!(
- map_res!(
- call!(delimited(space, digit, space)),
- byte_slice_to_str
- ),
- FromStr::from_str
- )
- | call!(brackets, "(", ")")
- )
-);
-
-// We read an initial factor and for each time we find
-// a * or / operator followed by another factor, we do
-// the math by folding everything
-named!(term <&[u8], i64>, do_parse!(
- init: factor >>
- res: fold_many0!(
- pair!(alt!(call!(operator, Star) | call!(operator, Slash)), factor),
- init,
- |acc, (op, val): (&[u8], i64)| {
- if (op[0] as char) == '*' { acc * val } else { acc / val }
- }
- ) >>
- (res)
- )
-);
-
-named!(expr <&[u8], i64>, do_parse!(
- init: term >>
- res: fold_many0!(
- call!(pair(alt((tag("+"), tag("-"))), term)),
- init,
- |acc, (op, val): (&[u8], i64)| {
- if (op[0] as char) == '+' { acc + val } else { acc - val }
- }
- ) >>
- (res)
- )
-);
-
-#[test]
-fn factor_test() {
- assert_eq!(factor(&b"3"[..]), Ok((&b""[..], 3)));
- assert_eq!(factor(&b" 12"[..]), Ok((&b""[..], 12)));
- assert_eq!(factor(&b"537 "[..]), Ok((&b""[..], 537)));
- assert_eq!(factor(&b" 24 "[..]), Ok((&b""[..], 24)));
-}
-
-#[test]
-fn term_test() {
- assert_eq!(term(&b" 12 *2 / 3"[..]), Ok((&b""[..], 8)));
- assert_eq!(term(&b" 2* 3 *2 *2 / 3"[..]), Ok((&b""[..], 8)));
- assert_eq!(term(&b" 48 / 3/2"[..]), Ok((&b""[..], 8)));
-}
-
-#[test]
-fn expr_test() {
- assert_eq!(expr(&b" 1 + 2 "[..]), Ok((&b""[..], 3)));
- assert_eq!(expr(&b" 12 + 6 - 4+ 3"[..]), Ok((&b""[..], 17)));
- assert_eq!(expr(&b" 1 + 2*3 + 4"[..]), Ok((&b""[..], 11)));
-}
-
-#[test]
-fn parens_test() {
- assert_eq!(expr(&b" ( 2 )"[..]), Ok((&b""[..], 2)));
- assert_eq!(expr(&b" 2* ( 3 + 4 ) "[..]), Ok((&b""[..], 14)));
- assert_eq!(expr(&b" 2*2 / ( 5 - 1) + 3"[..]), Ok((&b""[..], 4)));
-}
diff --git a/tests/overflow.rs b/tests/overflow.rs
index c66b9f4..ea513bb 100644
--- a/tests/overflow.rs
+++ b/tests/overflow.rs
@@ -1,39 +1,19 @@
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
#![cfg(target_pointer_width = "64")]
-#[macro_use]
-extern crate nom;
-
+use nom::bytes::streaming::take;
+#[cfg(feature = "alloc")]
+use nom::multi::{length_data, many0};
#[cfg(feature = "alloc")]
use nom::number::streaming::be_u64;
-use nom::{Err, Needed};
+use nom::sequence::tuple;
+use nom::{Err, IResult, Needed};
// Parser definition
// We request a length that would trigger an overflow if computing consumed + requested
-named!(parser01<&[u8],()>,
- do_parse!(
- hdr: take!(1) >>
- data: take!(18446744073709551615) >>
- ({
- let _ = hdr;
- let _ = data;
- ()
- })
- )
-);
-
-// We request a length that would trigger an overflow if computing consumed + requested
-named!(parser02<&[u8],(&[u8],&[u8])>,
- tuple!(take!(1),take!(18446744073709551615))
-);
-
-#[test]
-fn overflow_incomplete_do_parse() {
- assert_eq!(
- parser01(&b"3"[..]),
- Err(Err::Incomplete(Needed::new(18446744073709551615)))
- );
+fn parser02(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ tuple((take(1_usize), take(18446744073709551615_usize)))(i)
}
#[test]
@@ -47,7 +27,9 @@ fn overflow_incomplete_tuple() {
#[test]
#[cfg(feature = "alloc")]
fn overflow_incomplete_length_bytes() {
- named!(multi<&[u8], Vec<&[u8]> >, many0!( length_data!(be_u64) ) );
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many0(length_data(be_u64))(i)
+ }
// Trigger an overflow in length_data
assert_eq!(
@@ -59,7 +41,9 @@ fn overflow_incomplete_length_bytes() {
#[test]
#[cfg(feature = "alloc")]
fn overflow_incomplete_many0() {
- named!(multi<&[u8], Vec<&[u8]> >, many0!( length_data!(be_u64) ) );
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many0(length_data(be_u64))(i)
+ }
// Trigger an overflow in many0
assert_eq!(
@@ -71,7 +55,11 @@ fn overflow_incomplete_many0() {
#[test]
#[cfg(feature = "alloc")]
fn overflow_incomplete_many1() {
- named!(multi<&[u8], Vec<&[u8]> >, many1!( length_data!(be_u64) ) );
+ use nom::multi::many1;
+
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many1(length_data(be_u64))(i)
+ }
// Trigger an overflow in many1
assert_eq!(
@@ -83,7 +71,11 @@ fn overflow_incomplete_many1() {
#[test]
#[cfg(feature = "alloc")]
fn overflow_incomplete_many_till() {
- named!(multi<&[u8], (Vec<&[u8]>, &[u8]) >, many_till!( length_data!(be_u64), tag!("abc") ) );
+ use nom::{bytes::complete::tag, multi::many_till};
+
+ fn multi(i: &[u8]) -> IResult<&[u8], (Vec<&[u8]>, &[u8])> {
+ many_till(length_data(be_u64), tag("abc"))(i)
+ }
// Trigger an overflow in many_till
assert_eq!(
@@ -95,7 +87,11 @@ fn overflow_incomplete_many_till() {
#[test]
#[cfg(feature = "alloc")]
fn overflow_incomplete_many_m_n() {
- named!(multi<&[u8], Vec<&[u8]> >, many_m_n!(2, 4, length_data!(be_u64) ) );
+ use nom::multi::many_m_n;
+
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many_m_n(2, 4, length_data(be_u64))(i)
+ }
// Trigger an overflow in many_m_n
assert_eq!(
@@ -107,7 +103,11 @@ fn overflow_incomplete_many_m_n() {
#[test]
#[cfg(feature = "alloc")]
fn overflow_incomplete_count() {
- named!(counter<&[u8], Vec<&[u8]> >, count!( length_data!(be_u64), 2 ) );
+ use nom::multi::count;
+
+ fn counter(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ count(length_data(be_u64), 2)(i)
+ }
assert_eq!(
counter(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef"[..]),
@@ -118,8 +118,12 @@ fn overflow_incomplete_count() {
#[test]
#[cfg(feature = "alloc")]
fn overflow_incomplete_length_count() {
+ use nom::multi::length_count;
use nom::number::streaming::be_u8;
- named!(multi<&[u8], Vec<&[u8]> >, length_count!( be_u8, length_data!(be_u64) ) );
+
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ length_count(be_u8, length_data(be_u64))(i)
+ }
assert_eq!(
multi(&b"\x04\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xee"[..]),
@@ -130,7 +134,9 @@ fn overflow_incomplete_length_count() {
#[test]
#[cfg(feature = "alloc")]
fn overflow_incomplete_length_data() {
- named!(multi<&[u8], Vec<&[u8]> >, many0!( length_data!(be_u64) ) );
+ fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
+ many0(length_data(be_u64))(i)
+ }
assert_eq!(
multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xff"[..]),
diff --git a/tests/reborrow_fold.rs b/tests/reborrow_fold.rs
index b53555b..486617e 100644
--- a/tests/reborrow_fold.rs
+++ b/tests/reborrow_fold.rs
@@ -1,18 +1,31 @@
#![allow(dead_code)]
-#![allow(unused_variables)]
-
-#[macro_use]
-extern crate nom;
+// #![allow(unused_variables)]
use std::str;
-named_args!(atom<'a>(tomb: &'a mut ())<String>,
- map!(map_res!(is_not!(" \t\r\n()"), str::from_utf8), ToString::to_string));
+use nom::bytes::complete::is_not;
+use nom::character::complete::char;
+use nom::combinator::{map, map_res};
+use nom::multi::fold_many0;
+use nom::sequence::delimited;
+use nom::IResult;
+
+fn atom<'a>(_tomb: &'a mut ()) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], String> {
+ move |input| {
+ map(
+ map_res(is_not(" \t\r\n"), str::from_utf8),
+ ToString::to_string,
+ )(input)
+ }
+}
-/*FIXME: should we support the use case of borrowing data mutably in a parser?
-named_args!(list<'a>(tomb: &'a mut ())<String>,
- delimited!(
- char!('('),
- fold_many0!(call!(atom, tomb), "".to_string(), |acc: String, next: String| acc + next.as_str()),
- char!(')')));
-*/
+// FIXME: should we support the use case of borrowing data mutably in a parser?
+fn list<'a>(i: &'a [u8], tomb: &'a mut ()) -> IResult<&'a [u8], String> {
+ delimited(
+ char('('),
+ fold_many0(atom(tomb), String::new, |acc: String, next: String| {
+ acc + next.as_str()
+ }),
+ char(')'),
+ )(i)
+}
diff --git a/tests/test1.rs b/tests/test1.rs
deleted file mode 100644
index 85c442f..0000000
--- a/tests/test1.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-#![cfg(feature = "stream")]
-
-#[macro_use]
-extern crate nom;
-
-use nom::{not_line_ending, IResult};
-
-use std::fmt::Debug;
-
-/*
-#[test]
-#[allow(unused_must_use)]
-fn tag() {
- FileProducer::new("assets/links.txt", 20).map(|producer: FileProducer| {
- let mut p = producer;
- p.refill();
-
- consumer_from_parser!(PrintConsumer<()>, flat_map!(map_res!(tag!("https!"), str::from_utf8), print));
- let mut cs = PrintConsumer::new();
- for _ in 1..4 {
- p.apply(&mut cs);
- }
- });
-}
-*/
-
-pub fn print<T: Debug>(input: T) -> IResult<T, ()> {
- println!("{:?}", input);
- Ok((input, ()))
-}
-
-#[test]
-fn is_not() {
- //is_not!(foo b"\r\n");
- named!(foo<&[u8],&[u8]>, is_not!(&b"\r\n"[..]));
- let a = &b"ab12cd\nefgh"[..];
- assert_eq!(foo(a), Ok((&b"\nefgh"[..], &b"ab12cd"[..])));
-}
-
-#[test]
-fn exported_public_method_defined_by_macro() {
- let a = &b"ab12cd\nefgh"[..];
- assert_eq!(not_line_ending(a), Ok((&b"\nefgh"[..], &b"ab12cd"[..])));
-}