1extern crate proc_macro;
6
7#[macro_use]
8mod util;
9mod ansi;
10mod ansi_constants;
11mod color_context;
12mod error;
13mod format_args;
14mod parse;
15mod untagged;
16
17use proc_macro::TokenStream;
18use proc_macro2::TokenStream as TokenStream2;
19use quote::{ToTokens, quote};
20use syn::parse::{Parse, ParseStream};
21use syn::token::Comma;
22use syn::{Expr, parse_macro_input};
23
24#[proc_macro]
34pub fn cformat(input: TokenStream) -> TokenStream {
35 get_macro("format", input, false)
36}
37
38#[proc_macro]
40pub fn cwrite(input: TokenStream) -> TokenStream {
41 get_macro("write", input, true)
42}
43
44#[proc_macro]
46pub fn cwriteln(input: TokenStream) -> TokenStream {
47 get_macro("writeln", input, true)
48}
49
50#[proc_macro]
62pub fn cstr(input: TokenStream) -> TokenStream {
63 crate::ansi::get_cstr(input)
64 .unwrap_or_else(|err| err.to_token_stream())
65 .into()
66}
67
68#[proc_macro]
80pub fn untagged(input: TokenStream) -> TokenStream {
81 crate::untagged::get_untagged(input)
82 .unwrap_or_else(|err| err.to_token_stream())
83 .into()
84}
85
86struct WriteInput {
87 dst: Expr,
88 rest: TokenStream,
89}
90
91impl Parse for WriteInput {
92 fn parse(input: ParseStream) -> syn::parse::Result<Self> {
93 let dst: Expr = input.parse()?;
94 let _: Comma = input.parse()?;
95 let rest = input.parse::<TokenStream2>()?.into();
98 Ok(Self { dst, rest })
99 }
100}
101
102fn get_macro(macro_name: &str, input: TokenStream, is_write_macro: bool) -> TokenStream {
104 let macro_name = util::ident(macro_name);
105 let fmt_args = |input_tail| {
106 crate::ansi::get_format_args(input_tail).unwrap_or_else(|err| err.to_token_stream())
107 };
108
109 if is_write_macro {
110 let WriteInput { dst, rest } = parse_macro_input!(input);
111 let format_args = fmt_args(rest);
112 (quote! { #macro_name!(#dst, #format_args) }).into()
113 } else {
114 let format_args = fmt_args(input);
115 (quote! { #macro_name!(#format_args) }).into()
116 }
117}