diff --git a/dsl/src/context.rs b/dsl/src/dsl_context.rs similarity index 100% rename from dsl/src/context.rs rename to dsl/src/dsl_context.rs diff --git a/dsl/src/error.rs b/dsl/src/dsl_error.rs similarity index 100% rename from dsl/src/error.rs rename to dsl/src/dsl_error.rs diff --git a/dsl/src/iter.rs b/dsl/src/dsl_iter.rs similarity index 69% rename from dsl/src/iter.rs rename to dsl/src/dsl_iter.rs index 7f36289..de9fe7a 100644 --- a/dsl/src/iter.rs +++ b/dsl/src/dsl_iter.rs @@ -10,33 +10,56 @@ //! assert_eq!(view.peek(), view.0.peek()) //! ``` use crate::*; + /// Provides a native [Iterator] API over the [ConstIntoIter] [SourceIter] /// [TokenIter::next] returns just the [Token] and mutates `self`, /// instead of returning an updated version of the struct as [SourceIter::next] does. #[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct TokenIter<'a>(pub SourceIter<'a>); impl<'a> TokenIter<'a> { - pub const fn new (source: &'a str) -> Self { Self(SourceIter::new(source)) } - pub const fn peek (&self) -> Option> { self.0.peek() } + pub const fn new (source: &'a str) -> Self { + Self(SourceIter::new(source)) + } + pub const fn peek (&self) -> Option> { + self.0.peek() + } } + impl<'a> Iterator for TokenIter<'a> { type Item = Token<'a>; fn next (&mut self) -> Option> { self.0.next().map(|(item, rest)|{self.0 = rest; item}) } } + /// Owns a reference to the source text. /// [SourceIter::next] emits subsequent pairs of: /// * a [Token] and /// * the source text remaining /// * [ ] TODO: maybe [SourceIter::next] should wrap the remaining source in `Self` ? -#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct SourceIter<'a>(pub &'a str); +#[derive(Copy, Clone, Debug, Default, PartialEq)] +pub struct SourceIter<'a>(pub &'a str); + const_iter!(<'a>|self: SourceIter<'a>| => Token<'a> => self.next_mut().map(|(result, _)|result)); -impl<'a> From<&'a str> for SourceIter<'a> {fn from (source: &'a str) -> Self{Self::new(source)}} + +impl<'a> From<&'a str> for SourceIter<'a> { + fn from (source: &'a str) -> Self{ + Self::new(source) + } +} + impl<'a> SourceIter<'a> { - pub const fn new (source: &'a str) -> Self { Self(source) } - pub const fn chomp (&self, index: usize) -> Self { Self(split_at(self.0, index).1) } - pub const fn next (mut self) -> Option<(Token<'a>, Self)> { Self::next_mut(&mut self) } - pub const fn peek (&self) -> Option> { peek_src(self.0) } + pub const fn new (source: &'a str) -> Self { + Self(source) + } + pub const fn chomp (&self, index: usize) -> Self { + Self(split_at(self.0, index).1) + } + pub const fn next (mut self) -> Option<(Token<'a>, Self)> { + Self::next_mut(&mut self) + } + pub const fn peek (&self) -> Option> { + peek_src(self.0) + } pub const fn next_mut (&mut self) -> Option<(Token<'a>, Self)> { match self.peek() { Some(token) => Some((token, self.chomp(token.end()))), @@ -44,6 +67,7 @@ impl<'a> SourceIter<'a> { } } } + pub const fn peek_src <'a> (source: &'a str) -> Option> { let mut token: Token<'a> = Token::new(source, 0, 0, Nil); iterate!(char_indices(source) => (start, c) => token = match token.value() { @@ -93,6 +117,7 @@ pub const fn peek_src <'a> (source: &'a str) -> Option> { _ => Some(token), } } + pub const fn to_number (digits: &str) -> Result { let mut value = 0; iterate!(char_indices(digits) => (_, c) => match to_digit(c) { @@ -101,6 +126,7 @@ pub const fn to_number (digits: &str) -> Result { }); Ok(value) } + pub const fn to_digit (c: char) -> Result { Ok(match c { '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, @@ -108,37 +134,3 @@ pub const fn to_digit (c: char) -> Result { _ => return Result::Err(Unexpected(c)) }) } -#[cfg(test)] mod test_token_iter { - use super::*; - //use proptest::prelude::*; - #[test] fn test_iters () { - let mut iter = crate::SourceIter::new(&":foo :bar"); - let _ = iter.next(); - let mut iter = crate::TokenIter::new(&":foo :bar"); - let _ = iter.next(); - } - #[test] const fn test_const_iters () { - let mut iter = crate::SourceIter::new(&":foo :bar"); - let _ = iter.next(); - } - #[test] fn test_num () { - let digit = to_digit('0'); - let digit = to_digit('x'); - let number = to_number(&"123"); - let number = to_number(&"12asdf3"); - } - //proptest! { - //#[test] fn proptest_source_iter ( - //source in "\\PC*" - //) { - //let mut iter = crate::SourceIter::new(&source); - ////let _ = iter.next(); - //} - //#[test] fn proptest_token_iter ( - //source in "\\PC*" - //) { - //let mut iter = crate::TokenIter::new(&source); - ////let _ = iter.next(); - //} - //} -} diff --git a/dsl/src/dsl_macros.rs b/dsl/src/dsl_macros.rs new file mode 100644 index 0000000..b40f380 --- /dev/null +++ b/dsl/src/dsl_macros.rs @@ -0,0 +1,84 @@ +use crate::*; + +/// Static iteration helper. +#[macro_export] macro_rules! iterate { + ($expr:expr => $arg: pat => $body:expr) => { + let mut iter = $expr; + while let Some(($arg, next)) = iter.next() { + $body; + iter = next; + } + } +} + +/// Implement the const iterator pattern. +#[macro_export] macro_rules! const_iter { + ($(<$l:lifetime>)?|$self:ident: $Struct:ty| => $Item:ty => $expr:expr) => { + impl$(<$l>)? Iterator for $Struct { + type Item = $Item; + fn next (&mut $self) -> Option<$Item> { $expr } + } + impl$(<$l>)? ConstIntoIter for $Struct { + type Kind = IsIteratorKind; + type Item = $Item; + type IntoIter = Self; + } + } +} + +#[macro_export] macro_rules! expose { + ($([$self:ident:$State:ty] $(($Type:ty $(: $(($pat:literal $expr:expr))*)?))*)*) => { + $(expose!(@impl [$self: $State] { $([$Type] => { $($($pat => $expr),*)? })* });)* + }; + ($([$self:ident:$State:ty] { $([$($Type:tt)*] => { $($pat:pat => $expr:expr),* $(,)? })* })*) => { + $(expose!(@impl [$self: $State] { $([$($Type)*] => { $($pat => $expr),* })* });)* + }; + (@impl [$self:ident:$State:ty] { $([$($Type:tt)*] => { $($pat:pat => $expr:expr),* $(,)? })* }) => { + $(expose!(@type [$($Type)*] [$self: $State] => { $($pat => $expr),* });)* + }; + (@type [bool] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { + provide_bool!(bool: |$self: $State| { $($pat => $expr),* }); + }; + (@type [u16] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { + provide_num!(u16: |$self: $State| { $($pat => $expr),* }); + }; + (@type [usize] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { + provide_num!(usize: |$self: $State| { $($pat => $expr),* }); + }; + (@type [isize] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { + provide_num!(isize: |$self: $State| { $($pat => $expr),* }); + }; + (@type [$Type:ty] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { + provide!($Type: |$self: $State| { $($pat => $expr),* }); + }; +} + +#[macro_export] macro_rules! impose { + ([$self:ident:$Struct:ty] $(($Command:ty : $(($cmd:literal $args:tt $result:expr))*))*) => { + $(atom_command!($Command: |$self: $Struct| { $(($cmd $args $result))* });)* + }; + ([$self:ident:$Struct:ty] { $($Command:ty => $variants:tt)* }) => { + $(atom_command!($Command: |$self: $Struct| $variants);)* + }; +} + +#[macro_export] macro_rules! get_value { + ($state:expr => $token:expr) => { + if let Some(value) = $state.get(&$token.value) { + value + } else { + panic!("no value corresponding to {:?}", &$token.value); + } + } +} + +#[macro_export] macro_rules! get_content { + ($state:expr => $token:expr) => { + if let Some(content) = $state.get_content(&$token.value) { + content + } else { + panic!("no content corresponding to {:?}", &$token.value); + } + } +} + diff --git a/dsl/src/token.rs b/dsl/src/dsl_token.rs similarity index 66% rename from dsl/src/token.rs rename to dsl/src/dsl_token.rs index 467aeeb..855a5e8 100644 --- a/dsl/src/token.rs +++ b/dsl/src/dsl_token.rs @@ -22,12 +22,14 @@ //!``` use crate::*; use self::Value::*; + #[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'a> { pub source: &'a str, pub start: usize, pub length: usize, pub value: Value<'a>, } + #[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'a> { #[default] Nil, Err(ParseError), @@ -36,6 +38,7 @@ use self::Value::*; Key(&'a str), Exp(usize, TokenIter<'a>), } + impl<'a> Token<'a> { pub const fn new (source: &'a str, start: usize, length: usize, value: Value<'a>) -> Self { Self { source, start, length, value } @@ -110,60 +113,3 @@ impl<'a> Token<'a> { token } } -#[cfg(test)] mod test_token_prop { - use proptest::prelude::*; - proptest! { - #[test] fn test_token_prop ( - source in "\\PC*", - start in usize::MIN..usize::MAX, - length in usize::MIN..usize::MAX, - ) { - let token = crate::Token { - source: &source, - start, - length, - value: crate::Value::Nil - }; - let _ = token.slice(); - } - } -} -#[cfg(test)] #[test] fn test_token () -> Result<(), Box> { - let source = ":f00"; - let mut token = Token { source, start: 0, length: 1, value: Sym(":") }; - token = token.grow_sym(); - assert_eq!(token, Token { source, start: 0, length: 2, value: Sym(":f") }); - token = token.grow_sym(); - assert_eq!(token, Token { source, start: 0, length: 3, value: Sym(":f0") }); - token = token.grow_sym(); - assert_eq!(token, Token { source, start: 0, length: 4, value: Sym(":f00") }); - - let src = ""; - assert_eq!(None, SourceIter(src).next()); - - let src = " \n \r \t "; - assert_eq!(None, SourceIter(src).next()); - - let src = "7"; - assert_eq!(Num(7), SourceIter(src).next().unwrap().0.value); - - let src = " 100 "; - assert_eq!(Num(100), SourceIter(src).next().unwrap().0.value); - - let src = " 9a "; - assert_eq!(Err(Unexpected('a')), SourceIter(src).next().unwrap().0.value); - - let src = " :123foo "; - assert_eq!(Sym(":123foo"), SourceIter(src).next().unwrap().0.value); - - let src = " \r\r\r\n\n\n@bar456\t\t\t\t\t\t"; - assert_eq!(Sym("@bar456"), SourceIter(src).next().unwrap().0.value); - - let src = "foo123"; - assert_eq!(Key("foo123"), SourceIter(src).next().unwrap().0.value); - - let src = "foo/bar"; - assert_eq!(Key("foo/bar"), SourceIter(src).next().unwrap().0.value); - - Ok(()) -} diff --git a/dsl/src/lib.rs b/dsl/src/lib.rs index b42f442..f6e2dac 100644 --- a/dsl/src/lib.rs +++ b/dsl/src/lib.rs @@ -1,91 +1,18 @@ #![feature(adt_const_params)] #![feature(type_alias_impl_trait)] #![feature(impl_trait_in_fn_trait_return)] -mod error; pub use self::error::*; -mod token; pub use self::token::*; -mod iter; pub use self::iter::*; -mod context; pub use self::context::*; + pub(crate) use self::Value::*; pub(crate) use self::ParseError::*; pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind}; pub(crate) use konst::string::{split_at, str_range, char_indices}; pub(crate) use std::fmt::Debug; -/// Static iteration helper. -#[macro_export] macro_rules! iterate { - ($expr:expr => $arg: pat => $body:expr) => { - let mut iter = $expr; - while let Some(($arg, next)) = iter.next() { - $body; - iter = next; - } - } -} - -/// Implement the const iterator pattern. -#[macro_export] macro_rules! const_iter { - ($(<$l:lifetime>)?|$self:ident: $Struct:ty| => $Item:ty => $expr:expr) => { - impl$(<$l>)? Iterator for $Struct { - type Item = $Item; - fn next (&mut $self) -> Option<$Item> { $expr } - } - impl$(<$l>)? ConstIntoIter for $Struct { - type Kind = IsIteratorKind; - type Item = $Item; - type IntoIter = Self; - } - } -} - -#[macro_export] macro_rules! expose { - ($([$self:ident:$State:ty] { $([$($Type:tt)*] => { $($pat:pat => $expr:expr),* $(,)? })* })*) => { - $(expose!(@impl [$self: $State] { $([$($Type)*] => { $($pat => $expr),* })* });)* - }; - (@impl [$self:ident:$State:ty] { $([$($Type:tt)*] => { $($pat:pat => $expr:expr),* $(,)? })* }) => { - $(expose!(@type [$($Type)*] [$self: $State] => { $($pat => $expr),* });)* - }; - (@type [bool] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_bool!(bool: |$self: $State| { $($pat => $expr),* }); - }; - (@type [u16] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(u16: |$self: $State| { $($pat => $expr),* }); - }; - (@type [usize] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(usize: |$self: $State| { $($pat => $expr),* }); - }; - (@type [isize] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(isize: |$self: $State| { $($pat => $expr),* }); - }; - (@type [$Type:ty] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide!($Type: |$self: $State| { $($pat => $expr),* }); - }; -} - -#[macro_export] macro_rules! impose { - ([$self:ident:$Struct:ty] { $($Command:ty => $variants:tt)* }) => { - $(atom_command!($Command: |$self: $Struct| $variants);)* - }; -} - -#[macro_export] macro_rules! get_value { - ($state:expr => $token:expr) => { - if let Some(value) = $state.get(&$token.value) { - value - } else { - panic!("no value corresponding to {:?}", &$token.value); - } - } -} - -#[macro_export] macro_rules! get_content { - ($state:expr => $token:expr) => { - if let Some(content) = $state.get_content(&$token.value) { - content - } else { - panic!("no content corresponding to {:?}", &$token.value); - } - } -} +mod dsl_error; pub use self::dsl_error::*; +mod dsl_token; pub use self::dsl_token::*; +mod dsl_iter; pub use self::dsl_iter::*; +mod dsl_context; pub use self::dsl_context::*; +mod dsl_macros; pub use self::dsl_macros::*; //#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> { //// Let's pretend to render some view. @@ -111,3 +38,97 @@ pub(crate) use std::fmt::Debug; ////} //Ok(()) //} + +#[cfg(test)] mod test_token_iter { + use crate::*; + //use proptest::prelude::*; + #[test] fn test_iters () { + let mut iter = crate::SourceIter::new(&":foo :bar"); + let _ = iter.next(); + let mut iter = crate::TokenIter::new(&":foo :bar"); + let _ = iter.next(); + } + #[test] const fn test_const_iters () { + let mut iter = crate::SourceIter::new(&":foo :bar"); + let _ = iter.next(); + } + #[test] fn test_num () { + let digit = to_digit('0'); + let digit = to_digit('x'); + let number = to_number(&"123"); + let number = to_number(&"12asdf3"); + } + //proptest! { + //#[test] fn proptest_source_iter ( + //source in "\\PC*" + //) { + //let mut iter = crate::SourceIter::new(&source); + ////let _ = iter.next(); + //} + //#[test] fn proptest_token_iter ( + //source in "\\PC*" + //) { + //let mut iter = crate::TokenIter::new(&source); + ////let _ = iter.next(); + //} + //} +} + +#[cfg(test)] mod test_token_prop { + use proptest::prelude::*; + proptest! { + #[test] fn test_token_prop ( + source in "\\PC*", + start in usize::MIN..usize::MAX, + length in usize::MIN..usize::MAX, + ) { + let token = crate::Token { + source: &source, + start, + length, + value: crate::Value::Nil + }; + let _ = token.slice(); + } + } +} + +#[cfg(test)] #[test] fn test_token () -> Result<(), Box> { + let source = ":f00"; + let mut token = Token { source, start: 0, length: 1, value: Sym(":") }; + token = token.grow_sym(); + assert_eq!(token, Token { source, start: 0, length: 2, value: Sym(":f") }); + token = token.grow_sym(); + assert_eq!(token, Token { source, start: 0, length: 3, value: Sym(":f0") }); + token = token.grow_sym(); + assert_eq!(token, Token { source, start: 0, length: 4, value: Sym(":f00") }); + + let src = ""; + assert_eq!(None, SourceIter(src).next()); + + let src = " \n \r \t "; + assert_eq!(None, SourceIter(src).next()); + + let src = "7"; + assert_eq!(Num(7), SourceIter(src).next().unwrap().0.value); + + let src = " 100 "; + assert_eq!(Num(100), SourceIter(src).next().unwrap().0.value); + + let src = " 9a "; + assert_eq!(Err(Unexpected('a')), SourceIter(src).next().unwrap().0.value); + + let src = " :123foo "; + assert_eq!(Sym(":123foo"), SourceIter(src).next().unwrap().0.value); + + let src = " \r\r\r\n\n\n@bar456\t\t\t\t\t\t"; + assert_eq!(Sym("@bar456"), SourceIter(src).next().unwrap().0.value); + + let src = "foo123"; + assert_eq!(Key("foo123"), SourceIter(src).next().unwrap().0.value); + + let src = "foo/bar"; + assert_eq!(Key("foo/bar"), SourceIter(src).next().unwrap().0.value); + + Ok(()) +} diff --git a/tui/src/tui_engine/tui_input.rs b/tui/src/tui_engine/tui_input.rs index d09aa86..6f1c661 100644 --- a/tui/src/tui_engine/tui_input.rs +++ b/tui/src/tui_engine/tui_input.rs @@ -105,6 +105,7 @@ impl KeyMatcher { "down" => Down, "left" => Left, "right" => Right, + "esc" | "escape" => Esc, "enter" | "return" => Enter, "delete" | "del" => Delete, "tab" => Tab, @@ -120,6 +121,18 @@ impl KeyMatcher { "gt" => Char('>'), "openbracket" => Char('['), "closebracket" => Char(']'), + "f1" => F(1), + "f2" => F(2), + "f3" => F(3), + "f4" => F(4), + "f5" => F(5), + "f6" => F(6), + "f7" => F(7), + "f8" => F(8), + "f9" => F(9), + "f10" => F(10), + "f11" => F(11), + "f12" => F(12), _ => return None, }) }