Skip to main content

zyn_core/ast/
mod.rs

1pub mod at;
2mod group_node;
3mod interp_node;
4mod pipe_node;
5mod tokens_node;
6
7pub use at::*;
8pub use group_node::GroupNode;
9pub use interp_node::InterpNode;
10pub use pipe_node::PipeNode;
11pub use tokens_node::TokensNode;
12
13use proc_macro2::Ident;
14use proc_macro2::Span;
15use proc_macro2::TokenStream;
16use proc_macro2::TokenTree;
17
18use quote::ToTokens;
19
20use syn::Token;
21use syn::parse::ParseStream;
22
23use crate::Expand;
24use crate::ident;
25
26pub enum Node {
27    Tokens(TokensNode),
28    Interp(InterpNode),
29    At(AtNode),
30    Group(GroupNode),
31}
32
33impl Node {
34    pub fn is_tokens(&self) -> bool {
35        matches!(self, Self::Tokens(_))
36    }
37
38    pub fn is_interp(&self) -> bool {
39        matches!(self, Self::Interp(_))
40    }
41
42    pub fn is_at(&self) -> bool {
43        matches!(self, Self::At(_))
44    }
45
46    pub fn is_group(&self) -> bool {
47        matches!(self, Self::Group(_))
48    }
49}
50
51impl Node {
52    pub fn as_tokens(&self) -> &TokensNode {
53        match self {
54            Self::Tokens(v) => v,
55            _ => panic!("called as_tokens on non-Tokens node"),
56        }
57    }
58
59    pub fn as_interp(&self) -> &InterpNode {
60        match self {
61            Self::Interp(v) => v,
62            _ => panic!("called as_interp on non-Interp node"),
63        }
64    }
65
66    pub fn as_at(&self) -> &AtNode {
67        match self {
68            Self::At(v) => v,
69            _ => panic!("called as_at on non-At node"),
70        }
71    }
72
73    pub fn as_group(&self) -> &GroupNode {
74        match self {
75            Self::Group(v) => v,
76            _ => panic!("called as_group on non-Group node"),
77        }
78    }
79}
80
81impl Node {
82    pub fn span(&self) -> Span {
83        match self {
84            Self::Tokens(v) => v.span(),
85            Self::Interp(v) => v.span(),
86            Self::At(v) => v.span(),
87            Self::Group(v) => v.span(),
88        }
89    }
90}
91
92impl From<TokensNode> for Node {
93    fn from(v: TokensNode) -> Self {
94        Self::Tokens(v)
95    }
96}
97
98impl From<InterpNode> for Node {
99    fn from(v: InterpNode) -> Self {
100        Self::Interp(v)
101    }
102}
103
104impl From<AtNode> for Node {
105    fn from(v: AtNode) -> Self {
106        Self::At(v)
107    }
108}
109
110impl From<GroupNode> for Node {
111    fn from(v: GroupNode) -> Self {
112        Self::Group(v)
113    }
114}
115
116impl Node {
117    pub fn parse_brace(input: ParseStream) -> syn::Result<Self> {
118        let content;
119        let brace = syn::braced!(content in input);
120        let span = brace.span.join();
121
122        let fork = content.fork();
123        let is_interp = if fork.peek(syn::token::Brace) {
124            let inner;
125            syn::braced!(inner in fork);
126            fork.is_empty()
127        } else {
128            false
129        };
130
131        if is_interp {
132            let inner;
133            syn::braced!(inner in content);
134
135            let mut expr = TokenStream::new();
136            let mut pipes = Vec::new();
137
138            while !inner.is_empty() {
139                if inner.peek(Token![|]) {
140                    inner.parse::<Token![|]>()?;
141                    pipes.push(inner.parse::<PipeNode>()?);
142                } else if pipes.is_empty() {
143                    let tt: TokenTree = inner.parse()?;
144                    tt.to_tokens(&mut expr);
145                } else {
146                    break;
147                }
148            }
149
150            if expr.is_empty() {
151                return Err(syn::Error::new(span, "empty interpolation"));
152            }
153
154            Ok(InterpNode { span, expr, pipes }.into())
155        } else {
156            let body = content.parse::<crate::template::Template>()?;
157            Ok(GroupNode {
158                span,
159                delimiter: proc_macro2::Delimiter::Brace,
160                body: Box::new(body),
161            }
162            .into())
163        }
164    }
165}
166
167impl Expand for Node {
168    fn expand(&self, output: &Ident, idents: &mut ident::Iter) -> TokenStream {
169        match self {
170            Self::Tokens(v) => v.expand(output, idents),
171            Self::Interp(v) => v.expand(output, idents),
172            Self::At(v) => v.expand(output, idents),
173            Self::Group(v) => v.expand(output, idents),
174        }
175    }
176}