extern crate proc_macro;
#[macro_use]
mod util;
mod ansi;
mod ansi_constants;
mod color_context;
mod error;
mod format_args;
mod parse;
mod untagged;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::{ToTokens, quote};
use syn::parse::{Parse, ParseStream};
use syn::token::Comma;
use syn::{Expr, parse_macro_input};
#[proc_macro]
pub fn cformat(input: TokenStream) -> TokenStream {
get_macro("format", input, false)
}
#[proc_macro]
pub fn cwrite(input: TokenStream) -> TokenStream {
get_macro("write", input, true)
}
#[proc_macro]
pub fn cwriteln(input: TokenStream) -> TokenStream {
get_macro("writeln", input, true)
}
#[cfg(feature = "doc")]
#[proc_macro]
pub fn cformatdoc(input: TokenStream) -> TokenStream {
get_macro_doc("format", input, false)
}
#[cfg(feature = "doc")]
#[proc_macro]
pub fn cwritedoc(input: TokenStream) -> TokenStream {
get_macro_doc("write", input, true)
}
#[cfg(feature = "doc")]
#[proc_macro]
pub fn cwritelndoc(input: TokenStream) -> TokenStream {
get_macro_doc("writeln", input, true)
}
#[proc_macro]
pub fn cstr(input: TokenStream) -> TokenStream {
crate::ansi::get_cstr(input)
.unwrap_or_else(|err| err.to_token_stream())
.into()
}
#[proc_macro]
pub fn untagged(input: TokenStream) -> TokenStream {
crate::untagged::get_untagged(input)
.unwrap_or_else(|err| err.to_token_stream())
.into()
}
struct WriteInput {
dst: Expr,
rest: TokenStream,
}
impl Parse for WriteInput {
fn parse(input: ParseStream) -> syn::parse::Result<Self> {
let dst: Expr = input.parse()?;
let _: Comma = input.parse()?;
let rest = input.parse::<TokenStream2>()?.into();
Ok(Self { dst, rest })
}
}
fn get_macro(macro_name: &str, input: TokenStream, is_write_macro: bool) -> TokenStream {
get_macro_impl(
macro_name,
input,
is_write_macro,
crate::ansi::get_format_args,
)
}
#[cfg(feature = "doc")]
fn get_macro_doc(macro_name: &str, input: TokenStream, is_write_macro: bool) -> TokenStream {
get_macro_impl(
macro_name,
input,
is_write_macro,
crate::ansi::get_format_args_doc,
)
}
fn get_macro_impl(
macro_name: &str,
input: TokenStream,
is_write_macro: bool,
get_format_args: fn(TokenStream) -> Result<TokenStream2, crate::error::SpanError>,
) -> TokenStream {
let macro_name = util::ident(macro_name);
let fmt_args =
|input_tail| get_format_args(input_tail).unwrap_or_else(|err| err.to_token_stream());
if is_write_macro {
let WriteInput { dst, rest } = parse_macro_input!(input);
let format_args = fmt_args(rest);
(quote! { #macro_name!(#dst, #format_args) }).into()
} else {
let format_args = fmt_args(input);
(quote! { #macro_name!(#format_args) }).into()
}
}