use proc_macro2 as much as possible

This commit is contained in:
Iris System 2024-09-13 22:17:11 +12:00
parent fd7d3e6a3a
commit c99b59673a

View file

@ -1,30 +1,21 @@
use proc_macro::{Delimiter, TokenStream, TokenTree}; use proc_macro2::{Delimiter, TokenStream, TokenTree, Ident, Literal, Span};
use proc_macro2::{Ident, Literal, Span};
use quote::quote; use quote::quote;
fn make_command( fn make_command(
tokens: Vec<proc_macro2::TokenStream>, tokens: Vec<TokenStream>,
help: String, help: Literal,
cb: String, cb: Literal,
) -> proc_macro2::TokenStream { ) -> TokenStream {
let help = Literal::string(&help);
let cb = Literal::string(&cb);
quote! { quote! {
Command { tokens: vec![#(#tokens),*], help: #help.to_string(), cb: #cb.to_string() } Command { tokens: vec![#(#tokens),*], help: #help.to_string(), cb: #cb.to_string() }
} }
} }
// horrible, but the best way i could find to do this fn command_from_stream(stream: TokenStream) -> TokenStream {
fn token_to_string(i: String) -> String {
i.to_string()[1..i.to_string().len() - 1].to_string()
}
fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream {
let mut part = 0; let mut part = 0;
let mut found_tokens: Vec<proc_macro2::TokenStream> = Vec::new(); let mut found_tokens: Vec<TokenStream> = Vec::new();
let mut found_cb: Option<String> = None; let mut found_cb: Option<Literal> = None;
let mut found_help: Option<String> = None; let mut found_help: Option<Literal> = None;
let mut is_token_lit = false; let mut is_token_lit = false;
let mut tokens = stream.clone().into_iter(); let mut tokens = stream.clone().into_iter();
@ -34,11 +25,10 @@ fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream {
None if part == 2 && found_help.is_some() => break 'a, None if part == 2 && found_help.is_some() => break 'a,
Some(TokenTree::Ident(ident)) if part == 0 => { Some(TokenTree::Ident(ident)) if part == 0 => {
found_tokens.push(if is_token_lit { found_tokens.push(if is_token_lit {
let ident = Ident::new(ident.to_string().as_str(), Span::call_site());
quote! { Token::#ident }.into() quote! { Token::#ident }.into()
} else { } else {
let ident = Literal::string(format!("{ident}").as_str()); let lit = Literal::string(&format!("{ident}"));
quote! { Token::Value(vec![#ident.to_string() ]) } quote! { Token::Value(vec![#lit.to_string() ]) }
}); });
// reset this // reset this
is_token_lit = false; is_token_lit = false;
@ -52,9 +42,11 @@ fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream {
{ {
part += 1 part += 1
} }
Some(TokenTree::Ident(ident)) if part == 1 => found_cb = Some(format!("{ident}")), Some(TokenTree::Ident(ident)) if part == 1 => {
found_cb = Some(Literal::string(&format!("{ident}")))
}
Some(TokenTree::Literal(lit)) if part == 2 => { Some(TokenTree::Literal(lit)) if part == 2 => {
found_help = Some(token_to_string(lit.to_string())) found_help = Some(lit)
} }
_ => panic!("invalid command definition: {stream}"), _ => panic!("invalid command definition: {stream}"),
} }
@ -63,8 +55,9 @@ fn command_from_stream(stream: TokenStream) -> proc_macro2::TokenStream {
} }
#[proc_macro] #[proc_macro]
pub fn commands(stream: TokenStream) -> TokenStream { pub fn commands(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut commands: Vec<proc_macro2::TokenStream> = Vec::new(); let stream: TokenStream = stream.into();
let mut commands: Vec<TokenStream> = Vec::new();
let mut top_level_tokens = stream.into_iter(); let mut top_level_tokens = stream.into_iter();
'a: loop { 'a: loop {