1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
extern crate proc_macro; use proc_macro::TokenStream; use quote::{quote, quote_spanned}; use syn::{parse_macro_input, Lit, Expr, spanned::Spanned}; fn lit_to_bytes(lit: &Lit) -> Option<Vec<u8>> { match lit { Lit::Str(lit_str) => { Some(lit_str.value().into_bytes()) } Lit::ByteStr(lit_str) => { Some(lit_str.value()) } _ => { None } } } fn expr_to_bytes(expr: &Expr) -> Option<Vec<u8>> { match expr { Expr::Lit(lit) => lit_to_bytes(&lit.lit), Expr::Path(path) => { let ident = path.path.get_ident()?; Some(Vec::from(ident.to_string().as_bytes())) } Expr::Group(group) => { expr_to_bytes(&group.expr) } _ => None } } use std::sync::atomic::{AtomicBool, Ordering}; static EXIT: AtomicBool = AtomicBool::new(false); #[proc_macro] pub fn lua_bind_hash(input: TokenStream) -> TokenStream { if EXIT.load(Ordering::SeqCst) { return quote!{}.into(); } let expr = parse_macro_input!(input as Expr); match expr_to_bytes(&expr) { Some(string) => { let lua_bind_hash = lua_bind_hash::lua_bind_hash(&string); TokenStream::from(quote! { (#lua_bind_hash) }) } None => { let span = expr.span(); EXIT.store(true, Ordering::SeqCst); panic!("Invalid input: '{:?}'", expr); TokenStream::from(quote_spanned!{span => compile_error!("Invalid input"); }) } } }