diff --git a/weblog-proc-macro/src/lib.rs b/weblog-proc-macro/src/lib.rs index 227a8d7..c701011 100644 --- a/weblog-proc-macro/src/lib.rs +++ b/weblog-proc-macro/src/lib.rs @@ -1,34 +1,46 @@ +//! weblog-proc-macro contains procedural macro definitions for the +//! [`weblog`](https://crates.io/crates/weblog) crate. See its documentation for more information. extern crate proc_macro2; mod weblog_impl; use proc_macro::TokenStream; use std::iter; -use weblog_impl::{quote_console_func, ArgMode, ConsoleFunc}; +use syn::parse_macro_input; +use weblog_impl::{quote_console_func, ArgMode, ConsoleFunc, InputTokens}; -/// Call the browser's `console.assert()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/assert) +#[doc(hidden)] #[proc_macro] pub fn console_assert(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("assert_with_condition_and_data", 1), iter::once(ArgMode::PassThrough).chain(iter::repeat(ArgMode::IntoJsValue)), - input, + crate_name, + args, ) } -/// Call the browser's `console.clear()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/clear) +#[doc(hidden)] #[proc_macro] pub fn console_clear(input: TokenStream) -> TokenStream { - quote_console_func(ConsoleFunc::fixed("clear", 0), iter::empty(), input) + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + + quote_console_func( + ConsoleFunc::fixed("clear", 0), + iter::empty(), + crate_name, + args, + ) } -/// Call the browser's `console.count()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/count) +#[doc(hidden)] #[proc_macro] pub fn console_count(input: TokenStream) -> TokenStream { - let name = if input.is_empty() { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + + let name = if args.is_empty() { "count" } else { "count_with_label" @@ -37,15 +49,17 @@ pub fn console_count(input: TokenStream) -> TokenStream { quote_console_func( ConsoleFunc::fixed(name, 1), iter::once(ArgMode::PassThrough), - input, + crate_name, + args, ) } -/// Call the browser's `console.countReset()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/countReset) +#[doc(hidden)] #[proc_macro] pub fn console_count_reset(input: TokenStream) -> TokenStream { - let name = if input.is_empty() { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + + let name = if args.is_empty() { "count_reset" } else { "count_reset_with_label" @@ -54,103 +68,121 @@ pub fn console_count_reset(input: TokenStream) -> TokenStream { quote_console_func( ConsoleFunc::fixed(name, 1), iter::once(ArgMode::PassThrough), - input, + crate_name, + args, ) } -/// Call the browser's `console.debug()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/debug) +#[doc(hidden)] #[proc_macro] pub fn console_debug(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("debug", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.dir()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/dir) +#[doc(hidden)] #[proc_macro] pub fn console_dir(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("dir", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.dirxml()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/dirxml) +#[doc(hidden)] #[proc_macro] pub fn console_dirxml(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("dirxml", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.error()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/error) +#[doc(hidden)] #[proc_macro] pub fn console_error(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("error", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.exception()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/exception) +#[doc(hidden)] #[proc_macro] pub fn console_exception(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("exception", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.info()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/info) +#[doc(hidden)] #[proc_macro] pub fn console_info(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("info", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.log()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) +#[doc(hidden)] #[proc_macro] pub fn console_log(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("log", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.table()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/table) +#[doc(hidden)] #[proc_macro] pub fn console_table(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("table", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.time()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/time) +#[doc(hidden)] #[proc_macro] pub fn console_time(input: TokenStream) -> TokenStream { - let name = if input.is_empty() { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + + let name = if args.is_empty() { "time" } else { "time_with_label" @@ -159,15 +191,17 @@ pub fn console_time(input: TokenStream) -> TokenStream { quote_console_func( ConsoleFunc::fixed(name, 1), iter::once(ArgMode::PassThrough), - input, + crate_name, + args, ) } -/// Call the browser's `console.timeEnd()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/timeEnd) +#[doc(hidden)] #[proc_macro] pub fn console_time_end(input: TokenStream) -> TokenStream { - let name = if input.is_empty() { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + + let name = if args.is_empty() { "time_end" } else { "time_end_with_label" @@ -176,26 +210,30 @@ pub fn console_time_end(input: TokenStream) -> TokenStream { quote_console_func( ConsoleFunc::fixed(name, 1), iter::once(ArgMode::PassThrough), - input, + crate_name, + args, ) } -/// Call the browser's `console.timeLog()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/timeLog) +#[doc(hidden)] #[proc_macro] pub fn console_time_log(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("time_log_with_label_and_data", 1), iter::once(ArgMode::PassThrough).chain(iter::repeat(ArgMode::IntoJsValue)), - input, + crate_name, + args, ) } -/// Call the browser's `console.timeStamp()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/timeStamp) +#[doc(hidden)] #[proc_macro] pub fn console_time_stamp(input: TokenStream) -> TokenStream { - let name = if input.is_empty() { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + + let name = if args.is_empty() { "time_stamp" } else { "time_stamp_with_data" @@ -204,28 +242,33 @@ pub fn console_time_stamp(input: TokenStream) -> TokenStream { quote_console_func( ConsoleFunc::fixed(name, 1), iter::once(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.trace()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/trace) +#[doc(hidden)] #[proc_macro] pub fn console_trace(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("trace", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } -/// Call the browser's `console.warn()` function. -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/warn) +#[doc(hidden)] #[proc_macro] pub fn console_warn(input: TokenStream) -> TokenStream { + let InputTokens { crate_name, args } = parse_macro_input!(input as InputTokens); + quote_console_func( ConsoleFunc::variadic("warn", 0), iter::repeat(ArgMode::IntoJsValue), - input, + crate_name, + args, ) } diff --git a/weblog-proc-macro/src/weblog_impl.rs b/weblog-proc-macro/src/weblog_impl.rs index 572469d..cbec3a3 100644 --- a/weblog-proc-macro/src/weblog_impl.rs +++ b/weblog-proc-macro/src/weblog_impl.rs @@ -4,7 +4,7 @@ use quote::quote; use std::cmp; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; -use syn::{bracketed, parse_macro_input, Expr, Result, Token}; +use syn::{bracketed, Expr, Result, Token}; // The maximum number of variadic arguments accepted by web-sys function // groups such as `console::log_n`: @@ -18,7 +18,8 @@ const MAX_VARIADIC_ARGS: usize = 7; // // * `func`: an object containing the target function name and parameter configuration. // * `arg_modes`: an Iterator that will be called once per argument parsed from the input tokens. -// * `input`: the raw input tokens, as provided by the macro caller. +// * `crate_name`: an identifier that resolves to the name of the calling crate. +// * `in_args`: zero or more punctuated expressions passed as arguments by the caller. pub fn quote_console_func( ConsoleFunc { name, @@ -26,9 +27,9 @@ pub fn quote_console_func( is_variadic, }: ConsoleFunc, mut arg_modes: impl Iterator, - input: TokenStream, + crate_name: Ident, + in_args: Punctuated, ) -> TokenStream { - let InArgs(crate_name, in_args) = parse_macro_input!(input as InArgs); let mut out_args = in_args .iter() .map(|arg| quote_arg(&crate_name, arg, arg_modes.next().unwrap_or_default())); @@ -67,7 +68,7 @@ pub fn quote_console_func( (quote! { #crate_name::web_sys::console::#ident(#args) }).into() } -fn quote_arg(crate_name: &TokenStream2, arg: &Expr, arg_mode: ArgMode) -> TokenStream2 { +fn quote_arg(crate_name: &Ident, arg: &Expr, arg_mode: ArgMode) -> TokenStream2 { match arg_mode { ArgMode::PassThrough => { quote! { #arg } @@ -119,10 +120,12 @@ impl Default for ArgMode { } } -// InArgs is a struct required during parsing of input arguments. -struct InArgs(TokenStream2, Punctuated); +pub struct InputTokens { + pub crate_name: Ident, + pub args: Punctuated, +} -impl Parse for InArgs { +impl Parse for InputTokens { fn parse(input: ParseStream) -> Result { input.parse::()?; input.parse::()?; @@ -132,9 +135,9 @@ impl Parse for InArgs { bracketed.parse::()?; bracketed.parse::()?; - let crate_name = bracketed.parse()?; + let crate_name = bracketed.parse::()?; let args: Punctuated = Punctuated::parse_terminated(&input)?; - Ok(Self(crate_name, args)) + Ok(Self { crate_name, args }) } }