1
2extern crate proc_macro;
3
4use quote::quote;
5use syn::{self, parse::{Parse, ParseStream}, parse_macro_input, Token};
6
7struct Ternary {
11 condition: syn::Expr,
12 true_branch: Expression,
13 false_branch: Expression,
14}
15
16impl Parse for Ternary {
17 fn parse(input: ParseStream) -> syn::Result<Self> {
18 let condition = input.parse()?;
19
20 input.parse::<Token![=>]>()?;
21
22 let true_branch = input.parse()?;
23 input.parse::<Token![:]>()?;
24 let false_branch = input.parse()?;
25
26 Ok(Self {
27 condition,
28 true_branch,
29 false_branch,
30 })
31 }
32}
33
34impl quote::ToTokens for Ternary {
35 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
36 let condition = &self.condition;
37
38 let true_branch = match &self.true_branch {
39 Expression::Ternary(ternary) => quote! { #ternary },
40 Expression::Simple(simple) => quote! { #simple },
41 };
42
43 let false_branch = match &self.false_branch {
44 Expression::Ternary(ternary) => quote! { #ternary },
45 Expression::Simple(simple) => quote! { #simple },
46 };
47
48 tokens.extend(quote! { if #condition { #true_branch } else { #false_branch } });
49 }
50}
51struct SimpleExpression {
52 expr: syn::Expr,
53}
54
55impl Parse for SimpleExpression {
56 fn parse(input: ParseStream) -> syn::Result<Self> {
57 Ok(Self {
58 expr: input.parse()?,
59 })
60 }
61}
62
63impl quote::ToTokens for SimpleExpression {
64 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
65 let expr = &self.expr;
66 tokens.extend(quote! { #expr });
67 }
68}
69
70enum Expression {
71 Ternary(Box<Ternary>),
72 Simple(SimpleExpression),
73}
74
75impl Parse for Expression {
76 fn parse(input: ParseStream) -> syn::Result<Self> {
77 let expr: syn::Expr = input.parse()?;
78
79 if input.peek(Token![=>]) {
80 input.parse::<Token![=>]>()?;
81 let true_branch = input.parse()?;
82 input.parse::<Token![:]>()?;
83 let false_branch = input.parse()?;
84
85 return Ok(Self::Ternary(Box::new(Ternary {
86 condition: expr,
87 true_branch,
88 false_branch,
89 })))
90 }
91
92 Ok(Self::Simple(SimpleExpression { expr }))
93 }
94}
95
96#[proc_macro]
138pub fn tnr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
139 let tern = parse_macro_input!(input as Ternary);
140 quote! { #tern }.into()
141}