Skip to main content

zyn_core/ast/
group_node.rs

1use proc_macro2::Delimiter;
2use proc_macro2::Ident;
3use proc_macro2::Span;
4use proc_macro2::TokenStream;
5
6use quote::quote;
7
8use syn::parse::Parse;
9use syn::parse::ParseStream;
10
11use crate::template::Template;
12
13use crate::Expand;
14
15/// A delimited group in a zyn template: `(...)`, `[...]`, or `{...}`.
16///
17/// The body is expanded recursively and wrapped in the appropriate delimiter.
18pub struct GroupNode {
19    /// Source span.
20    pub span: Span,
21    /// The delimiter kind: parenthesis, bracket, or brace.
22    pub delimiter: Delimiter,
23    /// The template body inside the delimiters.
24    pub body: Box<Template>,
25}
26
27impl GroupNode {
28    pub fn span(&self) -> Span {
29        self.span
30    }
31
32    pub fn to_display_stream(&self, injections: &[(String, TokenStream)]) -> TokenStream {
33        use quote::ToTokens;
34        let inner = self.body.to_display_stream(injections);
35        let mut ts = TokenStream::new();
36        proc_macro2::Group::new(self.delimiter, inner).to_tokens(&mut ts);
37        ts
38    }
39}
40
41impl Parse for GroupNode {
42    fn parse(input: ParseStream) -> syn::Result<Self> {
43        if input.peek(syn::token::Paren) {
44            let content;
45            let paren = syn::parenthesized!(content in input);
46            let body = content.parse::<Template>()?;
47
48            Ok(Self {
49                span: paren.span.join(),
50                delimiter: Delimiter::Parenthesis,
51                body: Box::new(body),
52            })
53        } else if input.peek(syn::token::Bracket) {
54            let content;
55            let bracket = syn::bracketed!(content in input);
56            let body = content.parse::<Template>()?;
57
58            Ok(Self {
59                span: bracket.span.join(),
60                delimiter: Delimiter::Bracket,
61                body: Box::new(body),
62            })
63        } else {
64            Err(input.error("expected a delimited group"))
65        }
66    }
67}
68
69impl Expand for GroupNode {
70    fn expand(&self, output: &Ident, idents: &mut crate::ident::Iter) -> TokenStream {
71        let inner = idents.next().unwrap();
72        let body_expanded = self.body.expand(&inner, idents);
73
74        let delim = match self.delimiter {
75            Delimiter::Parenthesis => {
76                quote! { ::zyn::proc_macro2::Delimiter::Parenthesis }
77            }
78            Delimiter::Bracket => quote! { ::zyn::proc_macro2::Delimiter::Bracket },
79            Delimiter::Brace => quote! { ::zyn::proc_macro2::Delimiter::Brace },
80            Delimiter::None => quote! { ::zyn::proc_macro2::Delimiter::None },
81        };
82
83        quote! {
84            {
85                let mut #inner = ::zyn::proc_macro2::TokenStream::new();
86                #body_expanded
87                ::zyn::quote::ToTokens::to_tokens(
88                    &::zyn::proc_macro2::Group::new(#delim, #inner),
89                    &mut #output,
90                );
91            }
92        }
93    }
94}