From 9756862091abbff0ea59406da7b99f4a37f6d37c Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 18 Jan 2025 22:17:10 +0100 Subject: [PATCH] test top level expr parsing --- edn/src/iter.rs | 32 +++++++-------- edn/src/lib.rs | 95 ++++++++++++++++++++++++++----------------- edn/src/token.rs | 60 +++++++++++++++++++-------- output/src/op_bsp.rs | 4 +- output/src/op_cond.rs | 2 +- output/src/view.rs | 15 +++---- tek/src/lib.rs | 3 +- 7 files changed, 129 insertions(+), 82 deletions(-) diff --git a/edn/src/iter.rs b/edn/src/iter.rs index e87bc21c..7679f0e2 100644 --- a/edn/src/iter.rs +++ b/edn/src/iter.rs @@ -20,48 +20,44 @@ pub const fn peek_src <'a> (source: &'a str) -> Option> { 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(), } }, }); diff --git a/edn/src/lib.rs b/edn/src/lib.rs index 90fab9fe..67ce1041 100644 --- a/edn/src/lib.rs +++ b/edn/src/lib.rs @@ -43,44 +43,65 @@ pub(crate) use std::fmt::{Debug, Display, Formatter, Result as FormatResult, Err } } #[cfg(test)] #[test] fn test_token () -> Result<(), Box> { - 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 = >::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 = >::from(&layout); + //} Ok(()) } diff --git a/edn/src/token.rs b/edn/src/token.rs index 25c1750d..44f14f62 100644 --- a/edn/src/token.rs +++ b/edn/src/token.rs @@ -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 } } diff --git a/output/src/op_bsp.rs b/output/src/op_bsp.rs index a0925ef7..f1a82cf1 100644 --- a/output/src/op_bsp.rs +++ b/output/src/op_bsp.rs @@ -32,7 +32,9 @@ impl, B: Content> Content for Bsp { } } try_from_expr!(<'a, E>: Bsp, 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"), diff --git a/output/src/op_cond.rs b/output/src/op_cond.rs index bbec8dad..8241d55e 100644 --- a/output/src/op_cond.rs +++ b/output/src/op_cond.rs @@ -6,7 +6,7 @@ impl When { pub fn new (c: bool, a: A) -> Self { Self(c, a) } } pub struct Either(pub bool, pub A, pub B); impl Either { pub fn new (c: bool, a: A, b: B) -> Self { Self(c, a, b) } } try_from_expr!(<'a, E>: When>: |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 { diff --git a/output/src/view.rs b/output/src/view.rs index 04e3629a..90041e5b 100644 --- a/output/src/view.rs +++ b/output/src/view.rs @@ -9,9 +9,12 @@ use crate::*; impl<'a> ViewContext<'a, $Output> for $State { fn get_content_custom (&'a $self, value: &Value<'a>) -> Option> { 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 { - if let Value::Exp(0, $atoms) = atom { - $body; - } + fn try_from_expr ($state: &$l T, $iter: TokenIter<'a>) -> Option { + $body; None } } diff --git a/tek/src/lib.rs b/tek/src/lib.rs index e320c922..b2fd35e4 100644 --- a/tek/src/lib.rs +++ b/tek/src/lib.rs @@ -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 (