cpreprocess/
lib.rs

1//! Stupid and cursed Rust procedural macro that runs a C preprocessor on the input
2//!
3//! # Example
4//!
5//! ```no_run
6//! cpreprocess::cpreprocess!(r#"
7//!     #define MACRO(NAME) fn print_ ## NAME () { println!("hello world"); }
8//!
9//!     MACRO(hello_world)
10//!
11//!     print_hello_world()
12//! "#);
13//! ```
14
15mod cpp;
16
17use proc_macro::TokenStream;
18
19#[proc_macro]
20/// Stupid and cursed Rust procedural macro that runs a C preprocessor on the input
21///
22/// # Example
23///
24/// ```no_run
25/// cpreprocess::cpreprocess!(r#"
26///     #define MACRO(NAME) fn print_ ## NAME () { println!("hello world"); }
27///
28///     MACRO(hello_world)
29///
30///     print_hello_world()
31/// "#);
32/// ```
33pub fn cpreprocess(tokens: TokenStream) -> TokenStream {
34	#[cfg(not(feature = "nightly"))]
35	let tokens = syn::parse_macro_input!(tokens as syn::LitStr).value();
36
37	#[cfg(feature = "nightly")]
38	let tokens = match syn::parse::<syn::LitStr>(tokens.clone()) {
39		Ok(tokens) => tokens.value(),
40		Err(_) => proc_macro_faithful_display::faithful_display(&tokens).to_string()
41	};
42
43	match cpp::preprocess(tokens.as_bytes())
44		.map(|result| {
45			result.and_then(|code| {
46				String::from_utf8_lossy(&code).parse().map_err(Into::into)
47			})
48		})
49	{
50		Some(Ok(code)) => code,
51		Some(Err(err)) => format!("compile_error!(\"{}\")", err.to_string().replace('\\', "\\\\").replace('"', "\\\"")).parse().unwrap(),
52		None => "compile_error!(\"Couldn't find a compatible C compiler on this system\")".parse().unwrap()
53	}
54}