mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 03:36:42 +01:00
dsl: add sexpr syntaces; prefix modules
This commit is contained in:
parent
844681d6ad
commit
3d01f5558c
7 changed files with 234 additions and 178 deletions
|
|
@ -10,33 +10,56 @@
|
||||||
//! assert_eq!(view.peek(), view.0.peek())
|
//! assert_eq!(view.peek(), view.0.peek())
|
||||||
//! ```
|
//! ```
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Provides a native [Iterator] API over the [ConstIntoIter] [SourceIter]
|
/// Provides a native [Iterator] API over the [ConstIntoIter] [SourceIter]
|
||||||
/// [TokenIter::next] returns just the [Token] and mutates `self`,
|
/// [TokenIter::next] returns just the [Token] and mutates `self`,
|
||||||
/// instead of returning an updated version of the struct as [SourceIter::next] does.
|
/// 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>);
|
#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct TokenIter<'a>(pub SourceIter<'a>);
|
||||||
impl<'a> TokenIter<'a> {
|
impl<'a> TokenIter<'a> {
|
||||||
pub const fn new (source: &'a str) -> Self { Self(SourceIter::new(source)) }
|
pub const fn new (source: &'a str) -> Self {
|
||||||
pub const fn peek (&self) -> Option<Token<'a>> { self.0.peek() }
|
Self(SourceIter::new(source))
|
||||||
|
}
|
||||||
|
pub const fn peek (&self) -> Option<Token<'a>> {
|
||||||
|
self.0.peek()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for TokenIter<'a> {
|
impl<'a> Iterator for TokenIter<'a> {
|
||||||
type Item = Token<'a>;
|
type Item = Token<'a>;
|
||||||
fn next (&mut self) -> Option<Token<'a>> {
|
fn next (&mut self) -> Option<Token<'a>> {
|
||||||
self.0.next().map(|(item, rest)|{self.0 = rest; item})
|
self.0.next().map(|(item, rest)|{self.0 = rest; item})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Owns a reference to the source text.
|
/// Owns a reference to the source text.
|
||||||
/// [SourceIter::next] emits subsequent pairs of:
|
/// [SourceIter::next] emits subsequent pairs of:
|
||||||
/// * a [Token] and
|
/// * a [Token] and
|
||||||
/// * the source text remaining
|
/// * the source text remaining
|
||||||
/// * [ ] TODO: maybe [SourceIter::next] should wrap the remaining source in `Self` ?
|
/// * [ ] 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));
|
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> {
|
impl<'a> SourceIter<'a> {
|
||||||
pub const fn new (source: &'a str) -> Self { Self(source) }
|
pub const fn new (source: &'a str) -> Self {
|
||||||
pub const fn chomp (&self, index: usize) -> Self { Self(split_at(self.0, index).1) }
|
Self(source)
|
||||||
pub const fn next (mut self) -> Option<(Token<'a>, Self)> { Self::next_mut(&mut self) }
|
}
|
||||||
pub const fn peek (&self) -> Option<Token<'a>> { peek_src(self.0) }
|
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<Token<'a>> {
|
||||||
|
peek_src(self.0)
|
||||||
|
}
|
||||||
pub const fn next_mut (&mut self) -> Option<(Token<'a>, Self)> {
|
pub const fn next_mut (&mut self) -> Option<(Token<'a>, Self)> {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
Some(token) => Some((token, self.chomp(token.end()))),
|
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<Token<'a>> {
|
pub const fn peek_src <'a> (source: &'a str) -> Option<Token<'a>> {
|
||||||
let mut token: Token<'a> = Token::new(source, 0, 0, Nil);
|
let mut token: Token<'a> = Token::new(source, 0, 0, Nil);
|
||||||
iterate!(char_indices(source) => (start, c) => token = match token.value() {
|
iterate!(char_indices(source) => (start, c) => token = match token.value() {
|
||||||
|
|
@ -93,6 +117,7 @@ pub const fn peek_src <'a> (source: &'a str) -> Option<Token<'a>> {
|
||||||
_ => Some(token),
|
_ => Some(token),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn to_number (digits: &str) -> Result<usize, ParseError> {
|
pub const fn to_number (digits: &str) -> Result<usize, ParseError> {
|
||||||
let mut value = 0;
|
let mut value = 0;
|
||||||
iterate!(char_indices(digits) => (_, c) => match to_digit(c) {
|
iterate!(char_indices(digits) => (_, c) => match to_digit(c) {
|
||||||
|
|
@ -101,6 +126,7 @@ pub const fn to_number (digits: &str) -> Result<usize, ParseError> {
|
||||||
});
|
});
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn to_digit (c: char) -> Result<usize, ParseError> {
|
pub const fn to_digit (c: char) -> Result<usize, ParseError> {
|
||||||
Ok(match c {
|
Ok(match c {
|
||||||
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4,
|
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4,
|
||||||
|
|
@ -108,37 +134,3 @@ pub const fn to_digit (c: char) -> Result<usize, ParseError> {
|
||||||
_ => return Result::Err(Unexpected(c))
|
_ => 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();
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
84
dsl/src/dsl_macros.rs
Normal file
84
dsl/src/dsl_macros.rs
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -22,12 +22,14 @@
|
||||||
//!```
|
//!```
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use self::Value::*;
|
use self::Value::*;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'a> {
|
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'a> {
|
||||||
pub source: &'a str,
|
pub source: &'a str,
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
pub length: usize,
|
pub length: usize,
|
||||||
pub value: Value<'a>,
|
pub value: Value<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'a> {
|
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'a> {
|
||||||
#[default] Nil,
|
#[default] Nil,
|
||||||
Err(ParseError),
|
Err(ParseError),
|
||||||
|
|
@ -36,6 +38,7 @@ use self::Value::*;
|
||||||
Key(&'a str),
|
Key(&'a str),
|
||||||
Exp(usize, TokenIter<'a>),
|
Exp(usize, TokenIter<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Token<'a> {
|
impl<'a> Token<'a> {
|
||||||
pub const fn new (source: &'a str, start: usize, length: usize, value: Value<'a>) -> Self {
|
pub const fn new (source: &'a str, start: usize, length: usize, value: Value<'a>) -> Self {
|
||||||
Self { source, start, length, value }
|
Self { source, start, length, value }
|
||||||
|
|
@ -110,60 +113,3 @@ impl<'a> Token<'a> {
|
||||||
token
|
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<dyn std::error::Error>> {
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
179
dsl/src/lib.rs
179
dsl/src/lib.rs
|
|
@ -1,91 +1,18 @@
|
||||||
#![feature(adt_const_params)]
|
#![feature(adt_const_params)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(impl_trait_in_fn_trait_return)]
|
#![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::Value::*;
|
||||||
pub(crate) use self::ParseError::*;
|
pub(crate) use self::ParseError::*;
|
||||||
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
|
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
|
||||||
pub(crate) use konst::string::{split_at, str_range, char_indices};
|
pub(crate) use konst::string::{split_at, str_range, char_indices};
|
||||||
pub(crate) use std::fmt::Debug;
|
pub(crate) use std::fmt::Debug;
|
||||||
|
|
||||||
/// Static iteration helper.
|
mod dsl_error; pub use self::dsl_error::*;
|
||||||
#[macro_export] macro_rules! iterate {
|
mod dsl_token; pub use self::dsl_token::*;
|
||||||
($expr:expr => $arg: pat => $body:expr) => {
|
mod dsl_iter; pub use self::dsl_iter::*;
|
||||||
let mut iter = $expr;
|
mod dsl_context; pub use self::dsl_context::*;
|
||||||
while let Some(($arg, next)) = iter.next() {
|
mod dsl_macros; pub use self::dsl_macros::*;
|
||||||
$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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> {
|
//#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> {
|
||||||
//// Let's pretend to render some view.
|
//// Let's pretend to render some view.
|
||||||
|
|
@ -111,3 +38,97 @@ pub(crate) use std::fmt::Debug;
|
||||||
////}
|
////}
|
||||||
//Ok(())
|
//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<dyn std::error::Error>> {
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ impl KeyMatcher {
|
||||||
"down" => Down,
|
"down" => Down,
|
||||||
"left" => Left,
|
"left" => Left,
|
||||||
"right" => Right,
|
"right" => Right,
|
||||||
|
"esc" | "escape" => Esc,
|
||||||
"enter" | "return" => Enter,
|
"enter" | "return" => Enter,
|
||||||
"delete" | "del" => Delete,
|
"delete" | "del" => Delete,
|
||||||
"tab" => Tab,
|
"tab" => Tab,
|
||||||
|
|
@ -120,6 +121,18 @@ impl KeyMatcher {
|
||||||
"gt" => Char('>'),
|
"gt" => Char('>'),
|
||||||
"openbracket" => Char('['),
|
"openbracket" => Char('['),
|
||||||
"closebracket" => 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,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue