Skip to content

Commit 60449f0

Browse files
committed
Creates separate parse_match macro for string matching
1 parent 9eb64b2 commit 60449f0

File tree

4 files changed

+69
-157
lines changed

4 files changed

+69
-157
lines changed

examples/use_matching_string.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use nom_parse_macros::parse_from;
1+
use nom_parse_macros::parse_match;
22
use nom_parse_trait::ParseFrom;
33

4-
#[parse_from("({},{},{})")]
4+
#[parse_match("({},{},{})")]
55
#[derive(Debug, PartialEq)]
66
struct Vector3 {
77
x: u32,

src/lib.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
extern crate proc_macro;
22
mod fields;
33
mod nom_packages;
4-
mod settings;
4+
mod string_matching;
55

66
use proc_macro::TokenStream;
77

88
use crate::fields::parse_fields;
99
use crate::nom_packages::update_nom_expression;
1010
use quote::quote;
1111
use syn::{parse_macro_input, Expr, ItemStruct, LitStr};
12+
use crate::string_matching::parse_string_match;
1213

1314
#[proc_macro_attribute]
1415
pub fn parse_from(attrs: TokenStream, object: TokenStream) -> TokenStream {
@@ -39,3 +40,34 @@ pub fn parse_from(attrs: TokenStream, object: TokenStream) -> TokenStream {
3940

4041
tokens.into()
4142
}
43+
44+
#[proc_macro_attribute]
45+
pub fn parse_match(attrs: TokenStream, object: TokenStream) -> TokenStream {
46+
let literal = parse_macro_input! { attrs as LitStr };
47+
48+
let object = parse_macro_input!(object as ItemStruct);
49+
let fields = parse_fields(&object.fields);
50+
let name = object.ident.clone();
51+
52+
match parse_string_match(&fields, literal) {
53+
Ok(parts) => {
54+
let names: Vec<_> = fields.iter().map(|field| field.get_name()).collect();
55+
let tokens = quote! {
56+
#object
57+
58+
impl nom_parse_trait::ParseFrom<&str> for #name {
59+
fn parse(input: &str) -> nom::IResult<&str, Self> {
60+
use nom::*;
61+
62+
let mut input = input;
63+
#(#parts)*
64+
Ok((input, Self { #(#names),* }))
65+
}
66+
}
67+
};
68+
69+
tokens.into()
70+
}
71+
Err(e) => e.to_compile_error().into(),
72+
}
73+
}

src/settings.rs

Lines changed: 0 additions & 154 deletions
This file was deleted.

src/string_matching.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use crate::fields::Field;
2+
use crate::nom_packages::generate_match_expression;
3+
use itertools::Itertools;
4+
use proc_macro2::TokenStream;
5+
use quote::{quote_spanned, ToTokens};
6+
use syn::parse::Parse;
7+
use syn::spanned::Spanned;
8+
use syn::{Error, LitStr, Result};
9+
10+
pub fn parse_string_match(fields: &[Field], literal: LitStr) -> Result<Vec<TokenStream>> {
11+
let value = literal.value();
12+
let parts: Vec<_> = value
13+
.split("{}")
14+
.map(|part| {
15+
let expr = generate_match_expression(part.as_bytes(), literal.span());
16+
quote_spanned! { literal.span() => let (input, _) = #expr.parse(input)?; }
17+
})
18+
.collect();
19+
20+
if parts.len() != fields.len() + 1 {
21+
return Err(Error::new(
22+
literal.span(),
23+
"Number of {} parts in the literal is not equal to the number of fields",
24+
));
25+
}
26+
27+
Ok(Itertools::interleave(
28+
parts.into_iter(),
29+
fields
30+
.iter()
31+
.map(|field| field.generate_expression().into_token_stream()),
32+
)
33+
.collect())
34+
}

0 commit comments

Comments
 (0)