nom-4.2.3/CHANGELOG.md010064400007670000024000001264011344541074200123530ustar0000000000000000# Change Log ## [Unreleased][unreleased] ### Thanks ### Added ### Fixed ## 4.2.3 - 2019-03-23 ### Fixed - add missing `build.rs` file to the package - fix code comparison links in changelog ## 4.2.2 - 2019-03-04 ### Fixed - regression in do_parse macro import for edition 2018 ## 4.2.1 - 2019-02-27 ### Fixed - macro expansion error in `do_parse` due to `compile_error` macro usage ## 4.2.0 - 2019-01-29 ### Thanks - @JoshMcguigan for unit test fixes - @oza for documentation fixes - @wackywendell for better error conversion - @Zebradil for documentation fixes - @tsraom for new combinators - @hcpl for minimum Rust version tests - @KellerFuchs for removing some unsafe uses in float parsing ### Changed - macro import in edition 2018 code should work without importing internal macros now - the regex parsers do not require the calling code to have imported the regex crate anymore - error conversions are more ergonomic - method combinators are now deprecated. They might be moved to a separate crate - nom now specifies Rust 1.24.1 as minimum version. This was already the case before, now it is made explicit ### Added - `many0_count` abd `many1_count` to count applications of a parser instead of accumulating its results in a `Vec` ### Fixed - overflow in the byte wrapper for bit level parsers - `f64` parsing does not use `transmute` anymore ## 4.1.1 - 2018-10-14 ### Fixed - compilation issue in verbose-errors mode for `add_return_error` ## 4.1.0 - 2018-10-06 ### Thanks - @xfix for fixing warnings, simplifying examples and performance fixes - @dvberkel for documentation fixes - @chifflier for fixinf warnings - @myrrlyn for dead code elimination - @petrochenkov for removing redundant test macros - @tbelaire for documentation fixes - @khernyo for fixing warnings - @linkmauve for documentation fixes - @ProgVal for documentation fixes, warning fixes and error management - @Nemo157 for compilation fixes - @RReverser for documentation fixes - @xpayn for fixing warnings - Blas Rodriguez Irizar for documentation fixes - @badboy for documentation fixes - @kyrias for compilation fixes - @kurnevsky for the `rest_len` parser - @hjr3 for new documentation examples - @fengalin for error management - @ithinuel for the pcap example project - @phaazon for documentation fixes - @juchiast for documentation fixes - @jrakow for the `u128` and `i128` parsers - @smarnach for documentation fixes - @derekdreery for `pub(crate)` support - @YaLTeR for `map_res_err!` ### Added - `rest_len` parser, returns the length of the remaining input - `parse_to` has its own error code now - `u128` and `i128` parsers in big and little endian modes - support for `pub(crate)` syntax - `map_res_err!` combinator that appends the error of its argument function in verbose errors mode ### Fixed - lots of unused imports warnings were removed - the `bytes` combinator was not compiling in some cases - the big and little endian combinators now work without external imports - CI is now faster and uses less cache - in `add_return_error`, the provided error code is now evaluated only once ### Changed - `fold_many1` will now transmit a `Failure` instead of transforming it to an `Error` - `float` and `double` now work on all of nom's input types (`&[u8]`, `&str`, `CompleteByteSlice`, `CompleteStr` and any type that implements the required traits). `float_s` and `double_s` got the same modification, but are now deprecated - `CompleteByteSlice` and `CompleteStr` get a small optimization by inlining some functions ## 4.0.0 - 2018-05-14 ### Thanks - @jsgf for the new `AtEof` trait - @tmccombs for fixes on `escaped*` combinators - @s3bk for fixes around non Copy input types and documentation help - @kamarkiewicz for fixes to no_std and CI - @bheisler for documentation and examples - @target-san for simplifying the `InputIter` trait for `&[u8]` - @willmurphyscode for documentation and examples - @Chaitanya1416 for typo fixes - @fflorent for `input_len()` usage fixes - @dbrgn for typo fixes - @iBelieve for no_std fixes - @kpp for warning fixes and clippy fixes - @keruspe for fixes on FindToken - @dtrebbien for fixes on take_until_and_consume1 - @Henning-K for typo fixes - @vthriller for documentation fixes - @federicomenaquintero and @veprbl for their help fixing the float parsers - @vmchale for new named_args versions - @hywan for documentation fixes - @fbenkstein for typo fixes - @CAD97 for catching missing trait implementations - @goldenlentils for &str optimizations - @passy for typo fixes - @ayrat555 for typo fixes - @GuillaumeGomez for documentation fixes - @jrakow for documentation fixes and fiwes for `switch!` - @phlosioneer for dicumentation fixes - @creativcoder for typo fixes - @derekdreery for typo fixes - @lucasem for implementing `Deref` on `CompleteStr` and `CompleteByteSlice` - @lowenheim for `parse_to!` fixes - @myrrlyn for trait fixes around `CompleteStr` and `CompleteByteSlice` - @NotBad4U for fixing code coverage analysis - @murarth for code formatting - @glandium for fixing build in no_std - @csharad for regex compatibility with `CompleteStr` - @FauxFaux for implementing `AsRef` on `CompleteStr` - @jaje for implementing `std::Error` on `nom:Err` - @fengalin for warning fixes - @@khernyo for doc formatting Special thanks to @corkami for the logo :) ### Breaking changes - the `IResult` type now becomes a `Result` from the standard library - `Incomplete` now returns the additional data size needed, not the total data size needed - verbose-errors is now a superset of basic errors - all the errors now include the related input slice - the arguments from `error_position` and other such macros were swapped to be more consistent with the rest of nom - automatic error conversion: to fix error type inference issues, a custom error type must now implement `std::convert::From` - the `not!` combinator returns unit `()` - FindToken's calling convention was swapped - the `take_*` combinators are now more coherent and stricter, see commit 484f6724ea3ccb for more information - `many0` and other related parsers will now return `Incomplete` if the reach the end of input without an error of the child parser. They will also return `Incomplete` on an empty input - the `sep!` combinator for whitespace only consumes whitespace in the prefix, while the `ws!` combinator takes care of consuming the remaining whitespace ### Added - the `AtEof` trait for input type: indicate if we can get more input data later (related to streaming parsers and `Incomplete` handling) - the `escaped*` parsers now support the `&str`input type - the `Failure` error variant represents an unrecoverable error, for which `alt` and other combinators will not try other branches. This error means we got in the right part of the code (like, a prefix was checked correctly), but there was an error in the following parts - the `CompleteByteSlice` and `CompleteStr` input types consider there will be no more refill of the input. They fixed the `Incomplete` related issues when we have all of the data - the `exact!()` combinator will fail if we did not consume the whole input - the `take_while_m_n!` combinator will match a specified number of characters - `ErrorKind::TakeUntilAndConsume1` - the `recognize_float` parser will match a float number's characters, but will not transform to a `f32` or `f64` - `alpha` and other basic parsers are now much stricter about partial inputs. We also introduce the `*0` and `*1` versions of those parsers - `named_args` can now specify the input type as well - `HexDisplay` is now implemented for `&str` - `alloc` feature - the `InputTakeAtposition` trait allows specialized implementations of parsers like `take_while!` ### Removed - the producers and consumers were removed - the `error_code` and `error_node` macros are not used anymore ### Fixed - `anychar!` now works correctly with multibyte characters - `take_until_and_consume1!` no longer results in "no method named \`find_substring\`" and "no method named \`slice\`" compilation errors - `take_until_and_consume1!` returns the correct Incomplete(Needed) amount - `no_std` compiles properly, and nom can work with `alloc` too - `parse_to!` now consumes its input ### Changed - `alt` and other combinators will now clone the input if necessary. If the input is already `Copy` there is no performance impact - the `rest` parser now works on various input types - `InputIter::Item` for `&[u8]` is now a `u8` directly, not a reference - we now use the `compile_error` macro to return a compile time error if there was a syntax issue - the permutation combinator now supports optional child parsers - the float numbers parsers have been refactored to use one common implementation that is nearly 2 times faster than the previous one - the float number parsers now accept more variants ## 3.2.1 - 2017-10-27 ### Thanks - @ordian for `alt_complete` fixes - @friedm for documentation fixes - @kali for improving error management ### Fixed - there were cases where `alt_complete` could return `Incomplete` ### Added - an `into_error_kind` method can be used to transform any error to a common value. This helps when the library is included multiple times as dependency with different feature sets ## 3.2.0 - 2017-07-24 ### Thanks - @jedireza for documentation fixes - @gmorenz for the `bytes` combinator - @meh for character combinator fixes for UTF-8 - @jethrogb for avoiding move issues in `separated_list` ### Changed - new layout for the main page of documentation - `anychar` can now work on any input type - `length_bytes` is now an alias for `length_data` ### Fixed - `one_of`, `none_of` and `char` will now index correctly UTF-8 characters - the `compiler_error` macro is now correctly exported ### Added - the `bytes` combinator transforms a bit stream back to a byte slice for child parsers ## 3.1.0 - 2017-06-16 ### Thanks - @sdroege: implementing be_i24 and le_i24 - @Hywan: integrating faster substring search using memchr - @nizox: fixing type issues in bit stream parsing - @grissiom: documentation fixes - @doomrobo: implementing separated_list_complete and separated_nonempty_list_complete - @CWood1: fixing memchr integration in no_std - @lu_zero: integrating the compiler_error crate - @dtolnay: helping debug a type inference issue in map ### Changed - memchr is used for substring search if possible - if building on nightly, some common syntax errors will display a specific error message. If building no stable, display the documentation to activate those messages - `count` no longer preallocates its vector ### Fixed - better type inference in alt_complete - `alt` should now work with whitespace parsing - `map` should not make type inference errors anymore ### Added - be_i24 and le_i24, parsing big endian and little endian signed 24 bit integers - `separated_list_complete` and `separated_nonempty_list_complete` will treat incomplete from sub parsers as error ## 3.0.0 - 2017-05-12 ### Thanks - Chris Pick for some `Incomplete` related refactors - @dbrgn for documentation fixes - @valarauca for adding `be_u24` - @ithinuel for usability fixes - @evuez for README readability fixes and improvements to `IResult` - @s3bk for allowing non-`Copy` types as input - @keruspe for documentation fixes - @0xd34d10cc for trait fixes on `InputIter` - @sdleffler for lifetime shenanigans on `named_args` - @chengsun for type inference fixes in `alt` - @iBelieve for adding str to no_std - @Hywan for simplifying code in input traits - @azerupi for extensive documentation of `alt` and `alt_complete` ### Breaking Changes - `escaped`, `separated_list` and `separated_nonempty_list` can now return `Incomplete` when necessary - `InputIter` does not require `AsChar` on its `Item` type anymore - the `core` feature that was putting nom in `no_std` mode has been removed. There is now a `std` feature, activated by default. If it is not activated, nom is in `no_std` - in `verbose-errors` mode, the error list is now stored in a `Vec` instead of a box based linked list - `chain!` has finally been removed ### Changed - `Endianness` now implements `Debug`, `PartialEq`, `Eq`, `Clone` and `Copy` - custom input types can now be cloned if they're not `Copy` - the infamous 'Cannot infer type for E' error should happen less often now - `str` is now available in `no_std` mode ### Fixed - `FileProducer` will be marked as `Eof` on full buffer - `named_args!` now has lifetimes that cannot conflict with the lifetimes from other arguments ### Added - `be_u24`: big endian 24 bit unsigned integer parsing - `IResult` now has a `unwrap_or` method ## 2.2.1 - 2017-04-03 ### Thanks - @Victor-Savu for formatting fixes in the README - @chifflier for detecting and fixing integer overflows - @utkarshkukreti for some performance improvements in benchmarks ### Changed - when calculating how much data is needed in `IResult::Incomplete`, the addition could overflow (it is stored as a usize). This would apparently not result in any security vulnerability on release code ## 2.2.0 - 2017-03-20 ### Thanks - @seppo0010 for fixing `named_args` - @keruspe for implementing or() on `IResult`, adding the option of default cases in `switch!`, adding support for `cargo-travis` - @timlyo for documentation fixes - @JayKickliter for extending `hex_u32` - @1011X for fixing regex integration - @Kerollmops for actually marking `chain!` as deprecated - @joliss for documentation fixes - @utkarshkukreti for tests refactoring and performance improvement - @tmccombs for documentation fixes ### Added - `IResult` gets an `or()` method - `take_until1`, `take_until_and_consume1`, `take_till1!` and `take_till1_s!` require at least 1 character ### Changed - `hex_u32` accepts uppercase digits as well - the character based combinators leverage the input traits - the whitespace parsers now work on &str and other types - `take_while1` returns `Incomplete` on empty input - `switch!` can now take a default case ### Fixed - `named_args!` now imports `IResult` directly - the upgrade to regex 0.2 broke the regex combinators, they work now ## 2.1.0 - 2017-01-27 ### Thanks - @nickbabcock for documentation fixes - @derekdreery for documentation fixes - @DirkyJerky for documentation fixes - @saschagrunert for documentation fixes - @lucab for documentation fixes - @hyone for documentation fixes - @tstorch for factoring `Slice` - @shepmaster for adding crate categories - @antoyo for adding `named_args!` ### Added - `verify!` uses a first parser, then applies a function to check that its result satisfies some conditions - `named_args!` creates a parser function that can accept other arguments along with the input - `parse_to!` will use the `parse` method from `FromStr` to parse a value. It will automatically translate the input to a string if necessary - `float`, `float_s`, `double`, `double_s` can recognize floating point numbers in text ### Changed - `escaped!` will now return `Incomplete` if needed - `permutation!` supports up to 20 child parsers ## 2.0.1 - 2016-12-10 Bugfix release *Warning*: there is a small breaking change, `add_error!` is renamed to `add_return_error!`. This was planned for the 2.0 release but was forgotten. This is a small change in a feature that not many people use, for a release that is not yet widely in use, so there will be no 3.0 release for that change. ### Thanks - @nickbabcock for catching and fixing the `add_error!` mixup - @lucab for documentation fixes - @jtdowney for noticing that `tag_no_case!` was not working at all for byte slices ### Fixed - `add_error!` has been renamed to `add_return_error!` - the `not!` combinator now accepts functions - `tag_no_case!` is now working as accepted (before, it accepted everything) ## 2.0 - 2016-11-25 The 2.0 release is one of the biggest yet. It was a good opportunity to clean up some badly named combinators and fix invalid behaviours. Since this version introduces a few breaking changes, an [upgrade documentation](https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_2.md) is available, detailing the steps to fix the most common migration issues. After testing on a set of 30 crates, most of them will build directly, a large part will just need to activate the "verbose-errors" compilation feature. The remaining fixes are documented. This version also adds a lot of interesting features, like the permutation combinator or whitespace separated formats support. ### Thanks - @lu-zero for license help - @adamgreig for type inference fixes - @keruspe for documentation and example fixes, for the `IResult => Result` conversion work, making `AsChar`'s method more consistent, and adding `many_till!` - @jdeeny for implementing `Offset` on `&str` - @vickenty for documentation fixes and his refactoring of `length_value!` and `length_bytes!` - @overdrivenpotato for refactoring some combinators - @taralx for documentation fixes - @keeperofdakeys for fixing eol behaviour, writing documentation and adding `named_attr!` - @jturner314 for writing documentation - @bozaro for fixing compilation errors - @uniphil for adding a `crates.io` badge - @badboy for documentation fixes - @jugglerchris for fixing `take_s!` - @AndyShiue for implementing `Error` and `Display` on `ErrorKind` and detecting incorrect UTF-8 string indexing ### Added - the "simple" error management system does not accumulates errors when backtracking. This is a big perf gain, and is activated by default in nom 2.0 - nom can now work on any type that implement the traits defined in `src/traits.rs`: `InputLength`, `InputIter`, `InputTake`, `Compare`, `FindToken`, `FindSubstring`, `Slice` - the documentation from Github's wiki has been moved to the `doc/` directory. They are markdown files that you can build with [cargo-external-doc](https://crates.io/crates/cargo-external-doc) - whitespace separated format support: with the `ws!` combinator, you can automatically introduce whitespace parsers between all parsers and combinators - the `permutation!` combinator applies its child parsers in any order, as long as they all succeed once, and return a tuple of the results - `do_parse!` is a simpler alternative to `chain!`, which is now deprecated - you can now transform an `IResult` in a `std::result::Result` - `length_data!` parses a length, and returns a subslice of that length - `tag_no_case!` provides case independent comparison. It works nicely, without any allocation, for ASCII strings, but for UTF-8 strings, it defaults to an unsatisfying (and incorrect) comparison by lowercasing both strings - `named_attr!` creates functions like `named!` but can add attributes like documentation - `many_till!` applies repeatedly its first child parser until the second succeeds ### Changed - the "verbose" error management that was available in previous versions is now activated by the "verbose-errors" compilation feature - code reorganization: most of the parsers were moved in separate files to make the source easier to navigate - most of the combinators are now independent from the input type - the `eof` function was replaced with the `eof!` macro - `error!` and `add_error!` were replaced with `return_error!` and `add_return_error!` to fix the name conflict with the log crate - the `offset()` method is now in the `Offset` trait - `length_value!` has been renamed to `length_count!`. The new `length_value!` selects a slice and applies the second parser once on that slice - `AsChar::is_0_to_9` is now `AsChar::is_dec_digit` - the combinators with configurable endianness now take an enum instead of a boolean as parameter ### Fixed - the `count!`, `count_fixed!` and `length_*!` combinator calculate incomplete data needs correctly - `eol`, `line_ending` and `not_line_ending` now have a consistent behaviour that works correctly with incomplete data - `take_s!` didn't correctly handle the case when the slice is exactly the right length ## 1.2.4 - 2016-07-20 ### Thanks - @Phlosioneer for documentation fixes - @sourrust for fixing offsets in `take_bits!` - @ChrisMacNaughton for the XFS crate - @pwoolcoc for `rest_s` - @fitzgen for more `IResult` methods - @gtors for the negative lookahead feature - @frk1 and @jeandudey for little endian float parsing - @jethrogb for fixing input usage in `many1` - @acatton for beating me at nom golf :D ### Added - the `rest_s` method on `IResult` returns the remaining `&str` input - `unwrap_err` and `unwrap_inc` methods on `IResult` - `not!` will peek at the input and return `Done` if the underlying parser returned `Error` or `Incomplete`, without consuming the input - `le_f32` and `le_f64` parse little endian floating point numbers (IEEE 754) - ### Fixed - documentation fixes - `take_bits!` is now more precise - `many1` inccorectly used the `len` function instead of `input_len` - the INI parser is simpler - `recognize!` had an early `return` that is removed now ## 1.2.3 - 2016-05-10 ### Thanks - @lu-zero for the contribution guidelines - @GuillaumeGomez for fixes on `length_bytes` and some documentation - @Hywan for documentation and test fixes - @Xirdus for correct trait import issues - @mspiegel for the new AST example - @cholcombe973 for adding the `cond_with_error!` combinator - @tstorch for refactoring `many0!` - @panicbit for the folding combinators - @evestera for `separated_list!` fixes - @DanielKeep for correcting some enum imports ### Added - Regular expression combinators starting with `re_bytes_` work on byte slices - example parsing arithmetic expressions to an AST - `cond_with_error!` works like `cond!` but will return `None` if the condition is false, and `Some(value)` if the underlying parser succeeded - `fold_many0!`, `fold_many1!` and `fold_many_m_n!` will take a parser, an initial value and a combining function, and fold over the successful applications of the parser ### Fixed - `length_bytes!` converts the result of its child parser to usize - `take_till!` now imports `InputLength` instead of assuming it's in scope - `separated_list!` and `separated_nonempty_list!` will not consume the separator if there's no following successfully parsed value - no more warnings on build ### Changed - simpler implementation of `many0!` ## 1.2.2 - 2016-03-09 ### Thanks - @conradev for fixing `take_until_s!` - @GuillaumeGomez for some documentation fixes - @frewsxcv for some documentation fixes - @tstorch for some test refactorings ### Added - `nom::Err` now implements `std::error::Error` ### Fixed - `hex_u32` does not parses more than 8 chars now - `take_while!` and `take_while1!` will not perturb the behaviour of `recognize!` anymore ## 1.2.1 - 2016-02-23 ### Thanks - @sourrust for adding methods to `IResult` - @tstorch for the test refactoring, and for adding methods to `IResult` and `Needed` - @joelself for fixing the method system ### Added - mapping methods over `IResult` and `Needed` ### Changed - `apply_rf` is renamed to `apply_m`. This will not warrant a major version, since it is part missing from the methods feture added in the 1.2.0 release - the `regexp_macros` feature that used `regex!` to precompile regular expressions has been replaced by the normal regex engine combined with `lazy_static` ### Fixed - when a parser or combinator was returning an empty buffer as remaining part, it was generating one from a static empty string. This was messing with buffer offset calculation. Now, that empty slice is taken like this: `&input[input.len()..]`. - The `regexp_macros` and `no_std` feature build again and are now tested with Travis CI ## 1.2.0 - 2016-02-08 ### Thanks - @zentner-kyle for type inference fixes - @joelself for his work on `&str` parsing and method parsers - @GuillaumeGomez for implementing methods on `IResult` - @dirk for the `alt_complete!` combinator - @tstorch for a lot of refactoring work and unit tests additions - @jansegre for the hex digit parsers - @belgum for some documentation fixes - @lwandrebeck for some documentation fixes and code fixes in `hex_digit` ### Added - `take_until_and_consume_s!` for consumption of string data until a tag - more function patterns in `named!`. The error type can now be specified - `alt_complete!` works like the `alt!` combinator, but tries the next branch if the current one returned `Incomplete`, instead of returning directly - more unit tests for a lot of combinators - hexadecimal digit parsers - the `tuple!` combinator takes a list of parsers as argument, and applies them serially on the input. If all of them are successful, it willr eturn a tuple accumulating all the values. This combinator will (hopefully) replace most uses of `chain!` - parsers can now be implemented as a method for a struct thanks to the `method!`, `call_m!` and `apply_rf!` combinators ### Fixed - there were type inference issues in a few combinators. They will now be easier to compile - `peek!` compilation with bare functions - `&str` parsers were splitting data at the byte level, not at the char level, which can result in inconsistencies in parsing UTF-8 characters. They now use character indexes - some method implementations were missing on `IResult` (with specified error type instead of implicit) ## 1.1.0 - 2016-01-01 This release adds a lot of features related to `&str` parsing. The previous versions were focused on `&[u8]` and bit streams parsing, but there's a need for more text parsing with nom. The parsing functions like `alpha`, `digit` and others will now accept either a `&[u8]` or a `&str`, so there is no breaking change on that part. There are also a few performance improvements and documentation fixes. ### Thanks - @Binero for pushing the work on `&str` parsing - @meh for fixing `Option` and `Vec` imports - @hoodie for a documentation fix - @joelself for some documentation fixes - @vberger for his traits magic making nom functions more generic ### Added - string related parsers: `tag_s!`, `take_s!`, `is_a_s!`, `is_not_s!`, `take_while_s!`, `take_while1_s!`, `take_till_s!` - `value!` is a combinator that always returns the same value. If a child parser is passed as second argument, that value is returned when the child parser succeeds ### Changed - `tag!` will now compare even on partial input. If it expects "abcd" but receives "ef", it will now return an `Error` instead of `Incomplete` - `many0!` and others will preallocate a larger vector to avoid some copies and reallocations - `alpha`, `digit`, `alphanumeric`, `space` and `multispace` now accept as input a `&[u8]` or a `&str`. Additionally, they return an error if they receive an empty input - `take_while!`, `take_while1!`, `take_while_s!`, `take_while1_s!` wilreturn an error on empty input ### Fixed - if the child parser of `many0!` or `many1!` returns `Incomplete`, it will return `Incomplete` too, possibly updating the needed size - `Option,` `Some`, `None` and `Vec` are now used with full path imports ## 1.0.1 - 2015-11-22 This releases makes the 1.0 version compatible with Rust 1.2 and 1.3 ### Thanks - @steveklabnik for fixing lifetime issues in Producers and Consumers ## 1.0.0 - 2015-11-16 Stable release for nom. A lot of new features, a few breaking changes ### Thanks - @ahenry for macro fixes - @bluss for fixing documentation - @sourrust for cleaning code and debugging the new streaming utilities - @meh for inline optimizations - @ccmtaylor for fixing function imports - @soro for improvements to the streaming utilities - @breard-r for catching my typos - @nelsonjchen for catching my typos too - @divarvel for hex string parsers - @mrordinaire for the `length_bytes!` combinator ### Breaking changes - `IResult::Error` can now use custom error types, and is generic over the input type - Producers and consumers have been replaced. The new implementation uses less memory and integrates more with parsers - `nom::ErrorCode` is now `nom::ErrorKind` - `filter!` has been renamed to `take_while!` - `chain!` will count how much data is consumed and use that number to calculate how much data is needed if a parser returned `Incomplete` - `alt!` returns `Incomplete` if a child parser returned `Incomplete`, instead of skipping to the next parser - `IResult` does not require a lifetime tag anymore, yay! ### Added - `complete!` will return an error if the child parser returned `Incomplete` - `add_error!` will wrap an error, but allow backtracking - `hex_u32` parser ### Fixed - the behaviour around `Incomplete` is better for most parsers now ## 0.5.0 - 2015-10-16 This release fixes a few issues and stabilizes the code. ### Thanks - @nox for documentation fixes - @daboross for linting fixes - @ahenry for fixing `tap!` and extending `dbg!` and `dbg_dmp!` - @bluss for tracking down and fixing issues with unsafe code - @meh for inlining parser functions - @ccmtaylor for fixing import of `str::from_utf8` ### Fixed - `tap!`, `dbg!` and `dbg_dmp!` now accept function parameters ### Changed - the type used in `count_fixed!` must be `Copy` - `chain!` calculates how much data is needed if one of the parsers returns `Incomplete - optional parsers in `chain!` can return `Incomplete` ## 0.4.0 - 2015-09-08 Considering the number of changes since the last release, this version can contain breaking changes, so the version number becomes 0.4.0. A lot of new features and performance improvements! ### Thanks - @frewsxcv for documentation fixes - @ngrewe for his work on producers and consumers - @meh for fixes on `chain!` and for the `rest` parser - @daboross for refactoring `many0!` and `many1!` - @aleksander for the `switch!` combinator idea - @TechnoMancer for his help with bit level parsing - @sxeraverx for pointing out a bug in `is_a!` ### Fixed - `count_fixed!` must take an explicit type as argument to generate the fixed-size array - optional parsing behaviour in `chain!` - `count!` can take 0 elements - `is_a!` and `is_not!` can now consume the whole input ### Added - it is now possible to seek to the end of a `MemProducer` - `opt!` returns `Done(input, None)` if `the child parser returned `Incomplete` - `rest` will return the remaining input - consumers can now seek to and from the end of input - `switch!` applies a first parser then matches on its result to choose the next parser - bit-level parsers - character-level parsers - regular expression parsers - implementation of `take_till!`, `take_while!` and `take_while1!` ### Changed - `alt!` can return `Incomplete` - the error analysis functions will now take references to functions instead of moving them - performance improvements on producers - performance improvement for `filter!` - performance improvement for `count!`: a `Vec` of the right size is directly allocated ## 0.3.11 - 2015-08-04 ### Thanks - @bluss for remarking that the crate included random junk lying non commited in my local repository ### Fixed - cleanup of my local repository will ship less files in the crates, resulting in a smaller download ## 0.3.10 - 2015-08-03 ### Added - `bits!` for bit level parsing. It indicates that all child parsers will take a `(&[u8], usize)`as input, with the second parameter indicating the bit offset in the first byte. This allows viewing a byte slice as a bit stream. Most combinators can be used directly under `bits!` - `take_bits!` takes an integer type and a number of bits, consumes that number of bits and updates the offset, possibly by crossing byte boundaries - bit level parsers are all written in `src/bits.rs` ### Changed - Parsers that specifically handle bytes have been moved to src/bytes.rs`. This applies to `tag!`, `is_not!`, `is_a!`, `filter!`, `take!`, `take_str!`, `take_until_and_consume!`, `take_until!`, `take_until_either_and_consume!`, `take_until_either!` ## 0.3.9 - 2015-07-20 ### Thanks - @badboy for fixing `filter!` - @idmit for some documentation fixes ### Added - `opt_res!` applies a parser and transform its result in a Result. This parser never fails - `cond_reduce!` takes an expression as parameter, applies the parser if the expression is true, and returns an error if the expression is false - `tap!` pass the result of a parser to a block to manipulate it, but do not affect the parser's result - `AccReader` is a Read+BufRead that supports data accumulation and partial consumption. The `consume` method must be called afterwardsto indicate how much was consumed - Arithmetic expression evaluation and parsing example - `u16!`, `u32!`, `u64!`, `i16!`, `i32!`, `i64!` take an expression as parameter, if the expression is true, apply the big endian integer parser, if false, the little endian version - type information for combinators. This will make the documentation a bit easier to navigate ### Fixed - `map_opt!` and `map_res!` had issues with argument order due to bad macros - `delimited!` did not compile for certain combinations of arguments - `filter!` did not return a byte slice but a fixed array ## 0.3.8 - 2015-07-03 ### Added - code coverage is now calculated automatically on Travis CI - `Stepper`: wrap a `Producer`, and call the method `step` with a parser. This method will buffer data if there is not enough, apply the parser if there is, and keep the rest of the input in memory for the next call - `ReadProducer`: takes something implementing `Read`, and makes a `Producer` out of it ### Fixed - the combinators `separated_pair!` and `delimited!` did not work because an implementation macro was not exported - if a `MemProducer` reached its end, it should always return `Eof` - `map!` had issues with argument matching ## 0.3.7 - 2015-06-24 ### Added - `expr_res!` and `expr_opt!` evaluate an expression returning a Result or Opt and convert it to IResult - `AsBytes` is implemented for fixed size arrays. This allows `tag!([41u8, 42u8])` ### Fixed - `count_fixed!` argument parsing works again ## 0.3.6 - 2015-06-15 ### Added - documentation for a few functions - the consumer trait now requires the `failed(&self, error_code)` method in case of parsing error - `named!` now handles thge alternative `named!(pub fun_name, ...)` ### Fixed - `filter!` now returns the whole input if the filter function never returned false - `take!` casts its argument as usize, so it can accepts any integer type now ## 0.3.5 - 2015-06-10 ### Thanks - @cmr for some documentation fixes ### Added - `count_fixed!` returns a fixed array ### Fixed - `count!` is back to the previous behaviour, returning a `Vec` for sizes known at runtime ### Changed - functions and traits exported from `nom::util` are now directly in `nom::` ## 0.3.4 - 2015-06-09 ### Thanks - @andrew-d for fixes on `cond!` - @keruspe for features in `chain!` ### Added - `chain!` can now have mutable fields ### Fixed - `cond!` had an infinite macro recursion ### Changed - `chain!` generates less code now. No apprent compilation time improvement ## 0.3.3 - 2015-06-09 ### Thanks - @andrew-d for the little endian signed integer parsers - @keruspe for fixes on `count!` ### Added - `le_i8`, `le_i16`, `le_i32`, `le_i64`: little endian signed integer parsers ### Changed - the `alt!` parser compiles much faster, even with more than 8 branches - `count!` can now return a fixed size array instead of a growable vector ## 0.3.2 - 2015-05-31 ### Thanks - @keruspe for the `take_str` parser and the function application combinator ### Added - `take_str!`: takes the specified number of bytes and return a UTF-8 string - `apply!`: do partial application on the parameters of a function ### Changed - `Needed::Size` now contains a `usize` instead of a `u32` ## 0.3.1 - 2015-05-21 ### Thanks - @divarvel for the big endian signed integer parsers ### Added - `be_i8`, `be_i16`, `be_i32`, `be_i64`: big endian signed integer parsers - the `core` feature can be passed to cargo to build with `no_std` - colored hexdump can be generated from error chains ## 0.3.0 - 2015-05-07 ### Thanks - @filipegoncalves for some documentation and the new eof parser - @CrimsonVoid for putting fully qualified types in the macros - @lu_zero for some documentation fixes ### Added - new error types that can contain an error code, an input slice, and a list of following errors - `error!` will cut backtracking and return directly from the parser, with a specified error code - `eof` parser, successful if there is no more input - specific error codes for the parsers provided by nom ### Changed - fully qualified types in macros. A lot of imports are not needed anymore ### Removed - `FlatMap`, `FlatpMapOpt` and `Functor` traits (replaced by `map!`, `map_opt!` and `map_res!`) ## 0.2.2 - 2015-04-12 ### Thanks - @filipegoncalves and @thehydroimpulse for debugging an infinite loop in many0 and many1 - @thehydroimpulse for suggesting public named parsers - @skade for removing the dependency on the collections gate ### Added - `named!` can now declare public functions like this: `named!(pub tst, tag!("abcd"));` - `pair!(X,Y)` returns a tuple `(x, y)` - `separated_pair!(X, sep, Y)` returns a tuple `(x, y)` - `preceded!(opening, X)` returns `x` - `terminated!(X, closing)` returns `x` - `delimited(opening, X, closing)` returns `x` - `separated_list(sep, X)` returns a `Vec` - `separated_nonempty_list(sep, X)` returns a `Vec` of at list one element ### Changed - `many0!` and `many1!` forbid parsers that do not consume input - `is_a!`, `is_not!`, `alpha`, `digit`, `space`, `multispace` will now return an error if they do not consume at least one byte ## 0.2.1 - 2015-04-04 ### Thanks - @mtsr for catching the remaining debug println! - @jag426 who killed a lot of warnings - @skade for removing the dependency on the core feature gate ### Added - little endian unsigned int parsers le_u8, le_u16, le_u32, le_u64 - `count!` to apply a parser a specified number of times - `cond!` applies a parser if the condition is met - more parser development tools in `util::*` ### Fixed - in one case, `opt!` would not compile ### Removed - most of the feature gates are now removed. The only one still needed is `collections` ## 0.2.0 - 2015-03-24 *works with `rustc 1.0.0-dev (81e2396c7 2015-03-19) (built 2015-03-19)`* ### Thanks - Ryman for the AsBytes implementation - jag426 and jaredly for documentation fixes - eternaleye on #rust IRC for his help on the new macro syntax ### Changed - the AsBytes trait improves readability, no more b"...", but "..." instead - Incomplete will now hold either Needed;;Unknown, or Needed::Size(u32). Matching on Incomplete without caring for the value is done with `Incomplete(_)`, but if more granularity is mandatory, `Needed` can be matched too - `alt!` can pass the result of the parser to a closure - the `take_*` macros changed behaviour, the default case is now not to consume the separator. The macros have been renamed as follows: `take_until!` -> `take_until_and_consume!`, `take_until_and_leave!` -> `take_until!`, `take_until_either_and_leave!` -> `take_until_either!`, `take_until_either!` -> `take_until_either_and_consume!` ### Added - `peek!` macro: matches the future input but does not consume it - `length_value!` macro: the first argument is a parser returning a `n` that can cast to usize, then applies the second parser `n` times. The macro has a variant with a third argument indicating the expected input size for the second parser - benchmarks are available at https://github.com/Geal/nom_benchmarks - more documentation - **Unnamed parser syntax**: warning, this is a breaking change. With this new syntax, the macro combinators do not generate functions anymore, they create blocks. That way, they can be nested, for better readability. The `named!` macro is provided to create functions from parsers. Please be aware that nesting parsers comes with a small cost of compilation time, negligible in most cases, but can quickly get to the minutes scale if not careful. If this happens, separate your parsers in multiple subfunctions. - `named!`, `closure!` and `call!` macros used to support the unnamed syntax - `map!`, `map_opt!` and `map_res!` to combine a parser with a normal function, transforming the input directly, or returning an `Option` or `Result` ### Fixed - `is_a!` is now working properly ### Removed - the `o!` macro does less than `chain!`, so it has been removed - the `fold0!` and `fold1!` macros were too complex and awkward to use, the `many*` combinators will be useful for most uses for now ## 0.1.6 - 2015-02-24 ### Changed - consumers must have an end method that will be called after parsing ### Added - big endian unsigned int and float parsers: be_u8, be_u16, be_u32, be_u64, be_f32, be_f64 - producers can seek - function and macros documentation - README documentation ### Fixed - lifetime declarations - tag! can return Incomplete ## 0.1.5 - 2015-02-17 ### Changed - traits were renamed: FlatMapper -> FlatMap, Mapper -> FlatMapOpt, Mapper2 -> Functor ### Fixed - woeks with rustc f1bb6c2f4 ## 0.1.4 - 2015-02-17 ### Changed - the chaining macro can take optional arguments with '?' ## 0.1.3 - 2015-02-16 ### Changed - the chaining macro now takes the closure at the end of the argument list ## 0.1.2 - 2015-02-16 ### Added - flat_map implementation for <&[u8], &[u8]> - chaining macro - partial MP4 parser example ## 0.1.1 - 2015-02-06 ### Fixed - closure syntax change ## Compare code * [unreleased](https://github.com/Geal/nom/compare/4.2.3...HEAD) * [4.2.3](https://github.com/Geal/nom/compare/4.2.2...4.2.3) * [4.2.2](https://github.com/Geal/nom/compare/4.2.1...4.2.2) * [4.2.1](https://github.com/Geal/nom/compare/4.2.0...4.2.1) * [4.2.0](https://github.com/Geal/nom/compare/4.1.1...4.2.0) * [4.1.1](https://github.com/Geal/nom/compare/4.1.0...4.1.1) * [4.1.0](https://github.com/Geal/nom/compare/4.0.0...4.1.0) * [4.0.0](https://github.com/Geal/nom/compare/3.2.1...4.0.0) * [3.2.1](https://github.com/Geal/nom/compare/3.2.0...3.2.1) * [3.2.0](https://github.com/Geal/nom/compare/3.1.0...3.2.0) * [3.1.0](https://github.com/Geal/nom/compare/3.0.0...3.1.0) * [3.0.0](https://github.com/Geal/nom/compare/2.2.1...3.0.0) * [2.2.1](https://github.com/Geal/nom/compare/2.2.0...2.2.1) * [2.2.0](https://github.com/Geal/nom/compare/2.1.0...2.2.0) * [2.1.0](https://github.com/Geal/nom/compare/2.0.1...2.1.0) * [2.0.1](https://github.com/Geal/nom/compare/2.0.0...2.0.1) * [2.0.0](https://github.com/Geal/nom/compare/1.2.4...2.0.0) * [1.2.4](https://github.com/Geal/nom/compare/1.2.3...1.2.4) * [1.2.3](https://github.com/Geal/nom/compare/1.2.2...1.2.3) * [1.2.2](https://github.com/Geal/nom/compare/1.2.1...1.2.2) * [1.2.1](https://github.com/Geal/nom/compare/1.2.0...1.2.1) * [1.2.0](https://github.com/Geal/nom/compare/1.1.0...1.2.0) * [1.1.0](https://github.com/Geal/nom/compare/1.0.1...1.1.0) * [1.0.1](https://github.com/Geal/nom/compare/1.0.0...1.0.1) * [1.0.0](https://github.com/Geal/nom/compare/0.5.0...1.0.0) * [0.5.0](https://github.com/geal/nom/compare/0.4.0...0.5.0) * [0.4.0](https://github.com/geal/nom/compare/0.3.11...0.4.0) * [0.3.11](https://github.com/geal/nom/compare/0.3.10...0.3.11) * [0.3.10](https://github.com/geal/nom/compare/0.3.9...0.3.10) * [0.3.9](https://github.com/geal/nom/compare/0.3.8...0.3.9) * [0.3.8](https://github.com/Geal/nom/compare/0.3.7...0.3.8) * [0.3.7](https://github.com/Geal/nom/compare/0.3.6...0.3.7) * [0.3.6](https://github.com/Geal/nom/compare/0.3.5...0.3.6) * [0.3.5](https://github.com/Geal/nom/compare/0.3.4...0.3.5) * [0.3.4](https://github.com/Geal/nom/compare/0.3.3...0.3.4) * [0.3.3](https://github.com/Geal/nom/compare/0.3.2...0.3.3) * [0.3.2](https://github.com/Geal/nom/compare/0.3.1...0.3.2) * [0.3.1](https://github.com/Geal/nom/compare/0.3.0...0.3.1) * [0.3.0](https://github.com/Geal/nom/compare/0.2.2...0.3.0) * [0.2.2](https://github.com/Geal/nom/compare/0.2.1...0.2.2) * [0.2.1](https://github.com/Geal/nom/compare/0.2.0...0.2.1) * [0.2.0](https://github.com/Geal/nom/compare/0.1.6...0.2.0) * [0.1.6](https://github.com/Geal/nom/compare/0.1.5...0.1.6) * [0.1.5](https://github.com/Geal/nom/compare/0.1.4...0.1.5) * [0.1.4](https://github.com/Geal/nom/compare/0.1.3...0.1.4) * [0.1.3](https://github.com/Geal/nom/compare/0.1.2...0.1.3) * [0.1.2](https://github.com/Geal/nom/compare/0.1.1...0.1.2) * [0.1.1](https://github.com/Geal/nom/compare/0.1.0...0.1.1) nom-4.2.3/Cargo.toml.orig010064400007670000024000000045321344541027000134250ustar0000000000000000[package] name = "nom" version = "4.2.3" authors = [ "contact@geoffroycouprie.com" ] description = "A byte-oriented, zero-copy, parser combinators library" license = "MIT" repository = "https://github.com/Geal/nom" readme = "README.md" documentation = "https://docs.rs/nom" keywords = ["parser", "parser-combinators", "parsing", "streaming", "bit"] categories = ["parsing"] include = [ "CHANGELOG.md", "LICENSE", ".gitignore", ".travis.yml", "Cargo.toml", "src/*.rs", "tests/*.rs", "build.rs" ] [features] alloc = [] std = ["alloc", "memchr/use_std"] default = ["std"] regexp = ["regex"] regexp_macros = ["regexp", "lazy_static"] verbose-errors = ["alloc"] [dependencies.regex] version = "^1.0" optional = true [dependencies.lazy_static] version = "^1.0" optional = true [dependencies.memchr] version = "^2.0" default-features = false #[dev-dependencies.bytes] #git = "https://github.com/carllerche/bytes" #rev = "a7d38e29" [dev-dependencies] criterion = "0.2" jemallocator = "^0.1" [build-dependencies] version_check = "^0.1" [package.metadata.docs.rs] features = [ "alloc", "std", "regexp", "regexp_macros", "verbose-errors" ] all-features = true [profile.bench] debug = true lto = true codegen-units = 1 [[test]] name = "arithmetic" [[test]] name = "arithmetic_ast" required-features = ["alloc"] [[test]] name = "blockbuf-arithmetic" [[test]] name = "complete_arithmetic" [[test]] name = "complete_float" [[test]] name = "css" [[test]] name = "custom_errors" [[test]] name = "float" [[test]] name = "inference" [[test]] name = "ini" required-features = ["alloc"] [[test]] name = "ini_str" required-features = ["alloc"] [[test]] name = "issues" required-features = ["alloc", "regexp_macros"] [[test]] name = "json" [[test]] name = "mp4" [[test]] name = "multiline" required-features = ["alloc"] [[test]] name = "named_args" [[test]] name = "overflow" [[test]] name = "reborrow_fold" [[test]] name = "test1" [[bench]] name = "arithmetic" harness = false [[bench]] name = "http" harness = false [[bench]] name = "ini" harness = false [[bench]] name = "ini_complete" harness = false [[bench]] name = "ini_str" harness = false [[bench]] name = "json" harness = false [badges] travis-ci = { repository = "Geal/nom" } coveralls = { repository = "Geal/nom", branch = "master", service = "github" } maintenance = { status = "actively-developed" } nom-4.2.3/Cargo.toml0000644000000054320000000000000076740ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # 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 # # 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) [package] name = "nom" version = "4.2.3" authors = ["contact@geoffroycouprie.com"] include = ["CHANGELOG.md", "LICENSE", ".gitignore", ".travis.yml", "Cargo.toml", "src/*.rs", "tests/*.rs", "build.rs"] description = "A byte-oriented, zero-copy, parser combinators library" documentation = "https://docs.rs/nom" readme = "README.md" keywords = ["parser", "parser-combinators", "parsing", "streaming", "bit"] categories = ["parsing"] license = "MIT" repository = "https://github.com/Geal/nom" [package.metadata.docs.rs] all-features = true features = ["alloc", "std", "regexp", "regexp_macros", "verbose-errors"] [profile.bench] lto = true codegen-units = 1 debug = true [[test]] name = "arithmetic" [[test]] name = "arithmetic_ast" required-features = ["alloc"] [[test]] name = "blockbuf-arithmetic" [[test]] name = "complete_arithmetic" [[test]] name = "complete_float" [[test]] name = "css" [[test]] name = "custom_errors" [[test]] name = "float" [[test]] name = "inference" [[test]] name = "ini" required-features = ["alloc"] [[test]] name = "ini_str" required-features = ["alloc"] [[test]] name = "issues" required-features = ["alloc", "regexp_macros"] [[test]] name = "json" [[test]] name = "mp4" [[test]] name = "multiline" required-features = ["alloc"] [[test]] name = "named_args" [[test]] name = "overflow" [[test]] name = "reborrow_fold" [[test]] name = "test1" [[bench]] name = "arithmetic" harness = false [[bench]] name = "http" harness = false [[bench]] name = "ini" harness = false [[bench]] name = "ini_complete" harness = false [[bench]] name = "ini_str" harness = false [[bench]] name = "json" harness = false [dependencies.lazy_static] version = "^1.0" optional = true [dependencies.memchr] version = "^2.0" default-features = false [dependencies.regex] version = "^1.0" optional = true [dev-dependencies.criterion] version = "0.2" [dev-dependencies.jemallocator] version = "^0.1" [build-dependencies.version_check] version = "^0.1" [features] alloc = [] default = ["std"] regexp = ["regex"] regexp_macros = ["regexp", "lazy_static"] std = ["alloc", "memchr/use_std"] verbose-errors = ["alloc"] [badges.coveralls] branch = "master" repository = "Geal/nom" service = "github" [badges.maintenance] status = "actively-developed" [badges.travis-ci] repository = "Geal/nom" nom-4.2.3/LICENSE010064400007670000024000000020511341173145500115410ustar0000000000000000Copyright (c) 2014-2018 Geoffroy Couprie Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. nom-4.2.3/build.rs010064400007670000024000000004371341212163100121750ustar0000000000000000extern crate version_check; fn main() { match version_check::is_min_version("1.26.0") { Some((true, _actual_version)) => { println!("cargo:rustc-cfg=stable_i128"); } Some(_) => (), None => { eprintln!("couldn't query version info from rustc"); } } } nom-4.2.3/src/bits.rs010064400007670000024000000377641344541022400126500ustar0000000000000000//! 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; /// # fn main() { /// named!( take_4_bits, bits!( take_bits!( u8, 4 ) ) ); /// /// let input = vec![0xAB, 0xCD, 0xEF, 0x12]; /// let sl = &input[..]; /// /// assert_eq!(take_4_bits( sl ), Ok( (&sl[1..], 0xA) )); /// # } #[macro_export(local_inner_macros)] macro_rules! bits ( ($i:expr, $submac:ident!( $($args:tt)* )) => ( bits_impl!($i, $submac!($($args)*)); ); ($i:expr, $f:expr) => ( bits_impl!($i, call!($f)); ); ); #[cfg(feature = "verbose-errors")] /// Internal parser, do not use directly #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! bits_impl ( ($i:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Context,Err,Needed}; use $crate::Slice; let input = ($i, 0usize); match $submac!(input, $($args)*) { Err(Err::Error(e)) => { let err = match e { Context::Code((i,b), kind) => Context::Code(i.slice(b/8..), kind), Context::List(mut v) => { Context::List(v.drain(..).map(|((i,b), kind)| (i.slice(b/8..), kind)).collect()) } }; Err(Err::Error(err)) }, Err(Err::Failure(e)) => { let err = match e { Context::Code((i,b), kind) => Context::Code(i.slice(b/8..), kind), Context::List(mut v) => { Context::List(v.drain(..).map(|((i,b), kind)| (i.slice(b/8..), kind)).collect()) } }; Err(Err::Failure(err)) }, Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)), Err(Err::Incomplete(Needed::Size(i))) => { //println!("bits parser returned Needed::Size({})", i); Err(Err::Incomplete(Needed::Size(i / 8 + 1))) }, Ok(((i, bit_index), o)) => { let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ; //println!("bit index=={} => byte index=={}", bit_index, byte_index); Ok((i.slice(byte_index..), o)) } } } ); ); #[cfg(not(feature = "verbose-errors"))] /// Internal parser, do not use directly #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! bits_impl ( ($i:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,Context}; use $crate::Slice; let input = ($i, 0usize); match $submac!(input, $($args)*) { Err(Err::Error(e)) => { let Context::Code(_,err) = e; Err(Err::Error(error_position!($i, err))) }, Err(Err::Failure(e)) => { let Context::Code(_,err) = e; Err(Err::Failure(error_position!($i, err))) }, Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)), Err(Err::Incomplete(Needed::Size(i))) => { //println!("bits parser returned Needed::Size({})", i); $crate::need_more($i, $crate::Needed::Size(i / 8 + 1)) }, Ok(((i, bit_index), o)) => { let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ; //println!("bit index=={} => byte index=={}", bit_index, byte_index); Ok((i.slice(byte_index..), o)) } } } ); ); /// 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::rest; /// # fn main() { /// named!( parse<(u8, u8, &[u8])>, bits!( tuple!( /// take_bits!(u8, 4), /// take_bits!(u8, 8), /// bytes!(rest) /// ))); /// /// 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)* )) => ( bytes_impl!($i, $submac!($($args)*)); ); ($i:expr, $f:expr) => ( bytes_impl!($i, call!($f)); ); ); #[cfg(feature = "verbose-errors")] /// Internal parser, do not use directly #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! bytes_impl ( ($macro_i:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,Context,Slice,ErrorKind}; let inp; if $macro_i.1 % 8 != 0 { inp = $macro_i.0.slice(1 + $macro_i.1 / 8 ..); } else { inp = $macro_i.0.slice($macro_i.1 / 8 ..); } let sub = $submac!(inp, $($args)*); let res = match sub { Err(Err::Incomplete(Needed::Size(i))) => Err(match i.checked_mul(8) { Some(v) => Err::Incomplete(Needed::Size(v)), None => Err::Failure(error_position!((inp, 0),ErrorKind::TooLarge)), }), Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)), Ok((i, o)) => { Ok(((i, 0), o)) }, Err(Err::Error(e)) => { let err = match e { Context::Code(i, c) => Context::Code((i,0), c), Context::List(mut v) => { let (i, c) = v.remove(0); Context::Code((i,0), c) } }; Err(Err::Error(err)) }, Err(Err::Failure(e)) => { let err = match e { Context::Code(i, c) => Context::Code((i,0), c), Context::List(mut v) => { let (i, c) = v.remove(0); Context::Code((i,0), c) } }; Err(Err::Error(err)) }, Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)), Err(Err::Incomplete(Needed::Size(i))) => Err(match i.checked_mul(8) { Some(v) => Err::Incomplete(Needed::Size(v)), None => Err::Failure(error_position!((inp, 0),ErrorKind::TooLarge)), }), Ok((i, o)) => { Ok(((i, 0), o)) } }; res } ); ); #[cfg(not(feature = "verbose-errors"))] /// Internal parser, do not use directly #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! bytes_impl ( ($macro_i:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,Context,Slice,ErrorKind}; let inp; if $macro_i.1 % 8 != 0 { inp = $macro_i.0.slice(1 + $macro_i.1 / 8 ..); } else { inp = $macro_i.0.slice($macro_i.1 / 8 ..); } let sub = $submac!(inp, $($args)*); let res = match sub { Err(Err::Incomplete(Needed::Size(i))) => Err(match i.checked_mul(8) { Some(v) => Err::Incomplete(Needed::Size(v)), None => Err::Failure(error_position!((inp, 0),ErrorKind::TooLarge)), }), Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)), Ok((i, o)) => { Ok(((i, 0), o)) }, Err(Err::Error(e)) => { let Context::Code(i, c) = e; Err(Err::Error(Context::Code((i,0), c))) }, Err(Err::Failure(e)) => { let Context::Code(i, c) = e; Err(Err::Failure(Context::Code((i,0), c))) }, }; res } ); ); /// 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!( take_pair<(u8, u8)>, bits!( pair!( take_bits!(u8, 4), take_bits!(u8, 4) ) ) ); /// /// 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, $t:ty, $count:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Needed,IResult}; use $crate::lib::std::ops::Div; use $crate::lib::std::convert::Into; use $crate::Slice; //println!("taking {} bits from {:?}", $count, $i); let (input, bit_offset) = $i; let res : IResult<_, $t> = if $count == 0 { Ok(( (input, bit_offset), (0 as u8).into())) } else { let cnt = ($count as usize + bit_offset).div(8); if input.len() * 8 < $count as usize + bit_offset { //println!("returning incomplete: {}", $count as usize + bit_offset); $crate::need_more($i, Needed::Size($count as usize)) } else { let mut acc:$t = (0 as u8).into(); let mut offset: usize = bit_offset; let mut remaining: usize = $count; let mut end_offset: usize = 0; for byte in input.iter().take(cnt + 1) { if remaining == 0 { break; } let val: $t = if offset == 0 { (*byte as u8).into() } else { (((*byte as u8) << offset) as u8 >> offset).into() }; if remaining < 8 - offset { acc += val >> (8 - offset - remaining); end_offset = remaining + offset; break; } else { acc += val << (remaining - (8 - offset)); remaining -= 8 - offset; offset = 0; } } Ok(( (input.slice(cnt..), end_offset) , acc)) } }; 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, bits!( tag_bits!(u8, 4, 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, $t:ty, $count:expr, $p: pat) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,IResult}; match take_bits!($i, $t, $count) { Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)), Ok((i, o)) => { if let $p = o { let res: IResult<_,$t> = Ok((i, o)); res } else { let e: $crate::ErrorKind = $crate::ErrorKind::TagBits; Err(Err::Error(error_position!($i, e))) } }, _ => { let e: $crate::ErrorKind = $crate::ErrorKind::TagBits; Err(Err::Error(error_position!($i, e))) } } } ) ); #[cfg(test)] mod tests { use lib::std::ops::{AddAssign, Shl, Shr}; use internal::{Err, Needed}; use util::ErrorKind; use types::CompleteByteSlice; #[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), u8, 0), Ok(((sl, 0), 0))); assert_eq!(take_bits!((sl, 0), u8, 8), Ok(((&sl[1..], 0), 170))); assert_eq!(take_bits!((sl, 0), u8, 3), Ok(((&sl[0..], 3), 5))); assert_eq!(take_bits!((sl, 0), u8, 6), Ok(((&sl[0..], 6), 42))); assert_eq!(take_bits!((sl, 1), u8, 1), Ok(((&sl[0..], 2), 0))); assert_eq!(take_bits!((sl, 1), u8, 2), Ok(((&sl[0..], 3), 1))); assert_eq!(take_bits!((sl, 1), u8, 3), Ok(((&sl[0..], 4), 2))); assert_eq!(take_bits!((sl, 6), u8, 3), Ok(((&sl[1..], 1), 5))); assert_eq!(take_bits!((sl, 0), u16, 10), Ok(((&sl[1..], 2), 683))); assert_eq!(take_bits!((sl, 0), u16, 8), Ok(((&sl[1..], 0), 170))); assert_eq!(take_bits!((sl, 6), u16, 10), Ok(((&sl[2..], 0), 752))); assert_eq!(take_bits!((sl, 6), u16, 11), Ok(((&sl[2..], 1), 1504))); assert_eq!(take_bits!((sl, 0), u32, 20), Ok(((&sl[2..], 4), 700_163))); assert_eq!(take_bits!((sl, 4), u32, 20), Ok(((&sl[3..], 0), 716_851))); assert_eq!(take_bits!((CompleteByteSlice(sl), 4), u32, 20), Ok(((sl[3..].into(), 0), 716_851))); assert_eq!( take_bits!((sl, 4), u32, 22), Err(Err::Incomplete(Needed::Size(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), u8, 3, 0b101), Ok(((&sl[0..], 3), 5))); assert_eq!(tag_bits!((sl, 0), u8, 4, 0b1010), Ok(((&sl[0..], 4), 10))); assert_eq!(tag_bits!((CompleteByteSlice(sl), 0), u8, 4, 0b1010), Ok(((sl[0..].into(), 4), 10))); } named!(ch<(&[u8],usize),(u8,u8)>, do_parse!( tag_bits!(u8, 3, 0b101) >> x: take_bits!(u8, 4) >> y: take_bits!(u8, 5) >> (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::Size(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::Size(1)))); assert_eq!( ch_bytes(&input[1..]), Err(Err::Error(error_position!(&input[1..], ErrorKind::TagBits))) ); } named!(bits_bytes_bs, bits!(bytes!(::rest))); named!(bits_bytes_cbs, bits!(bytes!(::rest))); #[test] fn bits_bytes() { let input = [0b10_10_10_10]; assert_eq!(bits_bytes_bs(&input[..]), Ok((&[][..], &[0b10_10_10_10][..]))); assert_eq!(bits_bytes_cbs(CompleteByteSlice(&input[..])), Ok(([][..].into(), [0b10_10_10_10][..].into()))); } #[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 for FakeUint { type Output = FakeUint; fn shr(self, shift: usize) -> FakeUint { FakeUint(self.0 >> shift) } } impl Shl for FakeUint { type Output = FakeUint; fn shl(self, shift: usize) -> FakeUint { FakeUint(self.0 << shift) } } impl From 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), FakeUint, 20), Ok(((&sl[2..], 4), FakeUint(700_163))) ); assert_eq!( take_bits!((sl, 4), FakeUint, 20), Ok(((&sl[3..], 0), FakeUint(716_851))) ); assert_eq!( take_bits!((sl, 4), FakeUint, 22), Err(Err::Incomplete(Needed::Size(22))) ); } } nom-4.2.3/src/branch.rs010064400007670000024000001035311344000023700131200ustar0000000000000000/// Try a list of parsers and return the result of the first successful one /// /// ```rust,ignore /// alt!(I -> IResult | I -> IResult | ... | I -> IResult ) => I -> IResult /// ``` /// 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::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, 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::Unkown(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" ) ) /// ) /// ); /// ``` /// /// If you want the `complete!` combinator to be applied to all rules then use the convenience /// `alt_complete!` macro (see below). /// /// 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)* ) => ( 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) {} 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) {} 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,ErrorKind}; let e2 = ErrorKind::Alt; let err = Err::Error(error_position!($i, e2)); Err(err) } ); ($i:expr, $($rest:tt)*) => ( { alt!(__impl $i, $($rest)* | __end) } ); ); /// Is equivalent to the `alt!` combinator, except that it will not return `Incomplete` /// when one of the constituting parsers returns `Incomplete`. Instead, it will try the /// next alternative in the chain. /// /// You should use this combinator only if you know you /// will not receive partial input for the rules you're trying to match (this /// is almost always the case for parsing programming languages). /// /// ```rust,ignore /// alt_complete!(I -> IResult | I -> IResult | ... | I -> IResult ) => I -> IResult /// ``` /// All the parsers must have the same return type. /// /// If one of the parsers return `Incomplete`, `alt_complete!` will try the next alternative. /// If there is no other parser left to try, an `Error` will be returned. /// /// ```rust,ignore /// alt_complete!(parser_1 | parser_2 | ... | parser_n) /// ``` /// **For more in depth examples, refer to the documentation of `alt!`** #[macro_export(local_inner_macros)] macro_rules! alt_complete ( // Recursive rules (must include `complete!` around the head) ($i:expr, $e:path | $($rest:tt)*) => ( alt_complete!($i, complete!(call!($e)) | $($rest)*); ); ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; let i_ = $i.clone(); let res = complete!(i_, $subrule!($($args)*)); match res { Ok((_,_)) => res, Err(Err::Failure(e)) => Err(Err::Failure(e)), e => { let out = alt_complete!($i, $($rest)*); if let (&Err(Err::Error(ref e1)), &Err(Err::Error(ref e2))) = (&e, &out) { // 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) {} unify_types(e1, e2); } out }, } } ); ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; let i_ = $i.clone(); match complete!(i_, $subrule!($($args)*)) { Ok((i,o)) => Ok((i,$gen(o))), Err(Err::Failure(e)) => Err(Err::Failure(e)), e => { let out = alt_complete!($i, $($rest)*); if let (&Err(Err::Error(ref e1)), &Err(Err::Error(ref e2))) = (&e, &out) { // 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) {} unify_types(e1, e2); } out }, } } ); ($i:expr, $e:path => { $gen:expr } | $($rest:tt)*) => ( alt_complete!($i, complete!(call!($e)) => { $gen } | $($rest)*); ); // Tail (non-recursive) rules ($i:expr, $e:path => { $gen:expr }) => ( alt_complete!($i, call!($e) => { $gen }); ); ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( alt!(__impl $i, complete!($subrule!($($args)*)) => { $gen } | __end) ); ($i:expr, $e:path) => ( alt_complete!($i, call!($e)); ); ($i:expr, $subrule:ident!( $($args:tt)*)) => ( alt!(__impl $i, complete!($subrule!($($args)*)) | __end) ); ); /// `switch!(I -> IResult, P => I -> IResult | ... | P => I -> IResult ) => I -> IResult` /// 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::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,Convert,ErrorKind}; let i_ = $i.clone(); match map!(i_, $submac!($($args)*), Some) { Err(Err::Error(err)) => { fn unify_types(_: &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) {} 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 -> IResult, ... I -> IResult ) => I -> IResult` /// 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,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::Size(4)))); /// # } /// ``` /// /// If one of the child parsers is followed by a `?`, that parser is now /// optional: /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::{Err,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::Size(4)))); /// # } /// ``` #[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,Convert,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)*)); ); // HACK: for some reason, Rust 1.11 does not accept $res.$it in // permutation_unwrap. This is a bit ugly, but it will have no // impact on the generated code #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! acc ( (0, $tup:expr) => ($tup.0); (1, $tup:expr) => ($tup.1); (2, $tup:expr) => ($tup.2); (3, $tup:expr) => ($tup.3); (4, $tup:expr) => ($tup.4); (5, $tup:expr) => ($tup.5); (6, $tup:expr) => ($tup.6); (7, $tup:expr) => ($tup.7); (8, $tup:expr) => ($tup.8); (9, $tup:expr) => ($tup.9); (10, $tup:expr) => ($tup.10); (11, $tup:expr) => ($tup.11); (12, $tup:expr) => ($tup.12); (13, $tup:expr) => ($tup.13); (14, $tup:expr) => ($tup.14); (15, $tup:expr) => ($tup.15); (16, $tup:expr) => ($tup.16); (17, $tup:expr) => ($tup.17); (18, $tup:expr) => ($tup.18); (19, $tup:expr) => ($tup.19); (20, $tup:expr) => ($tup.20); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! permutation_unwrap ( ($it:tt, (), $res:ident, $e:ident?, $($rest:tt)*) => ( succ!($it, permutation_unwrap!((acc!($it, $res)), $res, $($rest)*)); ); ($it:tt, (), $res:ident, $e:ident, $($rest:tt)*) => ({ let res = acc!($it, $res); 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!((acc!($it, $res)), $res, $($rest)*)); ); ($it:tt, (), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({ let res = acc!($it, $res); 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),* , acc!($it, $res)), $res, $($rest)*)); ); ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident, $($rest:tt)*) => ({ let res = acc!($it, $res); 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),* , acc!($it, $res)), $res, $($rest)*)); ); ($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({ let res = acc!($it, $res); 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),* , { acc!($it, $res) })) ); ($it:tt, ($($parsed:expr),*), $res:ident, $e:ident) => ({ let res = acc!($it, $res); 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),* , { acc!($it, $res) })) ); ($it:tt, ($($parsed:expr),*), $res:ident, $submac:ident!( $($args:tt)* )) => ({ let res = acc!($it, $res); 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 acc!($it, $res).is_none() { match $submac!($i, $($args)*) { Ok((i,o)) => { $i = i; acc!($it, $res) = 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 acc!($it, $res).is_none() { match $submac!($i, $($args)*) { Ok((i,o)) => { $i = i; acc!($it, $res) = Some(o); continue; }, Err(Err::Error(_)) => { $all_done = false; }, Err(e) => { $needed = Some(e); break; } }; } }); ); #[cfg(test)] mod tests { #[cfg(feature = "alloc")] use lib::std::string::{String, ToString}; use internal::{Err, IResult, Needed}; use util::ErrorKind; // reproduce the tag and take macros, because of module import order macro_rules! tag ( ($i:expr, $inp: expr) => ( { #[inline(always)] fn as_bytes(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::need_more; 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<_,_,u32> = if reduced != b { let e: ErrorKind = ErrorKind::Tag::; Err(Err::Error(error_position!($i, e))) } else if m < blen { //let e:Err<&[u8], u32> = need_more($i, Needed::Size(blen)); //Err(e) need_more($i, Needed::Size(blen)) } else { Ok((&$i[blen..], reduced)) }; res } ); ); macro_rules! take( ($i:expr, $count:expr) => ( { use $crate::need_more; let cnt = $count as usize; let res:IResult<&[u8],&[u8],u32> = if $i.len() < cnt { need_more($i, Needed::Size(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 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")] #[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> { use Context; Err(Err::Error(Context::Code( &b""[..], ErrorKind::Custom(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, 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::Size(1)))); let a = &b"b"[..]; assert_eq!(alt1(a), Err(Err::Incomplete(Needed::Size(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::Size(3)))); let a = &b"defg"[..]; assert_eq!(alt1(a), Ok((&b"g"[..], &b"def"[..]))); } #[test] fn alt_complete() { named!(ac<&[u8], &[u8]>, alt_complete!(tag!("abcd") | tag!("ef") | tag!("ghi") | tag!("kl")) ); let a = &b""[..]; assert_eq!(ac(a), Err(Err::Error(error_position!(a, ErrorKind::Alt)))); let a = &b"ef"[..]; assert_eq!(ac(a), Ok((&b""[..], &b"ef"[..]))); let a = &b"cde"[..]; assert_eq!(ac(a), Err(Err::Error(error_position!(a, ErrorKind::Alt)))); } #[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::Size(4)))); } /* named!(does_not_compile, alt!(tag!("abcd"), tag!("efgh")) ); */ } nom-4.2.3/src/bytes.rs010064400007670000024000001636611344541017100130320ustar0000000000000000//! 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) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,IResult,ErrorKind}; use $crate::{Compare,CompareResult,InputLength,need_more,InputTake}; let res: IResult<_,_> = match ($i).compare($tag) { CompareResult::Ok => { let blen = $tag.input_len(); Ok($i.take_split(blen)) }, CompareResult::Incomplete => { need_more($i, Needed::Size($tag.input_len())) }, CompareResult::Error => { let e:ErrorKind = ErrorKind::Tag; Err(Err::Error($crate::Context::Code($i, e))) } }; res } ); ); /// `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) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,IResult,ErrorKind}; use $crate::{Compare,CompareResult,InputLength,InputTake}; let res: IResult<_,_> = match ($i).compare_no_case($tag) { CompareResult::Ok => { let blen = $tag.input_len(); Ok($i.take_split(blen)) }, CompareResult::Incomplete => { $crate::need_more($i, Needed::Size($tag.input_len())) }, CompareResult::Error => { let e:ErrorKind = ErrorKind::Tag; Err(Err::Error($crate::Context::Code($i, e))) } }; res } ); ); /// `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) => ( { use $crate::ErrorKind; use $crate::FindToken; use $crate::InputTakeAtPosition; let input = $input; input.split_at_position1(|c| $arr.find_token(c), ErrorKind::IsNot) } ); ); /// `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) => ( { use $crate::ErrorKind; use $crate::FindToken; use $crate::InputTakeAtPosition; let input = $input; input.split_at_position1(|c| !$arr.find_token(c), ErrorKind::IsA) } ); ); /// `escaped!(T -> IResult, U, T -> IResult) => T -> IResult 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::alpha; /// # fn main() { /// 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"[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! escaped ( // Internal parser, do not use directly (__impl $i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $escapable:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,IResult,ErrorKind,need_more}; use $crate::AsChar; use $crate::InputIter; use $crate::InputLength; use $crate::InputTake; use $crate::Slice; let cl = || -> IResult<_,_,u32> { use $crate::Offset; let mut input = $i.clone(); let control_char = $control_char.as_char(); while input.input_len() > 0 { match $normal!(input, $($args)*) { Ok((i, _)) => { if i.input_len() == 0 { return Ok(($i.slice($i.input_len()..), $i)) } else { input = i; } }, Err(Err::Failure(e)) => { return Err(Err::Failure(e)); }, Err(Err::Incomplete(i)) => { return Err(Err::Incomplete(i)); }, Err(Err::Error(_)) => { // unwrap() should be safe here since index < $i.input_len() if input.iter_elements().next().unwrap().as_char() == control_char { let next = control_char.len_utf8(); if next >= input.input_len() { return need_more($i, Needed::Size(next - input.input_len() + 1)); } else { match $escapable!(input.slice(next..), $($args2)*) { Ok((i,_)) => { if i.input_len() == 0 { return Ok(($i.slice($i.input_len()..), $i)) } else { input = i; } }, Err(e) => return Err(e) } } } else { let index = $i.offset(&input); return Ok($i.take_split(index)); } }, } } let index = $i.offset(&input); Ok($i.take_split(index)) }; match cl() { Err(Err::Incomplete(x)) => Err(Err::Incomplete(x)), Ok((i, o)) => Ok((i, o)), Err(Err::Error(e)) => { let e2 = ErrorKind::Escaped::; Err(Err::Error(error_node_position!($i, e2, e))) }, Err(Err::Failure(e)) => { let e2 = ErrorKind::Escaped::; Err(Err::Failure(error_node_position!($i, e2, e))) } } } ); // Internal parser, do not use directly (__impl_1 $i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => ( { escaped!(__impl $i, $submac1!($($args)*), $control_char, $submac2!($($args2)*)) } ); // Internal parser, do not use directly (__impl_1 $i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $g:expr) => ( escaped!(__impl $i, $submac1!($($args)*), $control_char, call!($g)) ); ($i:expr, $submac:ident!( $($args:tt)* ), $control_char: expr, $($rest:tt)+) => ( { escaped!(__impl_1 $i, $submac!($($args)*), $control_char, $($rest)*) } ); ($i:expr, $f:expr, $control_char: expr, $($rest:tt)+) => ( escaped!(__impl_1 $i, call!($f), $control_char, $($rest)*) ); ); /// `escaped_transform!(&[T] -> IResult<&[T], &[T]>, T, &[T] -> IResult<&[T], &[T]>) => &[T] -> IResult<&[T], Vec>` /// 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) /// /// WARNING: if you do not use the `verbose-errors` feature, this combinator will currently fail to build /// because of a type inference error /// /// # Example /// ```ignore /// # #[macro_use] extern crate nom; /// # use nom::alpha; /// # use $crate::lib::std::str::from_utf8; /// # fn main() { /// fn to_s(i:Vec) -> String { /// String::from_utf8_lossy(&i).into_owned() /// } /// named!(transform < String >, /// map!( /// escaped_transform!(call!(alpha), '\\', /// alt!( /// tag!("\\") => { |_| &b"\\"[..] } /// | tag!("\"") => { |_| &b"\""[..] } /// | tag!("n") => { |_| &b"\n"[..] } /// ) /// ), to_s /// ) /// ); /// assert_eq!(transform(&b"ab\\\"cd"[..]), Ok((&b""[..], String::from("ab\"cd")))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! escaped_transform ( // Internal parser, do not use directly (__impl $i: expr, $normal:ident!( $($args:tt)* ), $control_char: expr, $transform:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind}; use $crate::AsChar; use $crate::ExtendInto; use $crate::InputIter; use $crate::InputLength; use $crate::Needed; use $crate::Slice; use $crate::need_more; let cl = || -> $crate::IResult<_,_,_> { use $crate::Offset; let mut index = 0; let mut res = $i.new_builder(); let control_char = $control_char.as_char(); while index < $i.input_len() { let remainder = $i.slice(index..); match $normal!(remainder, $($args)*) { Ok((i,o)) => { o.extend_into(&mut res); if i.input_len() == 0 { return Ok(($i.slice($i.input_len()..), res)); } else { index = $i.offset(&i); } }, Err(Err::Incomplete(i)) => { return Err(Err::Incomplete(i)) }, Err(Err::Failure(e)) => { return Err(Err::Failure(e)) }, Err(Err::Error(_)) => { // unwrap() should be safe here since index < $i.input_len() if remainder.iter_elements().next().unwrap().as_char() == control_char { let next = index + control_char.len_utf8(); let input_len = $i.input_len(); if next >= input_len { return need_more($i, Needed::Size(next - input_len + 1)); } else { match $transform!($i.slice(next..), $($args2)*) { Ok((i,o)) => { o.extend_into(&mut res); if i.input_len() == 0 { return Ok(($i.slice($i.input_len()..), res)) } else { index = $i.offset(&i); } }, Err(Err::Error(e)) => { return Err(Err::Error(e)) }, Err(Err::Incomplete(i)) => { return Err(Err::Incomplete(i)) }, Err(Err::Failure(e)) => { return Err(Err::Failure(e)) }, } } } else { return Ok((remainder, res)) } } } } Ok(($i.slice(index..), res)) }; match cl() { Err(Err::Incomplete(x)) => Err(Err::Incomplete(x)), Ok((i, o)) => Ok((i, o)), Err(Err::Error(e)) => { let e2 = ErrorKind::EscapedTransform::; Err(Err::Error(error_node_position!($i, e2, e))) }, Err(Err::Failure(e)) => { let e2 = ErrorKind::EscapedTransform::; Err(Err::Failure(error_node_position!($i, e2, e))) } } } ); // Internal parser, do not use directly (__impl_1 $i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $submac2:ident!( $($args2:tt)*) ) => ( { escaped_transform!(__impl $i, $submac1!($($args)*), $control_char, $submac2!($($args2)*)) } ); // Internal parser, do not use directly (__impl_1 $i:expr, $submac1:ident!( $($args:tt)* ), $control_char: expr, $g:expr) => ( escaped_transform!(__impl $i, $submac1!($($args)*), $control_char, call!($g)) ); ($i:expr, $submac:ident!( $($args:tt)* ), $control_char: expr, $($rest:tt)+) => ( { escaped_transform!(__impl_1 $i, $submac!($($args)*), $control_char, $($rest)*) } ); ($i:expr, $f:expr, $control_char: expr, $($rest:tt)+) => ( escaped_transform!(__impl_1 $i, call!($f), $control_char, $($rest)*) ); ); /// `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::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)* )) => ( { use $crate::InputTakeAtPosition; let input = $input; input.split_at_position(|c| !$submac!(c, $($args)*)) } ); ($input:expr, $f:expr) => ( take_while!($input, call!($f)); ); ); /// `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,ErrorKind}; /// # use nom::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)* )) => ( { use $crate::ErrorKind; use $crate::InputTakeAtPosition; let input = $input; input.split_at_position1(|c| !$submac!(c, $($args)*), ErrorKind::TakeWhile1) } ); ($input:expr, $f:expr) => ( take_while1!($input, call!($f)); ); ); /// `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::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_m_n ( ($input:expr, $m:expr, $n:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::IResult; use $crate::ErrorKind; use $crate::{InputLength,InputIter,Slice,Err,Needed,AtEof,InputTake}; let input = $input; let m = $m; let n = $n; match input.position(|c| !$submac!(c, $($args)*)) { Some(idx) => { if idx >= m { if idx <= n { let res:IResult<_,_> = Ok(input.take_split(idx)); res } else { let res:IResult<_,_> = Ok(input.take_split(n)); res } } else { let e = ErrorKind::TakeWhileMN::; Err(Err::Error(error_position!(input, e))) } }, None => { let len = input.input_len(); if len >= n { let res:IResult<_,_> = Ok(input.take_split(n)); res } else { if input.at_eof() { if len >= $m && len <= $n { let res:IResult<_,_> = Ok((input.slice(len..), input)); res } else { let e = ErrorKind::TakeWhileMN::; Err(Err::Error(error_position!(input, e))) } } else { let needed = if m > len { m - len } else { 1 }; Err(Err::Incomplete(Needed::Size(needed))) } } } } } ); ($input:expr, $m:expr, $n: expr, $f:expr) => ( take_while_m_n!($input, $m, $n, call!($f)); ); ); /// `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)* )) => ( { use $crate::InputTakeAtPosition; let input = $input; input.split_at_position(|c| $submac!(c, $($args)*)) } ); ($input:expr, $f:expr) => ( take_till!($input, call!($f)); ); ); /// `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,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)* )) => ( { use $crate::{ErrorKind, InputTakeAtPosition}; let input = $input; input.split_at_position1(|c| $submac!(c, $($args)*), ErrorKind::TakeTill1) } ); ($input:expr, $f:expr) => ( take_till1!($input, call!($f)); ); ); /// `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) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Needed,IResult}; use $crate::InputIter; use $crate::InputTake; let input = $i; let cnt = $count as usize; let res: IResult<_,_,u32> = match input.slice_index(cnt) { None => $crate::need_more($i, Needed::Size(cnt)), Some(index) => Ok(input.take_split(index)) }; 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_and_consume!(tag) => &[T] -> IResult<&[T], &[T]>` /// generates a parser consuming bytes until the specified byte sequence is found, and consumes it /// /// The parsed input and the tag are removed from the remainder. /// (As opposed to `take_until!` that does not remove the tag from the remainder.) /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(x, take_until_and_consume!("foo")); /// let r = x(&b"abcd foo efgh"[..]); /// assert_eq!(r, Ok((&b" efgh"[..], &b"abcd "[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! take_until_and_consume ( ($i:expr, $substr:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Needed,IResult,ErrorKind,need_more_err}; use $crate::InputLength; use $crate::FindSubstring; use $crate::Slice; let input = $i; let res: IResult<_,_> = match input.find_substring($substr) { None => { need_more_err(input, Needed::Size($substr.input_len()), ErrorKind::TakeUntilAndConsume::) }, Some(index) => { Ok(($i.slice(index+$substr.input_len()..), $i.slice(0..index))) }, }; res } ); ); /// `take_until_and_consume1!(tag) => &[T] -> IResult<&[T], &[T]>` /// generates a parser consuming bytes (at least 1) until the specified byte sequence is found, and consumes it /// /// The parsed input and the tag are removed from the remainder. /// (As opposed to `take_until1!` that does not remove the tag from the remainder.) /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(x, take_until_and_consume!("foo")); /// let r = x(&b"abcd foo efgh"[..]); /// assert_eq!(r, Ok((&b" efgh"[..], &b"abcd "[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! take_until_and_consume1 ( ($i:expr, $substr:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Err,Needed,IResult,ErrorKind,need_more_err}; use $crate::InputLength; use $crate::FindSubstring; use $crate::Slice; let input = $i; let res: IResult<_,_> = match input.find_substring($substr) { None => { need_more_err(input, Needed::Size(1+$substr.input_len()), ErrorKind::TakeUntilAndConsume1::) }, Some(0) => { let e = ErrorKind::TakeUntilAndConsume1::; Err(Err::Error(error_position!($i, e))) } Some(index) => { Ok(($i.slice(index+$substr.input_len()..), $i.slice(0..index))) }, }; res } ); ); /// `take_until!(tag) => &[T] -> IResult<&[T], &[T]>` /// consumes data until it finds the specified tag. /// /// The remainder still contains the tag. /// (As opposed to `take_until_and_consume!` which removes it from the remainder.) /// /// # 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) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Needed,IResult,need_more_err, ErrorKind}; use $crate::InputLength; use $crate::FindSubstring; use $crate::InputTake; let input = $i; let res: IResult<_,_> = match input.find_substring($substr) { None => { need_more_err($i, Needed::Size($substr.input_len()), ErrorKind::TakeUntil::) }, Some(index) => { Ok($i.take_split(index)) }, }; 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. /// (As opposed to `take_until_and_consume1!` which removes it from the remainder.) /// /// # 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,need_more_err,ErrorKind}; use $crate::InputLength; use $crate::FindSubstring; use $crate::InputTake; let input = $i; let res: IResult<_,_> = match input.find_substring($substr) { None => { need_more_err($i, Needed::Size(1 + $substr.input_len()), ErrorKind::TakeUntil::) }, Some(0) => { let e = ErrorKind::TakeUntil::; Err(Err::Error(error_position!($i, e))) }, Some(index) => { Ok($i.take_split(index)) }, }; res } ); ); /// `take_until_either_and_consume!(chars) => &[T] -> IResult<&[T], &[T]>` /// consumes data until it finds any of the specified characters, and consume it /// /// The parsed input and the tag are removed from the remainder. /// (As opposed to `take_until_either!` that does not remove the tag from the remainder.) /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(x, take_until_either_and_consume!("012")); /// let r = x(&b"abcd2efgh"[..]); /// assert_eq!(r, Ok((&b"efgh"[..], &b"abcd"[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! take_until_either_and_consume ( ($input:expr, $arr:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Needed,IResult,need_more_err,ErrorKind}; use $crate::InputLength; use $crate::InputIter; use $crate::FindToken; use $crate::Slice; let input = $input; let res: IResult<_,_> = match input.position(|c| { $arr.find_token(c) }) { Some(n) => { let mut it = input.slice(n..).iter_indices(); // this unwrap() should be safe, since we already know there's a char there let r1 = it.next().unwrap(); let r2 = it.next(); match r2 { None => { // r1 was the last character of the input, and we consumed it Ok(( input.slice(input.input_len()..), input.slice(..n) )) }, Some(l) => { // index like this because the character we consume might be more than one byte Ok((input.slice(n+r1.0+l.0..), input.slice(..n))) } } }, None => { need_more_err(input, Needed::Size(1), ErrorKind::TakeUntilEitherAndConsume::) } }; res } ); ); /// `take_until_either_and_consume1!(chars) => &[T] -> IResult<&[T], &[T]>` /// consumes data (at least one byte) until it finds any of the specified characters, and consume it /// /// The parsed input and the tag are removed from the remainder. /// (As opposed to `take_until_either!` that does not remove the tag from the remainder.) /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(x, take_until_either_and_consume!("012")); /// let r = x(&b"abcd2efgh"[..]); /// assert_eq!(r, Ok((&b"efgh"[..], &b"abcd"[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! take_until_either_and_consume1 ( ($input:expr, $arr:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Err,Needed,IResult,need_more_err,ErrorKind}; use $crate::InputLength; use $crate::InputIter; use $crate::FindToken; use $crate::Slice; let input = $input; let res: IResult<_,_> = match $input.position(|c| { $arr.find_token(c) }) { Some(0) => Err(Err::Error(error_position!($input, ErrorKind::TakeUntilEitherAndConsume::))), Some(n) => { let mut it = input.slice(n..).iter_indices(); // this unwrap() should be safe, since we already know there's a char there let r1 = it.next().unwrap(); let r2 = it.next(); match r2 { None => { // r1 was the last character of the input, and we consumed it Ok(( input.slice(input.input_len()..), input.slice(..n) )) }, Some(l) => { // index like this because the character we consume might be more than one byte Ok((input.slice(n+r1.0+l.0..), input.slice(..n))) } } }, None => { need_more_err($input, Needed::Size(1), ErrorKind::TakeUntilEitherAndConsume::) } }; res } ); ); /// `take_until_either!(tag) => &[T] -> IResult<&[T], &[T]>` /// consumes data until it finds any of the specified characters /// /// The remainder still contains the tag. /// (As opposed to `take_until_either_and_consume!` which removes it from the remainder.) /// /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(x, take_until_either!("012")); /// let r = x(&b"abcd2efgh"[..]); /// assert_eq!(r, Ok((&b"2efgh"[..], &b"abcd"[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! take_until_either ( ($input:expr, $arr:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Needed,IResult,need_more_err,ErrorKind}; use $crate::InputIter; use $crate::FindToken; use $crate::InputTake; let res: IResult<_,_> = match $input.position(|c| { $arr.find_token(c) }) { Some(n) => { Ok($input.take_split(n)) }, None => { need_more_err($input, Needed::Size(1), ErrorKind::TakeUntilEither::) } }; res } ); ); /// `take_until_either1!(tag) => &[T] -> IResult<&[T], &[T]>` /// consumes data (at least one byte) until it finds any of the specified characters /// /// The remainder still contains the tag. /// (As opposed to `take_until_either_and_consume!` which removes it from the remainder.) /// /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(x, take_until_either!("012")); /// let r = x(&b"abcd2efgh"[..]); /// assert_eq!(r, Ok((&b"2efgh"[..], &b"abcd"[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! take_until_either1 ( ($input:expr, $arr:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Err,Needed,IResult,need_more_err,ErrorKind}; use $crate::InputIter; use $crate::InputTake; use $crate::FindToken; let res: IResult<_,_> = match $input.position(|c| { $arr.find_token(c) }) { Some(0) => Err(Err::Error(error_position!($input, ErrorKind::TakeUntilEither::))), Some(n) => { Ok($input.take_split(n)) }, None => { need_more_err($input, Needed::Size(1), ErrorKind::TakeUntilEither::) } }; res } ); ); /// `length_bytes!(&[T] -> IResult<&[T], nb>) => &[T] -> IResult<&[T], &[T]>` /// Gets a number from the first parser, then extracts that many bytes from the /// remaining stream /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # use nom::be_u8; /// # fn main() { /// named!(with_length, length_bytes!( be_u8 )); /// let r = with_length(&b"\x05abcdefgh"[..]); /// assert_eq!(r, Ok((&b"fgh"[..], &b"abcde"[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! length_bytes( ($i:expr, $submac:ident!( $($args:tt)* )) => ( { length_data!($i, $submac!($($args)*)) } ); ($i:expr, $f:expr) => ( length_data!($i, call!($f)) ) ); #[cfg(test)] mod tests { use internal::{Err, Needed}; use nom::{alpha, alphanumeric, digit, hex_digit, multispace, oct_digit, space}; use types::{CompleteByteSlice, CompleteStr}; use util::ErrorKind; #[cfg(feature = "alloc")] #[cfg(feature = "verbose-errors")] use lib::std::string::String; #[cfg(feature = "alloc")] #[cfg(feature = "verbose-errors")] use lib::std::vec::Vec; 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::Size(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::Size(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::Incomplete(Needed::Size(1)))); 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::Incomplete(Needed::Size(1)))); 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")] #[test] fn escaping_complete_str() { named!(esc, escaped!(call!(alpha), '\\', one_of!("\"n\\"))); assert_eq!( esc(CompleteStr("abcd;")), Ok((CompleteStr(";"), CompleteStr("abcd"))) ); assert_eq!( esc(CompleteStr("ab\\\"cd;")), Ok((CompleteStr(";"), CompleteStr("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(CompleteStr("AB\\")), Err(Err::Error(error_node_position!( CompleteStr("AB\\"), ErrorKind::Escaped, error_position!(CompleteStr("AB\\"), ErrorKind::Eof) ))) ); assert_eq!(esc(CompleteStr("")), Ok((CompleteStr(""), CompleteStr("")))); /*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")] #[cfg(feature = "verbose-errors")] fn to_s(i: Vec) -> String { String::from_utf8_lossy(&i).into_owned() } #[cfg(feature = "alloc")] #[cfg(feature = "verbose-errors")] #[test] fn escape_transform() { use lib::std::str; named!( esc, 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::Incomplete(Needed::Size(1)))); 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, 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 = "verbose-errors")] #[test] fn issue_84() { let r0 = is_a!(&b"aaaaefgh"[..], "abcd"); assert_eq!(r0, Ok((&b"efgh"[..], &b"aaaa"[..]))); let r1 = is_a!(&b"aaaa;"[..], "abcd"); assert_eq!(r1, Ok((&b";"[..], &b"aaaa"[..]))); let r2 = is_a!(&b"1;"[..], "123456789"); assert_eq!(r2, Ok((&b";"[..], &b"1"[..]))); } #[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::Incomplete(Needed::Size(1)))); 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"; assert_eq!(take_str!(&a[..], 5), Ok((&b"nom"[..], "omnom"))); assert_eq!(take_str!(&a[..], 9), Err(Err::Incomplete(Needed::Size(9)))); } #[test] fn take_until_and_consume() { named!(x, take_until_and_consume!("efgh")); let r = x(&b"abcdabcdefghijkl"[..]); assert_eq!(r, Ok((&b"ijkl"[..], &b"abcdabcd"[..]))); let r2 = x(&b"abcdabcdefgh"[..]); assert_eq!(r2, Ok((&b""[..], &b"abcdabcd"[..]))); let r3 = x(&b"abcefg"[..]); assert_eq!(r3, Err(Err::Incomplete(Needed::Size(4)))); assert_eq!(x(&b"ab"[..]), Err(Err::Incomplete(Needed::Size(4)))); } #[test] fn take_until_and_consume_complete() { named!(x, take_until_and_consume!("efgh")); let r = x(CompleteStr(&"abcdabcdefghijkl"[..])); assert_eq!( r, Ok((CompleteStr(&"ijkl"[..]), CompleteStr(&"abcdabcd"[..]))) ); let r2 = x(CompleteStr(&"abcdabcdefgh"[..])); assert_eq!(r2, Ok((CompleteStr(&""[..]), CompleteStr(&"abcdabcd"[..])))); let r3 = x(CompleteStr(&"abcefg"[..])); assert_eq!( r3, Err(Err::Error(error_position!( CompleteStr(&"abcefg"[..]), ErrorKind::TakeUntilAndConsume ))) ); assert_eq!( x(CompleteStr(&"ab"[..])), Err(Err::Error(error_position!( CompleteStr(&"ab"[..]), ErrorKind::TakeUntilAndConsume ))) ); } #[test] fn take_until_and_consume1() { named!(x, take_until_and_consume1!("efgh")); let r = x(&b"abcdabcdefghijkl"[..]); assert_eq!(r, Ok((&b"ijkl"[..], &b"abcdabcd"[..]))); let r2 = x(&b"abcdabcdefgh"[..]); assert_eq!(r2, Ok((&b""[..], &b"abcdabcd"[..]))); let r3 = x(&b"abcefg"[..]); assert_eq!(r3, Err(Err::Incomplete(Needed::Size(5)))); let r4 = x(&b"efgh"[..]); assert_eq!( r4, Err(Err::Error(error_position!( &b"efgh"[..], ErrorKind::TakeUntilAndConsume1 ))) ); named!(x2, take_until_and_consume1!("")); let r5 = x2(&b""[..]); assert_eq!( r5, Err(Err::Error(error_position!( &b""[..], ErrorKind::TakeUntilAndConsume1 ))) ); let r6 = x2(&b"a"[..]); assert_eq!( r6, Err(Err::Error(error_position!( &b"a"[..], ErrorKind::TakeUntilAndConsume1 ))) ); let r7 = x(&b"efghi"[..]); assert_eq!( r7, Err(Err::Error(error_position!( &b"efghi"[..], ErrorKind::TakeUntilAndConsume1 ))) ); } #[test] fn take_until_and_consume1_complete() { named!(x, take_until_and_consume1!("efgh")); let r = x(CompleteStr(&"abcdabcdefghijkl"[..])); assert_eq!( r, Ok((CompleteStr(&"ijkl"[..]), CompleteStr(&"abcdabcd"[..]))) ); let r2 = x(CompleteStr(&"abcdabcdefgh"[..])); assert_eq!(r2, Ok((CompleteStr(&""[..]), CompleteStr(&"abcdabcd"[..])))); let r3 = x(CompleteStr(&"abcefg"[..])); assert_eq!( r3, Err(Err::Error(error_position!( CompleteStr("abcefg"), ErrorKind::TakeUntilAndConsume1 ))) ); let r4 = x(CompleteStr(&"efgh"[..])); assert_eq!( r4, Err(Err::Error(error_position!( CompleteStr("efgh"), ErrorKind::TakeUntilAndConsume1 ))) ); named!(x2, take_until_and_consume1!("")); let r5 = x2(CompleteStr("")); assert_eq!( r5, Err(Err::Error(error_position!( CompleteStr(""), ErrorKind::TakeUntilAndConsume1 ))) ); let r6 = x2(CompleteStr("a")); assert_eq!( r6, Err(Err::Error(error_position!( CompleteStr("a"), ErrorKind::TakeUntilAndConsume1 ))) ); let r7 = x(CompleteStr("efghi")); assert_eq!( r7, Err(Err::Error(error_position!( CompleteStr("efghi"), ErrorKind::TakeUntilAndConsume1 ))) ); } #[test] fn take_until_either() { named!(x, take_until_either!("!.")); assert_eq!(x(&b"123!abc"[..]), Ok((&b"!abc"[..], &b"123"[..]))); assert_eq!(x(&b"123"[..]), Err(Err::Incomplete(Needed::Size(1)))); } #[test] fn take_until_either_complete() { named!(x, take_until_either!("!.")); assert_eq!( x(CompleteStr("123!abc")), Ok((CompleteStr("!abc"), CompleteStr("123"))) ); assert_eq!( x(CompleteStr("123")), Err(Err::Error(error_position!( CompleteStr("123"), ErrorKind::TakeUntilEither ))) ); } #[test] fn take_until_either_and_consume() { named!(x, take_until_either_and_consume!("!.")); assert_eq!(x(&b"123.abc"[..]), Ok((&b"abc"[..], &b"123"[..]))); } #[test] fn take_until_incomplete() { named!(y, take_until!("end")); assert_eq!(y(&b"nd"[..]), Err(Err::Incomplete(Needed::Size(3)))); assert_eq!(y(&b"123"[..]), Err(Err::Incomplete(Needed::Size(3)))); assert_eq!(y(&b"123en"[..]), Err(Err::Incomplete(Needed::Size(3)))); } #[test] fn take_until_complete() { named!(y, take_until!("end")); assert_eq!( y(CompleteStr("nd")), Err(Err::Error(error_position!( CompleteStr("nd"), ErrorKind::TakeUntil ))) ); assert_eq!( y(CompleteStr("123")), Err(Err::Error(error_position!( CompleteStr("123"), ErrorKind::TakeUntil ))) ); assert_eq!( y(CompleteStr("123en")), Err(Err::Error(error_position!( CompleteStr("123en"), ErrorKind::TakeUntil ))) ); assert_eq!( y(CompleteStr("123end")), Ok((CompleteStr("end"), CompleteStr("123"))) ); } #[test] fn take_until_incomplete_s() { named!(ys<&str, &str>, take_until!("end")); assert_eq!(ys("123en"), Err(Err::Incomplete(Needed::Size(3)))); } #[test] fn recognize() { named!( x, recognize!(delimited!(tag!(""))) ); let r = x(&b" aaa"[..]); assert_eq!(r, Ok((&b" aaa"[..], &b""[..]))); 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() { use nom::is_alphabetic; 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::Size(1)))); assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(f(&c[..]), Ok((&d[..], &b[..]))); assert_eq!(f(&d[..]), Ok((&d[..], &a[..]))); } #[test] fn take_while1() { use nom::is_alphabetic; 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::Size(1)))); assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::Size(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 nom::is_alphabetic; 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::Size(2)))); assert_eq!(x(&b[..]), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(x(&c[..]), Err(Err::Incomplete(Needed::Size(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_while_m_n_complete() { use nom::is_alphabetic; named!(x, take_while_m_n!(2, 4, is_alphabetic)); let a = CompleteByteSlice(b""); let b = CompleteByteSlice(b"a"); let c = CompleteByteSlice(b"abc"); let d = CompleteByteSlice(b"abc123"); let e = CompleteByteSlice(b"abcde"); let f = CompleteByteSlice(b"123"); assert_eq!( x(a), Err(Err::Error(error_position!(a, ErrorKind::TakeWhileMN))) ); assert_eq!( x(b), Err(Err::Error(error_position!(b, ErrorKind::TakeWhileMN))) ); assert_eq!(x(c), Ok((CompleteByteSlice(b""), c))); assert_eq!( x(d), Ok((CompleteByteSlice(b"123"), CompleteByteSlice(b"abc"))) ); assert_eq!( x(e), Ok((CompleteByteSlice(b"e"), CompleteByteSlice(b"abcd"))) ); assert_eq!( x(f), Err(Err::Error(error_position!(f, ErrorKind::TakeWhileMN))) ); } #[test] fn take_while1_complete() { use nom::is_alphabetic; named!(f, take_while1!(is_alphabetic)); let a = CompleteByteSlice(b""); let b = CompleteByteSlice(b"abcd"); let c = CompleteByteSlice(b"abcd123"); let d = CompleteByteSlice(b"123"); assert_eq!( f(a), Err(Err::Error(error_position!(a, ErrorKind::TakeWhile1))) ); assert_eq!(f(b), Ok((CompleteByteSlice(b""), b))); assert_eq!(f(c), Ok((CompleteByteSlice(b"123"), b))); assert_eq!( f(d), Err(Err::Error(error_position!(d, ErrorKind::TakeWhile1))) ); named!(f2, take_while1!(|c: char| c.is_alphabetic())); let a2 = CompleteStr(""); assert_eq!( f2(a2), Err(Err::Error(error_position!(a2, ErrorKind::TakeWhile1))) ); } #[test] fn take_till() { use nom::is_alphabetic; 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::Size(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::Size(1)))); } #[test] fn take_till_complete() { use nom::is_alphabetic; named!(f, take_till!(is_alphabetic)); let a = CompleteByteSlice(b""); let b = CompleteByteSlice(b"abcd"); let c = CompleteByteSlice(b"123abcd"); let d = CompleteByteSlice(b"123"); assert_eq!(f(a), Ok((a, a))); assert_eq!( f(b), Ok((CompleteByteSlice(b"abcd"), CompleteByteSlice(b""))) ); assert_eq!( f(c), Ok((CompleteByteSlice(b"abcd"), CompleteByteSlice(b"123"))) ); assert_eq!(f(d), Ok((a, d))); } #[test] fn take_till1() { use nom::is_alphabetic; 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::Size(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::Size(1)))); } #[test] fn take_while_utf8() { named!(f<&str,&str>, take_while!(|c:char| { c != '點' })); assert_eq!(f(""), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(f("abcd"), Err(Err::Incomplete(Needed::Size(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::Size(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::Size(1)))); assert_eq!(f("abcd"), Err(Err::Incomplete(Needed::Size(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::Size(1)))); assert_eq!(g("點abcd"), Ok(("abcd", "點"))); assert_eq!(g("點點點a"), Ok(("a", "點點點"))); } #[test] fn take_until_either_and_consume_utf8() { named!(f<&str,&str>, take_until_either_and_consume!("é點")); assert_eq!(f(""), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(f("abcd"), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(f("abcd點"), Ok(("", "abcd"))); assert_eq!(f("abcdéa"), Ok(("a", "abcd"))); assert_eq!(f("點a"), Ok(("a", ""))); named!(g<&str,&str>, take_until_either_and_consume1!("é點")); assert_eq!(g(""), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(g("xabcd"), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(g("xabcd點"), Ok(("", "xabcd"))); assert_eq!(g("xabcdéa"), Ok(("a", "xabcd"))); assert_eq!( g("點xa"), Err(Err::Error(error_position!( "點xa", ErrorKind::TakeUntilEitherAndConsume ))) ); } #[test] fn take_utf8() { named!(f<&str,&str>, take!(3)); assert_eq!(f(""), Err(Err::Incomplete(Needed::Size(3)))); assert_eq!(f("ab"), Err(Err::Incomplete(Needed::Size(3)))); assert_eq!(f("點"), Err(Err::Incomplete(Needed::Size(3)))); 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::Size(1)))); assert_eq!(g("點abcd"), Ok(("abcd", "點"))); assert_eq!(g("點點點a"), Ok(("a", "點點點"))); } #[cfg(nightly)] use test::Bencher; #[cfg(nightly)] #[bench] fn take_while_bench(b: &mut Bencher) { use nom::is_alphabetic; named!(f, take_while!(is_alphabetic)); b.iter(|| f(&b"abcdefghijklABCDEejfrfrjgro12aa"[..])); } #[test] #[cfg(feature = "std")] fn recognize_take_while() { use nom::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 nom::le_u8; named!(x, length_bytes!(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::Size(2)))); assert_eq!(x(b"\x02"), Err(Err::Incomplete(Needed::Size(2)))); named!( y, do_parse!(tag!("magic") >> b: length_bytes!(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::Size(2)))); assert_eq!(y(b"magic\x02"), Err(Err::Incomplete(Needed::Size(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::Size(4)))); 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::Size(4)))); 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"[..]))); } } nom-4.2.3/src/character.rs010064400007670000024000000141271344541017100136300ustar0000000000000000/// Character level parsers use internal::{IResult, Needed}; use traits::{AsChar, InputIter, InputLength, Slice}; use lib::std::ops::RangeFrom; use traits::{need_more, AtEof}; /// matches one of the provided characters /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(simple, 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) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Err,Needed}; use $crate::Slice; use $crate::AsChar; use $crate::FindToken; use $crate::InputIter; match ($i).iter_elements().next().map(|c| { (c, $inp.find_token(c)) }) { None => $crate::need_more($i, Needed::Size(1)), Some((_, false)) => Err(Err::Error(error_position!($i, $crate::ErrorKind::OneOf::))), //the unwrap should be safe here Some((c, true)) => Ok(( $i.slice(c.len()..), $i.iter_elements().next().unwrap().as_char() )) } } ); ); /// matches anything but the provided characters /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # use nom::{Err,ErrorKind}; /// # fn main() { /// named!(no_letter_a, none_of!(&b"abc"[..])); /// assert_eq!(no_letter_a(b"123"), Ok((&b"23"[..], '1'))); /// /// named!(err_on_single_quote, 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) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Err,Needed}; use $crate::Slice; use $crate::AsChar; use $crate::FindToken; use $crate::InputIter; match ($i).iter_elements().next().map(|c| { (c, !$inp.find_token(c)) }) { None => $crate::need_more($i, Needed::Size(1)), Some((_, false)) => Err(Err::Error(error_position!($i, $crate::ErrorKind::NoneOf::))), //the unwrap should be safe here Some((c, true)) => Ok(( $i.slice(c.len()..), $i.iter_elements().next().unwrap().as_char() )) } } ); ); /// matches one character: `char!(char) => &[u8] -> IResult<&[u8], char> /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # use nom::{Err,ErrorKind}; /// # fn main() { /// named!(match_letter_a, 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) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Err,Needed}; use $crate::Slice; use $crate::AsChar; use $crate::InputIter; match ($i).iter_elements().next().map(|c| { let b = c.as_char() == $c; b }) { None => $crate::need_more($i, Needed::Size(1)), Some(false) => { let e: $crate::ErrorKind = $crate::ErrorKind::Char; Err(Err::Error($crate::Context::Code($i, e))) }, //the unwrap should be safe here Some(true) => Ok(( $i.slice($c.len()..), $i.iter_elements().next().unwrap().as_char() )) } } ); ); named!(#[doc="Matches a newline character '\\n'"], pub newline, char!('\n')); named!(#[doc="Matches a tab character '\\t'"], pub tab, char!('\t')); /// matches one byte as a character. Note that the input type will /// accept a `str`, but not a `&[u8]`, unlike many other nom parsers. /// /// # Example /// ``` /// # #[macro_use] extern crate nom; /// # use nom::anychar; /// # fn main() { /// assert_eq!(anychar("abc"), Ok(("bc",'a'))); /// # } /// ``` pub fn anychar(input: T) -> IResult where T: InputIter + InputLength + Slice> + AtEof, ::Item: AsChar, { let mut it = input.iter_indices(); match it.next() { None => need_more(input, Needed::Size(1)), Some((_, c)) => match it.next() { None => Ok((input.slice(input.input_len()..), c.as_char())), Some((idx, _)) => Ok((input.slice(idx..), c.as_char())), }, } } #[cfg(test)] mod tests { use internal::Err; use util::ErrorKind; #[test] fn one_of() { named!(f, 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, 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!('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'))); } use types::CompleteStr; #[test] fn complete_char() { named!(f, char!('c')); let a = CompleteStr("abcd"); assert_eq!(f(a), Err(Err::Error(error_position!(a, ErrorKind::Char)))); let b = CompleteStr("cde"); assert_eq!(f(b), Ok((CompleteStr("de"), 'c'))); } #[test] fn anychar_str() { use super::anychar; assert_eq!(anychar("Ә"), Ok(("", 'Ә'))); } } nom-4.2.3/src/internal.rs010064400007670000024000000344211344000023700135000ustar0000000000000000//! Basic types to build the parsers use self::Needed::*; #[cfg(feature = "verbose-errors")] use verbose_errors::Context; #[cfg(not(feature = "verbose-errors"))] use simple_errors::Context; /// Holds the result of parsing functions /// /// It depends on I, the input type, O, the output type, and E, the error type (by default u32) /// /// The `Ok` side is an enum containing the remainder of the input (the part of the data that /// was not parsed) and the produced value. The `Err` side contains an instance of `nom::Err`. /// pub type IResult = Result<(I, O), Err>; /// Contains information on needed data if a parser returned `Incomplete` #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Needed { /// needs more data, but we do not know how much Unknown, /// contains the required data size Size(usize), } impl Needed { pub fn is_known(&self) -> bool { *self != Unknown } /// Maps a `Needed` to `Needed` by appling a function to a contained `Size` value. #[inline] pub fn map usize>(self, f: F) -> Needed { match self { Unknown => Unknown, Size(n) => Size(f(n)), } } } /// The `Err` enum indicates the parser was not successful /// /// It has three cases: /// /// * `Incomplete` indicates that more data is needed to decide. The `Needed` enum /// can contain how many additional bytes are necessary. If you are sure your parser /// is working on full data, you can wrap your parser with the `complete` combinator /// to transform that case in `Error` /// * `Error` means some parser did not succeed, but another one might (as an example, /// when testing different branches of an `alt` combinator) /// * `Failure` indicates an unrecoverable error. As an example, if you recognize a prefix /// to decide on the next parser to apply, and that parser fails, you know there's no need /// to try other parsers, you were already in the right branch, so the data is invalid /// /// Depending on a compilation flag, the content of the `Context` enum /// can change. In the default case, it will only have one variant: /// `Context::Code(I, ErrorKind)` (with `I` and `E` configurable). /// It contains an error code and the input position that triggered it. /// /// If you activate the `verbose-errors` compilation flags, it will add another /// variant to the enum: `Context::List(Vec<(I, ErrorKind)>)`. /// This variant aggregates positions and error codes as the code backtracks /// through the nested parsers. /// The verbose errors feature allows for very flexible error management: /// you can know precisely which parser got to which part of the input. /// The main drawback is that it is a lot slower than default error /// management. #[derive(Debug, Clone, PartialEq)] pub enum Err { /// There was not enough data Incomplete(Needed), /// The parser had an error (recoverable) Error(Context), /// The parser had an unrecoverable error: we got to the right /// branch and we know other branches won't work, so backtrack /// as fast as possible Failure(Context), } #[cfg(feature = "std")] use std::fmt; #[cfg(feature = "std")] impl fmt::Display for Err where I: fmt::Debug, E: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } #[cfg(feature = "std")] use std::error::Error; #[cfg(feature = "std")] impl Error for Err where I: fmt::Debug, E: fmt::Debug, { fn description(&self) -> &str { match self { &Err::Incomplete(..) => "there was not enough data", &Err::Error(Context::Code(_, ref error_kind)) | &Err::Failure(Context::Code(_, ref error_kind)) => error_kind.description(), #[cfg(feature = "verbose-errors")] &Err::Error(Context::List(..)) | &Err::Failure(Context::List(..)) => "list of errors", } } fn cause(&self) -> Option<&Error> { None } } use util::Convert; impl, F, E: From> Convert> for Err { fn convert(e: Err) -> Self { match e { Err::Incomplete(n) => Err::Incomplete(n), Err::Failure(c) => Err::Failure(Context::convert(c)), Err::Error(c) => Err::Error(Context::convert(c)), } } } impl Err { pub fn into_error_kind(self) -> ::util::ErrorKind { match self { Err::Incomplete(_) => ::util::ErrorKind::Complete, Err::Failure(c) => c.into_error_kind(), Err::Error(c) => c.into_error_kind(), } } pub fn is_incomplete(&self) -> bool { match *self { Err::Incomplete(_) => true, _ => false, } } } /* #[cfg(feature = "verbose-errors")] /// This is the same as IResult, but without Done /// /// This is used as the Error type when converting to std::result::Result #[derive(Debug,PartialEq,Eq,Clone)] pub enum IError { Error(Err), Incomplete(Needed) } #[cfg(not(feature = "verbose-errors"))] /// This is the same as IResult, but without Done /// /// This is used as the Error type when converting to std::result::Result #[derive(Debug,PartialEq,Eq,Clone)] pub enum IError { Error(Err), Incomplete(Needed) } impl IResult { pub fn is_done(&self) -> bool { match *self { Done(_,_) => true, _ => false } } pub fn is_err(&self) -> bool { match *self { Error(_) => true, _ => false } } pub fn is_incomplete(&self) -> bool { match *self { Incomplete(_) => true, _ => false } } pub fn or(self, other: IResult) -> IResult { if self.is_done() { self } else { other } } /// Maps a `IResult` to `IResult` by appling a function /// to a contained `Done` value, leaving `Error` and `Incomplete` value /// untouched. #[inline] pub fn map N>(self, f: F) -> IResult { match self { Done(i, o) => Done(i, f(o)), Error(e) => Error(e), Incomplete(n) => Incomplete(n), } } /// Maps a `IResult` to `IResult` by appling a function /// to a contained `Incomplete` value, leaving `Done` and `Error` value /// untouched. #[inline] pub fn map_inc(self, f: F) -> IResult where F: FnOnce(Needed) -> Needed { match self { Error(e) => Error(e), Incomplete(n) => Incomplete(f(n)), Done(i, o) => Done(i, o), } } /// Unwrap the contained `Done(I, O)` value, or panic if the `IResult` is not /// `Done`. pub fn unwrap(self) -> (I, O) { match self { Done(i, o) => (i, o), Incomplete(_) => panic!("unwrap() called on an IResult that is Incomplete"), Error(_) => panic!("unwrap() called on an IResult that is Error") } } /// Unwrap the contained `Done(I, O)` value or a default if the `IResult` is not /// `Done`. pub fn unwrap_or(self, default: (I, O)) -> (I, O) { match self { Done(i, o) => (i, o), Incomplete(_) => default, Error(_) => default } } /// Unwrap the contained `Incomplete(n)` value, or panic if the `IResult` is not /// `Incomplete`. pub fn unwrap_inc(self) -> Needed { match self { Incomplete(n) => n, Done(_, _) => panic!("unwrap_inc() called on an IResult that is Done"), Error(_) => panic!("unwrap_inc() called on an IResult that is Error") } } } pub trait GetInput { fn remaining_input(&self) -> Option; } pub trait GetOutput { fn output(&self) -> Option; } impl<'a,I,O,E> GetInput<&'a[I]> for IResult<&'a[I],O,E> { fn remaining_input(&self) -> Option<&'a[I]> { match *self { Done(ref i,_) => Some(*i), _ => None } } } impl GetInput<()> for IResult<(),O,E> { fn remaining_input(&self) -> Option<()> { match *self { Done((),_) => Some(()), _ => None } } } impl<'a,O,E> GetInput<&'a str> for IResult<&'a str,O,E> { fn remaining_input(&self) -> Option<&'a str> { match *self { Done(ref i,_) => Some(*i), _ => None } } } impl<'a,I,O,E> GetOutput<&'a[O]> for IResult { fn output(&self) -> Option<&'a[O]> { match *self { Done(_, ref o) => Some(*o), _ => None } } } impl GetOutput<()> for IResult { fn output(&self) -> Option<()> { match *self { Done(_,()) => Some(()), _ => None } } } impl<'a,I,E> GetOutput<&'a str> for IResult { fn output(&self) -> Option<&'a str> { match *self { Done(_,ref o) => Some(*o), _ => None } } }*/ #[cfg(feature = "verbose-errors")] /// creates a parse error from a `nom::ErrorKind` /// and the position in the input /// if "verbose-errors" is not activated, /// it default to only the error code #[macro_export(local_inner_macros)] macro_rules! error_position( ($input: expr, $code:expr) => ({ $crate::Context::Code($input, $code) }); ); #[cfg(not(feature = "verbose-errors"))] /// creates a parse error from a `nom::ErrorKind` /// and the position in the input /// if "verbose-errors" is not activated, /// it default to only the error code #[allow(unused_variables)] #[macro_export(local_inner_macros)] macro_rules! error_position( ($input:expr, $code:expr) => ({ $crate::Context::Code($input, $code) }); ); #[cfg(feature = "verbose-errors")] /// creates a parse error from a `nom::ErrorKind`, /// the position in the input and the next error in /// the parsing tree. /// if "verbose-errors" is not activated, /// it default to only the error code #[macro_export(local_inner_macros)] macro_rules! error_node_position( ($input:expr, $code:expr, $next:expr) => { { let mut error_vec = match $next { $crate::Context::Code(i, e) => { let mut v = $crate::lib::std::vec::Vec::new(); v.push((i, e)); v }, $crate::Context::List(v) => { v }, }; error_vec.push(($input, $code)); $crate::Context::List(error_vec) } } ); #[cfg(not(feature = "verbose-errors"))] /// creates a parse error from a `nom::ErrorKind`, /// the position in the input and the next error in /// the parsing tree. /// if "verbose-errors" is not activated, /// it default to only the error code #[allow(unused_variables)] #[macro_export(local_inner_macros)] macro_rules! error_node_position( ($input:expr, $code:expr, $next:expr) => ({ fn unify_types(_: &T, _: &T) {} let res = $crate::Context::Code($input, $code); unify_types(&res, &$next); res }); ); #[cfg(test)] mod tests { /* const REST: [u8; 0] = []; const DONE: IResult<&'static [u8], u32> = Ok((&REST, 5)); const ERROR: IResult<&'static [u8], u32> = Err(Err::Error(Context::Code(&b""[..], ErrorKind::Tag))); const INCOMPLETE: IResult<&'static [u8], u32> = Err(Err::Incomplete(Needed::Unknown)); */ /* #[test] fn iresult_or() { assert_eq!(DONE.or(ERROR), DONE); assert_eq!(ERROR.or(DONE), DONE); assert_eq!(INCOMPLETE.or(ERROR), ERROR); } #[test] fn needed_map() { let unknown = Needed::Unknown; let size = Needed::Size(5); assert_eq!(size.map(|x| x * 2), Needed::Size(10)); assert_eq!(unknown.map(|x| x * 2), Needed::Unknown); } #[test] fn iresult_map() { assert_eq!(DONE.map(|x| x * 2), IResult::Done(&b""[..], 10)); assert_eq!(ERROR.map(|x| x * 2), IResult::Error(error_code!(ErrorKind::Tag))); assert_eq!(INCOMPLETE.map(|x| x * 2), IResult::Incomplete(Needed::Unknown)); } #[test] fn iresult_map_inc() { let inc_unknown: IResult<&[u8], u32> = IResult::Incomplete(Needed::Unknown); let inc_size: IResult<&[u8], u32> = IResult::Incomplete(Needed::Size(5)); assert_eq!(DONE.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Done(&b""[..], 5)); assert_eq!(ERROR.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Error(error_code!(ErrorKind::Tag))); assert_eq!(inc_unknown.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Unknown)); assert_eq!(inc_size.map_inc(|n| if let Needed::Size(i) = n {Needed::Size(i+1)} else {n}), IResult::Incomplete(Needed::Size(6))); } #[test] #[cfg(feature = "std")] fn iresult_map_err() { #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Error(u32); let error_kind = error_code!(ErrorKind::Custom(Error(5))); assert_eq!(DONE.map_err(|_| error_kind.clone()), IResult::Done(&b""[..], 5)); assert_eq!(ERROR.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Error(error_kind.clone())); assert_eq!(INCOMPLETE.map_err(|x| {println!("err: {:?}", x); error_kind.clone()}), IResult::Incomplete(Needed::Unknown)); } #[test] fn iresult_unwrap_on_done() { assert_eq!(DONE.unwrap(), (&b""[..], 5)); } #[test] #[should_panic] fn iresult_unwrap_on_err() { ERROR.unwrap(); } #[test] #[should_panic] fn iresult_unwrap_on_inc() { INCOMPLETE.unwrap(); } #[test] fn iresult_unwrap_or_on_done() { assert_eq!(DONE.unwrap_or((&b""[..], 2)), (&b""[..], 5)); } #[test] fn iresult_unwrap_or_on_err() { assert_eq!(ERROR.unwrap_or((&b""[..], 2)), (&b""[..], 2)); } #[test] fn iresult_unwrap_or_on_inc() { assert_eq!(INCOMPLETE.unwrap_or((&b""[..], 2)), (&b""[..], 2)); } #[test] #[should_panic] fn iresult_unwrap_err_on_done() { DONE.unwrap_err(); } #[test] fn iresult_unwrap_err_on_err() { assert_eq!(ERROR.unwrap_err(), error_code!(ErrorKind::Tag)); } #[test] #[should_panic] fn iresult_unwrap_err_on_inc() { INCOMPLETE.unwrap_err(); } #[test] #[should_panic] fn iresult_unwrap_inc_on_done() { DONE.unwrap_inc(); } #[test] #[should_panic] fn iresult_unwrap_inc_on_err() { ERROR.unwrap_inc(); } #[test] fn iresult_unwrap_inc_on_inc() { assert_eq!(INCOMPLETE.unwrap_inc(), Needed::Unknown); } #[test] fn iresult_to_result() { assert_eq!(DONE.to_result(), Ok(5)); assert_eq!(ERROR.to_result(), Err(error_code!(ErrorKind::Tag))); } #[test] #[should_panic] fn iresult_to_result_on_incomplete() { INCOMPLETE.to_result().unwrap(); } #[test] fn iresult_to_full_result() { assert_eq!(DONE.to_full_result(), Ok(5)); assert_eq!(INCOMPLETE.to_full_result(), Err(IError::Incomplete(Needed::Unknown))); assert_eq!(ERROR.to_full_result(), Err(IError::Error(error_code!(ErrorKind::Tag)))); } */ } nom-4.2.3/src/lib.rs010064400007670000024000000353251344521703100124450ustar0000000000000000//! # nom, eating data byte by byte //! //! nom is a parser combinator library with a focus on safe parsing, //! streaming patterns, and as much as possible zero copy. //! //! ## Example //! //! ```rust //! #[macro_use] //! extern crate nom; //! //! #[derive(Debug,PartialEq)] //! pub struct Color { //! pub red: u8, //! pub green: u8, //! pub blue: u8, //! } //! //! fn from_hex(input: &str) -> Result { //! u8::from_str_radix(input, 16) //! } //! //! fn is_hex_digit(c: char) -> bool { //! c.is_digit(16) //! } //! //! named!(hex_primary<&str, u8>, //! map_res!(take_while_m_n!(2, 2, is_hex_digit), from_hex) //! ); //! //! named!(hex_color<&str, Color>, //! do_parse!( //! tag!("#") >> //! red: hex_primary >> //! green: hex_primary >> //! blue: hex_primary >> //! (Color { red, green, blue }) //! ) //! ); //! //! fn main() { //! assert_eq!(hex_color("#2F14DF"), Ok(("", Color { //! red: 47, //! green: 20, //! blue: 223, //! }))); //! } //! ``` //! //! 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](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), //! or the [error management system](https://github.com/Geal/nom/blob/master/doc/error_management.md). //! //! **Looking for a specific combinator? Read the //! ["choose a combinator" guide](https://github.com/Geal/nom/blob/master/doc/choosing_a_combinator.md)** //! //! If you are upgrading to nom 2.0, please read the //! [migration document](https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_2.md). //! //! If you are upgrading to nom 4.0, please read the //! [migration document](https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_4.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 //! software like [lex](https://en.wikipedia.org/wiki/Lex_(software)) and //! [yacc](https://en.wikipedia.org/wiki/Yacc). Instead of writing the grammar //! in a separate file and generating the corresponding code, you use very small //! functions with very specific purpose, like "take 5 bytes", or "recognize the //! word 'HTTP'", and assemble then in meaningful patterns like "recognize //! 'HTTP', then a space, then a version". //! The resulting code is small, and looks like the grammar you would have //! written with other parser approaches. //! //! This has a few advantages: //! //! - the parsers are small and easy to write //! - the parsers components are easy to reuse (if they're general enough, please add them to nom!) //! - the parsers components are easy to test separately (unit tests and property-based tests) //! - the parser combination code looks close to the grammar you would have written //! - you can build partial parsers, specific to the data you need at the moment, and ignore the rest //! //! Here is an example of one such parser, to recognize text between parentheses: //! //! ```rust //! #[macro_use] //! extern crate nom; //! //! # fn main() { //! named!(parens, delimited!(char!('('), is_not!(")"), char!(')'))); //! # } //! ``` //! //! It defines a function named `parens`, which will recognize a sequence of the character `(`, the longest byte array not containing `)`, then the character `)`, and will return the byte array in the middle. //! //! Here is another parser, written without using nom's macros this time: //! //! ```rust //! #[macro_use] //! extern crate nom; //! //! use nom::{IResult,Err,Needed}; //! //! # fn main() { //! fn take4(i:&[u8]) -> IResult<&[u8], &[u8]>{ //! if i.len() < 4 { //! Err(Err::Incomplete(Needed::Size(4))) //! } else { //! Ok((&i[4..],&i[0..4])) //! } //! } //! # } //! ``` //! //! 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 macros to help in //! developing parsers. //! //! With macros, you would write it like this: //! //! ```rust //! #[macro_use] //! extern crate nom; //! //! # fn main() { //! named!(take4, take!(4)); //! # } //! ``` //! //! 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: //! //! ```rust,ignore //! fn parser(input: I) -> IResult; //! ``` //! //! Or like this, if you don't want to specify a custom error type (it will be `u32` by default): //! //! ```rust,ignore //! fn parser(input: I) -> IResult; //! ``` //! //! `IResult` is an alias for the `Result` type: //! //! ```rust //! use nom::{Needed, Context}; //! //! type IResult = Result<(I, O), Err>; //! //! enum Err { //! Incomplete(Needed), //! Error(Context), //! Failure(Context), //! } //! ``` //! //! It can have the following values: //! //! - a correct result `Ok((I,O))` with the first element being the remaining of the input (not parsed yet), and the second the output value; //! - an error `Err(Err::Error(c))` with `c` an enum that contains an error code with its position in the input, and optionally a chain of accumulated errors; //! - an error `Err(Err::Incomplete(Needed))` indicating that more input is necessary. `Needed` can indicate how much data is needed //! - an error `Err(Err::Failure(c))`. It works like the `Error` case, except it indicates an unrecoverable error: we cannot backtrack and test another parser //! //! Please refer to the [documentation][doc] for an exhaustive list of parsers. See also the //! ["choose a combinator" guide](https://github.com/Geal/nom/blob/master/doc/choosing_a_combinator.md)**. //! //! ## Making new parsers with macros //! //! Macros are the main way to make new parsers by combining other ones. Those macros accept other macros or function names as arguments. You then need to make a function out of that combinator with **`named!`**, or a closure with **`closure!`**. Here is how you would do, with the **`tag!`** and **`take!`** combinators: //! //! ```rust //! # #[macro_use] extern crate nom; //! # fn main() { //! named!(abcd_parser, tag!("abcd")); // will consume bytes if the input begins with "abcd" //! //! named!(take_10, take!(10)); // will consume and return 10 bytes of input //! # } //! ``` //! //! The **`named!`** macro can take three different syntaxes: //! //! ```rust,ignore //! named!(my_function( &[u8] ) -> &[u8], tag!("abcd")); //! //! named!(my_function<&[u8], &[u8]>, tag!("abcd")); //! //! named!(my_function, tag!("abcd")); // when you know the parser takes &[u8] as input, and returns &[u8] as output //! ``` //! //! **IMPORTANT NOTE**: Rust's macros can be very sensitive to the syntax, so you may encounter an error compiling parsers like this one: //! //! ```rust //! # #[macro_use] extern crate nom; //! # #[cfg(feature = "alloc")] //! # fn main() { //! named!(my_function<&[u8], Vec<&[u8]>>, many0!(tag!("abcd"))); //! # } //! //! # #[cfg(not(feature = "alloc"))] //! # fn main() {} //! ``` //! //! You will get the following error: `error: expected an item keyword`. This //! happens because `>>` is seen as an operator, so the macro parser does not //! recognize what we want. There is a way to avoid it, by inserting a space: //! //! ```rust //! # #[macro_use] extern crate nom; //! # #[cfg(feature = "alloc")] //! # fn main() { //! named!(my_function<&[u8], Vec<&[u8]> >, many0!(tag!("abcd"))); //! # } //! # #[cfg(not(feature = "alloc"))] //! # fn main() {} //! ``` //! //! This will compile correctly. I am very sorry for this inconvenience. //! //! ## Combining parsers //! //! There are more high level patterns, like the **`alt!`** combinator, which provides a choice between multiple parsers. If one branch fails, it tries the next, and returns the result of the first parser that succeeds: //! //! ```rust //! # #[macro_use] extern crate nom; //! # fn main() { //! named!(alt_tags, alt!(tag!("abcd") | tag!("efgh"))); //! //! assert_eq!(alt_tags(b"abcdxxx"), Ok((&b"xxx"[..], &b"abcd"[..]))); //! assert_eq!(alt_tags(b"efghxxx"), Ok((&b"xxx"[..], &b"efgh"[..]))); //! assert_eq!(alt_tags(b"ijklxxx"), Err(nom::Err::Error(error_position!(&b"ijklxxx"[..], nom::ErrorKind::Alt)))); //! # } //! ``` //! //! The pipe `|` character is used as separator. //! //! The **`opt!`** combinator makes a parser optional. If the child parser returns an error, **`opt!`** will succeed and return None: //! //! ```rust //! # #[macro_use] extern crate nom; //! # fn main() { //! named!( abcd_opt< &[u8], Option<&[u8]> >, opt!( tag!("abcd") ) ); //! //! assert_eq!(abcd_opt(b"abcdxxx"), Ok((&b"xxx"[..], Some(&b"abcd"[..])))); //! assert_eq!(abcd_opt(b"efghxxx"), Ok((&b"efghxxx"[..], None))); //! # } //! ``` //! //! **`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 std::str; //! //! named!(multi< Vec<&str> >, many0!( map_res!(tag!( "abcd" ), str::from_utf8) ) ); //! let a = b"abcdef"; //! let b = b"abcdabcdef"; //! let c = b"azerty"; //! assert_eq!(multi(a), Ok((&b"ef"[..], vec!["abcd"]))); //! assert_eq!(multi(b), Ok((&b"ef"[..], vec!["abcd", "abcd"]))); //! assert_eq!(multi(c), Ok((&b"azerty"[..], Vec::new()))); //! # } //! # #[cfg(not(feature = "alloc"))] //! # fn main() {} //! ``` //! //! Here are some basic combining macros available: //! //! - **`opt!`**: will make the parser optional (if it returns the `O` type, the new parser returns `Option`) //! - **`many0!`**: will apply the parser 0 or more times (if it returns the `O` type, the new parser returns `Vec`) //! - **`many1!`**: will apply the parser 1 or more times //! //! There are more complex (and more useful) parsers like `do_parse!` and `tuple!`, which are used to apply a series of parsers then assemble their results. //! //! Example with `tuple!`: //! //! ```rust //! # #[macro_use] extern crate nom; //! # fn main() { //! use nom::{ErrorKind, Needed,be_u16}; //! //! named!(tpl<&[u8], (u16, &[u8], &[u8]) >, //! tuple!( //! be_u16 , //! take!(3), //! tag!("fg") //! ) //! ); //! //! assert_eq!( //! tpl(&b"abcdefgh"[..]), //! Ok(( //! &b"h"[..], //! (0x6162u16, &b"cde"[..], &b"fg"[..]) //! )) //! ); //! assert_eq!(tpl(&b"abcde"[..]), Err(nom::Err::Incomplete(Needed::Size(2)))); //! let input = &b"abcdejk"[..]; //! assert_eq!(tpl(input), Err(nom::Err::Error(error_position!(&input[5..], ErrorKind::Tag)))); //! # } //! ``` //! //! Example with `do_parse!`: //! //! ```rust //! # #[macro_use] extern crate nom; //! # fn main() { //! use nom::IResult; //! //! #[derive(Debug, PartialEq)] //! struct A { //! a: u8, //! b: u8 //! } //! //! fn ret_int1(i:&[u8]) -> IResult<&[u8], u8> { Ok((i,1)) } //! fn ret_int2(i:&[u8]) -> IResult<&[u8], u8> { Ok((i,2)) } //! //! named!(f<&[u8],A>, //! do_parse!( // the parser takes a byte array as input, and returns an A struct //! tag!("abcd") >> // begins with "abcd" //! opt!(tag!("abcd")) >> // this is an optional parser //! aa: ret_int1 >> // the return value of ret_int1, if it does not fail, will be stored in aa //! tag!("efgh") >> //! bb: ret_int2 >> //! tag!("efgh") >> //! //! (A{a: aa, b: bb}) // the final tuple will be able to use the variable defined previously //! ) //! ); //! //! let r = f(b"abcdabcdefghefghX"); //! assert_eq!(r, Ok((&b"X"[..], A{a: 1, b: 2}))); //! //! let r2 = f(b"abcdefghefghX"); //! assert_eq!(r2, Ok((&b"X"[..], A{a: 1, b: 2}))); //! # } //! ``` //! //! The double right arrow `>>` is used as separator between every parser in the sequence, and the last closure can see the variables storing the result of parsers. Unless the specified return type is already a tuple, the final line should be that type wrapped in a tuple. //! //! More examples of [`do_parse!`](macro.do_parse.html) and [`tuple!`](macro.tuple.html) usage can be found in the [INI file parser example](tests/ini.rs). //! //! **Going further:** read the [guides](https://github.com/Geal/nom/tree/master/doc)! #![cfg_attr(all(not(feature = "std"), feature = "alloc"), feature(alloc))] #![cfg_attr(not(feature = "std"), no_std)] //#![warn(missing_docs)] #![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))] #![cfg_attr(nightly, feature(test))] #[cfg(all(not(feature = "std"), feature = "alloc"))] #[macro_use] extern crate alloc; #[cfg(feature = "regexp_macros")] #[macro_use] extern crate lazy_static; extern crate memchr; #[cfg(feature = "regexp")] pub extern crate regex; #[cfg(nightly)] extern crate test; /// Lib module to re-export everything needed from `std` or `core`/`alloc`. This is how `serde` does /// it, albeit there it is not public. 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"))] pub mod std { #[cfg(feature = "alloc")] #[cfg_attr(feature = "alloc", macro_use)] pub use alloc::{boxed, string, vec}; pub use core::{cmp, convert, fmt, iter, mem, ops, option, result, slice, str}; pub mod prelude { pub use core::prelude as v1; } } #[cfg(feature = "std")] pub mod std { pub use std::{boxed, cmp, collections, convert, fmt, hash, iter, mem, ops, option, result, slice, str, string, vec}; pub mod prelude { pub use std::prelude as v1; } } #[cfg(feature = "regexp")] pub use regex; } pub use self::traits::*; pub use self::util::*; #[cfg(feature = "verbose-errors")] pub use self::verbose_errors::*; #[cfg(not(feature = "verbose-errors"))] pub use self::simple_errors::*; pub use self::branch::*; pub use self::internal::*; pub use self::macros::*; pub use self::methods::*; pub use self::multi::*; pub use self::sequence::*; pub use self::bits::*; pub use self::bytes::*; pub use self::character::*; pub use self::nom::*; pub use self::whitespace::*; #[cfg(feature = "regexp")] pub use self::regexp::*; pub use self::str::*; #[macro_use] mod util; #[cfg(feature = "verbose-errors")] #[macro_use] pub mod verbose_errors; #[cfg(not(feature = "verbose-errors"))] #[macro_use] pub mod simple_errors; #[macro_use] mod internal; mod traits; #[macro_use] mod macros; #[macro_use] mod branch; #[macro_use] mod sequence; #[macro_use] mod multi; #[macro_use] pub mod methods; #[macro_use] mod bytes; #[macro_use] pub mod bits; #[macro_use] mod character; #[macro_use] mod nom; #[macro_use] pub mod whitespace; #[cfg(feature = "regexp")] #[macro_use] mod regexp; mod str; pub mod types; nom-4.2.3/src/macros.rs010064400007670000024000001512661344000023700131570ustar0000000000000000//! 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)] /// Wraps a parser in a closure #[macro_export(local_inner_macros)] macro_rules! closure ( ($ty:ty, $submac:ident!( $($args:tt)* )) => ( |i: $ty| { $submac!(i, $($args)*) } ); ($submac:ident!( $($args:tt)* )) => ( |i| { $submac!(i, $($args)*) } ); ); /// Makes a function from a parser combination /// /// The type can be set up if the compiler needs /// more information /// /// ```ignore /// named!(my_function( &[u8] ) -> &[u8], tag!("abcd")); /// // first type parameter is input, second is output /// named!(my_function<&[u8], &[u8]>, tag!("abcd")); /// // will have &[u8] as input type, &[u8] as output type /// named!(my_function, tag!("abcd")); /// // will use &[u8] as input type (use this if the compiler /// // complains about lifetime issues /// named!(my_function<&[u8]>, tag!("abcd")); /// // prefix them with 'pub' to make the functions public /// named!(pub my_function, tag!("abcd")); /// // prefix them with 'pub(crate)' to make the functions public within the crate /// named!(pub(crate) my_function, tag!("abcd")); /// ``` #[macro_export(local_inner_macros)] macro_rules! named ( (#$($args:tt)*) => ( named_attr!(#$($args)*); ); ($name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( fn $name( i: $i ) -> $crate::IResult<$i,$o,u32> { $submac!(i, $($args)*) } ); ($name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { $submac!(i, $($args)*) } ); ($name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { $submac!(i, $($args)*) } ); ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, u32> { $submac!(i, $($args)*) } ); ($name:ident, $submac:ident!( $($args:tt)* )) => ( fn $name( i: &[u8] ) -> $crate::IResult<&[u8], &[u8], u32> { $submac!(i, $($args)*) } ); (pub $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( pub fn $name( i: $i ) -> $crate::IResult<$i,$o, u32> { $submac!(i, $($args)*) } ); (pub $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( pub fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { $submac!(i, $($args)*) } ); (pub $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( pub fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { $submac!(i, $($args)*) } ); (pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( pub fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, u32> { $submac!(i, $($args)*) } ); (pub $name:ident, $submac:ident!( $($args:tt)* )) => ( pub fn $name( i: &[u8] ) -> $crate::IResult<&[u8], &[u8], u32> { $submac!(i, $($args)*) } ); (pub(crate) $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub(crate) fn $name( i: $i ) -> $crate::IResult<$i,$o, u32> { $submac!(i, $($args)*) } ); (pub(crate) $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub(crate) fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { $submac!(i, $($args)*) } ); (pub(crate) $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub(crate) fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { $submac!(i, $($args)*) } ); (pub(crate) $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub(crate) fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, u32> { $submac!(i, $($args)*) } ); (pub(crate) $name:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub(crate) fn $name<'a>( i: &'a [u8] ) -> $crate::IResult<&[u8], &[u8], u32> { $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 { (pub $func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { pub fn $func_name(input: &[u8], $( $arg : $typ ),*) -> $crate::IResult<&[u8], $return_type> { $submac!(input, $($args)*) } }; (pub $func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { pub 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)*) } }; (pub(crate) $func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { pub(crate) fn $func_name(input: &[u8], $( $arg : $typ ),*) -> $crate::IResult<&[u8], $return_type> { $submac!(input, $($args)*) } }; (pub(crate) $func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { pub(crate) 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)*) } }; ($func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { fn $func_name(input: &[u8], $( $arg : $typ ),*) -> $crate::IResult<&[u8], $return_type> { $submac!(input, $($args)*) } }; ($func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { 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)*) } }; (pub $func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $input_type:ty, $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { pub fn $func_name(input: $input_type, $( $arg : $typ ),*) -> $crate::IResult<$input_type, $return_type> { $submac!(input, $($args)*) } }; ($func_name:ident ( $( $arg:ident : $typ:ty ),* ) < $input_type:ty, $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { fn $func_name(input: $input_type, $( $arg : $typ ),*) -> $crate::IResult<$input_type, $return_type> { $submac!(input, $($args)*) } }; (pub $func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $input_type:ty, $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { pub fn $func_name<'a>( input: $input_type, $( $arg : $typ ),*) -> $crate::IResult<$input_type, $return_type> { $submac!(input, $($args)*) } }; ($func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $input_type:ty, $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => { 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. /// /// ```ignore /// // Create my_function as if you wrote it with the doc comment /// My Func /// named_attr!(#[doc = "My Func"], my_function( &[u8] ) -> &[u8], tag!("abcd")); /// // Also works for pub functions, and multiple lines /// named!(#[doc = "My Func\nRecognise abcd"], pub my_function, tag!("abcd")); /// // Multiple attributes can be passed if required /// named!(#[doc = "My Func"] #[inline(always)], pub my_function, tag!("abcd")); /// ``` #[macro_export(local_inner_macros)] macro_rules! named_attr ( ($(#[$attr:meta])*, $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* fn $name( i: $i ) -> $crate::IResult<$i,$o,u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* fn $name<'a>( i: &'a[u8] ) -> $crate::IResult<&'a [u8], $o, u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, $name:ident, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* fn $name( i: &[u8] ) -> $crate::IResult<&[u8], &[u8], u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub fn $name( i: $i ) -> $crate::IResult<$i,$o, u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub $name:ident, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub fn $name<'a>( i: &'a [u8] ) -> $crate::IResult<&[u8], &[u8], u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub(crate) $name:ident( $i:ty ) -> $o:ty, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub(crate) fn $name( i: $i ) -> $crate::IResult<$i,$o, u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub(crate) $name:ident<$i:ty,$o:ty,$e:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub(crate) fn $name( i: $i ) -> $crate::IResult<$i, $o, $e> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub(crate) $name:ident<$i:ty,$o:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub(crate) fn $name( i: $i ) -> $crate::IResult<$i, $o, u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub(crate) $name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub(crate) fn $name( i: &[u8] ) -> $crate::IResult<&[u8], $o, u32> { $submac!(i, $($args)*) } ); ($(#[$attr:meta])*, pub(crate) $name:ident, $submac:ident!( $($args:tt)* )) => ( $(#[$attr])* pub(crate) fn $name<'a>( i: &'a [u8] ) -> $crate::IResult<&[u8], &[u8], u32> { $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),* ) ); ); /// emulate function currying: `apply!(my_function, arg1, arg2, ...)` becomes `my_function(input, arg1, arg2, ...)` /// /// ``` /// # #[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, apply!(take_wrapper, 2)); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! apply ( ($i:expr, $fun:expr, $($args:expr),* ) => ( $fun( $i, $($args),* ) ); ); /// 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::ErrorKind; /// # fn main() { /// named!(err_test<&[u8],&[u8],u32>, alt!( /// tag!("abcd") | /// preceded!(tag!("efgh"), return_error!(ErrorKind::Custom(42u32), /// do_parse!( /// tag!("ijkl") >> /// res: return_error!(ErrorKind::Custom(128), 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::Custom(42), error_position!(blah, ErrorKind::Tag))))); /// assert_eq!(res_b, Err(Err::Failure(error_node_position!(&b"ijklblah"[..], ErrorKind::Custom(42), /// error_node_position!(blah, ErrorKind::Custom(128), 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::{Context,Err}; let i_ = $i.clone(); let cl = || { $submac!(i_, $($args)*) }; fn unify_types(_: &Context, _: &Context) {} match cl() { Err(Err::Incomplete(x)) => Err(Err::Incomplete(x)), Ok((i, o)) => Ok((i, o)), Err(Err::Error(e)) | Err(Err::Failure(e)) => { unify_types(&e, &Context::Code($i, $code)); return Err(Err::Failure(error_node_position!($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::{Context,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)); ); ); /// Add an error if the child parser fails /// /// While 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::ErrorKind; /// # fn main() { /// named!(err_test, add_return_error!(ErrorKind::Custom(42u32), tag!("abcd"))); /// /// let a = &b"efghblah"[..]; /// let res_a = err_test(a); /// assert_eq!(res_a, Err(Err::Error(error_node_position!(a, ErrorKind::Custom(42), 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,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::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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind}; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Err(Err::Incomplete(_)) => { Err(Err::Error(error_position!($i, ErrorKind::Complete::))) }, rest => rest } } ); ($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::ErrorKind; /// # use nom::IResult; /// /// fn take_add(input:&[u8], size: u8) -> IResult<&[u8],&[u8]> { /// let (i1, sz) = try_parse!(input, nom::be_u8); /// let (i2, length) = try_parse!(i1, expr_opt!(size.checked_add(sz))); /// let (i3, data) = try_parse!(i2, take!(length)); /// return Ok((i3, 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!(&[2,3,4,5][..], ErrorKind::ExprOpt)))); /// # } /// ``` #[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, O -> P) => I -> IResult` /// maps a function on the result of a parser #[macro_export(local_inner_macros)] macro_rules! map( // Internal parser, do not use directly (__impl $i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( { pub fn _unify R>(f: F, t: T) -> R { f(t) } ($submac!($i, $($args)*)).map(|(i,o)| { (i, _unify($g, o)) }) } ); ($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, O -> Result

) => I -> IResult` /// maps a function returning a Result on the output of a parser #[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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Ok((i,o)) => { match $submac2!(o, $($args2)*) { Ok(output) => Ok((i, output)), Err(_) => { let e = $crate::ErrorKind::MapRes; Err(Err::Error(error_position!($i, e))) }, } }, Err(e) => Err(e), } } ); ($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_res_err!(I -> IResult, O -> Result

) => I -> IResult` /// maps a function returning a Result on the output of a parser, preserving the returned error #[macro_export(local_inner_macros)] macro_rules! map_res_err ( // Internal parser, do not use directly (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Context, Convert, Err}; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Ok((i,o)) => { match $submac2!(o, $($args2)*) { Ok(output) => Ok((i, output)), Err(e) => { let e = Context::convert(Context::Code($i, $crate::ErrorKind::Custom(e))); Err(Err::Error(error_node_position!($i, $crate::ErrorKind::MapRes, e))) }, } }, Err(e) => Err(e), } } ); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( map_res_err!(__impl $i, $submac!($($args)*), call!($g)); ); ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( map_res_err!(__impl $i, $submac!($($args)*), $submac2!($($args2)*)); ); ($i:expr, $f:expr, $g:expr) => ( map_res_err!(__impl $i, call!($f), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( map_res_err!(__impl $i, call!($f), $submac!($($args)*)); ); ); /// `map_opt!(I -> IResult, O -> Option

) => I -> IResult` /// maps a function returning an Option on the output of a parser #[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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Err,ErrorKind}; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Ok((i, o)) => match $submac2!(o, $($args2)*) { Some(output) => Ok((i, output)), None => { let e = ErrorKind::MapOpt; Err(Err::Error(error_position!($i, e))) } }, Err(e) => Err(e) } } ); ($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` /// uses the `parse` method from `std::str::FromStr` to convert the current /// input to the specified type /// /// this will completely consume the input #[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,ErrorKind,Context}; 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(Context::Code($i, ErrorKind::ParseTo::))) } } ); ); /// `verify!(I -> IResult, O -> bool) => I -> IResult` /// returns the result of the child parser if it satisfies a verification function /// /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(check, verify!(nom::be_u32, |val:u32| val >= 0 && val < 3)); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! verify ( // Internal parser, do not use directly (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind}; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Err(e) => Err(e), Ok((i, o)) => if $submac2!(o, $($args2)*) { Ok((i, o)) } else { Err(Err::Error(error_position!($i, ErrorKind::Verify))) } } } ); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( verify!(__impl $i, $submac!($($args)*), call!($g)); ); ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( verify!(__impl $i, $submac!($($args)*), $submac2!($($args2)*)); ); ($i:expr, $f:expr, $g:expr) => ( verify!(__impl $i, call!($f), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( verify!(__impl $i, call!($f), $submac!($($args)*)); ); ); /// `value!(T, R -> IResult ) => R -> IResult` /// /// or `value!(T) => R -> IResult` /// /// 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, value!(42, delimited!(tag!("")))); /// named!(y, delimited!(tag!(""))); /// let r = x(&b" 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)* )) => ( { use $crate::lib::std::result::Result::*; match $submac!($i, $($args)*) { Ok((i,_)) => { Ok((i, $res)) }, Err(e) => Err(e), } } ); ($i:expr, $res:expr, $f:expr) => ( value!($i, $res, call!($f)) ); ($i:expr, $res:expr) => ( { let res: $crate::IResult<_,_> = Ok(($i, $res)); res } ); ); /// `expr_res!(Result) => I -> IResult` /// evaluate an expression that returns a Result and returns a Ok((I,T)) if Ok /// /// See expr_opt for an example #[macro_export(local_inner_macros)] macro_rules! expr_res ( ($i:expr, $e:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind}; match $e { Ok(output) => Ok(($i, output)), Err(_) => Err(Err::Error(error_position!($i, ErrorKind::ExprRes::))) } } ); ); /// `expr_opt!(Option) => I -> IResult` /// evaluate an expression that returns a Option and returns a Ok((I,T)) if Some /// /// Useful when doing computations in a chain /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::Err; /// # use nom::IResult; /// # use nom::{be_u8,ErrorKind}; /// /// fn take_add(input:&[u8], size: u8) -> IResult<&[u8],&[u8]> { /// do_parse!(input, /// sz: be_u8 >> /// length: expr_opt!(size.checked_add(sz)) >> // checking for integer overflow (returns an Option) /// data: take!(length) >> /// (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!(&[2,3,4,5][..], ErrorKind::ExprOpt)))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! expr_opt ( ($i:expr, $e:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind}; match $e { $crate::lib::std::option::Option::Some(output) => Ok(($i, output)), $crate::lib::std::option::Option::None => Err(Err::Error(error_position!($i, ErrorKind::ExprOpt::))) } } ); ); /// `opt!(I -> IResult) => I -> IResult>` /// 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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::Err; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Ok((i,o)) => Ok((i, Some(o))), Err(Err::Error(_)) => Ok(($i, None)), Err(e) => Err(e), } } ); ($i:expr, $f:expr) => ( opt!($i, call!($f)); ); ); /// `opt_res!(I -> IResult) => I -> IResult>` /// make the underlying parser optional /// /// returns a Result, with Err containing the parsing error /// /// ```ignore /// # #[macro_use] extern crate nom; /// # #[cfg(feature = "verbose-errors")] /// # use nom::Err::Position; /// # 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_with_error!(bool, I -> IResult) => I -> IResult>` /// 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() { /// let b = true; /// let f: Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], /// cond!( b, tag!("abcd") )) /// ); /// /// let a = b"abcdef"; /// assert_eq!(f(&a[..]), Ok((&b"ef"[..], Some(&b"abcd"[..])))); /// /// let b2 = false; /// let f2:Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], /// cond!( b2, tag!("abcd") )) /// ); /// assert_eq!(f2(&a[..]), Ok((&b"abcdef"[..], None))); /// # } /// ``` /// #[macro_export(local_inner_macros)] macro_rules! cond_with_error( ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; if $cond { match $submac!($i, $($args)*) { Ok((i,o)) => Ok((i, $crate::lib::std::option::Option::Some(o))), Err(e) => Err(e), } } else { let res: $crate::lib::std::result::Result<_,_> = Ok(($i, $crate::lib::std::option::Option::None)); res } } ); ($i:expr, $cond:expr, $f:expr) => ( cond_with_error!($i, $cond, call!($f)); ); ); /// `cond!(bool, I -> IResult) => I -> IResult>` /// 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() { /// let b = true; /// let f: Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], /// cond!( b, tag!("abcd") )) /// ); /// /// let a = b"abcdef"; /// assert_eq!(f(&a[..]), Ok((&b"ef"[..], Some(&b"abcd"[..])))); /// /// let b2 = false; /// let f2:Box IResult<&[u8],Option<&[u8]>>> = Box::new(closure!(&'static[u8], /// cond!( b2, tag!("abcd") )) /// ); /// assert_eq!(f2(&a[..]), Ok((&b"abcdef"[..], None))); /// # } /// ``` /// #[macro_export(local_inner_macros)] macro_rules! cond( ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::Err; if $cond { let i_ = $i.clone(); match $submac!(i_, $($args)*) { Ok((i,o)) => Ok((i, Some(o))), Err(Err::Error(_)) => { Ok(($i, None)) }, Err(e) => Err(e), } } else { Ok(($i, None)) } } ); ($i:expr, $cond:expr, $f:expr) => ( cond!($i, $cond, call!($f)); ); ); /// `cond_reduce!(bool, I -> IResult) => I -> IResult` /// Conditional combinator with error /// /// Wraps another parser and calls it if the /// condition is met. This combinator returns /// an error if the condition is false /// /// 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::{Err,ErrorKind,IResult}; /// # fn main() { /// let b = true; /// let f = closure!(&'static[u8], /// cond_reduce!( b, tag!("abcd") ) /// ); /// /// let a = b"abcdef"; /// assert_eq!(f(&a[..]), Ok((&b"ef"[..], &b"abcd"[..]))); /// /// let b2 = false; /// let f2 = closure!(&'static[u8], /// cond_reduce!( b2, tag!("abcd") ) /// ); /// assert_eq!(f2(&a[..]), Err(Err::Error(error_position!(&a[..], ErrorKind::CondReduce)))); /// # } /// ``` /// #[macro_export(local_inner_macros)] macro_rules! cond_reduce( ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Convert,Err,ErrorKind,IResult}; let default_err = Err(Err::convert(Err::Error(error_position!($i, ErrorKind::CondReduce::)))); if $cond { let sub_res = $submac!($i, $($args)*); fn unify_types(_: &IResult, _: &IResult) {} unify_types(&sub_res, &default_err); match sub_res { Ok((i,o)) => Ok((i, o)), Err(e) => Err(e), } } else { default_err } } ); ($i:expr, $cond:expr, $f:expr) => ( cond_reduce!($i, $cond, call!($f)); ); ); /// `peek!(I -> IResult) => I -> IResult` /// 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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Convert,Err}; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Ok((_,o)) => Ok(($i, o)), Err(e) => Err(Err::convert(e)), } } ); ($i:expr, $f:expr) => ( peek!($i, call!($f)); ); ); /// `not!(I -> IResult) => I -> IResult` /// 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::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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Context,ErrorKind,Err,IResult}; let i_ = $i.clone(); //we need this to avoid type inference errors fn unify_types(_: &IResult, _: &IResult) {} match $submac!(i_, $($args)*) { Err(Err::Failure(e)) => Err(Err::Failure(e)), Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)), Err(_) => Ok(($i, ())), Ok(_) => { let c = Context::Code($i, ErrorKind::Not); let err = Err(Err::Error(c)); let default = Ok(($i, ())); unify_types(&err, &default); err }, } } ); ($i:expr, $f:expr) => ( not!($i, call!($f)); ); ); /// `tap!(name: I -> IResult => { block }) => I -> IResult` /// 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::{Convert,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 /// /// This combinator works with the `AtEof` trait that input types must implement. /// If an input type's `at_eof` method returns true, it means there will be no /// more refills (like what happens when buffering big files). /// /// When we're at the end of the data and `at_eof` returns true, this combinator /// will succeed /// /// TODO: example #[macro_export(local_inner_macros)] macro_rules! eof ( ($i:expr,) => ( { use $crate::lib::std::result::Result::*; use $crate::{AtEof,Err,ErrorKind}; use $crate::InputLength; if ($i).at_eof() && ($i).input_len() == 0 { Ok(($i, $i)) } else { //FIXME what do we do with need_more? Err(Err::Error(error_position!($i, ErrorKind::Eof::))) } } ); ); /// `exact!()` will fail if the child parser does not consume the whole data /// /// This combinator works with the `AtEof` trait that input types must implement. /// If an input type's `at_eof` method returns true, it means there will be no /// more refills (like what happens when buffering big files). /// /// 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 -> IResult` /// 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!("")))); /// let r = x(&b" aaa"[..]); /// assert_eq!(r, Ok((&b" aaa"[..], &b""[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! recognize ( ($i:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::Offset; use $crate::Slice; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Ok((i,_)) => { let index = (&$i).offset(&i); Ok((i, ($i).slice(..index))) }, Err(e) => Err(e) } } ); ($i:expr, $f:expr) => ( recognize!($i, call!($f)) ); ); #[cfg(test)] mod tests { use internal::{Err, IResult, Needed}; use util::ErrorKind; #[cfg(feature = "alloc")] use 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,ErrorKind}; use $crate::{Compare,CompareResult,InputLength,Slice,need_more}; let res: IResult<_,_> = match ($i).compare($tag) { CompareResult::Ok => { let blen = $tag.input_len(); Ok(($i.slice(blen..), $i.slice(..blen))) }, CompareResult::Incomplete => { need_more($i, Needed::Size($tag.input_len())) }, CompareResult::Error => { let e:ErrorKind = ErrorKind::Tag; Err(Err::Error($crate::Context::Code($i, e))) } }; res }); ); macro_rules! take( ($i:expr, $count:expr) => ( { let cnt = $count as usize; let res:IResult<&[u8],&[u8]> = if $i.len() < cnt { $crate::need_more($i, $crate::Needed::Size(cnt)) } 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 = apply!(1, sum2, 2); let b = apply!(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::Size(4)))); } #[cfg(feature = "verbose-errors")] #[test] fn opt_res() { named!(opt_res_abcd<&[u8], Result<&[u8], Err<&[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::Size(4)))); } #[cfg(not(feature = "verbose-errors"))] #[test] fn opt_res() { named!(opt_res_abcd<&[u8], Result<&[u8], Err<&[u8], u32>> >, 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::Size(4)))); } use lib::std::convert::From; #[derive(Debug, PartialEq)] pub struct CustomError(&'static str); impl From for CustomError { fn from(_: u32) -> Self { CustomError("test") } } #[test] #[cfg(feature = "alloc")] fn cond() { let f_true: Box IResult<&[u8], Option<&[u8]>, CustomError>> = Box::new(closure!( &'static [u8], fix_error!(CustomError, cond!(true, tag!("abcd"))) )); let f_false: Box IResult<&[u8], Option<&[u8]>, CustomError>> = Box::new(closure!( &'static [u8], fix_error!(CustomError, cond!(false, tag!("abcd"))) )); //let f_false = closure!(&'static [u8], 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::Size(4)))); assert_eq!(f_true(&b"xxx"[..]), Ok((&b"xxx"[..], None))); 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")); let f_true: Box IResult<&[u8], Option<&[u8]>, CustomError>> = Box::new(closure!( &'static [u8], fix_error!(CustomError, cond!(true, tag_abcd)) )); let f_false: Box IResult<&[u8], Option<&[u8]>, CustomError>> = Box::new(closure!( &'static [u8], fix_error!(CustomError, cond!(false, tag_abcd)) )); //let f_false = closure!(&'static [u8], cond!( b2, tag!("abcd") ) ); assert_eq!(f_true(&b"abcdef"[..]), Ok((&b"ef"[..], Some(&b"abcd"[..])))); assert_eq!(f_true(&b"ab"[..]), Err(Err::Incomplete(Needed::Size(4)))); assert_eq!(f_true(&b"xxx"[..]), Ok((&b"xxx"[..], None))); 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::Size(4)))); assert_eq!( peek_tag(&b"xxx"[..]), Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Tag))) ); } #[test] fn not() { use types::CompleteStr; 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::Size(3)))); assert_eq!(not_aaa(&b"abcd"[..]), Ok((&b"abcd"[..], ()))); named!(not_aaa_complete, not!(tag!("aaa"))); assert_eq!( not_aaa_complete(CompleteStr("aaa")), Err(Err::Error(error_position!( CompleteStr("aaa"), ErrorKind::Not ))) ); assert_eq!( not_aaa_complete(CompleteStr("aa")), Ok((CompleteStr("aa"), ())) ); assert_eq!( not_aaa_complete(CompleteStr("abcd")), Ok((CompleteStr("abcd"), ())) ); } #[test] fn verify() { named!(test, verify!(take!(5), |slice: &[u8]| slice[0] == b'a')); assert_eq!(test(&b"bcd"[..]), Err(Err::Incomplete(Needed::Size(5)))); 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() { use util::Convert; assert_eq!( parse_to!("ab", usize), Err(Err::Error(error_position!( "ab", ErrorKind::ParseTo ))) ); assert_eq!(parse_to!("42", usize), Ok(("", 42))); assert_eq!(ErrorKind::::convert(ErrorKind::ParseTo::), ErrorKind::ParseTo::); } #[test] fn map_res_err() { use Context; use be_u8; #[derive(Debug, Eq, PartialEq)] enum ParseError { InvalidValue(u8), } impl From for ParseError { fn from(_: u32) -> Self { unreachable!() } } #[derive(Debug, Eq, PartialEq)] enum ValidValue { One, Two, } fn validate(value: u8) -> Result { match value { b'1' => Ok(ValidValue::One), b'2' => Ok(ValidValue::Two), _ => Err(ParseError::InvalidValue(value)) } } named!(test<&[u8], ValidValue, ParseError>, map_res_err!(fix_error!(ParseError, be_u8), validate) ); assert_eq!(test(&b"1"[..]), Ok((&b""[..], ValidValue::One))); assert_eq!(test(&b"2"[..]), Ok((&b""[..], ValidValue::Two))); #[cfg(feature = "verbose-errors")] { assert_eq!( test(&b"3"[..]), Err( Err::Error( Context::List( vec![ (&b"3"[..], ErrorKind::Custom(ParseError::InvalidValue(b'3'))), (&b"3"[..], ErrorKind::MapRes) ] ) ) ) ); } #[cfg(not(feature = "verbose-errors"))] { assert_eq!(test(&b"3"[..]), Err(Err::Error(Context::Code(&b"3"[..], ErrorKind::MapRes)))); } } } nom-4.2.3/src/methods.rs010064400007670000024000000467541344000023700133430ustar0000000000000000//! Method macro combinators //! //! These macros make parsers as methods of structs //! and that can take methods of structs to call //! as parsers. //! //! 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 as methods in other combinators, are used //! like this: //! //! ```ignore //! method!(my_function >, self, tag!("abcd")); //! ``` //! //! Internally, other combinators will rewrite //! that call to pass the input as second argument: //! //! ```ignore //! macro_rules! method ( //! ($name:ident<$a:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( //! fn $name( $self_: $a, i: &[u8] ) -> IResult<&[u8], &[u8]> { //! $submac!(i, $($args)*) //! } //! ); //! ); //! ``` //! //! The `method!` macro is similar to the `named!` macro in the macros module. //! While `named!` will create a parser function, `method!` will create a parser //! method on the struct it is defined in. //! //! Compared to the `named!` macro there are a few differences in how they are //! invoked. A `method!` invocation always has to have the type of `self` //! declared and it can't be a reference due to Rust's borrow lifetime //! restrictions: //! //! ```ignore //! // -`self`'s type- //! method!(method_name< Parser<'a> >, ...); //! ``` //! `self`'s type always comes first. //! The next difference is you have to input the self struct. Due to Rust's //! macro hygiene the macro can't declare it on it's own. //! //! ```ignore //! // -self- //! method!(method_name, &'a str, &'a str>, self, ...); //! ``` //! When making a parsing struct with parsing methods, due to the static borrow //! checker,calling any parsing methods on self (or any other parsing struct) //! will cause self to be moved for the rest of the method.To get around this //! restriction all self is moved into the called method and then the called //! method will return self to the caller. //! //! To call a method on self you need to use the `call_m!` macro. For example: //! //! ```ignore //! struct<'a> Parser<'a> { //! parsed: &'a str, //! } //! impl<'a> Parser<'a> { //! // Constructor omitted for brevity //! method!(take4, &'a str, &'a str>, self, take!(4)); //! method!(caller, &'a str, &'a str>, self, call_m!(self.take4)); //! } //! ``` //! More complicated combinations still mostly look the same as their `named!` //! counterparts: //! //! ```ignore //! method!(pub simple_chain<&mut Parser<'a>, &'a str, &'a str>, self, //! do_parse!( //! call_m!(self.tag_abc) >> //! call_m!(self.tag_def) >> //! call_m!(self.tag_ghi) >> //! last: map!(call_m!(self.simple_peek), |parsed| sb.parsed = parsed) >> //! (last) //! ) //! ); //! ``` //! The three additions to method definitions to remember are: //! 1. Specify `self`'s type //! 2. Pass `self` to the macro //! 4. Call parser methods using the `call_m!` macro. /// Makes a method from a parser combination /// /// The must be set up because the compiler needs /// the information /// /// ```ignore /// method!(my_function >( &[u8] ) -> &[u8], tag!("abcd")); /// // first type parameter is `self`'s type, second is input, third is output /// method!(my_function, &[u8], &[u8]>, tag!("abcd")); /// //prefix them with 'pub' to make the methods public /// method!(pub my_function,&[u8], &[u8]>, tag!("abcd")); /// ``` #[deprecated(since = "4.2.0", note = "Please use the nom-methods crate instead")] #[macro_export(local_inner_macros)] macro_rules! method ( // Non-public immutable self ($name:ident<$a:ty>( $i:ty ) -> $o:ty, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ($name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ($name:ident<$a:ty,$i:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ($name:ident<$a:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], $o, u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ($name:ident<$a:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); // Public immutable self (pub $name:ident<$a:ty>( $i:ty ) -> $o:ty, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); (pub $name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { let result = $submac!(i, $($args)*); ($self_, result) } ); (pub $name:ident<$a:ty,$i:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( $self_: $a,i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); (pub $name:ident<$a:ty,$o:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], $o, u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); (pub $name:ident<$a:ty>, $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); // Non-public mutable self ($name:ident<$a:ty>( $i:ty ) -> $o:ty, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ($name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ($name:ident<$a:ty,$i:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ($name:ident<$a:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], $o, u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ($name:ident<$a:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); // Public mutable self (pub $name:ident<$a:ty>( $i:ty ) -> $o:ty, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); (pub $name:ident<$a:ty,$i:ty,$o:ty,$e:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( mut $self_: $a, i: $i ) -> ($a, $crate::IResult<$i, $o, $e>) { let result = $submac!(i, $($args)*); ($self_, result) } ); (pub $name:ident<$a:ty,$i:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( mut $self_: $a,i: $i ) -> ($a, $crate::IResult<$i,$o,u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); (pub $name:ident<$a:ty,$o:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], $o, u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); (pub $name:ident<$a:ty>, mut $self_:ident, $submac:ident!( $($args:tt)* )) => ( #[allow(unused_variables)] pub fn $name( mut $self_: $a, i: &[u8] ) -> ($a, $crate::IResult<&[u8], &[u8], u32>) { let result = $submac!(i, $($args)*); ($self_, result) } ); ); /// Used to called methods then move self back into self #[deprecated(since = "4.2.0", note = "Please use the nom-methods crate instead")] #[macro_export(local_inner_macros)] macro_rules! call_m ( ($i:expr, $self_:ident.$method:ident) => ( { let (tmp, res) = $self_.$method($i); $self_ = tmp; res } ); ($i:expr, $self_:ident.$method:ident, $($args:expr),* ) => ( { let (tmp, res) = $self_.$method($i, $($args),*); $self_ = tmp; res } ); ); /// emulate function currying for method calls on structs /// `apply_m!(self.my_function, arg1, arg2, ...)` becomes `self.my_function(input, arg1, arg2, ...)` /// /// Supports up to 6 arguments #[deprecated(since = "4.2.0", note = "Please use the nom-methods crate instead")] #[macro_export(local_inner_macros)] macro_rules! apply_m ( ($i:expr, $self_:ident.$method:ident, $($args:expr),* ) => ( { let (tmp, res) = $self_.$method( $i, $($args),* ); $self_ = tmp; res } ); ); #[cfg(test)] #[allow(deprecated)] mod tests { // reproduce the tag_s and take_s macros, because of module import order macro_rules! tag_s ( ($i:expr, $tag: expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,Needed,IResult, need_more}; let res: IResult<_,_> = if $tag.len() > $i.len() { need_more($i, Needed::Size($tag.len())) //} else if &$i[0..$tag.len()] == $tag { } else if ($i).starts_with($tag) { Ok((&$i[$tag.len()..], &$i[0..$tag.len()])) } else { Err(Err::Error(error_position!($i, ErrorKind::TagStr))) }; res } ); ); macro_rules! take_s ( ($i:expr, $count:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Needed,IResult,need_more}; let cnt = $count as usize; let res: IResult<_,_> = if $i.chars().count() < cnt { need_more($i, Needed::Size(cnt)) } else { let mut offset = $i.len(); let mut count = 0; for (o, _) in $i.char_indices() { if count == cnt { offset = o; break; } count += 1; } Ok((&$i[offset..], &$i[..offset])) }; res } ); ); struct Parser<'a> { bcd: &'a str, } impl<'a> Parser<'a> { pub fn new() -> Parser<'a> { Parser { bcd: "" } } method!( tag_abc, &'a str, &'a str>, self, tag_s!("áβç") ); method!(tag_bcd >(&'a str) -> &'a str, self, tag_s!("βçδ")); method!(pub tag_hij >(&'a str) -> &'a str, self, tag_s!("λïJ")); method!(pub tag_ijk, &'a str, &'a str>, self, tag_s!("ïJƙ")); method!(take3, &'a str, &'a str>, self, take_s!(3)); method!(pub simple_call, &'a str, &'a str>, mut self, call_m!(self.tag_abc) ); method!(pub simple_peek, &'a str, &'a str>, mut self, peek!(call_m!(self.take3)) ); method!(pub simple_chain, &'a str, &'a str>, mut self, do_parse!( map!(call_m!(self.tag_bcd), |bcd| self.bcd = bcd) >> last: call_m!(self.simple_peek) >> (last) ) ); fn tag_stuff(mut self: Parser<'a>, input: &'a str, something: &'a str) -> (Parser<'a>, ::IResult<&'a str, &'a str>) { self.bcd = something; let (tmp, res) = self.tag_abc(input); self = tmp; (self, res) } method!(use_apply, &'a str, &'a str>, mut self, apply_m!(self.tag_stuff, "βçδ")); } #[test] fn test_method_call_abc() { let p = Parser::new(); let input: &str = "áβçδèƒϱλïJƙ"; let consumed: &str = "áβç"; let leftover: &str = "δèƒϱλïJƙ"; let (_, res) = p.tag_abc(input); match res { Ok((extra, output)) => { assert!( extra == leftover, "`Parser.tag_abc` consumed leftover input. leftover: {}", extra ); assert!( output == consumed, "`Parser.tag_abc` doesnt return the string it consumed \ on success. Expected `{}`, got `{}`.", consumed, output ); } other => panic!( "`Parser.tag_abc` didn't succeed when it should have. \ Got `{:?}`.", other ), } } #[test] fn test_method_call_bcd() { let p = Parser::new(); let input: &str = "βçδèƒϱλïJƙ"; let consumed: &str = "βçδ"; let leftover: &str = "èƒϱλïJƙ"; let (_, res) = p.tag_bcd(input); match res { Ok((extra, output)) => { assert!( extra == leftover, "`Parser.tag_bcd` consumed leftover input. leftover: {}", extra ); assert!( output == consumed, "`Parser.tag_bcd` doesn't return the string it consumed \ on success. Expected `{}`, got `{}`.", consumed, output ); } other => panic!( "`Parser.tag_bcd` didn't succeed when it should have. \ Got `{:?}`.", other ), } } #[test] fn test_method_call_hij() { let p = Parser::new(); let input: &str = "λïJƙℓ₥ñôƥ9řƨ"; let consumed: &str = "λïJ"; let leftover: &str = "ƙℓ₥ñôƥ9řƨ"; let (_, res) = p.tag_hij(input); match res { Ok((extra, output)) => { assert!( extra == leftover, "`Parser.tag_hij` consumed leftover input. leftover: {}", extra ); assert!( output == consumed, "`Parser.tag_hij` doesn't return the string it consumed \ on success. Expected `{}`, got `{}`.", consumed, output ); } other => panic!( "`Parser.tag_hij` didn't succeed when it should have. \ Got `{:?}`.", other ), } } #[test] fn test_method_call_ijk() { let p = Parser::new(); let input: &str = "ïJƙℓ₥ñôƥ9řƨ"; let consumed: &str = "ïJƙ"; let leftover: &str = "ℓ₥ñôƥ9řƨ"; let (_, res) = p.tag_ijk(input); match res { Ok((extra, output)) => { assert!( extra == leftover, "`Parser.tag_ijk` consumed leftover input. leftover: {}", extra ); assert!( output == consumed, "`Parser.tag_ijk` doesn't return the string it consumed \ on success. Expected `{}`, got `{}`.", consumed, output ); } other => panic!( "`Parser.tag_ijk` didn't succeed when it should have. \ Got `{:?}`.", other ), } } #[test] fn test_method_simple_call() { let p = Parser::new(); let input: &str = "áβçδèƒϱλïJƙ"; let consumed: &str = "áβç"; let leftover: &str = "δèƒϱλïJƙ"; let (_, res) = p.simple_call(input); match res { Ok((extra, output)) => { assert!( extra == leftover, "`Parser.simple_call` consumed leftover input. leftover: {}", extra ); assert!( output == consumed, "`Parser.simple_call` doesn't return the string it consumed \ on success. Expected `{}`, got `{}`.", consumed, output ); } other => panic!( "`Parser.simple_call` didn't succeed when it should have. \ Got `{:?}`.", other ), } } #[test] fn test_apply_m() { let mut p = Parser::new(); let input: &str = "áβçδèƒϱλïJƙ"; let consumed: &str = "áβç"; let leftover: &str = "δèƒϱλïJƙ"; let (tmp, res) = p.use_apply(input); p = tmp; match res { Ok((extra, output)) => { assert!( extra == leftover, "`Parser.use_apply` consumed leftover input. leftover: {}", extra ); assert!( output == consumed, "`Parser.use_apply` doesn't return the string it was supposed to \ on success. Expected `{}`, got `{}`.", leftover, output ); assert!( p.bcd == "βçδ", "Parser.use_apply didn't modify the parser field correctly: {}", p.bcd ); } other => panic!( "`Parser.use_apply` didn't succeed when it should have. \ Got `{:?}`.", other ), } } #[test] fn test_method_call_peek() { let p = Parser::new(); let input: &str = "ж¥ƺáβçδèƒϱλïJƙ"; let consumed: &str = "ж¥ƺ"; let (_, res) = p.simple_peek(input); match res { Ok((extra, output)) => { assert!( extra == input, "`Parser.simple_peek` consumed leftover input. leftover: {}", extra ); assert!( output == consumed, "`Parser.simple_peek` doesn't return the string it consumed \ on success. Expected `{}`, got `{}`.", consumed, output ); } other => panic!( "`Parser.simple_peek` didn't succeed when it should have. \ Got `{:?}`.", other ), } } #[test] fn test_method_call_chain() { let mut p = Parser::new(); let input: &str = "βçδδèƒϱλïJƙℓ"; let leftover: &str = "δèƒϱλïJƙℓ"; let output: &str = "δèƒ"; let (tmp, res) = p.simple_chain(input); p = tmp; match res { Ok((extra, out)) => { assert!( extra == leftover, "`Parser.simple_chain` consumed leftover input. leftover: {}", extra ); assert!( out == output, "`Parser.simple_chain` doesn't return the string it was supposed to \ on success. Expected `{}`, got `{}`.", output, out ); assert!( p.bcd == "βçδ", "Parser.simple_chain didn't modify the parser field correctly: {}", p.bcd ); } other => panic!( "`Parser.simple_chain` didn't succeed when it should have. \ Got `{:?}`.", other ), } } } nom-4.2.3/src/multi.rs010064400007670000024000001563011344541017100130270ustar0000000000000000//! Parsers for applying parsers multiple times /// `separated_list!(I -> IResult, I -> IResult) => I -> IResult>` /// separated_list(sep, X) returns Vec will return Incomplete if there may be more elements #[cfg(feature = "alloc")] #[macro_export(local_inner_macros)] macro_rules! separated_list( ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; use $crate::InputLength; //FIXME: use crate vec let mut res = $crate::lib::std::vec::Vec::new(); let mut input = $i.clone(); // get the first element let input_ = input.clone(); match $submac!(input_, $($args2)*) { Err(Err::Error(_)) => Ok((input, res)), Err(e) => Err(e), Ok((i,o)) => { if i.input_len() == input.input_len() { Err(Err::Error(error_position!(input, $crate::ErrorKind::SeparatedList))) } else { res.push(o); input = i; let ret; loop { // get the separator first let input_ = input.clone(); match $sep!(input_, $($args)*) { Err(Err::Error(_)) => { ret = Ok((input, res)); break; } Err(e) => { ret = Err(e); break; }, Ok((i2,_)) => { let i2_len = i2.input_len(); if i2_len == input.input_len() { ret = Ok((input, res)); break; } // get the element next match $submac!(i2, $($args2)*) { Err(Err::Error(_)) => { ret = Ok((input, res)); break; }, Err(e) => { ret = Err(e); break; }, Ok((i3,o3)) => { if i3.input_len() == i2_len { ret = Ok((input, res)); break; } res.push(o3); input = i3; } } } } } ret } }, } } ); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( separated_list!($i, $submac!($($args)*), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( separated_list!($i, call!($f), $submac!($($args)*)); ); ($i:expr, $f:expr, $g:expr) => ( separated_list!($i, call!($f), call!($g)); ); ); /// `separated_nonempty_list!(I -> IResult, I -> IResult) => I -> IResult>` /// separated_nonempty_list(sep, X) returns Vec will return Incomplete if there may be more elements #[macro_export(local_inner_macros)] macro_rules! separated_nonempty_list( ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind}; use $crate::InputLength; let mut res = $crate::lib::std::vec::Vec::new(); let mut input = $i.clone(); // get the first element let input_ = input.clone(); match $submac!(input_, $($args2)*) { Err(e) => Err(e), Ok((i,o)) => { if i.input_len() == input.input_len() { let e = ErrorKind::SeparatedNonEmptyList; Err(Err::Error(error_position!(input, e))) } else { res.push(o); input = i; let ret; loop { // get the separator first let input_ = input.clone(); match $sep!(input_, $($args)*) { Err(Err::Error(_)) => { ret = Ok((input, res)); break; } Err(e) => { ret = Err(e); break; }, Ok((i2,_)) => { let i2_len = i2.input_len(); if i2_len == input.input_len() { ret = Ok((input, res)); break; } // get the element next match $submac!(i2, $($args2)*) { Err(Err::Error(_)) => { ret = Ok((input, res)); break; }, Err(e) => { ret = Err(e); break; }, Ok((i3,o3)) => { if i3.input_len() == i2_len { ret = Ok((input, res)); break; } res.push(o3); input = i3; } } } } } ret } }, } } ); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( separated_nonempty_list!($i, $submac!($($args)*), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( separated_nonempty_list!($i, call!($f), $submac!($($args)*)); ); ($i:expr, $f:expr, $g:expr) => ( separated_nonempty_list!($i, call!($f), call!($g)); ); ); /// `separated_list_complete!(I -> IResult, I -> IResult) => I -> IResult>` /// This is equivalent to the `separated_list!` combinator, except that it will return `Error` /// when either the separator or element subparser returns `Incomplete`. #[macro_export(local_inner_macros)] macro_rules! separated_list_complete { ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ({ separated_list!($i, complete!($sep!($($args)*)), complete!($submac!($($args2)*))) }); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( separated_list_complete!($i, $submac!($($args)*), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( separated_list_complete!($i, call!($f), $submac!($($args)*)); ); ($i:expr, $f:expr, $g:expr) => ( separated_list_complete!($i, call!($f), call!($g)); ); } /// `separated_nonempty_list_complete!(I -> IResult, I -> IResult) => I -> IResult>` /// This is equivalent to the `separated_nonempty_list!` combinator, except that it will return /// `Error` when either the separator or element subparser returns `Incomplete`. #[macro_export(local_inner_macros)] macro_rules! separated_nonempty_list_complete { ($i:expr, $sep:ident!( $($args:tt)* ), $submac:ident!( $($args2:tt)* )) => ({ separated_nonempty_list!($i, complete!($sep!($($args)*)), complete!($submac!($($args2)*))) }); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( separated_nonempty_list_complete!($i, $submac!($($args)*), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( separated_nonempty_list_complete!($i, call!($f), $submac!($($args)*)); ); ($i:expr, $f:expr, $g:expr) => ( separated_nonempty_list_complete!($i, call!($f), call!($g)); ); } /// `many0!(I -> IResult) => I -> IResult>` /// 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")] #[macro_export(local_inner_macros)] macro_rules! many0( ($i:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,AtEof}; let ret; let mut res = $crate::lib::std::vec::Vec::new(); let mut input = $i.clone(); loop { let input_ = input.clone(); match $submac!(input_, $($args)*) { Ok((i, o)) => { // loop trip must always consume (otherwise infinite loops) if i == input { if i.at_eof() { ret = Ok((input, res)); } else { ret = Err(Err::Error(error_position!(input, $crate::ErrorKind::Many0))); } break; } res.push(o); input = i; }, Err(Err::Error(_)) => { ret = Ok((input, res)); break; }, Err(e) => { ret = Err(e); break; }, } } ret } ); ($i:expr, $f:expr) => ( many0!($i, call!($f)); ); ); /// `many1!(I -> IResult) => I -> IResult>` /// 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::ErrorKind; /// # use nom::types::CompleteByteSlice; /// # 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::Many1)))); /// /// named!(multi_complete >, many1!( tag!( "abcd" ) ) ); /// let c = CompleteByteSlice(b"abcdabcd"); /// /// let res = vec![CompleteByteSlice(b"abcd"), CompleteByteSlice(b"abcd")]; /// assert_eq!(multi_complete(c), Ok((CompleteByteSlice(b""), res))); /// # } /// ``` #[cfg(feature = "alloc")] #[macro_export(local_inner_macros)] macro_rules! many1( ($i:expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; use $crate::InputLength; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Err(Err::Error(_)) => Err(Err::Error( error_position!(i_, $crate::ErrorKind::Many1) )), Err(Err::Failure(_)) => Err(Err::Failure( error_position!(i_, $crate::ErrorKind::Many1) )), Err(i) => Err(i), Ok((i1,o1)) => { let mut res = $crate::lib::std::vec::Vec::with_capacity(4); res.push(o1); let mut input = i1; let mut error = $crate::lib::std::option::Option::None; loop { let input_ = input.clone(); match $submac!(input_, $($args)*) { Err(Err::Error(_)) => { break; }, Err(e) => { error = $crate::lib::std::option::Option::Some(e); break; }, Ok((i, o)) => { if i.input_len() == input.input_len() { break; } res.push(o); input = i; } } } match error { $crate::lib::std::option::Option::Some(e) => Err(e), $crate::lib::std::option::Option::None => Ok((input, res)) } } } } ); ($i:expr, $f:expr) => ( many1!($i, call!($f)); ); ); /// `many_till!(I -> IResult, I -> IResult) => I -> IResult, 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::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")] #[macro_export(local_inner_macros)] macro_rules! many_till( (__impl $i:expr, $submac1:ident!( $($args1:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind}; let ret; let mut res = $crate::lib::std::vec::Vec::new(); let mut input = $i.clone(); loop { match $submac2!(input, $($args2)*) { Ok((i, o)) => { ret = Ok((i, (res, o))); break; }, Err(e1) => { match $submac1!(input, $($args1)*) { Err(Err::Error(err)) => { fn unify_types(_: &T, _: &T) {} let e = Err::Error(error_node_position!(input, ErrorKind::ManyTill, err)); unify_types(&e1, &e); ret = Err(e); break; }, Err(e) => { ret = Err(e); break; }, Ok((i, o)) => { // loop trip must always consume (otherwise infinite loops) if i == input { ret = Err(Err::Error(error_position!(input, $crate::ErrorKind::ManyTill))); break; } res.push(o); input = i; }, } }, } } ret } ); ($i:expr, $submac1:ident!( $($args1:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( many_till!(__impl $i, $submac1!($($args1)*), $submac2!($($args2)*)); ); ($i:expr, $submac1:ident!( $($args1:tt)* ), $g:expr) => ( many_till!(__impl $i, $submac1!($($args1)*), call!($g)); ); ($i:expr, $f:expr, $submac2:ident!( $($args2:tt)* )) => ( many_till!(__impl $i, call!($f), $submac2!($($args2)*)); ); ($i:expr, $f:expr, $g: expr) => ( many_till!(__impl $i, call!($f), call!($g)); ); ); /// `many_m_n!(usize, usize, I -> IResult) => I -> IResult>` /// 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::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!(&a[..], ErrorKind::ManyMN)))); /// 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")] #[macro_export(local_inner_macros)] macro_rules! many_m_n( ($i:expr, $m:expr, $n: expr, $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Context,Err,Needed}; use $crate::InputLength; let mut res = $crate::lib::std::vec::Vec::with_capacity($m); let mut input = $i.clone(); let mut count: usize = 0; let mut err = false; let mut incomplete: $crate::lib::std::option::Option = $crate::lib::std::option::Option::None; let mut failure: $crate::lib::std::option::Option> = $crate::lib::std::option::Option::None; loop { if count == $n { break } let i_ = input.clone(); match $submac!(i_, $($args)*) { Ok((i, o)) => { // do not allow parsers that do not consume input (causes infinite loops) if i.input_len() == input.input_len() { break; } res.push(o); input = i; count += 1; } Err(Err::Error(_)) => { err = true; break; }, Err(Err::Incomplete(i)) => { incomplete = $crate::lib::std::option::Option::Some(i); break; }, Err(Err::Failure(e)) => { failure = $crate::lib::std::option::Option::Some(e); break; }, } } if count < $m { if err { Err(Err::Error(error_position!($i, $crate::ErrorKind::ManyMN))) } else { match failure { $crate::lib::std::option::Option::Some(i) => Err(Err::Failure(i)), $crate::lib::std::option::Option::None => match incomplete { $crate::lib::std::option::Option::Some(i) => $crate::need_more($i, i), $crate::lib::std::option::Option::None => $crate::need_more($i, Needed::Unknown) } } } } else { match failure { $crate::lib::std::option::Option::Some(i) => Err(Err::Failure(i)), $crate::lib::std::option::Option::None => match incomplete { $crate::lib::std::option::Option::Some(i) => $crate::need_more($i, i), $crate::lib::std::option::Option::None => Ok((input, res)) } } } } ); ($i:expr, $m:expr, $n: expr, $f:expr) => ( many_m_n!($i, $m, $n, call!($f)); ); ); /// `many0_count!(I -> IResult) => I -> IResult` /// 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::digit; /// /// named!(number<&[u8], usize>, many0_count!(pair!(digit, 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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err, AtEof}; let ret; let mut count: usize = 0; let mut input = $i.clone(); loop { let input_ = input.clone(); match $submac!(input_, $($args)*) { Ok((i, _)) => { // loop trip must always consume (otherwise infinite loops) if i == input { if i.at_eof() { ret = Ok((input, count)); } else { ret = Err(Err::Error(error_position!(input, $crate::ErrorKind::Many0Count))); } break; } count += 1; input = i; }, Err(Err::Error(_)) => { ret = Ok((input, count)); break; }, Err(e) => { ret = Err(e); break; }, } } ret } ); ($i:expr, $f:expr) => ( many0_count!($i, call!($f)); ); } /// `many1_count!(I -> IResult) => I -> IResult` /// Applies the parser 1 or more times and returns the number of times the parser was applied. /// /// ``` /// #[macro_use] extern crate nom; /// use nom::digit; /// /// named!(number<&[u8], usize>, many1_count!(pair!(digit, 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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; use $crate::InputLength; let i_ = $i.clone(); match $submac!(i_, $($args)*) { Err(Err::Error(_)) => Err(Err::Error( error_position!(i_, $crate::ErrorKind::Many1Count) )), Err(Err::Failure(_)) => Err(Err::Failure( error_position!(i_, $crate::ErrorKind::Many1Count) )), Err(i) => Err(i), Ok((i1, _)) => { let mut count: usize = 1; let mut input = i1; let mut error = $crate::lib::std::option::Option::None; loop { let input_ = input.clone(); match $submac!(input_, $($args)*) { Err(Err::Error(_)) => { break; }, Err(e) => { error = $crate::lib::std::option::Option::Some(e); break; }, Ok((i, _)) => { if i.input_len() == input.input_len() { break; } count += 1; input = i; }, } } match error { $crate::lib::std::option::Option::Some(e) => Err(e), $crate::lib::std::option::Option::None => Ok((input, count)), } }, } } ); ($i:expr, $f:expr) => ( many1_count!($i, call!($f)); ); } /// `count!(I -> IResult, nb) => I -> IResult>` /// Applies the child parser a specified number of times /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::Err; /// # use nom::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[..], ErrorKind::Count)))); /// # } /// ``` /// #[cfg(feature = "alloc")] #[macro_export(local_inner_macros)] macro_rules! count( ($i:expr, $submac:ident!( $($args:tt)* ), $count: expr) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; let ret; let mut input = $i.clone(); let mut res = $crate::lib::std::vec::Vec::new(); loop { if res.len() == $count { ret = Ok((input, res)); break; } let input_ = input.clone(); match $submac!(input_, $($args)*) { Ok((i,o)) => { res.push(o); input = i; }, Err(Err::Error(e)) => { fn unify_types(_: &T, _: &T) {} let e2 = error_position!($i, $crate::ErrorKind::Count); unify_types(&e, &e2); ret = Err(Err::Error(e2)); break; }, Err(e) => { ret = Err(e); break; }, } } ret } ); ($i:expr, $f:expr, $count: expr) => ( count!($i, call!($f), $count); ); ); /// `count_fixed!(O, I -> IResult, nb) => I -> IResult` /// Applies the child parser a fixed number of times and returns a fixed size array /// The type must be specified and it must be `Copy` /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::Err; /// # use nom::ErrorKind; /// # fn main() { /// named!(counter< [&[u8]; 2] >, count_fixed!( &[u8], tag!( "abcd" ), 2 ) ); /// // can omit the type specifier if returning slices /// // named!(counter< [&[u8]; 2] >, count_fixed!( tag!( "abcd" ), 2 ) ); /// /// let a = b"abcdabcdabcdef"; /// let b = b"abcdefgh"; /// let res = [&b"abcd"[..], &b"abcd"[..]]; /// /// assert_eq!(counter(&a[..]),Ok((&b"abcdef"[..], res))); /// assert_eq!(counter(&b[..]), Err(Err::Error(error_position!(&b[..], ErrorKind::Count)))); /// # } /// ``` /// #[macro_export(local_inner_macros)] macro_rules! count_fixed ( ($i:expr, $typ:ty, $submac:ident!( $($args:tt)* ), $count: expr) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; let ret; let mut input = $i.clone(); // `$typ` must be Copy, and thus having no destructor, this is panic safe let mut res: [$typ; $count] = unsafe{[$crate::lib::std::mem::uninitialized(); $count as usize]}; let mut cnt: usize = 0; loop { if cnt == $count { ret = Ok((input, res)); break; } match $submac!(input, $($args)*) { Ok((i,o)) => { res[cnt] = o; cnt += 1; input = i; }, Err(Err::Error(e)) => { fn unify_types(_: &T, _: &T) {} let e2 = error_position!($i, $crate::ErrorKind::Count); unify_types(&e, &e2); ret = Err(Err::Error(e2)); break; }, Err(e) => { ret = Err(e); break; }, } } ret } ); ($i:expr, $typ: ty, $f:expr, $count: expr) => ( count_fixed!($i, $typ, call!($f), $count); ); ); /// `length_count!(I -> IResult, I -> IResult) => I -> IResult>` /// gets a number from the first parser, then applies the second parser that many times #[macro_export(local_inner_macros)] macro_rules! length_count( ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Convert}; 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) => O` /// /// `length_data` gets a number from the first parser, than takes a subslice of the input /// of that size, and returns that subslice #[macro_export(local_inner_macros)] macro_rules! length_data( ($i:expr, $submac:ident!( $($args:tt)* )) => ({ use $crate::lib::std::result::Result::*; use $crate::{Convert,Err}; match $submac!($i, $($args)*) { Err(e) => Err(e), Ok((i, o)) => { match take!(i, o as usize) { Err(e) => Err(Err::convert(e)), Ok((i2, o2)) => Ok((i2, o2)) } } } }); ($i:expr, $f:expr) => ( length_data!($i, call!($f)); ); ); /// `length_value!(I -> IResult, I -> IResult) => I -> IResult` /// /// 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 #[macro_export(local_inner_macros)] macro_rules! length_value( ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Convert}; match $submac!($i, $($args)*) { Err(e) => Err(e), Ok((i, o)) => { match take!(i, o as usize) { Err(e) => Err(Err::convert(e)), Ok((i2, o2)) => { match complete!(o2, $submac2!($($args2)*)) { Err(e) => Err(Err::convert(e)), Ok((_, o3)) => Ok((i2, o3)) } } } } } } ); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( length_value!($i, $submac!($($args)*), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( length_value!($i, call!($f), $submac!($($args)*)); ); ($i:expr, $f:expr, $g:expr) => ( length_value!($i, call!($f), call!($g)); ); ); /// `fold_many0!(I -> IResult, R, Fn(R, O) -> R) => I -> IResult` /// 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, $f:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,AtEof}; let ret; let f = $f; let mut res = $init; let mut input = $i.clone(); loop { match $submac!(input, $($args)*) { Ok((i, o)) => { // loop trip must always consume (otherwise infinite loops) if i == input { if i.at_eof() { ret = Ok((input, res)); } else { ret = Err(Err::Error(error_position!(input, $crate::ErrorKind::Many0))); } break; } res = f(res, o); input = i; }, Err(Err::Error(_)) => { ret = Ok((input, res)); break; }, Err(e) => { ret = Err(e); break; }, } } ret } ); ($i:expr, $f:expr, $init:expr, $fold_f:expr) => ( fold_many0!($i, call!($f), $init, $fold_f); ); ); /// `fold_many1!(I -> IResult, R, Fn(R, O) -> R) => I -> IResult` /// 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::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, $f:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,InputLength,Context,AtEof}; match $submac!($i, $($args)*) { Err(Err::Error(_)) => Err(Err::Error( error_position!($i, $crate::ErrorKind::Many1) )), Err(Err::Failure(_)) => Err(Err::Failure( error_position!($i, $crate::ErrorKind::Many1) )), Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)), Ok((i1,o1)) => { let f = $f; let mut acc = f($init, o1); let mut input = i1; let mut incomplete: $crate::lib::std::option::Option = $crate::lib::std::option::Option::None; let mut failure: $crate::lib::std::option::Option> = $crate::lib::std::option::Option::None; loop { match $submac!(input, $($args)*) { Err(Err::Error(_)) => { break; }, Err(Err::Incomplete(i)) => { incomplete = $crate::lib::std::option::Option::Some(i); break; }, Err(Err::Failure(e)) => { failure = $crate::lib::std::option::Option::Some(e); break; }, Ok((i, o)) => { if i.input_len() == input.input_len() { if !i.at_eof() { failure = $crate::lib::std::option::Option::Some(error_position!(i, $crate::ErrorKind::Many1)); } break; } acc = f(acc, o); input = i; } } } match failure { $crate::lib::std::option::Option::Some(e) => Err(Err::Failure(e)), $crate::lib::std::option::Option::None => match incomplete { $crate::lib::std::option::Option::Some(i) => $crate::need_more($i, i), $crate::lib::std::option::Option::None => Ok((input, acc)) } } } } } ); ($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, R, Fn(R, O) -> R) => I -> IResult` /// 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::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!(&a[..], ErrorKind::ManyMN)))); /// 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, $f:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed}; use $crate::InputLength; let mut acc = $init; let f = $f; let mut input = $i.clone(); let mut count: usize = 0; let mut err = false; let mut incomplete: $crate::lib::std::option::Option = $crate::lib::std::option::Option::None; loop { if count == $n { break } match $submac!(input, $($args)*) { Ok((i, o)) => { // do not allow parsers that do not consume input (causes infinite loops) if i.input_len() == input.input_len() { break; } acc = f(acc, o); input = i; count += 1; } //FIXME: handle failure properly Err(Err::Error(_)) | Err(Err::Failure(_)) => { err = true; break; }, Err(Err::Incomplete(i)) => { incomplete = $crate::lib::std::option::Option::Some(i); break; }, } } if count < $m { if err { Err(Err::Error(error_position!($i, $crate::ErrorKind::ManyMN))) } else { match incomplete { $crate::lib::std::option::Option::Some(i) => Err(Err::Incomplete(i)), $crate::lib::std::option::Option::None => Err(Err::Incomplete(Needed::Unknown)) } } } else { match incomplete { $crate::lib::std::option::Option::Some(i) => Err(Err::Incomplete(i)), $crate::lib::std::option::Option::None => Ok((input, acc)) } } } ); ($i:expr, $m:expr, $n: expr, $f:expr, $init:expr, $fold_f:expr) => ( fold_many_m_n!($i, $m, $n, call!($f), $init, $fold_f); ); ); #[cfg(test)] mod tests { use internal::{Err, IResult, Needed}; use nom::{digit, be_u16, be_u8, le_u16}; use lib::std::str::{self, FromStr}; #[cfg(feature = "alloc")] use lib::std::vec::Vec; use util::ErrorKind; // reproduce the tag and take macros, because of module import order macro_rules! tag ( ($i:expr, $inp: expr) => ( { #[inline(always)] fn as_bytes(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<_,_,u32> = if reduced != b { Err($crate::Err::Error($crate::Context::Code($i, $crate::ErrorKind::Tag::))) } else if m < blen { Err($crate::Err::Incomplete(Needed::Size(blen))) } else { Ok((&$i[blen..], reduced)) }; res } ); ); macro_rules! take ( ($i:expr, $count:expr) => ( { let cnt = $count as usize; let res:IResult<&[u8],&[u8],u32> = if $i.len() < cnt { Err($crate::Err::Incomplete(Needed::Size(cnt))) } else { Ok((&$i[cnt..],&$i[0..cnt])) }; res } ) ); #[test] #[cfg(feature = "alloc")] fn separated_list() { named!(multi<&[u8],Vec<&[u8]> >, separated_list!(tag!(","), tag!("abcd"))); named!(multi_empty<&[u8],Vec<&[u8]> >, separated_list!(tag!(","), tag!(""))); named!(multi_longsep<&[u8],Vec<&[u8]> >, separated_list!(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 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()))); assert_eq!( multi_empty(d), Err(Err::Error(error_position!(d, ErrorKind::SeparatedList))) ); //let res3 = vec![&b""[..], &b""[..], &b""[..]]; //assert_eq!(multi_empty(d),Ok((&b"abc"[..], res3))); let res4 = vec![&b"abcd"[..], &b"abcd"[..]]; assert_eq!(multi(e), Ok((&b",ef"[..], res4))); assert_eq!(multi(f), Err(Err::Incomplete(Needed::Size(4)))); assert_eq!(multi_longsep(g), Err(Err::Incomplete(Needed::Size(2)))); assert_eq!(multi(h), Err(Err::Incomplete(Needed::Size(4)))); } #[test] #[cfg(feature = "alloc")] fn separated_list_complete() { use nom::alpha; named!(multi<&[u8],Vec<&[u8]> >, separated_list_complete!(tag!(","), alpha)); let a = &b"abcdef;"[..]; let b = &b"abcd,abcdef;"[..]; let c = &b"abcd,abcd,ef;"[..]; let d = &b"abc."[..]; let e = &b"abcd,ef."[..]; let f = &b"123"[..]; assert_eq!(multi(a), Ok((&b";"[..], vec![&a[..a.len() - 1]]))); assert_eq!( multi(b), Ok((&b";"[..], vec![&b"abcd"[..], &b"abcdef"[..]])) ); assert_eq!( multi(c), Ok((&b";"[..], vec![&b"abcd"[..], &b"abcd"[..], &b"ef"[..]])) ); assert_eq!(multi(d), Ok((&b"."[..], vec![&b"abc"[..]]))); assert_eq!(multi(e), Ok((&b"."[..], vec![&b"abcd"[..], &b"ef"[..]]))); assert_eq!(multi(f), Ok((&b"123"[..], Vec::new()))); } #[test] #[cfg(feature = "alloc")] fn separated_nonempty_list() { named!(multi<&[u8],Vec<&[u8]> >, separated_nonempty_list!(tag!(","), tag!("abcd"))); named!(multi_longsep<&[u8],Vec<&[u8]> >, separated_nonempty_list!(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::Size(4)))); assert_eq!(multi_longsep(g), Err(Err::Incomplete(Needed::Size(2)))); assert_eq!(multi(h), Err(Err::Incomplete(Needed::Size(4)))); } #[test] #[cfg(feature = "alloc")] fn separated_nonempty_list_complete() { use nom::alpha; named!(multi<&[u8],Vec<&[u8]> >, separated_nonempty_list_complete!(tag!(","), alpha)); let a = &b"abcdef;"[..]; let b = &b"abcd,abcdef;"[..]; let c = &b"abcd,abcd,ef;"[..]; let d = &b"abc."[..]; let e = &b"abcd,ef."[..]; let f = &b"123"[..]; assert_eq!(multi(a), Ok((&b";"[..], vec![&a[..a.len() - 1]]))); assert_eq!( multi(b), Ok((&b";"[..], vec![&b"abcd"[..], &b"abcdef"[..]])) ); assert_eq!( multi(c), Ok((&b";"[..], vec![&b"abcd"[..], &b"abcd"[..], &b"ef"[..]])) ); assert_eq!(multi(d), Ok((&b"."[..], vec![&b"abc"[..]]))); assert_eq!(multi(e), Ok((&b"."[..], vec![&b"abcd"[..], &b"ef"[..]]))); assert_eq!( multi(f), Err(Err::Error(error_position!(&b"123"[..], ErrorKind::Alpha))) ); } #[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::Size(4)))); assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::Size(4)))); assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::Size(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::Many1))) ); assert_eq!(multi(d), Err(Err::Incomplete(Needed::Size(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::Custom(0u32)))) } // 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::Many1))) ); } #[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!(a, ErrorKind::ManyMN))) ); 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::Size(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::Size(3)))); assert_eq!(cnt_2(&b"abcab"[..]), Err(Err::Incomplete(Needed::Size(3)))); assert_eq!( cnt_2(&b"xxx"[..]), Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Count))) ); assert_eq!( cnt_2(&b"xxxabcabcdef"[..]), Err(Err::Error(error_position!( &b"xxxabcabcdef"[..], ErrorKind::Count ))) ); assert_eq!( cnt_2(&b"abcxxxabcdef"[..]), Err(Err::Error(error_position!( &b"abcxxxabcdef"[..], ErrorKind::Count ))) ); } #[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))); } #[test] fn count_fixed() { const TIMES: usize = 2; named!(tag_abc, tag!("abc")); named!( cnt_2<&[u8], [&[u8]; TIMES] >, count_fixed!(&[u8], tag_abc, TIMES ) ); assert_eq!( cnt_2(&b"abcabcabcdef"[..]), Ok((&b"abcdef"[..], [&b"abc"[..], &b"abc"[..]])) ); assert_eq!(cnt_2(&b"ab"[..]), Err(Err::Incomplete(Needed::Size(3)))); assert_eq!(cnt_2(&b"abcab"[..]), Err(Err::Incomplete(Needed::Size(3)))); assert_eq!( cnt_2(&b"xxx"[..]), Err(Err::Error(error_position!(&b"xxx"[..], ErrorKind::Count))) ); assert_eq!( cnt_2(&b"xxxabcabcdef"[..]), Err(Err::Error(error_position!( &b"xxxabcabcdef"[..], ErrorKind::Count ))) ); assert_eq!( cnt_2(&b"abcxxxabcdef"[..]), Err(Err::Error(error_position!( &b"abcxxxabcdef"[..], ErrorKind::Count ))) ); } #[allow(dead_code)] pub fn compile_count_fixed(input: &[u8]) -> IResult<&[u8], ()> { do_parse!( input, tag!("abcd") >> count_fixed!(u16, le_u16, 4) >> eof!() >> () ) } #[derive(Debug, Clone, PartialEq)] pub struct NilError; impl From for NilError { fn from(_: u32) -> Self { NilError } } #[allow(unused_variables)] #[test] fn count_fixed_no_type() { const TIMES: usize = 2; named!(tag_abc, tag!("abc")); named!( counter_2<&[u8], [&[u8]; TIMES], NilError >, count_fixed!(&[u8], fix_error!(NilError, tag_abc), TIMES ) ); let done = &b"abcabcabcdef"[..]; let parsed_main = [&b"abc"[..], &b"abc"[..]]; let rest = &b"abcdef"[..]; let incomplete_1 = &b"ab"[..]; let incomplete_2 = &b"abcab"[..]; let error = &b"xxx"[..]; let error_1 = &b"xxxabcabcdef"[..]; let error_1_remain = &b"xxxabcabcdef"[..]; let error_2 = &b"abcxxxabcdef"[..]; let error_2_remain = &b"abcxxxabcdef"[..]; assert_eq!(counter_2(done), Ok((rest, parsed_main))); assert_eq!( counter_2(incomplete_1), Err(Err::Incomplete(Needed::Size(3))) ); assert_eq!( counter_2(incomplete_2), Err(Err::Incomplete(Needed::Size(3))) ); assert_eq!( counter_2(error), Err(Err::Error(error_position!(error, ErrorKind::Count))) ); assert_eq!( counter_2(error_1), Err(Err::Error(error_position!( error_1_remain, ErrorKind::Count ))) ); assert_eq!( counter_2(error_2), Err(Err::Error(error_position!( error_2_remain, ErrorKind::Count ))) ); } named!(pub number, 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::Size(3)))); assert_eq!(cnt(&b"3abcab"[..]), Err(Err::Incomplete(Needed::Size(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"abcxxx"[..], ErrorKind::Count ))) ); } #[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::Size(3)))); 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(mut acc: Vec, item: T) -> Vec { 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::Size(4)))); assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::Size(4)))); assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::Size(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(mut acc: Vec, item: T) -> Vec { 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::Size(4)))); } #[test] #[cfg(feature = "alloc")] fn fold_many_m_n() { fn fold_into_vec(mut acc: Vec, item: T) -> Vec { 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!(a, ErrorKind::ManyMN))) ); 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::Size(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 ))) ); } } nom-4.2.3/src/nom.rs010064400007670000024000001464611344541017100124740ustar0000000000000000//! Useful parser combinators //! //! A number of useful parser combinators have already been implemented. //! Some of them use macros, other are implemented through functions. //! Hopefully, the syntax will converge to onely one way in the future, //! but the macros system makes no promises. //! #![allow(unused_imports)] #[cfg(feature = "alloc")] use lib::std::boxed::Box; #[cfg(feature = "std")] use lib::std::fmt::Debug; use internal::*; use traits::{AsChar, InputIter, InputLength, InputTakeAtPosition}; use traits::{need_more, need_more_err, AtEof, ParseTo}; use lib::std::ops::{Range, RangeFrom, RangeTo}; use traits::{Compare, CompareResult, Offset, Slice}; use util::ErrorKind; use lib::std::mem::transmute; #[cfg(feature = "alloc")] #[inline] pub fn tag_cl<'a, 'b>(rec: &'a [u8]) -> Box IResult<&'b [u8], &'b [u8]> + 'a> { Box::new(move |i: &'b [u8]| -> IResult<&'b [u8], &'b [u8]> { if i.len() >= rec.len() && &i[0..rec.len()] == rec { Ok((&i[rec.len()..], &i[0..rec.len()])) } else { let e: ErrorKind = ErrorKind::TagClosure; Err(Err::Error(error_position!(i, e))) } }) } #[cfg(feature = "std")] #[inline] pub fn print(input: T) -> IResult { println!("{:?}", input); Ok((input, ())) } #[inline] pub fn begin(input: &[u8]) -> IResult<(), &[u8]> { Ok(((), input)) } pub fn crlf(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: InputIter + AtEof, T: Compare<&'static str>, { match input.compare("\r\n") { //FIXME: is this the right index? CompareResult::Ok => Ok((input.slice(2..), input.slice(0..2))), CompareResult::Incomplete => need_more_err(input, Needed::Size(2), ErrorKind::CrLf), CompareResult::Error => { let e: ErrorKind = ErrorKind::CrLf; Err(Err::Error(error_position!(input, e))) } } } // FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export // public methods pub fn not_line_ending(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: InputIter + InputLength + AtEof, T: Compare<&'static str>, ::Item: AsChar, ::RawItem: AsChar, { match input.position(|item| { let c = item.as_char(); c == '\r' || c == '\n' }) { None => { if input.at_eof() { Ok((input.slice(input.input_len()..), input)) } else { Err(Err::Incomplete(Needed::Unknown)) } } Some(index) => { let mut it = input.slice(index..).iter_elements(); let nth = it.next().unwrap().as_char(); if nth == '\r' { let sliced = input.slice(index..); let comp = sliced.compare("\r\n"); match comp { //FIXME: calculate the right index CompareResult::Incomplete => need_more_err(input, Needed::Unknown, ErrorKind::Tag), CompareResult::Error => { let e: ErrorKind = ErrorKind::Tag; Err(Err::Error(error_position!(input, e))) } CompareResult::Ok => Ok((input.slice(index..), input.slice(..index))), } } else { Ok((input.slice(index..), input.slice(..index))) } } } } /// Recognizes an end of line (both '\n' and '\r\n') pub fn line_ending(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: InputIter + InputLength + AtEof, T: Compare<&'static str>, { match input.compare("\n") { CompareResult::Ok => Ok((input.slice(1..), input.slice(0..1))), CompareResult::Incomplete => need_more_err(input, Needed::Size(1), ErrorKind::CrLf::), CompareResult::Error => { match input.compare("\r\n") { //FIXME: is this the right index? CompareResult::Ok => Ok((input.slice(2..), input.slice(0..2))), CompareResult::Incomplete => need_more_err(input, Needed::Size(2), ErrorKind::CrLf::), CompareResult::Error => Err(Err::Error(error_position!(input, ErrorKind::CrLf::))), } } } } pub fn eol(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: InputIter + InputLength + AtEof, T: Compare<&'static str>, { line_ending(input) } /// Tests if byte is ASCII alphabetic: A-Z, a-z #[inline] pub fn is_alphabetic(chr: u8) -> bool { (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A) } /// Tests if byte is ASCII digit: 0-9 #[inline] pub fn is_digit(chr: u8) -> bool { chr >= 0x30 && chr <= 0x39 } /// Tests if byte is ASCII hex digit: 0-9, A-F, a-f #[inline] pub fn is_hex_digit(chr: u8) -> bool { (chr >= 0x30 && chr <= 0x39) || (chr >= 0x41 && chr <= 0x46) || (chr >= 0x61 && chr <= 0x66) } /// Tests if byte is ASCII octal digit: 0-7 #[inline] pub fn is_oct_digit(chr: u8) -> bool { chr >= 0x30 && chr <= 0x37 } /// Tests if byte is ASCII alphanumeric: A-Z, a-z, 0-9 #[inline] pub fn is_alphanumeric(chr: u8) -> bool { is_alphabetic(chr) || is_digit(chr) } /// Tests if byte is ASCII space or tab #[inline] pub fn is_space(chr: u8) -> bool { chr == b' ' || chr == b'\t' } // FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export //pub filter!(alpha is_alphabetic) //pub filter!(digit is_digit) //pub filter!(hex_digit is_hex_digit) //pub filter!(oct_digit is_oct_digit) //pub filter!(alphanumeric is_alphanumeric) /// Recognizes one or more lowercase and uppercase alphabetic characters. /// For ASCII strings: a-zA-Z /// For UTF8 strings, any alphabetic code point (ie, not only the ASCII ones) pub fn alpha(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { alpha1(input) } /// Recognizes zero or more lowercase and uppercase alphabetic characters. /// For ASCII strings: a-zA-Z /// For UTF8 strings, any alphabetic code point (ie, not only the ASCII ones) pub fn alpha0(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position(|item| !item.is_alpha()) } /// Recognizes one or more lowercase and uppercase alphabetic characters /// For ASCII strings: a-zA-Z /// For UTF8 strings, any alphabetic code point (ie, not only the ASCII ones) pub fn alpha1(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position1(|item| !item.is_alpha(), ErrorKind::Alpha) } /// Recognizes one or more numerical characters: 0-9 pub fn digit(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { digit1(input) } /// Recognizes zero or more numerical characters: 0-9 pub fn digit0(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position(|item| !item.is_dec_digit()) } /// Recognizes one or more numerical characters: 0-9 pub fn digit1(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position1(|item| !item.is_dec_digit(), ErrorKind::Digit) } /// Recognizes one or more hexadecimal numerical characters: 0-9, A-F, a-f pub fn hex_digit(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { hex_digit1(input) } /// Recognizes zero or more hexadecimal numerical characters: 0-9, A-F, a-f pub fn hex_digit0(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position(|item| !item.is_hex_digit()) } /// Recognizes one or more hexadecimal numerical characters: 0-9, A-F, a-f pub fn hex_digit1(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position1(|item| !item.is_hex_digit(), ErrorKind::HexDigit) } /// Recognizes one or more octal characters: 0-7 pub fn oct_digit(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { oct_digit1(input) } /// Recognizes zero or more octal characters: 0-7 pub fn oct_digit0(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position(|item| !item.is_oct_digit()) } /// Recognizes one or more octal characters: 0-7 pub fn oct_digit1(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position1(|item| !item.is_oct_digit(), ErrorKind::OctDigit) } /// Recognizes one or more numerical and alphabetic characters /// For ASCII strings: 0-9a-zA-Z /// For UTF8 strings, 0-9 and any alphabetic code point (ie, not only the ASCII ones) pub fn alphanumeric(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { alphanumeric1(input) } /// Recognizes zero or more numerical and alphabetic characters. /// For ASCII strings: 0-9a-zA-Z /// For UTF8 strings, 0-9 and any alphabetic code point (ie, not only the ASCII ones) pub fn alphanumeric0(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position(|item| !item.is_alphanum()) } /// Recognizes one or more numerical and alphabetic characters. /// For ASCII strings: 0-9a-zA-Z /// For UTF8 strings, 0-9 and any alphabetic code point (ie, not only the ASCII ones) pub fn alphanumeric1(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar, { input.split_at_position1(|item| !item.is_alphanum(), ErrorKind::AlphaNumeric) } /// Recognizes one or more spaces and tabs pub fn space(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar + Clone, { space1(input) } /// Recognizes zero or more spaces and tabs pub fn space0(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar + Clone, { input.split_at_position(|item| { let c = item.clone().as_char(); !(c == ' ' || c == '\t') }) } /// Recognizes one or more spaces and tabs pub fn space1(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar + Clone, { input.split_at_position1( |item| { let c = item.clone().as_char(); !(c == ' ' || c == '\t') }, ErrorKind::Space, ) } /// Recognizes one or more spaces, tabs, carriage returns and line feeds pub fn multispace(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar + Clone, { multispace1(input) } /// Recognizes zero or more spaces, tabs, carriage returns and line feeds pub fn multispace0(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar + Clone, { input.split_at_position(|item| { let c = item.clone().as_char(); !(c == ' ' || c == '\t' || c == '\r' || c == '\n') }) } /// Recognizes one or more spaces, tabs, carriage returns and line feeds pub fn multispace1(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar + Clone, { input.split_at_position1( |item| { let c = item.clone().as_char(); !(c == ' ' || c == '\t' || c == '\r' || c == '\n') }, ErrorKind::MultiSpace, ) } pub fn sized_buffer(input: &[u8]) -> IResult<&[u8], &[u8]> { if input.is_empty() { return need_more(input, Needed::Unknown); } let len = input[0] as usize; if input.len() >= len + 1 { Ok((&input[len + 1..], &input[1..len + 1])) } else { need_more(input, Needed::Size(1 + len)) } } /// Recognizes an unsigned 1 byte integer (equivalent to take!(1) #[inline] pub fn be_u8(i: &[u8]) -> IResult<&[u8], u8> { if i.len() < 1 { need_more(i, Needed::Size(1)) } else { Ok((&i[1..], i[0])) } } /// Recognizes big endian unsigned 2 bytes integer #[inline] pub fn be_u16(i: &[u8]) -> IResult<&[u8], u16> { if i.len() < 2 { need_more(i, Needed::Size(2)) } else { let res = ((i[0] as u16) << 8) + i[1] as u16; Ok((&i[2..], res)) } } /// Recognizes big endian unsigned 3 byte integer #[inline] pub fn be_u24(i: &[u8]) -> IResult<&[u8], u32> { if i.len() < 3 { need_more(i, Needed::Size(3)) } else { let res = ((i[0] as u32) << 16) + ((i[1] as u32) << 8) + (i[2] as u32); Ok((&i[3..], res)) } } /// Recognizes big endian unsigned 4 bytes integer #[inline] pub fn be_u32(i: &[u8]) -> IResult<&[u8], u32> { if i.len() < 4 { need_more(i, Needed::Size(4)) } else { let res = ((i[0] as u32) << 24) + ((i[1] as u32) << 16) + ((i[2] as u32) << 8) + i[3] as u32; Ok((&i[4..], res)) } } /// Recognizes big endian unsigned 8 bytes integer #[inline] pub fn be_u64(i: &[u8]) -> IResult<&[u8], u64, u32> { if i.len() < 8 { need_more(i, Needed::Size(8)) } else { let res = ((i[0] as u64) << 56) + ((i[1] as u64) << 48) + ((i[2] as u64) << 40) + ((i[3] as u64) << 32) + ((i[4] as u64) << 24) + ((i[5] as u64) << 16) + ((i[6] as u64) << 8) + i[7] as u64; Ok((&i[8..], res)) } } /// Recognizes big endian unsigned 16 bytes integer #[inline] #[cfg(stable_i128)] pub fn be_u128(i: &[u8]) -> IResult<&[u8], u128, u32> { if i.len() < 16 { need_more(i, Needed::Size(16)) } else { let res = ((i[0] as u128) << 120) + ((i[1] as u128) << 112) + ((i[2] as u128) << 104) + ((i[3] as u128) << 96) + ((i[4] as u128) << 88) + ((i[5] as u128) << 80) + ((i[6] as u128) << 72) + ((i[7] as u128) << 64) + ((i[8] as u128) << 56) + ((i[9] as u128) << 48) + ((i[10] as u128) << 40) + ((i[11] as u128) << 32) + ((i[12] as u128) << 24) + ((i[13] as u128) << 16) + ((i[14] as u128) << 8) + i[15] as u128; Ok((&i[16..], res)) } } /// Recognizes a signed 1 byte integer (equivalent to take!(1) #[inline] pub fn be_i8(i: &[u8]) -> IResult<&[u8], i8> { map!(i, be_u8, |x| x as i8) } /// Recognizes big endian signed 2 bytes integer #[inline] pub fn be_i16(i: &[u8]) -> IResult<&[u8], i16> { map!(i, be_u16, |x| x as i16) } /// Recognizes big endian signed 3 bytes integer #[inline] pub fn be_i24(i: &[u8]) -> IResult<&[u8], i32> { // Same as the unsigned version but we need to sign-extend manually here map!(i, be_u24, |x| if x & 0x80_00_00 != 0 { (x | 0xff_00_00_00) as i32 } else { x as i32 }) } /// Recognizes big endian signed 4 bytes integer #[inline] pub fn be_i32(i: &[u8]) -> IResult<&[u8], i32> { map!(i, be_u32, |x| x as i32) } /// Recognizes big endian signed 8 bytes integer #[inline] pub fn be_i64(i: &[u8]) -> IResult<&[u8], i64> { map!(i, be_u64, |x| x as i64) } /// Recognizes big endian signed 16 bytes integer #[inline] #[cfg(stable_i128)] pub fn be_i128(i: &[u8]) -> IResult<&[u8], i128> { map!(i, be_u128, |x| x as i128) } /// Recognizes an unsigned 1 byte integer (equivalent to take!(1) #[inline] pub fn le_u8(i: &[u8]) -> IResult<&[u8], u8> { if i.len() < 1 { need_more(i, Needed::Size(1)) } else { Ok((&i[1..], i[0])) } } /// Recognizes little endian unsigned 2 bytes integer #[inline] pub fn le_u16(i: &[u8]) -> IResult<&[u8], u16> { if i.len() < 2 { need_more(i, Needed::Size(2)) } else { let res = ((i[1] as u16) << 8) + i[0] as u16; Ok((&i[2..], res)) } } /// Recognizes little endian unsigned 3 byte integer #[inline] pub fn le_u24(i: &[u8]) -> IResult<&[u8], u32> { if i.len() < 3 { need_more(i, Needed::Size(3)) } else { let res = (i[0] as u32) + ((i[1] as u32) << 8) + ((i[2] as u32) << 16); Ok((&i[3..], res)) } } /// Recognizes little endian unsigned 4 bytes integer #[inline] pub fn le_u32(i: &[u8]) -> IResult<&[u8], u32> { if i.len() < 4 { need_more(i, Needed::Size(4)) } else { let res = ((i[3] as u32) << 24) + ((i[2] as u32) << 16) + ((i[1] as u32) << 8) + i[0] as u32; Ok((&i[4..], res)) } } /// Recognizes little endian unsigned 8 bytes integer #[inline] pub fn le_u64(i: &[u8]) -> IResult<&[u8], u64> { if i.len() < 8 { need_more(i, Needed::Size(8)) } else { let res = ((i[7] as u64) << 56) + ((i[6] as u64) << 48) + ((i[5] as u64) << 40) + ((i[4] as u64) << 32) + ((i[3] as u64) << 24) + ((i[2] as u64) << 16) + ((i[1] as u64) << 8) + i[0] as u64; Ok((&i[8..], res)) } } /// Recognizes little endian unsigned 16 bytes integer #[inline] #[cfg(stable_i128)] pub fn le_u128(i: &[u8]) -> IResult<&[u8], u128, u32> { if i.len() < 16 { need_more(i, Needed::Size(16)) } else { let res = ((i[15] as u128) << 120) + ((i[14] as u128) << 112) + ((i[13] as u128) << 104) + ((i[12] as u128) << 96) + ((i[11] as u128) << 88) + ((i[10] as u128) << 80) + ((i[9] as u128) << 72) + ((i[8] as u128) << 64) + ((i[7] as u128) << 56) + ((i[6] as u128) << 48) + ((i[5] as u128) << 40) + ((i[4] as u128) << 32) + ((i[3] as u128) << 24) + ((i[2] as u128) << 16) + ((i[1] as u128) << 8) + i[0] as u128; Ok((&i[16..], res)) } } /// Recognizes a signed 1 byte integer (equivalent to take!(1) #[inline] pub fn le_i8(i: &[u8]) -> IResult<&[u8], i8> { map!(i, le_u8, |x| x as i8) } /// Recognizes little endian signed 2 bytes integer #[inline] pub fn le_i16(i: &[u8]) -> IResult<&[u8], i16> { map!(i, le_u16, |x| x as i16) } /// Recognizes little endian signed 3 bytes integer #[inline] pub fn le_i24(i: &[u8]) -> IResult<&[u8], i32> { // Same as the unsigned version but we need to sign-extend manually here map!(i, le_u24, |x| if x & 0x80_00_00 != 0 { (x | 0xff_00_00_00) as i32 } else { x as i32 }) } /// Recognizes little endian signed 4 bytes integer #[inline] pub fn le_i32(i: &[u8]) -> IResult<&[u8], i32> { map!(i, le_u32, |x| x as i32) } /// Recognizes little endian signed 8 bytes integer #[inline] pub fn le_i64(i: &[u8]) -> IResult<&[u8], i64> { map!(i, le_u64, |x| x as i64) } /// Recognizes little endian signed 16 bytes integer #[inline] #[cfg(stable_i128)] pub fn le_i128(i: &[u8]) -> IResult<&[u8], i128> { map!(i, le_u128, |x| x as i128) } /// Configurable endianness #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Endianness { Big, Little, } /// if the parameter is nom::Endianness::Big, parse a big endian u16 integer, /// otherwise a little endian u16 integer #[macro_export(local_inner_macros)] macro_rules! u16 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u16($i) } else { $crate::le_u16($i) } } );); /// if the parameter is nom::Endianness::Big, parse a big endian u32 integer, /// otherwise a little endian u32 integer #[macro_export(local_inner_macros)] macro_rules! u32 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u32($i) } else { $crate::le_u32($i) } } );); /// if the parameter is nom::Endianness::Big, parse a big endian u64 integer, /// otherwise a little endian u64 integer #[macro_export(local_inner_macros)] macro_rules! u64 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u64($i) } else { $crate::le_u64($i) } } );); /// if the parameter is nom::Endianness::Big, parse a big endian u128 integer, /// otherwise a little endian u128 integer #[macro_export(local_inner_macros)] #[cfg(stable_i128)] macro_rules! u128 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u128($i) } else { $crate::le_u128($i) } } );); /// if the parameter is nom::Endianness::Big, parse a big endian i16 integer, /// otherwise a little endian i16 integer #[macro_export(local_inner_macros)] macro_rules! i16 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i16($i) } else { $crate::le_i16($i) } } );); /// if the parameter is nom::Endianness::Big, parse a big endian i32 integer, /// otherwise a little endian i32 integer #[macro_export(local_inner_macros)] macro_rules! i32 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i32($i) } else { $crate::le_i32($i) } } );); /// if the parameter is nom::Endianness::Big, parse a big endian i64 integer, /// otherwise a little endian i64 integer #[macro_export(local_inner_macros)] macro_rules! i64 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i64($i) } else { $crate::le_i64($i) } } );); /// if the parameter is nom::Endianness::Big, parse a big endian i64 integer, /// otherwise a little endian i64 integer #[macro_export(local_inner_macros)] #[cfg(stable_i128)] macro_rules! i128 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i128($i) } else { $crate::le_i128($i) } } );); /// Recognizes big endian 4 bytes floating point number #[inline] pub fn be_f32(input: &[u8]) -> IResult<&[u8], f32> { match be_u32(input) { Err(e) => Err(e), Ok((i, o)) => Ok((i, f32::from_bits(o))), } } /// Recognizes big endian 8 bytes floating point number #[inline] pub fn be_f64(input: &[u8]) -> IResult<&[u8], f64> { match be_u64(input) { Err(e) => Err(e), Ok((i, o)) => Ok((i, f64::from_bits(o))), } } /// Recognizes little endian 4 bytes floating point number #[inline] pub fn le_f32(input: &[u8]) -> IResult<&[u8], f32> { match le_u32(input) { Err(e) => Err(e), Ok((i, o)) => Ok((i, f32::from_bits(o))), } } /// Recognizes little endian 8 bytes floating point number #[inline] pub fn le_f64(input: &[u8]) -> IResult<&[u8], f64> { match le_u64(input) { Err(e) => Err(e), Ok((i, o)) => Ok((i, f64::from_bits(o))), } } /// Recognizes a hex-encoded integer #[inline] pub fn hex_u32(input: &[u8]) -> IResult<&[u8], u32> { match is_a!(input, &b"0123456789abcdefABCDEF"[..]) { Err(e) => Err(e), Ok((i, o)) => { // Do not parse more than 8 characters for a u32 let (parsed, remaining) = if o.len() <= 8 { (o, i) } else { (&input[..8], &input[8..]) }; let res = parsed .iter() .rev() .enumerate() .map(|(k, &v)| { let digit = v as char; digit.to_digit(16).unwrap_or(0) << (k * 4) }) .sum(); Ok((remaining, res)) } } } /// Recognizes non empty buffers #[inline] pub fn non_empty(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: InputLength + AtEof, { if input.input_len() == 0 { return need_more_err(input, Needed::Unknown, ErrorKind::NonEmpty::); } else { Ok((input.slice(input.input_len()..), input)) } } /// Return the remaining input. #[inline] pub fn rest(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: InputLength, { Ok((input.slice(input.input_len()..), input)) } /// Return the length of the remaining input. #[inline] pub fn rest_len(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: InputLength, { let len = input.input_len(); Ok((input, len)) } /// Return the remaining input, for strings. #[inline] pub fn rest_s(input: &str) -> IResult<&str, &str> { Ok((&input[input.len()..], input)) } #[allow(unused_imports)] #[cfg_attr(rustfmt, rustfmt_skip)] pub fn recognize_float(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: Clone + Offset, T: InputIter + AtEof, ::Item: AsChar, T: InputTakeAtPosition, ::Item: AsChar { recognize!(input, tuple!( opt!(alt!(char!('+') | char!('-'))), alt!( value!((), tuple!(digit, opt!(pair!(char!('.'), opt!(digit))))) | value!((), tuple!(char!('.'), digit)) ), opt!(tuple!( alt!(char!('e') | char!('E')), opt!(alt!(char!('+') | char!('-'))), digit ) ) ) ) } /// Recognizes floating point number in a byte string and returns a f32 #[cfg(feature = "alloc")] //pub fn float(input: &[u8]) -> IResult<&[u8], f32> { pub fn float(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: Clone + Offset, T: InputIter + InputLength + ParseTo + AtEof, ::Item: AsChar, T: InputTakeAtPosition, ::Item: AsChar { flat_map!(input, recognize_float, parse_to!(f32)) } /// Recognizes floating point number in a string and returns a f32 #[cfg(feature = "alloc")] #[deprecated(since = "4.1.0", note = "Please use `float` instead")] pub fn float_s(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: Clone + Offset, T: InputIter + InputLength + ParseTo + AtEof, ::Item: AsChar, T: InputTakeAtPosition, ::Item: AsChar { flat_map!(input, call!(recognize_float), parse_to!(f32)) } /// Recognizes floating point number in a byte string and returns a f64 #[cfg(feature = "alloc")] pub fn double(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: Clone + Offset, T: InputIter + InputLength + ParseTo + AtEof, ::Item: AsChar, T: InputTakeAtPosition, ::Item: AsChar { flat_map!(input, call!(recognize_float), parse_to!(f64)) } /// Recognizes floating point number in a string and returns a f64 #[cfg(feature = "alloc")] #[deprecated(since = "4.1.0", note = "Please use `double` instead")] pub fn double_s(input: T) -> IResult where T: Slice> + Slice> + Slice>, T: Clone + Offset, T: InputIter + InputLength + ParseTo + AtEof, ::Item: AsChar, T: InputTakeAtPosition, ::Item: AsChar { flat_map!(input, call!(recognize_float), parse_to!(f64)) } #[cfg(test)] mod tests { use super::*; use internal::{Err, IResult, Needed}; use types::{CompleteByteSlice, CompleteStr}; #[test] #[cfg(feature = "alloc")] fn tag_closure() { let x = tag_cl(&b"abcd"[..]); let r = x(&b"abcdabcdefgh"[..]); assert_eq!(r, Ok((&b"abcdefgh"[..], &b"abcd"[..]))); let r2 = x(&b"abcefgh"[..]); assert_eq!( r2, Err(Err::Error(error_position!( &b"abcefgh"[..], ErrorKind::TagClosure ),)) ); } #[test] fn character() { let empty: &[u8] = b""; let a: &[u8] = b"abcd"; let b: &[u8] = b"1234"; let c: &[u8] = b"a123"; let d: &[u8] = "azé12".as_bytes(); let e: &[u8] = b" "; let f: &[u8] = b" ;"; assert_eq!(alpha(a), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( alpha(CompleteByteSlice(a)), Ok((CompleteByteSlice(empty), CompleteByteSlice(a))) ); assert_eq!( alpha(b), Err(Err::Error(error_position!(b, ErrorKind::Alpha))) ); assert_eq!(alpha(c), Ok((&c[1..], &b"a"[..]))); assert_eq!(alpha(d), Ok(("é12".as_bytes(), &b"az"[..]))); assert_eq!( digit(a), Err(Err::Error(error_position!(a, ErrorKind::Digit))) ); assert_eq!(digit(b), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( digit(CompleteByteSlice(b)), Ok((CompleteByteSlice(empty), CompleteByteSlice(b))) ); assert_eq!( digit(c), Err(Err::Error(error_position!(c, ErrorKind::Digit))) ); assert_eq!( digit(d), Err(Err::Error(error_position!(d, ErrorKind::Digit))) ); assert_eq!(hex_digit(a), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( hex_digit(CompleteByteSlice(a)), Ok((CompleteByteSlice(empty), CompleteByteSlice(a))) ); assert_eq!(hex_digit(b), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( hex_digit(CompleteByteSlice(b)), Ok((CompleteByteSlice(empty), CompleteByteSlice(b))) ); assert_eq!(hex_digit(c), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( hex_digit(CompleteByteSlice(c)), Ok((CompleteByteSlice(empty), CompleteByteSlice(c))) ); assert_eq!(hex_digit(d), Ok(("zé12".as_bytes(), &b"a"[..]))); assert_eq!( hex_digit(e), Err(Err::Error(error_position!(e, ErrorKind::HexDigit))) ); assert_eq!( oct_digit(a), Err(Err::Error(error_position!(a, ErrorKind::OctDigit))) ); assert_eq!(oct_digit(b), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( oct_digit(CompleteByteSlice(b)), Ok((CompleteByteSlice(empty), CompleteByteSlice(b))) ); assert_eq!( oct_digit(c), Err(Err::Error(error_position!(c, ErrorKind::OctDigit))) ); assert_eq!( oct_digit(d), Err(Err::Error(error_position!(d, ErrorKind::OctDigit))) ); assert_eq!(alphanumeric(a), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( alphanumeric(CompleteByteSlice(a)), Ok((CompleteByteSlice(empty), CompleteByteSlice(a))) ); //assert_eq!(fix_error!(b,(), alphanumeric), Ok((empty, b))); assert_eq!(alphanumeric(c), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( alphanumeric(CompleteByteSlice(c)), Ok((CompleteByteSlice(empty), CompleteByteSlice(c))) ); assert_eq!(alphanumeric(d), Ok(("é12".as_bytes(), &b"az"[..]))); assert_eq!(space(e), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( space(CompleteByteSlice(e)), Ok((CompleteByteSlice(empty), CompleteByteSlice(b" "))) ); assert_eq!(space(f), Ok((&b";"[..], &b" "[..]))); assert_eq!( space(CompleteByteSlice(f)), Ok((CompleteByteSlice(b";"), CompleteByteSlice(b" "))) ); } #[cfg(feature = "alloc")] #[test] fn character_s() { let empty = ""; let a = "abcd"; let b = "1234"; let c = "a123"; let d = "azé12"; let e = " "; assert_eq!(alpha(a), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( alpha(CompleteStr(a)), Ok((CompleteStr(empty), CompleteStr(a))) ); assert_eq!( alpha(b), Err(Err::Error(error_position!(b, ErrorKind::Alpha))) ); assert_eq!(alpha(c), Ok((&c[1..], &"a"[..]))); assert_eq!(alpha(d), Ok(("12", &"azé"[..]))); assert_eq!( digit(a), Err(Err::Error(error_position!(a, ErrorKind::Digit))) ); assert_eq!(digit(b), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( digit(CompleteStr(b)), Ok((CompleteStr(empty), CompleteStr(b))) ); assert_eq!( digit(c), Err(Err::Error(error_position!(c, ErrorKind::Digit))) ); assert_eq!( digit(d), Err(Err::Error(error_position!(d, ErrorKind::Digit))) ); assert_eq!(hex_digit(a), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( hex_digit(CompleteStr(a)), Ok((CompleteStr(empty), CompleteStr(a))) ); assert_eq!(hex_digit(b), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( hex_digit(CompleteStr(b)), Ok((CompleteStr(empty), CompleteStr(b))) ); assert_eq!(hex_digit(c), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( hex_digit(CompleteStr(c)), Ok((CompleteStr(empty), CompleteStr(c))) ); assert_eq!(hex_digit(d), Ok(("zé12", &"a"[..]))); assert_eq!( hex_digit(e), Err(Err::Error(error_position!(e, ErrorKind::HexDigit))) ); assert_eq!( oct_digit(a), Err(Err::Error(error_position!(a, ErrorKind::OctDigit))) ); assert_eq!(oct_digit(b), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( oct_digit(CompleteStr(b)), Ok((CompleteStr(empty), CompleteStr(b))) ); assert_eq!( oct_digit(c), Err(Err::Error(error_position!(c, ErrorKind::OctDigit))) ); assert_eq!( oct_digit(d), Err(Err::Error(error_position!(d, ErrorKind::OctDigit))) ); assert_eq!(alphanumeric(a), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( alphanumeric(CompleteStr(a)), Ok((CompleteStr(empty), CompleteStr(a))) ); //assert_eq!(fix_error!(b,(), alphanumeric), Ok((empty, b))); assert_eq!(alphanumeric(c), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( alphanumeric(CompleteStr(c)), Ok((CompleteStr(empty), CompleteStr(c))) ); assert_eq!(alphanumeric(d), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!( alphanumeric(CompleteStr(d)), Ok((CompleteStr(""), CompleteStr("azé12"))) ); assert_eq!(space(e), Err(Err::Incomplete(Needed::Size(1)))); } use traits::Offset; #[test] fn offset() { let a = &b"abcd;"[..]; let b = &b"1234;"[..]; let c = &b"a123;"[..]; let d = &b" \t;"[..]; let e = &b" \t\r\n;"[..]; let f = &b"123abcDEF;"[..]; match alpha(a) { Ok((i, _)) => { assert_eq!(a.offset(i) + i.len(), a.len()); } _ => panic!("wrong return type in offset test for alpha"), } match digit(b) { Ok((i, _)) => { assert_eq!(b.offset(i) + i.len(), b.len()); } _ => panic!("wrong return type in offset test for digit"), } match alphanumeric(c) { Ok((i, _)) => { assert_eq!(c.offset(i) + i.len(), c.len()); } _ => panic!("wrong return type in offset test for alphanumeric"), } match space(d) { Ok((i, _)) => { assert_eq!(d.offset(i) + i.len(), d.len()); } _ => panic!("wrong return type in offset test for space"), } match multispace(e) { Ok((i, _)) => { assert_eq!(e.offset(i) + i.len(), e.len()); } _ => panic!("wrong return type in offset test for multispace"), } match hex_digit(f) { Ok((i, _)) => { assert_eq!(f.offset(i) + i.len(), f.len()); } _ => panic!("wrong return type in offset test for hex_digit"), } match oct_digit(f) { Ok((i, _)) => { assert_eq!(f.offset(i) + i.len(), f.len()); } _ => panic!("wrong return type in offset test for oct_digit"), } } #[test] fn is_not_line_ending_bytes() { let a: &[u8] = b"ab12cd\nefgh"; assert_eq!(not_line_ending(a), Ok((&b"\nefgh"[..], &b"ab12cd"[..]))); let b: &[u8] = b"ab12cd\nefgh\nijkl"; assert_eq!( not_line_ending(b), Ok((&b"\nefgh\nijkl"[..], &b"ab12cd"[..])) ); let c: &[u8] = b"ab12cd\r\nefgh\nijkl"; assert_eq!( not_line_ending(c), Ok((&b"\r\nefgh\nijkl"[..], &b"ab12cd"[..])) ); let d = CompleteByteSlice(b"ab12cd"); assert_eq!(not_line_ending(d), Ok((CompleteByteSlice(b""), d))); let d: &[u8] = b"ab12cd"; assert_eq!(not_line_ending(d), Err(Err::Incomplete(Needed::Unknown))); } #[test] fn is_not_line_ending_str() { /* let a: &str = "ab12cd\nefgh"; assert_eq!(not_line_ending(a), Ok((&"\nefgh"[..], &"ab12cd"[..]))); let b: &str = "ab12cd\nefgh\nijkl"; assert_eq!(not_line_ending(b), Ok((&"\nefgh\nijkl"[..], &"ab12cd"[..]))); let c: &str = "ab12cd\r\nefgh\nijkl"; assert_eq!(not_line_ending(c), Ok((&"\r\nefgh\nijkl"[..], &"ab12cd"[..]))); let d = "βèƒôřè\nÂßÇáƒƭèř"; assert_eq!(not_line_ending(d), Ok((&"\nÂßÇáƒƭèř"[..], &"βèƒôřè"[..]))); let e = "βèƒôřè\r\nÂßÇáƒƭèř"; assert_eq!(not_line_ending(e), Ok((&"\r\nÂßÇáƒƭèř"[..], &"βèƒôřè"[..]))); */ let f = "βèƒôřè\rÂßÇáƒƭèř"; assert_eq!( not_line_ending(f), Err(Err::Error(error_position!(f, ErrorKind::Tag))) ); let g = CompleteStr("ab12cd"); assert_eq!(not_line_ending(g), Ok((CompleteStr(""), g))); let g2: &str = "ab12cd"; assert_eq!(not_line_ending(g2), Err(Err::Incomplete(Needed::Unknown))); } #[test] #[cfg(feature = "alloc")] fn buffer_with_size() { use lib::std::vec::Vec; let i: Vec = vec![7, 8]; let o: Vec = vec![4, 5, 6]; //let arr:[u8; 6usize] = [3, 4, 5, 6, 7, 8]; let arr: [u8; 6usize] = [3, 4, 5, 6, 7, 8]; let res = sized_buffer(&arr[..]); assert_eq!(res, Ok((&i[..], &o[..]))) } /*#[test] fn t1() { let v1:Vec = vec![1,2,3]; let v2:Vec = vec![4,5,6]; let d = Ok((&v1[..], &v2[..])); let res = d.flat_map(print); assert_eq!(res, Ok((&v2[..], ()))); }*/ #[test] fn i8_tests() { assert_eq!(be_i8(&[0x00]), Ok((&b""[..], 0))); assert_eq!(be_i8(&[0x7f]), Ok((&b""[..], 127))); assert_eq!(be_i8(&[0xff]), Ok((&b""[..], -1))); assert_eq!(be_i8(&[0x80]), Ok((&b""[..], -128))); } #[test] fn i16_tests() { assert_eq!(be_i16(&[0x00, 0x00]), Ok((&b""[..], 0))); assert_eq!(be_i16(&[0x7f, 0xff]), Ok((&b""[..], 32_767_i16))); assert_eq!(be_i16(&[0xff, 0xff]), Ok((&b""[..], -1))); assert_eq!(be_i16(&[0x80, 0x00]), Ok((&b""[..], -32_768_i16))); } #[test] fn u24_tests() { assert_eq!(be_u24(&[0x00, 0x00, 0x00]), Ok((&b""[..], 0))); assert_eq!(be_u24(&[0x00, 0xFF, 0xFF]), Ok((&b""[..], 65_535_u32))); assert_eq!(be_u24(&[0x12, 0x34, 0x56]), Ok((&b""[..], 1_193_046_u32))); } #[test] fn i24_tests() { assert_eq!(be_i24(&[0xFF, 0xFF, 0xFF]), Ok((&b""[..], -1_i32))); assert_eq!(be_i24(&[0xFF, 0x00, 0x00]), Ok((&b""[..], -65_536_i32))); assert_eq!(be_i24(&[0xED, 0xCB, 0xAA]), Ok((&b""[..], -1_193_046_i32))); } #[test] fn i32_tests() { assert_eq!(be_i32(&[0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0))); assert_eq!( be_i32(&[0x7f, 0xff, 0xff, 0xff]), Ok((&b""[..], 2_147_483_647_i32)) ); assert_eq!(be_i32(&[0xff, 0xff, 0xff, 0xff]), Ok((&b""[..], -1))); assert_eq!( be_i32(&[0x80, 0x00, 0x00, 0x00]), Ok((&b""[..], -2_147_483_648_i32)) ); } #[test] fn i64_tests() { assert_eq!( be_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0)) ); assert_eq!( be_i64(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Ok((&b""[..], 9_223_372_036_854_775_807_i64)) ); assert_eq!( be_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Ok((&b""[..], -1)) ); assert_eq!( be_i64(&[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], -9_223_372_036_854_775_808_i64)) ); } #[test] #[cfg(stable_i128)] fn i128_tests() { assert_eq!( be_i128(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0)) ); assert_eq!( be_i128(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Ok((&b""[..], 170_141_183_460_469_231_731_687_303_715_884_105_727_i128)) ); assert_eq!( be_i128(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Ok((&b""[..], -1)) ); assert_eq!( be_i128(&[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], -170_141_183_460_469_231_731_687_303_715_884_105_728_i128)) ); } #[test] fn le_i8_tests() { assert_eq!(le_i8(&[0x00]), Ok((&b""[..], 0))); assert_eq!(le_i8(&[0x7f]), Ok((&b""[..], 127))); assert_eq!(le_i8(&[0xff]), Ok((&b""[..], -1))); assert_eq!(le_i8(&[0x80]), Ok((&b""[..], -128))); } #[test] fn le_i16_tests() { assert_eq!(le_i16(&[0x00, 0x00]), Ok((&b""[..], 0))); assert_eq!(le_i16(&[0xff, 0x7f]), Ok((&b""[..], 32_767_i16))); assert_eq!(le_i16(&[0xff, 0xff]), Ok((&b""[..], -1))); assert_eq!(le_i16(&[0x00, 0x80]), Ok((&b""[..], -32_768_i16))); } #[test] fn le_u24_tests() { assert_eq!(le_u24(&[0x00, 0x00, 0x00]), Ok((&b""[..], 0))); assert_eq!(le_u24(&[0xFF, 0xFF, 0x00]), Ok((&b""[..], 65_535_u32))); assert_eq!(le_u24(&[0x56, 0x34, 0x12]), Ok((&b""[..], 1_193_046_u32))); } #[test] fn le_i24_tests() { assert_eq!(le_i24(&[0xFF, 0xFF, 0xFF]), Ok((&b""[..], -1_i32))); assert_eq!(le_i24(&[0x00, 0x00, 0xFF]), Ok((&b""[..], -65_536_i32))); assert_eq!(le_i24(&[0xAA, 0xCB, 0xED]), Ok((&b""[..], -1_193_046_i32))); } #[test] fn le_i32_tests() { assert_eq!(le_i32(&[0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0))); assert_eq!( le_i32(&[0xff, 0xff, 0xff, 0x7f]), Ok((&b""[..], 2_147_483_647_i32)) ); assert_eq!(le_i32(&[0xff, 0xff, 0xff, 0xff]), Ok((&b""[..], -1))); assert_eq!( le_i32(&[0x00, 0x00, 0x00, 0x80]), Ok((&b""[..], -2_147_483_648_i32)) ); } #[test] fn le_i64_tests() { assert_eq!( le_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0)) ); assert_eq!( le_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]), Ok((&b""[..], 9_223_372_036_854_775_807_i64)) ); assert_eq!( le_i64(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Ok((&b""[..], -1)) ); assert_eq!( le_i64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), Ok((&b""[..], -9_223_372_036_854_775_808_i64)) ); } #[test] #[cfg(stable_i128)] fn le_i128_tests() { assert_eq!( le_i128(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0)) ); assert_eq!( le_i128(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]), Ok((&b""[..], 170_141_183_460_469_231_731_687_303_715_884_105_727_i128)) ); assert_eq!( le_i128(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), Ok((&b""[..], -1)) ); assert_eq!( le_i128(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), Ok((&b""[..], -170_141_183_460_469_231_731_687_303_715_884_105_728_i128)) ); } #[test] fn be_f32_tests() { assert_eq!(be_f32(&[0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0_f32))); assert_eq!( be_f32(&[0x4d, 0x31, 0x1f, 0xd8]), Ok((&b""[..], 185_728_392_f32)) ); } #[test] fn be_f64_tests() { assert_eq!( be_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0_f64)) ); assert_eq!( be_f64(&[0x41, 0xa6, 0x23, 0xfb, 0x10, 0x00, 0x00, 0x00]), Ok((&b""[..], 185_728_392_f64)) ); } #[test] fn le_f32_tests() { assert_eq!(le_f32(&[0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0_f32))); assert_eq!( le_f32(&[0xd8, 0x1f, 0x31, 0x4d]), Ok((&b""[..], 185_728_392_f32)) ); } #[test] fn le_f64_tests() { assert_eq!( le_f64(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), Ok((&b""[..], 0_f64)) ); assert_eq!( le_f64(&[0x00, 0x00, 0x00, 0x10, 0xfb, 0x23, 0xa6, 0x41]), Ok((&b""[..], 185_728_392_f64)) ); } #[test] fn hex_u32_tests() { assert_eq!( hex_u32(&b";"[..]), Err(Err::Error(error_position!(&b";"[..], ErrorKind::IsA))) ); assert_eq!(hex_u32(&b"ff;"[..]), Ok((&b";"[..], 255))); assert_eq!(hex_u32(&b"1be2;"[..]), Ok((&b";"[..], 7138))); assert_eq!(hex_u32(&b"c5a31be2;"[..]), Ok((&b";"[..], 3_315_801_058))); assert_eq!(hex_u32(&b"C5A31be2;"[..]), Ok((&b";"[..], 3_315_801_058))); assert_eq!(hex_u32(&b"00c5a31be2;"[..]), Ok((&b"e2;"[..], 12_952_347))); assert_eq!( hex_u32(&b"c5a31be201;"[..]), Ok((&b"01;"[..], 3_315_801_058)) ); assert_eq!(hex_u32(&b"ffffffff;"[..]), Ok((&b";"[..], 4_294_967_295))); assert_eq!(hex_u32(&b"0x1be2;"[..]), Ok((&b"x1be2;"[..], 0))); } /* #[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_eq!(rest(input), Ok((empty, input))); } #[test] fn rest_on_strs() { let input: &str = "Hello, world!"; let empty: &str = ""; assert_eq!(rest(input), Ok((empty, input))); } #[test] fn rest_len_on_slices() { let input: &[u8] = &b"Hello, world!"[..]; assert_eq!(rest_len(input), Ok((input, input.len()))); } #[test] fn configurable_endianness() { named!(be_tst16, u16!(Endianness::Big)); named!(le_tst16, 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!(Endianness::Big)); named!(le_tst32, 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!(Endianness::Big)); named!(le_tst64, 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!(Endianness::Big)); named!(le_tsti16, 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!(Endianness::Big)); named!(le_tsti32, 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!(Endianness::Big)); named!(le_tsti64, 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)) ); } #[test] #[cfg(feature = "std")] fn manual_configurable_endianness_test() { let x = 1; let int_parse: Box IResult<&[u8], u16>> = 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))); } use lib::std::convert::From; impl From for CustomError { fn from(_: u32) -> Self { CustomError } } struct CustomError; #[allow(dead_code)] fn custom_error(input: &[u8]) -> IResult<&[u8], &[u8], CustomError> { fix_error!(input, CustomError, alphanumeric) } #[test] fn hex_digit_test() { let i = &b"0123456789abcdefABCDEF;"[..]; assert_eq!(hex_digit(i), Ok((&b";"[..], &i[..i.len() - 1]))); let i = &b"g"[..]; assert_eq!( hex_digit(i), Err(Err::Error(error_position!(i, ErrorKind::HexDigit))) ); let i = &b"G"[..]; assert_eq!( hex_digit(i), Err(Err::Error(error_position!(i, ErrorKind::HexDigit))) ); assert!(is_hex_digit(b'0')); assert!(is_hex_digit(b'9')); assert!(is_hex_digit(b'a')); assert!(is_hex_digit(b'f')); assert!(is_hex_digit(b'A')); assert!(is_hex_digit(b'F')); assert!(!is_hex_digit(b'g')); assert!(!is_hex_digit(b'G')); assert!(!is_hex_digit(b'/')); assert!(!is_hex_digit(b':')); assert!(!is_hex_digit(b'@')); assert!(!is_hex_digit(b'\x60')); } #[test] fn oct_digit_test() { let i = &b"01234567;"[..]; assert_eq!(oct_digit(i), Ok((&b";"[..], &i[..i.len() - 1]))); let i = &b"8"[..]; assert_eq!( oct_digit(i), Err(Err::Error(error_position!(i, ErrorKind::OctDigit))) ); assert!(is_oct_digit(b'0')); assert!(is_oct_digit(b'7')); assert!(!is_oct_digit(b'8')); assert!(!is_oct_digit(b'9')); assert!(!is_oct_digit(b'a')); assert!(!is_oct_digit(b'A')); assert!(!is_oct_digit(b'/')); assert!(!is_oct_digit(b':')); assert!(!is_oct_digit(b'@')); assert!(!is_oct_digit(b'\x60')); } #[test] fn full_line_windows() { named!( take_full_line<(&[u8], &[u8])>, tuple!(not_line_ending, line_ending) ); let input = b"abc\r\n"; let output = take_full_line(input); assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\r\n"[..])))); } #[test] fn full_line_unix() { named!( take_full_line<(&[u8], &[u8])>, tuple!(not_line_ending, line_ending) ); let input = b"abc\n"; let output = take_full_line(input); assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\n"[..])))); } #[test] fn check_windows_lineending() { let input = b"\r\n"; let output = line_ending(&input[..]); assert_eq!(output, Ok((&b""[..], &b"\r\n"[..]))); } #[test] fn check_unix_lineending() { let input = b"\n"; let output = line_ending(&input[..]); assert_eq!(output, Ok((&b""[..], &b"\n"[..]))); } #[test] fn cr_lf() { assert_eq!(crlf(&b"\r\na"[..]), Ok((&b"a"[..], &b"\r\n"[..]))); assert_eq!(crlf(&b"\r"[..]), Err(Err::Incomplete(Needed::Size(2)))); assert_eq!( crlf(&b"\ra"[..]), Err(Err::Error(error_position!(&b"\ra"[..], ErrorKind::CrLf))) ); assert_eq!(crlf("\r\na"), Ok(("a", "\r\n"))); assert_eq!(crlf("\r"), Err(Err::Incomplete(Needed::Size(2)))); assert_eq!( crlf("\ra"), Err(Err::Error(error_position!("\ra", ErrorKind::CrLf))) ); } #[test] fn end_of_line() { assert_eq!(eol(&b"\na"[..]), Ok((&b"a"[..], &b"\n"[..]))); assert_eq!(eol(&b"\r\na"[..]), Ok((&b"a"[..], &b"\r\n"[..]))); assert_eq!(eol(&b"\r"[..]), Err(Err::Incomplete(Needed::Size(2)))); assert_eq!( eol(&b"\ra"[..]), Err(Err::Error(error_position!(&b"\ra"[..], ErrorKind::CrLf))) ); assert_eq!(eol("\na"), Ok(("a", "\n"))); assert_eq!(eol("\r\na"), Ok(("a", "\r\n"))); assert_eq!(eol("\r"), Err(Err::Incomplete(Needed::Size(2)))); assert_eq!( eol("\ra"), Err(Err::Error(error_position!("\ra", ErrorKind::CrLf))) ); } #[test] #[cfg(feature = "std")] fn float_test() { let mut test_cases = vec![ "+3.14", "3.14", "-3.14", "0", "0.0", "1.", ".789", "-.5", "1e7", "-1E-7", ".3e-2", "1.e4", "1.2e4", "-1.234E-12", "-1.234e-12", ]; for test in test_cases.drain(..) { let expected32 = str::parse::(test).unwrap(); let expected64 = str::parse::(test).unwrap(); println!("now parsing: {} -> {}", test, expected32); assert_eq!( recognize_float(CompleteStr(test)), Ok((CompleteStr(""), CompleteStr(test))) ); let larger = format!("{};", test); assert_eq!(recognize_float(&larger[..]), Ok((";", test))); assert_eq!(float(larger.as_bytes()), Ok((&b";"[..], expected32))); assert_eq!(float(&larger[..]), Ok((";", expected32))); assert_eq!(float(CompleteByteSlice(test.as_bytes())), Ok((CompleteByteSlice(&b""[..]), expected32))); assert_eq!(float(CompleteStr(test)), Ok((CompleteStr(""), expected32))); assert_eq!(double(larger.as_bytes()), Ok((&b";"[..], expected64))); assert_eq!(double(&larger[..]), Ok((";", expected64))); assert_eq!(double(CompleteByteSlice(test.as_bytes())), Ok((CompleteByteSlice(&b""[..]), expected64))); assert_eq!(double(CompleteStr(test)), Ok((CompleteStr(""), expected64))); //deprecated functions #[allow(deprecated)] { assert_eq!(float_s(&larger[..]), Ok((";", expected32))); assert_eq!(double_s(&larger[..]), Ok((";", expected64))); } } let remaining_exponent = "-1.234E-"; assert_eq!( recognize_float(remaining_exponent), Err(Err::Incomplete(Needed::Size(1))) ); } #[allow(dead_code)] pub fn end_of_line_completestr(input: CompleteStr) -> IResult { alt!(input, eof!() | eol) } } nom-4.2.3/src/regexp.rs010064400007670000024000000725461344000023700131700ustar0000000000000000#[doc(hidden)] #[macro_export] macro_rules! regex ( ($re: ident, $s:expr) => ( lazy_static! { static ref $re: $crate::lib::regex::Regex = $crate::lib::regex::Regex::new($s).unwrap(); } ); ); #[doc(hidden)] #[macro_export] macro_rules! regex_bytes ( ($re: ident, $s:expr) => ( lazy_static! { static ref $re: $crate::lib::regex::bytes::Regex = $crate::lib::regex::bytes::Regex::new($s).unwrap(); } ); ); /// `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)] macro_rules! re_match ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::InputLength; use $crate::Slice; let re = $crate::lib::regex::Regex::new($re).unwrap(); if re.is_match(&$i) { Ok(($i.slice($i.input_len()..), $i)) } else { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpMatch::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_match_static!(regexp) => &[T] -> IResult<&[T], &[T]>` /// Returns the whole input if a match is found. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_match_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::InputLength; use $crate::Slice; regex!(RE, $re); if RE.is_match(&$i) { Ok(($i.slice($i.input_len()..), $i)) } else { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpMatch::))); res } } ) ); /// `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)] macro_rules! re_bytes_match ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::InputLength; use $crate::Slice; let re = $crate::lib::regex::bytes::Regex::new($re).unwrap(); if re.is_match(&$i) { Ok(($i.slice($i.input_len()..), $i)) } else { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpMatch::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_bytes_match_static!(regexp) => &[T] -> IResult<&[T], &[T]>` /// Returns the whole input if a match is found. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_match_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::InputLength; use $crate::Slice; regex_bytes!(RE, $re); if RE.is_match(&$i) { Ok(($i.slice($i.input_len()..), $i)) } else { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpMatch::))); res } } ) ); /// `re_find!(regexp) => &[T] -> IResult<&[T], &[T]>` /// Returns the first match /// /// requires the `regexp` feature #[macro_export(local_inner_macros)] macro_rules! re_find ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; let re = $crate::lib::regex::Regex::new($re).unwrap(); if let Some(m) = re.find(&$i) { Ok(($i.slice(m.end()..), $i.slice(m.start()..m.end()))) } else { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpFind::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_find_static!(regexp) => &[T] -> IResult<&[T], &[T]>` /// Returns the first match. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_find_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; regex!(RE, $re); if let Some(m) = RE.find(&$i) { Ok(($i.slice(m.end()..), $i.slice(m.start()..m.end()))) } else { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpFind::))); res } } ) ); /// `re_bytes_find!(regexp) => &[T] -> IResult<&[T], &[T]>` /// Returns the first match /// /// requires the `regexp` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_find ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; let re = $crate::lib::regex::bytes::Regex::new($re).unwrap(); if let Some(m) = re.find(&$i) { Ok(($i.slice(m.end()..), $i.slice(m.start()..m.end()))) } else { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpFind::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_bytes_find!(regexp) => &[T] -> IResult<&[T], &[T]>` /// Returns the first match. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_find_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; regex_bytes!(RE, $re); if let Some(m) = RE.find(&$i) { Ok(($i.slice(m.end()..), $i.slice(m.start()..m.end()))) } else { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpFind::))); res } } ) ); /// `re_matches!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` /// Returns all the matched parts /// /// requires the `regexp` feature #[macro_export(local_inner_macros)] macro_rules! re_matches ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; let re = $crate::lib::regex::Regex::new($re).unwrap(); let v: Vec<_> = re.find_iter(&$i).map(|m| $i.slice(m.start()..m.end())).collect(); if v.len() != 0 { 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpMatches::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_matches_static!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` /// Returns all the matched parts. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_matches_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; regex!(RE, $re); let v: Vec<_> = RE.find_iter(&$i).map(|m| $i.slice(m.start()..m.end())).collect(); if v.len() != 0 { 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpMatches::))); res } } ) ); /// `re_bytes_matches!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` /// Returns all the matched parts /// /// requires the `regexp` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_matches ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; let re = $crate::lib::regex::bytes::Regex::new($re).unwrap(); let v: Vec<_> = re.find_iter(&$i).map(|m| $i.slice(m.start()..m.end())).collect(); if v.len() != 0 { 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpMatches::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_bytes_matches_static!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` /// Returns all the matched parts. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_matches_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; regex_bytes!(RE, $re); let v: Vec<_> = RE.find_iter(&$i).map(|m| $i.slice(m.start()..m.end())).collect(); if v.len() != 0 { 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpMatches::))); res } } ) ); /// `re_capture!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` /// Returns the first capture group /// /// requires the `regexp` feature #[macro_export(local_inner_macros)] macro_rules! re_capture ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; let re = $crate::lib::regex::Regex::new($re).unwrap(); 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpCapture::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_capture_static!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` /// Returns the first capture group. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_capture_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; regex!(RE, $re); 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpCapture::))); res } } ) ); /// `re_bytes_capture!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` /// Returns the first capture group /// /// requires the `regexp` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_capture ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; let re = $crate::lib::regex::bytes::Regex::new($re).unwrap(); 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpCapture::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_bytes_capture_static!(regexp) => &[T] -> IResult<&[T], Vec<&[T]>>` /// Returns the first capture group. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_capture_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; regex_bytes!(RE, $re); 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpCapture::))); res } } ) ); /// `re_captures!(regexp) => &[T] -> IResult<&[T], Vec>>` /// Returns all the capture groups /// /// requires the `regexp` feature #[macro_export(local_inner_macros)] macro_rules! re_captures ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; let re = $crate::lib::regex::Regex::new($re).unwrap(); let v: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.len() != 0 { 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpCapture::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_captures_static!(regexp) => &[T] -> IResult<&[T], Vec>>` /// Returns all the capture groups. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_captures_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; regex!(RE, $re); let v: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.len() != 0 { 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpCapture::))); res } } ) ); /// `re_bytes_captures!(regexp) => &[T] -> IResult<&[T], Vec>>` /// Returns all the capture groups /// /// requires the `regexp` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_captures ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; let re = $crate::lib::regex::bytes::Regex::new($re).unwrap(); let v: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.len() != 0 { 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpCapture::))); res } } ) ); #[cfg(feature = "regexp_macros")] /// `re_bytes_captures_static!(regexp) => &[T] -> IResult<&[T], Vec>>` /// Returns all the capture groups. Regular expression calculated at compile time /// /// requires the `regexp_macros` feature #[macro_export(local_inner_macros)] macro_rules! re_bytes_captures_static ( ($i:expr, $re:expr) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,ErrorKind,IResult}; use $crate::Slice; regex_bytes!(RE, $re); let v: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.len() != 0 { 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 { let res: IResult<_,_> = Err(Err::Error(error_position!($i, ErrorKind::RegexpCapture::))); res } } ) ); #[cfg(test)] mod tests { #[cfg(feature = "alloc")] use lib::std::vec::Vec; use util::ErrorKind; use internal::Err; #[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"))); } #[cfg(feature = "regexp_macros")] #[test] fn re_match_static() { named!(rm<&str,&str>, re_match_static!(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 = "regexp_macros")] #[test] fn re_find_static() { named!(rm<&str,&str>, re_find_static!(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 = "regexp_macros")] #[cfg(feature = "alloc")] #[test] fn re_matches_static() { named!(rm< &str,Vec<&str> >, re_matches_static!(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")] #[cfg(feature = "regexp_macros")] #[test] fn re_capture_static() { named!(rm< &str,Vec<&str> >, re_capture_static!(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> >, 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"], ] )) ); } #[cfg(feature = "alloc")] #[cfg(feature = "regexp_macros")] #[test] fn re_captures_static() { named!(rm< &str,Vec> >, re_captures_static!(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"[..])) ); } #[cfg(feature = "regexp_macros")] #[test] fn re_bytes_match_static() { named!(rm, re_bytes_match_static!(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 = "regexp_macros")] #[test] fn re_bytes_find_static() { named!(rm, re_bytes_find_static!(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>, 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")] #[cfg(feature = "regexp_macros")] #[test] fn re_bytes_matches_static() { named!( rm>, re_bytes_matches_static!(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>, 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")] #[cfg(feature = "regexp_macros")] #[test] fn re_bytes_capture_static() { named!( rm>, re_bytes_capture_static!(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>>, 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"[..], ], ] )) ); } #[cfg(feature = "alloc")] #[cfg(feature = "regexp_macros")] #[test] fn re_bytes_captures_static() { named!( rm>>, re_bytes_captures_static!(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"[..], ], ] )) ); } } nom-4.2.3/src/sequence.rs010064400007670000024000000662751344541017100135170ustar0000000000000000/// `tuple!(I->IResult, I->IResult, ... I->IResult) => I -> IResult` /// 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::ErrorKind; /// # use nom::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 -> IResult) => I -> IResult` /// pair(X,Y), returns (x,y) /// #[macro_export(local_inner_macros)] macro_rules! pair( ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( { tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) } ); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( pair!($i, $submac!($($args)*), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( pair!($i, call!($f), $submac!($($args)*)); ); ($i:expr, $f:expr, $g:expr) => ( pair!($i, call!($f), call!($g)); ); ); /// `separated_pair!(I -> IResult, I -> IResult, I -> IResult) => I -> IResult` /// separated_pair(X,sep,Y) returns (x,y) #[macro_export(local_inner_macros)] macro_rules! separated_pair( ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => ( { use $crate::lib::std::result::Result::*; match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) { Err(e) => Err(e), Ok((i1, (o1, _, o2))) => { Ok((i1, (o1, o2))) } } } ); ($i:expr, $f:expr, $($rest:tt)+) => ( separated_pair!($i, call!($f), $($rest)*); ); ); /// `preceded!(I -> IResult, I -> IResult) => I -> IResult` /// preceded(opening, X) returns X #[macro_export(local_inner_macros)] macro_rules! preceded( ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { Err(e) => Err(e), Ok((remaining, (_,o))) => { Ok((remaining, o)) } } } ); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( preceded!($i, $submac!($($args)*), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( preceded!($i, call!($f), $submac!($($args)*)); ); ($i:expr, $f:expr, $g:expr) => ( preceded!($i, call!($f), call!($g)); ); ); /// `terminated!(I -> IResult, I -> IResult) => I -> IResult` /// terminated(X, closing) returns X #[macro_export(local_inner_macros)] macro_rules! terminated( ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( { use $crate::lib::std::result::Result::*; match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { Err(e) => Err(e), Ok((remaining, (o,_))) => { Ok((remaining, o)) } } } ); ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => ( terminated!($i, $submac!($($args)*), call!($g)); ); ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => ( terminated!($i, call!($f), $submac!($($args)*)); ); ($i:expr, $f:expr, $g:expr) => ( terminated!($i, call!($f), call!($g)); ); ); /// `delimited!(I -> IResult, I -> IResult, I -> IResult) => I -> IResult` /// delimited(opening, X, closing) returns X /// /// ``` /// # #[macro_use] extern crate nom; /// named!(bracketed, /// delimited!( /// tag!("("), /// take_until!(")"), /// tag!(")") /// ) /// ); /// /// # fn main() { /// let input = &b"(test)"[..]; /// assert_eq!(bracketed(input), Ok((&b""[..], &b"test"[..]))); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! delimited( ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => ( { use $crate::lib::std::result::Result::*; match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) { Err(e) => Err(e), Ok((i1, (_, o, _))) => { Ok((i1, o)) } } } ); ($i:expr, $f:expr, $($rest:tt)+) => ( delimited!($i, call!($f), $($rest)*); ); ); /// `do_parse!(I->IResult >> I->IResult >> ... I->IResult , ( O ) ) => I -> IResult` /// 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::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 = vec!(42, 2, 3, 4, 5); /// let result_a: Vec = vec!(3, 4); /// let rest_a: Vec = 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 = vec!(42, 5, 3, 4, 5); /// assert_eq!(tag_length_value(&b[..]), Err(Err::Incomplete(Needed::Size(5)))); /// # } /// ``` /// /// the result is a tuple, so you can return multiple sub results, like /// this: /// `do_parse!(I->IResult >> I->IResult >> ... I->IResult , ( O, P ) ) => I -> IResult` /// /// ``` /// # #[macro_use] extern crate nom; /// use nom::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)*); ); ); #[macro_export] macro_rules! nom_compile_error ( (( $(args:tt)* )) => ( compile_error!($($args)*) ); ); #[cfg(test)] mod tests { use internal::{Err, IResult, Needed}; use util::ErrorKind; use nom::be_u16; #[cfg(feature = "alloc")] #[cfg(feature = "verbose-errors")] use lib::std::vec::Vec; // reproduce the tag and take macros, because of module import order macro_rules! tag ( ($i:expr, $inp: expr) => ( { #[inline(always)] fn as_bytes(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::need_more; 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<_,_,u32> = if reduced != b { Err($crate::Err::Error(error_position!($i, $crate::ErrorKind::Tag::))) } else if m < blen { need_more($i, Needed::Size(blen)) } else { Ok((&$i[blen..], reduced)) }; res } ); ); macro_rules! take ( ($i:expr, $count:expr) => ( { use $crate::need_more; let cnt = $count as usize; let res:IResult<&[u8],&[u8],u32> = if $i.len() < cnt { need_more($i, Needed::Size(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, } #[cfg(all(feature = "std", feature = "verbose-errors"))] use util::{add_error_pattern, error_to_list, print_error}; #[cfg(feature = "verbose-errors")] use verbose_errors::Context; #[cfg(feature = "std")] #[cfg(feature = "verbose-errors")] #[cfg_attr(rustfmt, rustfmt_skip)] fn error_to_string(e: &Context) -> &'static str { let v: Vec<(P, ErrorKind)> = 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> = 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() } }*/ #[cfg(feature = "verbose-errors")] #[cfg(feature = "std")] use std::collections; #[cfg_attr(rustfmt, rustfmt_skip)] #[cfg(feature = "std")] #[cfg(feature = "verbose-errors")] #[test] fn err() { named!(err_test, alt!( tag!("abcd") | preceded!( tag!("efgh"), return_error!( ErrorKind::Custom(42), do_parse!( tag!("ijkl") >> res: return_error!(ErrorKind::Custom(128), 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::Custom(42), error_position!(blah, ErrorKind::Tag))))); assert_eq!(res_b, Err(Err::Failure(error_node_position!(&b"ijklblah"[..], ErrorKind::Custom(42), error_node_position!(blah, ErrorKind::Custom(128), error_position!(blah, ErrorKind::Tag)))))); assert_eq!(res_c, Ok((&b""[..], &b"mnop"[..]))); // Merr-like error matching let mut err_map = collections::HashMap::new(); assert!(add_error_pattern(&mut err_map, err_test(&b"efghpouet"[..]), "missing `ijkl` tag")); assert!(add_error_pattern(&mut err_map, err_test(&b"efghijklpouet"[..]), "missing `mnop` tag after `ijkl`")); let res_a2 = res_a.clone(); match res_a { Err(Err::Error(e)) | Err(Err::Failure(e)) => { let collected: Vec> = error_to_list(&e).iter().map(|&(_, ref e)| e.clone()).collect(); assert_eq!(collected, [ErrorKind::Custom(42), ErrorKind::Tag]); assert_eq!(error_to_string(&e), "missing `ijkl` tag"); //FIXME: why? //assert_eq!(err_map.get(&error_to_list(&e)), Some(&"missing `ijkl` tag")); assert_eq!(err_map.get(&error_to_list(&e)), None); } _ => panic!(), }; let res_b2 = res_b.clone(); match res_b { Err(Err::Error(e)) | Err(Err::Failure(e)) => { let collected: Vec> = error_to_list(&e).iter().map(|&(_, ref e)| e.clone()).collect(); assert_eq!(collected, [ErrorKind::Custom(42), ErrorKind::Custom(128), ErrorKind::Tag]); assert_eq!(error_to_string(&e), "missing `mnop` tag after `ijkl`"); //FIXME: why? //assert_eq!(err_map.get(&error_to_list(&e)), Some(&"missing `mnop` tag after `ijkl`")); assert_eq!(err_map.get(&error_to_list(&e)), None); } _ => panic!(), }; print_error(a, res_a2); print_error(b, res_b2); } #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(unused_variables)] #[test] fn add_err() { named!(err_test, preceded!( tag!("efgh"), add_return_error!( ErrorKind::Custom(42u32), do_parse!( tag!("ijkl") >> res: add_return_error!(ErrorKind::Custom(128u32), 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), 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_c, Ok((&b""[..], &b"mnop"[..]))); } #[cfg_attr(rustfmt, 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::Size(3))) ); assert_eq!( pair_abc_def(&b"abcd"[..]), Err(Err::Incomplete(Needed::Size(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::Size(3))) ); assert_eq!( sep_pair_abc_def(&b"abc,d"[..]), Err(Err::Incomplete(Needed::Size(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::Size(4))) ); assert_eq!( preceded_abcd_efgh(&b"abcde"[..]), Err(Err::Incomplete(Needed::Size(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::Size(4))) ); assert_eq!( terminated_abcd_efgh(&b"abcde"[..]), Err(Err::Incomplete(Needed::Size(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::Size(3))) ); assert_eq!( delimited_abc_def_ghi(&b"abcde"[..]), Err(Err::Incomplete(Needed::Size(3))) ); assert_eq!( delimited_abc_def_ghi(&b"abcdefgh"[..]), Err(Err::Incomplete(Needed::Size(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::Size(3)))); assert_eq!( tuple_3(&b"abcde"[..]), Err(Err::Incomplete(Needed::Size(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::Size(4))) ); assert_eq!( do_parser(&b"abcdefghef"[..]), Err(Err::Incomplete(Needed::Size(4))) ); } #[cfg_attr(rustfmt, rustfmt_skip)] #[test] fn do_parse_dependency() { use nom::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::Size(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") >> ( () ) ); } */ } nom-4.2.3/src/simple_errors.rs010064400007670000024000000143751344000023700145570ustar0000000000000000//! Error management //! //! Depending on a compilation flag, the content of the `Context` enum //! can change. In the default case, it will only have one variant: //! `Context::Code(I, ErrorKind)` (with `I` and `E` configurable). //! It contains an error code and the input position that triggered it. //! //! If you activate the `verbose-errors` compilation flags, it will add another //! variant to the enum: `Context::List(Vec<(I, ErrorKind)>)`. //! This variant aggregates positions and error codes as the code backtracks //! through the nested parsers. //! The verbose errors feature allows for very flexible error management: //! you can know precisely which parser got to which part of the input. //! The main drawback is that it is a lot slower than default error //! management. use lib::std::convert::From; use util::{Convert, ErrorKind}; #[derive(Debug, Clone, PartialEq)] pub enum Context { Code(I, ErrorKind), } impl, F, E: From> Convert> for Context { fn convert(c: Context) -> Self { let Context::Code(i, e) = c; Context::Code(i.into(), ErrorKind::convert(e)) } } impl Context { /// Convert Err into ErrorKind. /// /// This allows application code to use ErrorKind and stay independent from the verbose-errors features activation. pub fn into_error_kind(self) -> ErrorKind { let Context::Code(_, e) = self; ErrorKind::convert(e) } } /* impl IResult { /// Maps a `IResult` to `IResult` by appling a function /// to a contained `Error` value, leaving `Done` and `Incomplete` value /// untouched. #[inline] pub fn map_err(self, f: F) -> IResult where F: FnOnce(Err) -> Err { match self { Error(e) => Error(f(e)), Incomplete(n) => Incomplete(n), Done(i, o) => Done(i, o), } } /// Unwrap the contained `Error(E)` value, or panic if the `IResult` is not /// `Error`. pub fn unwrap_err(self) -> Err { match self { Error(e) => e, Done(_, _) => panic!("unwrap_err() called on an IResult that is Done"), Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"), } } /// Convert the IResult to a std::result::Result pub fn to_full_result(self) -> Result> { match self { Done(_, o) => Ok(o), Incomplete(n) => Err(IError::Incomplete(n)), Error(e) => Err(IError::Error(e)) } } /// Convert the IResult to a std::result::Result, or panic if the `IResult` is `Incomplete` pub fn to_result(self) -> Result> { match self { Done(_, o) => Ok(o), Error(e) => Err(e), Incomplete(_) => panic!("to_result() called on an IResult that is Incomplete") } } } #[cfg(feature = "std")] use $crate::lib::std::any::Any; #[cfg(feature = "std")] use $crate::lib::std::{error,fmt}; #[cfg(feature = "std")] impl error::Error for Err { fn description(&self) -> &str { self.description() } } #[cfg(feature = "std")] impl fmt::Display for Err { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) } } */ /// translate parser result from IResult to IResult with a custom type /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::IResult; /// # use std::convert::From; /// # use nom::Context; /// # use nom::Err; /// # use nom::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 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; use $crate::{Convert,Context,ErrorKind}; match $submac!($i, $($args)*) { Ok((i,o)) => Ok((i,o)), Err(e) => { let e2 = match e { Err::Error(err) => { let Context::Code(i, code) = err; let code2: ErrorKind<$t> = ErrorKind::convert(code); Err::Error(Context::Code(i, code2)) }, Err::Failure(err) => { let Context::Code(i, code) = err; let code2: ErrorKind<$t> = ErrorKind::convert(code); Err::Failure(Context::Code(i, code2)) }, Err::Incomplete(e) => Err::Incomplete(e), }; Err(e2) } } } ); ($i:expr, $t:ty, $f:expr) => ( fix_error!($i, $t, call!($f)); ); ); /// `flat_map!(R -> IResult, S -> IResult) => R -> IResult` /// /// combines a parser R -> IResult and /// a parser S -> IResult to return another /// parser R -> IResult #[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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Convert,Err}; ($submac!($i, $($args)*)).and_then(|(i,o)| { match $submac2!(o, $($args2)*) { Err(e) => Err(Err::convert(e)), Ok((_, o2)) => Ok((i, o2)) } }) } ); ); nom-4.2.3/src/str.rs010064400007670000024000000522171344541017100125060ustar0000000000000000//! Parsers and helper functions operating on strings, especially useful when writing parsers for //! text-based formats. /// `tag_s!(&str) => &str -> IResult<&str, &str>` /// declares a string as a suite to recognize /// /// consumes the recognized characters /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::IResult; /// # fn main() { /// fn test(input: &str) -> IResult<&str, &str> { /// tag_s!(input, "abcd") /// } /// let r = test("abcdefgh"); /// assert_eq!(r,Ok(("efgh", "abcd"))); /// # } /// ``` #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `tag` instead")] macro_rules! tag_s ( ($i:expr, $tag: expr) => ( { tag!($i, $tag) } ); ); /// `tag_no_case_s!(&str) => &str -> IResult<&str, &str>` /// declares a case-insensitive string as a suite to recognize /// /// consumes the recognized characters /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::IResult; /// # use nom::InputLength; /// #[cfg(feature = "alloc")] /// # fn main() { /// fn test(input: &str) -> IResult<&str, &str> { /// tag_no_case_s!(input, "ABcd") /// } /// let r = test("aBCdefgh"); /// assert_eq!(r,Ok(("efgh", "aBCd"))); /// # } /// # #[cfg(not(feature = "alloc"))] /// # fn main() {} /// ``` #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `tag_no_case` instead")] macro_rules! tag_no_case_s ( ($i:expr, $tag: expr) => ( { tag_no_case!($i, $tag) } ); ); /// `take_s!(nb) => &str -> IResult<&str, &str>` /// generates a parser consuming the specified number of characters /// /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// // Desmond parser /// named!(take5<&str,&str>, take_s!( 5 ) ); /// /// let a = "abcdefgh"; /// /// assert_eq!(take5(a),Ok(("fgh", "abcde"))); /// /// let b = "12345"; /// /// assert_eq!(take5(b),Ok(("", "12345"))); /// # } /// ``` #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `take` instead")] macro_rules! take_s ( ($i:expr, $count:expr) => ( { let input = $i; let cnt = $count as usize; take!(input, cnt) } ); ); /// `is_not_s!(&str) => &str -> IResult<&str, &str>` /// returns the longest list of characters that do not appear in the provided array /// /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!( not_space<&str,&str>, is_not_s!( " \t\r\n" ) ); /// /// let r = not_space("abcdefgh\nijkl"); /// assert_eq!(r,Ok(("\nijkl", "abcdefgh"))); /// # } /// ``` #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `is_not` instead")] macro_rules! is_not_s ( ($input:expr, $arr:expr) => ( { is_not!($input, $arr) } ); ); /// `is_a_s!(&str) => &str -> IResult<&str, &str>` /// returns the longest list of characters that appear in the provided array /// /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(abcd<&str, &str>, is_a_s!( "abcd" )); /// /// let r1 = abcd("aaaaefgh"); /// assert_eq!(r1,Ok(("efgh", "aaaa"))); /// /// let r2 = abcd("dcbaefgh"); /// assert_eq!(r2,Ok(("efgh", "dcba"))); /// # } /// ``` #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `is_a` instead")] macro_rules! is_a_s ( ($input:expr, $arr:expr) => ( { is_a!($input, $arr) } ); ); /// `take_while_s!(char -> bool) => &str -> IResult<&str, &str>` /// returns the longest list of characters until the provided function fails. /// /// The argument is either a function `char -> bool` or a macro returning a `bool /// /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) } /// named!( alpha<&str,&str>, take_while_s!( alphabetic ) ); /// /// let r = alpha("abcd\nefgh"); /// assert_eq!(r,Ok(("\nefgh", "abcd"))); /// # } /// ``` #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `take_while` instead")] macro_rules! take_while_s ( ($input:expr, $submac:ident!( $($args:tt)* )) => ( { take_while!($input, $submac!($($args)*)) } ); ($input:expr, $f:expr) => ( take_while_s!($input, call!($f)); ); ); /// `take_while1_s!(char -> bool) => &str -> IResult<&str, &str>` /// returns the longest (non empty) list of characters until the provided function fails. /// /// The argument is either a function `char -> bool` or a macro returning a `bool` /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::is_alphanumeric; /// # fn main() { /// fn alphabetic(chr: char) -> bool { (chr >= 0x41 as char && chr <= 0x5A as char) || (chr >= 0x61 as char && chr <= 0x7A as char) } /// named!( alpha<&str,&str>, take_while1_s!( alphabetic ) ); /// /// let r = alpha("abcd\nefgh"); /// assert_eq!(r, Ok(("\nefgh", "abcd"))); /// # } /// ``` #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `take_while1` instead")] macro_rules! take_while1_s ( ($input:expr, $submac:ident!( $($args:tt)* )) => ( take_while1!($input, $submac!($($args)*)) ); ($input:expr, $f:expr) => ( take_while1_s!($input, call!($f)); ); ); /// `take_till_s!(char -> bool) => &str -> IResult<&str, &str>` /// returns the longest list of characters until the provided function succeeds /// /// The argument is either a function `char -> bool` or a macro returning a `bool #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `take_till` instead")] macro_rules! take_till_s ( ($input:expr, $submac:ident!( $($args:tt)* )) => ( { take_till!($input, $submac!($($args)*)) } ); ($input:expr, $f:expr) => ( take_till_s!($input, call!($f)); ); ); /// `take_till1_s!(char -> bool) => &str -> IResult<&str, &str>` /// returns the longest non empty list of characters until the provided function succeeds /// /// The argument is either a function `char -> bool` or a macro returning a `bool #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `take_till1` instead")] macro_rules! take_till1_s ( ($input:expr, $submac:ident!( $($args:tt)* )) => ( { take_till1!($input, $submac!($($args)*)) } ); ($input:expr, $f:expr) => ( take_till1_s!($input, call!($f)); ); ); /// `take_until_and_consume_s!(&str) => &str -> IResult<&str, &str>` /// generates a parser consuming all chars until the specified string is found and consumes it #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `take_until_and_consume` instead")] macro_rules! take_until_and_consume_s ( ($input:expr, $substr:expr) => ( { take_until_and_consume!($input, $substr) } ); ); /// `take_until_s!(&str) => &str -> IResult<&str, &str>` /// generates a parser consuming all chars until the specified string is found and leaves it in the remaining input #[macro_export(local_inner_macros)] #[deprecated(since = "4.0.0", note = "Please use `take_until` instead")] macro_rules! take_until_s ( ($input:expr, $substr:expr) => ( { take_until!($input, $substr) } ); ); #[cfg(test)] mod test { use {Err, ErrorKind, IResult}; #[test] fn tag_str_succeed() { const INPUT: &str = "Hello World!"; const TAG: &str = "Hello"; fn test(input: &str) -> IResult<&str, &str> { tag_s!(input, TAG) } match test(INPUT) { Ok((extra, output)) => { assert!( extra == " World!", "Parser `tag_s` consumed leftover input." ); assert!( output == TAG, "Parser `tag_s` doesn't return the tag it matched on success. \ Expected `{}`, got `{}`.", TAG, output ); } other => panic!( "Parser `tag_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn tag_str_incomplete() { const INPUT: &str = "Hello"; const TAG: &str = "Hello World!"; match tag_s!(INPUT, TAG) { Err(Err::Incomplete(_)) => (), other => { panic!( "Parser `tag_s` didn't require more input when it should have. \ Got `{:?}`.", other ); } }; } #[test] fn tag_str_error() { const INPUT: &str = "Hello World!"; const TAG: &str = "Random"; // TAG must be closer than INPUT. match tag_s!(INPUT, TAG) { Err(Err::Error(_)) => (), other => { panic!( "Parser `tag_s` didn't fail when it should have. Got `{:?}`.`", other ); } }; } #[test] fn take_s_succeed() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const CONSUMED: &str = "βèƒôřèÂßÇ"; const LEFTOVER: &str = "áƒƭèř"; match take_s!(INPUT, 9) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `take_s` consumed leftover input. Leftover `{}`.", extra ); assert!( output == CONSUMED, "Parser `take_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.", CONSUMED, output ); } other => panic!( "Parser `take_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_until_s_succeed() { const INPUT: &str = "βèƒôřèÂßÇ∂áƒƭèř"; const FIND: &str = "ÂßÇ∂"; const CONSUMED: &str = "βèƒôřè"; const LEFTOVER: &str = "ÂßÇ∂áƒƭèř"; match take_until_s!(INPUT, FIND) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `take_until_s`\ consumed leftover input. Leftover `{}`.", extra ); assert!( output == CONSUMED, "Parser `take_until_s`\ doens't return the string it consumed on success. Expected `{}`, got `{}`.", CONSUMED, output ); } other => panic!( "Parser `take_until_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_s_incomplete() { const INPUT: &str = "βèƒôřèÂßÇá"; match take_s!(INPUT, 13) { Err(Err::Incomplete(_)) => (), other => panic!( "Parser `take_s` didn't require more input when it should have. \ Got `{:?}`.", other ), } } use internal::Needed; pub fn is_alphabetic(c: char) -> bool { (c as u8 >= 0x41 && c as u8 <= 0x5A) || (c as u8 >= 0x61 && c as u8 <= 0x7A) } #[test] fn take_while_s() { named!(f<&str,&str>, take_while_s!(is_alphabetic)); let a = ""; let b = "abcd"; let c = "abcd123"; let d = "123"; assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(f(&c[..]), Ok((&d[..], &b[..]))); assert_eq!(f(&d[..]), Ok((&d[..], &a[..]))); } #[test] fn take_while1_s() { named!(f<&str,&str>, take_while1_s!(is_alphabetic)); let a = ""; let b = "abcd"; let c = "abcd123"; let d = "123"; assert_eq!(f(&a[..]), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(f(&b[..]), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(f(&c[..]), Ok((&"123"[..], &b[..]))); assert_eq!( f(&d[..]), Err(Err::Error(error_position!(&d[..], ErrorKind::TakeWhile1))) ); } #[test] fn take_till_s_succeed() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const CONSUMED: &str = "βèƒôřèÂßÇ"; const LEFTOVER: &str = "áƒƭèř"; fn till_s(c: char) -> bool { c == 'á' } fn test(input: &str) -> IResult<&str, &str> { take_till_s!(input, till_s) } match test(INPUT) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `take_till_s` consumed leftover input." ); assert!( output == CONSUMED, "Parser `take_till_s` doesn't return the string it consumed on success. \ Expected `{}`, got `{}`.", CONSUMED, output ); } other => panic!( "Parser `take_till_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_while_s_succeed_none() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const CONSUMED: &str = ""; const LEFTOVER: &str = "βèƒôřèÂßÇáƒƭèř"; fn while_s(c: char) -> bool { c == '9' } fn test(input: &str) -> IResult<&str, &str> { take_while_s!(input, while_s) } match test(INPUT) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `take_while_s` consumed leftover input." ); assert!( output == CONSUMED, "Parser `take_while_s` doesn't return the string it consumed on success. \ Expected `{}`, got `{}`.", CONSUMED, output ); } other => panic!( "Parser `take_while_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn is_not_s_succeed() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const AVOID: &str = "£úçƙ¥á"; const CONSUMED: &str = "βèƒôřèÂßÇ"; const LEFTOVER: &str = "áƒƭèř"; fn test(input: &str) -> IResult<&str, &str> { is_not_s!(input, AVOID) } match test(INPUT) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `is_not_s` consumed leftover input. Leftover `{}`.", extra ); assert!( output == CONSUMED, "Parser `is_not_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.", CONSUMED, output ); } other => panic!( "Parser `is_not_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_until_and_consume_s_succeed() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const FIND: &str = "ÂßÇ"; const OUTPUT: &str = "βèƒôřè"; const LEFTOVER: &str = "áƒƭèř"; match take_until_and_consume_s!(INPUT, FIND) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `take_until_and_consume_s`\ consumed leftover input. Leftover `{}`.", extra ); assert!( output == OUTPUT, "Parser `take_until_and_consume_s`\ doens't return the string it selected on success. Expected `{}`, got `{}`.", OUTPUT, output ); } other => panic!( "Parser `take_until_and_consume_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_while_s_succeed_some() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const CONSUMED: &str = "βèƒôřèÂßÇ"; const LEFTOVER: &str = "áƒƭèř"; fn while_s(c: char) -> bool { c == 'β' || c == 'è' || c == 'ƒ' || c == 'ô' || c == 'ř' || c == 'è' || c == 'Â' || c == 'ß' || c == 'Ç' } fn test(input: &str) -> IResult<&str, &str> { take_while_s!(input, while_s) } match test(INPUT) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `take_while_s` consumed leftover input." ); assert!( output == CONSUMED, "Parser `take_while_s` doesn't return the string it consumed on success. \ Expected `{}`, got `{}`.", CONSUMED, output ); } other => panic!( "Parser `take_while_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn is_not_s_fail() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const AVOID: &str = "βúçƙ¥"; fn test(input: &str) -> IResult<&str, &str> { is_not_s!(input, AVOID) } match test(INPUT) { Err(Err::Error(_)) => (), other => panic!( "Parser `is_not_s` didn't fail when it should have. Got `{:?}`.", other ), }; } #[test] fn take_while1_s_succeed() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const CONSUMED: &str = "βèƒôřèÂßÇ"; const LEFTOVER: &str = "áƒƭèř"; fn while1_s(c: char) -> bool { c == 'β' || c == 'è' || c == 'ƒ' || c == 'ô' || c == 'ř' || c == 'è' || c == 'Â' || c == 'ß' || c == 'Ç' } fn test(input: &str) -> IResult<&str, &str> { take_while1_s!(input, while1_s) } match test(INPUT) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `take_while1_s` consumed leftover input." ); assert!( output == CONSUMED, "Parser `take_while1_s` doesn't return the string it consumed on success. \ Expected `{}`, got `{}`.", CONSUMED, output ); } other => panic!( "Parser `take_while1_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_until_and_consume_s_incomplete() { const INPUT: &str = "βèƒôřè"; const FIND: &str = "βèƒôřèÂßÇ"; match take_until_and_consume_s!(INPUT, FIND) { Err(Err::Incomplete(_)) => (), other => panic!( "Parser `take_until_and_consume_s` didn't require more input when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_until_s_incomplete() { const INPUT: &str = "βèƒôřè"; const FIND: &str = "βèƒôřèÂßÇ"; match take_until_s!(INPUT, FIND) { Err(Err::Incomplete(_)) => (), other => panic!( "Parser `take_until_s` didn't require more input when it should have. \ Got `{:?}`.", other ), }; } #[test] fn is_a_s_succeed() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const MATCH: &str = "βèƒôřèÂßÇ"; const CONSUMED: &str = "βèƒôřèÂßÇ"; const LEFTOVER: &str = "áƒƭèř"; fn test(input: &str) -> IResult<&str, &str> { is_a_s!(input, MATCH) } match test(INPUT) { Ok((extra, output)) => { assert!( extra == LEFTOVER, "Parser `is_a_s` consumed leftover input. Leftover `{}`.", extra ); assert!( output == CONSUMED, "Parser `is_a_s` doens't return the string it consumed on success. Expected `{}`, got `{}`.", CONSUMED, output ); } other => panic!( "Parser `is_a_s` didn't succeed when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_while1_s_fail() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; fn while1_s(c: char) -> bool { c == '9' } fn test(input: &str) -> IResult<&str, &str> { take_while1_s!(input, while1_s) } match test(INPUT) { Err(Err::Error(_)) => (), other => panic!( "Parser `take_while1_s` didn't fail when it should have. \ Got `{:?}`.", other ), }; } #[test] fn is_a_s_fail() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const MATCH: &str = "Ûñℓúçƙ¥"; fn test(input: &str) -> IResult<&str, &str> { is_a_s!(input, MATCH) } match test(INPUT) { Err(Err::Error(_)) => (), other => panic!( "Parser `is_a_s` didn't fail when it should have. Got `{:?}`.", other ), }; } #[test] fn take_until_and_consume_s_error() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const FIND: &str = "Ráñδô₥"; match take_until_and_consume_s!(INPUT, FIND) { Err(Err::Incomplete(_)) => (), other => panic!( "Parser `take_until_and_consume_s` didn't fail when it should have. \ Got `{:?}`.", other ), }; } #[test] fn take_until_s_error() { const INPUT: &str = "βèƒôřèÂßÇáƒƭèř"; const FIND: &str = "Ráñδô₥"; match take_until_s!(INPUT, FIND) { Err(Err::Incomplete(_)) => (), other => panic!( "Parser `take_until_and_consume_s` didn't fail when it should have. \ Got `{:?}`.", other ), }; } #[test] #[cfg(feature = "alloc")] fn recognize_is_a_s() { let a = "aabbab"; let b = "ababcd"; named!(f <&str,&str>, recognize!(many1!(complete!(alt!( tag_s!("a") | tag_s!("b") ))))); assert_eq!(f(&a[..]), Ok((&a[6..], &a[..]))); assert_eq!(f(&b[..]), Ok((&b[4..], &b[..4]))); } #[test] fn utf8_indexing() { named!(dot(&str) -> &str, tag_s!(".") ); let _ = dot("點"); } #[cfg(feature = "alloc")] #[test] fn case_insensitive() { named!(test<&str,&str>, tag_no_case!("ABcd")); 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"))); } } nom-4.2.3/src/traits.rs010064400007670000024000000660431344541017100132060ustar0000000000000000//! Traits input types have to implement to work with nom combinators //! use internal::{Err, IResult, Needed}; use lib::std::ops::{Range, RangeFrom, RangeFull, RangeTo}; use lib::std::iter::Enumerate; use lib::std::slice::Iter; use lib::std::iter::Map; use lib::std::str::Chars; use lib::std::str::CharIndices; use lib::std::str::FromStr; use lib::std::str::from_utf8; #[cfg(feature = "alloc")] use lib::std::string::String; #[cfg(feature = "alloc")] use lib::std::vec::Vec; use memchr; #[cfg(feature = "verbose-errors")] use verbose_errors::Context; #[cfg(not(feature = "verbose-errors"))] use simple_errors::Context; use util::ErrorKind; /// abstract method to calculate the input length pub trait InputLength { /// calculates the input length, as indicated by its name, /// and the name of the trait itself #[inline] fn input_len(&self) -> usize; } impl<'a, T> InputLength for &'a [T] { #[inline] fn input_len(&self) -> usize { self.len() } } impl<'a> InputLength for &'a str { #[inline] fn input_len(&self) -> usize { self.len() } } impl<'a> InputLength for (&'a [u8], usize) { #[inline] fn input_len(&self) -> usize { //println!("bit input length for ({:?}, {}):", self.0, self.1); //println!("-> {}", self.0.len() * 8 - self.1); self.0.len() * 8 - self.1 } } /// 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 fn offset(&self, second: &Self) -> usize; } impl Offset for [u8] { fn offset(&self, second: &Self) -> usize { let fst = self.as_ptr(); let snd = second.as_ptr(); snd as usize - fst as usize } } impl<'a> Offset for &'a [u8] { fn offset(&self, second: &Self) -> usize { let fst = self.as_ptr(); let snd = second.as_ptr(); snd as usize - fst as usize } } impl Offset for str { fn offset(&self, second: &Self) -> usize { let fst = self.as_ptr(); let snd = second.as_ptr(); snd as usize - fst as usize } } impl<'a> Offset for &'a str { fn offset(&self, second: &Self) -> usize { let fst = self.as_ptr(); let snd = second.as_ptr(); snd as usize - fst as usize } } /// casts the input type to a byte slice pub trait AsBytes { fn as_bytes(&self) -> &[u8]; } impl<'a> AsBytes for &'a str { #[inline(always)] fn as_bytes(&self) -> &[u8] { ::as_bytes(self) } } impl AsBytes for str { #[inline(always)] fn as_bytes(&self) -> &[u8] { self.as_ref() } } impl<'a> AsBytes for &'a [u8] { #[inline(always)] fn as_bytes(&self) -> &[u8] { *self } } impl AsBytes for [u8] { #[inline(always)] fn as_bytes(&self) -> &[u8] { self } } macro_rules! as_bytes_array_impls { ($($N:expr)+) => { $( impl<'a> AsBytes for &'a [u8; $N] { #[inline(always)] fn as_bytes(&self) -> &[u8] { *self } } impl AsBytes for [u8; $N] { #[inline(always)] fn as_bytes(&self) -> &[u8] { self } } )+ }; } as_bytes_array_impls! { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 } /// transforms common types to a char for basic token parsing pub trait AsChar { /// makes a char from self #[inline] fn as_char(self) -> char; /// tests that self is an alphabetic character /// /// warning: for `&str` it recognizes alphabetic /// characters outside of the 52 ASCII letters #[inline] fn is_alpha(self) -> bool; /// tests that self is an alphabetic character /// or a decimal digit #[inline] fn is_alphanum(self) -> bool; /// tests that self is a decimal digit #[inline] fn is_dec_digit(self) -> bool; /// tests that self is an hex digit #[inline] fn is_hex_digit(self) -> bool; /// tests that self is an octal digit #[inline] fn is_oct_digit(self) -> bool; /// gets the len in bytes for self #[inline] fn len(self) -> usize; } impl AsChar for u8 { #[inline] fn as_char(self) -> char { self as char } #[inline] fn is_alpha(self) -> bool { (self >= 0x41 && self <= 0x5A) || (self >= 0x61 && self <= 0x7A) } #[inline] fn is_alphanum(self) -> bool { self.is_alpha() || self.is_dec_digit() } #[inline] fn is_dec_digit(self) -> bool { self >= 0x30 && self <= 0x39 } #[inline] fn is_hex_digit(self) -> bool { (self >= 0x30 && self <= 0x39) || (self >= 0x41 && self <= 0x46) || (self >= 0x61 && self <= 0x66) } #[inline] fn is_oct_digit(self) -> bool { self >= 0x30 && self <= 0x37 } #[inline] fn len(self) -> usize { 1 } } impl<'a> AsChar for &'a u8 { #[inline] fn as_char(self) -> char { *self as char } #[inline] fn is_alpha(self) -> bool { (*self >= 0x41 && *self <= 0x5A) || (*self >= 0x61 && *self <= 0x7A) } #[inline] fn is_alphanum(self) -> bool { self.is_alpha() || self.is_dec_digit() } #[inline] fn is_dec_digit(self) -> bool { *self >= 0x30 && *self <= 0x39 } #[inline] fn is_hex_digit(self) -> bool { (*self >= 0x30 && *self <= 0x39) || (*self >= 0x41 && *self <= 0x46) || (*self >= 0x61 && *self <= 0x66) } #[inline] fn is_oct_digit(self) -> bool { *self >= 0x30 && *self <= 0x37 } #[inline] fn len(self) -> usize { 1 } } impl AsChar for char { #[inline] fn as_char(self) -> char { self } #[cfg(feature = "alloc")] #[inline] fn is_alpha(self) -> bool { self.is_alphabetic() } #[cfg(not(feature = "alloc"))] #[inline] fn is_alpha(self) -> bool { unimplemented!( "error[E0658]: use of unstable library feature 'core_char_ext': the stable interface is `impl char` in later crate (see issue #32110)" ) } #[inline] fn is_alphanum(self) -> bool { self.is_alpha() || self.is_dec_digit() } #[inline] fn is_dec_digit(self) -> bool { self.is_digit(10) } #[inline] fn is_hex_digit(self) -> bool { self.is_digit(16) } #[inline] fn is_oct_digit(self) -> bool { self.is_digit(8) } #[inline] fn len(self) -> usize { self.len_utf8() } } impl<'a> AsChar for &'a char { #[inline] fn as_char(self) -> char { *self } #[inline] fn is_alpha(self) -> bool { ::is_alpha(*self) } #[inline] fn is_alphanum(self) -> bool { self.is_alpha() || self.is_dec_digit() } #[inline] fn is_dec_digit(self) -> bool { self.is_digit(10) } #[inline] fn is_hex_digit(self) -> bool { self.is_digit(16) } #[inline] fn is_oct_digit(self) -> bool { self.is_digit(8) } #[inline] fn len(self) -> usize { self.len_utf8() } } /// abstracts common iteration operations on the input type /// /// it needs a distinction between `Item` and `RawItem` because /// `&[T]` iterates on references pub trait InputIter { type Item; type RawItem; type Iter: Iterator; type IterElem: Iterator; /// returns an iterator over the elements and their byte offsets fn iter_indices(&self) -> Self::Iter; /// returns an iterator over the elements fn iter_elements(&self) -> Self::IterElem; /// finds the byte position of the element fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool; /// get the byte offset from the element's position in the stream fn slice_index(&self, count: usize) -> Option; } /// abstracts slicing operations pub trait InputTake: Sized { /// returns a slice of `count` bytes. panics if count > length fn take(&self, count: usize) -> Self; /// split the stream at the `count` byte offset. panics if count > length fn take_split(&self, count: usize) -> (Self, Self); } fn star(r_u8: &u8) -> u8 { *r_u8 } impl<'a> InputIter for &'a [u8] { type Item = u8; type RawItem = u8; type Iter = Enumerate; type IterElem = Map, fn(&u8) -> u8>; #[inline] fn iter_indices(&self) -> Self::Iter { self.iter_elements().enumerate() } #[inline] fn iter_elements(&self) -> Self::IterElem { self.iter().map(star) } #[inline] fn position

(&self, predicate: P) -> Option where P: Fn(Self::Item) -> bool, { self.iter().position(|b| predicate(*b)) } #[inline] fn slice_index(&self, count: usize) -> Option { if self.len() >= count { Some(count) } else { None } } } impl<'a> InputTake for &'a [u8] { #[inline] fn take(&self, count: usize) -> Self { &self[0..count] } #[inline] fn take_split(&self, count: usize) -> (Self, Self) { let (prefix, suffix) = self.split_at(count); (suffix, prefix) } } impl<'a> InputIter for &'a str { type Item = char; type RawItem = char; type Iter = CharIndices<'a>; type IterElem = Chars<'a>; #[inline] fn iter_indices(&self) -> Self::Iter { self.char_indices() } #[inline] fn iter_elements(&self) -> Self::IterElem { self.chars() } fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool, { for (o, c) in self.char_indices() { if predicate(c) { return Some(o); } } None } #[inline] fn slice_index(&self, count: usize) -> Option { let mut cnt = 0; for (index, _) in self.char_indices() { if cnt == count { return Some(index); } cnt += 1; } if cnt == count { return Some(self.len()); } None } } impl<'a> InputTake for &'a str { #[inline] fn take(&self, count: usize) -> Self { &self[..count] } // return byte index #[inline] fn take_split(&self, count: usize) -> (Self, Self) { (&self[count..], &self[..count]) } } /// Dummy trait used for default implementations (currently only used for `InputTakeAtPosition`). /// /// When implementing a custom input type, it is possible to use directly the /// default implementation: if the input type implements `InputLength`, `InputIter`, /// `InputTake`, `AtEof` and `Clone`, you can implement `UnspecializedInput` and get /// a default version of `InputTakeAtPosition`. /// /// For performance reasons, you might want to write a custom implementation of /// `InputTakeAtPosition` (like the one for `&[u8]`). pub trait UnspecializedInput {} use types::CompleteStr; use types::CompleteByteSlice; /// methods to take as much input as possible until the provided function returns true for the current element /// /// a large part of nom's basic parsers are built using this trait pub trait InputTakeAtPosition: Sized { type Item; fn split_at_position

(&self, predicate: P) -> IResult where P: Fn(Self::Item) -> bool; fn split_at_position1

(&self, predicate: P, e: ErrorKind) -> IResult where P: Fn(Self::Item) -> bool; } impl InputTakeAtPosition for T { type Item = ::RawItem; fn split_at_position

(&self, predicate: P) -> IResult where P: Fn(Self::Item) -> bool, { match self.position(predicate) { Some(n) => Ok(self.take_split(n)), None => { if self.at_eof() { Ok(self.take_split(self.input_len())) } else { Err(Err::Incomplete(Needed::Size(1))) } } } } fn split_at_position1

(&self, predicate: P, e: ErrorKind) -> IResult where P: Fn(Self::Item) -> bool, { match self.position(predicate) { Some(0) => Err(Err::Error(Context::Code(self.clone(), e))), Some(n) => Ok(self.take_split(n)), None => { if self.at_eof() { if self.input_len() == 0 { Err(Err::Error(Context::Code(self.clone(), e))) } else { Ok(self.take_split(self.input_len())) } } else { Err(Err::Incomplete(Needed::Size(1))) } } } } } impl<'a> InputTakeAtPosition for &'a [u8] { type Item = u8; fn split_at_position

(&self, predicate: P) -> IResult where P: Fn(Self::Item) -> bool, { match (0..self.len()).find(|b| predicate(self[*b])) { Some(i) => Ok((&self[i..], &self[..i])), None => Err(Err::Incomplete(Needed::Size(1))), } } fn split_at_position1

(&self, predicate: P, e: ErrorKind) -> IResult where P: Fn(Self::Item) -> bool, { match (0..self.len()).find(|b| predicate(self[*b])) { Some(0) => Err(Err::Error(Context::Code(self, e))), Some(i) => Ok((&self[i..], &self[..i])), None => Err(Err::Incomplete(Needed::Size(1))), } } } impl<'a> InputTakeAtPosition for CompleteByteSlice<'a> { type Item = u8; fn split_at_position

(&self, predicate: P) -> IResult where P: Fn(Self::Item) -> bool, { match (0..self.0.len()).find(|b| predicate(self.0[*b])) { Some(i) => Ok(( CompleteByteSlice(&self.0[i..]), CompleteByteSlice(&self.0[..i]), )), None => { let (i, o) = self.0.take_split(self.0.len()); Ok((CompleteByteSlice(i), CompleteByteSlice(o))) } } } fn split_at_position1

(&self, predicate: P, e: ErrorKind) -> IResult where P: Fn(Self::Item) -> bool, { match (0..self.0.len()).find(|b| predicate(self.0[*b])) { Some(0) => Err(Err::Error(Context::Code(CompleteByteSlice(self.0), e))), Some(i) => Ok(( CompleteByteSlice(&self.0[i..]), CompleteByteSlice(&self.0[..i]), )), None => { if self.0.len() == 0 { Err(Err::Error(Context::Code(CompleteByteSlice(self.0), e))) } else { Ok(( CompleteByteSlice(&self.0[self.0.len()..]), CompleteByteSlice(self.0), )) } } } } } impl<'a> InputTakeAtPosition for &'a str { type Item = char; fn split_at_position

(&self, predicate: P) -> IResult where P: Fn(Self::Item) -> bool, { match self.char_indices().find(|&(_, c)| predicate(c)) { Some((i, _)) => Ok((&self[i..], &self[..i])), None => Err(Err::Incomplete(Needed::Size(1))), } } fn split_at_position1

(&self, predicate: P, e: ErrorKind) -> IResult where P: Fn(Self::Item) -> bool, { match self.char_indices().find(|&(_, c)| predicate(c)) { Some((0, _)) => Err(Err::Error(Context::Code(self, e))), Some((i, _)) => Ok((&self[i..], &self[..i])), None => Err(Err::Incomplete(Needed::Size(1))), } } } impl<'a> InputTakeAtPosition for CompleteStr<'a> { type Item = char; fn split_at_position

(&self, predicate: P) -> IResult where P: Fn(Self::Item) -> bool, { match self.0.char_indices().find(|&(_, c)| predicate(c)) { Some((i, _)) => Ok((CompleteStr(&self.0[i..]), CompleteStr(&self.0[..i]))), None => { let (i, o) = self.0.take_split(self.0.len()); Ok((CompleteStr(i), CompleteStr(o))) } } } fn split_at_position1

(&self, predicate: P, e: ErrorKind) -> IResult where P: Fn(Self::Item) -> bool, { match self.0.char_indices().find(|&(_, c)| predicate(c)) { Some((0, _)) => Err(Err::Error(Context::Code(CompleteStr(self.0), e))), Some((i, _)) => Ok((CompleteStr(&self.0[i..]), CompleteStr(&self.0[..i]))), None => { if self.0.len() == 0 { Err(Err::Error(Context::Code(CompleteStr(self.0), e))) } else { let (i, o) = self.0.take_split(self.0.len()); Ok((CompleteStr(i), CompleteStr(o))) } } } } } /// indicates wether a comparison was successful, an error, or /// if more data was needed #[derive(Debug, PartialEq)] pub enum CompareResult { Ok, Incomplete, Error, } /// abstracts comparison operations pub trait Compare { /// compares self to another value for equality fn compare(&self, t: T) -> CompareResult; /// compares self to another value for equality /// independently of the case. /// /// warning: for `&str`, the comparison is done /// by lowercasing both strings and comparing /// the result. This is a temporary solution until /// a better one appears fn compare_no_case(&self, t: T) -> CompareResult; } impl<'a, 'b> Compare<&'b [u8]> for &'a [u8] { #[inline(always)] fn compare(&self, t: &'b [u8]) -> CompareResult { let pos = self.iter().zip(t.iter()).position(|(a, b)| a != b); match pos { Some(_) => CompareResult::Error, None => { if self.len() >= t.len() { CompareResult::Ok } else { CompareResult::Incomplete } } } /* let len = self.len(); let blen = t.len(); let m = if len < blen { len } else { blen }; let reduced = &self[..m]; let b = &t[..m]; if reduced != b { CompareResult::Error } else if m < blen { CompareResult::Incomplete } else { CompareResult::Ok } */ } #[inline(always)] fn compare_no_case(&self, t: &'b [u8]) -> CompareResult { let len = self.len(); let blen = t.len(); let m = if len < blen { len } else { blen }; let reduced = &self[..m]; let other = &t[..m]; if !reduced.iter().zip(other).all(|(a, b)| match (*a, *b) { (0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == b, (65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122) | (97...122, 65...90) => *a | 0b00_10_00_00 == *b | 0b00_10_00_00, _ => false, }) { CompareResult::Error } else if m < blen { CompareResult::Incomplete } else { CompareResult::Ok } } } impl<'a, 'b> Compare<&'b str> for &'a [u8] { #[inline(always)] fn compare(&self, t: &'b str) -> CompareResult { self.compare(AsBytes::as_bytes(t)) } #[inline(always)] fn compare_no_case(&self, t: &'b str) -> CompareResult { self.compare_no_case(AsBytes::as_bytes(t)) } } impl<'a, 'b> Compare<&'b str> for &'a str { #[inline(always)] fn compare(&self, t: &'b str) -> CompareResult { let pos = self.chars().zip(t.chars()).position(|(a, b)| a != b); match pos { Some(_) => CompareResult::Error, None => { if self.len() >= t.len() { CompareResult::Ok } else { CompareResult::Incomplete } } } } //FIXME: this version is too simple and does not use the current locale #[cfg(feature = "alloc")] #[inline(always)] fn compare_no_case(&self, t: &'b str) -> CompareResult { let pos = self .chars() .zip(t.chars()) .position(|(a, b)| a.to_lowercase().zip(b.to_lowercase()).any(|(a, b)| a != b)); match pos { Some(_) => CompareResult::Error, None => { if self.len() >= t.len() { CompareResult::Ok } else { CompareResult::Incomplete } } } } #[cfg(not(feature = "alloc"))] #[inline(always)] fn compare_no_case(&self, _: &'b str) -> CompareResult { unimplemented!() } } /// look for self in the given input stream pub trait FindToken { fn find_token(&self, token: T) -> bool; } impl<'a> FindToken for &'a [u8] { fn find_token(&self, token: u8) -> bool { memchr::memchr(token, self).is_some() } } impl<'a> FindToken for &'a str { fn find_token(&self, token: u8) -> bool { self.as_bytes().find_token(token) } } impl<'a, 'b> FindToken<&'a u8> for &'b [u8] { fn find_token(&self, token: &u8) -> bool { memchr::memchr(*token, self).is_some() } } impl<'a, 'b> FindToken<&'a u8> for &'b str { fn find_token(&self, token: &u8) -> bool { self.as_bytes().find_token(token) } } impl<'a> FindToken for &'a [u8] { fn find_token(&self, token: char) -> bool { memchr::memchr(token as u8, self).is_some() } } impl<'a> FindToken for &'a str { fn find_token(&self, token: char) -> bool { for i in self.chars() { if token == i { return true; } } false } } /// look for a substring in self pub trait FindSubstring { fn find_substring(&self, substr: T) -> Option; } impl<'a, 'b> FindSubstring<&'b [u8]> for &'a [u8] { fn find_substring(&self, substr: &'b [u8]) -> Option { let substr_len = substr.len(); if substr_len == 0 { // an empty substring is found at position 0 // This matches the behavior of str.find(""). Some(0) } else if substr_len == 1 { memchr::memchr(substr[0], self) } else if substr_len > self.len() { None } else { let max = self.len() - substr_len; let mut offset = 0; let mut haystack = &self[..]; while let Some(position) = memchr::memchr(substr[0], haystack) { offset += position; if offset > max { return None; } if &haystack[position..position + substr_len] == substr { return Some(offset); } haystack = &haystack[position + 1..]; offset += 1; } None } } } impl<'a, 'b> FindSubstring<&'b str> for &'a [u8] { fn find_substring(&self, substr: &'b str) -> Option { self.find_substring(AsBytes::as_bytes(substr)) } } impl<'a, 'b> FindSubstring<&'b str> for &'a str { //returns byte index fn find_substring(&self, substr: &'b str) -> Option { self.find(substr) } } /// used to integrate str's parse() method pub trait ParseTo { fn parse_to(&self) -> Option; } impl<'a, R: FromStr> ParseTo for &'a [u8] { fn parse_to(&self) -> Option { from_utf8(self).ok().and_then(|s| s.parse().ok()) } } impl<'a, R: FromStr> ParseTo for &'a str { fn parse_to(&self) -> Option { self.parse().ok() } } /// slicing operations using ranges /// /// this trait is loosely based on /// `Index`, but can actually return /// something else than a `&[T]` or `&str` pub trait Slice { #[inline(always)] fn slice(&self, range: R) -> Self; } macro_rules! impl_fn_slice { ( $ty:ty ) => { fn slice(&self, range:$ty) -> Self { &self[range] } } } macro_rules! slice_range_impl { ( [ $for_type:ident ], $ty:ty ) => { impl<'a, $for_type> Slice<$ty> for &'a [$for_type] { impl_fn_slice!( $ty ); } }; ( $for_type:ty, $ty:ty ) => { impl<'a> Slice<$ty> for &'a $for_type { impl_fn_slice!( $ty ); } } } macro_rules! slice_ranges_impl { ( [ $for_type:ident ] ) => { slice_range_impl! {[$for_type], Range} slice_range_impl! {[$for_type], RangeTo} slice_range_impl! {[$for_type], RangeFrom} slice_range_impl! {[$for_type], RangeFull} }; ( $for_type:ty ) => { slice_range_impl! {$for_type, Range} slice_range_impl! {$for_type, RangeTo} slice_range_impl! {$for_type, RangeFrom} slice_range_impl! {$for_type, RangeFull} } } slice_ranges_impl! {str} slice_ranges_impl! {[T]} /// indicates whether more data can come later in input /// /// When working with complete data, like a file that was entirely loaded /// in memory, you should use input types like `CompleteByteSlice` and /// `CompleteStr` to wrap the data. The `at_eof` method of those types /// always returns true, thus indicating to nom that it should not handle /// partial data cases. /// /// When working will partial data, like data coming from the network in /// buffers, the `at_eof` method can indicate if we expect more data to come, /// and let nom know that some parsers could still handle more data pub trait AtEof { fn at_eof(&self) -> bool; } pub fn need_more(input: I, needed: Needed) -> IResult { if input.at_eof() { Err(Err::Error(Context::Code(input, ErrorKind::Eof))) } else { Err(Err::Incomplete(needed)) } } pub fn need_more_err(input: I, needed: Needed, err: ErrorKind) -> IResult { if input.at_eof() { Err(Err::Error(Context::Code(input, err))) } else { Err(Err::Incomplete(needed)) } } // Tuple for bit parsing impl AtEof for (I, T) { fn at_eof(&self) -> bool { self.0.at_eof() } } impl<'a, T> AtEof for &'a [T] { fn at_eof(&self) -> bool { false } } impl<'a> AtEof for &'a str { fn at_eof(&self) -> bool { false } } macro_rules! array_impls { ($($N:expr)+) => { $( impl InputLength for [u8; $N] { #[inline] fn input_len(&self) -> usize { self.len() } } impl<'a> InputLength for &'a [u8; $N] { #[inline] fn input_len(&self) -> usize { self.len() } } impl<'a> Compare<[u8; $N]> for &'a [u8] { #[inline(always)] fn compare(&self, t: [u8; $N]) -> CompareResult { self.compare(&t[..]) } #[inline(always)] fn compare_no_case(&self, t: [u8;$N]) -> CompareResult { self.compare_no_case(&t[..]) } } impl<'a,'b> Compare<&'b [u8; $N]> for &'a [u8] { #[inline(always)] fn compare(&self, t: &'b [u8; $N]) -> CompareResult { self.compare(&t[..]) } #[inline(always)] fn compare_no_case(&self, t: &'b [u8;$N]) -> CompareResult { self.compare_no_case(&t[..]) } } impl FindToken for [u8; $N] { fn find_token(&self, token: u8) -> bool { memchr::memchr(token, &self[..]).is_some() } } impl<'a> FindToken<&'a u8> for [u8; $N] { fn find_token(&self, token: &u8) -> bool { memchr::memchr(*token, &self[..]).is_some() } } )+ }; } array_impls! { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 } /// abtracts something which can extend an `Extend` pub trait ExtendInto { type Item; type Extender: Extend; /// create a new `Extend` of the correct type #[inline] fn new_builder(&self) -> Self::Extender; /// accumulate the input into an accumulator #[inline] fn extend_into(&self, acc: &mut Self::Extender); } #[cfg(feature = "alloc")] impl ExtendInto for [u8] { type Item = u8; type Extender = Vec; #[inline] fn new_builder(&self) -> Vec { Vec::new() } #[inline] fn extend_into(&self, acc: &mut Vec) { acc.extend(self.iter().cloned()); } } #[cfg(feature = "alloc")] impl ExtendInto for str { type Item = char; type Extender = String; #[inline] fn new_builder(&self) -> String { String::new() } #[inline] fn extend_into(&self, acc: &mut String) { acc.push_str(self); } } #[cfg(feature = "alloc")] impl ExtendInto for char { type Item = char; type Extender = String; #[inline] fn new_builder(&self) -> String { String::new() } #[inline] fn extend_into(&self, acc: &mut String) { acc.push(*self); } } #[cfg(test)] mod tests { use super::*; #[test] fn test_offset_u8() { let s = b"abcd123"; let a = &s[..]; let b = &a[2..]; let c = &a[..4]; let d = &a[3..5]; assert_eq!(a.offset(b), 2); assert_eq!(a.offset(c), 0); assert_eq!(a.offset(d), 3); } #[test] fn test_offset_str() { let s = "abcřèÂßÇd123"; let a = &s[..]; let b = &a[7..]; let c = &a[..5]; let d = &a[5..9]; assert_eq!(a.offset(b), 7); assert_eq!(a.offset(c), 0); assert_eq!(a.offset(d), 5); } } nom-4.2.3/src/types.rs010064400007670000024000000276321344000023700130360ustar0000000000000000//! Custom input types //! use traits::{AsBytes, AtEof, Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputTake, Offset, ParseTo, Slice}; #[cfg(feature = "alloc")] use traits::ExtendInto; use lib::std::iter::{Enumerate, Map}; use lib::std::ops::{Deref, Range, RangeFrom, RangeFull, RangeTo}; use lib::std::slice::Iter; use lib::std::str::{self, CharIndices, Chars, FromStr}; use lib::std::convert::From; use lib::std::fmt::{Display, Formatter, Result}; #[cfg(feature = "alloc")] use lib::std::string::String; /// Holds a complete String, for which the `at_eof` method always returns true /// /// This means that this input type will completely avoid nom's streaming features /// and `Incomplete` results. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct CompleteStr<'a>(pub &'a str); impl<'a> From<&'a str> for CompleteStr<'a> { fn from(src: &'a str) -> Self { CompleteStr(src) } } impl<'a, 'b> From<&'b &'a str> for CompleteStr<'a> { fn from(src: &'b &'a str) -> Self { CompleteStr(*src) } } impl<'a> Display for CompleteStr<'a> { fn fmt(&self, f: &mut Formatter) -> Result { self.0.fmt(f) } } impl<'a> AsRef for CompleteStr<'a> { fn as_ref(&self) -> &str { self.0 } } impl<'a> Deref for CompleteStr<'a> { type Target = &'a str; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl<'a> AtEof for CompleteStr<'a> { #[inline] fn at_eof(&self) -> bool { true } } impl<'a> Slice> for CompleteStr<'a> { #[inline] fn slice(&self, range: Range) -> Self { CompleteStr(self.0.slice(range)) } } impl<'a> Slice> for CompleteStr<'a> { #[inline] fn slice(&self, range: RangeTo) -> Self { CompleteStr(self.0.slice(range)) } } impl<'a> Slice> for CompleteStr<'a> { #[inline] fn slice(&self, range: RangeFrom) -> Self { CompleteStr(self.0.slice(range)) } } impl<'a> Slice for CompleteStr<'a> { #[inline] fn slice(&self, range: RangeFull) -> Self { CompleteStr(self.0.slice(range)) } } impl<'a> InputIter for CompleteStr<'a> { type Item = char; type RawItem = char; type Iter = CharIndices<'a>; type IterElem = Chars<'a>; fn iter_indices(&self) -> Self::Iter { self.0.iter_indices() } fn iter_elements(&self) -> Self::IterElem { self.0.iter_elements() } fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool, { self.0.position(predicate) } fn slice_index(&self, count: usize) -> Option { self.0.slice_index(count) } } impl<'a> InputTake for CompleteStr<'a> { fn take(&self, count: usize) -> Self { CompleteStr(self.0.take(count)) } fn take_split(&self, count: usize) -> (Self, Self) { let (left, right) = self.0.take_split(count); (CompleteStr(left), CompleteStr(right)) } } impl<'a> InputLength for CompleteStr<'a> { fn input_len(&self) -> usize { self.0.input_len() } } impl<'a, 'b> Compare<&'b str> for CompleteStr<'a> { fn compare(&self, t: &'b str) -> CompareResult { self.0.compare(t) } fn compare_no_case(&self, t: &'b str) -> CompareResult { self.0.compare_no_case(t) } } impl<'a, 'b> FindSubstring<&'b str> for CompleteStr<'a> { fn find_substring(&self, substr: &'b str) -> Option { self.0.find_substring(substr) } } impl<'a> FindToken for CompleteStr<'a> { fn find_token(&self, token: char) -> bool { self.0.find_token(token) } } impl<'a> FindToken for CompleteStr<'a> { fn find_token(&self, token: u8) -> bool { self.0.find_token(token) } } impl<'a, 'b> FindToken<&'a u8> for CompleteStr<'b> { fn find_token(&self, token: &u8) -> bool { self.0.find_token(token) } } impl<'a, R: FromStr> ParseTo for CompleteStr<'a> { fn parse_to(&self) -> Option { self.0.parse().ok() } } impl<'a> Offset for CompleteStr<'a> { fn offset(&self, second: &CompleteStr<'a>) -> usize { self.0.offset(second.0) } } impl<'a> AsBytes for CompleteStr<'a> { fn as_bytes(&self) -> &[u8] { AsBytes::as_bytes(self.0) } } #[cfg(feature = "alloc")] impl<'a> ExtendInto for CompleteStr<'a> { type Item = char; type Extender = String; #[inline] fn new_builder(&self) -> String { String::new() } #[inline] fn extend_into(&self, acc: &mut String) { acc.extend(self.0.chars()); } } /// Holds a complete byte array, for which the `at_eof` method always returns true /// /// This means that this input type will completely avoid nom's streaming features /// and `Incomplete` results. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct CompleteByteSlice<'a>(pub &'a [u8]); impl<'a> From<&'a [u8]> for CompleteByteSlice<'a> { fn from(src: &'a [u8]) -> Self { CompleteByteSlice(src) } } impl<'a, 'b> From<&'b &'a [u8]> for CompleteByteSlice<'a> { fn from(src: &'b &'a [u8]) -> Self { CompleteByteSlice(*src) } } impl<'a> Deref for CompleteByteSlice<'a> { type Target = &'a [u8]; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl<'a> AtEof for CompleteByteSlice<'a> { #[inline] fn at_eof(&self) -> bool { true } } impl<'a> Slice> for CompleteByteSlice<'a> { #[inline] fn slice(&self, range: Range) -> Self { CompleteByteSlice(self.0.slice(range)) } } impl<'a> Slice> for CompleteByteSlice<'a> { #[inline] fn slice(&self, range: RangeTo) -> Self { CompleteByteSlice(self.0.slice(range)) } } impl<'a> Slice> for CompleteByteSlice<'a> { #[inline] fn slice(&self, range: RangeFrom) -> Self { CompleteByteSlice(self.0.slice(range)) } } impl<'a> Slice for CompleteByteSlice<'a> { #[inline] fn slice(&self, range: RangeFull) -> Self { CompleteByteSlice(self.0.slice(range)) } } impl<'a> InputIter for CompleteByteSlice<'a> { type Item = u8; type RawItem = u8; type Iter = Enumerate; type IterElem = Map, fn(&u8) -> u8>; //Iter<'a, Self::RawItem>; fn iter_indices(&self) -> Self::Iter { self.0.iter_indices() } fn iter_elements(&self) -> Self::IterElem { self.0.iter_elements() } fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool, { self.0.position(predicate) } fn slice_index(&self, count: usize) -> Option { self.0.slice_index(count) } } impl<'a> InputTake for CompleteByteSlice<'a> { fn take(&self, count: usize) -> Self { CompleteByteSlice(self.0.take(count)) } fn take_split(&self, count: usize) -> (Self, Self) { let (left, right) = self.0.take_split(count); (CompleteByteSlice(left), CompleteByteSlice(right)) } } impl<'a> InputLength for CompleteByteSlice<'a> { fn input_len(&self) -> usize { self.0.input_len() } } impl<'a, 'b> Compare<&'b [u8]> for CompleteByteSlice<'a> { fn compare(&self, t: &'b [u8]) -> CompareResult { self.0.compare(t) } fn compare_no_case(&self, t: &'b [u8]) -> CompareResult { self.0.compare_no_case(t) } } impl<'a, 'b> Compare<&'b str> for CompleteByteSlice<'a> { fn compare(&self, t: &'b str) -> CompareResult { self.0.compare(t) } fn compare_no_case(&self, t: &'b str) -> CompareResult { self.0.compare_no_case(t) } } impl<'a, 'b> FindSubstring<&'b [u8]> for CompleteByteSlice<'a> { fn find_substring(&self, substr: &'b [u8]) -> Option { self.0.find_substring(substr) } } impl<'a, 'b> FindSubstring<&'b str> for CompleteByteSlice<'a> { fn find_substring(&self, substr: &'b str) -> Option { self.0.find_substring(substr) } } impl<'a> FindToken for CompleteByteSlice<'a> { fn find_token(&self, token: char) -> bool { self.0.find_token(token) } } impl<'a> FindToken for CompleteByteSlice<'a> { fn find_token(&self, token: u8) -> bool { self.0.find_token(token) } } impl<'a, 'b> FindToken<&'a u8> for CompleteByteSlice<'b> { fn find_token(&self, token: &u8) -> bool { self.0.find_token(token) } } impl<'a, R: FromStr> ParseTo for CompleteByteSlice<'a> { fn parse_to(&self) -> Option { self.0.parse_to() } } impl<'a> Offset for CompleteByteSlice<'a> { fn offset(&self, second: &CompleteByteSlice<'a>) -> usize { self.0.offset(second.0) } } impl<'a> AsBytes for CompleteByteSlice<'a> { fn as_bytes(&self) -> &[u8] { self.0.as_bytes() } } #[cfg(feature = "std")] impl<'a> super::util::HexDisplay for CompleteByteSlice<'a> { fn to_hex(&self, chunk_size: usize) -> String { self.0.to_hex(chunk_size) } fn to_hex_from(&self, chunk_size: usize, from: usize) -> String { self.0.to_hex_from(chunk_size, from) } } #[derive(Clone, Copy, Debug, PartialEq, Hash)] pub struct Input { pub inner: T, pub at_eof: bool, } impl AtEof for Input { fn at_eof(&self) -> bool { self.at_eof } } impl>> Slice> for Input { fn slice(&self, range: Range) -> Self { Input { inner: self.inner.slice(range), at_eof: self.at_eof, } } } impl>> Slice> for Input { fn slice(&self, range: RangeTo) -> Self { Input { inner: self.inner.slice(range), at_eof: self.at_eof, } } } impl>> Slice> for Input { fn slice(&self, range: RangeFrom) -> Self { Input { inner: self.inner.slice(range), at_eof: self.at_eof, } } } impl> Slice for Input { fn slice(&self, range: RangeFull) -> Self { Input { inner: self.inner.slice(range), at_eof: self.at_eof, } } } impl InputIter for Input { type Item = ::Item; type RawItem = ::RawItem; type Iter = ::Iter; type IterElem = ::IterElem; fn iter_indices(&self) -> Self::Iter { self.inner.iter_indices() } fn iter_elements(&self) -> Self::IterElem { self.inner.iter_elements() } fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool, { self.inner.position(predicate) } fn slice_index(&self, count: usize) -> Option { self.inner.slice_index(count) } } impl InputTake for Input { fn take(&self, count: usize) -> Self { Input { inner: self.inner.take(count), at_eof: self.at_eof, } } fn take_split(&self, count: usize) -> (Self, Self) { let (left, right) = self.inner.take_split(count); ( Input { inner: left, at_eof: self.at_eof, }, Input { inner: right, at_eof: self.at_eof, }, ) } } impl InputLength for Input { fn input_len(&self) -> usize { self.inner.input_len() } } impl<'b, T: Compare<&'b str>> Compare<&'b str> for Input { fn compare(&self, t: &'b str) -> CompareResult { self.inner.compare(t) } fn compare_no_case(&self, t: &'b str) -> CompareResult { self.inner.compare_no_case(t) } } impl<'b, T: FindSubstring<&'b str>> FindSubstring<&'b str> for Input { fn find_substring(&self, substr: &'b str) -> Option { self.inner.find_substring(substr) } } impl> FindToken for Input { fn find_token(&self, token: char) -> bool { self.inner.find_token(token) } } impl> FindToken for Input { fn find_token(&self, token: u8) -> bool { self.inner.find_token(token) } } impl<'a, T: FindToken<&'a u8>> FindToken<&'a u8> for Input { fn find_token(&self, token: &'a u8) -> bool { self.inner.find_token(token) } } impl<'a, R: FromStr, T: ParseTo> ParseTo for Input { fn parse_to(&self) -> Option { self.inner.parse_to() } } impl Offset for Input { fn offset(&self, second: &Input) -> usize { self.inner.offset(&second.inner) } } impl AsBytes for Input { fn as_bytes(&self) -> &[u8] { AsBytes::as_bytes(&self.inner) } } nom-4.2.3/src/util.rs010064400007670000024000000603211344000023700126370ustar0000000000000000#[cfg(feature = "verbose-errors")] #[cfg(feature = "std")] use internal::{Err, IResult}; #[cfg(feature = "verbose-errors")] use verbose_errors::Context; #[cfg(feature = "std")] use std::collections::HashMap; #[cfg(feature = "alloc")] use lib::std::string::ToString; #[cfg(feature = "alloc")] use lib::std::vec::Vec; #[cfg(feature = "std")] 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: &'static [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) } } #[macro_export] macro_rules! nom_line ( () => (line!()); ); #[macro_export] macro_rules! nom_println ( ($($args:tt)*) => (println!($($args)*)); ); #[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!( 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 ( ($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!($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 /// /// ```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)] 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)); ); ); #[cfg(feature = "verbose-errors")] pub fn error_to_list(e: &Context) -> Vec<(P, ErrorKind)> { match e { &Context::Code(ref i, ref err) => { let mut v = Vec::new(); v.push((i.clone(), err.clone())); return v; } &Context::List(ref v) => { let mut v2 = v.clone(); v2.reverse(); v2 } } } #[cfg(feature = "verbose-errors")] pub fn compare_error_paths(e1: &Context, e2: &Context) -> bool { error_to_list(e1) == error_to_list(e2) } #[cfg(feature = "std")] #[cfg(feature = "verbose-errors")] use lib::std::hash::Hash; #[cfg(feature = "std")] #[cfg(feature = "verbose-errors")] pub fn add_error_pattern<'a, I: Clone + Hash + Eq, O, E: Clone + Hash + Eq>( h: &mut HashMap)>, &'a str>, res: IResult, message: &'a str, ) -> bool { match res { Err(Err::Error(e)) | Err(Err::Failure(e)) => { h.insert(error_to_list(&e), message); true } _ => false, } } pub fn slice_to_offsets(input: &[u8], s: &[u8]) -> (usize, usize) { let start = input.as_ptr(); let off1 = s.as_ptr() as usize - start as usize; let off2 = off1 + s.len(); (off1, off2) } #[cfg(feature = "std")] #[cfg(feature = "verbose-errors")] pub fn prepare_errors(input: &[u8], res: IResult<&[u8], O, E>) -> Option, usize, usize)>> { if let Err(Err::Error(e)) = res { let mut v: Vec<(ErrorKind, usize, usize)> = Vec::new(); match e { Context::Code(p, kind) => { let (o1, o2) = slice_to_offsets(input, p); v.push((kind, o1, o2)); } Context::List(mut l) => { for (p, kind) in l.drain(..) { let (o1, o2) = slice_to_offsets(input, p); v.push((kind, o1, o2)); } v.reverse() } } v.sort_by(|a, b| a.1.cmp(&b.1)); Some(v) } else { None } } #[cfg(feature = "std")] #[cfg(feature = "verbose-errors")] pub fn print_error(input: &[u8], res: IResult<&[u8], O, E>) { if let Some(v) = prepare_errors(input, res) { let colors = generate_colors(&v); println!("parser codes: {}", print_codes(&colors, &HashMap::new())); println!("{}", print_offsets(input, 0, &v)); } else { println!("not an error"); } } #[cfg(feature = "std")] #[cfg(feature = "verbose-errors")] pub fn generate_colors(v: &[(ErrorKind, usize, usize)]) -> HashMap { let mut h: HashMap = HashMap::new(); let mut color = 0; for &(ref c, _, _) in v.iter() { h.insert(error_to_u32(c), color + 31); color = color + 1 % 7; } h } pub fn code_from_offset(v: &[(ErrorKind, usize, usize)], offset: usize) -> Option { let mut acc: Option<(u32, usize, usize)> = None; for &(ref ek, s, e) in v.iter() { let c = error_to_u32(ek); if s <= offset && offset <= e { if let Some((_, start, end)) = acc { if start <= s && e <= end { acc = Some((c, s, e)); } } else { acc = Some((c, s, e)); } } } if let Some((code, _, _)) = acc { return Some(code); } else { return None; } } #[cfg(feature = "alloc")] pub fn reset_color(v: &mut Vec) { v.push(0x1B); v.push(b'['); v.push(0); v.push(b'm'); } #[cfg(feature = "alloc")] pub fn write_color(v: &mut Vec, color: u8) { v.push(0x1B); v.push(b'['); v.push(1); v.push(b';'); let s = color.to_string(); let bytes = s.as_bytes(); v.extend(bytes.iter().cloned()); v.push(b'm'); } #[cfg(feature = "std")] #[cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))] pub fn print_codes(colors: &HashMap, names: &HashMap) -> String { let mut v = Vec::new(); for (code, &color) in colors { if let Some(&s) = names.get(code) { let bytes = s.as_bytes(); write_color(&mut v, color); v.extend(bytes.iter().cloned()); } else { let s = code.to_string(); let bytes = s.as_bytes(); write_color(&mut v, color); v.extend(bytes.iter().cloned()); } reset_color(&mut v); v.push(b' '); } reset_color(&mut v); String::from_utf8_lossy(&v[..]).into_owned() } #[cfg(feature = "std")] #[cfg(feature = "verbose-errors")] pub fn print_offsets(input: &[u8], from: usize, offsets: &[(ErrorKind, usize, usize)]) -> String { let mut v = Vec::with_capacity(input.len() * 3); let mut i = from; let chunk_size = 8; let mut current_code: Option = None; let mut current_code2: Option = None; let colors = generate_colors(&offsets); for chunk in input.chunks(chunk_size) { let s = format!("{:08x}", i); for &ch in s.as_bytes().iter() { v.push(ch); } v.push(b'\t'); let mut k = i; let mut l = i; for &byte in chunk { if let Some(code) = code_from_offset(&offsets, k) { if let Some(current) = current_code { if current != code { reset_color(&mut v); current_code = Some(code); if let Some(&color) = colors.get(&code) { write_color(&mut v, color); } } } else { current_code = Some(code); if let Some(&color) = colors.get(&code) { write_color(&mut v, color); } } } v.push(CHARS[(byte >> 4) as usize]); v.push(CHARS[(byte & 0xf) as usize]); v.push(b' '); k = k + 1; } reset_color(&mut v); if chunk_size > chunk.len() { for _ in 0..(chunk_size - chunk.len()) { v.push(b' '); v.push(b' '); v.push(b' '); } } v.push(b'\t'); for &byte in chunk { if let Some(code) = code_from_offset(&offsets, l) { if let Some(current) = current_code2 { if current != code { reset_color(&mut v); current_code2 = Some(code); if let Some(&color) = colors.get(&code) { write_color(&mut v, color); } } } else { current_code2 = Some(code); if let Some(&color) = colors.get(&code) { write_color(&mut v, color); } } } if (byte >= 32 && byte <= 126) || byte >= 128 { v.push(byte); } else { v.push(b'.'); } l = l + 1; } reset_color(&mut v); v.push(b'\n'); i = i + chunk_size; } String::from_utf8_lossy(&v[..]).into_owned() } /// indicates which parser returned an error #[cfg_attr(rustfmt, rustfmt_skip)] #[derive(Debug,PartialEq,Eq,Hash,Clone)] #[allow(deprecated)] pub enum ErrorKind { Custom(E), Tag, MapRes, MapOpt, Alt, IsNot, IsA, SeparatedList, SeparatedNonEmptyList, Many0, Many1, ManyTill, Count, TakeUntilAndConsume, TakeUntil, TakeUntilEitherAndConsume, TakeUntilEither, LengthValue, TagClosure, Alpha, Digit, HexDigit, OctDigit, AlphaNumeric, Space, MultiSpace, LengthValueFn, Eof, ExprOpt, ExprRes, CondReduce, Switch, TagBits, OneOf, NoneOf, Char, CrLf, RegexpMatch, RegexpMatches, RegexpFind, RegexpCapture, RegexpCaptures, TakeWhile1, Complete, Fix, Escaped, EscapedTransform, #[deprecated(since = "4.0.0", note = "Please use `Tag` instead")] TagStr, #[deprecated(since = "4.0.0", note = "Please use `IsNot` instead")] IsNotStr, #[deprecated(since = "4.0.0", note = "Please use `IsA` instead")] IsAStr, #[deprecated(since = "4.0.0", note = "Please use `TakeWhile1` instead")] TakeWhile1Str, NonEmpty, ManyMN, #[deprecated(since = "4.0.0", note = "Please use `TakeUntilAndConsume` instead")] TakeUntilAndConsumeStr, #[deprecated(since = "4.0.0", note = "Please use `TakeUntil` instead")] TakeUntilStr, Not, Permutation, Verify, TakeTill1, TakeUntilAndConsume1, TakeWhileMN, ParseTo, TooLarge, Many0Count, Many1Count, } #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(deprecated)] pub fn error_to_u32(e: &ErrorKind) -> u32 { match *e { ErrorKind::Custom(_) => 0, ErrorKind::Tag => 1, ErrorKind::MapRes => 2, ErrorKind::MapOpt => 3, ErrorKind::Alt => 4, ErrorKind::IsNot => 5, ErrorKind::IsA => 6, ErrorKind::SeparatedList => 7, ErrorKind::SeparatedNonEmptyList => 8, ErrorKind::Many1 => 9, ErrorKind::Count => 10, ErrorKind::TakeUntilAndConsume => 11, ErrorKind::TakeUntil => 12, ErrorKind::TakeUntilEitherAndConsume => 13, ErrorKind::TakeUntilEither => 14, ErrorKind::LengthValue => 15, ErrorKind::TagClosure => 16, ErrorKind::Alpha => 17, ErrorKind::Digit => 18, ErrorKind::AlphaNumeric => 19, ErrorKind::Space => 20, ErrorKind::MultiSpace => 21, ErrorKind::LengthValueFn => 22, ErrorKind::Eof => 23, ErrorKind::ExprOpt => 24, ErrorKind::ExprRes => 25, ErrorKind::CondReduce => 26, ErrorKind::Switch => 27, ErrorKind::TagBits => 28, ErrorKind::OneOf => 29, ErrorKind::NoneOf => 30, ErrorKind::Char => 40, ErrorKind::CrLf => 41, ErrorKind::RegexpMatch => 42, ErrorKind::RegexpMatches => 43, ErrorKind::RegexpFind => 44, ErrorKind::RegexpCapture => 45, ErrorKind::RegexpCaptures => 46, ErrorKind::TakeWhile1 => 47, ErrorKind::Complete => 48, ErrorKind::Fix => 49, ErrorKind::Escaped => 50, ErrorKind::EscapedTransform => 51, ErrorKind::TagStr => 52, ErrorKind::IsNotStr => 53, ErrorKind::IsAStr => 54, ErrorKind::TakeWhile1Str => 55, ErrorKind::NonEmpty => 56, ErrorKind::ManyMN => 57, ErrorKind::TakeUntilAndConsumeStr => 58, ErrorKind::HexDigit => 59, ErrorKind::TakeUntilStr => 60, ErrorKind::OctDigit => 61, ErrorKind::Many0 => 62, ErrorKind::Not => 63, ErrorKind::Permutation => 64, ErrorKind::ManyTill => 65, ErrorKind::Verify => 66, ErrorKind::TakeTill1 => 67, ErrorKind::TakeUntilAndConsume1 => 68, ErrorKind::TakeWhileMN => 69, ErrorKind::ParseTo => 70, ErrorKind::TooLarge => 71, ErrorKind::Many0Count => 72, ErrorKind::Many1Count => 73, } } impl ErrorKind { #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(deprecated)] pub fn description(&self) -> &str { match *self { ErrorKind::Custom(_) => "Custom error", ErrorKind::Tag => "Tag", ErrorKind::MapRes => "Map on Result", ErrorKind::MapOpt => "Map on Option", ErrorKind::Alt => "Alternative", ErrorKind::IsNot => "IsNot", ErrorKind::IsA => "IsA", ErrorKind::SeparatedList => "Separated list", ErrorKind::SeparatedNonEmptyList => "Separated non empty list", ErrorKind::Many0 => "Many0", ErrorKind::Many1 => "Many1", ErrorKind::Count => "Count", ErrorKind::TakeUntilAndConsume => "Take until and consume", ErrorKind::TakeUntil => "Take until", ErrorKind::TakeUntilEitherAndConsume => "Take until either and consume", ErrorKind::TakeUntilEither => "Take until either", ErrorKind::LengthValue => "Length followed by value", ErrorKind::TagClosure => "Tag closure", ErrorKind::Alpha => "Alphabetic", ErrorKind::Digit => "Digit", ErrorKind::AlphaNumeric => "AlphaNumeric", ErrorKind::Space => "Space", ErrorKind::MultiSpace => "Multiple spaces", ErrorKind::LengthValueFn => "LengthValueFn", ErrorKind::Eof => "End of file", ErrorKind::ExprOpt => "Evaluate Option", ErrorKind::ExprRes => "Evaluate Result", ErrorKind::CondReduce => "Condition reduce", ErrorKind::Switch => "Switch", ErrorKind::TagBits => "Tag on bitstream", ErrorKind::OneOf => "OneOf", ErrorKind::NoneOf => "NoneOf", ErrorKind::Char => "Char", ErrorKind::CrLf => "CrLf", ErrorKind::RegexpMatch => "RegexpMatch", ErrorKind::RegexpMatches => "RegexpMatches", ErrorKind::RegexpFind => "RegexpFind", ErrorKind::RegexpCapture => "RegexpCapture", ErrorKind::RegexpCaptures => "RegexpCaptures", ErrorKind::TakeWhile1 => "TakeWhile1", ErrorKind::Complete => "Complete", ErrorKind::Fix => "Fix", ErrorKind::Escaped => "Escaped", ErrorKind::EscapedTransform => "EscapedTransform", ErrorKind::TagStr => "Tag on strings", ErrorKind::IsNotStr => "IsNot on strings", ErrorKind::IsAStr => "IsA on strings", ErrorKind::TakeWhile1Str => "TakeWhile1 on strings", ErrorKind::NonEmpty => "NonEmpty", ErrorKind::ManyMN => "Many(m, n)", ErrorKind::TakeUntilAndConsumeStr => "Take until and consume on strings", ErrorKind::HexDigit => "Hexadecimal Digit", ErrorKind::TakeUntilStr => "Take until on strings", ErrorKind::OctDigit => "Octal digit", ErrorKind::Not => "Negation", ErrorKind::Permutation => "Permutation", ErrorKind::ManyTill => "ManyTill", ErrorKind::Verify => "predicate verification", ErrorKind::TakeTill1 => "TakeTill1", ErrorKind::TakeUntilAndConsume1 => "Take at least 1 until and consume", 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", } } /// Convert Err into an ErrorKind. /// /// This allows application code to use ErrorKind and stay independent from the `verbose-errors` features activation. pub fn into_error_kind(self) -> ErrorKind { self } } pub trait Convert { fn convert(T) -> Self; } impl> Convert> for ErrorKind { #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(deprecated)] fn convert(e: ErrorKind) -> Self { match e { ErrorKind::Custom(c) => ErrorKind::Custom(E::from(c)), ErrorKind::Tag => ErrorKind::Tag, ErrorKind::MapRes => ErrorKind::MapRes, ErrorKind::MapOpt => ErrorKind::MapOpt, ErrorKind::Alt => ErrorKind::Alt, ErrorKind::IsNot => ErrorKind::IsNot, ErrorKind::IsA => ErrorKind::IsA, ErrorKind::SeparatedList => ErrorKind::SeparatedList, ErrorKind::SeparatedNonEmptyList => ErrorKind::SeparatedNonEmptyList, ErrorKind::Many1 => ErrorKind::Many1, ErrorKind::Count => ErrorKind::Count, ErrorKind::TakeUntilAndConsume => ErrorKind::TakeUntilAndConsume, ErrorKind::TakeUntil => ErrorKind::TakeUntil, ErrorKind::TakeUntilEitherAndConsume => ErrorKind::TakeUntilEitherAndConsume, ErrorKind::TakeUntilEither => ErrorKind::TakeUntilEither, ErrorKind::LengthValue => ErrorKind::LengthValue, ErrorKind::TagClosure => ErrorKind::TagClosure, ErrorKind::Alpha => ErrorKind::Alpha, ErrorKind::Digit => ErrorKind::Digit, ErrorKind::AlphaNumeric => ErrorKind::AlphaNumeric, ErrorKind::Space => ErrorKind::Space, ErrorKind::MultiSpace => ErrorKind::MultiSpace, ErrorKind::LengthValueFn => ErrorKind::LengthValueFn, ErrorKind::Eof => ErrorKind::Eof, ErrorKind::ExprOpt => ErrorKind::ExprOpt, ErrorKind::ExprRes => ErrorKind::ExprRes, ErrorKind::CondReduce => ErrorKind::CondReduce, ErrorKind::Switch => ErrorKind::Switch, ErrorKind::TagBits => ErrorKind::TagBits, ErrorKind::OneOf => ErrorKind::OneOf, ErrorKind::NoneOf => ErrorKind::NoneOf, ErrorKind::Char => ErrorKind::Char, ErrorKind::CrLf => ErrorKind::CrLf, ErrorKind::RegexpMatch => ErrorKind::RegexpMatch, ErrorKind::RegexpMatches => ErrorKind::RegexpMatches, ErrorKind::RegexpFind => ErrorKind::RegexpFind, ErrorKind::RegexpCapture => ErrorKind::RegexpCapture, ErrorKind::RegexpCaptures => ErrorKind::RegexpCaptures, ErrorKind::TakeWhile1 => ErrorKind::TakeWhile1, ErrorKind::Complete => ErrorKind::Complete, ErrorKind::Fix => ErrorKind::Fix, ErrorKind::Escaped => ErrorKind::Escaped, ErrorKind::EscapedTransform => ErrorKind::EscapedTransform, ErrorKind::TagStr => ErrorKind::TagStr, ErrorKind::IsNotStr => ErrorKind::IsNotStr, ErrorKind::IsAStr => ErrorKind::IsAStr, ErrorKind::TakeWhile1Str => ErrorKind::TakeWhile1Str, ErrorKind::NonEmpty => ErrorKind::NonEmpty, ErrorKind::ManyMN => ErrorKind::ManyMN, ErrorKind::TakeUntilAndConsumeStr => ErrorKind::TakeUntilAndConsumeStr, ErrorKind::HexDigit => ErrorKind::HexDigit, ErrorKind::TakeUntilStr => ErrorKind::TakeUntilStr, ErrorKind::OctDigit => ErrorKind::OctDigit, ErrorKind::Many0 => ErrorKind::Many0, ErrorKind::Not => ErrorKind::Not, ErrorKind::Permutation => ErrorKind::Permutation, ErrorKind::ManyTill => ErrorKind::ManyTill, ErrorKind::Verify => ErrorKind::Verify, ErrorKind::TakeTill1 => ErrorKind::TakeTill1, ErrorKind::TakeUntilAndConsume1 => ErrorKind::TakeUntilAndConsume1, ErrorKind::TakeWhileMN => ErrorKind::TakeWhileMN, ErrorKind::ParseTo => ErrorKind::ParseTo, ErrorKind::TooLarge => ErrorKind::TooLarge, ErrorKind::Many0Count => ErrorKind::Many0Count, ErrorKind::Many1Count => ErrorKind::Many1Count, } } } nom-4.2.3/src/verbose_errors.rs010064400007670000024000000206371344000023700147310ustar0000000000000000//! Error management //! //! Depending on a compilation flag, the content of the `Context` enum //! can change. In the default case, it will only have one variant: //! `Context::Code(I, ErrorKind)` (with `I` and `E` configurable). //! It contains an error code and the input position that triggered it. //! //! If you activate the `verbose-errors` compilation flags, it will add another //! variant to the enum: `Context::List(Vec<(I, ErrorKind)>)`. //! This variant aggregates positions and error codes as the code backtracks //! through the nested parsers. //! The verbose errors feature allows for very flexible error management: //! you can know precisely which parser got to which part of the input. //! The main drawback is that it is a lot slower than default error //! management. use util::{Convert, ErrorKind}; use lib::std::convert::From; #[cfg(feature = "alloc")] use lib::std::vec::Vec; /// Contains the error that a parser can return /// /// If you use the `verbose-errors` compilation feature, /// `nom::Err` will be the enum defined here, /// otherwise, it will amount to a `ErrorKind`. /// /// It can represent a linked list of errors, indicating the path taken in the parsing tree, with corresponding position in the input data. /// It depends on P, the input position (for a &[u8] parser, it would be a &[u8]), and E, the custom error type (by default, u32) #[derive(Debug, PartialEq, Eq, Clone)] pub enum Context { /// An error code, represented by an ErrorKind, which can contain a custom error code represented by E Code(I, ErrorKind), List(Vec<(I, ErrorKind)>), } impl, F, E: From> Convert> for Context { fn convert(c: Context) -> Self { match c { Context::Code(i, e) => Context::Code(i.into(), ErrorKind::convert(e)), Context::List(mut v) => Context::List( v.drain(..) .map(|(i, e)| (i.into(), ErrorKind::convert(e))) .collect(), ), } } } impl Context { /// Convert Err into ErrorKind. /// /// This allows application code to use ErrorKind and stay independent from the verbose-errors features activation. pub fn into_error_kind(self) -> ErrorKind { match self { Context::Code(_, kind) => kind, Context::List(mut v) => { let (_, kind) = v.remove(0); kind } } } } /* impl IResult { /// Maps a `IResult` to `IResult` by appling a function /// to a contained `Error` value, leaving `Done` and `Incomplete` value /// untouched. #[inline] pub fn map_err(self, f: F) -> IResult where F: FnOnce(Err) -> Err { match self { Error(e) => Error(f(e)), Incomplete(n) => Incomplete(n), Done(i, o) => Done(i, o), } } /// Unwrap the contained `Error(I, E)` value, or panic if the `IResult` is not /// `Error`. pub fn unwrap_err(self) -> Err { match self { Error(e) => e, Done(_, _) => panic!("unwrap_err() called on an IResult that is Done"), Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"), } } /// Convert the IResult to a std::result::Result pub fn to_full_result(self) -> Result> { match self { Done(_, o) => Ok(o), Incomplete(n) => Err(IError::Incomplete(n)), Error(e) => Err(IError::Error(e)) } } /// Convert the IResult to a std::result::Result pub fn to_result(self) -> Result> { match self { Done(_, o) => Ok(o), Error(e) => Err(e), Incomplete(_) => panic!("to_result() called on an IResult that is Incomplete") } } } #[cfg(feature = "std")] use $crate::lib::std::any::Any; #[cfg(feature = "std")] use $crate::lib::std::{error,fmt}; #[cfg(feature = "std")] use $crate::lib::std::fmt::Debug; #[cfg(feature = "std")] impl error::Error for Err { fn description(&self) -> &str { let kind = match *self { Err::Code(ref e) | Err::Node(ref e, _) | Err::Position(ref e, _) | Err::NodePosition(ref e, _, _) => e }; kind.description() } } #[cfg(feature = "std")] impl fmt::Display for Err { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Err::Code(ref e) | Err::Node(ref e, _) => { write!(f, "{:?}", e) }, Err::Position(ref e, ref p) | Err::NodePosition(ref e, ref p, _) => { write!(f, "{:?}:{:?}", p, e) } } } } */ /// translate parser result from IResult to IResult with a custom type /// /// ``` /// # #[macro_use] extern crate nom; /// # use nom::ErrorKind; /// # use nom::Context; /// # use nom::Err; /// # fn main() { /// #[derive(Debug,Clone,PartialEq)] /// pub struct ErrorStr(String); /// /// // Convert to IResult<&[u8], &[u8], ErrorStr> /// impl From for ErrorStr { /// fn from(i: u32) -> Self { /// ErrorStr(format!("custom error code: {}", i)) /// } /// } /// /// // will add a Custom(42) error to the error chain /// named!(err_test, add_return_error!(ErrorKind::Custom(42), tag!("abcd"))); /// /// // Convert to IResult<&[u8], &[u8], ErrorStr> /// 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())))))); /// let list = vec!((a, ErrorKind::Tag), (a, ErrorKind::Custom(ErrorStr("custom error code: 42".to_string())))); /// assert_eq!( /// parser(a), /// Err(Err::Error(Context::List(list))) /// ); /// # } /// ``` #[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,Convert,ErrorKind,Context}; match $submac!($i, $($args)*) { Err(e) => { let e2 = match e { Err::Error(err) => { let err2 = match err { Context::Code(i, code) => { let code2: ErrorKind<$t> = ErrorKind::convert(code); Context::Code(i, code2) }, Context::List(mut v) => { Context::List(v.drain(..).map(|(i, code)| { let code2: ErrorKind<$t> = ErrorKind::convert(code); (i, code2) }).collect()) } }; Err::Error(err2) }, Err::Failure(err) => { let err2 = match err { Context::Code(i, code) => { let code2: ErrorKind<$t> = ErrorKind::convert(code); Context::Code(i, code2) }, Context::List(mut v) => { Context::List(v.drain(..).map(|(i, code)| { let code2: ErrorKind<$t> = ErrorKind::convert(code); (i, code2) }).collect()) } }; Err::Failure(err2) }, Err::Incomplete(i) => Err::Incomplete(i), }; Err(e2) }, Ok((i, o)) => Ok((i, o)), } } ); ($i:expr, $t:ty, $f:expr) => ( fix_error!($i, $t, call!($f)); ); ); /// `flat_map!(R -> IResult, S -> IResult) => R -> IResult` /// /// combines a parser R -> IResult and /// a parser S -> IResult to return another /// parser R -> IResult #[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)* )) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Convert}; ($submac!($i, $($args)*)).and_then(|(i,o)| { match $submac2!(o, $($args2)*) { Err(e) => Err(Err::convert(e)), Ok((_, o2)) => Ok((i, o2)) } }) } ); ); nom-4.2.3/src/whitespace.rs010064400007670000024000001033751344000023700140250ustar0000000000000000//! Support for whitespace delimited formats //! //! a lot of textual formats allows spaces and other //! types of separators between tokens. Handling it //! manually with nom means wrapping all parsers //! like this: //! //! ```ignore //! named!(token, delimited!(space, tk, space)); //! ``` //! //! To ease the development of such parsers, you //! can use the whitespace parsing facility, which works //! as follows: //! //! ``` //! # #[macro_use] extern crate nom; //! # fn main() { //! named!(tuple<&[u8], (&[u8], &[u8]) >, //! ws!(tuple!( take!(3), tag!("de") )) //! ); //! //! assert_eq!( //! tuple(&b" \t abc de fg"[..]), //! Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) //! ); //! # } //! ``` //! //! The `ws!` combinator will modify the parser to //! intersperse space parsers everywhere. By default, //! it will consume the following characters: `" \t\r\n"`. //! //! If you want to modify that behaviour, you can make //! your own whitespace wrapper. As an example, if //! you don't want to consume ends of lines, only //! spaces and tabs, you can do it like this: //! //! ``` //! # #[macro_use] extern crate nom; //! named!(pub space, eat_separator!(&b" \t"[..])); //! //! #[macro_export] //! macro_rules! sp ( //! ($i:expr, $($args:tt)*) => ( //! { //! use nom::Convert; //! use nom::Err; //! //! match sep!($i, space, $($args)*) { //! Err(e) => Err(e), //! Ok((i1,o)) => { //! match space(i1) { //! Err(e) => Err(Err::convert(e)), //! Ok((i2,_)) => Ok((i2, o)) //! } //! } //! } //! } //! ) //! ); //! //! # fn main() { //! named!(tuple<&[u8], (&[u8], &[u8]) >, //! sp!(tuple!( take!(3), tag!("de") )) //! ); //! //! assert_eq!( //! tuple(&b" \t abc de fg"[..]), //! Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) //! ); //! # } //! ``` //! //! This combinator works by replacing each combinator with //! a version that supports wrapping with separator parsers. //! It will not support the combinators you wrote in your //! own code. You can still manually wrap them with the separator //! you want, or you can copy the macros defined in src/whitespace.rs //! and modify them to support a new combinator: //! //! * copy the combinator's code here, add the _sep suffix //! * add the `$separator:expr` as second argument //! * wrap any sub parsers with sep!($separator, $submac!($($args)*)) //! * reference it in the definition of `sep!` as follows: //! //! ```ignore //! ($i:expr, $separator:path, my_combinator ! ($($rest:tt)*) ) => { //! wrap_sep!($i, //! $separator, //! my_combinator_sep!($separator, $($rest)*) //! ) //! }; //! ``` //! #[macro_export(local_inner_macros)] macro_rules! wrap_sep ( ($i:expr, $separator:expr, $submac:ident!( $($args:tt)* )) => ({ use $crate::lib::std::result::Result::*; use $crate::{Err,Convert,IResult}; fn unify_types(_: &IResult, _: &IResult) {} let sep_res = ($separator)($i); match sep_res { Ok((i1,_)) => { let res = $submac!(i1, $($args)*); unify_types(&sep_res, &res); res }, Err(e) => Err(Err::convert(e)), } }); ($i:expr, $separator:expr, $f:expr) => ( wrap_sep!($i, $separator, call!($f)) ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! pair_sep ( ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( tuple!( $i, sep!($separator, $submac!($($args)*)), sep!($separator, $submac2!($($args2)*)) ) ); ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $g:expr) => ( pair_sep!($i, $separator, $submac!($($args)*), call!($g)); ); ($i:expr, $separator:path, $f:expr, $submac:ident!( $($args:tt)* )) => ( pair_sep!($i, $separator, call!($f), $submac!($($args)*)); ); ($i:expr, $separator:path, $f:expr, $g:expr) => ( pair_sep!($i, $separator, call!($f), call!($g)); ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! delimited_sep ( ($i:expr, $separator:path, $submac1:ident!( $($args1:tt)* ), $($rest:tt)+) => ({ use $crate::lib::std::result::Result::*; match tuple_sep!($i, $separator, (), $submac1!($($args1)*), $($rest)*) { Err(e) => Err(e), Ok((remaining, (_,o,_))) => { Ok((remaining, o)) } } }); ($i:expr, $separator:path, $f:expr, $($rest:tt)+) => ( delimited_sep!($i, $separator, call!($f), $($rest)*); ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! separated_pair_sep ( ($i:expr, $separator:path, $submac1:ident!( $($args1:tt)* ), $($rest:tt)+) => ({ use $crate::lib::std::result::Result::*; match tuple_sep!($i, $separator, (), $submac1!($($args1)*), $($rest)*) { Err(e) => Err(e), Ok((remaining, (o1,_,o2))) => { Ok((remaining, (o1,o2))) } } }); ($i:expr, $separator:path, $f:expr, $($rest:tt)+) => ( separated_pair_sep!($i, $separator, call!($f), $($rest)*); ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! preceded_sep ( ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ({ use $crate::lib::std::result::Result::*; match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) { Err(e) => Err(e), Ok((remaining, (_,o))) => { Ok((remaining, o)) } } }); ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $g:expr) => ( preceded_sep!($i, $separator, $submac!($($args)*), call!($g)); ); ($i:expr, $separator:path, $f:expr, $submac:ident!( $($args:tt)* )) => ( preceded_sep!($i, $separator, call!($f), $submac!($($args)*)); ); ($i:expr, $separator:path, $f:expr, $g:expr) => ( preceded_sep!($i, $separator, call!($f), call!($g)); ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! terminated_sep ( ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ({ use $crate::lib::std::result::Result::*; match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) { Err(e) => Err(e), Ok((remaining, (o,_))) => { Ok((remaining, o)) } } }); ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $g:expr) => ( terminated_sep!($i, $separator, $submac!($($args)*), call!($g)); ); ($i:expr, $separator:path, $f:expr, $submac:ident!( $($args:tt)* )) => ( terminated_sep!($i, $separator, call!($f), $submac!($($args)*)); ); ($i:expr, $separator:path, $f:expr, $g:expr) => ( terminated_sep!($i, $separator, call!($f), call!($g)); ); ); /// Internal parser, do not use directly #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! tuple_sep ( ($i:expr, $separator:path, ($($parsed:tt),*), $e:path, $($rest:tt)*) => ( tuple_sep!($i, $separator, ($($parsed),*), call!($e), $($rest)*); ); ($i:expr, $separator:path, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( { use $crate::lib::std::result::Result::*; match sep!($i, $separator, $submac!($($args)*)) { Err(e) => Err(e), Ok((i,o)) => { tuple_sep!(i, $separator, (o), $($rest)*) } } } ); ($i:expr, $separator:path, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ( { use $crate::lib::std::result::Result::*; match sep!($i, $separator, $submac!($($args)*)) { Err(e) => Err(e), Ok((i,o)) => { tuple_sep!(i, $separator, ($($parsed)* , o), $($rest)*) } } } ); ($i:expr, $separator:path, ($($parsed:tt),*), $e:path) => ( tuple_sep!($i, $separator, ($($parsed),*), call!($e)); ); ($i:expr, $separator:path, (), $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; match sep!($i, $separator, $submac!($($args)*)) { Err(e) => Err(e), Ok((i,o)) => { Ok((i, (o))) } } } ); ($i:expr, $separator:path, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => ( { use $crate::lib::std::result::Result::*; match sep!($i, $separator, $submac!($($args)*)) { Err(e) => Err(e), Ok((i,o)) => { Ok((i, ($($parsed),* , o))) } } } ); ($i:expr, $separator:path, ($($parsed:expr),*)) => ( { ::sts::result::Result::Ok(($i, ($($parsed),*))) } ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! do_parse_sep ( (__impl $i:expr, $separator:path, ( $($rest:expr),* )) => ( $crate::lib::std::result::Result::Ok(($i, ( $($rest),* ))) ); (__impl $i:expr, $separator:path, $e:ident >> $($rest:tt)*) => ( do_parse_sep!(__impl $i, $separator, call!($e) >> $($rest)*); ); (__impl $i:expr, $separator:path, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( { use $crate::lib::std::result::Result::*; match sep!($i, $separator, $submac!($($args)*)) { Err(e) => Err(e), Ok((i,_)) => { do_parse_sep!(__impl i, $separator, $($rest)*) }, } } ); (__impl $i:expr, $separator:path, $field:ident : $e:ident >> $($rest:tt)*) => ( do_parse_sep!(__impl $i, $separator, $field: call!($e) >> $($rest)*); ); (__impl $i:expr, $separator:path, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( { use $crate::lib::std::result::Result::*; match sep!($i, $separator, $submac!($($args)*)) { Err(e) => Err(e), Ok((i,o)) => { let $field = o; do_parse_sep!(__impl i, $separator, $($rest)*) }, } } ); // ending the chain (__impl $i:expr, $separator:path, $e:ident >> ( $($rest:tt)* )) => ( do_parse_sep!(__impl $i, $separator, call!($e) >> ( $($rest)* )); ); (__impl $i:expr, $separator:path, $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ({ use $crate::lib::std::result::Result::*; match sep!($i, $separator, $submac!($($args)*)) { Err(e) => Err(e), Ok((i,_)) => { Ok((i, ( $($rest)* ))) }, } }); (__impl $i:expr, $separator:path, $field:ident : $e:ident >> ( $($rest:tt)* )) => ( do_parse_sep!(__impl $i, $separator, $field: call!($e) >> ( $($rest)* ) ); ); (__impl $i:expr, $separator:path, $field:ident : $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => ({ use $crate::lib::std::result::Result::*; match sep!($i, $separator, $submac!($($args)*)) { Err(e) => Err(e), Ok((i,o)) => { let $field = o; Ok((i, ( $($rest)* ))) }, } }); ($i:expr, $separator:path, $($rest:tt)*) => ( { do_parse_sep!(__impl $i, $separator, $($rest)*) } ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! permutation_sep ( ($i:expr, $separator:path, $($rest:tt)*) => ( { use $crate::lib::std::result::Result::*; use $crate::lib::std::option::Option::*; use $crate::{Err,ErrorKind,Convert}; 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_sep!(0, input, $separator, 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 = Option::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_iterator_sep ( ($it:tt,$i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $e:ident?, $($rest:tt)*) => ( permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, call!($e), $($rest)*); ); ($it:tt,$i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $e:ident, $($rest:tt)*) => ( permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, call!($e), $($rest)*); ); ($it:tt, $i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?, $($rest:tt)*) => ({ permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, $submac!($($args)*), $($rest)*); }); ($it:tt, $i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)*) => ({ use $crate::lib::std::result::Result::*; use $crate::Err; if acc!($it, $res) == $crate::lib::std::option::Option::None { match {sep!($i, $separator, $submac!($($args)*))} { Ok((i,o)) => { $i = i; acc!($it, $res) = $crate::lib::std::option::Option::Some(o); continue; }, Err(Err::Error(_)) => { $all_done = false; }, Err(e) => { $needed = $crate::lib::std::option::Option::Some(e); break; } }; } succ!($it, permutation_iterator_sep!($i, $separator, $all_done, $needed, $res, $($rest)*)); }); ($it:tt,$i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $e:ident?) => ( permutation_iterator_sep!($it, $i, $separator, $all_done, $res, call!($e)); ); ($it:tt,$i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $e:ident) => ( permutation_iterator_sep!($it, $i, $separator, $all_done, $res, call!($e)); ); ($it:tt, $i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )?) => ({ permutation_iterator_sep!($it, $i, $separator, $all_done, $needed, $res, $submac!($($args)*)); }); ($it:tt, $i:expr, $separator:path, $all_done:expr, $needed:expr, $res:expr, $submac:ident!( $($args:tt)* )) => ({ use $crate::lib::std::result::Result::*; use $crate::Err; if acc!($it, $res) == $crate::lib::std::option::Option::None { match sep!($i, $separator, $submac!($($args)*)) { Ok((i,o)) => { $i = i; acc!($it, $res) = $crate::lib::std::option::Option::Some(o); continue; }, Err(Err::Error(_)) => { $all_done = false; }, Err(e) => { $needed = $crate::lib::std::option::Option::Some(e); break; } }; } }); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! alt_sep ( (__impl $i:expr, $separator:path, $e:path | $($rest:tt)*) => ( alt_sep!(__impl $i, $separator, call!($e) | $($rest)*); ); (__impl $i:expr, $separator:path, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; let res = sep!($i, $separator, $subrule!($($args)*)); match res { Ok((_,_)) => res, Err(Err::Error(_)) => alt_sep!(__impl $i, $separator, $($rest)*), Err(e) => Err(e), } } ); (__impl $i:expr, $separator:path, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; match sep!($i, $separator, $subrule!( $($args)* )) { Ok((i,o)) => Ok((i,$gen(o))), Err(Err::Error(_)) => { alt_sep!(__impl $i, $separator, $($rest)*) }, Err(e) => Err(e), } } ); (__impl $i:expr, $separator:path, $e:path => { $gen:expr } | $($rest:tt)*) => ( alt_sep!(__impl $i, $separator, call!($e) => { $gen } | $($rest)*); ); (__impl $i:expr, $separator:path, $e:path => { $gen:expr }) => ( alt_sep!(__impl $i, $separator, call!($e) => { $gen }); ); (__impl $i:expr, $separator:path, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; match sep!($i, $separator, $subrule!( $($args)* )) { Ok((i,o)) => Ok((i,$gen(o))), Err(Err::Error(e)) => { fn unify_types(_: &T, _: &T) {} let e2 = error_position!($i, $crate::ErrorKind::Alt); unify_types(&e, &e2); Err(Err::Error(e2)) }, Err(e) => Err(e), } } ); (__impl $i:expr, $separator:path, $e:path) => ( alt_sep!(__impl $i, $separator, call!($e)); ); (__impl $i:expr, $separator:path, $subrule:ident!( $($args:tt)*)) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; match sep!($i, $separator, $subrule!( $($args)* )) { Ok((i,o)) => Ok((i,o)), Err(Err::Error(e)) => { fn unify_types(_: &T, _: &T) {} let e2 = error_position!($i, $crate::ErrorKind::Alt); unify_types(&e, &e2); Err(Err::Error(e2)) }, Err(e) => Err(e), } } ); (__impl $i:expr) => ({ use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,IResult}; Err(Err::Error(error_position!($i, $crate::ErrorKind::Alt))) }); (__impl $i:expr, $separator:path) => ({ use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,IResult}; Err(Err::Error(error_position!($i, $crate::ErrorKind::Alt))) }); ($i:expr, $separator:path, $($rest:tt)*) => ( { alt_sep!(__impl $i, $separator, $($rest)*) } ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! alt_complete_sep ( ($i:expr, $separator:path, $e:path | $($rest:tt)*) => ( alt_complete_sep!($i, $separator, complete!(call!($e)) | $($rest)*); ); ($i:expr, $separator:path, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => ( { use $crate::lib::std::result::Result::*; let res = complete!($i, sep!($separator, $subrule!($($args)*))); match res { Ok((_,_)) => res, _ => alt_complete_sep!($i, $separator, $($rest)*), } } ); ($i:expr, $separator:path, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => ( { use $crate::lib::std::result::Result::*; use $crate::{Err,Needed,IResult}; match complete!($i, sep!($separator, $subrule!($($args)*))) { Ok((i,o)) => Ok((i,$gen(o))), _ => alt_complete_sep!($i, $separator, $($rest)*), } } ); ($i:expr, $separator:path, $e:path => { $gen:expr } | $($rest:tt)*) => ( alt_complete_sep!($i, $separator, complete!(call!($e)) => { $gen } | $($rest)*); ); // Tail (non-recursive) rules ($i:expr, $separator:path, $e:path => { $gen:expr }) => ( alt_complete_sep!($i, $separator, call!($e) => { $gen }); ); ($i:expr, $separator:path, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => ( alt_sep!(__impl $i, $separator, complete!($subrule!($($args)*)) => { $gen }) ); ($i:expr, $separator:path, $e:path) => ( alt_complete_sep!($i, $separator, call!($e)); ); ($i:expr, $separator:path, $subrule:ident!( $($args:tt)*)) => ( alt_sep!(__impl $i, $separator, complete!($subrule!($($args)*))) ); ); #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! switch_sep ( (__impl $i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => ( { use $crate::lib::std::result::Result::*; use $crate::Err; match sep!($i, $separator, $submac!($($args)*)) { Err(Err::Error(e)) => Err(Err::Error(error_node_position!( $i, $crate::ErrorKind::Switch, e ))), Err(Err::Failure(e)) => Err(Err::Failure( error_node_position!($i, $crate::ErrorKind::Switch, e))), Err(e) => Err(e), Ok((i, o)) => { match o { $($p => match sep!(i, $separator, $subrule!($($args2)*)) { Err(Err::Error(e)) => Err(Err::Error(error_node_position!( $i, $crate::ErrorKind::Switch, e ))), Err(Err::Failure(e)) => Err(Err::Failure( error_node_position!($i, $crate::ErrorKind::Switch, e))), a => a, }),*, _ => Err(Err::Error(error_position!($i, $crate::ErrorKind::Switch))) } } } } ); ($i:expr, $separator:path, $submac:ident!( $($args:tt)*), $($rest:tt)*) => ( { switch_sep!(__impl $i, $separator, $submac!($($args)*), $($rest)*) } ); ($i:expr, $separator:path, $e:path, $($rest:tt)*) => ( { switch_sep!(__impl $i, $separator, call!($e), $($rest)*) } ); ); #[doc(hidden)] #[cfg(feature = "alloc")] #[macro_export(local_inner_macros)] macro_rules! separated_list_sep ( ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => ( separated_list!( $i, sep!($separator, $submac!($($args)*)), sep!($separator, $submac2!($($args2)*)) ) ); ($i:expr, $separator:path, $submac:ident!( $($args:tt)* ), $g:expr) => ( separated_list_sep!($i, $separator, $submac!($($args)*), call!($g)); ); ($i:expr, $separator:path, $f:expr, $submac:ident!( $($args:tt)* )) => ( separated_list_sep!($i, $separator, call!($f), $submac!($($args)*)); ); ($i:expr, $separator:path, $f:expr, $g:expr) => ( separated_list_sep!($i, $separator, call!($f), call!($g)); ); ); /// helper macros to build a separator parser /// /// ``` /// # #[macro_use] extern crate nom; /// named!(pub space, eat_separator!(&b" \t"[..])); /// # fn main() {} /// ``` #[macro_export(local_inner_macros)] macro_rules! eat_separator ( ($i:expr, $arr:expr) => ( { use $crate::{FindToken, InputTakeAtPosition}; let input = $i; input.split_at_position(|c| !$arr.find_token(c)) } ); ); /// sep is the parser rewriting macro for whitespace separated formats /// /// it takes as argument a space eating function and a parser tree, /// and will intersperse the space parser everywhere /// /// ```ignore /// #[macro_export(local_inner_macros)] /// macro_rules! ws ( /// ($i:expr, $($args:tt)*) => ( /// { /// use sp; /// sep!($i, sp, $($args)*) /// } /// ) /// ); /// ``` #[macro_export(local_inner_macros)] macro_rules! sep ( ($i:expr, $separator:path, tuple ! ($($rest:tt)*) ) => { tuple_sep!($i, $separator, (), $($rest)*) }; ($i:expr, $separator:path, pair ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, pair_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, delimited ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, delimited_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, separated_pair ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, separated_pair_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, preceded ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, preceded_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, terminated ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, terminated_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, do_parse ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, do_parse_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, permutation ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, permutation_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, alt ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, alt_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, alt_complete ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, alt_complete_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, switch ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, switch_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, separated_list ! ($($rest:tt)*) ) => { wrap_sep!($i, $separator, separated_list_sep!($separator, $($rest)*) ) }; ($i:expr, $separator:path, many0 ! ($($rest:tt)*) ) => { many0!($i, wrap_sep!($separator, $($rest)*)) }; ($i:expr, $separator:path, many1 ! ($($rest:tt)*) ) => { many1!($i, wrap_sep!($separator, $($rest)*)) }; ($i:expr, $separator:path, return_error!( $($args:tt)* )) => { return_error!($i, wrap_sep!($separator, $($args)*)) }; //FIXME: missing separated_nonempty_list, // many_till, many_m_n, count, count_fixed, fold_many0, fold_many1, // fold_many_m_n ($i:expr, $separator:path, $submac:ident!( $($args:tt)* )) => { wrap_sep!($i, $separator, $submac!($($args)*)) }; ($i:expr, $separator:path, $f:expr) => { wrap_sep!($i, $separator, call!($f)) }; ); use internal::IResult; use traits::{AsChar, FindToken, InputTakeAtPosition}; #[allow(unused_imports)] pub fn sp<'a, T>(input: T) -> IResult where T: InputTakeAtPosition, ::Item: AsChar + Clone, &'a str: FindToken<::Item>, { input.split_at_position(|item| { let c = item.clone().as_char(); !(c == ' ' || c == '\t' || c == '\r' || c == '\n') }) //this could be written as followed, but not using FindToken is faster //eat_separator!(input, " \t\r\n") } /// `ws!(I -> IResult) => I -> IResult` /// /// transforms a parser to automatically consume /// whitespace between each token. By default, /// it takes the following characters: `" \t\r\n"`. /// /// If you need a whitespace parser consuming a /// different set of characters, you can make /// your own by reusing the `sep!` combinator. /// /// To use `ws!`, pass your parser as argument: /// /// ``` /// # #[macro_use] extern crate nom; /// # fn main() { /// named!(tuple<&[u8], (&[u8], &[u8]) >, /// ws!(tuple!( take!(3), tag!("de") )) /// ); /// /// assert_eq!( /// tuple(&b" \t abc de fg"[..]), /// Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) /// ); /// # } /// ``` /// #[macro_export(local_inner_macros)] macro_rules! ws ( ($i:expr, $($args:tt)*) => ( { use $crate::sp; use $crate::Convert; use $crate::Err; use $crate::lib::std::result::Result::*; match sep!($i, sp, $($args)*) { Err(e) => Err(e), Ok((i1,o)) => { match (sp)(i1) { Err(e) => Err(Err::convert(e)), Ok((i2,_)) => Ok((i2, o)) } } } } ) ); #[cfg(test)] #[allow(dead_code)] mod tests { #[cfg(feature = "alloc")] use lib::std::string::{String, ToString}; use internal::{Err, IResult, Needed}; use super::sp; use util::ErrorKind; use types::CompleteStr; #[test] fn spaaaaace() { assert_eq!(sp(&b" \t abc "[..]), Ok((&b"abc "[..], &b" \t "[..]))); } #[test] fn tag() { named!(abc, ws!(tag!("abc"))); assert_eq!(abc(&b" \t abc def"[..]), Ok((&b"def"[..], &b"abc"[..]))); } #[test] fn pair() { named!(pair_2<&[u8], (&[u8], &[u8]) >, ws!(pair!( take!(3), tag!("de") )) ); assert_eq!( pair_2(&b" \t abc de fg"[..]), Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) ); } #[test] fn preceded() { named!(prec<&[u8], &[u8] >, ws!(preceded!( take!(3), tag!("de") )) ); assert_eq!(prec(&b" \t abc de fg"[..]), Ok((&b"fg"[..], &b"de"[..]))); } #[test] fn terminated() { named!(term<&[u8], &[u8] >, ws!(terminated!( take!(3), tag!("de") )) ); assert_eq!(term(&b" \t abc de fg"[..]), Ok((&b"fg"[..], &b"abc"[..]))); } #[test] fn tuple() { //trace_macros!(true); named!(tuple_2<&[u8], (&[u8], &[u8]) >, ws!(tuple!( take!(3), tag!("de") )) ); //trace_macros!(false); assert_eq!( tuple_2(&b" \t abc de fg"[..]), Ok((&b"fg"[..], (&b"abc"[..], &b"de"[..]))) ); } #[test] fn levels() { //trace_macros!(true); named!(level_2<&[u8], (&[u8], (&[u8], &[u8])) >, ws!(pair!(take!(3), tuple!( tag!("de"), tag!("fg ") ))) ); //trace_macros!(false); assert_eq!( level_2(&b" \t abc de fg \t hi "[..]), Ok((&b"hi "[..], (&b"abc"[..], (&b"de"[..], &b"fg "[..])))) ); } #[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)>, ws!(do_parse!( tag!("abcd") >> opt!(tag!("abcd")) >> aa: ret_int1 >> tag!("efgh") >> bb: ret_int2 >> tag!("efgh") >> (aa, bb) )) ); //trace_macros!(false); assert_eq!( do_parser(&b"abcd abcd\tefghefghX"[..]), Ok((&b"X"[..], (1, 2))) ); assert_eq!( do_parser(&b"abcd\tefgh efgh X"[..]), Ok((&b"X"[..], (1, 2))) ); assert_eq!( do_parser(&b"abcd ab"[..]), Err(Err::Incomplete(Needed::Size(4))) ); assert_eq!( do_parser(&b" abcd\tefgh\tef"[..]), Err(Err::Incomplete(Needed::Size(4))) ); } #[test] fn permutation() { //trace_macros!(true); named!( perm<(&[u8], &[u8], &[u8])>, ws!(permutation!(tag!("abcd"), tag!("efg"), tag!("hi"))) ); //trace_macros!(false); let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]); let a = &b"abcd\tefg \thijk"[..]; assert_eq!(perm(a), Ok((&b"jk"[..], expected))); let b = &b" efg \tabcdhi jk"[..]; assert_eq!(perm(b), Ok((&b"jk"[..], expected))); let c = &b" hi efg\tabcdjk"[..]; assert_eq!(perm(c), Ok((&b"jk"[..], expected))); let d = &b"efg xyzabcdefghi"[..]; assert_eq!( perm(d), Err(Err::Error(error_node_position!( &b"efg xyzabcdefghi"[..], ErrorKind::Permutation, error_position!(&b" xyzabcdefghi"[..], ErrorKind::Permutation) ))) ); let e = &b" efg \tabc"[..]; assert_eq!(perm(e), Err(Err::Incomplete(Needed::Size(4)))); } #[cfg(feature = "alloc")] #[derive(Debug, Clone, PartialEq)] pub struct ErrorStr(String); #[cfg(feature = "alloc")] impl From 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")] #[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> { use Context; Err(Err::Error(Context::Code( &b""[..], ErrorKind::Custom(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) } let a = &b"\tabcd"[..]; 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, ws!(alt!(tag!("abcd") | tag!("efgh")))); assert_eq!( alt4(CompleteStr("\tabcd")), Ok((CompleteStr(""), CompleteStr(r"abcd"))) ); assert_eq!( alt4(CompleteStr(" efgh ")), Ok((CompleteStr(""), CompleteStr("efgh"))) ); // test the alternative syntax named!(alt5, ws!(alt!(tag!("abcd") => { |_| false } | tag!("efgh") => { |_| true }))); assert_eq!(alt5(CompleteStr("\tabcd")), Ok((CompleteStr(""), false))); assert_eq!(alt5(CompleteStr(" efgh ")), Ok((CompleteStr(""), true))); } /*FIXME: alt_complete works, but ws will return Incomplete on end of input #[test] fn alt_complete() { named!(ac<&[u8], &[u8]>, ws!(alt_complete!(tag!("abcd") | tag!("ef") | tag!("ghi") | tag!("kl"))) ); let a = &b""[..]; assert_eq!(ac(a), Err(Err::Error(error_position!(a, ErrorKind::Alt)))); let a = &b" \tef "[..]; assert_eq!(ac(a),Ok((&b""[..], &b"ef"[..]))); let a = &b" cde"[..]; assert_eq!(ac(a), Err(Err::Error(error_position!(&a[1..], ErrorKind::Alt)))); } */ #[allow(unused_variables)] #[test] fn switch() { named!(sw, ws!(switch!(take!(4), CompleteStr("abcd") => take!(2) | CompleteStr("efgh") => take!(4) )) ); let a = CompleteStr(" abcd ef gh"); assert_eq!(sw(a), Ok((CompleteStr("gh"), CompleteStr("ef")))); let b = CompleteStr("\tefgh ijkl "); assert_eq!(sw(b), Ok((CompleteStr(""), CompleteStr("ijkl")))); let c = CompleteStr("afghijkl"); assert_eq!( sw(c), Err(Err::Error(error_position!( CompleteStr("afghijkl"), ErrorKind::Switch ))) ); } named!(str_parse(&str) -> &str, ws!(tag!("test"))); #[allow(unused_variables)] #[test] fn str_test() { assert_eq!(str_parse(" \n test\t a\nb"), Ok(("a\nb", "test"))); } // test whitespace parser generation for alt named!(space, tag!(" ")); #[cfg(feature = "alloc")] named!(pipeline_statement<&[u8], ()>, ws!( do_parse!( tag!("pipeline") >> attributes: delimited!(char!('{'), separated_list!(char!(','), alt!( space | space )), char!('}')) >> ({ let _ = attributes; () }) ) ) ); #[cfg(feature = "alloc")] named!( fail<&[u8]>, map!(many_till!(take!(1), ws!(tag!("."))), |(r, _)| r[0]) ); } nom-4.2.3/tests/arithmetic.rs010064400007670000024000000047251331546446000144110ustar0000000000000000#[macro_use] extern crate nom; use nom::digit; use nom::types::CompleteStr; // Parser definition use std::str::FromStr; // We parse any expr surrounded by parens, ignoring all whitespaces around those named!(parens, ws!(delimited!( tag!("("), expr, tag!(")") )) ); // 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 parens parser defined above named!(factor, alt!( map_res!( ws!(digit), |s:CompleteStr| { FromStr::from_str(s.0) } ) | parens ) ); // 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 , do_parse!( init: factor >> res: fold_many0!( pair!(alt!(char!('*') | char!('/')), factor), init, |acc, (op, val): (char, i64)| { if op == '*' { acc * val } else { acc / val } } ) >> (res) ) ); named!(expr , do_parse!( init: term >> res: fold_many0!( pair!(alt!(char!('+') | char!('-')), term), init, |acc, (op, val): (char, i64)| { if op == '+' { acc + val } else { acc - val } } ) >> (res) ) ); #[test] fn factor_test() { assert_eq!(factor(CompleteStr("3")), Ok((CompleteStr(""), 3))); assert_eq!(factor(CompleteStr(" 12")), Ok((CompleteStr(""), 12))); assert_eq!(factor(CompleteStr("537 ")), Ok((CompleteStr(""), 537))); assert_eq!(factor(CompleteStr(" 24 ")), Ok((CompleteStr(""), 24))); } #[test] fn term_test() { assert_eq!(term(CompleteStr(" 12 *2 / 3")), Ok((CompleteStr(""), 8))); assert_eq!( term(CompleteStr(" 2* 3 *2 *2 / 3")), Ok((CompleteStr(""), 8)) ); assert_eq!(term(CompleteStr(" 48 / 3/2")), Ok((CompleteStr(""), 8))); } #[test] fn expr_test() { assert_eq!(expr(CompleteStr(" 1 + 2 ")), Ok((CompleteStr(""), 3))); assert_eq!( expr(CompleteStr(" 12 + 6 - 4+ 3")), Ok((CompleteStr(""), 17)) ); assert_eq!(expr(CompleteStr(" 1 + 2*3 + 4")), Ok((CompleteStr(""), 11))); } #[test] fn parens_test() { assert_eq!(expr(CompleteStr(" ( 2 )")), Ok((CompleteStr(""), 2))); assert_eq!( expr(CompleteStr(" 2* ( 3 + 4 ) ")), Ok((CompleteStr(""), 14)) ); assert_eq!( expr(CompleteStr(" 2*2 / ( 5 - 1) + 3")), Ok((CompleteStr(""), 4)) ); } nom-4.2.3/tests/arithmetic_ast.rs010064400007670000024000000077271331546446000152650ustar0000000000000000#[macro_use] extern crate nom; use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::str::FromStr; use nom::{digit, multispace}; use nom::types::CompleteStr; pub enum Expr { Value(i64), Add(Box, Box), Sub(Box, Box), Mul(Box, Box), Div(Box, Box), Paren(Box), } #[derive(Debug)] pub enum Oper { Add, Sub, Mul, Div, } impl Display for Expr { fn fmt(&self, format: &mut Formatter) -> fmt::Result { use self::Expr::*; match *self { Value(val) => write!(format, "{}", val), Add(ref left, ref right) => write!(format, "{} + {}", left, right), Sub(ref left, ref right) => write!(format, "{} - {}", left, right), Mul(ref left, ref right) => write!(format, "{} * {}", left, right), Div(ref left, ref right) => write!(format, "{} / {}", left, right), Paren(ref expr) => write!(format, "({})", expr), } } } impl Debug for Expr { fn fmt(&self, format: &mut Formatter) -> fmt::Result { use self::Expr::*; match *self { Value(val) => write!(format, "{}", val), Add(ref left, ref right) => write!(format, "({:?} + {:?})", left, right), Sub(ref left, ref right) => write!(format, "({:?} - {:?})", left, right), Mul(ref left, ref right) => write!(format, "({:?} * {:?})", left, right), Div(ref left, ref right) => write!(format, "({:?} / {:?})", left, right), Paren(ref expr) => write!(format, "[{:?}]", expr), } } } named!(parens< CompleteStr, Expr >, delimited!( delimited!(opt!(multispace), tag!("("), opt!(multispace)), map!(map!(expr, Box::new), Expr::Paren), delimited!(opt!(multispace), tag!(")"), opt!(multispace)) ) ); named!(factor< CompleteStr, Expr >, alt_complete!( map!( map_res!( delimited!(opt!(multispace), digit, opt!(multispace)), |s: CompleteStr| { FromStr::from_str(s.0) } ), Expr::Value ) | parens ) ); fn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr { remainder.into_iter().fold(initial, |acc, pair| { let (oper, expr) = pair; match oper { Oper::Add => Expr::Add(Box::new(acc), Box::new(expr)), Oper::Sub => Expr::Sub(Box::new(acc), Box::new(expr)), Oper::Mul => Expr::Mul(Box::new(acc), Box::new(expr)), Oper::Div => Expr::Div(Box::new(acc), Box::new(expr)), } }) } named!(term< CompleteStr, Expr >, do_parse!( initial: factor >> remainder: many0!( alt!( do_parse!(tag!("*") >> mul: factor >> (Oper::Mul, mul)) | do_parse!(tag!("/") >> div: factor >> (Oper::Div, div)) ) ) >> (fold_exprs(initial, remainder)) )); named!(expr< CompleteStr, Expr >, do_parse!( initial: term >> remainder: many0!( alt!( do_parse!(tag!("+") >> add: term >> (Oper::Add, add)) | do_parse!(tag!("-") >> sub: term >> (Oper::Sub, sub)) ) ) >> (fold_exprs(initial, remainder)) )); #[test] fn factor_test() { assert_eq!( factor(CompleteStr(" 3 ")).map(|(i, x)| (i, format!("{:?}", x))), Ok((CompleteStr(""), String::from("3"))) ); } #[test] fn term_test() { assert_eq!( term(CompleteStr(" 3 * 5 ")).map(|(i, x)| (i, format!("{:?}", x))), Ok((CompleteStr(""), String::from("(3 * 5)"))) ); } #[test] fn expr_test() { assert_eq!( expr(CompleteStr(" 1 + 2 * 3 ")).map(|(i, x)| (i, format!("{:?}", x))), Ok((CompleteStr(""), String::from("(1 + (2 * 3))"))) ); assert_eq!( expr(CompleteStr(" 1 + 2 * 3 / 4 - 5 ")).map(|(i, x)| (i, format!("{:?}", x))), Ok((CompleteStr(""), String::from("((1 + ((2 * 3) / 4)) - 5)"))) ); assert_eq!( expr(CompleteStr(" 72 / 2 / 3 ")).map(|(i, x)| (i, format!("{:?}", x))), Ok((CompleteStr(""), String::from("((72 / 2) / 3)"))) ); } #[test] fn parens_test() { assert_eq!( expr(CompleteStr(" ( 1 + 2 ) * 3 ")).map(|(i, x)| (i, format!("{:?}", x))), Ok((CompleteStr(""), String::from("([(1 + 2)] * 3)"))) ); } nom-4.2.3/tests/blockbuf-arithmetic.rs010064400007670000024000000167351326711743200162020ustar0000000000000000/* #[macro_use] extern crate nom; extern crate bytes; use nom::{Compare,CompareResult,InputLength,InputIter,Slice,HexDisplay}; use std::str; use std::str::FromStr; use bytes::{Buf,MutBuf}; use bytes::buf::{BlockBuf,BlockBufCursor}; use std::ops::{Range,RangeTo,RangeFrom,RangeFull}; use std::iter::{Enumerate,Iterator}; use std::fmt; use std::cmp::{min,PartialEq}; #[derive(Clone,Copy)] #[repr(C)] pub struct BlockSlice<'a> { buf: &'a BlockBuf, start: usize, end: usize, } impl<'a> BlockSlice<'a> { fn cursor(&self) -> WrapCursor<'a> { let mut cur = self.buf.buf(); cur.advance(self.start); WrapCursor { cursor: cur, length: self.end - self.start, } } } impl<'a> fmt::Debug for BlockSlice<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "BlockSlice {{ start: {}, end: {}, data:\n{}\n}}", self.start, self.end, self.buf.bytes().unwrap_or(&b""[..]).to_hex(16)) } } impl<'a> PartialEq for BlockSlice<'a> { fn eq(&self, other: &BlockSlice<'a>) -> bool { let bufs = (self.buf as *const BlockBuf) == (other.buf as *const BlockBuf); self.start == other.start && self.end == other.end && bufs } } impl<'a> Slice> for BlockSlice<'a> { fn slice(&self, range:Range) -> Self { BlockSlice { buf: self.buf, start: self.start + range.start, //FIXME: check for valid end here end: self.start + range.end, } } } impl<'a> Slice> for BlockSlice<'a> { fn slice(&self, range:RangeTo) -> Self { self.slice(0..range.end) } } impl<'a> Slice> for BlockSlice<'a> { fn slice(&self, range:RangeFrom) -> Self { self.slice(range.start..self.end - self.start) } } impl<'a> Slice for BlockSlice<'a> { fn slice(&self, _:RangeFull) -> Self { BlockSlice { buf: self.buf, start: self.start, end: self.end, } } } impl<'a> InputIter for BlockSlice<'a> { type Item = u8; type RawItem = u8; type Iter = Enumerate>; type IterElem = WrapCursor<'a>; fn iter_indices(&self) -> Self::Iter { self.cursor().enumerate() } fn iter_elements(&self) -> Self::IterElem { self.cursor() } fn position

(&self, predicate: P) -> Option where P: Fn(Self::RawItem) -> bool { self.cursor().position(|b| predicate(b)) } fn slice_index(&self, count:usize) -> Option { if self.end - self.start >= count { Some(count) } else { None } } } impl<'a> InputLength for BlockSlice<'a> { fn input_len(&self) -> usize { self.end - self.start } } impl<'a,'b> Compare<&'b[u8]> for BlockSlice<'a> { fn compare(&self, t: &'b[u8]) -> CompareResult { let len = self.end - self.start; let blen = t.len(); let m = if len < blen { len } else { blen }; let reduced = self.slice(..m); let b = &t[..m]; for (a,b) in reduced.cursor().zip(b.iter()) { if a != *b { return CompareResult::Error; } } if m < blen { CompareResult::Incomplete } else { CompareResult::Ok } } #[inline(always)] fn compare_no_case(&self, t: &'b[u8]) -> CompareResult { let len = self.end - self.start; let blen = t.len(); let m = if len < blen { len } else { blen }; let reduced = self.slice(..m); let other = &t[..m]; if !reduced.cursor().zip(other).all(|(a, b)| { match (a,*b) { (0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == *b, (65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122 ) |(97...122, 65...90) => { a & 0b01000000 == *b & 0b01000000 } _ => false } }) { CompareResult::Error } else if m < blen { CompareResult::Incomplete } else { CompareResult::Ok } } } impl<'a,'b> Compare<&'b str> for BlockSlice<'a> { fn compare(&self, t: &'b str) -> CompareResult { self.compare(str::as_bytes(t)) } fn compare_no_case(&self, t: &'b str) -> CompareResult { self.compare_no_case(str::as_bytes(t)) } } //Wrapper to implement Iterator on BlockBufCursor pub struct WrapCursor<'a> { pub cursor: BlockBufCursor<'a>, pub length: usize, } impl<'a> Iterator for WrapCursor<'a> { type Item = u8; fn next(&mut self) -> Option { //println!("NEXT: length={}, remaining={}", self.length, self.cursor.remaining()); if min(self.length, self.cursor.remaining()) > 0 { self.length -=1; Some(self.cursor.read_u8()) } else { None } } } //Reimplement eat_separator instead of fixing iterators #[macro_export] macro_rules! block_eat_separator ( ($i:expr, $arr:expr) => ( { use nom::{InputLength,InputIter,Slice}; if ($i).input_len() == 0 { Ok(($i, ($i).slice(0..0))) } else { match ($i).iter_indices().position(|(_, item)| { for (_,c) in ($arr).iter_indices() { if *c == item { return false; } } true }) { Some(index) => { Ok((($i).slice(index..), ($i).slice(..index))) }, None => { Ok((($i).slice(($i).input_len()..), $i)) } } } } ) ); #[macro_export] macro_rules! block_named ( ($name:ident, $submac:ident!( $($args:tt)* )) => ( fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult, BlockSlice<'a>, u32> { $submac!(i, $($args)*) } ); ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult, $o, u32> { $submac!(i, $($args)*) } ); ); block_named!(sp, block_eat_separator!(&b" \t\r\n"[..])); macro_rules! block_ws ( ($i:expr, $($args:tt)*) => ( { sep!($i, sp, $($args)*) } ) ); block_named!(digit, is_a!("0123456789")); block_named!(parens, block_ws!(delimited!( tag!("("), expr, tag!(")") )) ); block_named!(factor, alt!( map_res!( block_ws!(digit), to_i64 ) | parens ) ); block_named!(term , do_parse!( init: factor >> res: fold_many0!( pair!(alt!(tag!("*") | tag!("/")), factor), init, |acc, (op, val): (BlockSlice, i64)| { if (op.cursor().next().unwrap() as char) == '*' { acc * val } else { acc / val } } ) >> (res) ) ); block_named!(expr , do_parse!( init: term >> res: fold_many0!( pair!(alt!(tag!("+") | tag!("-")), term), init, |acc, (op, val): (BlockSlice, i64)| { if (op.cursor().next().unwrap() as char) == '+' { acc + val } else { acc - val } } ) >> (res) ) ); fn blockbuf_from(input: &[u8]) -> BlockBuf { let mut b = BlockBuf::new(2, 100); b.copy_from(input); b } fn sl<'a>(input: &'a BlockBuf) -> BlockSlice<'a> { BlockSlice { buf: input, start: 0, end: input.len(), } } fn to_i64<'a>(input: BlockSlice<'a>) -> Result { let v: Vec = input.cursor().collect(); match str::from_utf8(&v) { Err(_) => Err(()), Ok(s) => match FromStr::from_str(s) { Err(_) => Err(()), Ok(i) => Ok(i) } } } #[test] fn factor_test() { let a = blockbuf_from(&b"3"[..]); println!("calculated: {:?}", factor(sl(&a))); } #[test] fn parens_test() { let input1 = blockbuf_from(&b" 2* ( 3 + 4 ) "[..]); println!("calculated 1: {:?}", expr(sl(&input1))); let input2 = blockbuf_from(&b" 2*2 / ( 5 - 1) + 3"[..]); println!("calculated 2: {:?}", expr(sl(&input2))); } */ nom-4.2.3/tests/complete_arithmetic.rs010064400007670000024000000041561331546446000162770ustar0000000000000000#[macro_use] extern crate nom; use nom::types::CompleteStr; use std::str::FromStr; #[macro_export] macro_rules! complete_named ( ($name:ident, $submac:ident!( $($args:tt)* )) => ( fn $name( i: CompleteStr ) -> nom::IResult { $submac!(i, $($args)*) } ); ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( fn $name( i: CompleteStr ) -> nom::IResult { $submac!(i, $($args)*) } ); ); complete_named!(digit, is_a!("0123456789")); complete_named!(parens, ws!(delimited!(tag!("("), expr, tag!(")")))); complete_named!(factor, alt!(map_res!(ws!(digit), to_i64) | parens)); complete_named!( term, do_parse!( init: factor >> res: fold_many0!( pair!(alt!(tag!("*") | tag!("/")), factor), init, |acc, (op, val): (CompleteStr, i64)| if (op.0.chars().next().unwrap() as char) == '*' { acc * val } else { acc / val } ) >> (res) ) ); complete_named!( expr, do_parse!( init: term >> res: fold_many0!( pair!(alt!(tag!("+") | tag!("-")), term), init, |acc, (op, val): (CompleteStr, i64)| if (op.0.chars().next().unwrap() as char) == '+' { acc + val } else { acc - val } ) >> (res) ) ); complete_named!(root_expr, terminated!(expr, eof!())); fn to_i64(input: CompleteStr) -> Result { match FromStr::from_str(input.0) { Err(_) => Err(()), Ok(i) => Ok(i), } } #[test] fn factor_test() { let a = CompleteStr("3"); println!("calculated: {:?}", factor(a)); } #[test] fn parens_test() { use nom::ErrorKind; let input1 = CompleteStr(" 2* ( 3 + 4 ) "); assert_eq!(expr(input1), Ok((CompleteStr(""), 14))); let input2 = CompleteStr(" 2*2 / ( 5 - 1) + 3"); assert_eq!(expr(input2), Ok((CompleteStr(""), 4))); let input3 = CompleteStr(" 2*2 / ( 5 - 1) + "); assert_eq!( root_expr(input3), Err(nom::Err::Error(error_position!( CompleteStr("+ "), ErrorKind::Eof ))) ); } nom-4.2.3/tests/complete_float.rs010064400007670000024000000033611331546446000152500ustar0000000000000000#[macro_use] extern crate nom; use nom::digit; use nom::types::CompleteStr; #[macro_export] macro_rules! complete_named ( ($name:ident, $submac:ident!( $($args:tt)* )) => ( fn $name( i: CompleteStr ) -> nom::IResult { $submac!(i, $($args)*) } ); ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( fn $name( i: CompleteStr ) -> nom::IResult { $submac!(i, $($args)*) } ); ); complete_named!( unsigned_float, flat_map!( recognize!(alt!( delimited!(digit, tag!("."), opt!(digit)) | delimited!(opt!(digit), tag!("."), digit) )), parse_to!(f32) ) ); complete_named!( float, map!( pair!(opt!(alt!(tag!("+") | tag!("-"))), unsigned_float), |(sign, value): (Option, f32)| sign .and_then(|s| s.0.chars().next()) .and_then(|c| if c == '-' { Some(-1f32) } else { None }) .unwrap_or(1f32) * value ) ); #[test] fn unsigned_float_test() { assert_eq!( unsigned_float(CompleteStr("123.456")), Ok((CompleteStr(""), 123.456)) ); assert_eq!( unsigned_float(CompleteStr("0.123")), Ok((CompleteStr(""), 0.123)) ); assert_eq!( unsigned_float(CompleteStr("123.0")), Ok((CompleteStr(""), 123.0)) ); assert_eq!( unsigned_float(CompleteStr("123.")), Ok((CompleteStr(""), 123.0)) ); assert_eq!( unsigned_float(CompleteStr(".123")), Ok((CompleteStr(""), 0.123)) ); } #[test] fn float_test() { assert_eq!( float(CompleteStr("123.456")), Ok((CompleteStr(""), 123.456)) ); assert_eq!( float(CompleteStr("+123.456")), Ok((CompleteStr(""), 123.456)) ); assert_eq!( float(CompleteStr("-123.456")), Ok((CompleteStr(""), -123.456)) ); } nom-4.2.3/tests/css.rs010064400007670000024000000013501335613157700130440ustar0000000000000000#[macro_use] extern crate nom; #[derive(Debug, PartialEq)] pub struct Color { pub red: u8, pub green: u8, pub blue: u8, } fn from_hex(input: &str) -> Result { u8::from_str_radix(input, 16) } fn is_hex_digit(c: char) -> bool { c.is_digit(16) } named!(hex_primary<&str, u8>, map_res!(take_while_m_n!(2, 2, is_hex_digit), from_hex) ); named!(hex_color<&str, Color>, do_parse!( tag!("#") >> red: hex_primary >> green: hex_primary >> blue: hex_primary >> (Color { red, green, blue }) ) ); #[test] fn parse_color() { assert_eq!( hex_color("#2F14DF"), Ok(( "", Color { red: 47, green: 20, blue: 223, } )) ); } nom-4.2.3/tests/custom_errors.rs010064400007670000024000000014741331546446000151640ustar0000000000000000#![allow(dead_code)] #![cfg_attr(feature = "cargo-clippy", allow(block_in_if_condition_stmt))] #[macro_use] extern crate nom; use nom::IResult; use nom::digit; use std::convert::From; pub struct CustomError(String); impl From for CustomError { fn from(error: u32) -> Self { CustomError(format!("error code was: {}", error)) } } fn test1(input: &str) -> IResult<&str, &str, CustomError> { fix_error!(input, CustomError, tag!("abcd")) } fn test2(input: &str) -> IResult<&str, &str, CustomError> { terminated!(input, test1, fix_error!(CustomError, digit)) } fn test3(input: &str) -> IResult<&str, &str, CustomError> { verify!(input, test1, |s: &str| { s.starts_with("abcd") }) } #[cfg(feature = "alloc")] fn test4(input: &str) -> IResult<&str, Vec<&str>, CustomError> { count!(input, test1, 4) } nom-4.2.3/tests/float.rs010064400007670000024000000022461331546446000133610ustar0000000000000000#[macro_use] extern crate nom; use nom::digit; use std::str; use std::str::FromStr; named!( unsigned_float, map_res!( map_res!( recognize!(alt!( delimited!(digit, tag!("."), opt!(digit)) | delimited!(opt!(digit), tag!("."), digit) )), str::from_utf8 ), FromStr::from_str ) ); named!( float, 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 ) ); #[test] fn unsigned_float_test() { assert_eq!(unsigned_float(&b"123.456;"[..]), Ok((&b";"[..], 123.456))); assert_eq!(unsigned_float(&b"0.123;"[..]), Ok((&b";"[..], 0.123))); assert_eq!(unsigned_float(&b"123.0;"[..]), Ok((&b";"[..], 123.0))); assert_eq!(unsigned_float(&b"123.;"[..]), Ok((&b";"[..], 123.0))); assert_eq!(unsigned_float(&b".123;"[..]), Ok((&b";"[..], 0.123))); } #[test] fn float_test() { assert_eq!(float(&b"123.456;"[..]), Ok((&b";"[..], 123.456))); assert_eq!(float(&b"+123.456;"[..]), Ok((&b";"[..], 123.456))); assert_eq!(float(&b"-123.456;"[..]), Ok((&b";"[..], -123.456))); } nom-4.2.3/tests/inference.rs010064400007670000024000000023561344541017100142060ustar0000000000000000//! 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 std::str; use nom::{alpha, is_digit}; // issue #617 named!(multi<&[u8], () >, fold_many0!( take_while1!( is_digit ), (), |_, _| {})); // issue #561 #[cfg(feature = "alloc")] named!( value>>, do_parse!( first_line: map_res!(is_not_s!("\n"), std::str::from_utf8) >> rest: many_m_n!( 0, 1, separated_list!( 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>) -> Option { 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>,do_parse!( u: opt!(many1!(alt_complete!( tag!("%") | tag!("#") | tag!("@") | alpha ))) >> (wrap_suffix(&u)) )); nom-4.2.3/tests/ini.rs010064400007670000024000000131271331546446000130330ustar0000000000000000#[macro_use] extern crate nom; use nom::{alphanumeric, multispace, space}; use nom::types::CompleteByteSlice; use std::str; use std::collections::HashMap; named!(category, map_res!( delimited!( char!('['), take_while!(call!(|c| c != b']')), char!(']') ), complete_byte_slice_to_str )); fn complete_byte_slice_to_str<'a>(s: CompleteByteSlice<'a>) -> Result<&'a str, str::Utf8Error> { str::from_utf8(s.0) } named!(key_value , 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 >, map!( many0!(terminated!(key_value, opt!(multispace))), |vec: Vec<_>| vec.into_iter().collect() ) ); named!(category_and_keys)>, do_parse!( category: category >> opt!(multispace) >> keys: keys_and_values >> (category, keys) ) ); named!(categories > >, 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() ) ); #[test] fn parse_category_test() { let ini_file = CompleteByteSlice( b"[category] parameter=value key = value2", ); let ini_without_category = CompleteByteSlice( b"\n\nparameter=value key = value2", ); let res = category(ini_file); println!("{:?}", res); match res { Ok((i, o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i.0), o), _ => println!("error"), } assert_eq!(res, Ok((ini_without_category, "category"))); } #[test] fn parse_key_value_test() { let ini_file = CompleteByteSlice( b"parameter=value key = value2", ); let ini_without_key_value = CompleteByteSlice(b"\nkey = value2"); let res = key_value(ini_file); println!("{:?}", res); match res { Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i.0), o1, o2), _ => println!("error"), } assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); } #[test] fn parse_key_value_with_space_test() { let ini_file = CompleteByteSlice( b"parameter = value key = value2", ); let ini_without_key_value = CompleteByteSlice(b"\nkey = value2"); let res = key_value(ini_file); println!("{:?}", res); match res { Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i.0), o1, o2), _ => println!("error"), } assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); } #[test] fn parse_key_value_with_comment_test() { let ini_file = CompleteByteSlice( b"parameter=value;abc key = value2", ); let ini_without_key_value = CompleteByteSlice(b"\nkey = value2"); let res = key_value(ini_file); println!("{:?}", res); match res { Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i.0), o1, o2), _ => println!("error"), } assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); } #[test] fn parse_multiple_keys_and_values_test() { let ini_file = CompleteByteSlice( b"parameter=value;abc key = value2 [category]", ); let ini_without_key_value = CompleteByteSlice(b"[category]"); let res = keys_and_values(ini_file); println!("{:?}", res); match res { Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i.0), o), _ => println!("error"), } let mut expected: HashMap<&str, &str> = HashMap::new(); expected.insert("parameter", "value"); expected.insert("key", "value2"); assert_eq!(res, Ok((ini_without_key_value, expected))); } #[test] fn parse_category_then_multiple_keys_and_values_test() { //FIXME: there can be an empty line or a comment line after a category let ini_file = CompleteByteSlice( b"[abcd] parameter=value;abc key = value2 [category]", ); let ini_after_parser = CompleteByteSlice(b"[category]"); let res = category_and_keys(ini_file); println!("{:?}", res); match res { Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i.0), o), _ => println!("error"), } let mut expected_h: HashMap<&str, &str> = HashMap::new(); expected_h.insert("parameter", "value"); expected_h.insert("key", "value2"); assert_eq!(res, Ok((ini_after_parser, ("abcd", expected_h)))); } #[test] fn parse_multiple_categories_test() { let ini_file = CompleteByteSlice( b"[abcd] parameter=value;abc key = value2 [category] parameter3=value3 key4 = value4 ", ); let ini_after_parser = CompleteByteSlice(b""); let res = categories(ini_file); //println!("{:?}", res); match res { Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i.0), o), _ => println!("error"), } let mut expected_1: HashMap<&str, &str> = HashMap::new(); expected_1.insert("parameter", "value"); expected_1.insert("key", "value2"); let mut expected_2: HashMap<&str, &str> = HashMap::new(); expected_2.insert("parameter3", "value3"); expected_2.insert("key4", "value4"); let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); expected_h.insert("abcd", expected_1); expected_h.insert("category", expected_2); assert_eq!(res, Ok((ini_after_parser, expected_h))); } nom-4.2.3/tests/ini_str.rs010064400007670000024000000141151344541017100137130ustar0000000000000000#[macro_use] extern crate nom; use nom::IResult; use nom::types::CompleteStr; use std::collections::HashMap; fn is_alphabetic(chr: char) -> bool { (chr as u8 >= 0x41 && chr as u8 <= 0x5A) || (chr as u8 >= 0x61 && chr as u8 <= 0x7A) } fn is_digit(chr: char) -> bool { chr as u8 >= 0x30 && chr as u8 <= 0x39 } fn is_alphanumeric(chr: char) -> bool { is_alphabetic(chr) || is_digit(chr) } fn is_space(chr: char) -> bool { chr == ' ' || chr == '\t' } fn is_line_ending_or_comment(chr: char) -> bool { chr == ';' || chr == '\n' } named!(alphanumeric, take_while_s!(is_alphanumeric)); named!(not_line_ending, is_not_s!("\r\n")); named!(space, take_while_s!(is_space)); named!(space_or_line_ending, is_a_s!(" \r\n")); fn right_bracket(c: char) -> bool { c == ']' } named!(category , do_parse!( tag_s!("[") >> name: take_till_s!(right_bracket) >> tag_s!("]") >> opt!(space_or_line_ending) >> (name.0) ) ); named!(key_value , do_parse!( key: alphanumeric >> opt!(space) >> tag_s!("=") >> opt!(space) >> val: take_till_s!(is_line_ending_or_comment) >> opt!(space) >> opt!(pair!(tag_s!(";"), not_line_ending)) >> opt!(space_or_line_ending) >> (key.0, val.0) ) ); named!(keys_and_values_aggregator >, many0!(key_value)); fn keys_and_values(input: CompleteStr) -> IResult> { match keys_and_values_aggregator(input) { Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())), Err(e) => Err(e), } } named!(category_and_keys)>, pair!(category, keys_and_values) ); named!(categories_aggregator)> >, many0!(category_and_keys)); fn categories(input: CompleteStr) -> IResult>> { match categories_aggregator(input) { Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())), Err(e) => Err(e), } } #[test] fn parse_category_test() { let ini_file = CompleteStr( "[category] parameter=value key = value2", ); let ini_without_category = CompleteStr( "parameter=value key = value2", ); let res = category(ini_file); println!("{:?}", res); match res { Ok((i, o)) => println!("i: {} | o: {:?}", i.0, o), _ => println!("error"), } assert_eq!(res, Ok((ini_without_category, "category"))); } #[test] fn parse_key_value_test() { let ini_file = CompleteStr( "parameter=value key = value2", ); let ini_without_key_value = CompleteStr("key = value2"); let res = key_value(ini_file); println!("{:?}", res); match res { Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i.0, o1, o2), _ => println!("error"), } assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); } #[test] fn parse_key_value_with_space_test() { let ini_file = CompleteStr( "parameter = value key = value2", ); let ini_without_key_value = CompleteStr("key = value2"); let res = key_value(ini_file); println!("{:?}", res); match res { Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i.0, o1, o2), _ => println!("error"), } assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); } #[test] fn parse_key_value_with_comment_test() { let ini_file = CompleteStr( "parameter=value;abc key = value2", ); let ini_without_key_value = CompleteStr("key = value2"); let res = key_value(ini_file); println!("{:?}", res); match res { Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i.0, o1, o2), _ => println!("error"), } assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); } #[test] fn parse_multiple_keys_and_values_test() { let ini_file = CompleteStr( "parameter=value;abc key = value2 [category]", ); let ini_without_key_value = CompleteStr("[category]"); let res = keys_and_values(ini_file); println!("{:?}", res); match res { Ok((i, ref o)) => println!("i: {} | o: {:?}", i.0, o), _ => println!("error"), } let mut expected: HashMap<&str, &str> = HashMap::new(); expected.insert("parameter", "value"); expected.insert("key", "value2"); assert_eq!(res, Ok((ini_without_key_value, expected))); } #[test] fn parse_category_then_multiple_keys_and_values_test() { //FIXME: there can be an empty line or a comment line after a category let ini_file = CompleteStr( "[abcd] parameter=value;abc key = value2 [category]", ); let ini_after_parser = CompleteStr("[category]"); let res = category_and_keys(ini_file); println!("{:?}", res); match res { Ok((i, ref o)) => println!("i: {} | o: {:?}", i.0, o), _ => println!("error"), } let mut expected_h: HashMap<&str, &str> = HashMap::new(); expected_h.insert("parameter", "value"); expected_h.insert("key", "value2"); assert_eq!(res, Ok((ini_after_parser, ("abcd", expected_h)))); } #[test] fn parse_multiple_categories_test() { let ini_file = CompleteStr( "[abcd] parameter=value;abc key = value2 [category] parameter3=value3 key4 = value4 ", ); let res = categories(ini_file); //println!("{:?}", res); match res { Ok((i, ref o)) => println!("i: {} | o: {:?}", i.0, o), _ => println!("error"), } let mut expected_1: HashMap<&str, &str> = HashMap::new(); expected_1.insert("parameter", "value"); expected_1.insert("key", "value2"); let mut expected_2: HashMap<&str, &str> = HashMap::new(); expected_2.insert("parameter3", "value3"); expected_2.insert("key4", "value4"); let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); expected_h.insert("abcd", expected_1); expected_h.insert("category", expected_2); assert_eq!(res, Ok((CompleteStr(""), expected_h))); } nom-4.2.3/tests/issues.rs010064400007670000024000000211761344541022400135630ustar0000000000000000//#![feature(trace_macros)] #![allow(dead_code)] #![cfg_attr(feature = "cargo-clippy", allow(redundant_closure))] #[macro_use] extern crate nom; use nom::{space, Err, IResult, Needed, ErrorKind, le_u64, is_digit}; use nom::types::{CompleteStr, CompleteByteSlice}; #[allow(dead_code)] struct Range { start: char, end: char, } pub fn take_char(input: &[u8]) -> IResult<&[u8], char> { if !input.is_empty() { Ok((&input[1..], input[0] as char)) } else { Err(Err::Incomplete(Needed::Size(1))) } } //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 >, 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::{digit, space, IResult}; use std::str; named!(parse_ints>, many0!(spaces_or_int)); 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) ) } #[test] fn issue_142() { let subject = parse_ints(&b"12 34 5689a"[..]); let expected = Ok((&b"a"[..], vec![12, 34, 5689])); assert_eq!(subject, expected); let subject = parse_ints(&b"12 34 5689 "[..]); let expected = Ok((&b" "[..], vec![12, 34, 5689])); assert_eq!(subject, expected) } } #[test] fn usize_length_bytes_issue() { use nom::be_u16; let _: IResult<&[u8], &[u8], u32> = length_bytes!(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 ) ); } */ #[test] fn take_till_issue() { named!(nothing, take_till!(call!(|_| true))); assert_eq!(nothing(b""), Err(Err::Incomplete(Needed::Size(1)))); assert_eq!(nothing(b"abc"), Ok((&b"abc"[..], &b""[..]))); } named!( issue_498>, separated_nonempty_list!(opt!(space), tag!("abcd")) ); named!(issue_308(&str) -> bool, do_parse! ( tag_s! ("foo") >> b: alt_complete! ( map! (tag_s! ("1"), |_: &str|->bool {true}) | value! (false) ) >> (b) )); #[cfg(feature = "alloc")] fn issue_302(input: &[u8]) -> IResult<&[u8], Option>> { do_parse!(input, entries: cond!(true, count!(le_u64, 3)) >> (entries)) } #[test] fn issue_655() { use nom::{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)) ) ); assert_eq!(twolines("foo\nbar\n"), Ok(("", ("foo", "bar")))); assert_eq!(twolines("féo\nbar\n"), Ok(("", ("féo", "bar")))); assert_eq!(twolines("foé\nbar\n"), Ok(("", ("foé", "bar")))); assert_eq!(twolines("foé\r\nbar\n"), Ok(("", ("foé", "bar")))); } #[cfg(feature = "std")] named!(issue_666 , dbg_dmp!(tag!("abc"))); #[test] fn issue_667() { use nom::alpha; named!(foo >, many0!( alt!(alpha | is_a!("_")) ) ); assert_eq!( foo(CompleteByteSlice(b"")), Ok((CompleteByteSlice(b""), vec![])) ); assert_eq!( foo(CompleteByteSlice(b"loremipsum")), Ok(( CompleteByteSlice(b""), vec![CompleteByteSlice(b"loremipsum")] )) ); assert_eq!( foo(CompleteByteSlice(b"lorem_ipsum")), Ok(( CompleteByteSlice(b""), vec![ CompleteByteSlice(b"lorem"), CompleteByteSlice(b"_"), CompleteByteSlice(b"ipsum"), ] )) ); assert_eq!( foo(CompleteByteSlice(b"_lorem_ipsum")), Ok(( CompleteByteSlice(b""), vec![ CompleteByteSlice(b"_"), CompleteByteSlice(b"lorem"), CompleteByteSlice(b"_"), CompleteByteSlice(b"ipsum"), ] )) ); assert_eq!( foo(CompleteByteSlice(b"!@#$")), Ok((CompleteByteSlice(b"!@#$"), vec![])) ); } #[test] fn issue_721() { 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_list!(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) ) ); named!(issue_741_str, re_match!(r"^_?[A-Za-z][0-9A-Z_a-z-]*")); named!(issue_741_bytes, re_bytes_match!(r"^_?[A-Za-z][0-9A-Z_a-z-]*")); #[test] fn issue_752() { assert_eq!( Err::Error(nom::Context::Code("ab", nom::ErrorKind::ParseTo)), parse_to!("ab", usize).unwrap_err() ) } fn atom_specials(c: u8) -> bool { c == b'q' } named!( capability<&str>, do_parse!(tag_s!(" ") >> _atom: map_res!(take_till1!(atom_specials), std::str::from_utf8) >> ("a")) ); #[test] fn issue_759() { assert_eq!(capability(b" abcqd"), Ok((&b"qd"[..], "a"))); } named_args!(issue_771(count: usize)>, length_count!(value!(count), call!(nom::be_u32)) ); #[test] fn issue_768() { named!(bit_vec8>, bits!(many0!(take_bits!(u16, 8)))); named!(bit_vec4>, bits!(many0!(take_bits!(u16, 4)))); named!(bit_vec3>, bits!(many0!(take_bits!(u16, 3)))); named!(bit_vec11>, bits!(many0!(take_bits!(u16, 11)))); let m: Vec = vec![70, 97, 106, 121, 86, 66, 105, 98, 86, 106, 101]; assert_eq!( bit_vec8(CompleteByteSlice(m.as_slice())), Ok((CompleteByteSlice(&[]), vec![70, 97, 106, 121, 86, 66, 105, 98, 86, 106, 101])) ); assert_eq!( bit_vec4(CompleteByteSlice(m.as_slice())), Ok((CompleteByteSlice(&[]), vec![4, 6, 6, 1, 6, 10, 7, 9, 5, 6, 4, 2, 6, 9, 6, 2, 5, 6, 6, 10, 6, 5])) ); assert_eq!( bit_vec3(CompleteByteSlice(m.as_slice())), Ok((CompleteByteSlice(&[]), vec![2, 1, 4, 6, 0, 5, 5, 2, 3, 6, 2, 5, 3, 1, 0, 2, 3, 2, 2, 6, 1, 1, 2, 6, 3, 2, 4, 6, 2])) ); assert_eq!( bit_vec11(CompleteByteSlice(m.as_slice())), Ok((CompleteByteSlice(&[]), vec![563, 90, 1266, 1380, 308, 1417, 717, 613])) ); } /// 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::alpha), '\\', 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::{Err,be_f64}; pub type Input<'a> = &'a [u8]; #[derive(PartialEq, Debug, Clone)] struct Data { c: f64, v: Vec } fn list<'a,'b>(input: Input<'a>, _cs: &'b f64) -> Result<(Input<'a>,Vec), Err<&'a [u8]>> { separated_list_complete!(input, tag!(","),be_f64) } named!(data, map!( do_parse!( c: be_f64 >> tag!("\n") >> v: call!(list,&c) >> (c,v) ), |(c,v)| { Data { c: c, v: v } } )); } named!(issue_775, take_till1!(|_| true)); #[test] fn issue_848_overflow_incomplete_bits_to_bytes() { named!(parser<&[u8], &[u8]>, bits!(bytes!(take!(0x2000000000000000)))); assert_eq!(parser(&b""[..]), Err(Err::Failure(error_position!(&b""[..], ErrorKind::TooLarge)))); } nom-4.2.3/tests/json.rs010064400007670000024000000042531340516466600132320ustar0000000000000000#![cfg(feature = "alloc")] //#![feature(trace_macros)] #[macro_use] extern crate nom; use nom::{is_alphanumeric, recognize_float}; use std::str; use std::collections::HashMap; #[derive(Debug, PartialEq)] pub enum JsonValue { Str(String), Num(f32), Array(Vec), Object(HashMap), } named!(float, flat_map!(recognize_float, parse_to!(f32))); //FIXME: verify how json strings are formatted named!( string<&str>, delimited!( char!('"'), //map_res!(escaped!(call!(alphanumeric), '\\', is_a!("\"n\\")), str::from_utf8), map_res!( escaped!(take_while1!(is_alphanumeric), '\\', one_of!("\"n\\")), str::from_utf8 ), char!('"') ) ); named!( array>, ws!(delimited!( char!('['), separated_list!(char!(','), value), char!(']') )) ); named!( key_value<(&str, JsonValue)>, ws!(separated_pair!(string, char!(':'), value)) ); named!( hash>, ws!(map!( delimited!(char!('{'), separated_list!(char!(','), key_value), char!('}')), |tuple_vec| { let mut h: HashMap = HashMap::new(); for (k, v) in tuple_vec { h.insert(String::from(k), v); } h } )) ); named!( value, ws!(alt!( hash => { |h| JsonValue::Object(h) } | array => { |v| JsonValue::Array(v) } | string => { |s| JsonValue::Str(String::from(s)) } | float => { |num| JsonValue::Num(num) } )) ); #[test] fn json_object() { let input = r#"{ "a": 42, "b": "x" }\0"#; let mut expected_map = HashMap::new(); expected_map.insert(String::from("a"), JsonValue::Num(42f32)); expected_map.insert(String::from("b"), JsonValue::Str(String::from("x"))); let expected = JsonValue::Object(expected_map); assert_eq!(expected, value(input.as_bytes()).unwrap().1); } #[test] fn json_array() { let input = r#"[ 42, "x" ]\0"#; let expected_vec = vec![ JsonValue::Num(42f32), JsonValue::Str(String::from("x")) ]; let expected = JsonValue::Array(expected_vec); assert_eq!(expected, value(input.as_bytes()).unwrap().1); } nom-4.2.3/tests/mp4.rs010064400007670000024000000366261331546446000127650ustar0000000000000000#![cfg(feature = "stream")] #![allow(dead_code)] #[macro_use] extern crate nom; use nom::{IResult, Needed, be_f32, be_u16, be_u32, be_u64}; //use nom::{Consumer,ConsumerState,Move,Input,Producer,FileProducer,FileProducerState}; //use nom::IResult; use nom::{Err, ErrorKind}; use std::str; fn mp4_box(input: &[u8]) -> IResult<&[u8], &[u8]> { match be_u32(input) { Ok((i, offset)) => { let sz: usize = offset as usize; if i.len() >= sz - 4 { Ok((&i[(sz - 4)..], &i[0..(sz - 4)])) } else { Err(Err::Incomplete(Needed::Size(offset as usize + 4))) } } Err(e) => Err(e), } } #[cfg_attr(rustfmt, rustfmt_skip)] #[derive(PartialEq,Eq,Debug)] struct FileType<'a> { major_brand: &'a str, major_brand_version: &'a [u8], compatible_brands: Vec<&'a str> } #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(non_snake_case)] #[derive(Debug,Clone)] pub struct Mvhd32 { version_flags: u32, // actually: // version: u8, // flags: u24 // 3 bytes created_date: u32, modified_date: u32, scale: u32, duration: u32, speed: f32, volume: u16, // actually a 2 bytes decimal /* 10 bytes reserved */ scaleA: f32, rotateB: f32, angleU: f32, rotateC: f32, scaleD: f32, angleV: f32, positionX: f32, positionY: f32, scaleW: f32, preview: u64, poster: u32, selection: u64, current_time: u32, track_id: u32 } #[cfg_attr(rustfmt, rustfmt_skip)] #[allow(non_snake_case)] #[derive(Debug,Clone)] pub struct Mvhd64 { version_flags: u32, // actually: // version: u8, // flags: u24 // 3 bytes created_date: u64, modified_date: u64, scale: u32, duration: u64, speed: f32, volume: u16, // actually a 2 bytes decimal /* 10 bytes reserved */ scaleA: f32, rotateB: f32, angleU: f32, rotateC: f32, scaleD: f32, angleV: f32, positionX: f32, positionY: f32, scaleW: f32, preview: u64, poster: u32, selection: u64, current_time: u32, 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 }) )) ); #[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 }) )) ); #[derive(Debug, Clone)] pub enum MvhdBox { M32(Mvhd32), M64(Mvhd64), } #[derive(Debug, Clone)] pub enum MoovBox { Mdra, Dref, Cmov, Rmra, Iods, Mvhd(MvhdBox), Clip, Trak, Udta, } #[derive(Debug)] enum MP4BoxType { Ftyp, Moov, Mdat, Free, Skip, Wide, Mdra, Dref, Cmov, Rmra, Iods, Mvhd, Clip, Trak, Udta, Unknown, } #[derive(Debug)] struct MP4BoxHeader { length: u32, tag: MP4BoxType, } named!(brand_name<&[u8],&str>, map_res!(take!(4), str::from_utf8)); 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 mvhd_box(input: &[u8]) -> IResult<&[u8], MvhdBox> { let res = if input.len() < 100 { Err(Err::Incomplete(Needed::Size(100))) } else if input.len() == 100 { mvhd32(input) } else if input.len() == 112 { mvhd64(input) } else { Err(Err::Error(error_position!(input, ErrorKind::Custom(32u32)))) }; println!("res: {:?}", res); res } 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, u32> { 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 ) } // 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 } ) ); named!(box_header<&[u8],MP4BoxHeader>, do_parse!( length: be_u32 >> tag: box_type >> (MP4BoxHeader{ length: length, tag: tag}) ) ); named!(moov_header<&[u8],MP4BoxHeader>, do_parse!( length: be_u32 >> tag: moov_type >> (MP4BoxHeader{ length: length, tag: tag}) ) ); /* #[derive(Debug,PartialEq,Eq)] enum MP4State { Main, Moov, Mvhd(usize) } pub struct MP4Consumer { state: MP4State, moov_bytes: usize, c_state: ConsumerState<(), (), Move> } impl MP4Consumer { fn new() -> MP4Consumer { MP4Consumer { state: MP4State::Main, moov_bytes: 0, c_state: ConsumerState::Continue(Move::Consume(0)) } } fn consume_main(&mut self, input: Input<&[u8]>) -> ConsumerState<(), (), Move> { //println!("\nparsing box header:\n{}", input.to_hex(8)); match input { Input::Eof(None) => ConsumerState::Done(Move::Consume(0), ()), Input::Empty => ConsumerState::Continue(Move::Consume(0)), Input::Element(sl) | Input::Eof(Some(sl)) => { match box_header(sl) { Ok((i, header)) => { match header.tag { MP4BoxType::Ftyp => { println!("-> FTYP"); match filetype_parser(&i[0..(header.length as usize - 8)]) { Ok((rest, filetype_header)) => { println!("filetype header: {:?}", filetype_header); //return ConsumerState::Await(header.length as usize, header.length as usize - 8); return ConsumerState::Continue(Move::Consume(sl.offset(rest))); } Err(Err::Error(a)) => { println!("ftyp parsing error: {:?}", a); assert!(false); return ConsumerState::Error(()); }, Err(Err::Incomplete(n)) => { println!("ftyp incomplete -> await: {}", sl.len()); return ConsumerState::Continue(Move::Await(n)); //return ConsumerState::Await(0, input.len() + 100); } } }, MP4BoxType::Moov => { println!("-> MOOV"); self.state = MP4State::Moov; self.moov_bytes = header.length as usize - 8; return ConsumerState::Continue(Move::Consume(sl.offset(i))); }, MP4BoxType::Mdat => println!("-> MDAT"), MP4BoxType::Free => println!("-> FREE"), MP4BoxType::Skip => println!("-> SKIP"), MP4BoxType::Wide => println!("-> WIDE"), MP4BoxType::Unknown => { println!("-> UNKNOWN"); println!("bytes:\n{}", (sl).to_hex(8)); //return ConsumerState::Continue(Move::Consume(sl.offset(i))); }, _ => { println!("invalid"); return ConsumerState::Error(())} } return ConsumerState::Continue(Move::Seek(SeekFrom::Current((header.length) as i64))) }, Err(Err::Error(a)) => { println!("mp4 parsing error: {:?}", a); assert!(false); return ConsumerState::Error(()); }, Err(Err::Incomplete(i)) => { // FIXME: incomplete should send the required size println!("mp4 incomplete -> await: {}", sl.len()); return ConsumerState::Continue(Move::Await(i)); } } } } } fn consume_moov(&mut self, input: Input<&[u8]>) -> ConsumerState<(), (), Move> { //println!("\nparsing moov box(remaining {} bytes):\n{}", self.moov_bytes, input.to_hex(8)); match input { Input::Eof(None) => return ConsumerState::Error(()), Input::Empty => return ConsumerState::Continue(Move::Consume(0)), Input::Element(sl) | Input::Eof(Some(sl)) => { if self.moov_bytes == 0 { //println!("finished parsing moov atom, continuing with main parser"); self.state = MP4State::Main; return ConsumerState::Continue(Move::Consume(0)); } match moov_header(sl) { Ok((i, header)) => { match header.tag { MP4BoxType::Mvhd => { println!("-> MVHD"); self.state = MP4State::Mvhd(header.length as usize - 8); // TODO: check for overflow here self.moov_bytes = self.moov_bytes - (sl.len() - i.len()); println!("remaining moov_bytes: {}", self.moov_bytes); return ConsumerState::Continue(Move::Consume(sl.offset(i))); }, MP4BoxType::Wide => println!("-> WIDE"), MP4BoxType::Mdra => println!("-> MDRA"), MP4BoxType::Dref => println!("-> DREF"), MP4BoxType::Cmov => println!("-> CMOV"), MP4BoxType::Rmra => println!("-> RMRA"), MP4BoxType::Iods => println!("-> IODS"), MP4BoxType::Clip => println!("-> CLIP"), MP4BoxType::Trak => println!("-> TRAK"), MP4BoxType::Udta => println!("-> UDTA"), MP4BoxType::Unknown => println!("-> MOOV UNKNOWN"), _ => { println!("invalid header here: {:?}", header.tag); return ConsumerState::Error(());} }; // TODO: check for overflow here self.moov_bytes = self.moov_bytes - header.length as usize; println!("remaining moov_bytes: {}", self.moov_bytes); return ConsumerState::Continue(Move::Seek(SeekFrom::Current((header.length) as i64))) }, Err(Err::Error(a)) => { println!("moov parsing error: {:?}", a); println!("data:\n{}", sl.to_hex(8)); assert!(false); return ConsumerState::Error(()); }, Err(Err::Incomplete(i)) => { println!("moov incomplete -> await: {}", sl.len()); return ConsumerState::Continue(Move::Await(i)); } } } }; } } consumer_from_parser!(MvhdConsumer, mvhd_box); impl<'a> Consumer<&'a[u8], (), (), Move> for MP4Consumer { fn handle(&mut self, input: Input<&[u8]>) -> &ConsumerState<(), (), Move> { match self.state { MP4State::Main => { self.c_state = self.consume_main(input); }, MP4State::Moov => { self.c_state = self.consume_moov(input); }, MP4State::Mvhd(sz) => { match input { Input::Eof(None) => self.c_state = ConsumerState::Error(()), Input::Empty => self.c_state = ConsumerState::Continue(Move::Consume(0)), Input::Element(sl) | Input::Eof(Some(sl)) => { let mut c = MvhdConsumer{ state:ConsumerState::Continue(Move::Consume(0)) }; self.c_state = c.handle(Input::Element(&sl[..sz])).flat_map(|m, _| { self.state = MP4State::Moov; ConsumerState::Continue(m) }); println!("found mvhd?: {:?}", c.state()); match self.c_state { ConsumerState::Continue(Move::Consume(sz)) => self.moov_bytes = self.moov_bytes - sz, ConsumerState::Continue(Move::Seek(SeekFrom::Current(sz))) => self.moov_bytes = self.moov_bytes - (sz as usize), _ => () }; println!("remaining moov_bytes: {}", self.moov_bytes); } } } }; &self.c_state } fn state(&self) -> &ConsumerState<(), (), Move> { &self.c_state } } #[allow(unused_must_use)] fn explore_mp4_file(filename: &str) { let mut p = FileProducer::new(filename, 400).unwrap(); let mut c = MP4Consumer{state: MP4State::Main, moov_bytes: 0, c_state: ConsumerState::Continue(Move::Consume(0))}; //c.run(&mut p); while let &ConsumerState::Continue(mv) = p.apply(&mut c) { println!("move: {:?}", mv); } println!("last consumer state: {:?} | last state: {:?}", c.c_state, c.state); if let ConsumerState::Done(Move::Consume(0), ()) = c.c_state { println!("consumer state ok"); } else { assert!(false, "consumer should have reached Done state"); } assert_eq!(c.state, MP4State::Main); assert_eq!(p.state(), FileProducerState::Eof); //assert!(false); } #[test] fn small_test() { explore_mp4_file("assets/small.mp4"); } #[test] fn big_bunny_test() { explore_mp4_file("assets/bigbuckbunny.mp4"); } */ nom-4.2.3/tests/multiline.rs010064400007670000024000000013671331546446000142610ustar0000000000000000#[macro_use] extern crate nom; use nom::types::CompleteStr; use nom::{alphanumeric, eol}; use nom::IResult; pub fn end_of_line(input: CompleteStr) -> IResult { alt!(input, eof!() | eol) } pub fn read_line(input: CompleteStr) -> IResult { terminated!(input, alphanumeric, end_of_line) } pub fn read_lines(input: CompleteStr) -> IResult> { many0!(input, read_line) } #[cfg(feature = "alloc")] #[test] fn read_lines_test() { let res = Ok(( CompleteStr(""), vec![CompleteStr("Duck"), CompleteStr("Dog"), CompleteStr("Cow")], )); assert_eq!(read_lines(CompleteStr("Duck\nDog\nCow\n")), res); assert_eq!(read_lines(CompleteStr("Duck\nDog\nCow")), res); } nom-4.2.3/tests/named_args.rs010064400007670000024000000067011331546446000143540ustar0000000000000000#[macro_use] extern crate nom; use nom::digit; use nom::types::CompleteByteSlice; // 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) , 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) , i64>, ws!(delimited!( tag!(open_tag), expr, tag!(close_tag) )) ); fn complete_byte_slice_to_str<'a>(s: CompleteByteSlice<'a>) -> Result<&'a str, str::Utf8Error> { str::from_utf8(s.0) } // 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, alt!( map_res!( map_res!( ws!(digit), complete_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 , do_parse!( init: factor >> res: fold_many0!( pair!(alt!(call!(operator, Star) | call!(operator, Slash)), factor), init, |acc, (op, val): (CompleteByteSlice, i64)| { if ((op.0)[0] as char) == '*' { acc * val } else { acc / val } } ) >> (res) ) ); named!(expr , do_parse!( init: term >> res: fold_many0!( pair!(alt!(tag!("+") | tag!("-")), term), init, |acc, (op, val): (CompleteByteSlice, i64)| { if ((op.0)[0] as char) == '+' { acc + val } else { acc - val } } ) >> (res) ) ); #[test] fn factor_test() { assert_eq!( factor(CompleteByteSlice(b"3")), Ok((CompleteByteSlice(b""), 3)) ); assert_eq!( factor(CompleteByteSlice(b" 12")), Ok((CompleteByteSlice(b""), 12)) ); assert_eq!( factor(CompleteByteSlice(b"537 ")), Ok((CompleteByteSlice(b""), 537)) ); assert_eq!( factor(CompleteByteSlice(b" 24 ")), Ok((CompleteByteSlice(b""), 24)) ); } #[test] fn term_test() { assert_eq!( term(CompleteByteSlice(b" 12 *2 / 3")), Ok((CompleteByteSlice(b""), 8)) ); assert_eq!( term(CompleteByteSlice(b" 2* 3 *2 *2 / 3")), Ok((CompleteByteSlice(b""), 8)) ); assert_eq!( term(CompleteByteSlice(b" 48 / 3/2")), Ok((CompleteByteSlice(b""), 8)) ); } #[test] fn expr_test() { assert_eq!( expr(CompleteByteSlice(b" 1 + 2 ")), Ok((CompleteByteSlice(b""), 3)) ); assert_eq!( expr(CompleteByteSlice(b" 12 + 6 - 4+ 3")), Ok((CompleteByteSlice(b""), 17)) ); assert_eq!( expr(CompleteByteSlice(b" 1 + 2*3 + 4")), Ok((CompleteByteSlice(b""), 11)) ); } #[test] fn parens_test() { assert_eq!( expr(CompleteByteSlice(b" ( 2 )")), Ok((CompleteByteSlice(b""), 2)) ); assert_eq!( expr(CompleteByteSlice(b" 2* ( 3 + 4 ) ")), Ok((CompleteByteSlice(b""), 14)) ); assert_eq!( expr(CompleteByteSlice(b" 2*2 / ( 5 - 1) + 3")), Ok((CompleteByteSlice(b""), 4)) ); } nom-4.2.3/tests/overflow.rs010064400007670000024000000077171344520222200141150ustar0000000000000000#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] #[macro_use] extern crate nom; use nom::{Err, Needed, be_u64}; // 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::Size(18446744073709551615))) ); } #[test] fn overflow_incomplete_tuple() { assert_eq!( parser02(&b"3"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551615))) ); } #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_length_bytes() { named!(multi<&[u8], Vec<&[u8]> >, many0!( length_bytes!(be_u64) ) ); // Trigger an overflow in length_bytes assert_eq!( multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xff\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551615))) ); } #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_many0() { named!(multi<&[u8], Vec<&[u8]> >, many0!( length_bytes!(be_u64) ) ); // Trigger an overflow in many0 assert_eq!( multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551599))) ); } #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_many1() { named!(multi<&[u8], Vec<&[u8]> >, many1!( length_bytes!(be_u64) ) ); // Trigger an overflow in many1 assert_eq!( multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551599))) ); } #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_many_till() { named!(multi<&[u8], (Vec<&[u8]>, &[u8]) >, many_till!( length_bytes!(be_u64), tag!("abc") ) ); // Trigger an overflow in many_till assert_eq!( multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551599))) ); } #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_many_m_n() { named!(multi<&[u8], Vec<&[u8]> >, many_m_n!(2, 4, length_bytes!(be_u64) ) ); // Trigger an overflow in many_m_n assert_eq!( multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551599))) ); } #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_count() { named!(counter<&[u8], Vec<&[u8]> >, count!( length_bytes!(be_u64), 2 ) ); assert_eq!( counter(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551599))) ); } #[test] fn overflow_incomplete_count_fixed() { named!( counter<[&[u8]; 2]>, count_fixed!(&[u8], length_bytes!(be_u64), 2) ); assert_eq!( counter(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551599))) ); } #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_length_count() { use nom::be_u8; named!(multi<&[u8], Vec<&[u8]> >, length_count!( be_u8, length_bytes!(be_u64) ) ); assert_eq!( multi(&b"\x04\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xee\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551598))) ); } #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_length_data() { named!(multi<&[u8], Vec<&[u8]> >, many0!( length_data!(be_u64) ) ); assert_eq!( multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xff\xaa"[..]), Err(Err::Incomplete(Needed::Size(18446744073709551615))) ); } nom-4.2.3/tests/reborrow_fold.rs010064400007670000024000000006611344541017100151120ustar0000000000000000#![allow(dead_code)] #![allow(unused_variables)] #[macro_use] extern crate nom; use std::str; named_args!(atom<'a>(tomb: &'a mut ()), map!(map_res!(is_not_s!(" \t\r\n()"), str::from_utf8), ToString::to_string)); named_args!(list<'a>(tomb: &'a mut ()), delimited!( char!('('), fold_many0!(call!(atom, tomb), "".to_string(), |acc: String, next: String| acc + next.as_str()), char!(')'))); nom-4.2.3/tests/test1.rs010064400007670000024000000016661331546446000133210ustar0000000000000000#![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(input: T) -> IResult { 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"[..]))); } nom-4.2.3/.cargo_vcs_info.json0000644000000001120000000000000116640ustar00{ "git": { "sha1": "8d195e77285c67d5b5acededa3e9a743a3385db4" } }