Skip to content

Commit

Permalink
remove mentions of macros in the documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Geal committed Aug 21, 2021
1 parent 195d398 commit 3de8318
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 72 deletions.
11 changes: 0 additions & 11 deletions doc/FAQ.md

This file was deleted.

121 changes: 121 additions & 0 deletions doc/archive/FAQ.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# FAQ

### Using nightly to get better error messages

**warning**: this only applies to nom 3. nom 4 uses the
[compile_error](https://doc.rust-lang.org/std/macro.compile_error.html) macro
available since Rust 1.20

If you got the following error when compiling your nom parser:

```
error[E0425]: cannot find value `INVALID_NOM_SYNTAX_PLEASE_SEE_FAQ` in this scope
--> src/lib.rs:111:7
|
111 | INVALID_NOM_SYNTAX_PLEASE_SEE_FAQ //https://github.com/Geal/nom/blob/master/doc/FAQ.md#using-nightly-to-get-better-error-messages
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
```

It means that you are using Rust stable, and that one of your nom parsers has an invalid syntax.
If you can switch to a nightly Rust compiler (as an example, with `rustup default nightly`),
and if you activate the `nightly` feature on your nom dependency like this:

```toml
[dependencies.nom]
version = "^3"
features = ["nightly"]
```

You can get more helpful error messages, such as this one:

```
$ cargo test --features nightly
Compiling compiler_error v0.1.1
Compiling nom v3.0.0 (file:///Users/geal/dev/rust/projects/nom)
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 } )
"
--> src/sequence.rs:368:5
|
368 | / compiler_error!("do_parse is missing the return value. A do_parse call must end
369 | | with a return value between parenthesis, as follows:
370 | |
371 | | do_parse!(
... |
375 | | ( Value { a: a, b: b } )
376 | | ");
| |______^
...
851 | / named!(no_compiler,
852 | | do_parse!(
853 | | length: be_u8 >>
854 | | bytes: take!(length)
855 | | )
856 | | );
| |___- in this macro invocation
error: aborting due to previous error(s)
error: Could not compile `nom`.
```

If the error message is not helpful, please reach out on the [Gitter chat](https://gitter.im/Geal/nom?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) or the IRC channel (#nom on freenode), and show
your code and the error message you got.

### nom 1.0 does not compile on Rust older than 1.4

Typically, the error would look like this:

```ignore
src/stream.rs:74:44: 74:64 error: the parameter type `E` may not live long enough [E0309]
src/stream.rs:74 if let &ConsumerState::Done(_,ref o) = self.apply(consumer) {
^~~~~~~~~~~~~~~~~~~~
note: in expansion of if let expansion
src/stream.rs:74:5: 78:6 note: expansion site
src/stream.rs:74:44: 74:64 help: run `rustc --explain E0309` to see a detailed explanation
src/stream.rs:74:44: 74:64 help: consider adding an explicit lifetime bound `E: 'b`...
src/stream.rs:74:44: 74:64 note: ...so that the reference type `&stream::ConsumerState<O, E, M>` does not outlive the data it points at
src/stream.rs:74 if let &ConsumerState::Done(_,ref o) = self.apply(consumer) {
^~~~~~~~~~~~~~~~~~~~
note: in expansion of if let expansion
src/stream.rs:74:5: 78:6 note: expansion site
src/stream.rs:74:44: 74:64 error: the parameter type `M` may not live long enough [E0309]
src/stream.rs:74 if let &ConsumerState::Done(_,ref o) = self.apply(consumer) {
^~~~~~~~~~~~~~~~~~~~
note: in expansion of if let expansion
src/stream.rs:74:5: 78:6 note: expansion site
src/stream.rs:74:44: 74:64 help: run `rustc --explain E0309` to see a detailed explanation
src/stream.rs:74:44: 74:64 help: consider adding an explicit lifetime bound `M: 'b`...
src/stream.rs:74:44: 74:64 note: ...so that the reference type `&stream::ConsumerState<O, E, M>` does not outlive the data it points at
src/stream.rs:74 if let &ConsumerState::Done(_,ref o) = self.apply(consumer) {
^~~~~~~~~~~~~~~~~~~~
note: in expansion of if let expansion
src/stream.rs:74:5: 78:6 note: expansion site
error: aborting due to 2 previous errors
Could not compile `nom`.
```

This is caused by some lifetime issues that may be fixed in a future version of nom. In the meantime, you can add `default-features=false` to nom's declaration in `Cargo.toml` to deactivate this part of the code:

```toml
[dependencies.nom]
version = "~1.0.0"
default-features = false
```

### The compiler indicates `error: expected an item keyword` then points to the function's return type in `named!`:

```ignore
error: expected an item keyword
named!(multi<Vec<&str>>, many0!( map_res!(tag!( "abcd" ), str::from_utf8) ) );
^~~
```

This happens because the macro processor mistakes `>>` for an operator. It will work correctly by adding a space, like this: `named!(multi< Vec<&str> >, ...`
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# How nom macros work

**NOTE: macros were removed in nom 7. You should now use the function based combinators**

nom uses Rust macros heavily to provide a nice syntax and generate parsing code.
This has multiple advantages:

Expand Down
2 changes: 1 addition & 1 deletion doc/error_management.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ through 2 recursive map parsers:
While you are writing your parsers, you will sometimes need to follow
which part of the parser sees which part of the input.

To that end, nom provides the `dbg_dmp` function and macro, that will observe
To that end, nom provides the `dbg_dmp` function that will observe
a parser's input and output, and print a hexdump of the input if there was an
error. Here is what it could return:

Expand Down
1 change: 0 additions & 1 deletion doc/home.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ channel on irc.mozilla.org, or ping 'geal' on Mozilla, Freenode, Geeknode or oft
* [Making a new parser from scratch](making_a_new_parser_from_scratch.md)
(general tips on writing a parser and code architecture)
* [How to handle parser errors](error_management.md)
* [How nom's macro combinators work](how_nom_macros_work.md)
* [Recipes for common nom tasks](nom_recipes.md)
63 changes: 4 additions & 59 deletions doc/making_a_new_parser_from_scratch.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ nom is designed to abstract data manipulation (counting array offsets,
converting to structures, etc) while providing a safe, composable API. It also
takes care of making the code easy to test and read, but it can be confusing at
first, if you are not familiar with parser combinators, or if you are not used
to Rust macros and generic functions.
to Rust generic functions.

This document is here to help you in getting started with nom. You can also find
[nom recipes for common short parsing tasks here](nom_recipes.md). If you need
more specific help, please ping `geal` on IRC (freenode, geeknode,
oftc), go to `#nom-parsers` on Freenode IRC, or on the
[Gitter chat room](https://gitter.im/Geal/nom).
more specific help, please ping `geal` on IRC (libera, geeknode,
oftc), go to `#nom-parsers` on Libera IRC, or on the
[Gitter chat room](https://gitter.im/Geal/nom).

# First step: the initial research

Expand Down Expand Up @@ -42,8 +42,6 @@ Usually, you can separate the parsing functions in their own module, so you
could have a `src/lib.rs` file containing this:

```rust
#[macro_use]
extern crate nom;
pub mod parser;
```

Expand Down Expand Up @@ -205,56 +203,3 @@ fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
f(a);
```

## Macros specific debugging tools

### trace\_macros

The `trace_macros` feature show how macros are applied. To use it, add `#![feature(trace_macros)]` at the top of your file (you need Rust nightly for this), then apply it like this:

```rust
trace_macros!(true);
named!(manytag< Vec<&[u8]> >, many0!(take!(5)));
trace_macros!(false);
```

It will result in the following output during compilation:

```rust
named! { manytag , many0 ! ( take ! ( 5 ) ) }
many0! { i , take ! ( 5 ) }
take! { input , 5 }
```

### Pretty printing

rustc can show how code is expanded with the option `--pretty=expanded`. If you want to use it with cargo, use the following command line: `cargo rustc <cargo options> -- -Z unstable-options --pretty=expanded`

It will print the `manytag` function like this:

```rust
fn manytag(i: &[u8]) -> ::nom::IResult<&[u8], Vec<&[u8]>> {
let mut res = Vec::new();
let mut input = i;
while let Ok((i, o)) =
{
let cnt = 5 as usize;
let res: ::nom::IResult<&[u8], &[u8]> =
if input.len() < cnt {
Err(::nom::Err::Incomplete(::nom::Needed::Size(cnt)))
} else {
Ok( (&input[cnt..], &input[0..cnt]))
};
res
} {
if i.len() == input.len() { break ; }
res.push(o);
input = i;
}
Ok((input, res))
}
```

### nom-trace

The [nom-trace crate](https://github.com/rust-bakery/nom-trace) extends
the principle of `dbg_dmp!` to give more context to a parse tree.

0 comments on commit 3de8318

Please sign in to comment.