Skip to content

Commit beca77c

Browse files
committed
Making the generated parsers more generic for re-use
- Improve support for variants with no fields - Add many more nom functions for parsing numbers
1 parent 20a87ca commit beca77c

File tree

11 files changed

+161
-90
lines changed

11 files changed

+161
-90
lines changed

examples/basic_enum_with_members.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! The expected outcome of the nom expression should be a tuple with the same
33
//! amount of parameters as the struct has.
44
5+
use nom::IResult;
56
use nom_parse_macros::parse_from;
67
use nom_parse_trait::ParseFrom;
78

@@ -15,10 +16,10 @@ enum SomeConfig {
1516

1617
fn main() {
1718
let input = "32";
18-
let number = SomeConfig::parse(input).unwrap().1;
19-
println!("Parsed \"{}\" as {:?}", input, number);
19+
let number: IResult<_, _> = SomeConfig::parse(input);
20+
println!("Parsed \"{}\" as {:?}", input, number.unwrap().1);
2021

2122
let input = "(32,34,46)";
22-
let numbers = SomeConfig::parse(input).unwrap().1;
23-
println!("Parsed \"{}\" as {:?}", input, numbers);
23+
let numbers: IResult<_, _> = SomeConfig::parse(input);
24+
println!("Parsed \"{}\" as {:?}", input, numbers.unwrap().1);
2425
}

examples/basic_struct_with_members.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! The expected outcome of the nom expression should be a tuple with the same
33
//! amount of parameters as the struct has.
44
5+
use nom::IResult;
56
use nom_parse_macros::parse_from;
67
use nom_parse_trait::ParseFrom;
78

@@ -14,6 +15,6 @@ struct NumberPair {
1415

1516
fn main() {
1617
let input = "1 , 2";
17-
let pair = NumberPair::parse(input).unwrap();
18-
println!("Parsed \"{}\" as {:?}", input, pair.1);
18+
let pair: IResult<_, _> = NumberPair::parse(input);
19+
println!("Parsed \"{}\" as {:?}", input, pair.unwrap().1);
1920
}

examples/derived_fields.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! A derived field is not actually parsed, but derived from all of the other
33
//! fields that are parsed.
44
5+
use nom::IResult;
56
use nom_parse_macros::parse_from;
67
use nom_parse_trait::ParseFrom;
78

@@ -16,6 +17,6 @@ struct NumberPair {
1617

1718
fn main() {
1819
let input = "1 , 2";
19-
let pair = NumberPair::parse(input).unwrap();
20-
println!("Parsed \"{}\" as {:?}", input, pair.1);
20+
let pair: IResult<_, _> = NumberPair::parse(input);
21+
println!("Parsed \"{}\" as {:?}", input, pair.unwrap().1);
2122
}

examples/use_matching_string.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! The {} gets replaced with a parser for the corresponding field. The rest of
33
//! the characters are matched verbatim.
44
5+
use nom::IResult;
56
use nom_parse_macros::parse_match;
67
use nom_parse_trait::ParseFrom;
78

@@ -15,6 +16,6 @@ struct Vector3 {
1516

1617
fn main() {
1718
let input = "(1,3,4)";
18-
let pair = Vector3::parse(input).unwrap();
19-
println!("Parsed \"{}\" as {:?}", input, pair.1);
19+
let pair: IResult<_, _> = Vector3::parse(input);
20+
println!("Parsed \"{}\" as {:?}", input, pair.unwrap().1);
2021
}

src/fields.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,13 @@ impl Fields {
139139
pub fn create_instance_expr(&self, variant_name: Option<&Ident>) -> TokenStream {
140140
let all_names = self.get_all_names();
141141

142-
if let Some(name) = variant_name {
142+
if all_names.is_empty() {
143+
if let Some(name) = variant_name {
144+
quote! { Self::#name }
145+
} else {
146+
quote! { Self }
147+
}
148+
} else if let Some(name) = variant_name {
143149
if self.is_named {
144150
quote! { Self::#name { #(#all_names),* } }
145151
} else {

src/lib.rs

Lines changed: 64 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -40,25 +40,16 @@ fn generate_struct_parser(attrs: TokenStream, mut object: ItemStruct) -> TokenSt
4040
let expression_names = fields.get_expression_names();
4141
let derived_expressions = fields.get_derived_expressions();
4242
let create_expr = fields.create_instance_expr(None);
43-
let where_clause = generate_where_clause();
4443

45-
let tokens = quote! {
46-
#object
47-
48-
impl<I> nom_parse_trait::ParseFrom<I> for #name
49-
#where_clause
50-
{
51-
fn parse(input: I) -> nom::IResult<I, Self> {
52-
use nom::*;
53-
54-
let (input, (#(#expression_names),*)) = #expression.parse(input)?;
55-
#(#derived_expressions)*
56-
Ok((input, #create_expr))
57-
}
58-
}
59-
};
60-
61-
tokens.into()
44+
generate_parser(
45+
object,
46+
name,
47+
quote! {
48+
let (input, (#(#expression_names),*)) = #expression.parse(input)?;
49+
#(#derived_expressions)*
50+
Ok((input, #create_expr))
51+
},
52+
)
6253
}
6354

6455
fn generate_enum_parser(mut object: ItemEnum) -> TokenStream {
@@ -107,35 +98,39 @@ fn generate_enum_parser(mut object: ItemEnum) -> TokenStream {
10798
);
10899
mapping_names.push(mapping_name.clone());
109100

110-
mappings.push(quote! {
111-
let #mapping_name = nom::combinator::map(
112-
#format_expr,
113-
|(#(#expression_names),*): (#(#expression_types),*)| {
114-
#(#derived_expressions)*
115-
#create_expr
116-
}
117-
);
118-
})
101+
if expression_names.is_empty() {
102+
// Parsing a variant without fields
103+
mappings.push(quote! {
104+
let #mapping_name = nom::combinator::map(
105+
#format_expr,
106+
|_| { #create_expr }
107+
);
108+
})
109+
} else {
110+
mappings.push(quote! {
111+
let #mapping_name = nom::combinator::map(
112+
#format_expr,
113+
|(#(#expression_names),*): (#(#expression_types),*)| {
114+
#(#derived_expressions)*
115+
#create_expr
116+
}
117+
);
118+
})
119+
}
119120
}
120121

121122
let name = object.ident.clone();
122123

123-
let tokens = quote! {
124-
#object
125-
126-
impl nom_parse_trait::ParseFrom<&str> for #name {
127-
fn parse(input: &str) -> nom::IResult<&str, Self> {
128-
use nom::*;
129-
130-
#(#mappings)*
131-
nom::branch::alt((
132-
#(#mapping_names),*
133-
)).parse(input)
134-
}
135-
}
136-
};
137-
138-
tokens.into()
124+
generate_parser(
125+
object,
126+
name,
127+
quote! {
128+
#(#mappings)*
129+
nom::branch::alt((
130+
#(#mapping_names),*
131+
)).parse(input)
132+
},
133+
)
139134
}
140135

141136
#[proc_macro_attribute]
@@ -148,36 +143,30 @@ pub fn parse_match(attrs: TokenStream, object: TokenStream) -> TokenStream {
148143
Err(e) => return e.to_compile_error().into(),
149144
};
150145
let name = object.ident.clone();
151-
let where_clause = generate_where_clause();
152146

153147
match parse_string_match(&fields, literal) {
154148
Ok(parts) => {
155149
let names: Vec<_> = fields.fields.iter().map(|field| field.get_name()).collect();
156-
let tokens = quote! {
157-
#object
158-
159-
impl<I> nom_parse_trait::ParseFrom<I> for #name
160-
#where_clause
161-
{
162-
fn parse(input: I) -> nom::IResult<I, Self> {
163-
use nom::*;
164-
165-
let mut input = input;
166-
#(#parts)*
167-
Ok((input, Self { #(#names),* }))
168-
}
169-
}
170-
};
171-
172-
tokens.into()
150+
generate_parser(
151+
object,
152+
name,
153+
quote! {
154+
#(#parts)*
155+
Ok((input, Self { #(#names),* }))
156+
},
157+
)
173158
}
174159
Err(e) => e.to_compile_error().into(),
175160
}
176161
}
177162

178-
fn generate_where_clause() -> proc_macro2::TokenStream {
179-
quote! {
163+
fn generate_parser(object: impl ToTokens, name: Ident, content: impl ToTokens) -> TokenStream {
164+
let tokens = quote! {
165+
#object
166+
167+
impl<I, E> nom_parse_trait::ParseFrom<I, E> for #name
180168
where
169+
E: nom::error::ParseError<I>,
181170
I: Clone,
182171
I: nom::Slice<std::ops::RangeTo<usize>> + nom::Slice<std::ops::RangeFrom<usize>> + nom::Slice<std::ops::Range<usize>>,
183172
I: nom::InputTake + nom::InputLength + nom::Offset + nom::AsBytes,
@@ -187,5 +176,15 @@ fn generate_where_clause() -> proc_macro2::TokenStream {
187176
I: nom::InputTakeAtPosition,
188177
<I as nom::InputTakeAtPosition>::Item: nom::AsChar + Copy,
189178
I: for<'a> nom::Compare<&'a [u8]>,
190-
}
191-
}
179+
I: nom::Compare<&'static str>,
180+
{
181+
fn parse(input: I) -> nom::IResult<I, Self, E> {
182+
use nom::*;
183+
use nom_parse_trait::ParseFrom;
184+
185+
#content
186+
}
187+
}
188+
};
189+
tokens.into()
190+
}

src/nom_packages.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,49 @@ const NOM_FUNCTIONS: phf::Map<&'static str, (&'static str, &'static [bool])> = p
5151
"multispace0" => ("nom::character::complete::multispace0", &[]),
5252
"multispace1" => ("nom::character::complete::multispace1", &[]),
5353
"sign" => ("nom::character::complete::sign", &[]),
54+
// Primitive parsers
55+
"u8" => ("nom::character::complete::u8", &[]),
56+
"u16" => ("nom::character::complete::u16", &[]),
57+
"u32" => ("nom::character::complete::u32", &[]),
58+
"u64" => ("nom::character::complete::u64", &[]),
59+
"u128" => ("nom::character::complete::u128", &[]),
60+
"i8" => ("nom::character::complete::i8", &[]),
61+
"i16" => ("nom::character::complete::i16", &[]),
62+
"i32" => ("nom::character::complete::i32", &[]),
63+
"i64" => ("nom::character::complete::i64", &[]),
64+
"i128" => ("nom::character::complete::i128", &[]),
65+
// From the nom::number::complete module,
66+
"be_u8" => ("nom::number::complete::be_u8", &[]),
67+
"be_i8" => ("nom::number::complete::be_i8", &[]),
68+
"be_u16" => ("nom::number::complete::be_u16", &[]),
69+
"be_i16" => ("nom::number::complete::be_i16", &[]),
70+
"be_u24" => ("nom::number::complete::be_u24", &[]),
71+
"be_i24" => ("nom::number::complete::be_i24", &[]),
72+
"be_u32" => ("nom::number::complete::be_u32", &[]),
73+
"be_i32" => ("nom::number::complete::be_i32", &[]),
74+
"be_u64" => ("nom::number::complete::be_u64", &[]),
75+
"be_i64" => ("nom::number::complete::be_i64", &[]),
76+
"be_u128" => ("nom::number::complete::be_u128", &[]),
77+
"be_i128" => ("nom::number::complete::be_i128", &[]),
78+
"be_f32" => ("nom::number::complete::be_f32", &[]),
79+
"be_f64" => ("nom::number::complete::be_f64", &[]),
80+
"le_u8" => ("nom::number::complete::le_u8", &[]),
81+
"le_i8" => ("nom::number::complete::le_i8", &[]),
82+
"le_u16" => ("nom::number::complete::le_u16", &[]),
83+
"le_i16" => ("nom::number::complete::le_i16", &[]),
84+
"le_u24" => ("nom::number::complete::le_u24", &[]),
85+
"le_i24" => ("nom::number::complete::le_i24", &[]),
86+
"le_u32" => ("nom::number::complete::le_u32", &[]),
87+
"le_i32" => ("nom::number::complete::le_i32", &[]),
88+
"le_u64" => ("nom::number::complete::le_u64", &[]),
89+
"le_i64" => ("nom::number::complete::le_i64", &[]),
90+
"le_u128" => ("nom::number::complete::le_u128", &[]),
91+
"le_i128" => ("nom::number::complete::le_i128", &[]),
92+
"le_f32" => ("nom::number::complete::le_f32", &[]),
93+
"le_f64" => ("nom::number::complete::le_f64", &[]),
94+
"hex_u32" => ("nom::number::complete::hex_u32", &[]),
95+
"float" => ("nom::number::complete::float", &[]),
96+
"double" => ("nom::number::complete::double", &[]),
5497
// From the nom::combinator module
5598
"rest" => ("nom::combinator::rest", &[]),
5699
"rest_len" => ("nom::combinator::rest_len", &[]),

tests/different_input_types.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use nom::error::Error;
12
use nom_parse_macros::parse_from;
23
use nom_parse_trait::ParseFromExt;
34

@@ -7,10 +8,13 @@ struct Test(i32);
78

89
#[test]
910
pub fn from_str() {
10-
assert_eq!(Ok(Test(32)), Test::parse_complete("32"));
11+
assert_eq!(Ok::<_, Error<_>>(Test(32)), Test::parse_complete("32"));
1112
}
1213

1314
#[test]
1415
pub fn from_bytes() {
15-
assert_eq!(Ok(Test(32)), Test::parse_complete(b"32".as_ref()));
16-
}
16+
assert_eq!(
17+
Ok::<_, Error<_>>(Test(32)),
18+
Test::parse_complete(b"32".as_ref())
19+
);
20+
}

tests/enums.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use nom::error::Error;
12
use nom_parse_macros::parse_from;
23
use nom_parse_trait::ParseFromExt;
34

@@ -7,34 +8,47 @@ enum TestStruct {
78
Number(u32),
89
#[format(delimited('(', separated_list0(",", ()), ')'))]
910
Numbers(Vec<u32>, #[derived(field_0.iter().sum())] u32),
10-
#[format(delimited('"', map(alpha0, |s: &str| s.to_string()), '"'))]
11+
#[format(delimited('"', map(alpha0, |s: I| String::from_utf8_lossy(s.as_bytes()).to_string()), '"'))]
1112
String {
1213
value: String,
1314
#[derived(value.len())]
1415
len: usize,
1516
},
17+
#[format("dummy")]
18+
Dummy,
1619
}
1720

1821
#[test]
1922
fn test_number() {
20-
assert_eq!(Ok(TestStruct::Number(32)), TestStruct::parse_complete("32"));
23+
assert_eq!(
24+
Ok::<_, Error<_>>(TestStruct::Number(32)),
25+
TestStruct::parse_complete("32")
26+
);
2127
}
2228

2329
#[test]
2430
fn test_numbers() {
2531
assert_eq!(
26-
Ok(TestStruct::Numbers(vec![32, 34, 46], 112)),
32+
Ok::<_, Error<_>>(TestStruct::Numbers(vec![32, 34, 46], 112)),
2733
TestStruct::parse_complete("(32,34,46)")
2834
);
2935
}
3036

3137
#[test]
3238
fn test_string() {
3339
assert_eq!(
34-
Ok(TestStruct::String {
40+
Ok::<_, Error<_>>(TestStruct::String {
3541
value: "dummy".to_string(),
3642
len: 5,
3743
}),
3844
TestStruct::parse_complete("\"dummy\"")
3945
)
4046
}
47+
48+
#[test]
49+
fn test_dummy() {
50+
assert_eq!(
51+
Ok::<_, Error<_>>(TestStruct::Dummy),
52+
TestStruct::parse_complete("dummy")
53+
);
54+
}

tests/string_matching.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn test_vector() {
1313
}
1414

1515
assert_eq!(
16-
Ok(Test { x: 1, y: 3, z: 4 }),
16+
Ok::<_, Error<_>>(Test { x: 1, y: 3, z: 4 }),
1717
Test::parse_complete("(1,3,4)")
1818
);
1919

0 commit comments

Comments
 (0)