diff --git a/Cargo.lock b/Cargo.lock index 0ba0ef4..97bf463 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -938,6 +938,7 @@ version = "0.13.0" dependencies = [ "crossterm", "tengri", + "tengri_core", "tengri_dsl", "tengri_input", "tengri_output", @@ -945,6 +946,10 @@ dependencies = [ "tengri_tui", ] +[[package]] +name = "tengri_core" +version = "0.13.0" + [[package]] name = "tengri_dsl" version = "0.13.0" @@ -952,6 +957,7 @@ dependencies = [ "itertools 0.14.0", "konst", "proptest", + "tengri_core", "tengri_tui", "thiserror", ] @@ -960,6 +966,7 @@ dependencies = [ name = "tengri_input" version = "0.13.0" dependencies = [ + "tengri_core", "tengri_dsl", "tengri_tui", ] @@ -971,6 +978,7 @@ dependencies = [ "proptest", "proptest-derive", "tengri", + "tengri_core", "tengri_dsl", "tengri_tui", ] @@ -983,6 +991,7 @@ dependencies = [ "proc-macro2", "quote", "syn", + "tengri_core", ] [[package]] @@ -998,6 +1007,7 @@ dependencies = [ "rand", "ratatui", "tengri", + "tengri_core", "tengri_dsl", "tengri_input", "tengri_output", diff --git a/Cargo.toml b/Cargo.toml index 4a6d408..a7bb2eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,15 @@ -[workspace.package] -version = "0.13.0" -edition = "2024" +[profile.release] +lto = true + +[profile.coverage] +inherits = "test" +lto = false [workspace] resolver = "2" members = [ "./tengri", + "./core", "./input", "./output", "./tui", @@ -13,9 +17,25 @@ members = [ "./proc", ] -[profile.release] -lto = true +[workspace.package] +version = "0.13.0" +edition = "2024" -[profile.coverage] -inherits = "test" -lto = false +[workspace.dependencies] +atomic_float = { version = "1" } +better-panic = { version = "0.3.0" } +crossterm = { version = "0.28.1" } +heck = { version = "0.5" } +itertools = { version = "0.14.0" } +konst = { version = "0.3.16", features = [ "rust_1_83" ] } +palette = { version = "0.7.6", features = [ "random" ] } +proc-macro2 = { version = "1", features = ["span-locations"] } +proptest = { version = "^1" } +proptest-derive = { version = "^0.5.1" } +quanta = { version = "0.12.3" } +quote = { version = "1" } +rand = { version = "0.8.5" } +ratatui = { version = "0.29.0", features = [ "unstable-widget-ref", "underline-color" ] } +syn = { version = "2", features = ["full", "extra-traits"] } +thiserror = { version = "2.0" } +unicode-width = { version = "0.2" } diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 0000000..b4e9baa --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "tengri_core" +description = "UI metaframework, core definitions." +version = { workspace = true } +edition = { workspace = true } + diff --git a/core/src/lib.rs b/core/src/lib.rs new file mode 100644 index 0000000..22288d1 --- /dev/null +++ b/core/src/lib.rs @@ -0,0 +1,7 @@ +use std::error::Error; + +/// Standard result type. +pub type Usually = Result>; + +/// Standard optional result type. +pub type Perhaps = Result, Box>; diff --git a/dsl/Cargo.toml b/dsl/Cargo.toml index 3609ada..ab0bc37 100644 --- a/dsl/Cargo.toml +++ b/dsl/Cargo.toml @@ -5,12 +5,10 @@ version = { workspace = true } edition = { workspace = true } [dependencies] -konst = { version = "0.3.16", features = [ "rust_1_83" ] } -itertools = "0.14.0" -thiserror = "2.0" - -[features] -default = [] +tengri_core = { path = "../core" } +konst = { workspace = true } +itertools = { workspace = true } +thiserror = { workspace = true } [dev-dependencies] tengri_tui = { path = "../tui" } diff --git a/dsl/src/dsl.rs b/dsl/src/dsl_parse.rs similarity index 81% rename from dsl/src/dsl.rs rename to dsl/src/dsl_parse.rs index f4eedaf..3923cd4 100644 --- a/dsl/src/dsl.rs +++ b/dsl/src/dsl_parse.rs @@ -1,5 +1,4 @@ use crate::*; -use thiserror::Error; pub type ParseResult = Result; @@ -16,41 +15,6 @@ pub type ParseResult = Result; Code(u8), } -pub trait TryFromDsl<'state, T>: Sized { - fn try_from_expr <'source: 'state> ( - _state: &'state T, _iter: &mut TokenIter<'source> - ) -> Option { - None - } - fn try_from_atom <'source: 'state> ( - state: &'state T, value: Value<'source> - ) -> Option { - if let Exp(0, mut iter) = value { - return Self::try_from_expr(state, &mut iter) - } - None - } -} - -/// Map EDN tokens to parameters of a given type for a given context -pub trait Context<'state, U>: Sized { - fn get <'source> (&'state self, _iter: &mut TokenIter<'source>) -> Option { - None - } -} - -impl<'state, T: Context<'state, U>, U> Context<'state, U> for &T { - fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { - (*self).get(iter) - } -} - -impl<'state, T: Context<'state, U>, U> Context<'state, U> for Option { - fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { - self.as_ref().map(|s|s.get(iter)).flatten() - } -} - /// Implement the const iterator pattern. #[macro_export] macro_rules! const_iter { ($(<$l:lifetime>)?|$self:ident: $Struct:ty| => $Item:ty => $expr:expr) => { @@ -138,6 +102,7 @@ impl<'a> SourceIter<'a> { } } } + /// Static iteration helper. #[macro_export] macro_rules! iterate { ($expr:expr => $arg: pat => $body:expr) => { @@ -240,7 +205,9 @@ pub const fn to_digit (c: char) -> Result { } impl<'source> Token<'source> { - pub const fn new (source: &'source str, start: usize, length: usize, value: Value<'source>) -> Self { + pub const fn new ( + source: &'source str, start: usize, length: usize, value: Value<'source> + ) -> Self { Self { source, start, length, value } } pub const fn end (&self) -> usize { @@ -248,7 +215,6 @@ impl<'source> Token<'source> { } pub const fn slice (&'source self) -> &'source str { self.slice_source(self.source) - //str_range(self.source, self.start, self.end()) } pub const fn slice_source <'range> (&'source self, source: &'range str) -> &'range str { str_range(source, self.start, self.end()) @@ -256,6 +222,9 @@ impl<'source> Token<'source> { pub const fn slice_source_exp <'range> (&'source self, source: &'range str) -> &'range str { str_range(source, self.start.saturating_add(1), self.end()) } + pub const fn with_value (self, value: Value<'source>) -> Self { + Self { value, ..self } + } pub const fn value (&self) -> Value { self.value } @@ -272,49 +241,43 @@ impl<'source> Token<'source> { } } pub const fn grow_key (self) -> Self { - let mut token = self.grow(); - token.value = Key(token.slice_source(self.source)); - token + let token = self.grow(); + token.with_value(Key(token.slice_source(self.source))) } pub const fn grow_sym (self) -> Self { - let mut token = self.grow(); - token.value = Sym(token.slice_source(self.source)); - token + let token = self.grow(); + token.with_value(Sym(token.slice_source(self.source))) } pub const fn grow_str (self) -> Self { - let mut token = self.grow(); - token.value = Str(token.slice_source(self.source)); - token + let token = self.grow(); + token.with_value(Str(token.slice_source(self.source))) } pub const fn grow_exp (self) -> Self { - let mut token = self.grow(); + let token = self.grow(); if let Exp(depth, _) = token.value { - token.value = Exp(depth, TokenIter::new(token.slice_source_exp(self.source))); + token.with_value(Exp(depth, TokenIter::new(token.slice_source_exp(self.source)))) } else { unreachable!() } - token } pub const fn grow_in (self) -> Self { - let mut token = self.grow_exp(); + let token = self.grow_exp(); if let Value::Exp(depth, source) = token.value { - token.value = Value::Exp(depth.saturating_add(1), source) + token.with_value(Value::Exp(depth.saturating_add(1), source)) } else { unreachable!() } - token } pub const fn grow_out (self) -> Self { - let mut token = self.grow_exp(); + let token = self.grow_exp(); if let Value::Exp(depth, source) = token.value { if depth > 0 { - token.value = Value::Exp(depth - 1, source) + token.with_value(Value::Exp(depth - 1, source)) } else { return self.error(Unexpected(')')) } } else { unreachable!() } - token } } diff --git a/dsl/src/dsl_provide.rs b/dsl/src/dsl_provide.rs new file mode 100644 index 0000000..209b37c --- /dev/null +++ b/dsl/src/dsl_provide.rs @@ -0,0 +1,44 @@ +use crate::*; + +/// Map EDN tokens to parameters of a given type for a given context +pub trait Dsl: Sized { + fn take <'state, 'source> (_: &'state Self, _: &mut TokenIter<'source>) -> Perhaps { + Ok(None) + } +} + +/// Map EDN tokens to parameters of a given type for a given context +pub trait Context<'state, U>: Sized { + fn get <'source> (&'state self, _iter: &mut TokenIter<'source>) -> Option { + None + } +} + +impl<'state, T: Context<'state, U>, U> Context<'state, U> for &T { + fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { + (*self).get(iter) + } +} + +impl<'state, T: Context<'state, U>, U> Context<'state, U> for Option { + fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { + self.as_ref().map(|s|s.get(iter)).flatten() + } +} + +pub trait TryFromDsl<'state, T>: Sized { + fn try_from_expr <'source: 'state> ( + _state: &'state T, _iter: &mut TokenIter<'source> + ) -> Option { + None + } + fn try_from_atom <'source: 'state> ( + state: &'state T, value: Value<'source> + ) -> Option { + if let Exp(0, mut iter) = value { + return Self::try_from_expr(state, &mut iter) + } + None + } +} + diff --git a/dsl/src/lib.rs b/dsl/src/lib.rs index c685572..c72ff23 100644 --- a/dsl/src/lib.rs +++ b/dsl/src/lib.rs @@ -1,3 +1,7 @@ +#![feature(adt_const_params)] +#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_fn_trait_return)] + //! [Token]s are parsed substrings with an associated [Value]. //! //! * [ ] FIXME: Value may be [Err] which may shadow [Result::Err] @@ -31,17 +35,18 @@ //! assert_eq!(view.0.0, src); //! assert_eq!(view.peek(), view.0.peek()) //! ``` -#![feature(adt_const_params)] -#![feature(type_alias_impl_trait)] -#![feature(impl_trait_in_fn_trait_return)] -pub(crate) use self::Value::*; -pub(crate) use self::ParseError::*; +pub(crate) use ::tengri_core::*; + +pub(crate) use std::fmt::Debug; pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind}; pub(crate) use konst::string::{split_at, str_range, char_indices}; -pub(crate) use std::fmt::Debug; +pub(crate) use thiserror::Error; +pub(crate) use self::Value::*; +pub(crate) use self::ParseError::*; -mod dsl; pub use self::dsl::*; +mod dsl_parse; pub use self::dsl_parse::*; +mod dsl_provide; pub use self::dsl_provide::*; #[cfg(test)] mod test_token_iter { use crate::*; diff --git a/input/Cargo.toml b/input/Cargo.toml index 3b7772f..d3bf1ec 100644 --- a/input/Cargo.toml +++ b/input/Cargo.toml @@ -4,12 +4,13 @@ description = "UI metaframework, input layer." version = { workspace = true } edition = { workspace = true } -[dependencies] -tengri_dsl = { optional = true, path = "../dsl" } - [features] dsl = [ "tengri_dsl" ] +[dependencies] +tengri_core = { path = "../core" } +tengri_dsl = { optional = true, path = "../dsl" } + [dev-dependencies] tengri_tui = { path = "../tui" } tengri_dsl = { path = "../dsl" } diff --git a/input/src/lib.rs b/input/src/lib.rs index c4c230d..21035fe 100644 --- a/input/src/lib.rs +++ b/input/src/lib.rs @@ -1,18 +1,16 @@ #![feature(associated_type_defaults)] -pub(crate) use std::error::Error; -pub(crate) type Perhaps = Result, Box>; -#[cfg(test)] pub(crate) type Usually = Result>; -#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*; -#[cfg(feature = "dsl")] mod input_dsl; -#[cfg(feature = "dsl")] pub use self::input_dsl::*; +pub(crate) use tengri_core::*; mod input_macros; mod input_command; pub use self::input_command::*; mod input_handle; pub use self::input_handle::*; -#[cfg(test)] -#[test] fn test_stub_input () -> Usually<()> { +#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*; +#[cfg(feature = "dsl")] mod input_dsl; +#[cfg(feature = "dsl")] pub use self::input_dsl::*; + +#[cfg(test)] #[test] fn test_stub_input () -> Usually<()> { use crate::*; struct TestInput(bool); enum TestEvent { Test1 } @@ -33,8 +31,7 @@ mod input_handle; pub use self::input_handle::*; Ok(()) } -#[cfg(all(test, feature = "dsl"))] -#[test] fn test_dsl_keymap () -> Usually<()> { +#[cfg(all(test, feature = "dsl"))] #[test] fn test_dsl_keymap () -> Usually<()> { let keymap = SourceIter::new(""); Ok(()) } diff --git a/output/Cargo.toml b/output/Cargo.toml index 2505df5..5172710 100644 --- a/output/Cargo.toml +++ b/output/Cargo.toml @@ -4,15 +4,16 @@ description = "UI metaframework, output layer." version = { workspace = true } edition = { workspace = true } -[dependencies] -tengri_dsl = { optional = true, path = "../dsl" } - [features] dsl = [ "tengri_dsl" ] +[dependencies] +tengri_core = { path = "../core" } +tengri_dsl = { optional = true, path = "../dsl" } + [dev-dependencies] tengri = { path = "../tengri", features = [ "dsl", "tui" ] } tengri_tui = { path = "../tui" } tengri_dsl = { path = "../dsl" } -proptest = "^1" -proptest-derive = "^0.5.1" +proptest = { workspace = true } +proptest-derive = { workspace = true } diff --git a/output/src/lib.rs b/output/src/lib.rs index 45bf90a..2b12b04 100644 --- a/output/src/lib.rs +++ b/output/src/lib.rs @@ -7,18 +7,13 @@ mod space; pub use self::space::*; mod ops; pub use self::ops::*; mod output; pub use self::output::*; +pub(crate) use tengri_core::*; pub(crate) use std::marker::PhantomData; -pub(crate) use std::error::Error; #[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*; #[cfg(feature = "dsl")] mod view; #[cfg(feature = "dsl")] pub use self::view::*; -/// Standard result type. -pub type Usually = Result>; -/// Standard optional result type. -pub type Perhaps = Result, Box>; - #[cfg(test)] use proptest_derive::Arbitrary; #[cfg(test)] #[test] fn test_stub_output () -> Usually<()> { diff --git a/proc/Cargo.toml b/proc/Cargo.toml index 6001947..d7c3a9a 100644 --- a/proc/Cargo.toml +++ b/proc/Cargo.toml @@ -8,7 +8,8 @@ edition = { workspace = true } proc-macro = true [dependencies] -syn = { version = "2", features = ["full", "extra-traits"] } -quote = { version = "1" } -proc-macro2 = { version = "1", features = ["span-locations"] } -heck = { version = "0.5" } +tengri_core = { path = "../core" } +syn = { workspace = true } +quote = { workspace = true } +proc-macro2 = { workspace = true } +heck = { workspace = true } diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index cc5b134..502041f 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -10,10 +10,7 @@ pub(crate) struct CommandMeta(Ident); pub(crate) struct CommandImpl(ItemImpl, BTreeMap, CommandArm>); #[derive(Debug, Clone)] -struct CommandArm(Ident, Vec, ReturnType); - -#[derive(Debug, Clone)] -struct CommandVariant(Ident, Vec); +struct CommandArm(Ident, Vec, #[allow(unused)] ReturnType); impl Parse for CommandMeta { fn parse (input: ParseStream) -> Result { @@ -203,25 +200,3 @@ impl CommandArm { write_quote(quote! { Self::#variant => Self::#ident(state, #(#give_args)* #give_rest), }) } } - -impl ToTokens for CommandVariant { - fn to_tokens (&self, out: &mut TokenStream2) { - let Self(ident, args) = self; - out.append(LitStr::new(&format!("{}", ident), Span::call_site()) - .token()); - out.append(Group::new(Delimiter::Parenthesis, { - let mut out = TokenStream2::new(); - for arg in args.iter() { - if let FnArg::Typed(PatType { ty, .. }) = arg { - out.append(LitStr::new( - &format!("{}", quote! { #ty }), - Span::call_site() - ).token()); - out.append(Punct::new(',', Alone)); - } - } - out - })); - out.append(Punct::new(',', Alone)); - } -} diff --git a/tengri/Cargo.toml b/tengri/Cargo.toml index 23e87f8..cd87dfc 100644 --- a/tengri/Cargo.toml +++ b/tengri/Cargo.toml @@ -4,7 +4,15 @@ edition = "2024" description = "UI metaframework." version = { workspace = true } +[features] +default = [ "input", "output", "tui" ] +input = [ "tengri_input" ] +output = [ "tengri_output" ] +tui = [ "tengri_tui" ] +dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl", "tengri_tui/dsl" ] + [dependencies] +tengri_core = { path = "../core" } tengri_dsl = { optional = true, path = "../dsl" } tengri_input = { optional = true, path = "../input" } tengri_output = { optional = true, path = "../output" } @@ -13,11 +21,4 @@ tengri_tui = { optional = true, path = "../tui" } [dev-dependencies] tengri_proc = { path = "../proc" } tengri = { path = ".", features = [ "dsl" ] } -crossterm = "0.28.1" - -[features] -default = [ "input", "output", "tui" ] -input = [ "tengri_input" ] -output = [ "tengri_output" ] -tui = [ "tengri_tui" ] -dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl", "tengri_tui/dsl" ] +crossterm = { workspace = true } diff --git a/tengri/src/lib.rs b/tengri/src/lib.rs index 53850cd..5fd2870 100644 --- a/tengri/src/lib.rs +++ b/tengri/src/lib.rs @@ -1,3 +1,4 @@ +pub use ::tengri_core::*; #[cfg(feature="output")] pub use ::tengri_output as output; #[cfg(feature="input")] pub use ::tengri_input as input; #[cfg(feature="dsl")] pub use ::tengri_dsl as dsl; diff --git a/tui/Cargo.toml b/tui/Cargo.toml index a9eb4d9..5fe3f34 100644 --- a/tui/Cargo.toml +++ b/tui/Cargo.toml @@ -4,25 +4,26 @@ description = "UI metaframework, Ratatui backend." version = { workspace = true } edition = { workspace = true } -[dependencies] -palette = { version = "0.7.6", features = [ "random" ] } -rand = "0.8.5" -crossterm = "0.28.1" -ratatui = { version = "0.29.0", features = [ "unstable-widget-ref", "underline-color" ] } -better-panic = "0.3.0" -konst = { version = "0.3.16", features = [ "rust_1_83" ] } -atomic_float = "1" -quanta = "0.12.3" -unicode-width = "0.2" +[features] +dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl" ] +[dependencies] +tengri_core = { path = "../core" } tengri_input = { path = "../input" } tengri_output = { path = "../output" } tengri_dsl = { optional = true, path = "../dsl" } +palette = { workspace = true } +rand = { workspace = true } +crossterm = { workspace = true } +ratatui = { workspace = true } +better-panic = { workspace = true } +konst = { workspace = true } +atomic_float = { workspace = true } +quanta = { workspace = true } +unicode-width = { workspace = true } + [dev-dependencies] tengri = { path = "../tengri", features = [ "dsl" ] } tengri_dsl = { path = "../dsl" } tengri_proc = { path = "../proc" } - -[features] -dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl" ] diff --git a/tui/src/lib.rs b/tui/src/lib.rs index 8e98c58..01eb7d9 100644 --- a/tui/src/lib.rs +++ b/tui/src/lib.rs @@ -3,6 +3,8 @@ mod tui_engine; pub use self::tui_engine::*; mod tui_content; pub use self::tui_content::*; +pub(crate) use ::tengri_core::*; + pub use ::tengri_input as input; pub(crate) use ::tengri_input::*;