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#[cfg(feature = "doc")]
52#[proc_macro]
53pub fn cformatdoc(input: TokenStream) -> TokenStream {
54 get_macro_doc("format", input, false)
55}
56
57#[cfg(feature = "doc")]
59#[proc_macro]
60pub fn cwritedoc(input: TokenStream) -> TokenStream {
61 get_macro_doc("write", input, true)
62}
63
64#[cfg(feature = "doc")]
66#[proc_macro]
67pub fn cwritelndoc(input: TokenStream) -> TokenStream {
68 get_macro_doc("writeln", input, true)
69}
70
71#[proc_macro]
83pub fn cstr(input: TokenStream) -> TokenStream {
84 crate::ansi::get_cstr(input)
85 .unwrap_or_else(|err| err.to_token_stream())
86 .into()
87}
88
89#[proc_macro]
101pub fn untagged(input: TokenStream) -> TokenStream {
102 crate::untagged::get_untagged(input)
103 .unwrap_or_else(|err| err.to_token_stream())
104 .into()
105}
106
107struct WriteInput {
108 dst: Expr,
109 rest: TokenStream,
110}
111
112impl Parse for WriteInput {
113 fn parse(input: ParseStream) -> syn::parse::Result<Self> {
114 let dst: Expr = input.parse()?;
115 let _: Comma = input.parse()?;
116 let rest = input.parse::<TokenStream2>()?.into();
119 Ok(Self { dst, rest })
120 }
121}
122
123fn get_macro(macro_name: &str, input: TokenStream, is_write_macro: bool) -> TokenStream {
125 get_macro_impl(
126 macro_name,
127 input,
128 is_write_macro,
129 crate::ansi::get_format_args,
130 )
131}
132
133#[cfg(feature = "doc")]
135fn get_macro_doc(macro_name: &str, input: TokenStream, is_write_macro: bool) -> TokenStream {
136 get_macro_impl(
137 macro_name,
138 input,
139 is_write_macro,
140 crate::ansi::get_format_args_doc,
141 )
142}
143
144fn get_macro_impl(
145 macro_name: &str,
146 input: TokenStream,
147 is_write_macro: bool,
148 get_format_args: fn(TokenStream) -> Result<TokenStream2, crate::error::SpanError>,
149) -> TokenStream {
150 let macro_name = util::ident(macro_name);
151 let fmt_args =
152 |input_tail| get_format_args(input_tail).unwrap_or_else(|err| err.to_token_stream());
153
154 if is_write_macro {
155 let WriteInput { dst, rest } = parse_macro_input!(input);
156 let format_args = fmt_args(rest);
157 (quote! { #macro_name!(#dst, #format_args) }).into()
158 } else {
159 let format_args = fmt_args(input);
160 (quote! { #macro_name!(#format_args) }).into()
161 }
162}