Skip to main content

zyn_core/ast/at/
match_node.rs

1use proc_macro2::Ident;
2use proc_macro2::Span;
3use proc_macro2::TokenStream;
4use proc_macro2::TokenTree;
5
6use quote::ToTokens;
7use quote::quote;
8
9use syn::Token;
10use syn::parse::Parse;
11use syn::parse::ParseStream;
12
13use crate::template::Template;
14
15use crate::Expand;
16
17pub struct MatchNode {
18    pub span: Span,
19    pub expr: TokenStream,
20    pub arms: Vec<(TokenStream, Template)>,
21}
22
23impl MatchNode {
24    pub fn span(&self) -> Span {
25        self.span
26    }
27}
28
29impl Parse for MatchNode {
30    fn parse(input: ParseStream) -> syn::Result<Self> {
31        let expr_content;
32        syn::parenthesized!(expr_content in input);
33        let expr: TokenStream = expr_content.parse()?;
34
35        let arms_content;
36        syn::braced!(arms_content in input);
37
38        let mut arms = Vec::new();
39
40        while !arms_content.is_empty() {
41            let mut pattern = TokenStream::new();
42
43            while !arms_content.is_empty() {
44                if arms_content.peek(Token![=>]) {
45                    arms_content.parse::<Token![=>]>()?;
46                    break;
47                }
48
49                let tt: TokenTree = arms_content.parse()?;
50                tt.to_tokens(&mut pattern);
51            }
52
53            let body_content;
54            syn::braced!(body_content in arms_content);
55            let body = body_content.parse::<Template>()?;
56
57            arms.push((pattern, body));
58
59            if arms_content.peek(Token![,]) {
60                arms_content.parse::<Token![,]>()?;
61            }
62        }
63
64        Ok(Self {
65            span: Span::call_site(),
66            expr,
67            arms,
68        })
69    }
70}
71
72impl Expand for MatchNode {
73    fn expand(&self, output: &Ident, idents: &mut crate::ident::Iter) -> TokenStream {
74        let expr = &self.expr;
75        let arms: Vec<TokenStream> = self
76            .arms
77            .iter()
78            .map(|(pattern, body)| {
79                let body_expanded = body.expand(output, idents);
80                quote! { #pattern => { #body_expanded } }
81            })
82            .collect();
83
84        quote! {
85            match #expr {
86                #(#arms),*
87            }
88        }
89    }
90}