zyn_core/ast/
pipe_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::Expand;
14use crate::pascal;
15
16pub struct PipeNode {
17 pub span: Span,
18 pub name: syn::Ident,
19 pub args: Vec<TokenStream>,
20}
21
22impl PipeNode {
23 pub fn span(&self) -> Span {
24 self.span
25 }
26}
27
28impl Parse for PipeNode {
29 fn parse(input: ParseStream) -> syn::Result<Self> {
30 let name: syn::Ident = input.parse()?;
31 let span = name.span();
32
33 let mut args = Vec::new();
34
35 while input.peek(Token![:]) {
36 input.parse::<Token![:]>()?;
37
38 let mut arg = TokenStream::new();
39
40 while !input.is_empty() && !input.peek(Token![:]) && !input.peek(Token![|]) {
41 let tt: TokenTree = input.parse()?;
42 tt.to_tokens(&mut arg);
43 }
44
45 args.push(arg);
46 }
47
48 Ok(Self { span, name, args })
49 }
50}
51
52const BUILTIN_PIPES: &[&str] = &[
53 "upper",
54 "lower",
55 "snake",
56 "camel",
57 "pascal",
58 "kebab",
59 "screaming",
60 "ident",
61 "fmt",
62 "str",
63 "trim",
64 "plural",
65 "singular",
66];
67
68impl Expand for PipeNode {
69 fn expand(&self, _output: &Ident, _idents: &mut crate::ident::Iter) -> TokenStream {
70 let pascal_name = pascal!(self.name => ident);
71 let is_builtin = BUILTIN_PIPES.contains(&self.name.to_string().as_str());
72
73 if is_builtin {
74 if self.args.is_empty() {
75 quote! { let __zyn_val = ::zyn::Pipe::pipe(&(::zyn::pipes::#pascal_name), __zyn_val); }
76 } else {
77 let args = &self.args;
78 quote! { let __zyn_val = ::zyn::Pipe::pipe(&(::zyn::pipes::#pascal_name(#(#args),*)), __zyn_val); }
79 }
80 } else if self.args.is_empty() {
81 quote! { let __zyn_val = ::zyn::Pipe::pipe(&(#pascal_name), __zyn_val); }
82 } else {
83 let args = &self.args;
84 quote! { let __zyn_val = ::zyn::Pipe::pipe(&(#pascal_name(#(#args),*)), __zyn_val); }
85 }
86 }
87}