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