diff --git a/crates/pmp-emitter/crates/pmp-emitter-core/Cargo.toml b/crates/pmp-emitter/crates/pmp-emitter-core/Cargo.toml index 9fe2e0c..1d6a584 100644 --- a/crates/pmp-emitter/crates/pmp-emitter-core/Cargo.toml +++ b/crates/pmp-emitter/crates/pmp-emitter-core/Cargo.toml @@ -10,7 +10,6 @@ license-file.workspace = true proc-macro = true [dependencies] - syn = { version = "^2", features = ["full"] } quote = "^1" darling = "^0" diff --git a/crates/pmp-macro/crates/pmp-macro-misc/src/lib.rs b/crates/pmp-macro/crates/pmp-macro-misc/src/lib.rs index 0a3cca8..a6f9f6a 100644 --- a/crates/pmp-macro/crates/pmp-macro-misc/src/lib.rs +++ b/crates/pmp-macro/crates/pmp-macro-misc/src/lib.rs @@ -7,7 +7,7 @@ //! | `target` | [`Target`] bitflags for PHP attribute target sites | //! | `descriptor` | [`MacroDescriptor`] and [`ParamDescriptor`] - static metadata | //! | `context` | [`MacroContext`], [`AttributedNode`], [`ResolvedAttr`], etc. | -//! | `traits` | [`PmpMacro`] trait, [`MacroRegistration`], [`validate_registry`]| +//! | `traits` | [`PmpMacro`] trait, [`MacroRegistration`], [`MacroRegistry`] | mod target; mod traits; diff --git a/crates/pmp-macro/crates/pmp-macro-misc/src/traits.rs b/crates/pmp-macro/crates/pmp-macro-misc/src/traits.rs index 437a6e4..b0085d7 100644 --- a/crates/pmp-macro/crates/pmp-macro-misc/src/traits.rs +++ b/crates/pmp-macro/crates/pmp-macro-misc/src/traits.rs @@ -10,24 +10,16 @@ use crate::{ // --------------------------------------------------------------------------------------------- // -/// The core trait every PHP macro attribute handler must implement. +/// The handler trait implemented by each PHP macro attribute struct. /// -/// The `descriptor` method is generated by `#[derive(PmpMacro)]` and should -/// not be written by hand. The two handler methods have default no-op +/// The two handler methods have default no-op /// implementations so that analysis-only and transform-only macros only need /// to override what they actually do. /// -/// The trait is object-safe (`&self`, no generics) so the registry can store +/// The trait is object-safe (`&self`, no generics), so the registry can store /// `Box` without knowing concrete types. -pub trait PmpMacro: Send + Sync { - // --- generated by #[derive(PmpMacro)] --------------------------------------------------- // - - /// Returns the static metadata for this macro. - /// Must not be implemented by hand - use `#[derive(PmpMacro)]`. - fn descriptor(&self) -> &'static MacroDescriptor; - - // --- user-implemented handler hooks ----------------------------------------------------- // - +pub trait PmpMacro: Send + Sync +{ /// Analyse the attributed PHP node and emit diagnostics. /// /// Called during the analysis pass. Returning an empty `Vec` means no @@ -38,9 +30,7 @@ pub trait PmpMacro: Send + Sync { ctx: &MacroContext, attr: &ResolvedAttr, node: &AttributedNode, - ) -> Vec { - vec![] - } + ) -> Vec { vec![] } /// Produce rewrite instructions for the attributed PHP node. /// @@ -52,25 +42,40 @@ pub trait PmpMacro: Send + Sync { ctx: &MacroContext, attr: &ResolvedAttr, node: &AttributedNode, - ) -> Vec { - vec![] - } + ) -> Vec { vec![] } } // --------------------------------------------------------------------------------------------- // +/// Type alias for the analyze handler function pointer. +pub type AnalyzeFn = fn(&MacroContext, &ResolvedAttr, &AttributedNode) -> Vec; +/// Type alias for the transform handler function pointer. +pub type TransformFn = fn(&MacroContext, &ResolvedAttr, &AttributedNode) -> Vec; + /// An entry in the global macro registry, submitted via `inventory::submit!`. /// -/// Wraps a `&'static dyn PmpMacro` so the inventory iterator can hand out -/// references to every registered handler without allocation. +/// Stores static metadata alongside fn pointers that delegate to the +/// handler struct's `PmpMacro` impl, avoiding the need for `dyn` dispatch. +/// +/// Generated via `#[derive(PmpMacro)]` pub struct MacroRegistration { - pub handler: &'static dyn PmpMacro, + /// Static metadata for this macro — attribute name, targets, params, docs. + pub descriptor: &'static MacroDescriptor, + /// Delegates to `::analyze`. + pub analyze: AnalyzeFn, + /// Delegates to `::transform`. + pub transform: TransformFn, } impl MacroRegistration { - pub const fn new(handler: &'static dyn PmpMacro) -> Self { - Self { handler } + pub const fn new( + descriptor: &'static MacroDescriptor, + analyze: AnalyzeFn, + transform: TransformFn, + ) -> Self + { + Self { descriptor, analyze, transform } } } @@ -79,11 +84,10 @@ inventory::collect!(MacroRegistration); // --------------------------------------------------------------------------------------------- // /// Validated, deduplicated view of the global macro registry. -/// -/// Built once on first access and then cached for the lifetime of the process. +/// Built once on first access via [`registry()`] and cached for the process lifetime. pub struct MacroRegistry { /// Handlers keyed by attribute name for O(1) lookup during processing. - handlers: HashMap<&'static str, &'static dyn PmpMacro>, + handlers: HashMap<&'static str, &'static MacroRegistration>, } static REGISTRY: OnceLock = OnceLock::new(); @@ -104,14 +108,13 @@ impl MacroRegistry fn build() -> Self { - let mut handlers: HashMap<&'static str, &'static dyn PmpMacro> = HashMap::new(); + let mut handlers: HashMap<&'static str, &'static MacroRegistration> = HashMap::new(); for reg in inventory::iter:: { - let name = reg.handler.descriptor().name; + let name = reg.descriptor.name; - if handlers.insert(name, reg.handler).is_some() - { + if handlers.insert(name, reg).is_some() { panic!( "duplicate PmpMacro registration: attribute name \"{name}\" is \ registered more than once - check your macro definitions" @@ -122,13 +125,13 @@ impl MacroRegistry Self { handlers } } - /// Look up a registered macro handler by its PHP attribute name. - pub fn get(&self, name: &str) -> Option<&'static dyn PmpMacro> { + /// Look up a registered macro by its PHP attribute name. + pub fn get(&self, name: &str) -> Option<&'static MacroRegistration> { self.handlers.get(name).copied() } - /// Iterate over all registered handlers. - pub fn iter(&self) -> impl Iterator { + /// Iterate over all registered macros. + pub fn iter(&self) -> impl Iterator { self.handlers.values().copied() }