• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# How nom macros work
2
3**NOTE: macros were removed in nom 7. You should now use the function based combinators**
4
5nom uses Rust macros heavily to provide a nice syntax and generate parsing code.
6This has multiple advantages:
7
8* It gives the appearance of combining functions without the runtime cost of closures
9* It helps Rust's code inference and borrow checking (less lifetime issues than iterator based solutions)
10* The generated code is very linear, just a large chain of pattern matching
11
12As a prerequisite, if you need more information on macros, please refer to
13[the little book of Rust macros](https://danielkeep.github.io/tlborm/book/README.html)
14and the [Macromancy talk](https://www.youtube.com/watch?v=8rodUyaGkQo)
15
16# Defining a new macro
17
18Let's take the `opt!` macro as example: `opt!` returns `IResult<I,Option<O>>`,
19producing a `Some(o)` if the child parser succeeded, and None otherwise. Here
20is how you could use it:
21
22```rust
23named!(opt_tag<Option<&[u8]>>, opt!(digit));
24```
25
26And here is how it is defined:
27
28```rust
29#[macro_export]
30macro_rules! opt(
31  ($i:expr, $submac:ident!( $($args:tt)* )) => ({
32    match $submac!($i, $($args)*) {
33      Ok((i,o))          => Ok((i, Some(o))),
34      Err(Err::Error(_)) => Ok(($i, None)),
35      Err(e)             => Err(e),
36    }
37  });
38  ($i:expr, $f:expr) => (
39    opt!($i, call!($f));
40  );
41);
42```
43
44To define a Rust macro, you indicate the name of the macro, then each pattern it
45is meant to apply to:
46
47```rust
48macro_rules! my_macro (
49  (<pattern1>) => ( <generated code for pattern1> );
50  (<pattern2>) => ( <generated code for pattern2> );
51);
52```
53
54## Passing input
55
56The first thing you can see in `opt!` is that the pattern have an additional
57parameter that you do not use:
58
59```rust
60($i:expr, $f:expr)
61```
62
63While you call:
64
65```rust
66opt!(digit)
67```
68
69This is the first trick of nom macros: the first parameter, usually `$i` or `$input`,
70is the input data, passed by the parent parser. The expression using `named!` will
71translate like this:
72
73```rust
74named!(opt_tag<Option<&[u8]>>, opt!(digit));
75```
76
77to
78
79```rust
80fn opt_tag(input:&[u8]) -> IResult<&[u8], Option<&[u8]>> {
81  opt!(input, digit)
82}
83```
84
85This is how combinators hide all the plumbing: they receive the input automatically
86from the parent parser, may use that input, and pass the remaining input to the child
87parser.
88
89When you have multiple submacros, such as this example, the input is always passed
90to the first, top level combinator:
91
92```rust
93macro_rules! multispaced (
94    ($i:expr, $submac:ident!( $($args:tt)* )) => (
95        delimited!($i, opt!(multispace), $submac!($($args)*), opt!(multispace));
96    );
97    ($i:expr, $f:expr) => (
98        multispaced!($i, call!($f));
99    );
100);
101```
102
103Here, `delimited!` will apply `opt!(multispace)` on the input, and if successful,
104will apply `$submac!($($args)*)` on the remaining input, and if successful, store
105the output and apply `opt!(multispace)` on the remaining input.
106
107## Applying on macros or functions
108
109The second trick you can see is the two patterns:
110
111```rust
112#[macro_export]
113macro_rules! opt(
114  ($i:expr, $submac:ident!( $($args:tt)* )) => (
115    [...]
116  );
117  ($i:expr, $f:expr) => (
118    opt!($i, call!($f));
119  );
120);
121```
122
123The first pattern is used to receive a macro as child parser, like this:
124
125```rust
126opt!(tag!("abcd"))
127```
128
129The second pattern can receive a function, and transforms it in a macro, then calls
130itself again. This is done to avoid repeating code. Applying `opt!` with `digit`
131as argument would be transformed from this:
132
133```rust
134opt!(digit)
135```
136
137transformed with the second pattern:
138
139```rust
140opt!(call!(digit))
141```
142
143The `call!` macro transforms `call!(input, f)` into `f(input)`. If you need to pass
144more parameters to the function, you can Use `call!(input, f, arg, arg2)` to get
145`f(input, arg, arg2)`.
146
147## Using the macro's parameters
148
149The macro argument is decomposed into `$submac:ident!`, the macro's name and a bang,
150and `( $($args:tt)* )`, the tokens contained between the parenthesis of the macro call.
151
152```rust
153($i:expr, $submac:ident!( $($args:tt)* )) => ({
154    match $submac!($i, $($args)*) {
155      Ok((i,o))          => Ok((i, Some(o))),
156      Err(Err::Error(_)) => Ok(($i, None)),
157      Err(e)             => Err(e),
158    }
159  });
160```
161
162The macro is called with the input we got, as first argument, then we pattern
163match on the result. Every combinator or parser must return a `IResult`, which
164is a `Result<(I, O), nom::Err<I, E>>`, so you know which patterns you need to
165verify. If you need to call two parsers in a sequence, use the first parameter
166of `Ok((i,o))`: It is the input remaining after the first parser was applied.
167
168As an example, see how the `preceded!` macro works:
169
170```rust
171($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
172    {
173      match $submac!($i, $($args)*) {
174        Err(e) => Err(e),
175        Ok((i1, _)) => {
176          $submac2!(i1, $($args2)*)
177        },
178      }
179    }
180  );
181```
182
183It applies the first parser, and if it succeeds, discards its result, and applies
184the remaining input `i1` to the second parser.
185