1use proc_macro2::{TokenStream, TokenTree};
2use quote::ToTokens;
3use syn::{bracketed, parse::ParseStream};
4
5#[derive(Debug)]
6pub struct MapExpr {
7 pub root_mapping: syn::Expr,
8 pub segments: Vec<syn::Expr>,
9 pub assign_token: Option<syn::Token![=]>,
10 pub assigned_value: Option<syn::Expr>
11}
12
13impl syn::parse::Parse for MapExpr {
14 fn parse(input: ParseStream) -> syn::Result<Self> {
15 let mut root_expr_stream = TokenStream::new();
16 input.step(|cursor| {
17 let mut rest = *cursor;
18 while let Some((tt, next)) = rest.token_tree() {
19 if matches!(tt, TokenTree::Group(_)) {
20 return Ok(((), rest));
21 } else {
22 tt.to_tokens(&mut root_expr_stream);
23 rest = next;
24 }
25 }
26 Err(cursor.error("no `TokenTree::Group` was found after this point"))
27 })?;
28
29 let mut segments = Vec::new();
30 while !input.is_empty() && !input.lookahead1().peek(syn::Token![=]) {
31 let content;
32 let _bracket_token = bracketed!(content in input);
33
34 while !content.is_empty() {
35 segments.push(content.parse()?);
36 }
37 }
38
39 if segments.is_empty() {
40 return Err(input.error("expected at least one segment"));
41 }
42
43 let root_mapping = syn::parse2(root_expr_stream)?;
44
45 if !input.is_empty() {
46 let assign_token = input.parse()?;
47 let assigned_value = input.parse()?;
48 Ok(Self {
49 root_mapping,
50 segments,
51 assign_token: Some(assign_token),
52 assigned_value: Some(assigned_value)
53 })
54 } else {
55 Ok(Self {
56 root_mapping,
57 segments,
58 assign_token: None,
59 assigned_value: None
60 })
61 }
62 }
63}
64
65#[cfg(test)]
66mod test {
67 use crate::MapExpr;
68
69 #[test]
70 fn basic_parsing_works() {
71 let simple_expr = syn::parse_str::<MapExpr>("self.tokens[a]").unwrap();
72
73 assert_eq!(simple_expr.segments.len(), 1);
74 assert_eq!(simple_expr.assign_token, None);
75 assert_eq!(simple_expr.assigned_value, None);
76
77 let complex_expr = syn::parse_str::<MapExpr>("self.tokens[a][b][c][d][e]").unwrap();
78
79 assert_eq!(complex_expr.segments.len(), 5);
80 assert_eq!(complex_expr.assign_token, None);
81 assert_eq!(complex_expr.assigned_value, None);
82
83 let invalid_expr = syn::parse_str::<MapExpr>("self.tokens[a][b"); assert!(invalid_expr.is_err());
85
86 let invalid_expr = syn::parse_str::<MapExpr>("self.tokens.get(a)"); assert!(invalid_expr.is_err());
88
89 let invalid_expr = syn::parse_str::<MapExpr>("self.tokens(a)(b)"); assert!(invalid_expr.is_err());
91
92 let invalid_expr = syn::parse_str::<MapExpr>("self.tokens"); assert!(invalid_expr.is_err());
94 }
95
96 #[test]
97 fn assigning_parsing_works() {
98 let simple_expr = syn::parse_str::<MapExpr>("self.tokens[a] = 1").unwrap();
99
100 assert_eq!(simple_expr.segments.len(), 1);
101 assert!(simple_expr.assign_token.is_some());
102 assert!(simple_expr.assigned_value.is_some());
103
104 let complex_expr =
105 syn::parse_str::<MapExpr>("self.tokens[a][b][c][d][e] = String::from(3)").unwrap();
106
107 assert_eq!(complex_expr.segments.len(), 5);
108 assert!(complex_expr.assign_token.is_some());
109 assert!(complex_expr.assigned_value.is_some());
110 }
111
112 #[test]
113 fn parsing_complex_expressions_works() {
114 let simple_expr = syn::parse_str::<MapExpr>(
115 "get_mapping[self.build_key()][String::from(1)] = calculate_value()"
116 )
117 .unwrap();
118
119 assert_eq!(simple_expr.segments.len(), 2);
120 assert!(simple_expr.assign_token.is_some());
121 assert!(simple_expr.assigned_value.is_some());
122 }
123}