From 2ba09dd68d73d624af75be4880df36ce82efe2bc Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Thu, 13 Apr 2023 22:13:40 +0200 Subject: [PATCH] rtic-macros: wrap everything in macro_rules! to improve the error experience and royally **** up the DX experience (for lib.rs in rtic-macros, at least :P) --- rtic-macros/src/codegen/bindings.rs | 7 -- rtic-macros/src/lib.rs | 149 ++++++++++++++++------------ 2 files changed, 86 insertions(+), 70 deletions(-) diff --git a/rtic-macros/src/codegen/bindings.rs b/rtic-macros/src/codegen/bindings.rs index 6c214cdb1f..c328ee0be8 100644 --- a/rtic-macros/src/codegen/bindings.rs +++ b/rtic-macros/src/codegen/bindings.rs @@ -1,10 +1,3 @@ -#[cfg(not(any( - feature = "cortex-m-source-masking", - feature = "cortex-m-basepri", - feature = "test-template" -)))] -compile_error!("No backend selected"); - #[cfg(any(feature = "cortex-m-source-masking", feature = "cortex-m-basepri"))] pub use cortex::*; diff --git a/rtic-macros/src/lib.rs b/rtic-macros/src/lib.rs index cd2a9245db..3a655977d6 100644 --- a/rtic-macros/src/lib.rs +++ b/rtic-macros/src/lib.rs @@ -4,87 +4,110 @@ )] //deny_warnings_placeholder_for_ci -use proc_macro::TokenStream; -use std::{env, fs, path::Path}; +macro_rules! with_backend { + (mod: [$($mod:tt),*]) => { + $( + with_backend!{ mod $mod; } + )* + }; + ($($tokens:tt)*) => { + #[cfg(any( + feature = "cortex-m-source-masking", + feature = "cortex-m-basepri", + feature = "test-template" + ))] + $($tokens)* + }; +} -mod analyze; -mod check; -mod codegen; -mod syntax; +with_backend! { mod: [analyze, check, codegen, syntax] } +with_backend! { use std::{fs, env, path::Path}; } +with_backend! { use proc_macro::TokenStream; } -// Used for mocking the API in testing -#[doc(hidden)] -#[proc_macro_attribute] -pub fn mock_app(args: TokenStream, input: TokenStream) -> TokenStream { - if let Err(e) = syntax::parse(args, input) { - e.to_compile_error().into() - } else { - "fn main() {}".parse().unwrap() +with_backend! { + // Used for mocking the API in testing + #[doc(hidden)] + #[proc_macro_attribute] + pub fn mock_app(args: TokenStream, input: TokenStream) -> TokenStream { + if let Err(e) = syntax::parse(args, input) { + e.to_compile_error().into() + } else { + "fn main() {}".parse().unwrap() + } } } -/// Attribute used to declare a RTIC application -/// -/// For user documentation see the [RTIC book](https://rtic.rs) -/// -/// # Panics -/// -/// Should never panic, cargo feeds a path which is later converted to a string -#[proc_macro_attribute] -pub fn app(args: TokenStream, input: TokenStream) -> TokenStream { - let (app, analysis) = match syntax::parse(args, input) { - Err(e) => return e.to_compile_error().into(), - Ok(x) => x, - }; +with_backend! { + /// Attribute used to declare a RTIC application + /// + /// For user documentation see the [RTIC book](https://rtic.rs) + /// + /// # Panics + /// + /// Should never panic, cargo feeds a path which is later converted to a string + #[proc_macro_attribute] + pub fn app(_args: TokenStream, _input: TokenStream) -> TokenStream { + let (app, analysis) = match syntax::parse(_args, _input) { + Err(e) => return e.to_compile_error().into(), + Ok(x) => x, + }; - if let Err(e) = check::app(&app, &analysis) { - return e.to_compile_error().into(); - } + if let Err(e) = check::app(&app, &analysis) { + return e.to_compile_error().into(); + } - let analysis = analyze::app(analysis, &app); + let analysis = analyze::app(analysis, &app); - let ts = codegen::app(&app, &analysis); + let ts = codegen::app(&app, &analysis); - // Default output path: /target/ - let mut out_dir = Path::new("target"); + // Default output path: /target/ + let mut out_dir = Path::new("target"); - // Get output directory from Cargo environment - // TODO don't want to break builds if OUT_DIR is not set, is this ever the case? - let out_str = env::var("OUT_DIR").unwrap_or_else(|_| "".to_string()); + // Get output directory from Cargo environment + // TODO don't want to break builds if OUT_DIR is not set, is this ever the case? + let out_str = env::var("OUT_DIR").unwrap_or_else(|_| "".to_string()); - if !out_dir.exists() { - // Set out_dir to OUT_DIR - out_dir = Path::new(&out_str); + if !out_dir.exists() { + // Set out_dir to OUT_DIR + out_dir = Path::new(&out_str); - // Default build path, annotated below: - // $(pwd)/target/thumbv7em-none-eabihf/debug/build/rtic-/out/ - // ///debug/build/rtic-/out/ - // - // traverse up to first occurrence of TARGET, approximated with starts_with("thumbv") - // and use the parent() of this path - // - // If no "target" directory is found, / is used - for path in out_dir.ancestors() { - if let Some(dir) = path.components().last() { - let dir = dir.as_os_str().to_str().unwrap(); + // Default build path, annotated below: + // $(pwd)/target/thumbv7em-none-eabihf/debug/build/rtic-/out/ + // ///debug/build/rtic-/out/ + // + // traverse up to first occurrence of TARGET, approximated with starts_with("thumbv") + // and use the parent() of this path + // + // If no "target" directory is found, / is used + for path in out_dir.ancestors() { + if let Some(dir) = path.components().last() { + let dir = dir.as_os_str().to_str().unwrap(); - if dir.starts_with("thumbv") || dir.starts_with("riscv") { - if let Some(out) = path.parent() { - out_dir = out; + if dir.starts_with("thumbv") || dir.starts_with("riscv") { + if let Some(out) = path.parent() { + out_dir = out; + break; + } + // If no parent, just use it + out_dir = path; break; } - // If no parent, just use it - out_dir = path; - break; } } } - } - // Try to write the expanded code to disk - if let Some(out_str) = out_dir.to_str() { - fs::write(format!("{out_str}/rtic-expansion.rs"), ts.to_string()).ok(); - } + // Try to write the expanded code to disk + if let Some(out_str) = out_dir.to_str() { + fs::write(format!("{out_str}/rtic-expansion.rs"), ts.to_string()).ok(); + } - ts.into() + ts.into() + } } + +#[cfg(not(any( + feature = "cortex-m-source-masking", + feature = "cortex-m-basepri", + feature = "test-template" +)))] +compile_error!("Cannot compile. No backend feature selected.");