zyn_core/ast/
interp_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 super::PipeNode;
14
15use crate::Expand;
16
17pub struct InterpNode {
18 pub span: Span,
19 pub expr: TokenStream,
20 pub pipes: Vec<PipeNode>,
21}
22
23impl InterpNode {
24 pub fn span(&self) -> Span {
25 self.span
26 }
27}
28
29impl Parse for InterpNode {
30 fn parse(input: ParseStream) -> syn::Result<Self> {
31 let content;
32 let brace = syn::braced!(content in input);
33 let span = brace.span.join();
34
35 let inner;
36 syn::braced!(inner in content);
37
38 let mut expr = TokenStream::new();
39 let mut pipes = Vec::new();
40
41 while !inner.is_empty() {
42 if inner.peek(Token![|]) {
43 inner.parse::<Token![|]>()?;
44 pipes.push(inner.parse::<PipeNode>()?);
45 } else if pipes.is_empty() {
46 let tt: TokenTree = inner.parse()?;
47 tt.to_tokens(&mut expr);
48 } else {
49 break;
50 }
51 }
52
53 if expr.is_empty() {
54 return Err(syn::Error::new(span, "empty interpolation"));
55 }
56
57 Ok(Self { span, expr, pipes })
58 }
59}
60
61impl Expand for InterpNode {
62 fn expand(&self, output: &Ident, idents: &mut crate::ident::Iter) -> TokenStream {
63 let expr = &self.expr;
64
65 if self.pipes.is_empty() {
66 return quote! {
67 ::zyn::quote::ToTokens::to_tokens(&(#expr), &mut #output);
68 };
69 }
70
71 let mut steps = vec![quote! { let __zyn_val = (#expr).to_string(); }];
72
73 for (i, pipe) in self.pipes.iter().enumerate() {
74 if i > 0 {
75 steps.push(quote! { let __zyn_val = __zyn_val.to_string(); });
76 }
77
78 steps.push(pipe.expand(output, idents));
79 }
80
81 quote! {
82 {
83 #(#steps)*
84 ::zyn::quote::ToTokens::to_tokens(&__zyn_val, &mut #output);
85 }
86 }
87 }
88}