mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
test top level expr parsing
This commit is contained in:
parent
d14d67172c
commit
9756862091
7 changed files with 129 additions and 82 deletions
|
|
@ -20,48 +20,44 @@ pub const fn peek_src <'a> (source: &'a str) -> Option<Token<'a>> {
|
|||
Err(_) => return Some(token),
|
||||
Nil => match c {
|
||||
' '|'\n'|'\r'|'\t' => token.grow(),
|
||||
'(' => Token {
|
||||
source, start, length: 1,
|
||||
'(' => Token { source, start, length: 1,
|
||||
value: Value::Exp(1, TokenIter(str_range(source, start, start + 1))),
|
||||
},
|
||||
'0'..='9' => Token {
|
||||
source, start, length: 1,
|
||||
':'|'@' => Token { source, start, length: 1,
|
||||
value: Value::Sym(str_range(source, start, start + 1)),
|
||||
},
|
||||
'/'|'a'..='z' => Token { source, start, length: 1,
|
||||
value: Value::Key(str_range(source, start, start + 1)),
|
||||
},
|
||||
'0'..='9' => Token { source, start, length: 1,
|
||||
value: match to_digit(c) {
|
||||
Ok(c) => Value::Num(c),
|
||||
Result::Err(e) => Value::Err(e)
|
||||
}
|
||||
},
|
||||
':'|'@' => Token {
|
||||
source, start, length: 1,
|
||||
value: Value::Sym(str_range(source, start, start + 1)),
|
||||
},
|
||||
'/'|'a'..='z' => Token {
|
||||
source, start, length: 1,
|
||||
value: Value::Key(str_range(source, start, start + 1)),
|
||||
},
|
||||
_ => token.error(Unexpected(c))
|
||||
},
|
||||
Num(_) => match c {
|
||||
'0'..='9' => token.grow(),
|
||||
Num(n) => match c {
|
||||
'0'..='9' => token.grow_num(n, c),
|
||||
' '|'\n'|'\r'|'\t' => return Some(token),
|
||||
_ => token.error(Unexpected(c))
|
||||
},
|
||||
Sym(_) => match c {
|
||||
'a'..='z'|'0'..='9'|'-' => token.grow(),
|
||||
'a'..='z'|'0'..='9'|'-' => token.grow_sym(),
|
||||
' '|'\n'|'\r'|'\t' => return Some(token),
|
||||
_ => token.error(Unexpected(c))
|
||||
},
|
||||
Key(_) => match c {
|
||||
'a'..='z'|'0'..='9'|'-'|'/' => token.grow(),
|
||||
'a'..='z'|'0'..='9'|'-'|'/' => token.grow_key(),
|
||||
' '|'\n'|'\r'|'\t' => return Some(token),
|
||||
_ => token.error(Unexpected(c))
|
||||
},
|
||||
Exp(depth, _) => match depth {
|
||||
0 => return Some(token),
|
||||
0 => return Some(token.grow_exp()),
|
||||
_ => match c {
|
||||
')' => token.grow_out(),
|
||||
'(' => token.grow_in(),
|
||||
_ => token.grow(),
|
||||
_ => token.grow_exp(),
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,44 +43,65 @@ pub(crate) use std::fmt::{Debug, Display, Formatter, Result as FormatResult, Err
|
|||
}
|
||||
}
|
||||
#[cfg(test)] #[test] fn test_token () -> Result<(), Box<dyn std::error::Error>> {
|
||||
use Token::*;
|
||||
assert_eq!(Nil, Token::chomp_one("")?);
|
||||
assert_eq!(Nil, Token::chomp_one(" \n \r \t ")?);
|
||||
assert_eq!(Num("8", 0, 1), Token::chomp_one("8")?);
|
||||
assert_eq!(Num(" 8 ", 3, 1), Token::chomp_one(" 8 ")?);
|
||||
assert_eq!(Sym(":foo", 0, 4), Token::chomp_one(":foo")?);
|
||||
assert_eq!(Sym("@bar", 0, 4), Token::chomp_one("@bar")?);
|
||||
assert_eq!(Key("foo/bar", 0, 7), Token::chomp_one("foo/bar")?);
|
||||
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, TokenIter(src).next());
|
||||
|
||||
let src = " \n \r \t ";
|
||||
assert_eq!(None, TokenIter(src).next());
|
||||
|
||||
let src = "7";
|
||||
assert_eq!(Num(7), TokenIter(src).next().unwrap().0.value);
|
||||
|
||||
let src = " 100 ";
|
||||
assert_eq!(Num(100), TokenIter(src).next().unwrap().0.value);
|
||||
|
||||
let src = " 9a ";
|
||||
assert_eq!(Err(Unexpected('a')), TokenIter(src).next().unwrap().0.value);
|
||||
|
||||
let src = " :123foo ";
|
||||
assert_eq!(Sym(":123foo"), TokenIter(src).next().unwrap().0.value);
|
||||
|
||||
let src = " \r\r\r\n\n\n@bar456\t\t\t\t\t\t";
|
||||
assert_eq!(Sym("@bar456"), TokenIter(src).next().unwrap().0.value);
|
||||
|
||||
let src = "foo123";
|
||||
assert_eq!(Key("foo123"), TokenIter(src).next().unwrap().0.value);
|
||||
|
||||
let src = "foo/bar";
|
||||
assert_eq!(Key("foo/bar"), TokenIter(src).next().unwrap().0.value);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(test)] #[test] fn test_lang () -> Result<(), ParseError> {
|
||||
use Atom::*;
|
||||
assert_eq!(Atom::read_all("")?,
|
||||
vec![]);
|
||||
assert_eq!(Atom::read_all(" ")?,
|
||||
vec![]);
|
||||
assert_eq!(Atom::read_all("1234")?,
|
||||
vec![Num(1234)]);
|
||||
assert_eq!(Atom::read_all("1234 5 67")?,
|
||||
vec![Num(1234), Num(5), Num(67)]);
|
||||
assert_eq!(Atom::read_all("foo/bar")?,
|
||||
vec![Key("foo/bar".into())]);
|
||||
assert_eq!(Atom::read_all(":symbol")?,
|
||||
vec![Sym(":symbol".into())]);
|
||||
assert_eq!(Atom::read_all(" foo/bar :baz 456")?,
|
||||
vec![Key("foo/bar".into()), Sym(":baz".into()), Num(456)]);
|
||||
assert_eq!(Atom::read_all(" (foo/bar :baz 456) ")?,
|
||||
vec![Exp(vec![Key("foo/bar".into()), Sym(":baz".into()), Num(456)])]);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(test)] #[test] fn test_lang_examples () -> Result<(), ParseError> {
|
||||
for example in [
|
||||
include_str!("../../tui/examples/edn01.edn"),
|
||||
include_str!("../../tui/examples/edn02.edn"),
|
||||
] {
|
||||
let items = Atom::read_all(example)?;
|
||||
//panic!("{layout:?}");
|
||||
//let content = <dyn ViewContext<::tek_engine::tui::Tui>>::from(&layout);
|
||||
}
|
||||
#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> {
|
||||
let src = include_str!("../../tek/src/view_arranger.edn");
|
||||
let mut view = TokenIter(src);
|
||||
assert_eq!(view.0, src);
|
||||
let mut expr = view.peek();
|
||||
assert_eq!(view.0, src);
|
||||
assert_eq!(expr, Some(Token {
|
||||
source: src,
|
||||
start: 0,
|
||||
length: src.len(),
|
||||
value: Exp(0, TokenIter(src))
|
||||
}));
|
||||
//panic!("{view:?}");
|
||||
//panic!("{:#?}", expr);
|
||||
//for example in [
|
||||
//include_str!("../../tui/examples/edn01.edn"),
|
||||
//include_str!("../../tui/examples/edn02.edn"),
|
||||
//] {
|
||||
////let items = Atom::read_all(example)?;
|
||||
////panic!("{layout:?}");
|
||||
////let content = <dyn ViewContext<::tek_engine::tui::Tui>>::from(&layout);
|
||||
//}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use self::Value::*;
|
|||
pub source: &'a str,
|
||||
pub start: usize,
|
||||
pub length: usize,
|
||||
pub value: Value<'a>,
|
||||
pub value: Value<'a>,
|
||||
}
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'a> {
|
||||
#[default] Nil,
|
||||
|
|
@ -37,25 +37,51 @@ impl<'a> Token<'a> {
|
|||
pub const fn grow (self) -> Self {
|
||||
Self { length: self.length + 1, ..self }
|
||||
}
|
||||
pub const fn grow_in (self) -> Self {
|
||||
match self.value {
|
||||
Value::Exp(depth, source) => Self {
|
||||
value: Value::Exp(depth + 1, TokenIter(self.grow().slice_source(source.0))),
|
||||
..self.grow()
|
||||
},
|
||||
_ => self.grow()
|
||||
pub const fn grow_num (self, m: usize, c: char) -> Self {
|
||||
match to_digit(c) {
|
||||
Ok(n) => Self { value: Num(10*m+n), ..self.grow() },
|
||||
Result::Err(e) => Self { value: Err(e), ..self.grow() },
|
||||
}
|
||||
}
|
||||
pub const fn grow_key (self) -> Self {
|
||||
let mut token = self.grow();
|
||||
token.value = Key(token.slice_source(self.source));
|
||||
token
|
||||
}
|
||||
pub const fn grow_sym (self) -> Self {
|
||||
let mut token = self.grow();
|
||||
token.value = Sym(token.slice_source(self.source));
|
||||
token
|
||||
}
|
||||
pub const fn grow_exp (self) -> Self {
|
||||
let mut token = self.grow();
|
||||
if let Exp(depth, _) = token.value {
|
||||
token.value = Exp(depth, TokenIter(token.slice_source(self.source)));
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
token
|
||||
}
|
||||
pub const fn grow_in (self) -> Self {
|
||||
let mut token = self.grow_exp();
|
||||
if let Value::Exp(depth, source) = token.value {
|
||||
token.value = Value::Exp(depth + 1, source)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
token
|
||||
}
|
||||
pub const fn grow_out (self) -> Self {
|
||||
match self.value {
|
||||
Value::Exp(depth, source) => match depth {
|
||||
0 => self.error(Unexpected(')')),
|
||||
d => Self {
|
||||
value: Value::Exp(d - 1, TokenIter(self.grow().slice_source(source.0))),
|
||||
..self.grow()
|
||||
}
|
||||
},
|
||||
_ => self.grow()
|
||||
let mut token = self.grow_exp();
|
||||
if let Value::Exp(depth, source) = token.value {
|
||||
if depth > 0 {
|
||||
token.value = Value::Exp(depth - 1, source)
|
||||
} else {
|
||||
return self.error(Unexpected(')'))
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
token
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ impl<E: Output, A: Content<E>, B: Content<E>> Content<E> for Bsp<A, B> {
|
|||
}
|
||||
}
|
||||
try_from_expr!(<'a, E>: Bsp<RenderBox<'a, E>, RenderBox<'a, E>>: |state, iter| {
|
||||
if let Some((Token { value: Value::Key(key), .. }, _)) = iter.next() {
|
||||
panic!("bsp:\n{iter:#?}\n{:#?}", iter.peek());
|
||||
if let Some(Token { value: Value::Key(key), .. }) = iter.peek() {
|
||||
let iter = iter.clone().next().unwrap().1;
|
||||
match key {
|
||||
"bsp/n" => return Some(Self::n(
|
||||
state.get_content(&iter.next()?.0.value).expect("no south"),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ impl<A> When<A> { pub fn new (c: bool, a: A) -> Self { Self(c, a) } }
|
|||
pub struct Either<A, B>(pub bool, pub A, pub B);
|
||||
impl<A, B> Either<A, B> { pub fn new (c: bool, a: A, b: B) -> Self { Self(c, a, b) } }
|
||||
try_from_expr!(<'a, E>: When<RenderBox<'a, E>>: |state, iter| {
|
||||
if let Some((Token { value: Value::Key("when"), .. }, _)) = iter.next() {
|
||||
if let Some(Token { value: Value::Key("when"), .. }) = iter.peek() {
|
||||
let iter = iter.clone();
|
||||
let condition = iter.next();
|
||||
if let Some((ref condition, _)) = condition {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@ use crate::*;
|
|||
impl<'a> ViewContext<'a, $Output> for $State {
|
||||
fn get_content_custom (&'a $self, value: &Value<'a>) -> Option<RenderBox<'a, $Output>> {
|
||||
if let Value::Sym(s) = value {
|
||||
match *s { $($sym => Some($body),)* _ => None }
|
||||
match *s {
|
||||
$($sym => Some($body),)*
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
panic!("expected symbol")
|
||||
panic!("expected content, got: {value:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,12 +75,10 @@ pub trait ViewContext<'a, E: Output + 'a>: Send + Sync
|
|||
}
|
||||
}
|
||||
#[macro_export] macro_rules! try_from_expr {
|
||||
(<$l:lifetime, $E:ident>: $Struct:ty: |$state:ident, $atoms:ident|$body:expr) => {
|
||||
(<$l:lifetime, $E:ident>: $Struct:ty: |$state:ident, $iter:ident|$body:expr) => {
|
||||
impl<$l, $E: Output + $l, T: ViewContext<$l, $E>> TryFromAtom<$l, T> for $Struct {
|
||||
fn try_from_atom ($state: &$l T, atom: Value<$l>) -> Option<Self> {
|
||||
if let Value::Exp(0, $atoms) = atom {
|
||||
$body;
|
||||
}
|
||||
fn try_from_expr ($state: &$l T, $iter: TokenIter<'a>) -> Option<Self> {
|
||||
$body;
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,7 +203,8 @@ provide_num!(u16: |self: Tek| {
|
|||
":samples-y" => if self.is_editing() { 1 } else { 0 },
|
||||
":pool-w" => if self.is_editing() { 5 } else {
|
||||
let w = self.size.w();
|
||||
if w > 60 { 20 } else if w > 40 { 15 } else { 10 } }
|
||||
if w > 60 { 20 } else if w > 40 { 15 } else { 10 }
|
||||
}
|
||||
});
|
||||
impl Tek {
|
||||
fn new_clock (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue