diff options
author | Joel Galenson <jgalenson@google.com> | 2021-10-14 18:53:44 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-10-14 18:53:44 +0000 |
commit | 0570be5d9d4f1fdfa570f7af6b884cdcfd1ae261 (patch) | |
tree | a93ddce82b1f939de7017c5f19ef6ad61a5fee00 | |
parent | 9eac2f42d0429011e784967cc7f270fe8184af54 (diff) | |
parent | 5492d0ac8220239408785c8cabe6fa370dc75f49 (diff) | |
download | nom-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
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 @@ -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) @@ -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 @@ -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 } } @@ -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èDEF;"[..]), - Ok((&b";"[..], String::from("abèDEF"))) - ); - assert_eq!( - esc2(&b"abèDà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èDEF;"), Ok((";", String::from("abèDEF")))); - assert_eq!( - esc2("abèDà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èDEF;"[..]), + Ok((&b";"[..], String::from("abèDEF"))) + ); + assert_eq!( + esc2(&b"abèDà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èDEF;"), Ok((";", String::from("abèDEF")))); + assert_eq!( + esc2("abèDà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>, @@ -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))) + ); +} @@ -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"[..]))); -} |