diff options
Diffstat (limited to 'macros/src/lib.rs')
| -rw-r--r-- | macros/src/lib.rs | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/macros/src/lib.rs b/macros/src/lib.rs new file mode 100644 index 0000000..222f14d --- /dev/null +++ b/macros/src/lib.rs @@ -0,0 +1,158 @@ +extern crate proc_macro; +use proc_macro::TokenStream; +use proc_macro2::{Ident, Span}; +use quote::quote; + +use syn::parse_macro_input; + +mod macro_types; + +use macro_types::*; + +fn generate_help(items: &Items) -> proc_macro2::TokenStream { + let command_help = items.inner.iter().filter_map(|x| { + if let Item::Command(command) = x { + let help = command.help(); + Some(quote! { + bot.send_notice(target, #help).unwrap(); + }) + } else { + None + } + }); + + let matcher_help = items.inner.iter().filter_map(|x| { + if let Item::Matcher(matcher) = x { + let help = matcher.help(); + Some(quote! { + bot.send_notice(target, #help).unwrap(); + }) + } else { + None + } + }); + + let hook_help = items.inner.iter().filter_map(|x| { + if let Item::Hook(hook) = x { + let help = hook.help(); + Some(quote! { + bot.send_notice(target, #help).unwrap(); + }) + } else { + None + } + }); + + let gen = quote! { + let target = message.source_nickname().unwrap(); + + bot.send_notice(target, "COMMANDS:").unwrap(); + #(#command_help)* + + bot.send_notice(target, "MATCHERS:").unwrap(); + #(#matcher_help)* + + bot.send_notice(target, "HOOKS:").unwrap(); + #(#hook_help)* + }; + gen.into() +} + +#[proc_macro] +pub fn catinator(tokens: TokenStream) -> TokenStream { + let items = parse_macro_input!(tokens as Items); + + let hooks = items.inner.iter().filter_map(|x| { + if let Item::Hook(hook) = x { + Some(hook.to_call()) + } else { + None + } + }); + + let commands = items.inner.iter().filter_map(|x| { + if let Item::Command(command) = x { + Some(command.to_call()) + } else { + None + } + }); + + let matchers = items.inner.iter().filter_map(|x| { + if let Item::Matcher(command) = x { + Some(command.to_call()) + } else { + None + } + }); + + let matchers_regex = items.inner.iter().filter_map(|x| { + if let Item::Matcher(matcher) = x { + let name = &matcher.name; + let regex = &matcher.matcher; + + let ident = Ident::new(&name.value(), Span::call_site()); + + Some(quote! { + let #ident = regex::Regex::new(#regex).unwrap(); + }) + } else { + None + } + }); + + let help = generate_help(&items); + + let gen = quote! { + use std::env; + + use futures::prelude::*; + use tracing::{info, debug, trace}; + + use irc::client::prelude::*; + use catinator::Bot; + + let config_path = env::var("CATINATOR_CONFIG").unwrap_or("config.toml".to_string()); + info!("starting bot with config file {}", config_path); + let mut bot = Bot::new(&config_path).await.unwrap(); + + if bot.config.server.sasl { + info!("initializing sasl"); + bot.sasl_init().await.unwrap() + } + + #(#matchers_regex)* + + info!("starting main event loop"); + let mut stream = bot.irc_client.stream().unwrap(); + + while let Some(message) = stream.next().await.transpose().unwrap() { + trace!("{:?}", message); + + let command = message.clone().command; + + #(#hooks)* + + match &command { + Command::PRIVMSG(_target, text) => { + let mut word = text.split_ascii_whitespace().next().unwrap().chars(); + let prefix = word.next().unwrap(); + let rest: String = word.collect(); + + if prefix == bot.config.settings.prefix { + if "help" == rest { + #help + } + + #(#commands)* + } else { + #(#matchers)* + } + } + _ => (), + } + } + }; + + return gen.into(); +} |
