nom_parse_macros/lib.rs
1//! # nom-parse-trait
2//!
3//! This macro generates a `ParseFrom` implementation for a struct or enum using the provided
4//! nom expression(s). The expression should return a tuple for the parsed fields.
5//!
6//! The [`parse_from()`] macro can be used in 2 separate ways.
7//! The first one is using an expression that results in a nom parser. This is generic and can be
8//! useful in many cases, since you have the full flexibility of nom functions and combinators.
9//! The second one is a very simple one that matches a string verbatim. You do this by starting the
10//! expression with the `match` keyword. This is useful when you have a very simple format that you
11//! want to parse.
12//!
13//! # nom functions
14//!
15//! The expression in the `parse_from` attribute will be translated to be using valid nom functions.
16//! The main function here is to automatically put the namespace before the function name, so you
17//! don't need a ton of use statements in your code. But there are also a couple of special cases:
18//!
19//! - `{}` or `()` will be replaced with a [`nom_parse_trait::ParseFrom::parse`] call for the
20//! corresponding field. This is useful when you are using types that have implemented the
21//! `ParseFrom` trait already.
22//! - Strings, bytes strings and characters will be translated to match the input verbatim using
23//! the [`nom::bytes::complete::tag`] function.
24//!
25//! # Input types that are supported
26//!
27//! The generated `ParseFrom` implementation is made to be very generic, where it supports any
28//! input and error type from nom. This is done with a where clause with many traits that the input
29//! should have implemented. All of these are true for the standard `&str` and `&[u8]` types.
30//!
31//! If you run into a situation where the trait limitations on the input type does not match your
32//! use case, please open an issue on the GitHub repository.
33//!
34//! # Known limitations
35//!
36//! - When your try to use a custom parser combinator, the nom function parser will try to change
37//! all parameters to be nom parsers. This is useful in many cases, but when you need to pass in
38//! a normal string for example, it won't work. In these cases, you can define a separate function
39//! to wrap the call. I'm not sure how to fix that right now, but I'm open to suggestions.
40//!
41//! - Since the generated input type is very generic, all functions that you want to use in the
42//! nom expression should also be very generic. In the future I might add a way to specify if you
43//! want to generate a specific input type, but for now it's not possible.
44
45extern crate proc_macro;
46mod fields;
47mod nom_packages;
48mod parse_format;
49mod parsed_item;
50mod parser_generator;
51
52use crate::parse_format::ParseFormat;
53use crate::parsed_item::ParsedItem;
54use crate::parser_generator::ParserGenerator;
55use proc_macro::TokenStream;
56use quote::ToTokens;
57
58/// This macro generates a [`nom_parse_trait::ParseFrom`] implementation for a struct or enum using
59/// the provided nom expression(s). The expression should return a tuple for the parsed fields.
60///
61/// # Examples
62///
63/// ## Basic struct with fields
64///
65/// This first example shows how to parse a simple struct with two fields, using the `separated_pair`
66/// combinator. Here we also show some of the special parsing that goes on behind the scenes, where
67/// the special {} syntax means that it infers the type parser it needs to use in that place. Also,
68/// we accept normal strings as matching input, which will be translated to `tag` function calls.
69///
70/// ```rust
71/// use nom_parse_macros::parse_from;
72///
73/// #[parse_from(separated_pair({}, (space0, ",", space0), {}))]
74/// struct NumberPair {
75/// x: u32,
76/// y: u32,
77/// }
78/// ```
79///
80/// ## Basic enum with variants
81///
82/// This example shows how we can define a format for each variant in an enum. The first variant
83/// actually uses the default `ParseFrom` implementation for parsing the u32. The `Numbers` variant
84/// uses a custom format, which is a delimited list of u32 values.
85///
86/// ```rust
87/// use nom_parse_macros::parse_from;
88///
89/// #[parse_from]
90/// enum MultipleTypes {
91/// Number(u32),
92/// #[format(delimited('(', separated_list0(",", {}), ')'))]
93/// Numbers(Vec<u32>),
94/// }
95/// ```
96///
97/// ## Derived fields
98///
99/// Sometimes it's useful to have a field that is not actually parsed, but derived from the other
100/// fields. This can be done with the `#[derived]` attribute. In this example, we derive the sum of
101/// the two fields `x` and `y`.
102///
103/// ```rust
104/// use nom_parse_macros::parse_from;
105///
106/// #[parse_from(separated_pair({}, (space0, ",", space0), {}))]
107/// struct NumberPair {
108/// x: u32,
109/// y: u32,
110/// #[derived(x + y)]
111/// sum: u32,
112/// }
113/// ```
114///
115/// ## Match verbatim
116///
117/// This example shows how to match a string verbatim. This is useful when you have a very simple
118/// format that you want to parse. In this case, we match a vector inside braces. As you can see
119/// the `{}` placeholders are replaced with the corresponding field parsers.
120///
121/// ```rust
122/// use nom_parse_macros::parse_from;
123///
124/// #[parse_from(match "({}, {})")]
125/// struct Vector {
126/// x: f32,
127/// y: f32,
128/// }
129/// ```
130
131#[proc_macro_attribute]
132pub fn parse_from(attrs: TokenStream, object: TokenStream) -> TokenStream {
133 let parse_format = syn::parse_macro_input!(attrs as ParseFormat);
134 let parsed_item = syn::parse_macro_input!(object as ParsedItem);
135
136 ParserGenerator::new(parse_format, parsed_item)
137 .to_token_stream()
138 .into()
139}