zyn_core/ast/at/
match_node.rs1use 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 {
26 pub span: Span,
28 pub expr: TokenStream,
30 pub arms: Vec<(TokenStream, Template)>,
32}
33
34impl MatchNode {
35 pub fn span(&self) -> Span {
36 self.span
37 }
38
39 pub fn to_display_stream(&self, injections: &[(String, TokenStream)]) -> TokenStream {
40 let expr = &self.expr;
41 let arms: Vec<TokenStream> = self
42 .arms
43 .iter()
44 .map(|(pattern, body)| {
45 let body_display = body.to_display_stream(injections);
46 quote! { #pattern => { #body_display } }
47 })
48 .collect();
49
50 quote! { match #expr { #(#arms),* } }
51 }
52}
53
54impl Parse for MatchNode {
55 fn parse(input: ParseStream) -> syn::Result<Self> {
56 let expr_content;
57 syn::parenthesized!(expr_content in input);
58 let expr: TokenStream = expr_content.parse()?;
59
60 let arms_content;
61 syn::braced!(arms_content in input);
62
63 let mut arms = Vec::new();
64
65 while !arms_content.is_empty() {
66 let mut pattern = TokenStream::new();
67
68 while !arms_content.is_empty() {
69 if arms_content.peek(Token![=>]) {
70 arms_content.parse::<Token![=>]>()?;
71 break;
72 }
73
74 let tt: TokenTree = arms_content.parse()?;
75 tt.to_tokens(&mut pattern);
76 }
77
78 let body_content;
79 syn::braced!(body_content in arms_content);
80 let body = body_content.parse::<Template>()?;
81
82 arms.push((pattern, body));
83
84 if arms_content.peek(Token![,]) {
85 arms_content.parse::<Token![,]>()?;
86 }
87 }
88
89 Ok(Self {
90 span: Span::call_site(),
91 expr,
92 arms,
93 })
94 }
95}
96
97impl Expand for MatchNode {
98 fn expand(&self, output: &Ident, idents: &mut crate::ident::Iter) -> TokenStream {
99 let expr = &self.expr;
100 let arms: Vec<TokenStream> = self
101 .arms
102 .iter()
103 .map(|(pattern, body)| {
104 let body_expanded = body.expand(output, idents);
105 quote! { #pattern => { #body_expanded }}
106 })
107 .collect();
108
109 quote! {
110 match #expr {
111 #(#arms),*
112 }
113 }
114 }
115}