#![doc=include_str!("README.md")] // // This is the actual proc-macro crate. // // All it exports (or can export) are the proc macros themselves. // Everything else that is `pub` could be written `pub(crate)`. mod prelude; pub(crate) use prelude::*; // Implementation - common parts #[macro_use] pub(crate) mod utils; pub(crate) mod framework; // modules containing the actual implementations of our proc-macros pub(crate) mod capture; pub(crate) mod definition; pub(crate) mod invocation; // Implementation - specific areas pub(crate) mod boolean; pub(crate) mod dbg_allkw; pub(crate) mod expand; pub(crate) mod options; pub(crate) mod paste; pub(crate) mod repeat; pub(crate) mod syntax; pub(crate) mod compat_syn_2; pub(crate) mod compat_syn_common; #[doc=include_str!("HACKING.md")] mod _doc_hacking {} #[doc=include_str!("NOTES.md")] mod _doc_notes {} /// Dummy of proc_macro for use when compiling outside of proc macro context #[cfg(not(proc_macro))] pub(crate) mod proc_macro { pub(crate) use proc_macro2::TokenStream; } //========== `expect`, the `check` module (or dummy version) ========== // "expect" feature; module named check.rs for tab completion reasons #[cfg(feature = "expect")] mod check; #[cfg(not(feature = "expect"))] mod check { use super::prelude::*; #[derive(Debug, Clone, Copy, PartialEq)] pub struct Target(Void); impl FromStr for Target { type Err = Void; fn from_str(_: &str) -> Result { panic!("output syntax checking not supported, enable `expect` feature of `derive-adhoc`") } } pub fn check_expected_target_syntax( _ctx: &framework::Context, _output: &mut TokenStream, target: DaOptVal, ) { void::unreachable(target.value.0) } } impl DaOptValDescribable for check::Target { const DESCRIPTION: &'static str = "expected output syntax (`expect` option)"; } //========== actual macro entrypoints ========== /// Template expansion engine, internal /// /// Normally you do not need to mention this macro. /// /// derive-adhoc does its work by /// (defining and then) invoking various interrelated macros /// including `macro_rules` macros and proc macros. /// These ultimately end up calling this macro, /// which takes a template and a data structure, /// and expands the template for that data structure. /// /// This macro's behvaiour is not currently stable or documented. /// If you invoke it yourself, you get to keep all the pieces. #[cfg_attr(proc_macro, proc_macro)] pub fn derive_adhoc_expand( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let input: proc_macro2::TokenStream = input.into(); let output = expand::derive_adhoc_expand_func_macro(input) .unwrap_or_else(|e| e.into_compile_error()); output.into() } /// Expand an ad-hoc template, on a data structure decorated `#[derive(Adhoc)]` /// /// ```ignore /// # use derive_adhoc_macros::{Adhoc, derive_adhoc, derive_adhoc_expand}; /// # #[derive(Adhoc)] struct DataStructureType; /// # fn main() { /// # const TEMPLATE: () = (); /// derive_adhoc! { /// DataStructureType OPTIONS,..: /// TEMPLATE /// } /// # ; /// # } /// ``` /// /// Expands the template `TEMPLATE` for the type `DataStructureType`, /// /// `OPTIONS,..` is an optional comma-separated list of /// [expansion options](doc_reference/index.html#expansion-options). /// /// The definition of `DataStructureType` must have been decorated /// with [`#[derive(Adhoc)]`](crate::Adhoc), /// and the resulting `derive_adhoc_driver_TYPE` macro must be /// available in scope. #[cfg_attr(proc_macro, proc_macro)] pub fn derive_adhoc( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let input = TokenStream::from(input); let output = invocation::derive_adhoc_func_macro(input) .unwrap_or_else(|e| e.into_compile_error()); output.into() } /// Define a reuseable template /// /// ```text /// define_derive_adhoc! { /// [/// DOCS] /// [pub] MyMacro OPTIONS,.. = /// TEMPLATE /// } /// ``` /// /// Then, `MyMacro` can be used with /// [`#[derive(Adhoc)]`](crate::Adhoc) /// `#[derive_adhoc(MyMacro)]`. /// /// `OPTIONS,..` /// is an optional comma-separated list of /// [expansion options](doc_reference/index.html#expansion-options), /// which will be applied whenever this template is expanded. /// /// `DOCS`, /// if supplied, are used as the rustdocs /// for the captured template macro `derive_adhoc_template_MyMacro`. /// derive-adhoc will then also append a note about /// how to invoke the template. /// /// ## Template definition macro `derive_adhoc_template_MyMacro` /// /// The template is made into a `macro_rules` macro /// named `derive_adhoc_template_MyMacro`, /// which is referenced when the template is applied. /// /// The template definition macro /// from `define_derive_adhoc!` /// must be in scope at the point where you try to use it /// (with `#[derive(Adhoc)] #[derive_adhoc(MyMacro)]`). /// See the /// [documentation for `#[derive(Adhoc)]`](derive.Adhoc.html#scoping-and-ordering-within-the-same-crate). /// /// ## Exporting a template for use by other crates /// /// With `pub MyMacro`, `define_derive_adhoc!` exports the template /// for use by other crates. /// Then, it is referred to in other crates /// with `#[derive_ahdoc(this_crate::MyMacro)]`. /// /// I.e., `pub MyMacro` causes the `derive_adhoc_template_MyMacro` /// pattern macro to be exported with `#[macro_export]`. /// /// Note that a template is always exported at the crate top level, /// not in a sub-module, /// even if it is *defined* in a sub-module. /// /// ### You must re-export `derive_adhoc`; (usually no) semver implications /// /// When exporting a template to other crates, you must also /// re-export `derive_adhoc`, /// at the top level of your crate: /// /// ```ignore /// #[doc(hidden)] /// pub use derive_adhoc; /// ``` /// This is used to find the template expansion engine, /// and will arrange that your template is expanded /// by the right version of derive-adhoc. /// The template syntax is that for *your* version of `derive-adhoc`, /// even if the depending crate uses a different version of derive-adhoc. /// /// You should *not* treat a breaking change /// to derive-adhoc's template syntax /// (which is a major change to derive-adhoc), /// nor a requirement to use a newer template feature, /// as a breaking changes in the API of your crate. /// (You *should* use `#[doc(hidden)]`, or other approaches, /// to discourage downstream crates from using /// the derive-adhoc version you re-export. /// Such use would be outside the semver guarantees.) /// /// Changes that would require a semver bump /// for all libraries that export templates, /// will be rare, and specially marked in the derive-adhoc /// changelog. /// /// ## Namespacing within a template /// /// Within the template, /// items within your crate can be referred to with `$crate`. /// /// For other items, /// including from the standard library e.g., `std::option::Option`, /// you may rely on the context which uses the template /// to have a reasonable namespace, /// or use a explicit paths starting with `std` or `core` /// or `$crate` (perhaps naming a re-export). /// /// Overall, the situation is similar to defining /// an exported `macro_rules` macro. #[cfg_attr(proc_macro, proc_macro)] pub fn define_derive_adhoc( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let input = TokenStream::from(input); let output = definition::define_derive_adhoc_func_macro(input) .unwrap_or_else(|e| e.into_compile_error()); output.into() } /// Perform ad-hoc templating driven by a data structure /// /// This macro does two things: /// /// 1. It captures the data structure definition, /// so that it can be used with calls to /// [`derive_adhoc!`](macro@crate::derive_adhoc). /// /// 2. If `#[derive_adhoc(MyMacro)]` attributes are also specified, /// they are taken to refer to reuseable templates /// defined with /// [`define_derive_adhoc!`](macro@crate::define_derive_adhoc). /// Each such `MyMacro` is applied to the data structure. /// /// You can specify /// [expansion options](doc_reference/index.html#expansion-options) /// for each such template application, by writing /// `#[derive_adhoc(MyMacro[OPTIONS,..])]`, where /// `[OPTIONS,..]` is a comma-separated list of expansion options /// contained within `[ ]`. /// /// ## `#[adhoc]` attribute /// /// The contents of `#[adhoc]` attributes are made available /// to templates via the /// [`${Xmeta}`](doc_reference/index.html#tmeta-vmeta-fmeta--adhoc-attributes) /// expansions. /// /// If the template(s) don't use them, they are ignored. /// `derive-adhoc` does not impose any namespacing within `#[adhoc]`: /// all templates see the same adhoc meta attributes. /// /// ## Captured data structure definition `derive_adhoc_driver_TYPE` /// /// The data structure is captured by defining /// a `macro_rules` macro called `derive_adhoc_driver_TYPE`, /// where `TYPE` is the name of the type /// that `#[derive(Adhoc)]` is applied to. /// /// ## Scoping and ordering within the same crate /// /// **Summary of required ordering** /// /// 1. `define_derive_adhoc! { MyMacro = ... }` /// 2. `#[derive(Adhoc)] #[derive_adhoc(MyMacro)] struct MyStruct { ... }` /// 3. `derive_adhoc! { MyStruct: ... }` /// /// Any reusable templates defined with /// `define_derive_adhoc!` must lexically their precede /// uses with `#[derive(Adhoc) #[derive_adhoc(...)]`. /// /// And, for one-off templates (`derive_adhoc!`), /// the data structure with its `#[derive(Adhoc)]` /// must lexically precede /// the references in `derive_adhoc!`, /// so that the data structure definition macro /// is in scope. /// /// In each case, /// if the definition is in another module /// in the same crate, /// the defining module's `mod` statement must come before /// the reference, /// and /// the `mod` statement will need `#[macro_use]`. /// So the placement and order of `mod` statements can matter. /// /// ## Applying a template (derive-adhoc macro) from another crate /// /// `#[derive_adhoc(some_crate::MyMacro)]` /// applies an exported (`pub`) template /// defined and exported by `some_crate`. /// /// You can import a template from another crate, /// so you can apply it with an unqualified name, /// with `use`, /// but the `use` must refer to /// the actual pattern macro name `derive_adhoc_template_MyMacro`: /// ```ignore /// use other_crate::derive_adhoc_template_TheirMacro; /// #[derive(Adhoc)] /// #[derive_Adhoc(TheirMacro)] /// struct MyStruct { // ... /// # } /// ``` /// /// ## Exporting the driver for downstream crates' templates /// // Really, the documentation about this in `pub-a.rs` and `pub-b.rs`, // should be somewhere in our rustdoc output. // But I don't want to put it *here* because it would completely // dominate this macro documentation. // So for now just reference the source tree docs. // (We can't really easily provide even a link.) // I think this is such a minority feature, // that hiding the docs like this is OK. // /// To cause the macro embodying the driver struct to be exported, /// write: /// `#[derive_adhoc(pub)]`. /// The driver can then be derived from in other crates, /// with `derive_adhoc! { exporting_crate::DriverStruct: ... }`. /// /// This is a tricky feature, /// which should only be used by experts /// who fully understand the implications. /// It effectively turns the body of the struct into a macro, /// with a brittle API /// and very limited support for namespacing or hygiene. /// /// See `pub mod a_driver` in the example file `pub-a.rs`, /// in the source tree, /// for a fuller discussion of the implications, /// and some advice. /// /// If you do this, you must **pin your derive-adhoc** to a minor version, /// as you may need to treat *minor* version updates in derive-adhoc /// as semver breaks for your crate. // // This is the implementation of #[derive(Adhoc)] // // It should parse the struct name out of its input. // // The expansion should be // macro_rules! derive_adhoc_driver_ChannelsParams ... // as per NOTES.txt // // For the MVP it does not need to have any attributes, but // later it will want to be // #[proc_macro_derive(Adhoc, attributes(adhoc))] // and then it will perhaps want to do *something* with the attributes? // Although maybe just ignoring them and letting them get to the expander // is right. #[cfg_attr( proc_macro, proc_macro_derive(Adhoc, attributes(adhoc, derive_adhoc)) )] pub fn derive_adhoc_derive_macro( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let input = TokenStream::from(input); let output = capture::derive_adhoc_derive_macro(input) .unwrap_or_else(|e| e.into_compile_error()); output.into() }