From b4a0a77a59f93f47c97120bf77e97da45ea8cf97 Mon Sep 17 00:00:00 2001 From: Felix Date: Tue, 23 Jan 2024 15:08:11 +0000 Subject: [PATCH 1/5] add rule registry and sanity check --- Cargo.lock | 39 +++++++++++++++++++++++++++ Cargo.toml | 2 ++ conjure_oxide/Cargo.toml | 2 ++ conjure_oxide/src/lib.rs | 1 - conjure_oxide/src/main.rs | 6 ++--- conjure_oxide/src/rules/mod.rs | 11 -------- conjure_oxide/tests/rewrite_tests.rs | 6 +++++ crates/conjure_macros/Cargo.toml | 14 ++++++++++ crates/conjure_macros/src/lib.rs | 28 +++++++++++++++++++ crates/conjure_rules/Cargo.toml | 12 +++++++++ crates/conjure_rules/src/lib.rs | 13 +++++++++ crates/conjure_rules/src/rules/mod.rs | 8 ++++++ 12 files changed, 126 insertions(+), 16 deletions(-) delete mode 100644 conjure_oxide/src/rules/mod.rs create mode 100644 crates/conjure_macros/Cargo.toml create mode 100644 crates/conjure_macros/src/lib.rs create mode 100644 crates/conjure_rules/Cargo.toml create mode 100644 crates/conjure_rules/src/lib.rs create mode 100644 crates/conjure_rules/src/rules/mod.rs diff --git a/Cargo.lock b/Cargo.lock index b13643407..f76eb577e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,6 +270,14 @@ dependencies = [ "thiserror", ] +[[package]] +name = "conjure_macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn 2.0.48", +] + [[package]] name = "conjure_oxide" version = "0.0.1" @@ -277,6 +285,8 @@ dependencies = [ "anyhow", "clap", "conjure_core", + "conjure_rules", + "linkme", "minion_rs", "serde", "serde_json", @@ -288,6 +298,15 @@ dependencies = [ "walkdir", ] +[[package]] +name = "conjure_rules" +version = "0.1.0" +dependencies = [ + "conjure_core", + "conjure_macros", + "linkme", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -555,6 +574,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "linkme" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b53ad6a33de58864705954edb5ad5d571a010f9e296865ed43dc72a5621b430" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e542a18c94a9b6fcc7adb090fa3ba6b79ee220a16404f325672729f32a66ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "linux-raw-sys" version = "0.4.11" diff --git a/Cargo.toml b/Cargo.toml index 834320ce1..e59889883 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,8 @@ resolver = "2" members = [ "conjure_oxide", "crates/conjure_core", + "crates/conjure_macros", + "crates/conjure_rules", "solvers/kissat", "solvers/minion", "solvers/chuffed", diff --git a/conjure_oxide/Cargo.toml b/conjure_oxide/Cargo.toml index 7015b3012..70e6a2107 100644 --- a/conjure_oxide/Cargo.toml +++ b/conjure_oxide/Cargo.toml @@ -10,6 +10,7 @@ walkdir = "2.4.0" [dependencies] conjure_core = {path = "../crates/conjure_core" } +conjure_rules = {path = "../crates/conjure_rules" } serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" @@ -21,6 +22,7 @@ clap = { version = "4.4.16", features = ["derive"] } strum_macros = "0.25.3" strum = "0.25.0" versions = "6.1.0" +linkme = "0.3.22" [lints] workspace = true diff --git a/conjure_oxide/src/lib.rs b/conjure_oxide/src/lib.rs index e7f1a854a..c2c17a283 100644 --- a/conjure_oxide/src/lib.rs +++ b/conjure_oxide/src/lib.rs @@ -1,7 +1,6 @@ pub mod error; pub mod find_conjure; pub mod parse; -pub mod rules; mod solvers; pub use conjure_core::ast; // re-export core::ast as conjure_oxide::ast diff --git a/conjure_oxide/src/main.rs b/conjure_oxide/src/main.rs index 6452d82a9..0699ff379 100644 --- a/conjure_oxide/src/main.rs +++ b/conjure_oxide/src/main.rs @@ -19,6 +19,8 @@ struct Cli { } pub fn main() -> AnyhowResult<()> { + println!("Rules: {:?}", conjure_rules::get_rules()); + let cli = Cli::parse(); println!("Input file: {}", cli.input_file.display()); let input_file: &str = cli.input_file.to_str().ok_or(anyhow!( @@ -48,9 +50,5 @@ pub fn main() -> AnyhowResult<()> { let model = model_from_json(&astjson)?; println!("{:?}", model); - // for rule in get_rules_by_kind() { - // println!("Applying rule {:?}", rule); - // } - Ok(()) } diff --git a/conjure_oxide/src/rules/mod.rs b/conjure_oxide/src/rules/mod.rs deleted file mode 100644 index 3911c82ed..000000000 --- a/conjure_oxide/src/rules/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -use conjure_core::ast::Expression; -use conjure_core::rule::{Rule, RuleApplicationError}; - -fn identity(expr: &Expression) -> Result { - Ok(expr.clone()) -} - -pub static IDENTITY_RULE: Rule = Rule { - name: "identity", - application: identity, -}; diff --git a/conjure_oxide/tests/rewrite_tests.rs b/conjure_oxide/tests/rewrite_tests.rs index 13e4a6779..0061c6efe 100644 --- a/conjure_oxide/tests/rewrite_tests.rs +++ b/conjure_oxide/tests/rewrite_tests.rs @@ -4,6 +4,12 @@ use core::panic; use conjure_oxide::ast::*; +#[test] +fn rules_present() { + let rules = conjure_rules::get_rules(); + assert!(rules.len() > 0); +} + #[test] fn sum_of_constants() { let valid_sum_expression = Expression::Sum(vec![ diff --git a/crates/conjure_macros/Cargo.toml b/crates/conjure_macros/Cargo.toml new file mode 100644 index 000000000..f5d6fa13a --- /dev/null +++ b/crates/conjure_macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "conjure_macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc_macro = true + +[dependencies] +quote = "1.0.34" +syn = { version = "2.0.43", features = ["full"] } + +[lints] +workspace = true diff --git a/crates/conjure_macros/src/lib.rs b/crates/conjure_macros/src/lib.rs new file mode 100644 index 000000000..49567371c --- /dev/null +++ b/crates/conjure_macros/src/lib.rs @@ -0,0 +1,28 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Ident, ItemFn}; + +#[proc_macro_attribute] +/// This procedural macro registers a decorated function with Conjure's rule engine. +/// Functions must have the signature `fn(&Expr) -> Result`. +/// +/// Intermediary static variables are created to allow for the decentralized registry, with the prefix `CONJURE_GEN_`. +/// Please ensure that other variable names in the same scope do not conflict with these. +pub fn register_rule(_: TokenStream, item: TokenStream) -> TokenStream { + let func = parse_macro_input!(item as ItemFn); + let rule_ident = &func.sig.ident; + let static_name = format!("CONJURE_GEN_RULE_{}", rule_ident).to_uppercase(); + let static_ident = Ident::new(&static_name, rule_ident.span()); + + let expanded = quote! { + #func + + #[::linkme::distributed_slice(_RULES_DISTRIBUTED_SLICE)] + pub static #static_ident: ::conjure_core::rule::Rule = ::conjure_core::rule::Rule { + name: stringify!(#rule_ident), + application: #rule_ident, + }; + }; + + TokenStream::from(expanded) +} diff --git a/crates/conjure_rules/Cargo.toml b/crates/conjure_rules/Cargo.toml new file mode 100644 index 000000000..0a4f06d7c --- /dev/null +++ b/crates/conjure_rules/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "conjure_rules" +version = "0.1.0" +edition = "2021" + +[dependencies] +conjure_macros = { path = "../conjure_macros" } +conjure_core = { path = "../conjure_core" } +linkme = "0.3.22" + +[lints] +workspace = true diff --git a/crates/conjure_rules/src/lib.rs b/crates/conjure_rules/src/lib.rs new file mode 100644 index 000000000..49c9f8c7c --- /dev/null +++ b/crates/conjure_rules/src/lib.rs @@ -0,0 +1,13 @@ +use conjure_core::rule::Rule; +use linkme::distributed_slice; + +#[distributed_slice] +pub static _RULES_DISTRIBUTED_SLICE: [Rule<'static>]; + +pub fn get_rules() -> Vec> { + _RULES_DISTRIBUTED_SLICE.to_vec() +} + +mod rules; + +static _TEMP: &Rule = &rules::CONJURE_GEN_RULE_IDENTITY; // Temporary hack to force the static to be included in the binary diff --git a/crates/conjure_rules/src/rules/mod.rs b/crates/conjure_rules/src/rules/mod.rs new file mode 100644 index 000000000..27682650d --- /dev/null +++ b/crates/conjure_rules/src/rules/mod.rs @@ -0,0 +1,8 @@ +use crate::_RULES_DISTRIBUTED_SLICE; +use conjure_core::{ast::Expression, rule::RuleApplicationError}; +use conjure_macros::register_rule; + +#[register_rule] +fn identity(expr: &Expression) -> Result { + Ok(expr.clone()) +} From b9f77ea4a60ea087378da27b310ff46e1ab54ae1 Mon Sep 17 00:00:00 2001 From: Niklas Dewally Date: Tue, 23 Jan 2024 18:44:23 +0000 Subject: [PATCH 2/5] fix: replace the linkme hack with a slightly less bad one --- Cargo.toml | 6 ++++++ crates/conjure_rules/src/lib.rs | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e59889883..39f4190a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,9 @@ members = [ [workspace.lints.clippy] unwrap_used = "warn" expect_used = "warn" + +[profile.dev] +codegen-units = 1 + +[profile.release] +codegen-units = 1 diff --git a/crates/conjure_rules/src/lib.rs b/crates/conjure_rules/src/lib.rs index 49c9f8c7c..ff4cd7590 100644 --- a/crates/conjure_rules/src/lib.rs +++ b/crates/conjure_rules/src/lib.rs @@ -9,5 +9,3 @@ pub fn get_rules() -> Vec> { } mod rules; - -static _TEMP: &Rule = &rules::CONJURE_GEN_RULE_IDENTITY; // Temporary hack to force the static to be included in the binary From d30c2be3475945c3350c83dbf629ebe53da9581a Mon Sep 17 00:00:00 2001 From: Niklas Dewally Date: Tue, 23 Jan 2024 23:06:33 +0000 Subject: [PATCH 3/5] make rule macro safe to use everywhere, and move rules into conjure_oxide. This commit makes the rule macro safe to use in all crates, not just conjure_rules. This allows for completely decentralised definition of rules, without the user having to worrying about dependencies. Previously, the macro expansion made imports from external crates, which would break when used in crates that did not explicitly list said crates in their Cargo.toml. Some simple solutions to this are to limit use of the macro to a single crate, or to force users to add stuff to their Cargo.toml. These are both non-ideal: the former limits how "decentralised" rule definition could be; the latter is a leaky abstraction and would make updating this crate difficult for a user. See: - https://users.rust-lang.org/t/proc-macros-using-third-party-crate/42465/4 - https://doc.rust-lang.org/reference/procedural-macros.html#procedural-macro-hygiene Procedural macros and external crate imports ============================================== Procedural macros are unhygienic - they directly substitute into source code, and do not have their own scope, imports, and so on. Therefore, we cannot assume the user has any dependencies apart from the one they imported the macro from. (Also, note Rust does not bring transitive dependencies into scope, so we cannot assume the presence of a dependency of the crate.) To solve this, the crate the macro is in must re-export everything the macro needs to run. However, proc-macro crates can only export proc-macros. Therefore, we must use a "front end crate" to re-export both the macro and all the things it may need. Conjure_rules is the frontend crate, and re-exports the macro from conjure_rules_proc_macro. --- Cargo.lock | 19 +++++----- Cargo.toml | 2 +- conjure_oxide/src/lib.rs | 1 + .../src/rules/mod.rs | 3 +- crates/conjure_rules/Cargo.toml | 2 +- crates/conjure_rules/src/lib.rs | 35 +++++++++++++++++-- .../Cargo.toml | 3 +- .../src/lib.rs | 5 +-- 8 files changed, 51 insertions(+), 19 deletions(-) rename {crates/conjure_rules => conjure_oxide}/src/rules/mod.rs (71%) rename crates/{conjure_macros => conjure_rules_proc_macro}/Cargo.toml (70%) rename crates/{conjure_macros => conjure_rules_proc_macro}/src/lib.rs (81%) diff --git a/Cargo.lock b/Cargo.lock index 54cc87905..2bd606f88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,14 +270,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "conjure_macros" -version = "0.1.0" -dependencies = [ - "quote", - "syn 2.0.48", -] - [[package]] name = "conjure_oxide" version = "0.0.1" @@ -303,10 +295,19 @@ name = "conjure_rules" version = "0.1.0" dependencies = [ "conjure_core", - "conjure_macros", + "conjure_rules_proc_macro", "linkme", ] +[[package]] +name = "conjure_rules_proc_macro" +version = "0.1.0" +dependencies = [ + "conjure_core", + "quote", + "syn 2.0.48", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" diff --git a/Cargo.toml b/Cargo.toml index 39f4190a3..67bae205d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = [ "conjure_oxide", "crates/conjure_core", - "crates/conjure_macros", + "crates/conjure_rules_proc_macro", "crates/conjure_rules", "solvers/kissat", "solvers/minion", diff --git a/conjure_oxide/src/lib.rs b/conjure_oxide/src/lib.rs index c2c17a283..022ac9106 100644 --- a/conjure_oxide/src/lib.rs +++ b/conjure_oxide/src/lib.rs @@ -1,6 +1,7 @@ pub mod error; pub mod find_conjure; pub mod parse; +mod rules; mod solvers; pub use conjure_core::ast; // re-export core::ast as conjure_oxide::ast diff --git a/crates/conjure_rules/src/rules/mod.rs b/conjure_oxide/src/rules/mod.rs similarity index 71% rename from crates/conjure_rules/src/rules/mod.rs rename to conjure_oxide/src/rules/mod.rs index 27682650d..4d4702c64 100644 --- a/crates/conjure_rules/src/rules/mod.rs +++ b/conjure_oxide/src/rules/mod.rs @@ -1,6 +1,5 @@ -use crate::_RULES_DISTRIBUTED_SLICE; use conjure_core::{ast::Expression, rule::RuleApplicationError}; -use conjure_macros::register_rule; +use conjure_rules::register_rule; #[register_rule] fn identity(expr: &Expression) -> Result { diff --git a/crates/conjure_rules/Cargo.toml b/crates/conjure_rules/Cargo.toml index 0a4f06d7c..563888c59 100644 --- a/crates/conjure_rules/Cargo.toml +++ b/crates/conjure_rules/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -conjure_macros = { path = "../conjure_macros" } +conjure_rules_proc_macro = { path = "../conjure_rules_proc_macro" } conjure_core = { path = "../conjure_core" } linkme = "0.3.22" diff --git a/crates/conjure_rules/src/lib.rs b/crates/conjure_rules/src/lib.rs index ff4cd7590..26c8a85f4 100644 --- a/crates/conjure_rules/src/lib.rs +++ b/crates/conjure_rules/src/lib.rs @@ -1,11 +1,40 @@ +//! Rule registry for conjure_oxide. +//! TODO: doc comment. +//! + +// Why all the re-exports and wierdness? +// ============================ +// +// Procedural macros are unhygenic - they directly subsitute into source code, and do not have +// their own scope, imports, and so on. +// +// See [https://doc.rust-lang.org/reference/procedural-macros.html#procedural-macro-hygiene]. +// +// Therefore, we cannot assume the user has any dependencies apart from the one they imported the +// macro from. (Also, note Rust does not bring transitive dependencies into scope, so we cannot +// assume the presence of a dependency of the crate.) +// +// To solve this, the crate the macro is in must re-export everything the macro needs to run. +// +// However, proc-macro crates can only export proc-macros. Therefore, we must use a "front end +// crate" (i.e. this one) to re-export both the macro and all the things it may need. + use conjure_core::rule::Rule; use linkme::distributed_slice; +#[doc(hidden)] +pub mod _dependencies { + pub use conjure_core::rule::Rule; + pub use linkme::distributed_slice; +} + +#[doc(hidden)] #[distributed_slice] -pub static _RULES_DISTRIBUTED_SLICE: [Rule<'static>]; +pub static RULES_DISTRIBUTED_SLICE: [Rule<'static>]; pub fn get_rules() -> Vec> { - _RULES_DISTRIBUTED_SLICE.to_vec() + RULES_DISTRIBUTED_SLICE.to_vec() } -mod rules; +/// TODO: docs +pub use conjure_rules_proc_macro::register_rule; diff --git a/crates/conjure_macros/Cargo.toml b/crates/conjure_rules_proc_macro/Cargo.toml similarity index 70% rename from crates/conjure_macros/Cargo.toml rename to crates/conjure_rules_proc_macro/Cargo.toml index f5d6fa13a..a5661e5b8 100644 --- a/crates/conjure_macros/Cargo.toml +++ b/crates/conjure_rules_proc_macro/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "conjure_macros" +name = "conjure_rules_proc_macro" version = "0.1.0" edition = "2021" @@ -8,6 +8,7 @@ proc_macro = true [dependencies] quote = "1.0.34" +conjure_core = {path= "../conjure_core"} syn = { version = "2.0.43", features = ["full"] } [lints] diff --git a/crates/conjure_macros/src/lib.rs b/crates/conjure_rules_proc_macro/src/lib.rs similarity index 81% rename from crates/conjure_macros/src/lib.rs rename to crates/conjure_rules_proc_macro/src/lib.rs index 49567371c..bf89079eb 100644 --- a/crates/conjure_macros/src/lib.rs +++ b/crates/conjure_rules_proc_macro/src/lib.rs @@ -2,6 +2,7 @@ use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, Ident, ItemFn}; +#[doc(hidden)] #[proc_macro_attribute] /// This procedural macro registers a decorated function with Conjure's rule engine. /// Functions must have the signature `fn(&Expr) -> Result`. @@ -17,8 +18,8 @@ pub fn register_rule(_: TokenStream, item: TokenStream) -> TokenStream { let expanded = quote! { #func - #[::linkme::distributed_slice(_RULES_DISTRIBUTED_SLICE)] - pub static #static_ident: ::conjure_core::rule::Rule = ::conjure_core::rule::Rule { + #[::conjure_rules::_dependencies::distributed_slice(::conjure_rules::RULES_DISTRIBUTED_SLICE)] + pub static #static_ident: ::conjure_rules::_dependencies::Rule = ::conjure_rules::_dependencies::Rule { name: stringify!(#rule_ident), application: #rule_ident, }; From c1d7a9ff196f46e2976867204dfa98bb6142d1c6 Mon Sep 17 00:00:00 2001 From: Felix Date: Wed, 24 Jan 2024 23:26:47 +0000 Subject: [PATCH 4/5] add documentation to rule registry features --- crates/conjure_rules/src/lib.rs | 32 ++++++++++++++++-- crates/conjure_rules_proc_macro/src/lib.rs | 38 +++++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/crates/conjure_rules/src/lib.rs b/crates/conjure_rules/src/lib.rs index 26c8a85f4..d7e45fb95 100644 --- a/crates/conjure_rules/src/lib.rs +++ b/crates/conjure_rules/src/lib.rs @@ -1,5 +1,8 @@ -//! Rule registry for conjure_oxide. -//! TODO: doc comment. +//! ### A decentralised rule registry for Conjure Oxide +//! +//! This crate allows registering valid functions as expression-reduction rules. +//! Functions can be decorated with the `register_rule` macro in any downstream crate and be used by Conjure Oxide's rule engine. +//! To achieve compile-time linking, we make use of the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate. //! // Why all the re-exports and wierdness? @@ -32,9 +35,32 @@ pub mod _dependencies { #[distributed_slice] pub static RULES_DISTRIBUTED_SLICE: [Rule<'static>]; +/// Returns a copied `Vec` of all rules registered with the `register_rule` macro. +/// +/// Rules defined in the same file will remain contiguous and in order, but order may not be maintained between files. +/// +/// # Example +/// ```rust +/// use conjure_rules::register_rule; +/// use conjure_oxide::rule::{Rule, RuleApplicationError}; +/// +/// #[register_rule] +/// fn identity(expr: &Expression) -> Result { +/// Ok(expr.clone()) +/// } +/// +/// fn main() { +/// println!("Rules: {:?}", conjure_rules::get_rules()); +/// } +/// ``` +/// +/// This will print (if no other rules are registered): +/// ```text +/// Rules: [Rule { name: "identity", application: MEM }] +/// ``` +/// Where `MEM` is the memory address of the `identity` function. pub fn get_rules() -> Vec> { RULES_DISTRIBUTED_SLICE.to_vec() } -/// TODO: docs pub use conjure_rules_proc_macro::register_rule; diff --git a/crates/conjure_rules_proc_macro/src/lib.rs b/crates/conjure_rules_proc_macro/src/lib.rs index bf89079eb..5bc4880aa 100644 --- a/crates/conjure_rules_proc_macro/src/lib.rs +++ b/crates/conjure_rules_proc_macro/src/lib.rs @@ -4,11 +4,47 @@ use syn::{parse_macro_input, Ident, ItemFn}; #[doc(hidden)] #[proc_macro_attribute] -/// This procedural macro registers a decorated function with Conjure's rule engine. +/// This procedural macro registers a decorated function with `conjure_rules`' global registry. +/// It may be used in any downstream crate. For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate. +/// +/// **IMPORTANT**: Since the resulting rule may not be explicitly referenced, it may be removed by the compiler's dead code elimination. +/// To prevent this, you must ensure that either: +/// 1. codegen-units is set to 1, i.e. in Cargo.toml: +/// ```toml +/// [profile.release] +/// codegen-units = 1 +/// ``` +/// 2. The function is included somewhere else in the code +/// +///
+/// /// Functions must have the signature `fn(&Expr) -> Result`. +/// The created rule will have the same name as the function. /// /// Intermediary static variables are created to allow for the decentralized registry, with the prefix `CONJURE_GEN_`. /// Please ensure that other variable names in the same scope do not conflict with these. +/// +///
+/// +/// For example: +/// ```rust +/// #[register_rule] +/// fn identity(expr: &Expression) -> Result { +/// Ok(expr.clone()) +/// } +/// ``` +/// ... will expand into the following code: +/// ```rust +/// fn identity(expr: &Expression) -> Result { +/// Ok(expr.clone()) +/// } +/// #[::conjure_rules::_dependencies::distributed_slice(::conjure_rules::RULES_DISTRIBUTED_SLICE)] +/// pub static CONJURE_GEN_RULE_IDENTITY: ::conjure_rules::_dependencies::Rule = ::conjure_rules::_dependencies::Rule { +/// name: "identity", +/// application: identity, +/// }; +/// ``` +/// pub fn register_rule(_: TokenStream, item: TokenStream) -> TokenStream { let func = parse_macro_input!(item as ItemFn); let rule_ident = &func.sig.ident; From 87a5e9edc6381e7727a13b47a04d376f33561ed4 Mon Sep 17 00:00:00 2001 From: Felix Date: Thu, 25 Jan 2024 11:08:03 +0000 Subject: [PATCH 5/5] update docs and fix doctests --- crates/conjure_rules/src/lib.rs | 43 +++++++++++++++++++-- crates/conjure_rules_proc_macro/src/lib.rs | 44 +--------------------- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/crates/conjure_rules/src/lib.rs b/crates/conjure_rules/src/lib.rs index d7e45fb95..7ce4b1e87 100644 --- a/crates/conjure_rules/src/lib.rs +++ b/crates/conjure_rules/src/lib.rs @@ -37,13 +37,14 @@ pub static RULES_DISTRIBUTED_SLICE: [Rule<'static>]; /// Returns a copied `Vec` of all rules registered with the `register_rule` macro. /// -/// Rules defined in the same file will remain contiguous and in order, but order may not be maintained between files. +/// Rules are not guaranteed to be in any particular order. /// /// # Example /// ```rust -/// use conjure_rules::register_rule; -/// use conjure_oxide::rule::{Rule, RuleApplicationError}; -/// +/// # use conjure_rules::register_rule; +/// # use conjure_core::rule::{Rule, RuleApplicationError}; +/// # use conjure_core::ast::Expression; +/// # /// #[register_rule] /// fn identity(expr: &Expression) -> Result { /// Ok(expr.clone()) @@ -63,4 +64,38 @@ pub fn get_rules() -> Vec> { RULES_DISTRIBUTED_SLICE.to_vec() } +/// This procedural macro registers a decorated function with `conjure_rules`' global registry. +/// It may be used in any downstream crate. For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate. +/// +/// **IMPORTANT**: Since the resulting rule may not be explicitly referenced, it may be removed by the compiler's dead code elimination. +/// To prevent this, you must ensure that either: +/// 1. codegen-units is set to 1, i.e. in Cargo.toml: +/// ```toml +/// [profile.release] +/// codegen-units = 1 +/// ``` +/// 2. The function is included somewhere else in the code +/// +///
+/// +/// Functions must have the signature `fn(&Expr) -> Result`. +/// The created rule will have the same name as the function. +/// +/// Intermediary static variables are created to allow for the decentralized registry, with the prefix `CONJURE_GEN_`. +/// Please ensure that other variable names in the same scope do not conflict with these. +/// +///
+/// +/// For example: +/// ```rust +/// # use conjure_core::ast::Expression; +/// # use conjure_core::rule::RuleApplicationError; +/// # use conjure_rules::register_rule; +/// # +/// #[register_rule] +/// fn identity(expr: &Expression) -> Result { +/// Ok(expr.clone()) +/// } +/// ``` +#[doc(inline)] pub use conjure_rules_proc_macro::register_rule; diff --git a/crates/conjure_rules_proc_macro/src/lib.rs b/crates/conjure_rules_proc_macro/src/lib.rs index 5bc4880aa..610cf1b4d 100644 --- a/crates/conjure_rules_proc_macro/src/lib.rs +++ b/crates/conjure_rules_proc_macro/src/lib.rs @@ -1,50 +1,10 @@ +//! This is the backend procedural macro crate for `conjure_rules`. USE THAT INSTEAD! + use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, Ident, ItemFn}; -#[doc(hidden)] #[proc_macro_attribute] -/// This procedural macro registers a decorated function with `conjure_rules`' global registry. -/// It may be used in any downstream crate. For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate. -/// -/// **IMPORTANT**: Since the resulting rule may not be explicitly referenced, it may be removed by the compiler's dead code elimination. -/// To prevent this, you must ensure that either: -/// 1. codegen-units is set to 1, i.e. in Cargo.toml: -/// ```toml -/// [profile.release] -/// codegen-units = 1 -/// ``` -/// 2. The function is included somewhere else in the code -/// -///
-/// -/// Functions must have the signature `fn(&Expr) -> Result`. -/// The created rule will have the same name as the function. -/// -/// Intermediary static variables are created to allow for the decentralized registry, with the prefix `CONJURE_GEN_`. -/// Please ensure that other variable names in the same scope do not conflict with these. -/// -///
-/// -/// For example: -/// ```rust -/// #[register_rule] -/// fn identity(expr: &Expression) -> Result { -/// Ok(expr.clone()) -/// } -/// ``` -/// ... will expand into the following code: -/// ```rust -/// fn identity(expr: &Expression) -> Result { -/// Ok(expr.clone()) -/// } -/// #[::conjure_rules::_dependencies::distributed_slice(::conjure_rules::RULES_DISTRIBUTED_SLICE)] -/// pub static CONJURE_GEN_RULE_IDENTITY: ::conjure_rules::_dependencies::Rule = ::conjure_rules::_dependencies::Rule { -/// name: "identity", -/// application: identity, -/// }; -/// ``` -/// pub fn register_rule(_: TokenStream, item: TokenStream) -> TokenStream { let func = parse_macro_input!(item as ItemFn); let rule_ident = &func.sig.ident;