Skip to content

Commit 30c75b5

Browse files
committed
Add support for prefix, suffix parsers and literal strings as parsers
1 parent 296ca75 commit 30c75b5

File tree

6 files changed

+131
-56
lines changed

6 files changed

+131
-56
lines changed

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ path = "src/lib.rs"
2525
name = "basic_struct_with_members"
2626
path = "examples/basic_struct_with_members.rs"
2727

28+
[[example]]
29+
name = "use_matching_string"
30+
path = "examples/use_matching_string.rs"
31+
32+
[[example]]
33+
name = "use_prefix_and_suffix"
34+
path = "examples/use_prefix_and_suffix.rs"
2835

2936
[dependencies]
3037
quote = "1.0"

examples/basic_struct_with_members.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use nom_parse_macros::parse_from;
22
use nom_parse_trait::ParseFrom;
33

4-
#[parse_from(split = delimited(space0, tag(","), space0))]
4+
#[parse_from(split = delimited(space0, ",", space0))]
55
#[derive(Debug, PartialEq)]
66
struct NumberPair {
77
x: u32,

examples/use_matching_string.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use nom_parse_macros::parse_from;
22
use nom_parse_trait::ParseFrom;
33

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

examples/use_prefix_and_suffix.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use nom_parse_macros::parse_from;
2+
use nom_parse_trait::ParseFrom;
3+
4+
#[parse_from(prefix = '('; split = delimited(space0, ',', space0); suffix = ')')]
5+
#[derive(Debug, PartialEq)]
6+
struct Vector3 {
7+
x: u32,
8+
y: u32,
9+
z: u32,
10+
}
11+
12+
fn main() {
13+
let input = "(1,3,4)";
14+
let pair = Vector3::parse(input).unwrap();
15+
println!("Parsed \"{}\" as {:?}", input, pair.1);
16+
}

src/nom_packages.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
use syn::{Expr, Path, Stmt};
1+
use proc_macro2::Span;
2+
use quote::quote_spanned;
3+
use syn::{parse, parse_str, Expr, ExprArray, ExprLit, Lit, Path, Stmt};
4+
use syn::__private::IntoSpans;
25

36
const NOM_FUNCTIONS: phf::Map<&'static str, &'static str> = phf::phf_map! {
47
// From the nom::branch module
58
"alt" => "nom::branch::alt",
69
// From the nom::bytes::complete module
7-
"tag" => "nom::bytes::complete::tag",
10+
// "tag" => "nom::bytes::complete::tag", tag is no longer explicitly supported, we use a raw string literal instead
811
"tag_no_case" => "nom::bytes::complete::tag_no_case",
912
"is_not" => "nom::bytes::complete::is_not",
1013
"is_a" => "nom::bytes::complete::is_a",
@@ -90,6 +93,7 @@ const NOM_FUNCTIONS: phf::Map<&'static str, &'static str> = phf::phf_map! {
9093
"terminated" => "nom::sequence::terminated",
9194
"separated_pair" => "nom::sequence::separated_pair",
9295
"delimited" => "nom::sequence::delimited",
96+
"tuple" => "nom::sequence::tuple",
9397
};
9498

9599
pub fn apply_nom_namespaces(expr: &mut Expr) {
@@ -159,6 +163,21 @@ pub fn apply_nom_namespaces(expr: &mut Expr) {
159163
Expr::Let(let_expr) => {
160164
apply_nom_namespaces(&mut let_expr.expr);
161165
}
166+
Expr::Lit(lit_expr) => match &lit_expr.lit {
167+
Lit::Str(value) => {
168+
*expr = match_bytes(value.value().as_bytes(), value.span());
169+
}
170+
Lit::ByteStr(value) => {
171+
*expr = match_bytes(&value.value(), value.span());
172+
}
173+
Lit::Byte(value) => {
174+
*expr = match_bytes(&[value.value()], value.span());
175+
}
176+
Lit::Char(value) => {
177+
*expr = match_bytes(value.value().to_string().as_bytes(), value.span());
178+
}
179+
_ => {}
180+
},
162181
Expr::Loop(loop_expr) => {
163182
loop_expr.body.stmts.iter_mut().for_each(|stmt| {
164183
apply_nom_namespaces_stmt(stmt);
@@ -184,7 +203,7 @@ pub fn apply_nom_namespaces(expr: &mut Expr) {
184203
if segments.len() == 1 {
185204
let ident = &segments[0].ident;
186205
if let Some(nom_path) = NOM_FUNCTIONS.get(ident.to_string().as_str()) {
187-
path_expr.path.segments = syn::parse_str::<Path>(nom_path).unwrap().segments;
206+
path_expr.path.segments = parse_str::<Path>(nom_path).unwrap().segments;
188207
}
189208
}
190209
}
@@ -251,6 +270,18 @@ pub fn apply_nom_namespaces(expr: &mut Expr) {
251270
}
252271
}
253272

273+
fn match_bytes(value: &[u8], span: Span) -> Expr {
274+
let mut array = parse_str::<ExprArray>(format!("{:?}", value).as_str()).unwrap();
275+
array.bracket_token.span = span.into_spans();
276+
array.elems.iter_mut().for_each(|elem| {
277+
if let Expr::Lit(ExprLit { lit, .. }) = elem {
278+
lit.set_span(span);
279+
}
280+
});
281+
parse::<Expr>(quote_spanned! { span => nom::bytes::complete::tag(#array.as_ref()) }.into())
282+
.unwrap()
283+
}
284+
254285
fn apply_nom_namespaces_stmt(statement: &mut Stmt) {
255286
match statement {
256287
Stmt::Local(local) => {

src/settings.rs

Lines changed: 72 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,54 @@
11
use crate::fields::Field;
22
use crate::nom_packages::apply_nom_namespaces;
33
use itertools::Itertools;
4+
use proc_macro::Span;
45
use proc_macro2::TokenStream;
56
use quote::{quote, ToTokens};
67
use syn::parse::{Parse, ParseStream};
78
use syn::{parse, Error, Expr, LitStr, Token};
89

910
pub enum ParseSettings {
10-
Split(Expr),
11+
Split {
12+
prefix: Option<Expr>,
13+
split: Expr,
14+
suffix: Option<Expr>,
15+
},
1116
Match(LitStr),
1217
}
1318

1419
impl ParseSettings {
1520
pub fn from(attrs: TokenStream) -> syn::Result<Self> {
16-
let arguments = parse::<Arguments>(attrs.into())?;
17-
18-
match arguments {
19-
Arguments::Split { expr, .. } => Ok(ParseSettings::Split(expr)),
20-
Arguments::Match { lit, .. } => Ok(ParseSettings::Match(lit)),
21-
Arguments::LiteralMatch { lit } => Ok(ParseSettings::Match(lit)),
22-
}
21+
parse::<ParseSettings>(attrs.into())
2322
}
2423

2524
pub fn generate_parse_expressions(&self, fields: &[Field]) -> Vec<TokenStream> {
2625
match self {
27-
ParseSettings::Split(expr) => {
28-
let mut expr = expr.clone();
29-
apply_nom_namespaces(&mut expr);
30-
let expr = quote! { let (input, _) = #expr.parse(input)?; };
31-
Itertools::intersperse(
26+
ParseSettings::Split{ prefix, split, suffix} => {
27+
let mut split = split.clone();
28+
apply_nom_namespaces(&mut split);
29+
30+
let mut expressions: Vec<_> = Itertools::intersperse(
3231
fields
3332
.iter()
3433
.map(|field| field.generate_expression().into_token_stream()),
35-
expr,
34+
quote! { let (input, _) = split.parse(input)?; },
3635
)
37-
.collect()
36+
.collect();
37+
38+
if let Some(prefix) = prefix {
39+
let mut prefix = prefix.clone();
40+
apply_nom_namespaces(&mut prefix);
41+
expressions.insert(0, quote! { let (input, _) = #prefix.parse(input)?; });
42+
}
43+
44+
if let Some(suffix) = suffix {
45+
let mut suffix = suffix.clone();
46+
apply_nom_namespaces(&mut suffix);
47+
expressions.push(quote! { let (input, _) = #suffix.parse(input)?; });
48+
}
49+
50+
expressions.insert(0, quote! { let mut split = #split; });
51+
expressions
3852
}
3953
ParseSettings::Match(literal) => {
4054
let value = literal.value();
@@ -68,50 +82,57 @@ impl ParseSettings {
6882
mod keywords {
6983
use syn::custom_keyword;
7084

85+
custom_keyword!(prefix);
7186
custom_keyword!(split);
87+
custom_keyword!(suffix);
7288
}
7389

74-
#[allow(dead_code)]
75-
enum Arguments {
76-
Split {
77-
token: keywords::split,
78-
eq_token: Token![=],
79-
expr: Expr,
80-
},
81-
Match {
82-
token: Token![match],
83-
eq_token: Token![=],
84-
lit: LitStr,
85-
},
86-
LiteralMatch {
87-
lit: LitStr,
88-
},
89-
}
90-
91-
impl Parse for Arguments {
90+
impl Parse for ParseSettings {
9291
fn parse(input: ParseStream) -> syn::Result<Self> {
9392
let lookahead = input.lookahead1();
94-
if lookahead.peek(keywords::split) {
95-
let token = input.parse::<keywords::split>()?;
96-
let eq_token = input.parse::<Token![=]>()?;
97-
let expr = input.parse::<Expr>()?;
98-
Ok(Arguments::Split {
99-
token,
100-
eq_token,
101-
expr,
102-
})
103-
} else if lookahead.peek(Token![match]) {
104-
let token = input.parse::<Token![match]>()?;
105-
let eq_token = input.parse::<Token![=]>()?;
93+
if lookahead.peek(LitStr) {
10694
let lit = input.parse::<LitStr>()?;
107-
Ok(Arguments::Match {
108-
token,
109-
eq_token,
110-
lit,
95+
return Ok(ParseSettings::Match(lit));
96+
}
97+
98+
let mut prefix: Option<Expr> = None;
99+
let mut split: Option<Expr> = None;
100+
let mut suffix: Option<Expr> = None;
101+
let mut first = true;
102+
103+
while !input.is_empty() {
104+
if first {
105+
first = false;
106+
} else {
107+
input.parse::<Token![;]>()?;
108+
}
109+
110+
let lookahead = input.lookahead1();
111+
if lookahead.peek(keywords::prefix) {
112+
input.parse::<keywords::prefix>()?;
113+
input.parse::<Token![=]>()?;
114+
prefix = Some(input.parse()?);
115+
} else if lookahead.peek(keywords::split) {
116+
input.parse::<keywords::split>()?;
117+
input.parse::<Token![=]>()?;
118+
split = Some(input.parse()?);
119+
} else if lookahead.peek(keywords::suffix) {
120+
input.parse::<keywords::suffix>()?;
121+
input.parse::<Token![=]>()?;
122+
suffix = Some(input.parse()?);
123+
} else {
124+
return Err(lookahead.error());
125+
}
126+
}
127+
128+
if let Some(split) = split {
129+
Ok(ParseSettings::Split {
130+
prefix,
131+
split,
132+
suffix,
111133
})
112134
} else {
113-
let lit = input.parse::<LitStr>()?;
114-
Ok(Arguments::LiteralMatch { lit })
135+
Err(Error::new(Span::call_site().into(), "Missing `split` keyword"))
115136
}
116137
}
117138
}

0 commit comments

Comments
 (0)