Skip to content

Commit 627bc97

Browse files
committed
Several smaller improvements to support more use cases
- Support generics on nom functions - Improve generics support for structs and enums - Fix the nom function parsing
1 parent 491d5fb commit 627bc97

File tree

4 files changed

+73
-29
lines changed

4 files changed

+73
-29
lines changed

src/fields.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,6 @@ impl Fields {
186186
struct RenameDerived(HashMap<Ident, Ident>);
187187
impl VisitMut for RenameDerived {
188188
fn visit_path_mut(&mut self, path: &mut Path) {
189-
eprintln!("visit_path_mut: {:#?}", path);
190-
191189
for (source, target) in &self.0 {
192190
if path.is_ident(source) {
193191
path.segments = Punctuated::new();

src/lib.rs

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use proc_macro2::{Ident, Span};
1212
use quote::{quote, ToTokens};
1313
use std::default::Default;
1414
use syn::{
15-
parse_macro_input, Expr, GenericParam, Generics, Item, ItemEnum, ItemStruct, LitStr, TypeParam,
15+
parse_macro_input, parse_quote, Expr, GenericParam, Generics, Item, ItemEnum, ItemStruct,
16+
LitStr, TypeParam, WhereClause, WherePredicate,
1617
};
1718

1819
#[proc_macro_attribute]
@@ -167,25 +168,15 @@ fn generate_parser(
167168
object: impl ToTokens,
168169
content: impl ToTokens,
169170
) -> TokenStream {
170-
let (impl_generics, extra_where_predicates) = parser_generics(generics.clone());
171+
let merged_generics = parser_generics(generics.clone());
172+
let (impl_generics, _, where_statement) = merged_generics.split_for_impl();
173+
let (_, type_generics, _) = generics.split_for_impl();
171174

172175
let tokens = quote! {
173176
#object
174177

175-
impl #impl_generics nom_parse_trait::ParseFrom<I, E> for #name #generics
176-
where
177-
#(#extra_where_predicates,)*
178-
E: nom::error::ParseError<I>,
179-
I: Clone,
180-
I: nom::Slice<std::ops::RangeTo<usize>> + nom::Slice<std::ops::RangeFrom<usize>> + nom::Slice<std::ops::Range<usize>>,
181-
I: nom::InputTake + nom::InputLength + nom::Offset + nom::AsBytes,
182-
I: nom::InputIter,
183-
<I as nom::InputIter>::Item: nom::AsChar + Copy,
184-
<I as nom::InputIter>::IterElem: Clone,
185-
I: nom::InputTakeAtPosition,
186-
<I as nom::InputTakeAtPosition>::Item: nom::AsChar + Copy,
187-
I: for<'a> nom::Compare<&'a [u8]>,
188-
I: nom::Compare<&'static str>,
178+
impl #impl_generics nom_parse_trait::ParseFrom<I, E> for #name #type_generics
179+
#where_statement
189180
{
190181
fn parse(input: I) -> nom::IResult<I, Self, E> {
191182
use nom::*;
@@ -198,7 +189,7 @@ fn generate_parser(
198189
tokens.into()
199190
}
200191

201-
fn parser_generics(mut generics: Generics) -> (Generics, Vec<proc_macro2::TokenStream>) {
192+
fn parser_generics(mut generics: Generics) -> Generics {
202193
// If there are no generics, start a new one
203194
if generics.params.is_empty() {
204195
generics = Generics::default();
@@ -207,12 +198,12 @@ fn parser_generics(mut generics: Generics) -> (Generics, Vec<proc_macro2::TokenS
207198
}
208199

209200
// Generate some extra where predicates for the generics
210-
let extra_where_predicates: Vec<_> = generics
201+
let extra_parse_from_traits: Vec<WherePredicate> = generics
211202
.params
212203
.iter()
213204
.flat_map(|param| {
214205
if let GenericParam::Type(TypeParam { ident, .. }) = param {
215-
Some(quote! { #ident: nom_parse_trait::ParseFrom<I, E> })
206+
Some(parse_quote! { #ident: nom_parse_trait::ParseFrom<I, E> })
216207
} else {
217208
None
218209
}
@@ -233,5 +224,54 @@ fn parser_generics(mut generics: Generics) -> (Generics, Vec<proc_macro2::TokenS
233224
Span::call_site(),
234225
))));
235226

236-
(generics, extra_where_predicates)
227+
if generics.where_clause.is_none() {
228+
generics.where_clause = Some(WhereClause {
229+
where_token: Default::default(),
230+
predicates: Default::default(),
231+
});
232+
}
233+
234+
let where_clause = generics.where_clause.as_mut().unwrap();
235+
for extra_parse_from_traits in extra_parse_from_traits {
236+
where_clause.predicates.push(extra_parse_from_traits);
237+
}
238+
239+
where_clause
240+
.predicates
241+
.push(parse_quote! { I: nom::InputTake + nom::InputLength + nom::Offset + nom::AsBytes });
242+
243+
where_clause
244+
.predicates
245+
.push(parse_quote! { E: nom::error::ParseError<I> });
246+
where_clause.predicates.push(parse_quote! { I: Clone });
247+
where_clause.predicates.push(parse_quote! { I: nom::Slice<std::ops::RangeTo<usize>> + nom::Slice<std::ops::RangeFrom<usize>> + nom::Slice<std::ops::Range<usize>> });
248+
where_clause
249+
.predicates
250+
.push(parse_quote! { I: nom::InputTake + nom::InputLength + nom::Offset + nom::AsBytes });
251+
where_clause
252+
.predicates
253+
.push(parse_quote! { I: nom::InputIter });
254+
where_clause
255+
.predicates
256+
.push(parse_quote! { <I as nom::InputIter>::Item: nom::AsChar + Copy });
257+
where_clause
258+
.predicates
259+
.push(parse_quote! { <I as nom::InputIter>::IterElem: Clone });
260+
where_clause
261+
.predicates
262+
.push(parse_quote! { I: nom::InputTakeAtPosition });
263+
where_clause
264+
.predicates
265+
.push(parse_quote! { <I as nom::InputTakeAtPosition>::Item: nom::AsChar + Copy });
266+
where_clause
267+
.predicates
268+
.push(parse_quote! { I: for<'a> nom::Compare<&'a [u8]> });
269+
where_clause
270+
.predicates
271+
.push(parse_quote! { I: nom::Compare<&'static str> });
272+
where_clause
273+
.predicates
274+
.push(parse_quote! { for<'a> &'a str: nom::FindToken<<I as nom::InputIter>::Item> });
275+
276+
generics
237277
}

src/nom_packages.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ const NOM_FUNCTIONS: phf::Map<&'static str, (&'static str, &'static [bool])> = p
1515
"tag_no_case" => ("nom::bytes::complete::tag_no_case", &[false]),
1616
"is_not" => ("nom::bytes::complete::is_not", &[false]),
1717
"is_a" => ("nom::bytes::complete::is_a", &[false]),
18-
"take_while" => ("nom::bytes::complete::take_while", &[true]),
19-
"take_while1" => ("nom::bytes::complete::take_while1", &[true]),
20-
"take_while_m_n" => ("nom::bytes::complete::take_while_m_n", &[false, false, true]),
21-
"take_till" => ("nom::bytes::complete::take_till", &[true]),
22-
"take_till1" => ("nom::bytes::complete::take_till1", &[true]),
18+
"take_while" => ("nom::bytes::complete::take_while", &[false]),
19+
"take_while1" => ("nom::bytes::complete::take_while1", &[false]),
20+
"take_while_m_n" => ("nom::bytes::complete::take_while_m_n", &[false, false, false]),
21+
"take_till" => ("nom::bytes::complete::take_till", &[false]),
22+
"take_till1" => ("nom::bytes::complete::take_till1", &[false]),
2323
"take" => ("nom::bytes::complete::take", &[false]),
2424
"take_until" => ("nom::bytes::complete::take_until", &[false]),
2525
"take_until1" => ("nom::bytes::complete::take_until1", &[false]),
@@ -115,8 +115,8 @@ const NOM_FUNCTIONS: phf::Map<&'static str, (&'static str, &'static [bool])> = p
115115
"consumed" => ("nom::combinator::consumed", &[true]),
116116
"cut" => ("nom::combinator::cut", &[true]),
117117
"into" => ("nom::combinator::into", &[true]),
118-
"success" => ("nom::combinator::success", &[false]),
119-
"fail" => ("nom::combinator::fail", &[false]),
118+
"success" => ("nom::combinator::success", &[]),
119+
"fail" => ("nom::combinator::fail", &[]),
120120
// From the nom::multi module
121121
"many0" => ("nom::multi::many0", &[true]),
122122
"many1" => ("nom::multi::many1", &[true]),
@@ -209,9 +209,11 @@ fn parse_call(call: &mut ExprCall) -> Result<()> {
209209
if let Expr::Path(ExprPath { path, .. }) = call.func.as_mut() {
210210
if path.segments.len() == 1 {
211211
let ident = path.segments[0].ident.to_string();
212+
let arguments = path.segments[0].arguments.clone();
212213

213214
if let Some(&(nom_path, parameters)) = NOM_FUNCTIONS.get(ident.as_str()) {
214215
path.segments = parse_str::<Path>(nom_path)?.segments;
216+
path.segments.last_mut().unwrap().arguments = arguments;
215217

216218
// For the tuple and alt functions, wrap the arguments in a tuple if they are not already
217219
// and handle the arguments as if they were all parsers
@@ -273,6 +275,7 @@ fn parse_call(call: &mut ExprCall) -> Result<()> {
273275
pub fn parse_path(path_expr: &mut Path) -> Result<()> {
274276
if path_expr.segments.len() == 1 {
275277
let ident = path_expr.segments[0].ident.to_string();
278+
let arguments = path_expr.segments[0].arguments.clone();
276279

277280
if let Some(&(nom_path, parameters)) = NOM_FUNCTIONS.get(ident.as_str()) {
278281
if !parameters.is_empty() {
@@ -286,6 +289,7 @@ pub fn parse_path(path_expr: &mut Path) -> Result<()> {
286289
}
287290

288291
path_expr.segments = parse_str::<Path>(nom_path)?.segments;
292+
path_expr.segments.last_mut().unwrap().arguments = arguments;
289293
}
290294
}
291295

tests/generics.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ enum Command {
1111
B,
1212
#[format("c")]
1313
C,
14+
#[format(fail::<_, (), _>)]
15+
Unknown,
1416
}
1517

1618
#[parse_from(separated_pair(separated_list1(",", {}), " => ", {}))]

0 commit comments

Comments
 (0)