flatk_derive/
lib.rs

1extern crate proc_macro;
2use proc_macro::TokenStream;
3
4mod component;
5
6use syn::{DeriveInput, Expr};
7
8#[proc_macro_derive(Component, attributes(component))]
9pub fn component(input: TokenStream) -> TokenStream {
10    let input: DeriveInput = syn::parse(input).unwrap();
11
12    let gen = component::impl_component(&input);
13
14    gen.into()
15}
16
17/// Evaluate a numeric expression
18fn eval_expr(expr: Expr) -> u64 {
19    use syn::{BinOp, ExprBinary, ExprLit, ExprUnary, Lit, UnOp};
20    match expr {
21        Expr::Binary(ExprBinary {
22            left, op, right, ..
23        }) => {
24            let l = eval_expr(*left);
25            let r = eval_expr(*right);
26            match op {
27                BinOp::Add(_) => l + r,
28                BinOp::Sub(_) => l - r,
29                BinOp::Mul(_) => l * r,
30                BinOp::Div(_) => l / r,
31                BinOp::Rem(_) => l % r,
32                BinOp::BitXor(_) => l ^ r,
33                BinOp::BitAnd(_) => l & r,
34                BinOp::BitOr(_) => l | r,
35                BinOp::Shl(_) => l << r,
36                BinOp::Shr(_) => l >> r,
37                op => panic!("Unsuported operator type: {:?}", op),
38            }
39        }
40        Expr::Unary(ExprUnary { op, expr, .. }) => {
41            let a = eval_expr(*expr);
42            match op {
43                UnOp::Not(_) => !a,
44                op => panic!("Unsuported operator type: {:?}", op),
45            }
46        }
47        Expr::Lit(ExprLit {
48            lit: Lit::Int(i), ..
49        }) => i.base10_parse::<u64>().expect("Invalid integer literal"),
50        _ => panic!("Unsuported expression type"),
51    }
52}
53
54/// A simple macro constructing U# types given an expression.
55///
56/// For example: `U![3*3]` becomes `U9`.
57#[allow(non_snake_case)]
58#[proc_macro]
59pub fn U(input: TokenStream) -> TokenStream {
60    use proc_macro2::Span;
61    use quote::quote;
62    use syn::Ident;
63    let expr: Expr = syn::parse(input).expect("Expected an expression");
64
65    let num = eval_expr(expr);
66    let ident = Ident::new(&format!("U{}", num), Span::call_site());
67    (quote! {
68        #ident
69    })
70    .into()
71}