aboutsummaryrefslogtreecommitdiff
path: root/src/_tutorial/chapter_1.rs
blob: a2af005dfeb6e2d543461aeb110054108ff5a7df (plain)
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! # Chapter 1: The Winnow Way
//!
//! First of all, we need to understand the way that winnow thinks about parsing.
//! As discussed in the introduction, winnow lets us build simple parsers, and
//! then combine them (using "combinators").
//!
//! Let's discuss what a "parser" actually does. A parser takes an input and returns
//! a result, where:
//!  - `Ok` indicates the parser successfully found what it was looking for; or
//!  - `Err` indicates the parser could not find what it was looking for.
//!
//! Parsers do more than just return a binary "success"/"failure" code.
//! On success, the parser will return the processed data.  The input will be left pointing to
//! data that still needs processing
//!
//! If the parser failed, then there are multiple errors that could be returned.
//! For simplicity, however, in the next chapters we will leave these unexplored.
//!
//! ```text
//!                                    ┌─► Ok(what matched the parser)
//!              ┌─────────┐           │
//!  my input───►│my parser├──►either──┤
//!              └─────────┘           └─► Err(...)
//! ```
//!
//!
//! To represent this model of the world, winnow uses the [`PResult<O>`] type.
//! The `Ok` variant has `output: O`;
//! whereas the `Err` variant stores an error.
//!
//! You can import that from:
//!
//! ```rust
//! use winnow::PResult;
//! ```
//!
//! To combine parsers, we need a common way to refer to them which is where the [`Parser<I, O, E>`]
//! trait comes in with [`Parser::parse_next`] being the primary way to drive
//! parsing forward.
//!
//! You'll note that `I` and `O` are parameterized -- while most of the examples in this book
//! will be with `&str` (i.e. parsing a string); they do not have to be strings; nor do they
//! have to be the same type (consider the simple example where `I = &str`, and `O = u64` -- this
//! parses a string into an unsigned integer.)
//!
//!
//! # Let's write our first parser!
//!
//! The simplest parser we can write is one which successfully does nothing.
//!
//! To make it easier to implement a [`Parser`], the trait is implemented for
//! functions of the form `Fn(&mut I) -> PResult<O>`.
//!
//! This parser function should take in a `&str`:
//!
//!  - Since it is supposed to succeed, we know it will return the Ok Variant.
//!  - Since it does nothing to our input, the remaining input is the same as the input.
//!  - Since it doesn't parse anything, it also should just return an empty string.
//!
//! ```rust
//! use winnow::PResult;
//! use winnow::Parser;
//!
//! pub fn do_nothing_parser<'s>(input: &mut &'s str) -> PResult<&'s str> {
//!     Ok("")
//! }
//!
//! fn main() {
//!     let mut input = "0x1a2b Hello";
//!
//!     let output = do_nothing_parser.parse_next(&mut input).unwrap();
//!     // Same as:
//!     // let output = do_nothing_parser(&mut input).unwrap();
//!
//!     assert_eq!(input, "0x1a2b Hello");
//!     assert_eq!(output, "");
//! }
//! ```

#![allow(unused_imports)]
use crate::PResult;
use crate::Parser;

pub use super::chapter_0 as previous;
pub use super::chapter_2 as next;
pub use crate::_tutorial as table_of_content;