diff --git a/Cargo.lock b/Cargo.lock index bd3a639d..1543564a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,19 @@ dependencies = [ "syn", ] +[[package]] +name = "cgp-base" +version = "0.7.0" +dependencies = [ + "cgp-base-types", + "cgp-component", + "cgp-macro", +] + +[[package]] +name = "cgp-base-types" +version = "0.7.0" + [[package]] name = "cgp-component" version = "0.7.0" @@ -34,6 +47,7 @@ name = "cgp-core" version = "0.7.0" dependencies = [ "cgp-async-macro", + "cgp-base", "cgp-component", "cgp-error", "cgp-field", @@ -54,7 +68,7 @@ dependencies = [ name = "cgp-error" version = "0.7.0" dependencies = [ - "cgp-component", + "cgp-base", "cgp-field", "cgp-macro", "cgp-type", @@ -127,6 +141,7 @@ dependencies = [ name = "cgp-field" version = "0.7.0" dependencies = [ + "cgp-base-types", "cgp-component", "cgp-type", ] @@ -153,10 +168,21 @@ dependencies = [ "syn", ] +[[package]] +name = "cgp-macro-core" +version = "0.7.0" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "cgp-macro-lib" version = "0.7.0" dependencies = [ + "cgp-macro-core", "itertools", "prettyplease", "proc-macro2", @@ -199,6 +225,7 @@ dependencies = [ name = "cgp-type" version = "0.7.0" dependencies = [ + "cgp-base", "cgp-component", "cgp-macro", ] diff --git a/Cargo.toml b/Cargo.toml index cd6f5bd9..4bfd4674 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,14 @@ resolver = "3" members = [ "crates/cgp", + "crates/cgp-base", + "crates/cgp-base-types", "crates/cgp-core", "crates/cgp-extra", "crates/cgp-async-macro", "crates/cgp-component", "crates/cgp-macro", + "crates/cgp-macro-core", "crates/cgp-macro-lib", "crates/cgp-type", "crates/cgp-field", @@ -38,11 +41,14 @@ keywords = ["cgp"] [workspace.dependencies] cgp = { version = "0.7.0", path = "./crates/cgp" } +cgp-base = { version = "0.7.0", path = "./crates/cgp-base" } +cgp-base-types = { version = "0.7.0", path = "./crates/cgp-base-types" } cgp-core = { version = "0.7.0", path = "./crates/cgp-core" } cgp-extra = { version = "0.7.0", path = "./crates/cgp-extra" } cgp-async-macro = { version = "0.7.0", path = "./crates/cgp-async-macro" } cgp-component = { version = "0.7.0", path = "./crates/cgp-component" } cgp-macro = { version = "0.7.0", path = "./crates/cgp-macro" } +cgp-macro-core = { version = "0.7.0", path = "./crates/cgp-macro-core" } cgp-macro-lib = { version = "0.7.0", path = "./crates/cgp-macro-lib" } cgp-type = { version = "0.7.0", path = "./crates/cgp-type" } cgp-field = { version = "0.7.0", path = "./crates/cgp-field" } diff --git a/crates/cgp-base-types/Cargo.toml b/crates/cgp-base-types/Cargo.toml new file mode 100644 index 00000000..1db41cea --- /dev/null +++ b/crates/cgp-base-types/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cgp-base-types" +version = "0.7.0" +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +keywords = { workspace = true } + +[dependencies] diff --git a/crates/cgp-base-types/src/lib.rs b/crates/cgp-base-types/src/lib.rs new file mode 100644 index 00000000..b59e7464 --- /dev/null +++ b/crates/cgp-base-types/src/lib.rs @@ -0,0 +1,5 @@ +#![allow(non_camel_case_types)] + +pub mod macro_prelude; +pub mod traits; +pub mod types; diff --git a/crates/cgp-base-types/src/macro_prelude.rs b/crates/cgp-base-types/src/macro_prelude.rs new file mode 100644 index 00000000..833e6e30 --- /dev/null +++ b/crates/cgp-base-types/src/macro_prelude.rs @@ -0,0 +1,2 @@ +pub use crate::traits::ConcatPath; +pub use crate::types::*; diff --git a/crates/cgp-component/src/types/path.rs b/crates/cgp-base-types/src/traits/concat_path.rs similarity index 59% rename from crates/cgp-component/src/types/path.rs rename to crates/cgp-base-types/src/traits/concat_path.rs index c09902af..f34f03b1 100644 --- a/crates/cgp-component/src/types/path.rs +++ b/crates/cgp-base-types/src/traits/concat_path.rs @@ -1,8 +1,4 @@ -use core::marker::PhantomData; - -pub struct PathCons(pub PhantomData, pub PhantomData); - -pub struct PathNil; +use crate::types::{Nil, PathCons}; pub trait ConcatPath { type Output: ?Sized; @@ -15,6 +11,6 @@ where type Output = PathCons>::Output>; } -impl ConcatPath for PathNil { +impl ConcatPath for Nil { type Output = Other; } diff --git a/crates/cgp-base-types/src/traits/mod.rs b/crates/cgp-base-types/src/traits/mod.rs new file mode 100644 index 00000000..c1632d17 --- /dev/null +++ b/crates/cgp-base-types/src/traits/mod.rs @@ -0,0 +1,5 @@ +mod concat_path; +mod static_format; + +pub use concat_path::*; +pub use static_format::*; diff --git a/crates/cgp-field/src/traits/static_format.rs b/crates/cgp-base-types/src/traits/static_format.rs similarity index 100% rename from crates/cgp-field/src/traits/static_format.rs rename to crates/cgp-base-types/src/traits/static_format.rs diff --git a/crates/cgp-field/src/types/chars.rs b/crates/cgp-base-types/src/types/chars.rs similarity index 100% rename from crates/cgp-field/src/types/chars.rs rename to crates/cgp-base-types/src/types/chars.rs diff --git a/crates/cgp-field/src/types/product.rs b/crates/cgp-base-types/src/types/cons.rs similarity index 70% rename from crates/cgp-field/src/types/product.rs rename to crates/cgp-base-types/src/types/cons.rs index 218aaec2..315c3f39 100644 --- a/crates/cgp-field/src/types/product.rs +++ b/crates/cgp-base-types/src/types/cons.rs @@ -34,18 +34,4 @@ #[allow(non_camel_case_types)] pub struct π(pub Head, pub Tail); -/** - The `Nil` type, a.k.a. `ε`, is used to represent the end of a _type-level list_, - or an empty type-level list. - - `Nil` is commonly used as the `Tail` of a [`Cons`] type, to terminate the list. - When used on its own, it represents an empty type-level list. - - Read more about type-level lists, a.k.a. the product types, in [`Cons`]. -*/ -#[derive(Eq, PartialEq, Clone, Default, Debug)] -#[allow(non_camel_case_types)] -pub struct ε; - -pub use ε as Nil; pub use π as Cons; diff --git a/crates/cgp-base-types/src/types/mod.rs b/crates/cgp-base-types/src/types/mod.rs new file mode 100644 index 00000000..ccc13be7 --- /dev/null +++ b/crates/cgp-base-types/src/types/mod.rs @@ -0,0 +1,11 @@ +mod chars; +mod cons; +mod nil; +mod path; +mod symbol; + +pub use chars::*; +pub use cons::*; +pub use nil::*; +pub use path::*; +pub use symbol::*; diff --git a/crates/cgp-base-types/src/types/nil.rs b/crates/cgp-base-types/src/types/nil.rs new file mode 100644 index 00000000..9f6ee60d --- /dev/null +++ b/crates/cgp-base-types/src/types/nil.rs @@ -0,0 +1,14 @@ +/** + The `Nil` type, a.k.a. `ε`, is used to represent the end of a _type-level list_, + or an empty type-level list. + + `Nil` is commonly used as the `Tail` of a [`Cons`] type, to terminate the list. + When used on its own, it represents an empty type-level list. + + Read more about type-level lists, a.k.a. the product types, in [`Cons`]. +*/ +#[derive(Eq, PartialEq, Clone, Default, Debug)] +#[allow(non_camel_case_types)] +pub struct ε; + +pub use ε as Nil; diff --git a/crates/cgp-base-types/src/types/path.rs b/crates/cgp-base-types/src/types/path.rs new file mode 100644 index 00000000..48bc11bf --- /dev/null +++ b/crates/cgp-base-types/src/types/path.rs @@ -0,0 +1,3 @@ +use core::marker::PhantomData; + +pub struct PathCons(pub PhantomData, pub PhantomData); diff --git a/crates/cgp-field/src/types/symbol.rs b/crates/cgp-base-types/src/types/symbol.rs similarity index 100% rename from crates/cgp-field/src/types/symbol.rs rename to crates/cgp-base-types/src/types/symbol.rs diff --git a/crates/cgp-base/Cargo.toml b/crates/cgp-base/Cargo.toml new file mode 100644 index 00000000..00548ed4 --- /dev/null +++ b/crates/cgp-base/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "cgp-base" +version = "0.7.0" +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +keywords = { workspace = true } + +[dependencies] +cgp-base-types = { workspace = true } +cgp-component = { workspace = true } +cgp-macro = { workspace = true } diff --git a/crates/cgp-base/src/lib.rs b/crates/cgp-base/src/lib.rs new file mode 100644 index 00000000..52669be9 --- /dev/null +++ b/crates/cgp-base/src/lib.rs @@ -0,0 +1 @@ +pub mod macro_prelude; diff --git a/crates/cgp-base/src/macro_prelude.rs b/crates/cgp-base/src/macro_prelude.rs new file mode 100644 index 00000000..6f11db29 --- /dev/null +++ b/crates/cgp-base/src/macro_prelude.rs @@ -0,0 +1,2 @@ +pub use cgp_base_types::macro_prelude::*; +pub use cgp_component::macro_prelude::*; diff --git a/crates/cgp-component/src/lib.rs b/crates/cgp-component/src/lib.rs index a92a79a1..9680af2e 100644 --- a/crates/cgp-component/src/lib.rs +++ b/crates/cgp-component/src/lib.rs @@ -5,13 +5,14 @@ CGP component implementation. */ +pub mod macro_prelude; + mod namespaces; +mod providers; mod traits; -mod types; -pub use namespaces::DefaultNamespace; -pub use traits::{CanUseComponent, DelegateComponent, IsProviderFor}; -pub use types::{ - ConcatPath, PathCons, PathNil, RedirectLookup, UseContext, UseDefault, UseDelegate, UseFields, - WithContext, WithProvider, +pub use namespaces::{DefaultImpls1, DefaultImpls2, DefaultNamespace}; +pub use providers::{ + RedirectLookup, UseContext, UseDefault, UseDelegate, UseFields, WithContext, WithProvider, }; +pub use traits::{CanUseComponent, DelegateComponent, IsProviderFor}; diff --git a/crates/cgp-component/src/macro_prelude.rs b/crates/cgp-component/src/macro_prelude.rs new file mode 100644 index 00000000..f08affab --- /dev/null +++ b/crates/cgp-component/src/macro_prelude.rs @@ -0,0 +1,5 @@ +pub use crate::namespaces::DefaultNamespace; +pub use crate::providers::{ + RedirectLookup, UseContext, UseDefault, UseDelegate, UseFields, WithContext, WithProvider, +}; +pub use crate::traits::{CanUseComponent, DelegateComponent, IsProviderFor}; diff --git a/crates/cgp-component/src/namespaces.rs b/crates/cgp-component/src/namespaces.rs index 3c8e4bf5..3daddeb5 100644 --- a/crates/cgp-component/src/namespaces.rs +++ b/crates/cgp-component/src/namespaces.rs @@ -1,3 +1,11 @@ pub trait DefaultNamespace { - type Provider; + type Delegate; +} + +pub trait DefaultImpls1 { + type Delegate; +} + +pub trait DefaultImpls2 { + type Delegate; } diff --git a/crates/cgp-component/src/types/mod.rs b/crates/cgp-component/src/providers/mod.rs similarity index 85% rename from crates/cgp-component/src/types/mod.rs rename to crates/cgp-component/src/providers/mod.rs index 56890656..1e07f782 100644 --- a/crates/cgp-component/src/types/mod.rs +++ b/crates/cgp-component/src/providers/mod.rs @@ -1,4 +1,3 @@ -mod path; mod redirect_lookup; mod use_context; mod use_default; @@ -6,7 +5,6 @@ mod use_delegate; mod use_fields; mod with_provider; -pub use path::{ConcatPath, PathCons, PathNil}; pub use redirect_lookup::RedirectLookup; pub use use_context::{UseContext, WithContext}; pub use use_default::UseDefault; diff --git a/crates/cgp-component/src/types/redirect_lookup.rs b/crates/cgp-component/src/providers/redirect_lookup.rs similarity index 100% rename from crates/cgp-component/src/types/redirect_lookup.rs rename to crates/cgp-component/src/providers/redirect_lookup.rs diff --git a/crates/cgp-component/src/types/use_context.rs b/crates/cgp-component/src/providers/use_context.rs similarity index 100% rename from crates/cgp-component/src/types/use_context.rs rename to crates/cgp-component/src/providers/use_context.rs diff --git a/crates/cgp-component/src/types/use_default.rs b/crates/cgp-component/src/providers/use_default.rs similarity index 100% rename from crates/cgp-component/src/types/use_default.rs rename to crates/cgp-component/src/providers/use_default.rs diff --git a/crates/cgp-component/src/types/use_delegate.rs b/crates/cgp-component/src/providers/use_delegate.rs similarity index 100% rename from crates/cgp-component/src/types/use_delegate.rs rename to crates/cgp-component/src/providers/use_delegate.rs diff --git a/crates/cgp-component/src/types/use_field.rs b/crates/cgp-component/src/providers/use_field.rs similarity index 100% rename from crates/cgp-component/src/types/use_field.rs rename to crates/cgp-component/src/providers/use_field.rs diff --git a/crates/cgp-component/src/types/use_fields.rs b/crates/cgp-component/src/providers/use_fields.rs similarity index 100% rename from crates/cgp-component/src/types/use_fields.rs rename to crates/cgp-component/src/providers/use_fields.rs diff --git a/crates/cgp-component/src/types/with_provider.rs b/crates/cgp-component/src/providers/with_provider.rs similarity index 100% rename from crates/cgp-component/src/types/with_provider.rs rename to crates/cgp-component/src/providers/with_provider.rs diff --git a/crates/cgp-core/Cargo.toml b/crates/cgp-core/Cargo.toml index 7aae1dc7..968e00a2 100644 --- a/crates/cgp-core/Cargo.toml +++ b/crates/cgp-core/Cargo.toml @@ -12,6 +12,7 @@ description = """ """ [dependencies] +cgp-base = { workspace = true } cgp-async-macro = { workspace = true } cgp-component = { workspace = true } cgp-macro = { workspace = true } diff --git a/crates/cgp-core/src/lib.rs b/crates/cgp-core/src/lib.rs index 549cce23..b9eeed7c 100644 --- a/crates/cgp-core/src/lib.rs +++ b/crates/cgp-core/src/lib.rs @@ -3,6 +3,7 @@ pub mod prelude; +pub use prelude as macro_prelude; #[doc(inline)] pub use { cgp_async_macro::async_trait, cgp_component as component, cgp_error as error, diff --git a/crates/cgp-core/src/prelude.rs b/crates/cgp-core/src/prelude.rs index 41063b28..5702afab 100644 --- a/crates/cgp-core/src/prelude.rs +++ b/crates/cgp-core/src/prelude.rs @@ -1,9 +1,10 @@ pub use core::marker::PhantomData; pub use cgp_async_macro::async_trait; +pub use cgp_base::macro_prelude::{ConcatPath, PathCons}; pub use cgp_component::{ - CanUseComponent, ConcatPath, DefaultNamespace, DelegateComponent, IsProviderFor, PathCons, - PathNil, RedirectLookup, UseContext, UseDelegate, UseFields, WithContext, WithProvider, + CanUseComponent, DefaultNamespace, DelegateComponent, IsProviderFor, RedirectLookup, + UseContext, UseDelegate, UseFields, WithContext, WithProvider, }; pub use cgp_error::{CanRaiseError, CanWrapError, HasErrorType}; pub use cgp_field::impls::{IsMut, IsNothing, IsPresent, IsRef, IsVoid, UseField}; diff --git a/crates/cgp-dispatch/Cargo.toml b/crates/cgp-dispatch/Cargo.toml index ff0d9db1..75c8243a 100644 --- a/crates/cgp-dispatch/Cargo.toml +++ b/crates/cgp-dispatch/Cargo.toml @@ -10,6 +10,6 @@ keywords = { workspace = true } description = "Extensible data type dispatchers for CGP handlers" [dependencies] -cgp-core = { workspace = true } +cgp = { version = "0.7.0", path = "../cgp-core", package = "cgp-core" } cgp-monad = { workspace = true } cgp-handler = { workspace = true } diff --git a/crates/cgp-dispatch/src/providers/builders/build_and_merge_outputs.rs b/crates/cgp-dispatch/src/providers/builders/build_and_merge_outputs.rs index a5d6eed0..696152e1 100644 --- a/crates/cgp-dispatch/src/providers/builders/build_and_merge_outputs.rs +++ b/crates/cgp-dispatch/src/providers/builders/build_and_merge_outputs.rs @@ -1,5 +1,5 @@ -use cgp_core::field::traits::MapFields; -use cgp_core::prelude::*; +use cgp::field::traits::MapFields; +use cgp::prelude::*; use cgp_handler::{ ComputerComponent, ComputerRefComponent, HandlerComponent, HandlerRefComponent, TryComputerComponent, TryComputerRefComponent, diff --git a/crates/cgp-dispatch/src/providers/field_builders/build_and_merge.rs b/crates/cgp-dispatch/src/providers/field_builders/build_and_merge.rs index f44a422e..e440847d 100644 --- a/crates/cgp-dispatch/src/providers/field_builders/build_and_merge.rs +++ b/crates/cgp-dispatch/src/providers/field_builders/build_and_merge.rs @@ -1,5 +1,5 @@ -use cgp_core::field::impls::CanBuildFrom; -use cgp_core::prelude::*; +use cgp::field::impls::CanBuildFrom; +use cgp::prelude::*; use cgp_handler::{ Computer, ComputerComponent, Handler, HandlerComponent, TryComputer, TryComputerComponent, }; diff --git a/crates/cgp-dispatch/src/providers/field_builders/build_and_set_field.rs b/crates/cgp-dispatch/src/providers/field_builders/build_and_set_field.rs index fbb196e3..0532a8a9 100644 --- a/crates/cgp-dispatch/src/providers/field_builders/build_and_set_field.rs +++ b/crates/cgp-dispatch/src/providers/field_builders/build_and_set_field.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{ Computer, ComputerComponent, Handler, HandlerComponent, TryComputer, TryComputerComponent, }; diff --git a/crates/cgp-dispatch/src/providers/field_matchers/extract_field.rs b/crates/cgp-dispatch/src/providers/field_matchers/extract_field.rs index 334f8ce1..05313bdb 100644 --- a/crates/cgp-dispatch/src/providers/field_matchers/extract_field.rs +++ b/crates/cgp-dispatch/src/providers/field_matchers/extract_field.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; pub struct ExtractFieldAndHandle(pub PhantomData<(Tag, Provider)>); diff --git a/crates/cgp-dispatch/src/providers/field_matchers/extract_first_field.rs b/crates/cgp-dispatch/src/providers/field_matchers/extract_first_field.rs index 18c4f838..1fdab5f5 100644 --- a/crates/cgp-dispatch/src/providers/field_matchers/extract_first_field.rs +++ b/crates/cgp-dispatch/src/providers/field_matchers/extract_first_field.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; pub struct ExtractFirstFieldAndHandle(pub PhantomData<(Tag, Provider)>); diff --git a/crates/cgp-dispatch/src/providers/field_matchers/extract_handle.rs b/crates/cgp-dispatch/src/providers/field_matchers/extract_handle.rs index 0b7d907e..a37d6a65 100644 --- a/crates/cgp-dispatch/src/providers/field_matchers/extract_handle.rs +++ b/crates/cgp-dispatch/src/providers/field_matchers/extract_handle.rs @@ -1,5 +1,5 @@ -use cgp_core::field::impls::CanDowncastFields; -use cgp_core::prelude::*; +use cgp::field::impls::CanDowncastFields; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; pub struct DowncastAndHandle(pub PhantomData<(Input, Provider)>); diff --git a/crates/cgp-dispatch/src/providers/field_matchers/field_value.rs b/crates/cgp-dispatch/src/providers/field_matchers/field_value.rs index 9eef319a..191c957c 100644 --- a/crates/cgp-dispatch/src/providers/field_matchers/field_value.rs +++ b/crates/cgp-dispatch/src/providers/field_matchers/field_value.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; pub struct HandleFieldValue(pub PhantomData); diff --git a/crates/cgp-dispatch/src/providers/field_matchers/first_field_value.rs b/crates/cgp-dispatch/src/providers/field_matchers/first_field_value.rs index 899e955c..074fde06 100644 --- a/crates/cgp-dispatch/src/providers/field_matchers/first_field_value.rs +++ b/crates/cgp-dispatch/src/providers/field_matchers/first_field_value.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; pub struct HandleFirstFieldValue(pub PhantomData); diff --git a/crates/cgp-dispatch/src/providers/matchers/match_first_with_field_handlers.rs b/crates/cgp-dispatch/src/providers/matchers/match_first_with_field_handlers.rs index 1fe4cea6..51f12599 100644 --- a/crates/cgp-dispatch/src/providers/matchers/match_first_with_field_handlers.rs +++ b/crates/cgp-dispatch/src/providers/matchers/match_first_with_field_handlers.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::UseInputDelegate; use crate::providers::matchers::to_field_handlers::{ diff --git a/crates/cgp-dispatch/src/providers/matchers/match_with_field_handlers.rs b/crates/cgp-dispatch/src/providers/matchers/match_with_field_handlers.rs index fd9089e1..087f8afe 100644 --- a/crates/cgp-dispatch/src/providers/matchers/match_with_field_handlers.rs +++ b/crates/cgp-dispatch/src/providers/matchers/match_with_field_handlers.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{ AsyncComputerComponent, AsyncComputerRefComponent, ComputerComponent, ComputerRefComponent, HandlerComponent, HandlerRefComponent, PromoteRef, TryComputerComponent, diff --git a/crates/cgp-dispatch/src/providers/matchers/to_field_handlers.rs b/crates/cgp-dispatch/src/providers/matchers/to_field_handlers.rs index 79c1546c..29f4d78d 100644 --- a/crates/cgp-dispatch/src/providers/matchers/to_field_handlers.rs +++ b/crates/cgp-dispatch/src/providers/matchers/to_field_handlers.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::{ExtractFieldAndHandle, ExtractFirstFieldAndHandle}; diff --git a/crates/cgp-dispatch/src/providers/with_handlers/build_with_handlers.rs b/crates/cgp-dispatch/src/providers/with_handlers/build_with_handlers.rs index 73d9f583..081aaae4 100644 --- a/crates/cgp-dispatch/src/providers/with_handlers/build_with_handlers.rs +++ b/crates/cgp-dispatch/src/providers/with_handlers/build_with_handlers.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{ Computer, ComputerComponent, Handler, HandlerComponent, PipeHandlers, TryComputer, TryComputerComponent, diff --git a/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers.rs b/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers.rs index e7384169..fe068031 100644 --- a/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers.rs +++ b/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; use crate::DispatchMatchers; diff --git a/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers_mut.rs b/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers_mut.rs index 7b351916..89f93988 100644 --- a/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers_mut.rs +++ b/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers_mut.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; use crate::DispatchMatchers; diff --git a/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers_ref.rs b/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers_ref.rs index 9c869999..c1c2e330 100644 --- a/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers_ref.rs +++ b/crates/cgp-dispatch/src/providers/with_handlers/match_first_with_handlers_ref.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; use crate::DispatchMatchers; diff --git a/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers.rs b/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers.rs index f2ae5ef6..75fecc44 100644 --- a/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers.rs +++ b/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; -use cgp_core::field::traits::FinalizeExtractResult; -use cgp_core::prelude::*; +use cgp::field::traits::FinalizeExtractResult; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; use crate::DispatchMatchers; diff --git a/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers_mut.rs b/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers_mut.rs index 01e6100b..a0ef403b 100644 --- a/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers_mut.rs +++ b/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers_mut.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; -use cgp_core::field::traits::FinalizeExtractResult; -use cgp_core::prelude::*; +use cgp::field::traits::FinalizeExtractResult; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; use crate::DispatchMatchers; diff --git a/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers_ref.rs b/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers_ref.rs index 07c08f91..5a98f62e 100644 --- a/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers_ref.rs +++ b/crates/cgp-dispatch/src/providers/with_handlers/match_with_handlers_ref.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; -use cgp_core::field::traits::FinalizeExtractResult; -use cgp_core::prelude::*; +use cgp::field::traits::FinalizeExtractResult; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; use crate::DispatchMatchers; diff --git a/crates/cgp-error/Cargo.toml b/crates/cgp-error/Cargo.toml index 061de754..53f0432b 100644 --- a/crates/cgp-error/Cargo.toml +++ b/crates/cgp-error/Cargo.toml @@ -7,12 +7,9 @@ repository = { workspace = true } authors = { workspace = true } rust-version = { workspace = true } keywords = { workspace = true } -description = """ - Context-generic programming error components -""" [dependencies] -cgp-component = { workspace = true } +cgp = { version = "0.7.0", path = "../cgp-base", package = "cgp-base" } cgp-macro = { workspace = true } cgp-type = { workspace = true } cgp-field = { workspace = true } diff --git a/crates/cgp-error/src/traits/can_raise_error.rs b/crates/cgp-error/src/traits/can_raise_error.rs index 2865b095..324834e2 100644 --- a/crates/cgp-error/src/traits/can_raise_error.rs +++ b/crates/cgp-error/src/traits/can_raise_error.rs @@ -1,5 +1,4 @@ -use cgp_component::*; -use cgp_field::types::*; +use cgp::macro_prelude::*; use cgp_macro::cgp_component; use crate::traits::has_error_type::HasErrorType; @@ -12,7 +11,7 @@ use crate::traits::has_error_type::HasErrorType; provider: ErrorRaiser, derive_delegate: UseDelegate, }] -#[namespace(@cgp.core.error.ErrorRaiserComponent)] +#[prefix(@cgp.core.error)] pub trait CanRaiseError: HasErrorType { fn raise_error(error: SourceError) -> Self::Error; } diff --git a/crates/cgp-error/src/traits/can_wrap_error.rs b/crates/cgp-error/src/traits/can_wrap_error.rs index 1237f354..704157fc 100644 --- a/crates/cgp-error/src/traits/can_wrap_error.rs +++ b/crates/cgp-error/src/traits/can_wrap_error.rs @@ -1,5 +1,4 @@ -use cgp_component::*; -use cgp_field::types::*; +use cgp::macro_prelude::*; use cgp_macro::cgp_component; use crate::traits::HasErrorType; @@ -8,7 +7,7 @@ use crate::traits::HasErrorType; provider: ErrorWrapper, derive_delegate: UseDelegate, }] -#[namespace(@cgp.core.error.ErrorWrapperComponent)] +#[prefix(@cgp.core.error)] pub trait CanWrapError: HasErrorType { fn wrap_error(error: Self::Error, detail: Detail) -> Self::Error; } diff --git a/crates/cgp-error/src/traits/has_error_type.rs b/crates/cgp-error/src/traits/has_error_type.rs index 8c54d424..ab18343c 100644 --- a/crates/cgp-error/src/traits/has_error_type.rs +++ b/crates/cgp-error/src/traits/has_error_type.rs @@ -1,10 +1,6 @@ use core::fmt::Debug; -use cgp_component::{ - DefaultNamespace, DelegateComponent, IsProviderFor, PathCons, PathNil, RedirectLookup, - UseContext, WithProvider, -}; -use cgp_field::types::*; +use cgp::macro_prelude::*; use cgp_macro::cgp_type; use cgp_type::{TypeProvider, UseType}; @@ -28,7 +24,7 @@ use cgp_type::{TypeProvider, UseType}; */ #[cgp_type] -#[namespace(@cgp.core.error.ErrorTypeProviderComponent)] +#[prefix(@cgp.core.error)] pub trait HasErrorType { type Error: Debug; } diff --git a/crates/cgp-field/Cargo.toml b/crates/cgp-field/Cargo.toml index fd1d255f..7a32d855 100644 --- a/crates/cgp-field/Cargo.toml +++ b/crates/cgp-field/Cargo.toml @@ -12,5 +12,6 @@ description = """ """ [dependencies] +cgp-base-types = { workspace = true } cgp-component = { workspace = true } cgp-type = { workspace = true } diff --git a/crates/cgp-field/src/traits/mod.rs b/crates/cgp-field/src/traits/mod.rs index 63d13dc7..6ab96625 100644 --- a/crates/cgp-field/src/traits/mod.rs +++ b/crates/cgp-field/src/traits/mod.rs @@ -13,7 +13,6 @@ mod map_fields; mod map_type; mod map_type_ref; mod partial_data; -mod static_format; mod static_string; mod take_field; mod to_fields; @@ -35,7 +34,6 @@ pub use map_fields::*; pub use map_type::*; pub use map_type_ref::*; pub use partial_data::*; -pub use static_format::*; pub use static_string::*; pub use take_field::*; pub use to_fields::*; diff --git a/crates/cgp-field/src/types/mod.rs b/crates/cgp-field/src/types/mod.rs index be1dfcbc..02880ce3 100644 --- a/crates/cgp-field/src/types/mod.rs +++ b/crates/cgp-field/src/types/mod.rs @@ -1,17 +1,12 @@ -mod chars; mod field; mod index; mod life; mod mref; -mod product; mod sum; -mod symbol; -pub use chars::*; +pub use cgp_base_types::types::*; pub use field::*; pub use index::*; pub use life::*; pub use mref::*; -pub use product::*; pub use sum::*; -pub use symbol::*; diff --git a/crates/cgp-handler/Cargo.toml b/crates/cgp-handler/Cargo.toml index 07247c75..7d61e121 100644 --- a/crates/cgp-handler/Cargo.toml +++ b/crates/cgp-handler/Cargo.toml @@ -10,4 +10,4 @@ keywords = { workspace = true } description = "Generalized handler interfaces for functional programming" [dependencies] -cgp-core = { workspace = true } +cgp = { version = "0.7.0", path = "../cgp-core", package = "cgp-core" } diff --git a/crates/cgp-handler/src/components/async_computer.rs b/crates/cgp-handler/src/components/async_computer.rs index 8b385641..3e58a4f4 100644 --- a/crates/cgp-handler/src/components/async_computer.rs +++ b/crates/cgp-handler/src/components/async_computer.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; -use cgp_core::component::UseDelegate; -use cgp_core::prelude::*; +use cgp::component::UseDelegate; +use cgp::prelude::*; use crate::UseInputDelegate; diff --git a/crates/cgp-handler/src/components/computer.rs b/crates/cgp-handler/src/components/computer.rs index d2ba0f0d..8d971f9f 100644 --- a/crates/cgp-handler/src/components/computer.rs +++ b/crates/cgp-handler/src/components/computer.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; -use cgp_core::component::UseDelegate; -use cgp_core::prelude::*; +use cgp::component::UseDelegate; +use cgp::prelude::*; use crate::UseInputDelegate; diff --git a/crates/cgp-handler/src/components/handler.rs b/crates/cgp-handler/src/components/handler.rs index aed0a397..098815e9 100644 --- a/crates/cgp-handler/src/components/handler.rs +++ b/crates/cgp-handler/src/components/handler.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; -use cgp_core::component::UseDelegate; -use cgp_core::prelude::*; +use cgp::component::UseDelegate; +use cgp::prelude::*; use crate::UseInputDelegate; diff --git a/crates/cgp-handler/src/components/produce.rs b/crates/cgp-handler/src/components/produce.rs index 9f81158d..4dc88db1 100644 --- a/crates/cgp-handler/src/components/produce.rs +++ b/crates/cgp-handler/src/components/produce.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; -use cgp_core::component::UseDelegate; -use cgp_core::prelude::*; +use cgp::component::UseDelegate; +use cgp::prelude::*; #[cgp_component { provider: Producer, diff --git a/crates/cgp-handler/src/components/try_compute.rs b/crates/cgp-handler/src/components/try_compute.rs index dec02530..75b970b6 100644 --- a/crates/cgp-handler/src/components/try_compute.rs +++ b/crates/cgp-handler/src/components/try_compute.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; -use cgp_core::component::UseDelegate; -use cgp_core::prelude::*; +use cgp::component::UseDelegate; +use cgp::prelude::*; use crate::UseInputDelegate; diff --git a/crates/cgp-handler/src/providers/compose.rs b/crates/cgp-handler/src/providers/compose.rs index a8a4918b..262a1e4b 100644 --- a/crates/cgp-handler/src/providers/compose.rs +++ b/crates/cgp-handler/src/providers/compose.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::{ AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent, Handler, HandlerComponent, diff --git a/crates/cgp-handler/src/providers/pipe.rs b/crates/cgp-handler/src/providers/pipe.rs index 4a368b16..7c9c4df4 100644 --- a/crates/cgp-handler/src/providers/pipe.rs +++ b/crates/cgp-handler/src/providers/pipe.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::ComposeHandlers; diff --git a/crates/cgp-handler/src/providers/promote.rs b/crates/cgp-handler/src/providers/promote.rs index 8e8427c0..46dd2ab4 100644 --- a/crates/cgp-handler/src/providers/promote.rs +++ b/crates/cgp-handler/src/providers/promote.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::{ AsyncComputer, Computer, ComputerComponent, Handler, HandlerComponent, Producer, TryComputer, diff --git a/crates/cgp-handler/src/providers/promote_all.rs b/crates/cgp-handler/src/providers/promote_all.rs index f302388a..5c4472cf 100644 --- a/crates/cgp-handler/src/providers/promote_all.rs +++ b/crates/cgp-handler/src/providers/promote_all.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::{ AsyncComputerComponent, AsyncComputerRefComponent, ComputerComponent, ComputerRefComponent, diff --git a/crates/cgp-handler/src/providers/promote_async.rs b/crates/cgp-handler/src/providers/promote_async.rs index 7392a0f1..cbe2cfb7 100644 --- a/crates/cgp-handler/src/providers/promote_async.rs +++ b/crates/cgp-handler/src/providers/promote_async.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::{ AsyncComputer, AsyncComputerComponent, Computer, Handler, HandlerComponent, TryComputer, diff --git a/crates/cgp-handler/src/providers/promote_ref.rs b/crates/cgp-handler/src/providers/promote_ref.rs index 2b8619ac..92e76ffb 100644 --- a/crates/cgp-handler/src/providers/promote_ref.rs +++ b/crates/cgp-handler/src/providers/promote_ref.rs @@ -1,6 +1,6 @@ use core::ops::Deref; -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::{ AsyncComputer, AsyncComputerComponent, AsyncComputerRef, AsyncComputerRefComponent, Computer, diff --git a/crates/cgp-handler/src/providers/return_input.rs b/crates/cgp-handler/src/providers/return_input.rs index 0ff28e87..a7d542d7 100644 --- a/crates/cgp-handler/src/providers/return_input.rs +++ b/crates/cgp-handler/src/providers/return_input.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::{ AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent, Handler, HandlerComponent, diff --git a/crates/cgp-handler/src/providers/try_promote.rs b/crates/cgp-handler/src/providers/try_promote.rs index 99938621..39de548a 100644 --- a/crates/cgp-handler/src/providers/try_promote.rs +++ b/crates/cgp-handler/src/providers/try_promote.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use crate::{ AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent, Handler, HandlerComponent, diff --git a/crates/cgp-macro-core/Cargo.toml b/crates/cgp-macro-core/Cargo.toml new file mode 100644 index 00000000..2d69a19d --- /dev/null +++ b/crates/cgp-macro-core/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "cgp-macro-core" +version = "0.7.0" +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +keywords = { workspace = true } +description = """ + Context-generic programming core component macros implemented as a library. +""" + +[features] +default = [] + +[dependencies] +syn = { version = "2.0.95", features = [ "full", "extra-traits", "visit", "visit-mut" ] } +quote = "1.0.38" +proc-macro2 = "1.0.92" +itertools = "0.14.0" diff --git a/crates/cgp-macro-core/src/exports.rs b/crates/cgp-macro-core/src/exports.rs new file mode 100644 index 00000000..36841735 --- /dev/null +++ b/crates/cgp-macro-core/src/exports.rs @@ -0,0 +1,12 @@ +use crate::export_constructs; + +export_constructs! { + Nil, + Cons, + Chars, + Symbol, + PathCons, + RedirectLookup, + DelegateComponent, + IsProviderFor, +} diff --git a/crates/cgp-macro-lib/src/delegate_components/merge_generics.rs b/crates/cgp-macro-core/src/functions/merge_generics.rs similarity index 100% rename from crates/cgp-macro-lib/src/delegate_components/merge_generics.rs rename to crates/cgp-macro-core/src/functions/merge_generics.rs diff --git a/crates/cgp-macro-core/src/functions/mod.rs b/crates/cgp-macro-core/src/functions/mod.rs new file mode 100644 index 00000000..f5b39fc2 --- /dev/null +++ b/crates/cgp-macro-core/src/functions/mod.rs @@ -0,0 +1,3 @@ +mod merge_generics; + +pub use merge_generics::*; diff --git a/crates/cgp-macro-core/src/lib.rs b/crates/cgp-macro-core/src/lib.rs new file mode 100644 index 00000000..a6dbd9e7 --- /dev/null +++ b/crates/cgp-macro-core/src/lib.rs @@ -0,0 +1,7 @@ +#![allow(mixed_script_confusables)] + +pub mod exports; +pub mod functions; +pub mod macros; +pub mod traits; +pub mod types; diff --git a/crates/cgp-macro-core/src/macros.rs b/crates/cgp-macro-core/src/macros.rs new file mode 100644 index 00000000..fc68dc74 --- /dev/null +++ b/crates/cgp-macro-core/src/macros.rs @@ -0,0 +1,33 @@ +#[macro_export] +macro_rules! export_construct { + ( $from:ident => $to:ident ) => { + pub struct $from; + + impl ::quote::ToTokens for $from { + fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) { + tokens.extend(::quote::quote! { ::cgp::macro_prelude::$to }) + } + } + }; + ( $ident:ident ) => { + $crate::export_construct! { $ident => $ident } + }; +} + +#[macro_export] +macro_rules! export_constructs { + ( $( $from:ident $( => $to:ident )? ),* $(,)? ) => { + $( $crate::export_construct! { $from $( => $to )* } )* + }; +} + +#[macro_export] +macro_rules! define_keyword { + ( $struct_ident:ident, $value:literal ) => { + pub struct $struct_ident; + + impl $crate::traits::IsKeyword for $struct_ident { + const IDENT: &'static str = $value; + } + }; +} diff --git a/crates/cgp-macro-core/src/traits/keyword.rs b/crates/cgp-macro-core/src/traits/keyword.rs new file mode 100644 index 00000000..125c7937 --- /dev/null +++ b/crates/cgp-macro-core/src/traits/keyword.rs @@ -0,0 +1,22 @@ +use syn::Ident; +use syn::parse::ParseBuffer; + +pub trait IsKeyword { + const IDENT: &'static str; +} + +pub trait PeekKeyword { + fn peek_keyword(&self) -> bool; +} + +impl<'a> PeekKeyword for ParseBuffer<'a> { + fn peek_keyword(&self) -> bool { + if let Ok(ident) = self.fork().parse::() + && ident == K::IDENT + { + true + } else { + false + } + } +} diff --git a/crates/cgp-macro-core/src/traits/mod.rs b/crates/cgp-macro-core/src/traits/mod.rs new file mode 100644 index 00000000..9484894c --- /dev/null +++ b/crates/cgp-macro-core/src/traits/mod.rs @@ -0,0 +1,5 @@ +mod keyword; +mod to_type; + +pub use keyword::*; +pub use to_type::*; diff --git a/crates/cgp-macro-core/src/traits/to_type.rs b/crates/cgp-macro-core/src/traits/to_type.rs new file mode 100644 index 00000000..f11eb2a4 --- /dev/null +++ b/crates/cgp-macro-core/src/traits/to_type.rs @@ -0,0 +1,5 @@ +use syn::Type; + +pub trait ToType { + fn to_type(&self) -> Type; +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/entries.rs b/crates/cgp-macro-core/src/types/delegate_component/entries.rs new file mode 100644 index 00000000..919ad512 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/entries.rs @@ -0,0 +1,85 @@ +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{Generics, ItemImpl, Type}; + +use crate::types::delegate_component::{ + DelegateMapping, DelegateStatement, EvalDelegateEntries, ExtractInnerDelegateTables, + InnerDelegateTable, +}; + +#[derive(Debug, Clone)] +pub struct DelegateEntries { + pub statements: Vec, + pub entries: Punctuated, +} + +impl Parse for DelegateEntries { + fn parse(input: ParseStream) -> syn::Result { + let mut statements = Vec::new(); + + while DelegateStatement::peek_statement(input) { + let statement = input.parse()?; + statements.push(statement); + } + + let entries = Punctuated::parse_terminated(input)?; + + Ok(Self { + statements, + entries, + }) + } +} + +impl EvalDelegateEntries for DelegateEntries { + fn eval_entries( + &self, + table_type: &Type, + ) -> syn::Result> { + let mut evaluated_entries = Vec::new(); + + for statement in &self.statements { + evaluated_entries.extend(statement.eval_entries(table_type)?); + } + + for entry in &self.entries { + evaluated_entries.extend(entry.eval_entries(table_type)?); + } + + Ok(evaluated_entries) + } +} + +impl DelegateEntries { + pub fn build_impls( + &self, + table_type: &Type, + outer_generics: &Generics, + ) -> syn::Result> { + let mut item_impls = Vec::new(); + + let evaluated_entries = self.eval_entries(table_type)?; + + for evaluated_entry in evaluated_entries { + let delegate_component_impl = + evaluated_entry.build_delegate_component_impl(outer_generics)?; + + let is_provider_impl = evaluated_entry.build_is_provider_for_impl(outer_generics)?; + + item_impls.push(delegate_component_impl); + item_impls.push(is_provider_impl); + } + + Ok(item_impls) + } +} + +impl ExtractInnerDelegateTables for DelegateEntries { + fn extract_inner_tables(&self) -> Vec { + self.entries + .iter() + .flat_map(|entry| entry.extract_inner_tables()) + .collect() + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/key/combined.rs b/crates/cgp-macro-core/src/types/delegate_component/key/combined.rs new file mode 100644 index 00000000..04df43d4 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/key/combined.rs @@ -0,0 +1,44 @@ +use syn::parse::{Parse, ParseStream}; +use syn::token::{At, Bracket}; + +use crate::types::delegate_component::{ + EvalDelegateKey, EvaluatedDelegateKey, MultiDelegateKey, PathDelegateKey, SingleDelegateKey, +}; +use crate::types::generics::ImplGenerics; + +#[derive(Debug, Clone)] +pub enum DelegateKey { + Single(SingleDelegateKey), + Multi(MultiDelegateKey), + Path(PathDelegateKey), +} + +impl Parse for DelegateKey { + fn parse(input: ParseStream) -> syn::Result { + let fork = input.fork(); + let _generics: ImplGenerics = fork.parse()?; + + let key = if fork.peek(At) { + let path = input.parse()?; + Self::Path(path) + } else if input.peek(Bracket) { + let keys = input.parse()?; + Self::Multi(keys) + } else { + let key = input.parse()?; + Self::Single(key) + }; + + Ok(key) + } +} + +impl EvalDelegateKey for DelegateKey { + fn eval(&self) -> syn::Result> { + match self { + Self::Single(key) => key.eval(), + Self::Multi(key) => key.eval(), + Self::Path(key) => key.eval(), + } + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/key/eval.rs b/crates/cgp-macro-core/src/types/delegate_component/key/eval.rs new file mode 100644 index 00000000..99159104 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/key/eval.rs @@ -0,0 +1,10 @@ +use syn::{Generics, Type}; + +pub struct EvaluatedDelegateKey { + pub generics: Generics, + pub key: Type, +} + +pub trait EvalDelegateKey { + fn eval(&self) -> syn::Result>; +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/key/mod.rs b/crates/cgp-macro-core/src/types/delegate_component/key/mod.rs new file mode 100644 index 00000000..fc077b08 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/key/mod.rs @@ -0,0 +1,11 @@ +mod combined; +mod eval; +mod multi; +mod path; +mod single; + +pub use combined::*; +pub use eval::*; +pub use multi::*; +pub use path::*; +pub use single::*; diff --git a/crates/cgp-macro-core/src/types/delegate_component/key/multi.rs b/crates/cgp-macro-core/src/types/delegate_component/key/multi.rs new file mode 100644 index 00000000..c571ae0b --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/key/multi.rs @@ -0,0 +1,38 @@ +use syn::bracketed; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::Comma; + +use crate::types::delegate_component::{EvalDelegateKey, EvaluatedDelegateKey, SingleDelegateKey}; + +#[derive(Debug, Clone)] +pub struct MultiDelegateKey { + pub keys: Punctuated, +} + +impl Parse for MultiDelegateKey { + fn parse(input: ParseStream) -> syn::Result { + let body; + bracketed!(body in input); + let keys = Punctuated::parse_terminated(&body)?; + + Ok(Self { keys }) + } +} + +impl EvalDelegateKey for MultiDelegateKey { + fn eval(&self) -> syn::Result> { + let mut keys = Vec::new(); + + for key in &self.keys { + let key = EvaluatedDelegateKey { + generics: key.generics.generics.clone(), + key: key.ty.clone(), + }; + + keys.push(key) + } + + Ok(keys) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/key/path.rs b/crates/cgp-macro-core/src/types/delegate_component/key/path.rs new file mode 100644 index 00000000..9bd71af0 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/key/path.rs @@ -0,0 +1,50 @@ +use syn::parse::{Parse, ParseStream}; +use syn::parse_quote; +use syn::token::At; + +use crate::functions::merge_generics; +use crate::types::delegate_component::{EvalDelegateKey, EvaluatedDelegateKey}; +use crate::types::generics::ImplGenerics; +use crate::types::path::PathHead; + +#[derive(Debug, Clone)] +pub struct PathDelegateKey { + pub generics: ImplGenerics, + pub at: At, + pub path: PathHead, +} + +impl Parse for PathDelegateKey { + fn parse(input: ParseStream) -> syn::Result { + let generics = input.parse()?; + let at = input.parse()?; + let path = input.parse()?; + + Ok(Self { generics, at, path }) + } +} + +impl EvalDelegateKey for PathDelegateKey { + fn eval(&self) -> syn::Result> { + let paths = self.path.into_paths(); + let outer_generics = &self.generics; + let mut keys = Vec::new(); + + for (inner_generics, path) in paths { + let mut generics = merge_generics(outer_generics, &inner_generics); + generics.params.push(parse_quote!(__Wildcard__)); + + let prefix = path.to_prefix(parse_quote!(__Wildcard__)); + let key_type = parse_quote!(#prefix); + + let key = EvaluatedDelegateKey { + generics, + key: key_type, + }; + + keys.push(key) + } + + Ok(keys) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/key/single.rs b/crates/cgp-macro-core/src/types/delegate_component/key/single.rs new file mode 100644 index 00000000..6e234165 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/key/single.rs @@ -0,0 +1,31 @@ +use syn::Type; +use syn::parse::{Parse, ParseStream}; + +use crate::types::delegate_component::{EvalDelegateKey, EvaluatedDelegateKey}; +use crate::types::generics::ImplGenerics; + +#[derive(Debug, Clone)] +pub struct SingleDelegateKey { + pub generics: ImplGenerics, + pub ty: Type, +} + +impl Parse for SingleDelegateKey { + fn parse(input: ParseStream) -> syn::Result { + let generics = input.parse()?; + let ty = input.parse()?; + + Ok(Self { generics, ty }) + } +} + +impl EvalDelegateKey for SingleDelegateKey { + fn eval(&self) -> syn::Result> { + let key = EvaluatedDelegateKey { + generics: self.generics.generics.clone(), + key: self.ty.clone(), + }; + + Ok(vec![key]) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/mapping/combined.rs b/crates/cgp-macro-core/src/types/delegate_component/mapping/combined.rs new file mode 100644 index 00000000..7a1a8354 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/mapping/combined.rs @@ -0,0 +1,58 @@ +use syn::Type; +use syn::parse::{Parse, ParseStream}; + +use crate::types::delegate_component::{ + DelegateMode, DirectDelegateMapping, EvalDelegateEntries, EvaluatedDelegateEntry, + ExtractInnerDelegateTables, InnerDelegateTable, NormalDelegateMapping, RedirectDelegateMapping, +}; + +#[derive(Debug, Clone)] +pub enum DelegateMapping { + Normal(NormalDelegateMapping), + Direct(DirectDelegateMapping), + Redirect(RedirectDelegateMapping), +} + +impl Parse for DelegateMapping { + fn parse(input: ParseStream) -> syn::Result { + let key = input.parse()?; + let mode: DelegateMode = input.parse()?; + + let entry = match mode { + DelegateMode::Normal(colon) => { + let value = input.parse()?; + Self::Normal(NormalDelegateMapping { key, colon, value }) + } + DelegateMode::Direct(arrow) => { + let value = input.parse()?; + Self::Direct(DirectDelegateMapping { key, arrow, value }) + } + DelegateMode::Redirect(arrow) => { + let value = input.parse()?; + Self::Redirect(RedirectDelegateMapping { key, arrow, value }) + } + }; + + Ok(entry) + } +} + +impl EvalDelegateEntries for DelegateMapping { + fn eval_entries(&self, table_type: &Type) -> syn::Result> { + match self { + Self::Normal(entry) => entry.eval_entries(table_type), + Self::Direct(entry) => entry.eval_entries(table_type), + Self::Redirect(entry) => entry.eval_entries(table_type), + } + } +} + +impl ExtractInnerDelegateTables for DelegateMapping { + fn extract_inner_tables(&self) -> Vec { + match self { + Self::Normal(entry) => entry.extract_inner_tables(), + Self::Direct(entry) => entry.extract_inner_tables(), + Self::Redirect(_entry) => Vec::new(), + } + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/mapping/direct.rs b/crates/cgp-macro-core/src/types/delegate_component/mapping/direct.rs new file mode 100644 index 00000000..e27694de --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/mapping/direct.rs @@ -0,0 +1,58 @@ +use syn::token::RArrow; +use syn::{Type, parse_quote}; + +use crate::exports::DelegateComponent; +use crate::types::delegate_component::{ + DelegateKey, DelegateValue, EvalDelegateEntries, EvalDelegateKey, EvalDelegateValue, + EvaluatedDelegateEntry, ExtractInnerDelegateTables, InnerDelegateTable, +}; + +#[derive(Debug, Clone)] +pub struct DirectDelegateMapping { + pub key: DelegateKey, + pub arrow: RArrow, + pub value: DelegateValue, +} + +impl EvalDelegateEntries for DirectDelegateMapping { + fn eval_entries(&self, table_type: &Type) -> syn::Result> { + let keys = self.key.eval()?; + let value_type = self.value.eval()?; + + let entries = keys + .into_iter() + .map(|key| { + let key_type = key.key; + let mut generics = key.generics; + + let where_predicate = parse_quote! { + #value_type: #DelegateComponent< #key_type > + }; + + generics + .make_where_clause() + .predicates + .push(where_predicate); + + let direct_value_type = parse_quote! { + < #value_type as #DelegateComponent< #key_type > >::Delegate + }; + + EvaluatedDelegateEntry { + table_type: table_type.clone(), + generics, + key: key_type, + value: direct_value_type, + } + }) + .collect(); + + Ok(entries) + } +} + +impl ExtractInnerDelegateTables for DirectDelegateMapping { + fn extract_inner_tables(&self) -> Vec { + self.value.extract_inner_tables() + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/mapping/eval.rs b/crates/cgp-macro-core/src/types/delegate_component/mapping/eval.rs new file mode 100644 index 00000000..70da8f30 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/mapping/eval.rs @@ -0,0 +1,95 @@ +use quote::quote; +use syn::{Generics, ItemImpl, Type, parse_quote, parse2}; + +use crate::exports::{DelegateComponent, IsProviderFor}; +use crate::functions::merge_generics; + +pub struct EvaluatedDelegateEntry { + pub table_type: Type, + pub generics: Generics, + pub key: Type, + pub value: Type, +} + +pub trait EvalDelegateEntry { + fn eval_entry(&self, table_type: &Type) -> syn::Result; +} + +pub trait EvalDelegateEntries { + fn eval_entries(&self, table_type: &Type) -> syn::Result>; +} + +impl EvaluatedDelegateEntry { + pub fn build_delegate_component_impl( + &self, + outer_generics: &Generics, + ) -> syn::Result { + let table_type = &self.table_type; + + let generics = merge_generics(outer_generics, &self.generics); + + let key = &self.key; + let value = &self.value; + + let (impl_generics, _, where_clause) = generics.split_for_impl(); + + parse2(quote! { + impl #impl_generics + #DelegateComponent< #key > + for #table_type + #where_clause + { + type Delegate = #value; + } + }) + } + + pub fn build_is_provider_for_impl(&self, outer_generics: &Generics) -> syn::Result { + let table_type = &self.table_type; + + let mut generics = merge_generics(outer_generics, &self.generics); + + let key = &self.key; + let value = &self.value; + + generics.params.push(parse_quote!(__Context__)); + generics.params.push(parse_quote!(__Params__)); + + generics.make_where_clause().predicates.push(parse_quote! { + #value: #IsProviderFor<#key, __Context__, __Params__> + }); + + let (impl_generics, _, where_clause) = generics.split_for_impl(); + + parse2(quote! { + impl #impl_generics + #IsProviderFor< #key, __Context__, __Params__ > + for #table_type + #where_clause + {} + }) + } + + pub fn build_namespace_impl( + &self, + namespace_trait: &Type, + outer_generics: &Generics, + ) -> syn::Result { + let generics = merge_generics(outer_generics, &self.generics); + + let key = &self.key; + let value = &self.value; + + let (impl_generics, _, where_clause) = generics.split_for_impl(); + + parse2(quote! { + impl #impl_generics + #namespace_trait + for #key + #where_clause + { + type Delegate = #value; + } + }) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/mapping/mod.rs b/crates/cgp-macro-core/src/types/delegate_component/mapping/mod.rs new file mode 100644 index 00000000..cf054474 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/mapping/mod.rs @@ -0,0 +1,13 @@ +mod combined; +mod direct; +mod eval; +mod mode; +mod normal; +mod redirect; + +pub use combined::*; +pub use direct::*; +pub use eval::*; +pub use mode::*; +pub use normal::*; +pub use redirect::*; diff --git a/crates/cgp-macro-core/src/types/delegate_component/mapping/mode.rs b/crates/cgp-macro-core/src/types/delegate_component/mapping/mode.rs new file mode 100644 index 00000000..eb8e9b8e --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/mapping/mode.rs @@ -0,0 +1,20 @@ +use syn::parse::{Parse, ParseStream}; +use syn::token::{Colon, FatArrow, RArrow}; + +pub enum DelegateMode { + Normal(Colon), + Direct(RArrow), + Redirect(FatArrow), +} + +impl Parse for DelegateMode { + fn parse(input: ParseStream) -> syn::Result { + if input.peek(RArrow) { + Ok(Self::Direct(input.parse()?)) + } else if input.peek(FatArrow) { + Ok(Self::Redirect(input.parse()?)) + } else { + Ok(Self::Normal(input.parse()?)) + } + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/mapping/normal.rs b/crates/cgp-macro-core/src/types/delegate_component/mapping/normal.rs new file mode 100644 index 00000000..7c036cef --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/mapping/normal.rs @@ -0,0 +1,51 @@ +use syn::Type; +use syn::parse::{Parse, ParseStream}; +use syn::token::Colon; + +use crate::types::delegate_component::{ + DelegateKey, DelegateValue, EvalDelegateEntries, EvalDelegateKey, EvalDelegateValue, + EvaluatedDelegateEntry, ExtractInnerDelegateTables, InnerDelegateTable, +}; + +#[derive(Debug, Clone)] +pub struct NormalDelegateMapping { + pub key: DelegateKey, + pub colon: Colon, + pub value: DelegateValue, +} + +impl Parse for NormalDelegateMapping { + fn parse(input: ParseStream) -> syn::Result { + let key = input.parse()?; + let colon = input.parse()?; + let value = input.parse()?; + + Ok(Self { key, colon, value }) + } +} + +impl EvalDelegateEntries for NormalDelegateMapping { + fn eval_entries(&self, table_type: &Type) -> syn::Result> { + let keys = self.key.eval()?; + let value_type = self.value.eval()?; + + let mut entries = Vec::new(); + + for key in keys { + entries.push(EvaluatedDelegateEntry { + table_type: table_type.clone(), + generics: key.generics, + key: key.key, + value: value_type.clone(), + }) + } + + Ok(entries) + } +} + +impl ExtractInnerDelegateTables for NormalDelegateMapping { + fn extract_inner_tables(&self) -> Vec { + self.value.extract_inner_tables() + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs b/crates/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs new file mode 100644 index 00000000..5e3f1558 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/mapping/redirect.rs @@ -0,0 +1,47 @@ +use syn::token::FatArrow; +use syn::{Type, parse_quote}; + +use crate::exports::RedirectLookup; +use crate::types::delegate_component::{ + DelegateKey, EvalDelegateEntries, EvalDelegateKey, EvaluatedDelegateEntry, +}; +use crate::types::path::UniPath; + +#[derive(Debug, Clone)] +pub struct RedirectDelegateMapping { + pub key: DelegateKey, + pub arrow: FatArrow, + pub value: UniPath, +} + +impl EvalDelegateEntries for RedirectDelegateMapping { + fn eval_entries(&self, table_type: &Type) -> syn::Result> { + let value_type: Type = match &self.key { + DelegateKey::Path(_) => { + let prefix = self.value.clone().to_prefix(parse_quote!(__Wildcard__)); + parse_quote! { + #RedirectLookup<#table_type, #prefix> + } + } + _ => { + let path = &self.value; + parse_quote!(#RedirectLookup<#table_type, #path>) + } + }; + + let mut entries = Vec::new(); + + for key in self.key.eval()? { + let entry = EvaluatedDelegateEntry { + table_type: table_type.clone(), + generics: key.generics, + key: key.key, + value: value_type.clone(), + }; + + entries.push(entry); + } + + Ok(entries) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/mod.rs b/crates/cgp-macro-core/src/types/delegate_component/mod.rs new file mode 100644 index 00000000..30440c2c --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/mod.rs @@ -0,0 +1,13 @@ +mod entries; +mod key; +mod mapping; +mod statement; +mod table; +mod value; + +pub use entries::*; +pub use key::*; +pub use mapping::*; +pub use statement::*; +pub use table::*; +pub use value::*; diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/combined.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/combined.rs new file mode 100644 index 00000000..53c40386 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/combined.rs @@ -0,0 +1,50 @@ +use syn::parse::{Parse, ParseStream}; +use syn::token::For; +use syn::{Error, Type}; + +use crate::traits::PeekKeyword; +use crate::types::delegate_component::{ + EvalDelegateEntries, EvaluatedDelegateEntry, ForDelegateStatement, NamespaceDelegateStatement, + OpenDelegateStatement, +}; +use crate::types::keywords::{Namespace, Open}; + +#[derive(Debug, Clone)] +pub enum DelegateStatement { + Namespace(NamespaceDelegateStatement), + Open(OpenDelegateStatement), + For(Box), +} + +impl DelegateStatement { + pub fn peek_statement(input: ParseStream) -> bool { + input.peek_keyword::() || input.peek_keyword::() || input.peek(For) + } +} + +impl Parse for DelegateStatement { + fn parse(input: ParseStream) -> syn::Result { + if input.peek_keyword::() { + let namespace_entry = input.parse()?; + Ok(Self::Namespace(namespace_entry)) + } else if input.peek_keyword::() { + let open_entry = input.parse()?; + Ok(Self::Open(open_entry)) + } else if input.peek(For) { + let for_entry = input.parse()?; + Ok(Self::For(for_entry)) + } else { + Err(Error::new(input.span(), "invalid delegate statement")) + } + } +} + +impl EvalDelegateEntries for DelegateStatement { + fn eval_entries(&self, table_type: &Type) -> syn::Result> { + match self { + Self::Namespace(entry) => entry.eval_entries(table_type), + Self::Open(entry) => entry.eval_entries(table_type), + Self::For(entry) => entry.eval_entries(table_type), + } + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs new file mode 100644 index 00000000..8a47c5b5 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/eval.rs @@ -0,0 +1,83 @@ +use syn::{Generics, Ident, Type, parse_quote}; + +use crate::types::delegate_component::{EvalDelegateEntry, EvaluatedDelegateEntry}; +use crate::types::generics::TypeGenerics; + +pub trait EvalForEntries { + fn eval_for_entries(&self, table_type: &Type) -> syn::Result>; +} + +pub trait EvalForEntry { + fn eval_for_entry(&self, table_type: &Type) -> syn::Result; +} + +pub struct EvaluatedForEntry { + pub generics: Generics, + pub table_type: Type, + pub for_key: Ident, + pub for_value: Ident, + pub namespace_ident: Ident, + pub namespace_generics: TypeGenerics, + pub mapping_key: Type, + pub mapping_value: Type, +} + +pub fn eval_delegate_entries_via_for( + entry: &Entry, + table_type: &Type, +) -> syn::Result> +where + Entry: EvalForEntries, +{ + let mut entries = Vec::new(); + + let for_entries = entry.eval_for_entries(table_type)?; + for for_entry in for_entries { + entries.push(for_entry.eval_entry(table_type)?); + } + + Ok(entries) +} + +impl EvalDelegateEntry for EvaluatedForEntry { + fn eval_entry(&self, _table_type: &Type) -> syn::Result { + let for_key = &self.for_key; + let for_value = &self.for_value; + let mapping_value = &self.mapping_value; + let table_type = &self.table_type; + + let namespace_trait: Type = { + let namespace_ident = &self.namespace_ident; + let mut namespace_generics = self.namespace_generics.clone(); + + namespace_generics + .generics + .params + .push(parse_quote!(#table_type)); + + namespace_generics.generics.params.push(parse_quote! { + Delegate = #mapping_value + }); + + parse_quote!( #namespace_ident #namespace_generics ) + }; + + let mut generics = self.generics.clone(); + generics.params.push(parse_quote!(#for_key)); + generics.params.push(parse_quote!(#for_value)); + + let where_clause = generics.make_where_clause(); + where_clause.predicates.push(parse_quote! { + #for_key: #namespace_trait + }); + + let entry = EvaluatedDelegateEntry { + table_type: table_type.clone(), + generics, + key: self.mapping_key.clone(), + value: self.mapping_value.clone(), + }; + + Ok(entry) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs new file mode 100644 index 00000000..511c633a --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/for_loop.rs @@ -0,0 +1,92 @@ +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::{Comma, For, Gt, In, Lt}; +use syn::{Ident, Type, WhereClause, braced}; + +use crate::types::delegate_component::{ + EvalDelegateEntries, EvalDelegateKey, EvalDelegateValue, EvalForEntries, + EvaluatedDelegateEntry, EvaluatedForEntry, NormalDelegateMapping, + eval_delegate_entries_via_for, +}; +use crate::types::ident_type::IdentType; + +#[derive(Debug, Clone)] +pub struct ForDelegateStatement { + pub for_token: For, + pub lt: Lt, + pub key: Ident, + pub comma: Comma, + pub value: Ident, + pub gt: Gt, + pub in_token: In, + pub namespace: IdentType, + pub where_clause: Option, + pub mappings: Punctuated, +} + +impl Parse for ForDelegateStatement { + fn parse(input: ParseStream) -> syn::Result { + let for_token = input.parse()?; + let lt = input.parse()?; + let key = input.parse()?; + let comma = input.parse()?; + let value = input.parse()?; + let gt = input.parse()?; + let in_token = input.parse()?; + let namespace = input.parse()?; + let where_clause = input.parse()?; + + let mappings = { + let body; + braced!(body in input); + Punctuated::parse_terminated(&body)? + }; + + Ok(Self { + for_token, + lt, + key, + comma, + value, + gt, + in_token, + namespace, + where_clause, + mappings, + }) + } +} + +impl EvalForEntries for ForDelegateStatement { + fn eval_for_entries(&self, table_type: &Type) -> syn::Result> { + let mut entries = Vec::new(); + + for mapping in &self.mappings { + let keys = mapping.key.eval()?; + let value_type = mapping.value.eval()?; + + for key in keys { + let entry = EvaluatedForEntry { + generics: key.generics, + table_type: table_type.clone(), + for_key: self.key.clone(), + for_value: self.value.clone(), + namespace_ident: self.namespace.ident.clone(), + namespace_generics: self.namespace.generics.clone(), + mapping_key: key.key, + mapping_value: value_type.clone(), + }; + + entries.push(entry); + } + } + + Ok(entries) + } +} + +impl EvalDelegateEntries for ForDelegateStatement { + fn eval_entries(&self, table_type: &Type) -> syn::Result> { + eval_delegate_entries_via_for(self, table_type) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/mod.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/mod.rs new file mode 100644 index 00000000..a33bf11f --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/mod.rs @@ -0,0 +1,11 @@ +mod combined; +mod eval; +mod for_loop; +mod namespace; +mod open; + +pub use combined::*; +pub use eval::*; +pub use for_loop::*; +pub use namespace::*; +pub use open::*; diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/namespace.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/namespace.rs new file mode 100644 index 00000000..81074ae3 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/namespace.rs @@ -0,0 +1,62 @@ +use syn::parse::{Parse, ParseStream}; +use syn::token::Semi; +use syn::{Generics, Ident, Type, parse_quote}; + +use crate::types::delegate_component::{ + EvalDelegateEntries, EvalForEntries, EvalForEntry, EvaluatedDelegateEntry, EvaluatedForEntry, + eval_delegate_entries_via_for, +}; +use crate::types::generics::TypeGenerics; +use crate::types::keyword::Keyword; +use crate::types::keywords::Namespace; + +#[derive(Debug, Clone)] +pub struct NamespaceDelegateStatement { + pub namespace: Keyword, + pub ident: Ident, + pub semi: Semi, +} + +impl Parse for NamespaceDelegateStatement { + fn parse(input: ParseStream) -> syn::Result { + let namespace = input.parse()?; + let ident = input.parse()?; + let semi = input.parse()?; + + Ok(Self { + namespace, + ident, + semi, + }) + } +} + +impl EvalForEntry for NamespaceDelegateStatement { + fn eval_for_entry(&self, table_type: &Type) -> syn::Result { + let entry = EvaluatedForEntry { + generics: Generics::default(), + table_type: table_type.clone(), + for_key: parse_quote!(__Key__), + for_value: parse_quote!(__Value__), + mapping_key: parse_quote!(__Key__), + mapping_value: parse_quote!(__Value__), + namespace_ident: self.ident.clone(), + namespace_generics: TypeGenerics::default(), + }; + + Ok(entry) + } +} + +impl EvalForEntries for NamespaceDelegateStatement { + fn eval_for_entries(&self, table_type: &Type) -> syn::Result> { + let entry = self.eval_for_entry(table_type)?; + Ok(vec![entry]) + } +} + +impl EvalDelegateEntries for NamespaceDelegateStatement { + fn eval_entries(&self, table_type: &Type) -> syn::Result> { + eval_delegate_entries_via_for(self, table_type) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/statement/open.rs b/crates/cgp-macro-core/src/types/delegate_component/statement/open.rs new file mode 100644 index 00000000..29f99539 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/statement/open.rs @@ -0,0 +1,63 @@ +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::{Comma, Semi}; +use syn::{Type, braced, parse_quote}; + +use crate::exports::{Nil, PathCons, RedirectLookup}; +use crate::types::delegate_component::{EvalDelegateEntries, EvaluatedDelegateEntry}; +use crate::types::keyword::Keyword; +use crate::types::keywords::Open; + +#[derive(Debug, Clone)] +pub struct OpenDelegateStatement { + pub open: Keyword, + pub components: Punctuated, + pub semi: Semi, +} + +impl Parse for OpenDelegateStatement { + fn parse(input: ParseStream) -> syn::Result { + let open = input.parse()?; + + let components: Punctuated = { + let body; + braced!(body in input); + + Punctuated::parse_terminated(&body)? + }; + + let semi = input.parse()?; + + Ok(Self { + open, + components, + semi, + }) + } +} + +impl EvalDelegateEntries for OpenDelegateStatement { + fn eval_entries(&self, table_type: &Type) -> syn::Result> { + let mut entries = Vec::new(); + + for component in &self.components { + let value: Type = parse_quote! { + #RedirectLookup< + #table_type, + #PathCons<#component, #Nil>, + > + }; + + let key = component.clone(); + + entries.push(EvaluatedDelegateEntry { + table_type: table_type.clone(), + generics: Default::default(), + key, + value, + }) + } + + Ok(entries) + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/table/inner.rs b/crates/cgp-macro-core/src/types/delegate_component/table/inner.rs new file mode 100644 index 00000000..d9777820 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/table/inner.rs @@ -0,0 +1,66 @@ +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::{Ident, ItemImpl, Type, braced, parse2}; + +use crate::types::delegate_component::DelegateEntries; +use crate::types::generics::TypeGenerics; +use crate::types::provider_struct::ProviderStruct; + +pub trait ExtractInnerDelegateTables { + fn extract_inner_tables(&self) -> Vec; +} + +#[derive(Debug, Clone)] +pub struct InnerDelegateTable { + pub table_ident: Ident, + pub table_generics: TypeGenerics, + pub entries: DelegateEntries, +} + +impl Parse for InnerDelegateTable { + fn parse(input: ParseStream) -> syn::Result { + let table_ident = input.parse()?; + + let table_generics: TypeGenerics = input.parse()?; + + let entries = { + let body; + braced!(body in input); + + body.parse()? + }; + + Ok(Self { + table_ident, + table_generics, + entries, + }) + } +} + +impl InnerDelegateTable { + pub fn build_table_type(&self) -> syn::Result { + let ident = &self.table_ident; + let type_generics = self.table_generics.split_for_impl().1; + + parse2(quote!( #ident #type_generics )) + } + + pub fn build_table_struct(&self) -> ProviderStruct { + let ident = self.table_ident.clone(); + let generics = self.table_generics.generics.clone(); + + ProviderStruct { ident, generics } + } + + pub fn build_impls(&self) -> syn::Result> { + let table_type = self.build_table_type()?; + self.entries.build_impls(&table_type, &self.table_generics) + } +} + +impl ExtractInnerDelegateTables for InnerDelegateTable { + fn extract_inner_tables(&self) -> Vec { + self.entries.extract_inner_tables() + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/table/main.rs b/crates/cgp-macro-core/src/types/delegate_component/table/main.rs new file mode 100644 index 00000000..6a5bb9db --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/table/main.rs @@ -0,0 +1,100 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::parse::{Parse, ParseStream}; +use syn::{ItemImpl, ItemStruct, Type, braced, parse2}; + +use crate::traits::PeekKeyword; +use crate::types::delegate_component::{DelegateEntries, ExtractInnerDelegateTables}; +use crate::types::generics::ImplGenerics; +use crate::types::ident_type::IdentType; +use crate::types::keyword::Keyword; +use crate::types::keywords::New; +use crate::types::provider_struct::ProviderStruct; + +pub struct DelegateTable { + pub impl_generics: ImplGenerics, + pub new: Option>, + pub table_type: Type, + pub entries: DelegateEntries, +} + +pub struct EvaluatedDelegateTable { + pub item_impls: Vec, + pub item_structs: Vec, +} + +impl Parse for DelegateTable { + fn parse(input: ParseStream) -> syn::Result { + let impl_generics = input.parse()?; + + let new = if input.peek_keyword::() { + Some(input.parse()?) + } else { + None + }; + + let table_type = input.parse()?; + + let entries = { + let body; + braced!(body in input); + + body.parse()? + }; + + Ok(Self { + impl_generics, + new, + table_type, + entries, + }) + } +} + +impl DelegateTable { + pub fn eval(&self) -> syn::Result { + let mut item_impls = Vec::new(); + let mut item_structs = Vec::new(); + + if self.new.is_some() { + let struct_type: IdentType = parse2(self.table_type.to_token_stream())?; + item_structs.push( + ProviderStruct { + ident: struct_type.ident, + generics: struct_type.generics.generics, + } + .to_item_struct()?, + ); + } + + item_impls.extend( + self.entries + .build_impls(&self.table_type, &self.impl_generics)?, + ); + + let inner_tables = self.entries.extract_inner_tables(); + + for inner_table in inner_tables { + item_structs.push(inner_table.build_table_struct().to_item_struct()?); + + item_impls.extend(inner_table.build_impls()?); + } + + Ok(EvaluatedDelegateTable { + item_impls, + item_structs, + }) + } +} + +impl ToTokens for EvaluatedDelegateTable { + fn to_tokens(&self, tokens: &mut TokenStream) { + for item_struct in &self.item_structs { + item_struct.to_tokens(tokens); + } + + for item_impl in &self.item_impls { + item_impl.to_tokens(tokens); + } + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/table/mod.rs b/crates/cgp-macro-core/src/types/delegate_component/table/mod.rs new file mode 100644 index 00000000..0e43a88d --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/table/mod.rs @@ -0,0 +1,5 @@ +mod inner; +mod main; + +pub use inner::*; +pub use main::*; diff --git a/crates/cgp-macro-core/src/types/delegate_component/value/combined.rs b/crates/cgp-macro-core/src/types/delegate_component/value/combined.rs new file mode 100644 index 00000000..bce6fb69 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/value/combined.rs @@ -0,0 +1,45 @@ +use syn::Type; +use syn::parse::discouraged::Speculative; +use syn::parse::{Parse, ParseStream}; + +use crate::types::delegate_component::{ + DelegateValueWithInnerTable, EvalDelegateValue, ExtractInnerDelegateTables, InnerDelegateTable, +}; + +#[derive(Debug, Clone)] +pub enum DelegateValue { + Type(Type), + WithTable(DelegateValueWithInnerTable), +} + +impl Parse for DelegateValue { + fn parse(input: ParseStream) -> syn::Result { + let fork = input.fork(); + + if let Ok(value) = fork.parse::() { + input.advance_to(&fork); + return Ok(Self::WithTable(value)); + } + + let ty: Type = input.parse()?; + Ok(Self::Type(ty)) + } +} + +impl EvalDelegateValue for DelegateValue { + fn eval(&self) -> syn::Result { + match self { + Self::Type(ty) => Ok(ty.clone()), + Self::WithTable(value) => value.eval(), + } + } +} + +impl ExtractInnerDelegateTables for DelegateValue { + fn extract_inner_tables(&self) -> Vec { + match self { + Self::Type(_) => Vec::new(), + Self::WithTable(value) => value.extract_inner_tables(), + } + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/value/eval.rs b/crates/cgp-macro-core/src/types/delegate_component/value/eval.rs new file mode 100644 index 00000000..77accf66 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/value/eval.rs @@ -0,0 +1,5 @@ +use syn::Type; + +pub trait EvalDelegateValue { + fn eval(&self) -> syn::Result; +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/value/inner_table.rs b/crates/cgp-macro-core/src/types/delegate_component/value/inner_table.rs new file mode 100644 index 00000000..d09e42c0 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/value/inner_table.rs @@ -0,0 +1,56 @@ +use syn::parse::{Parse, ParseStream}; +use syn::token::{Gt, Lt}; +use syn::{Ident, Type, parse_quote}; + +use crate::types::delegate_component::{ + EvalDelegateValue, ExtractInnerDelegateTables, InnerDelegateTable, +}; +use crate::types::keyword::Keyword; +use crate::types::keywords::New; + +#[derive(Debug, Clone)] +pub struct DelegateValueWithInnerTable { + pub new: Keyword, + pub wrapper_ident: Ident, + pub inner_table: InnerDelegateTable, +} + +impl Parse for DelegateValueWithInnerTable { + fn parse(input: ParseStream) -> syn::Result { + let wrapper_ident = input.parse()?; + + let _: Lt = input.parse()?; + + let new = input.parse()?; + + let inner_table = input.parse()?; + + let _: Gt = input.parse()?; + + Ok(Self { + new, + wrapper_ident, + inner_table, + }) + } +} + +impl EvalDelegateValue for DelegateValueWithInnerTable { + fn eval(&self) -> syn::Result { + let wrapper_ident = &self.wrapper_ident; + let struct_ident = &self.inner_table.table_ident; + let struct_generics = &self.inner_table.table_generics; + + let ty = parse_quote!( #wrapper_ident < #struct_ident #struct_generics > ); + Ok(ty) + } +} + +impl ExtractInnerDelegateTables for DelegateValueWithInnerTable { + fn extract_inner_tables(&self) -> Vec { + let mut inner_tables = self.inner_table.extract_inner_tables(); + inner_tables.push(self.inner_table.clone()); + + inner_tables + } +} diff --git a/crates/cgp-macro-core/src/types/delegate_component/value/mod.rs b/crates/cgp-macro-core/src/types/delegate_component/value/mod.rs new file mode 100644 index 00000000..27b36a52 --- /dev/null +++ b/crates/cgp-macro-core/src/types/delegate_component/value/mod.rs @@ -0,0 +1,7 @@ +mod combined; +mod eval; +mod inner_table; + +pub use combined::*; +pub use eval::*; +pub use inner_table::*; diff --git a/crates/cgp-macro-lib/src/parse/impl_generics.rs b/crates/cgp-macro-core/src/types/generics/impl_generics.rs similarity index 68% rename from crates/cgp-macro-lib/src/parse/impl_generics.rs rename to crates/cgp-macro-core/src/types/generics/impl_generics.rs index 7828aed8..614b50b1 100644 --- a/crates/cgp-macro-lib/src/parse/impl_generics.rs +++ b/crates/cgp-macro-core/src/types/generics/impl_generics.rs @@ -1,17 +1,26 @@ +use core::ops::{Deref, DerefMut}; + use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; -use syn::{Error, Generics, TypeGenerics, parse2}; +use syn::{Error, Generics, parse2}; -#[derive(Clone, Default)] +#[derive(Debug, Clone, Default)] pub struct ImplGenerics { pub generics: Generics, } -impl ImplGenerics { - pub fn as_type_generics(&self) -> TypeGenerics<'_> { - let (_, type_generics, _) = self.generics.split_for_impl(); - type_generics +impl Deref for ImplGenerics { + type Target = Generics; + + fn deref(&self) -> &Generics { + &self.generics + } +} + +impl DerefMut for ImplGenerics { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.generics } } diff --git a/crates/cgp-macro-core/src/types/generics/mod.rs b/crates/cgp-macro-core/src/types/generics/mod.rs new file mode 100644 index 00000000..9d6eafc8 --- /dev/null +++ b/crates/cgp-macro-core/src/types/generics/mod.rs @@ -0,0 +1,5 @@ +mod impl_generics; +mod type_generics; + +pub use impl_generics::*; +pub use type_generics::*; diff --git a/crates/cgp-macro-lib/src/parse/type_generics.rs b/crates/cgp-macro-core/src/types/generics/type_generics.rs similarity index 77% rename from crates/cgp-macro-lib/src/parse/type_generics.rs rename to crates/cgp-macro-core/src/types/generics/type_generics.rs index c4620438..4924f0d3 100644 --- a/crates/cgp-macro-lib/src/parse/type_generics.rs +++ b/crates/cgp-macro-core/src/types/generics/type_generics.rs @@ -1,13 +1,29 @@ +use core::ops::{Deref, DerefMut}; + use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; use syn::{Error, Generics, parse2}; -#[derive(Clone, Default)] +#[derive(Debug, Clone, Default)] pub struct TypeGenerics { pub generics: Generics, } +impl Deref for TypeGenerics { + type Target = Generics; + + fn deref(&self) -> &Generics { + &self.generics + } +} + +impl DerefMut for TypeGenerics { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.generics + } +} + impl Parse for TypeGenerics { fn parse(input: ParseStream) -> syn::Result { let generics: Generics = input.parse()?; diff --git a/crates/cgp-macro-core/src/types/ident_type.rs b/crates/cgp-macro-core/src/types/ident_type.rs new file mode 100644 index 00000000..2578807c --- /dev/null +++ b/crates/cgp-macro-core/src/types/ident_type.rs @@ -0,0 +1,19 @@ +use syn::Ident; +use syn::parse::{Parse, ParseStream}; + +use crate::types::generics::TypeGenerics; + +#[derive(Debug, Clone)] +pub struct IdentType { + pub ident: Ident, + pub generics: TypeGenerics, +} + +impl Parse for IdentType { + fn parse(input: ParseStream) -> syn::Result { + let ident = input.parse()?; + let generics = input.parse()?; + + Ok(Self { ident, generics }) + } +} diff --git a/crates/cgp-macro-core/src/types/keyword.rs b/crates/cgp-macro-core/src/types/keyword.rs new file mode 100644 index 00000000..812e3467 --- /dev/null +++ b/crates/cgp-macro-core/src/types/keyword.rs @@ -0,0 +1,58 @@ +use core::fmt::Debug; +use core::marker::PhantomData; + +use proc_macro2::Span; +use syn::parse::{Parse, ParseStream}; +use syn::{Error, Ident}; + +use crate::traits::IsKeyword; + +pub struct Keyword { + pub span: Span, + pub phantom: PhantomData, +} + +impl Default for Keyword { + fn default() -> Self { + Self { + span: Span::call_site(), + phantom: PhantomData, + } + } +} + +impl Debug for Keyword { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("keyword").field("ident", &K::IDENT).finish() + } +} + +impl Clone for Keyword { + fn clone(&self) -> Self { + Self { + span: self.span, + phantom: PhantomData, + } + } +} + +impl Parse for Keyword +where + K: IsKeyword, +{ + fn parse(input: ParseStream) -> syn::Result { + let ident: Ident = input.parse()?; + + if ident != K::IDENT { + return Err(Error::new_spanned( + ident, + format!("expect keyword: `{}`", K::IDENT), + )); + } + + Ok(Self { + span: ident.span(), + phantom: PhantomData, + }) + } +} diff --git a/crates/cgp-macro-core/src/types/keywords.rs b/crates/cgp-macro-core/src/types/keywords.rs new file mode 100644 index 00000000..124f505a --- /dev/null +++ b/crates/cgp-macro-core/src/types/keywords.rs @@ -0,0 +1,7 @@ +use crate::define_keyword; + +define_keyword!(New, "new"); + +define_keyword!(Namespace, "namespace"); + +define_keyword!(Open, "open"); diff --git a/crates/cgp-macro-core/src/types/mod.rs b/crates/cgp-macro-core/src/types/mod.rs new file mode 100644 index 00000000..166a4e6d --- /dev/null +++ b/crates/cgp-macro-core/src/types/mod.rs @@ -0,0 +1,9 @@ +pub mod delegate_component; +pub mod generics; +pub mod ident_type; +pub mod keyword; +pub mod keywords; +pub mod namespace; +pub mod path; +pub mod provider_struct; +pub mod symbol; diff --git a/crates/cgp-macro-core/src/types/namespace/eval.rs b/crates/cgp-macro-core/src/types/namespace/eval.rs new file mode 100644 index 00000000..5fa14135 --- /dev/null +++ b/crates/cgp-macro-core/src/types/namespace/eval.rs @@ -0,0 +1,25 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{ItemImpl, ItemStruct, ItemTrait}; + +pub struct EvaluatedNamespaceTable { + pub item_impls: Vec, + pub item_trait: Option, + pub item_struct: Option, +} + +impl ToTokens for EvaluatedNamespaceTable { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(item_struct) = &self.item_struct { + item_struct.to_tokens(tokens); + } + + if let Some(item_trait) = &self.item_trait { + item_trait.to_tokens(tokens); + } + + for item_impl in &self.item_impls { + item_impl.to_tokens(tokens); + } + } +} diff --git a/crates/cgp-macro-core/src/types/namespace/ident.rs b/crates/cgp-macro-core/src/types/namespace/ident.rs new file mode 100644 index 00000000..2aa80364 --- /dev/null +++ b/crates/cgp-macro-core/src/types/namespace/ident.rs @@ -0,0 +1,18 @@ +use syn::Ident; +use syn::parse::{Parse, ParseStream}; + +use crate::types::generics::TypeGenerics; + +pub struct NamespaceIdent { + pub ident: Ident, + pub generics: TypeGenerics, +} + +impl Parse for NamespaceIdent { + fn parse(input: ParseStream) -> syn::Result { + let ident = input.parse()?; + let generics = input.parse()?; + + Ok(Self { ident, generics }) + } +} diff --git a/crates/cgp-macro-core/src/types/namespace/inherit.rs b/crates/cgp-macro-core/src/types/namespace/inherit.rs new file mode 100644 index 00000000..7852a286 --- /dev/null +++ b/crates/cgp-macro-core/src/types/namespace/inherit.rs @@ -0,0 +1,42 @@ +use syn::{Generics, Ident, Type, parse_quote}; + +use crate::types::delegate_component::{EvalForEntry, EvaluatedForEntry}; +use crate::types::generics::TypeGenerics; + +#[derive(Debug, Clone)] +pub struct InheritNamespaceStatement { + pub ident: Ident, + pub type_generics: TypeGenerics, + pub local_table_ident: Ident, +} + +impl EvalForEntry for InheritNamespaceStatement { + fn eval_for_entry(&self, table_type: &Type) -> syn::Result { + let namespace_ident = self.ident.clone(); + let local_table_ident = &self.local_table_ident; + + let mut namespace_where_generics = self.type_generics.clone(); + + namespace_where_generics + .params + .push(parse_quote!(#local_table_ident)); + + let mut generics = Generics::default(); + generics.make_where_clause().predicates.push(parse_quote! { + __Key__: #namespace_ident #namespace_where_generics + }); + + let for_entry = EvaluatedForEntry { + generics, + table_type: table_type.clone(), + for_key: parse_quote!(__Key__), + for_value: parse_quote!(__Value__), + mapping_key: parse_quote!(__Key__), + mapping_value: parse_quote!(__Value__), + namespace_ident, + namespace_generics: self.type_generics.clone(), + }; + + Ok(for_entry) + } +} diff --git a/crates/cgp-macro-core/src/types/namespace/mod.rs b/crates/cgp-macro-core/src/types/namespace/mod.rs new file mode 100644 index 00000000..d8f487b1 --- /dev/null +++ b/crates/cgp-macro-core/src/types/namespace/mod.rs @@ -0,0 +1,9 @@ +mod eval; +mod ident; +mod inherit; +mod table; + +pub use eval::*; +pub use ident::*; +pub use inherit::*; +pub use table::*; diff --git a/crates/cgp-macro-core/src/types/namespace/table.rs b/crates/cgp-macro-core/src/types/namespace/table.rs new file mode 100644 index 00000000..d84b9400 --- /dev/null +++ b/crates/cgp-macro-core/src/types/namespace/table.rs @@ -0,0 +1,168 @@ +use syn::parse::{Parse, ParseStream}; +use syn::token::Colon; +use syn::{Error, Ident, ItemImpl, ItemStruct, ItemTrait, Type, braced, parse_quote}; + +use crate::traits::PeekKeyword; +use crate::types::delegate_component::{ + DelegateEntries, EvalDelegateEntries, EvalDelegateEntry, EvalForEntry, +}; +use crate::types::generics::ImplGenerics; +use crate::types::ident_type::IdentType; +use crate::types::keyword::Keyword; +use crate::types::keywords::New; +use crate::types::namespace::{EvaluatedNamespaceTable, InheritNamespaceStatement}; + +pub struct NamespaceTable { + pub impl_generics: ImplGenerics, + pub new: Option>, + pub namespace_type: IdentType, + pub parent_namespace: Option<(Colon, IdentType)>, + pub entries: DelegateEntries, +} + +impl Parse for NamespaceTable { + fn parse(input: ParseStream) -> syn::Result { + let impl_generics = input.parse()?; + + let new = if input.peek_keyword::() { + Some(input.parse()?) + } else { + None + }; + + let namespace_type = input.parse()?; + let parent_namespace = if input.peek(Colon) { + let colon: Colon = input.parse()?; + let parent_namespace_type = input.parse()?; + Some((colon, parent_namespace_type)) + } else { + None + }; + + let entries = { + let body; + braced!(body in input); + + body.parse()? + }; + + Ok(Self { + impl_generics, + new, + namespace_type, + parent_namespace, + entries, + }) + } +} + +impl NamespaceTable { + pub fn build_namespace_trait(&self) -> syn::Result { + let namespace_ident = &self.namespace_type.ident; + let mut namespace_generics = self.namespace_type.generics.clone(); + namespace_generics.params.push(parse_quote!(__Table__)); + + let namespace_trait: Type = parse_quote!( #namespace_ident #namespace_generics ); + Ok(namespace_trait) + } + + pub fn build_item_trait(&self) -> syn::Result> { + let namespace_trait = self.build_namespace_trait()?; + + let item_trait: Option = if self.new.is_some() { + let item_trait = parse_quote! { + pub trait #namespace_trait { + type Delegate; + } + }; + + Some(item_trait) + } else { + None + }; + + Ok(item_trait) + } + + pub fn build_item_impls(&self) -> syn::Result> { + let mut impl_generics = self.impl_generics.clone(); + impl_generics.params.push(parse_quote!(__Table__)); + + let namespace_trait = self.build_namespace_trait()?; + let table_type: Type = parse_quote!(__Table__); + + let evaluated_entries = self.entries.eval_entries(&table_type)?; + + let mut item_impls: Vec = Vec::new(); + + for evaluated_entry in evaluated_entries { + let item_impl = + evaluated_entry.build_namespace_impl(&namespace_trait, &impl_generics)?; + + item_impls.push(item_impl); + } + + Ok(item_impls) + } + + pub fn build_parent_namespace_impl(&self) -> syn::Result> { + let Some((_, parent_namespace)) = &self.parent_namespace else { + return Ok(None); + }; + + if self.new.is_none() { + return Err(Error::new( + parent_namespace.ident.span(), + "parent namespace can only be specified with `new` namespaces", + )); + } + + let namespace_ident = self.namespace_type.ident.clone(); + + let table_type: Type = parse_quote!(__Table__); + + let namespace_struct_ident = Ident::new( + &format!("__{}Components", namespace_ident), + namespace_ident.span(), + ); + + let namespace_struct: ItemStruct = parse_quote! { + pub struct #namespace_struct_ident; + }; + + let for_entry = InheritNamespaceStatement { + ident: parent_namespace.ident.clone(), + type_generics: parent_namespace.generics.clone(), + local_table_ident: namespace_struct_ident, + } + .eval_for_entry(&table_type)?; + + let evaluated_entry = for_entry.eval_entry(&table_type)?; + + let namespace_trait = self.build_namespace_trait()?; + + let mut generics = self.impl_generics.generics.clone(); + generics.params.push(parse_quote!(#table_type)); + + let item_impl = evaluated_entry.build_namespace_impl(&namespace_trait, &generics)?; + + Ok(Some((namespace_struct, item_impl))) + } + + pub fn eval(&self) -> syn::Result { + let mut item_struct = None; + let item_trait = self.build_item_trait()?; + let mut item_impls = self.build_item_impls()?; + + if let Some((namespace_struct, item_impl)) = self.build_parent_namespace_impl()? { + item_impls.insert(0, item_impl); + item_struct = Some(namespace_struct); + } + + Ok(EvaluatedNamespaceTable { + item_impls, + item_trait, + item_struct, + }) + } +} diff --git a/crates/cgp-macro-core/src/types/path/mod.rs b/crates/cgp-macro-core/src/types/path/mod.rs new file mode 100644 index 00000000..7537b012 --- /dev/null +++ b/crates/cgp-macro-core/src/types/path/mod.rs @@ -0,0 +1,11 @@ +mod path_element; +mod path_head; +mod path_head_or_type; +mod prefix; +mod unipath; + +pub use path_element::*; +pub use path_head::*; +pub use path_head_or_type::*; +pub use prefix::*; +pub use unipath::*; diff --git a/crates/cgp-macro-core/src/types/path/path_element.rs b/crates/cgp-macro-core/src/types/path/path_element.rs new file mode 100644 index 00000000..2e5d8afc --- /dev/null +++ b/crates/cgp-macro-core/src/types/path/path_element.rs @@ -0,0 +1,68 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::parse::{Parse, ParseStream}; +use syn::{Ident, Type, parse2}; + +use crate::traits::ToType; +use crate::types::symbol::Symbol; + +#[derive(Debug, Clone)] +pub enum PathElement { + Type(Type), + Symbol(Symbol), +} + +impl Parse for PathElement { + fn parse(input: ParseStream) -> syn::Result { + let ty: Type = input.parse()?; + + let parsed = if let Ok(path_ident) = parse2::(ty.to_token_stream()) { + let path_str = path_ident.to_string(); + + if let Some(path_char) = path_str.chars().next() + && path_char.is_ascii_lowercase() + && !is_primitive_type(&path_str) + { + Self::Symbol(Symbol { ident: path_ident }) + } else { + Self::Type(ty) + } + } else { + Self::Type(ty) + }; + + Ok(parsed) + } +} + +impl ToType for PathElement { + fn to_type(&self) -> Type { + match self { + Self::Type(ty) => ty.clone(), + Self::Symbol(symbol) => symbol.to_type(), + } + } +} + +impl ToTokens for PathElement { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Type(ty) => ty.to_tokens(tokens), + Self::Symbol(symbol) => symbol.to_tokens(tokens), + } + } +} + +fn is_primitive_type(ident: &str) -> bool { + if (ident.starts_with("i") || ident.starts_with("u") || ident.starts_with("f")) + && ident[1..].chars().all(|c| c.is_numeric()) + { + return true; + } + + if ["char", "bool", "usize", "isize", "str"].contains(&ident) { + return true; + } + + false +} diff --git a/crates/cgp-macro-core/src/types/path/path_head.rs b/crates/cgp-macro-core/src/types/path/path_head.rs new file mode 100644 index 00000000..a0ce9ea6 --- /dev/null +++ b/crates/cgp-macro-core/src/types/path/path_head.rs @@ -0,0 +1,69 @@ +use syn::braced; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::{Brace, Comma, Dot}; + +use crate::types::generics::ImplGenerics; +use crate::types::path::{PathElement, UniPath}; + +#[derive(Debug, Clone)] +pub enum PathHead { + Type(ImplGenerics, Box, Box), + Group(Punctuated), + End, +} + +impl PathHead { + pub fn into_paths(&self) -> Vec<(ImplGenerics, UniPath)> { + match self { + Self::Type(generics, path_element, tail) => { + let tail_paths = tail.into_paths(); + let mut out_paths = Vec::new(); + + for (tail_generics, mut tail_path) in tail_paths { + let mut generics = generics.clone(); + generics.params.extend(tail_generics.params.iter().cloned()); + tail_path.elements.insert(0, path_element.as_ref().clone()); + out_paths.push((generics, tail_path)) + } + + out_paths + } + Self::Group(path_heads) => path_heads + .iter() + .flat_map(|path| path.into_paths()) + .collect(), + Self::End => { + vec![(ImplGenerics::default(), UniPath::default())] + } + } + } +} + +impl Parse for PathHead { + fn parse(input: ParseStream) -> syn::Result { + if input.is_empty() { + Ok(Self::End) + } else if input.peek(Brace) { + let body; + braced!(body in input); + + let group = Punctuated::parse_terminated(&body)?; + + Ok(Self::Group(group)) + } else { + let generics = input.parse()?; + + let path_type: PathElement = input.parse()?; + + let rest_path = if input.peek(Dot) { + let _: Dot = input.parse()?; + Box::new(Self::parse(input)?) + } else { + Box::new(Self::End) + }; + + Ok(Self::Type(generics, Box::new(path_type), rest_path)) + } + } +} diff --git a/crates/cgp-macro-core/src/types/path/path_head_or_type.rs b/crates/cgp-macro-core/src/types/path/path_head_or_type.rs new file mode 100644 index 00000000..7ff473c6 --- /dev/null +++ b/crates/cgp-macro-core/src/types/path/path_head_or_type.rs @@ -0,0 +1,29 @@ +use syn::Type; +use syn::parse::{Parse, ParseStream}; +use syn::token::At; + +use crate::types::generics::ImplGenerics; +use crate::types::path::PathHead; + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] +pub enum PathHeadOrType { + PathHead(PathHead), + Type(ImplGenerics, Type), +} + +impl Parse for PathHeadOrType { + fn parse(input: ParseStream) -> syn::Result { + if input.peek(At) { + let _: At = input.parse()?; + + let path_head = input.parse()?; + + Ok(Self::PathHead(path_head)) + } else { + let generics = input.parse()?; + let ty = input.parse()?; + Ok(Self::Type(generics, ty)) + } + } +} diff --git a/crates/cgp-macro-core/src/types/path/prefix.rs b/crates/cgp-macro-core/src/types/path/prefix.rs new file mode 100644 index 00000000..5d1b4268 --- /dev/null +++ b/crates/cgp-macro-core/src/types/path/prefix.rs @@ -0,0 +1,25 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; +use syn::Type; +use syn::punctuated::Punctuated; +use syn::token::Dot; + +use crate::exports::PathCons; +use crate::types::path::PathElement; + +#[derive(Debug, Clone)] +pub struct PrefixPath { + pub elements: Punctuated, + pub suffix: Type, +} + +impl ToTokens for PrefixPath { + fn to_tokens(&self, tokens: &mut TokenStream) { + let out = self.elements.iter().rev().fold( + self.suffix.to_token_stream(), + |acc, current| quote!( #PathCons < #current, #acc > ), + ); + + tokens.extend(out) + } +} diff --git a/crates/cgp-macro-core/src/types/path/unipath.rs b/crates/cgp-macro-core/src/types/path/unipath.rs new file mode 100644 index 00000000..b0155216 --- /dev/null +++ b/crates/cgp-macro-core/src/types/path/unipath.rs @@ -0,0 +1,56 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; +use syn::Type; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::{At, Dot}; + +use crate::exports::{Nil, PathCons}; +use crate::types::path::{PathElement, PrefixPath}; + +#[derive(Debug, Clone, Default)] +pub struct UniPath { + pub elements: Punctuated, +} + +impl FromIterator for UniPath { + fn from_iter>(elements: T) -> Self { + Self { + elements: Punctuated::from_iter(elements), + } + } +} + +impl UniPath { + pub fn append_type(&mut self, ty: Type) { + self.elements.push(PathElement::Type(ty)); + } + + pub fn to_prefix(self, suffix: Type) -> PrefixPath { + PrefixPath { + elements: self.elements, + suffix, + } + } +} + +impl Parse for UniPath { + fn parse(input: ParseStream) -> syn::Result { + let _: At = input.parse()?; + + let elements = Punctuated::parse_separated_nonempty(input)?; + + Ok(Self { elements }) + } +} + +impl ToTokens for UniPath { + fn to_tokens(&self, tokens: &mut TokenStream) { + let out = self.elements.iter().rev().fold( + quote!(#Nil), + |acc, current| quote!( #PathCons < #current, #acc > ), + ); + + tokens.extend(out) + } +} diff --git a/crates/cgp-macro-core/src/types/provider_struct.rs b/crates/cgp-macro-core/src/types/provider_struct.rs new file mode 100644 index 00000000..21a07bb0 --- /dev/null +++ b/crates/cgp-macro-core/src/types/provider_struct.rs @@ -0,0 +1,51 @@ +use quote::quote; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{GenericParam, Generics, Ident, ItemStruct, Type, parse2}; + +pub struct ProviderStruct { + pub ident: Ident, + pub generics: Generics, +} + +impl ProviderStruct { + pub fn to_item_struct(&self) -> syn::Result { + let struct_ident = &self.ident; + let struct_generics = &self.generics; + + if struct_generics.params.is_empty() { + parse2(quote! { + pub struct #struct_ident; + }) + } else { + let mut generic_params = struct_generics.params.clone(); + let mut phantom_params: Punctuated = Default::default(); + + for param in generic_params.iter_mut() { + match param { + GenericParam::Type(type_param) => { + type_param.colon_token = None; + type_param.bounds.clear(); + + let type_ident = &type_param.ident; + phantom_params.push(parse2(quote!( #type_ident ))?); + } + GenericParam::Lifetime(life_param) => { + life_param.colon_token = None; + life_param.bounds.clear(); + + let lifetime = &life_param.lifetime; + phantom_params.push(parse2(quote!( Life<#lifetime> ))?); + } + _ => {} + } + } + + parse2(quote! { + pub struct #struct_ident < #generic_params > ( + pub ::core::marker::PhantomData<( #phantom_params )> + ); + }) + } + } +} diff --git a/crates/cgp-macro-core/src/types/symbol.rs b/crates/cgp-macro-core/src/types/symbol.rs new file mode 100644 index 00000000..e7081e47 --- /dev/null +++ b/crates/cgp-macro-core/src/types/symbol.rs @@ -0,0 +1,42 @@ +use proc_macro2::{Literal, TokenStream}; +use quote::{ToTokens, quote_spanned}; +use syn::{Ident, Type, parse_quote}; + +use crate::traits::ToType; + +#[derive(Debug, Clone)] +pub struct Symbol { + pub ident: Ident, +} + +impl Symbol { + pub fn new(ident: Ident) -> Self { + Self { ident } + } +} + +impl ToTokens for Symbol { + fn to_tokens(&self, tokens: &mut TokenStream) { + use crate::exports::{Chars, Nil, Symbol}; + + let span = self.ident.span(); + let str_value = self.ident.to_string(); + + let chars = str_value.chars().rev().fold( + quote_spanned!(span => #Nil), + |acc, current| quote_spanned!(span => #Chars < #current, #acc >), + ); + + let len = Literal::usize_unsuffixed(str_value.len()); + + let out = quote_spanned! { span => #Symbol < #len, #chars > }; + + tokens.extend(out); + } +} + +impl ToType for Symbol { + fn to_type(&self) -> Type { + parse_quote!( #self ) + } +} diff --git a/crates/cgp-macro-lib/Cargo.toml b/crates/cgp-macro-lib/Cargo.toml index a490a0e0..44e48059 100644 --- a/crates/cgp-macro-lib/Cargo.toml +++ b/crates/cgp-macro-lib/Cargo.toml @@ -15,6 +15,8 @@ description = """ default = [] [dependencies] +cgp-macro-core = { workspace = true } + syn = { version = "2.0.95", features = [ "full", "extra-traits", "visit", "visit-mut" ] } quote = "1.0.38" proc-macro2 = "1.0.92" diff --git a/crates/cgp-macro-lib/src/attributes/namespace.rs b/crates/cgp-macro-lib/src/attributes/namespace.rs index ef142a5d..31aa51e0 100644 --- a/crates/cgp-macro-lib/src/attributes/namespace.rs +++ b/crates/cgp-macro-lib/src/attributes/namespace.rs @@ -1,37 +1,24 @@ -use quote::quote; +use cgp_macro_core::types::path::UniPath; +use syn::Ident; use syn::parse::{Parse, ParseStream}; -use syn::punctuated::Punctuated; -use syn::token::{At, Colon, Dot}; -use syn::{Ident, Type, parse2}; - -use crate::parse::PathType; +use syn::token::In; pub struct UseNamespaceAttribute { pub namespace: Ident, - pub path: Type, + pub path: UniPath, } impl Parse for UseNamespaceAttribute { fn parse(input: ParseStream) -> syn::Result { - let namespace = if input.peek2(Colon) { - let namespace = input.parse()?; - let _: Colon = input.parse()?; - namespace + let path = input.parse()?; + + let namespace = if input.peek(In) { + let _: In = input.parse()?; + input.parse()? } else { Ident::new("DefaultNamespace", input.span()) }; - let _: At = input.parse()?; - - let paths: Punctuated = Punctuated::parse_separated_nonempty(input)?; - - let raw_path_type = paths.into_iter().rev().fold( - quote!(PathNil), - |tail, PathType { path_type }| quote!(PathCons<#path_type, #tail>), - ); - - let path: Type = parse2(raw_path_type)?; - Ok(UseNamespaceAttribute { namespace, path }) } } diff --git a/crates/cgp-macro-lib/src/cgp_namespace/mod.rs b/crates/cgp-macro-lib/src/cgp_namespace/mod.rs deleted file mode 100644 index cc05df3b..00000000 --- a/crates/cgp-macro-lib/src/cgp_namespace/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod spec; diff --git a/crates/cgp-macro-lib/src/cgp_namespace/spec.rs b/crates/cgp-macro-lib/src/cgp_namespace/spec.rs deleted file mode 100644 index 837b7766..00000000 --- a/crates/cgp-macro-lib/src/cgp_namespace/spec.rs +++ /dev/null @@ -1,83 +0,0 @@ -use quote::quote; -use syn::parse::{Parse, ParseStream}; -use syn::punctuated::Punctuated; -use syn::token::{At, Colon, Comma, Dot, Lt}; -use syn::{Ident, Type, braced, parse2}; - -use crate::parse::{ComponentPath, ComponentPaths, ImplGenerics, PathType}; - -pub struct NamespaceSpec { - pub namespace_ident: Ident, - pub parent_namespace_ident: Option, - pub entries: Punctuated, -} - -pub struct NamespaceEntry { - pub keys: ComponentPaths, - pub value: Type, -} - -impl Parse for NamespaceSpec { - fn parse(input: ParseStream) -> syn::Result { - let namespace_ident: Ident = input.parse()?; - - let parent_namespace_ident: Option = if input.peek(Colon) { - let _: Colon = input.parse()?; - let ident = input.parse()?; - Some(ident) - } else { - None - }; - - let content; - braced!(content in input); - - let entries = Punctuated::parse_terminated(&content)?; - - Ok(NamespaceSpec { - namespace_ident, - parent_namespace_ident, - entries, - }) - } -} - -impl Parse for NamespaceEntry { - fn parse(input: ParseStream) -> syn::Result { - let keys: ComponentPaths = if input.peek(At) { - let _: At = input.parse()?; - - input.parse()? - } else { - let generics: ImplGenerics = if input.peek(Lt) { - input.parse()? - } else { - Default::default() - }; - - let path_type: Type = input.parse()?; - - let path = ComponentPath { - generics, - path_type, - }; - - ComponentPaths { paths: vec![path] } - }; - - let _: Colon = input.parse()?; - - let _: At = input.parse()?; - - let value_path: Punctuated = Punctuated::parse_separated_nonempty(input)?; - - let value = value_path.into_iter().rev().fold( - quote!(PathNil), - |tail, PathType { path_type }| quote!( PathCons< #path_type, #tail > ), - ); - - let value: Type = parse2(value)?; - - Ok(Self { keys, value }) - } -} diff --git a/crates/cgp-macro-lib/src/check_components/derive.rs b/crates/cgp-macro-lib/src/check_components/derive.rs index 28b70a2e..30cbe64d 100644 --- a/crates/cgp-macro-lib/src/check_components/derive.rs +++ b/crates/cgp-macro-lib/src/check_components/derive.rs @@ -1,10 +1,10 @@ +use cgp_macro_core::functions::merge_generics; use quote::quote; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{ItemImpl, ItemTrait, Type, parse2}; use crate::check_components::override_span; -use crate::delegate_components::merge_generics; use crate::parse::{CheckComponents, CheckEntry}; pub fn derive_check_components(spec: &CheckComponents) -> syn::Result<(ItemTrait, Vec)> { diff --git a/crates/cgp-macro-lib/src/delegate_components/define_struct.rs b/crates/cgp-macro-lib/src/delegate_components/define_struct.rs deleted file mode 100644 index 2a4bc308..00000000 --- a/crates/cgp-macro-lib/src/delegate_components/define_struct.rs +++ /dev/null @@ -1,41 +0,0 @@ -use quote::quote; -use syn::punctuated::Punctuated; -use syn::token::Comma; -use syn::{GenericParam, Generics, Ident, ItemStruct, Type, parse2}; - -pub fn define_struct(ident: &Ident, generics: &Generics) -> syn::Result { - if generics.params.is_empty() { - parse2(quote! { - pub struct #ident; - }) - } else { - let mut generic_params = generics.params.clone(); - let mut phantom_params: Punctuated = Default::default(); - - for param in generic_params.iter_mut() { - match param { - GenericParam::Type(type_param) => { - type_param.colon_token = None; - type_param.bounds.clear(); - - let type_ident = &type_param.ident; - phantom_params.push(parse2(quote!( #type_ident ))?); - } - GenericParam::Lifetime(life_param) => { - life_param.colon_token = None; - life_param.bounds.clear(); - - let lifetime = &life_param.lifetime; - phantom_params.push(parse2(quote!( Life<#lifetime> ))?); - } - _ => {} - } - } - - parse2(quote! { - pub struct #ident < #generic_params > ( - pub ::core::marker::PhantomData<( #phantom_params )> - ); - }) - } -} diff --git a/crates/cgp-macro-lib/src/delegate_components/impl_delegate.rs b/crates/cgp-macro-lib/src/delegate_components/impl_delegate.rs index 9722c269..d235f42c 100644 --- a/crates/cgp-macro-lib/src/delegate_components/impl_delegate.rs +++ b/crates/cgp-macro-lib/src/delegate_components/impl_delegate.rs @@ -2,15 +2,16 @@ use alloc::boxed::Box; use alloc::vec; use alloc::vec::Vec; +use cgp_macro_core::functions::merge_generics; +use cgp_macro_core::types::generics::ImplGenerics; +use cgp_macro_core::types::provider_struct::ProviderStruct; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{ImplItem, ImplItemType, ItemImpl, Path, Type, parse2}; -use crate::delegate_components::define_struct; -use crate::delegate_components::merge_generics::merge_generics; -use crate::parse::{DelegateEntry, DelegateKey, DelegateMode, DelegateValue, ImplGenerics}; +use crate::parse::{DelegateEntry, DelegateKey, DelegateMode, DelegateValue}; pub fn impl_delegate_components( target_type: &Type, @@ -39,7 +40,11 @@ where if let DelegateValue::New(value) = source { let struct_ident = &value.struct_ident; - let item_struct = define_struct(struct_ident, &value.struct_generics)?; + let item_struct = ProviderStruct { + ident: struct_ident.clone(), + generics: value.struct_generics.clone(), + } + .to_item_struct()?; let (impl_generics, type_generics, _) = value.struct_generics.split_for_impl(); diff --git a/crates/cgp-macro-lib/src/delegate_components/mod.rs b/crates/cgp-macro-lib/src/delegate_components/mod.rs index 828d2726..c9f86cb6 100644 --- a/crates/cgp-macro-lib/src/delegate_components/mod.rs +++ b/crates/cgp-macro-lib/src/delegate_components/mod.rs @@ -1,7 +1,3 @@ -mod define_struct; mod impl_delegate; -mod merge_generics; -pub use define_struct::*; pub use impl_delegate::*; -pub use merge_generics::*; diff --git a/crates/cgp-macro-lib/src/derive_component/attributes.rs b/crates/cgp-macro-lib/src/derive_component/attributes.rs index ff8e5605..13d2a8f3 100644 --- a/crates/cgp-macro-lib/src/derive_component/attributes.rs +++ b/crates/cgp-macro-lib/src/derive_component/attributes.rs @@ -1,5 +1,6 @@ use core::mem; +use syn::parse::Parse; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Attribute, TypeParamBound}; @@ -36,11 +37,9 @@ pub fn parse_component_attributes( } parsed_attributes.use_type.extend(use_type_specs); - } else if ident == "namespace" { - let namespace_specs = attribute.parse_args_with( - Punctuated::::parse_terminated, - )?; - parsed_attributes.namespace.extend(namespace_specs); + } else if ident == "prefix" { + let namespace_specs = attribute.parse_args_with(UseNamespaceAttribute::parse)?; + parsed_attributes.namespace.push(namespace_specs); } else { attributes.push(attribute); } diff --git a/crates/cgp-macro-lib/src/derive_component/derive_namespace.rs b/crates/cgp-macro-lib/src/derive_component/derive_namespace.rs index e3dde545..5bcd3559 100644 --- a/crates/cgp-macro-lib/src/derive_component/derive_namespace.rs +++ b/crates/cgp-macro-lib/src/derive_component/derive_namespace.rs @@ -1,5 +1,5 @@ use quote::quote; -use syn::{Ident, ItemImpl, parse2}; +use syn::{Ident, ItemImpl, parse_quote, parse2}; use crate::attributes::UseNamespaceAttribute; @@ -21,12 +21,13 @@ pub fn derive_namespace_impl( component_name: &Ident, ) -> syn::Result { let namespace = &attribute.namespace; - let path = &attribute.path; + let mut path = attribute.path.clone(); + path.append_type(parse_quote!(#component_name)); let out = quote! { impl<__Components__> #namespace < __Components__ > for #component_name { - type Provider = RedirectLookup< __Components__, #path >; + type Delegate = RedirectLookup< __Components__, #path >; } }; diff --git a/crates/cgp-macro-lib/src/derive_component/derive_redirect_lookup.rs b/crates/cgp-macro-lib/src/derive_component/derive_redirect_lookup.rs index ea294f3f..6c3be886 100644 --- a/crates/cgp-macro-lib/src/derive_component/derive_redirect_lookup.rs +++ b/crates/cgp-macro-lib/src/derive_component/derive_redirect_lookup.rs @@ -86,7 +86,7 @@ pub fn extract_type_generics(generics: &Generics) -> syn::Result> { if type_params.is_empty() { Ok(None) } else { - let mut out = quote! { PathNil }; + let mut out = quote! { Nil }; for param in type_params.iter().rev() { out = quote! { diff --git a/crates/cgp-macro-lib/src/derive_component/use_context_impl.rs b/crates/cgp-macro-lib/src/derive_component/use_context_impl.rs index ffbc63d4..918a1e6a 100644 --- a/crates/cgp-macro-lib/src/derive_component/use_context_impl.rs +++ b/crates/cgp-macro-lib/src/derive_component/use_context_impl.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::types::generics::TypeGenerics; use proc_macro2::Span; use quote::quote; use syn::spanned::Spanned; @@ -8,7 +9,6 @@ use syn::{ use crate::derive_component::delegate_fn::derive_delegated_fn_impl; use crate::derive_component::delegate_type::derive_delegate_type_impl; -use crate::parse::TypeGenerics; pub fn derive_use_context_impl( context_type: &Ident, diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_inherit.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_inherit.rs index b5da921a..42745075 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_inherit.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_inherit.rs @@ -1,8 +1,9 @@ +use cgp_macro_core::types::generics::TypeGenerics; use proc_macro2::TokenStream; use quote::quote; use syn::{Ident, ItemImpl, ItemStruct, parse_quote, parse2}; -use crate::parse::{SimpleType, TypeGenerics}; +use crate::parse::SimpleType; pub fn cgp_inherit(attr: TokenStream, body: TokenStream) -> syn::Result { let context_struct: ItemStruct = parse2(body)?; diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_namespace.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_namespace.rs index 7b39a741..cb8aa32f 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_namespace.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_namespace.rs @@ -1,82 +1,9 @@ +use cgp_macro_core::types::namespace::NamespaceTable; use proc_macro2::TokenStream; -use quote::quote; -use syn::{Ident, ItemImpl, ItemStruct, ItemTrait, parse2}; - -use crate::cgp_namespace::spec::NamespaceSpec; +use quote::ToTokens; +use syn::parse2; pub fn cgp_namespace(body: TokenStream) -> syn::Result { - let spec: NamespaceSpec = parse2(body)?; - - let mut out = TokenStream::new(); - - let namespace_ident = &spec.namespace_ident; - - let namespace_trait: ItemTrait = parse2(quote! { - pub trait #namespace_ident< __Components__ > { - type Provider; - } - })?; - - out.extend(quote! { - #namespace_trait - }); - - if let Some(parent_namespace_ident) = spec.parent_namespace_ident { - let namespace_struct_ident = Ident::new( - &format!("__{}Components", namespace_ident), - namespace_ident.span(), - ); - - let namespace_struct: ItemStruct = parse2(quote! { - pub struct #namespace_struct_ident; - })?; - - let item_impl: ItemImpl = parse2(quote! { - impl<__Context__, __Components__, __Provider__> - #namespace_ident< __Components__ > - for __Context__ - where - __Context__: #parent_namespace_ident< __Components__, Provider = __Provider__ > - + #parent_namespace_ident< #namespace_struct_ident >, - { - type Provider = __Provider__; - } - })?; - - out.extend(quote! { - #namespace_struct - - #item_impl - }) - } - - for entry in spec.entries.into_iter() { - let value = entry.value; - for path in entry.keys.paths.into_iter() { - let path_type = path.path_type; - - let mut generics = path.generics.generics; - generics.params.push(parse2(quote!(__Components__))?); - - let impl_generics = generics.split_for_impl().0; - - let item_impl: ItemImpl = parse2(quote! { - impl #impl_generics - #namespace_ident< __Components__ > - for #path_type - { - type Provider = RedirectLookup< - __Components__, - #value, - >; - } - })?; - - out.extend(quote! { - #item_impl - }) - } - } - - Ok(out) + let namespace_table: NamespaceTable = parse2(body)?; + Ok(namespace_table.eval()?.to_token_stream()) } diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs index 847dfd96..11d1bed7 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_preset.rs @@ -1,13 +1,15 @@ use std::collections::HashSet; +use cgp_macro_core::types::generics::ImplGenerics; +use cgp_macro_core::types::provider_struct::ProviderStruct; use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, TokenStreamExt, quote}; use syn::punctuated::Punctuated; use syn::token::{At, Comma}; use syn::{GenericParam, Ident, ItemTrait, TypeParamBound, parse_quote, parse2}; -use crate::delegate_components::{define_struct, impl_delegate_components}; -use crate::parse::{DefinePreset, DelegateEntry, ImplGenerics, SimpleType}; +use crate::delegate_components::impl_delegate_components; +use crate::parse::{DefinePreset, DelegateEntry, SimpleType}; use crate::preset::{define_substitution_macro, impl_components_is_preset}; use crate::replace_self::to_snake_case_str; @@ -100,7 +102,7 @@ pub fn define_preset(body: TokenStream) -> syn::Result { let preset_generics: ImplGenerics = syn::parse2(quote!( #preset_generic_args ))?; let provider_type = { - let type_generics = preset_generics.as_type_generics(); + let type_generics = preset_generics.split_for_impl().1; parse2(quote! { #provider_struct_name #type_generics })? }; @@ -132,7 +134,11 @@ pub fn define_preset(body: TokenStream) -> syn::Result { &delegate_entries, ); - let provider_struct = define_struct(&provider_struct_name, &preset_generics.generics)?; + let provider_struct = ProviderStruct { + ident: provider_struct_name.clone(), + generics: preset_generics.generics.clone(), + } + .to_item_struct()?; let export_provider = match ast.provider_wrapper { Some(wrapper) => { diff --git a/crates/cgp-macro-lib/src/entrypoints/delegate_and_check_components.rs b/crates/cgp-macro-lib/src/entrypoints/delegate_and_check_components.rs index 6f635434..4763b9f9 100644 --- a/crates/cgp-macro-lib/src/entrypoints/delegate_and_check_components.rs +++ b/crates/cgp-macro-lib/src/entrypoints/delegate_and_check_components.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::types::generics::ImplGenerics; use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, TokenStreamExt}; use syn::punctuated::Punctuated; @@ -9,7 +10,6 @@ use crate::check_components::derive_check_components; use crate::delegate_components::impl_delegate_components; use crate::parse::{ CheckComponents, CheckEntries, CheckEntry, DelegateAndCheckSpec, DelegateEntry, DelegateKey, - ImplGenerics, }; pub fn delegate_and_check_components(body: TokenStream) -> syn::Result { diff --git a/crates/cgp-macro-lib/src/entrypoints/delegate_components.rs b/crates/cgp-macro-lib/src/entrypoints/delegate_components.rs index 5dea004f..ba10cd0e 100644 --- a/crates/cgp-macro-lib/src/entrypoints/delegate_components.rs +++ b/crates/cgp-macro-lib/src/entrypoints/delegate_components.rs @@ -1,31 +1,12 @@ +use cgp_macro_core::types::delegate_component::DelegateTable; use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse2; -use crate::delegate_components::{define_struct, impl_delegate_components}; -use crate::parse::{DelegateComponents, SimpleType, TypeGenerics}; - pub fn delegate_components(body: TokenStream) -> syn::Result { - let spec: DelegateComponents = parse2(body)?; - - let target_type = &spec.target_type; - let target_generics = &spec.target_generics; - - let mut output = TokenStream::new(); - - if spec.new_struct { - let target_type: SimpleType = parse2(target_type.to_token_stream())?; - - let type_generics = target_type.generics.unwrap_or_default().generics; - - let component_struct = define_struct(&target_type.name, &type_generics)?; - - output.extend(component_struct.to_token_stream()); - } - - let impl_items = impl_delegate_components(target_type, target_generics, &spec.entries)?; + let table: DelegateTable = parse2(body.clone())?; - output.extend(impl_items); + let evaluated_table = table.eval()?; - Ok(output) + Ok(evaluated_table.to_token_stream()) } diff --git a/crates/cgp-macro-lib/src/lib.rs b/crates/cgp-macro-lib/src/lib.rs index 23501b7a..2b322b95 100644 --- a/crates/cgp-macro-lib/src/lib.rs +++ b/crates/cgp-macro-lib/src/lib.rs @@ -11,7 +11,6 @@ pub(crate) mod attributes; pub(crate) mod blanket_trait; pub(crate) mod cgp_fn; pub(crate) mod cgp_impl; -pub(crate) mod cgp_namespace; pub(crate) mod check_components; pub(crate) mod delegate_components; pub(crate) mod derive_builder; diff --git a/crates/cgp-macro-lib/src/parse/check_components.rs b/crates/cgp-macro-lib/src/parse/check_components.rs index cbfdee97..00bca26b 100644 --- a/crates/cgp-macro-lib/src/parse/check_components.rs +++ b/crates/cgp-macro-lib/src/parse/check_components.rs @@ -1,3 +1,4 @@ +use cgp_macro_core::types::generics::ImplGenerics; use proc_macro2::Span; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; @@ -6,7 +7,7 @@ use syn::spanned::Spanned; use syn::token::{Bracket, Colon, Comma, Lt, Pound, Where}; use syn::{Attribute, Ident, Type, WhereClause, braced, bracketed, parse2}; -use crate::parse::{ImplGenerics, SimpleType}; +use crate::parse::SimpleType; pub struct CheckComponentsSpecs { pub specs: Vec, diff --git a/crates/cgp-macro-lib/src/parse/delegate_and_check_components.rs b/crates/cgp-macro-lib/src/parse/delegate_and_check_components.rs index 118d0f5e..ba8e96eb 100644 --- a/crates/cgp-macro-lib/src/parse/delegate_and_check_components.rs +++ b/crates/cgp-macro-lib/src/parse/delegate_and_check_components.rs @@ -1,5 +1,6 @@ use core::iter; +use cgp_macro_core::types::generics::ImplGenerics; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; @@ -7,7 +8,7 @@ use syn::spanned::Spanned; use syn::token::{Bracket, Comma, Lt, Pound}; use syn::{Attribute, Ident, Type, braced, bracketed, parse2}; -use crate::parse::{DelegateMode, DelegateValue, ImplGenerics, SimpleType}; +use crate::parse::{DelegateMode, DelegateValue, SimpleType}; pub struct DelegateAndCheckSpec { pub impl_generics: ImplGenerics, diff --git a/crates/cgp-macro-lib/src/parse/delegate_components.rs b/crates/cgp-macro-lib/src/parse/delegate_components.rs index 28cfcae3..e3c25f4c 100644 --- a/crates/cgp-macro-lib/src/parse/delegate_components.rs +++ b/crates/cgp-macro-lib/src/parse/delegate_components.rs @@ -1,22 +1,16 @@ use core::iter; -use proc_macro2::{Span, TokenStream}; +use cgp_macro_core::functions::merge_generics; +use cgp_macro_core::types::generics::{ImplGenerics, TypeGenerics}; +use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt, quote}; use syn::parse::discouraged::Speculative; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; -use syn::token::{At, Bracket, Colon, Comma, Gt, Lt, RArrow, Semi}; -use syn::{Error, Generics, Ident, Token, Type, braced, bracketed, parse_quote, parse2}; +use syn::token::{At, Bracket, Colon, Comma, Gt, Lt, RArrow}; +use syn::{Error, Generics, Ident, Token, Type, braced, bracketed, parse_quote}; -use crate::delegate_components::merge_generics; -use crate::parse::{ComponentPaths, ImplGenerics, SimpleType, TypeGenerics}; - -pub struct DelegateComponents { - pub new_struct: bool, - pub target_type: Type, - pub target_generics: ImplGenerics, - pub entries: Punctuated, Comma>, -} +use crate::parse::{ComponentPaths, SimpleType}; #[derive(Clone)] pub struct DelegateEntry { @@ -37,7 +31,6 @@ pub enum DelegateValue { New(DelegateNewValue), } -#[allow(dead_code)] #[derive(Clone)] pub enum DelegateMode { Provider(Colon), @@ -71,123 +64,6 @@ impl DelegateValue { } } -impl Parse for DelegateComponents { - fn parse(input: ParseStream) -> syn::Result { - let target_generics = if input.peek(Lt) { - input.parse()? - } else { - Default::default() - }; - - let new_struct = { - let fork = input.fork(); - let new_ident: Option = fork.parse().ok(); - match new_ident { - Some(new_ident) if new_ident == "new" => { - input.advance_to(&fork); - true - } - _ => false, - } - }; - - let target_type: Type = input.parse()?; - - let content; - braced!(content in input); - - let meta_entries = parse_meta_delegate_entries(&content, &target_type)?; - - let delegate_entries: Punctuated, Comma> = - Punctuated::parse_terminated(&content)?; - - let entries = meta_entries.into_iter().chain(delegate_entries).collect(); - - Ok(Self { - new_struct, - target_type, - target_generics, - entries, - }) - } -} - -pub fn parse_meta_delegate_entries( - input: ParseStream, - target_type: &Type, -) -> syn::Result>> { - let mut entries = Vec::new(); - - while input.peek(Ident) { - let fork = input.fork(); - let keyword: Ident = fork.parse()?; - - if keyword == "open" { - input.advance_to(&fork); - - let components: Punctuated = Punctuated::parse_separated_nonempty(input)?; - let _: Semi = input.parse()?; - - for component in components { - let value = DelegateValue::Type(parse2( - quote!(RedirectLookup<#target_type, PathCons<#component, PathNil>>), - )?); - - let key = DelegateKey { - ty: component, - generics: Default::default(), - }; - - let entry = DelegateEntry { - keys: Punctuated::from_iter([key]), - mode: DelegateMode::Provider(Colon(Span::call_site())), - value, - }; - - entries.push(entry) - } - } else if keyword == "namespace" { - input.advance_to(&fork); - - let ident: Ident = input.parse()?; - let _: Semi = input.parse()?; - - let namespace_ident = if ident == "default" { - Ident::new("DefaultNamespace", ident.span()) - } else { - ident - }; - - let delegate_key: Type = parse2(quote! { - __Component__ - })?; - - let generics: ImplGenerics = parse2(quote! { - <__Component__: #namespace_ident< #target_type >> - })?; - - let delegate_value: Type = parse2(quote! { - < __Component__ as #namespace_ident< #target_type >>::Provider - })?; - - let entry = DelegateEntry { - keys: Punctuated::from_iter([DelegateKey { - ty: delegate_key, - generics, - }]), - mode: DelegateMode::Provider(Colon(Span::call_site())), - value: DelegateValue::Type(delegate_value), - }; - - entries.push(entry) - } else { - break; - } - } - - Ok(entries) -} - impl Parse for DelegateEntry { fn parse(input: ParseStream) -> syn::Result { let components = if input.peek(Bracket) { diff --git a/crates/cgp-macro-lib/src/parse/is_provider_params.rs b/crates/cgp-macro-lib/src/parse/is_provider_params.rs index 8fbeb98e..88c085fd 100644 --- a/crates/cgp-macro-lib/src/parse/is_provider_params.rs +++ b/crates/cgp-macro-lib/src/parse/is_provider_params.rs @@ -1,9 +1,8 @@ +use cgp_macro_core::types::generics::TypeGenerics; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{GenericParam, Generics, Type, parse_quote}; -use crate::parse::TypeGenerics; - pub fn parse_is_provider_params(generics: &Generics) -> syn::Result> { let params = TypeGenerics::try_from(generics)?.generics.params; diff --git a/crates/cgp-macro-lib/src/parse/mod.rs b/crates/cgp-macro-lib/src/parse/mod.rs index 0c63770c..6dd0a2a2 100644 --- a/crates/cgp-macro-lib/src/parse/mod.rs +++ b/crates/cgp-macro-lib/src/parse/mod.rs @@ -4,11 +4,9 @@ mod define_preset; mod delegate_and_check_components; mod delegate_components; mod entry; -mod impl_generics; mod is_provider_params; mod path; mod simple_type; -mod type_generics; mod type_spec; pub use check_components::*; @@ -17,9 +15,7 @@ pub use define_preset::*; pub use delegate_and_check_components::*; pub use delegate_components::*; pub use entry::*; -pub use impl_generics::*; pub use is_provider_params::*; pub use path::*; pub use simple_type::*; -pub use type_generics::*; pub use type_spec::*; diff --git a/crates/cgp-macro-lib/src/parse/path.rs b/crates/cgp-macro-lib/src/parse/path.rs index 78d91694..ccf5d4d5 100644 --- a/crates/cgp-macro-lib/src/parse/path.rs +++ b/crates/cgp-macro-lib/src/parse/path.rs @@ -1,12 +1,9 @@ -use proc_macro2::{TokenStream, TokenTree}; +use cgp_macro_core::types::generics::ImplGenerics; +use cgp_macro_core::types::path::PathHead; +use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::parse::{Parse, ParseStream}; -use syn::punctuated::Punctuated; -use syn::token::{Brace, Comma, Dot, Lt}; -use syn::{Ident, Type, braced, parse_quote, parse2}; - -use crate::parse::ImplGenerics; -use crate::symbol::symbol_from_string_spanned; +use syn::{Type, parse_quote}; pub struct ComponentPaths { pub paths: Vec>, @@ -16,7 +13,7 @@ impl Parse for ComponentPaths { fn parse(input: ParseStream) -> syn::Result { let path_head = PathHead::parse(input)?; - if let PathHead::Wildcard = path_head { + if let PathHead::End = path_head { return Err(syn::Error::new( input.span(), "Expected at least one path element", @@ -25,7 +22,7 @@ impl Parse for ComponentPaths { let mut paths = Vec::new(); - for path in path_head.to_paths() { + for path in path_head_to_prefix(&path_head) { let path_type: Type = syn::parse2(path.path_type)?; paths.push(ComponentPath { path_type, @@ -42,38 +39,26 @@ pub struct ComponentPath { pub generics: ImplGenerics, } -pub enum PathHead { - Type(Option, Box, Box), - Group(Punctuated), - Wildcard, -} - -impl PathHead { - pub fn to_paths(&self) -> Vec> { - match self { - Self::Type(generics, path_type, rest) => { - let rest_types = rest.to_paths(); +pub fn path_head_to_prefix(path_head: &PathHead) -> Vec> { + match path_head { + PathHead::Type(generics, path_type, rest) => { + let rest_types = path_head_to_prefix(rest); - prepend_path( - path_type.path_type.to_token_stream(), - generics.clone(), - rest_types, - ) - } - Self::Group(paths) => paths.iter().flat_map(|path| path.to_paths()).collect(), - Self::Wildcard => { - vec![ComponentPath { - path_type: quote! { __Wildcard__ }, - generics: parse_quote! { <__Wildcard__> }, - }] - } + prepend_path(path_type.to_token_stream(), generics.clone(), rest_types) + } + PathHead::Group(paths) => paths.iter().flat_map(path_head_to_prefix).collect(), + PathHead::End => { + vec![ComponentPath { + path_type: quote! { __Wildcard__ }, + generics: parse_quote! { <__Wildcard__> }, + }] } } } pub fn prepend_path( path_type: TokenStream, - generics: Option, + generics: ImplGenerics, rest_types: Vec>, ) -> Vec> { rest_types @@ -81,12 +66,10 @@ pub fn prepend_path( .map(|mut path| { let rest_tokens = path.path_type; - if let Some(generics) = &generics { - path.generics - .generics - .params - .extend(generics.generics.params.clone()); - } + path.generics + .generics + .params + .extend(generics.generics.params.clone()); let new_path = quote! { PathCons< #path_type , #rest_tokens > }; ComponentPath { @@ -96,88 +79,3 @@ pub fn prepend_path( }) .collect() } - -impl Parse for PathHead { - fn parse(input: ParseStream) -> syn::Result { - if input.is_empty() { - Ok(Self::Wildcard) - } else if input.peek(Brace) { - let body; - braced!(body in input); - - let group = Punctuated::parse_terminated(&body)?; - - Ok(Self::Group(group)) - } else { - let generics = if input.peek(Lt) { - Some(input.parse()?) - } else { - None - }; - - let path_type: PathType = input.parse()?; - - let rest_path = if input.peek(Dot) { - let _: Dot = input.parse()?; - Box::new(Self::parse(input)?) - } else { - Box::new(Self::Wildcard) - }; - - Ok(Self::Type(generics, Box::new(path_type), rest_path)) - } - } -} - -pub fn path_type_as_ident(path_type: &Type) -> Option { - let path_tokens = path_type.to_token_stream().into_iter().collect::>(); - let [path_token]: [TokenTree; 1] = path_tokens.try_into().ok()?; - - if let TokenTree::Ident(path_ident) = path_token { - let path_str = path_ident.to_string(); - if let Some(path_char) = path_str.chars().next() - && path_char.is_ascii_lowercase() - && !is_primitive_type(&path_str) - { - return Some(path_ident); - } - } - - None -} - -pub struct PathType { - pub path_type: Type, -} - -impl Parse for PathType { - fn parse(input: ParseStream) -> syn::Result { - let path_type: Type = input.parse()?; - - if let Some(path_ident) = path_type_as_ident(&path_type) { - let path_symbol = parse2(symbol_from_string_spanned( - path_ident.span(), - &path_ident.to_string(), - ))?; - Ok(Self { - path_type: path_symbol, - }) - } else { - Ok(Self { path_type }) - } - } -} - -pub fn is_primitive_type(ident: &str) -> bool { - if (ident.starts_with("i") || ident.starts_with("u") || ident.starts_with("f")) - && ident[1..].chars().all(|c| c.is_numeric()) - { - return true; - } - - if ["char", "bool", "usize", "isize", "str"].contains(&ident) { - return true; - } - - false -} diff --git a/crates/cgp-macro-lib/src/parse/type_spec.rs b/crates/cgp-macro-lib/src/parse/type_spec.rs index 40929ee5..285a96a9 100644 --- a/crates/cgp-macro-lib/src/parse/type_spec.rs +++ b/crates/cgp-macro-lib/src/parse/type_spec.rs @@ -1,10 +1,9 @@ +use cgp_macro_core::types::generics::ImplGenerics; use quote::ToTokens; use syn::Ident; use syn::parse::{Parse, ParseStream}; use syn::token::Lt; -use crate::parse::ImplGenerics; - pub struct TypeSpec { pub name: Ident, pub generics: Option, diff --git a/crates/cgp-macro-lib/src/preset/impl_is_preset.rs b/crates/cgp-macro-lib/src/preset/impl_is_preset.rs index af083209..ec912b26 100644 --- a/crates/cgp-macro-lib/src/preset/impl_is_preset.rs +++ b/crates/cgp-macro-lib/src/preset/impl_is_preset.rs @@ -1,10 +1,11 @@ use alloc::vec::Vec; +use cgp_macro_core::types::generics::ImplGenerics; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Ident, ItemImpl, Type, parse_quote}; -use crate::parse::{DelegateEntry, DelegateKey, ImplGenerics, SimpleType}; +use crate::parse::{DelegateEntry, DelegateKey, SimpleType}; pub fn impl_components_is_preset( trait_name: &Ident, diff --git a/crates/cgp-monad/Cargo.toml b/crates/cgp-monad/Cargo.toml index 558b5ab3..2de784d6 100644 --- a/crates/cgp-monad/Cargo.toml +++ b/crates/cgp-monad/Cargo.toml @@ -10,5 +10,5 @@ keywords = { workspace = true } description = "Monadic constructs for CGP computation" [dependencies] -cgp-core = { workspace = true } +cgp = { version = "0.7.0", path = "../cgp-core", package = "cgp-core" } cgp-handler = { workspace = true } diff --git a/crates/cgp-monad/src/monadic/err.rs b/crates/cgp-monad/src/monadic/err.rs index f080b77a..3beea7d5 100644 --- a/crates/cgp-monad/src/monadic/err.rs +++ b/crates/cgp-monad/src/monadic/err.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; use crate::monadic::ident::IdentMonadic; diff --git a/crates/cgp-monad/src/monadic/ok.rs b/crates/cgp-monad/src/monadic/ok.rs index c90dba65..d8bfdf4f 100644 --- a/crates/cgp-monad/src/monadic/ok.rs +++ b/crates/cgp-monad/src/monadic/ok.rs @@ -1,4 +1,4 @@ -use cgp_core::prelude::*; +use cgp::prelude::*; use cgp_handler::{AsyncComputer, AsyncComputerComponent, Computer, ComputerComponent}; use crate::monadic::ident::IdentMonadic; diff --git a/crates/cgp-monad/src/providers/pipe_monadic.rs b/crates/cgp-monad/src/providers/pipe_monadic.rs index da2c81b6..eff049ad 100644 --- a/crates/cgp-monad/src/providers/pipe_monadic.rs +++ b/crates/cgp-monad/src/providers/pipe_monadic.rs @@ -1,5 +1,5 @@ -use cgp_core::field::traits::MapFields; -use cgp_core::prelude::*; +use cgp::field::traits::MapFields; +use cgp::prelude::*; use cgp_handler::{ AsyncComputerComponent, ComposeHandlers, ComputerComponent, HandlerComponent, TryComputerComponent, TryPromote, diff --git a/crates/cgp-tests/src/namespaces/extended.rs b/crates/cgp-tests/src/namespaces/extended.rs index 3c4699e0..2e74b25e 100644 --- a/crates/cgp-tests/src/namespaces/extended.rs +++ b/crates/cgp-tests/src/namespaces/extended.rs @@ -1,12 +1,8 @@ -use cgp::core::component::RedirectLookup; -use cgp::core::error::{ErrorRaiserComponent, ErrorTypeProviderComponent}; -use cgp::prelude::*; +use cgp::prelude::{DefaultNamespace, cgp_namespace}; cgp_namespace! { - ExtendedNamespace: DefaultNamespace { - @cgp.core.error.ErrorRaiserComponent: - @app.ErrorRaiserComponent, - @cgp.core.error.ErrorTypeProviderComponent: - @app.ErrorTypeProviderComponent, + new ExtendedNamespace: DefaultNamespace { + @cgp.core.error => + @app, } } diff --git a/crates/cgp-tests/src/namespaces/generics.rs b/crates/cgp-tests/src/namespaces/generics.rs new file mode 100644 index 00000000..b9ac9a27 --- /dev/null +++ b/crates/cgp-tests/src/namespaces/generics.rs @@ -0,0 +1,38 @@ +use core::fmt::Display; + +use cgp::core::component::DefaultImpls1; +use cgp::prelude::*; + +#[cgp_component(ShowImpl)] +#[prefix(@test)] +pub trait Show { + fn show(&self, value: &T) -> String; +} + +#[cgp_impl(new ShowWithDisplay)] +// #[default_impl(DefaultNamespace1)] +impl ShowImpl { + fn show(&self, value: &T) -> String { + value.to_string() + } +} + +// cgp_namespace! { +// DefaultShow { +// T: +// @ShowWithDisplay, +// } +// } + +/* + cgp_namespace! { + DefaultNamespace1 { + String: + ShowWithDisplay, + } + } +*/ + +impl DefaultImpls1 for String { + type Delegate = ShowWithDisplay; +} diff --git a/crates/cgp-tests/src/namespaces/mod.rs b/crates/cgp-tests/src/namespaces/mod.rs index 34d3c6b8..b9a1bced 100644 --- a/crates/cgp-tests/src/namespaces/mod.rs +++ b/crates/cgp-tests/src/namespaces/mod.rs @@ -1,3 +1,2 @@ -mod extended; - -pub use extended::*; +pub mod extended; +pub mod generics; diff --git a/crates/cgp-tests/tests/component_tests/delegate_components/direct.rs b/crates/cgp-tests/tests/component_tests/delegate_components/direct.rs index e068aca1..c5017a8b 100644 --- a/crates/cgp-tests/tests/component_tests/delegate_components/direct.rs +++ b/crates/cgp-tests/tests/component_tests/delegate_components/direct.rs @@ -9,8 +9,10 @@ delegate_components! { delegate_components! { new BarComponents { - Index<0>: FooComponents, - Index<1> -> FooComponents, + Index<0>: + FooComponents, + Index<1> -> + FooComponents, } } diff --git a/crates/cgp-tests/tests/namespace_tests/multi_param.rs b/crates/cgp-tests/tests/namespace_tests/multi_param.rs index 5fe681e5..502e2e23 100644 --- a/crates/cgp-tests/tests/namespace_tests/multi_param.rs +++ b/crates/cgp-tests/tests/namespace_tests/multi_param.rs @@ -1,7 +1,7 @@ use cgp::prelude::*; #[cgp_component(FooProvider)] -#[namespace(@app.FooProviderComponent)] +#[prefix(@app)] pub trait Foo<'a, T, U> { fn foo(&self, first: &'a T, second: U); } @@ -15,7 +15,7 @@ pub struct AppA; delegate_components! { AppA { - open FooProviderComponent; + open {FooProviderComponent}; @FooProviderComponent.String.u32: DummyFoo, @@ -39,7 +39,7 @@ pub struct AppB; delegate_components! { AppB { - namespace default; + namespace DefaultNamespace; @app.FooProviderComponent.String.u64: DummyFoo, diff --git a/crates/cgp-tests/tests/namespace_tests/namespace.rs b/crates/cgp-tests/tests/namespace_tests/namespace.rs index 3525f4f9..0742ec6e 100644 --- a/crates/cgp-tests/tests/namespace_tests/namespace.rs +++ b/crates/cgp-tests/tests/namespace_tests/namespace.rs @@ -5,7 +5,7 @@ use cgp::prelude::*; pub struct MyComponents; #[cgp_component(FooProvider)] -#[namespace(DefaultNamespace: @app.MyComponents.FooProviderComponent)] +#[prefix(@app.MyComponents.FooProviderComponent in DefaultNamespace)] pub trait Foo { fn foo(&self); } @@ -14,7 +14,7 @@ pub struct App; delegate_components! { App { - namespace default; + namespace DefaultNamespace; @cgp.core.error.ErrorTypeProviderComponent: UseType, diff --git a/crates/cgp-tests/tests/namespace_tests/namespace_macro/basic.rs b/crates/cgp-tests/tests/namespace_tests/namespace_macro/basic.rs index 4eb8080a..ab0aac0c 100644 --- a/crates/cgp-tests/tests/namespace_tests/namespace_macro/basic.rs +++ b/crates/cgp-tests/tests/namespace_tests/namespace_macro/basic.rs @@ -6,14 +6,14 @@ pub trait Foo { } cgp_namespace! { - MyNamespace { - FooProviderComponent: + new MyNamespace { + FooProviderComponent => @MyFooComponent, } } #[cgp_component(BarProvider)] -#[namespace(MyNamespace: @MyBarComponent)] +#[prefix(@MyBarComponent in MyNamespace)] pub trait Bar { fn bar(&self); } diff --git a/crates/cgp-tests/tests/namespace_tests/namespace_macro/default_generics.rs b/crates/cgp-tests/tests/namespace_tests/namespace_macro/default_generics.rs new file mode 100644 index 00000000..7d1b7d4e --- /dev/null +++ b/crates/cgp-tests/tests/namespace_tests/namespace_macro/default_generics.rs @@ -0,0 +1,33 @@ +use cgp::core::component::DefaultImpls1; +use cgp::prelude::*; +use cgp_tests::namespaces::generics::{ShowImplComponent, ShowWithDisplay}; + +pub struct App; + +delegate_components! { + App { + // use DefaultNamespace; + // for in DefaultNamespace { + // Component: Provider, + // } + namespace DefaultNamespace; + + for in DefaultImpls1 { + @test.ShowImplComponent.T: Provider, + } + + @test.ShowImplComponent.u64: + ShowWithDisplay, + + // namespace DefaultNamespace1 => @test.ShowImplComponent; + } +} + +check_components! { + App { + ShowImplComponent: [ + String, + u64, + ] + } +} diff --git a/crates/cgp-tests/tests/namespace_tests/namespace_macro/extended_namespace.rs b/crates/cgp-tests/tests/namespace_tests/namespace_macro/extended_namespace.rs index 7e10c72f..64d08afb 100644 --- a/crates/cgp-tests/tests/namespace_tests/namespace_macro/extended_namespace.rs +++ b/crates/cgp-tests/tests/namespace_tests/namespace_macro/extended_namespace.rs @@ -2,7 +2,7 @@ use cgp::core::error::{ErrorRaiserComponent, ErrorTypeProviderComponent, ErrorWr use cgp::extra::error::RaiseFrom; use cgp::extra::handler::CanTryCompute; use cgp::prelude::*; -use cgp_tests::namespaces::ExtendedNamespace; +use cgp_tests::namespaces::extended::ExtendedNamespace; pub struct App; diff --git a/crates/cgp-tests/tests/namespace_tests/namespace_macro/mod.rs b/crates/cgp-tests/tests/namespace_tests/namespace_macro/mod.rs index dbd2d282..26d24110 100644 --- a/crates/cgp-tests/tests/namespace_tests/namespace_macro/mod.rs +++ b/crates/cgp-tests/tests/namespace_tests/namespace_macro/mod.rs @@ -1,4 +1,5 @@ pub mod basic; +pub mod default_generics; pub mod extended_namespace; pub mod multi_namespace; pub mod symbol_path; diff --git a/crates/cgp-tests/tests/namespace_tests/namespace_macro/multi_namespace.rs b/crates/cgp-tests/tests/namespace_tests/namespace_macro/multi_namespace.rs index a0807142..4425feb0 100644 --- a/crates/cgp-tests/tests/namespace_tests/namespace_macro/multi_namespace.rs +++ b/crates/cgp-tests/tests/namespace_tests/namespace_macro/multi_namespace.rs @@ -8,22 +8,22 @@ pub trait Foo { } cgp_namespace! { - MyNamespace { - FooProviderComponent: + new MyNamespace { + FooProviderComponent => @MyApp.MyFooComponent, } } cgp_namespace! { - OtherNamespace { - FooProviderComponent: + new OtherNamespace { + FooProviderComponent => @my_app.MyFooComponent, } } #[cgp_component(BarProvider)] -#[namespace(MyNamespace: @MyApp.MyBarComponent)] -#[namespace(OtherNamespace: @my_app.MyBarComponent)] +#[prefix(@MyApp.MyBarComponent in MyNamespace)] +#[prefix(@my_app.MyBarComponent in OtherNamespace)] pub trait Bar { fn bar(&self); } diff --git a/crates/cgp-tests/tests/namespace_tests/namespace_macro/symbol_path.rs b/crates/cgp-tests/tests/namespace_tests/namespace_macro/symbol_path.rs index 684949db..e781932c 100644 --- a/crates/cgp-tests/tests/namespace_tests/namespace_macro/symbol_path.rs +++ b/crates/cgp-tests/tests/namespace_tests/namespace_macro/symbol_path.rs @@ -6,14 +6,14 @@ pub trait Foo { } cgp_namespace! { - MyNamespace { - FooProviderComponent: + new MyNamespace { + FooProviderComponent => @my_app.MyFooComponent, } } #[cgp_component(BarProvider)] -#[namespace(MyNamespace: @my_app.MyBarComponent)] +#[prefix(@my_app.MyBarComponent in MyNamespace)] pub trait Bar { fn bar(&self); } diff --git a/crates/cgp-tests/tests/namespace_tests/namespace_macro/type_path.rs b/crates/cgp-tests/tests/namespace_tests/namespace_macro/type_path.rs index 8b699987..0881b5f1 100644 --- a/crates/cgp-tests/tests/namespace_tests/namespace_macro/type_path.rs +++ b/crates/cgp-tests/tests/namespace_tests/namespace_macro/type_path.rs @@ -8,14 +8,14 @@ pub trait Foo { } cgp_namespace! { - MyNamespace { - FooProviderComponent: + new MyNamespace { + FooProviderComponent => @MyApp.MyFooComponent, } } #[cgp_component(BarProvider)] -#[namespace(MyNamespace: @MyApp.MyBarComponent)] +#[prefix(@MyApp.MyBarComponent in MyNamespace)] pub trait Bar { fn bar(&self); } diff --git a/crates/cgp-tests/tests/namespace_tests/open.rs b/crates/cgp-tests/tests/namespace_tests/open.rs index 61b6aa2c..21c7f9cd 100644 --- a/crates/cgp-tests/tests/namespace_tests/open.rs +++ b/crates/cgp-tests/tests/namespace_tests/open.rs @@ -24,7 +24,12 @@ impl BarProvider { delegate_components! { App { - open FooProviderComponent, BarProviderComponent; + open {FooProviderComponent, BarProviderComponent}; + + // FooProviderComponent => + // @FooProviderComponent, + // BarProviderComponent => + // @BarProviderComponent, @FooProviderComponent.String: DummyFoo, diff --git a/crates/cgp-tests/tests/namespace_tests/redirect.rs b/crates/cgp-tests/tests/namespace_tests/redirect.rs index e941395a..f47dddd1 100644 --- a/crates/cgp-tests/tests/namespace_tests/redirect.rs +++ b/crates/cgp-tests/tests/namespace_tests/redirect.rs @@ -1,7 +1,7 @@ use cgp::prelude::*; #[cgp_component(FooProvider)] -#[namespace(@bar.baz.FooProviderComponent)] +#[prefix(@bar.baz)] pub trait CanDoFoo { fn foo(); } @@ -19,7 +19,7 @@ pub struct App; delegate_components! { App { - namespace default; + namespace DefaultNamespace; // @bar: TestProvider, diff --git a/crates/cgp-type/Cargo.toml b/crates/cgp-type/Cargo.toml index f9232b60..822af9ff 100644 --- a/crates/cgp-type/Cargo.toml +++ b/crates/cgp-type/Cargo.toml @@ -14,3 +14,4 @@ description = """ [dependencies] cgp-component = { workspace = true } cgp-macro = { workspace = true } +cgp-base = { workspace = true } diff --git a/crates/cgp-type/src/traits/has_type.rs b/crates/cgp-type/src/traits/has_type.rs index 84a39a3b..67f846a6 100644 --- a/crates/cgp-type/src/traits/has_type.rs +++ b/crates/cgp-type/src/traits/has_type.rs @@ -1,4 +1,4 @@ -use cgp_component::*; +use cgp_base::macro_prelude::*; use cgp_macro::cgp_component; #[cgp_component { diff --git a/crates/cgp/src/lib.rs b/crates/cgp/src/lib.rs index f9d27a73..1874b49f 100644 --- a/crates/cgp/src/lib.rs +++ b/crates/cgp/src/lib.rs @@ -5,3 +5,5 @@ pub use {cgp_core as core, cgp_core::re_export_imports, cgp_extra as extra}; pub mod prelude; + +pub use prelude as macro_prelude;