Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A Book for Nom #1525

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

A Book for Nom #1525

wants to merge 3 commits into from

Conversation

tfpk
Copy link
Contributor

@tfpk tfpk commented May 2, 2022

Hi,

I'm a newbie to Nom (and I'm probably only an intermediate Rust programmer), and I have personally found that this project lacks documentation for newcomers. I thought that it would be valuable to have a "book" for Nom, in the vein of the Rust Book or the many other excellent books that projects around the Rust ecosystem have.

Based on my limited experience, I've written about a quarter of a short book. This is a book I think would have helped me, had I had access to it a few weeks ago.

I'm posting it here for a few reasons:

  1. Whether it's useful enough to continue working on, and whether the Nom project would be interested in accepting it.
  2. If I've put in any significant (or even minor) mistakes that could be corrected.
  3. If the order and plan for content is reasonable.

I'm happy to move this to an issue if that's the right place to discuss, though I suppose a useful issue to reference is #1506 .

I'd welcome any and all feedback!

Thanks :)

Copy link
Contributor

@Xiretza Xiretza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, thanks a lot! I found a few nits, but overall this seems like a great start for a tutorial-style introduction to nom! Props for the name of the book, too.

ahead and start parsing the middle of the line.


To represent this model of the world, nom uses the `IResult<(I, O)>` type.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be IResult<I, O>.

these are so common, there already exists a function called `tag()`.
This function returns a parser for a given string.

<div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what's up with this HTML, it breaks the markdown in the contents.

```

If you'd like to, you can also check case insensitive `/tag/i`
with the `tag_case_insensitive`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 84 to 113
```rust
# extern crate nom;
use nom::branch::alt;
use nom::bytes::complete::{tag};
use nom::character::complete::{digit1};
use nom::IResult;

fn parse_numbers_or_abc(input: &str) -> IResult<&str, &str> {
alt((
tag("abc"),
digit1
))(input)
}


let input = "abc";
let parsed_input = parse_numbers_or_abc(input);
match parsed_input {
Ok((_, matched_str)) => assert_eq!(matched_str, "abc"),
Err(_) => unreachable!()
}


let input = "def";
let parsed_input = parse_numbers_or_abc(input);
match parsed_input {
Ok(_) => unreachable!(),
Err(_) => assert!(true)
}
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example seems to be mismatched (does not contain tuple() at all)?

@tfpk
Copy link
Contributor Author

tfpk commented May 2, 2022

Thank you for the feedback! I'll fix those nits up.

Did you have any broader feedback on the structure I'm planning in SUMMARY.md? And if I kept working on this is it something you'd be interested in integrating?

I'm new enough to the project I don't know if there are things I should be explaining!

@Xiretza
Copy link
Contributor

Xiretza commented May 3, 2022

The overall structure looks great for a comprehensive tutorial, which is something that nom kind of lacks right now (there is some tutorial-style documentation in docs/, but it's not as coherent as an mdbook).

if I kept working on this is it something you'd be interested in integrating?

Well, you'll have to ask @Geal about that, I'm not a maintainer, but personally I'd gladly accept it ;)

I'm new enough to the project I don't know if there are things I should be explaining!

I hang out in #geal_nom:gitter.im, and while it's hard to find a most common issue, error handling is definitely something a lot of users struggle with. There are just a lot of levels to the current IResult, and it takes a while to dig through them to understand it.

Copy link
Collaborator

@Geal Geal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a great idea, a comprehensive suite of small examples from the ground up will really help in understanding nom!

I am not sure about requiring knowledge of regular expressions, parser combinators should be able to stand by themselves. But keeping the regex equivalent with the examples can help some readers.

I'd be happy to merge this after a few fixes. I'm not sure I'll have the time to write a lot in it, but I'll make sure to help and review

doc/nom-guide/book.toml Show resolved Hide resolved
doc/nom-guide/src/chapter_1.md Outdated Show resolved Hide resolved
doc/nom-guide/src/chapter_1.md Outdated Show resolved Hide resolved
This function returns a parser for a given string.

<div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
**Warning**: `nom` has multiple different definitions of `tag`, make sure you use this one for the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that will need a link to the future chapter about parsers of complete VS streaming inputs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed; I'll add it in when that chapter is written.


let err_input = "defWorld";
match parse_input(err_input) {
Ok((leftover_input, output)) => unreachable!(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if all those examples are only looking at one branch, they should use unwrap and unwrap_err instead of a match with one branch using unreachable!(), that will make them shorter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've chosen to go with returning a Box<dyn Error>, so that I can use Try. I've done this because (from my limited understanding) the Rust guide to writing documentation suggests avoiding unwrap in documentation examples.

Happy to change this if you think it's the wrong direction.

doc/nom-guide/src/chapter_3.md Outdated Show resolved Hide resolved
doc/nom-guide/src/introduction.md Show resolved Hide resolved
@tfpk
Copy link
Contributor Author

tfpk commented Jul 1, 2022

@Xiretza + @Geal -- I've updated this PR with the next section of the book.

Particularly curious if there's anything major that needs changing in the order or in topics covered.

I'm also blocked on the last three chapters:

  • Re Streaming -- I couldn't find an easy to grok example of how they are used. Is there an up-to-date one? My thinking is that the best "simple" example would be reading in from stdin; and doing something like bracket-matching; but I don't know if that plays to nom's strengths.
  • Re bytes + bits -- again, I don't know the area well enough to have a good example; and I don't know what's worth covering.
  • Re Exercises, is this worth having? I come from a teaching background, so having exercises is the norm for me, but I'm not sure if it's the done thing in Rust projects. I could also go through and add one or two per chapter?

One other thought -- some of the other documentation in docs/ would fit well in the book (I haven't written an errors chapter, because the errors document that exists is great!) Is it worth moving some/all of the documentation into the book? I've borrowed particularly heavily from the list of parsers/combinators -- I'm not sure if duplicating them was the best idea, so maybe references to them either by link; or as an appendix might be helpful?

Keen to hear your thoughts/feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants