use crate::*; #[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Token<'a> { #[default] Nil, Num(&'a str, usize, usize), Sym(&'a str, usize, usize), Key(&'a str, usize, usize), Exp(&'a str, usize, usize, usize), } pub type ChompResult<'a> = Result<(&'a str, Token<'a>), ParseError>; impl<'a> Token<'a> { pub const fn chomp (source: &'a str) -> ChompResult<'a> { use Token::*; use konst::string::{split_at, char_indices}; let mut state = Self::Nil; let mut chars = char_indices(source); while let Some(((index, c), next)) = chars.next() { state = match state { // must begin expression Nil => match c { ' '|'\n'|'\r'|'\t' => Nil, '(' => Exp(source, index, 1, 1), ':'|'@' => Sym(source, index, 1), '0'..='9' => Num(source, index, 1), 'a'..='z' => Key(source, index, 1), //'\'' => Chr(source, index, 1), _ => return Err(ParseError::Unexpected(c)) }, Num(_, _, 0) => unreachable!(), Sym(_, _, 0) => unreachable!(), Key(_, _, 0) => unreachable!(), //Chr(_, _, 0) => unreachable!(), Num(source, index, length) => match c { '0'..='9' => Num(source, index, length + 1), ' '|'\n'|'\r'|'\t' => return Ok(( split_at(source, index+length).1, Num(source, index, length) )), _ => return Err(ParseError::Unexpected(c)) }, Sym(source, index, length) => match c { 'a'..='z'|'0'..='9'|'-' => Sym(source, index, length + 1), ' '|'\n'|'\r'|'\t' => return Ok(( split_at(source, index+length).1, Sym(source, index, length) )), _ => return Err(ParseError::Unexpected(c)) }, Key(source, index, length) => match c { 'a'..='z'|'0'..='9'|'-'|'/' => Key(source, index, length + 1), ' '|'\n'|'\r'|'\t' => return Ok(( split_at(source, index+length).1, Key(source, index, length) )), _ => return Err(ParseError::Unexpected(c)) }, Exp(source, index, length, 0) => match c { ' '|'\n'|'\r'|'\t' => return Ok(( split_at(source, index+length).1, Exp(source, index, length, 0) )), _ => return Err(ParseError::Unexpected(c)) }, Exp(source, index, length, depth) => match c { ')' => Exp(source, index, length + 1, depth - 1), '(' => Exp(source, index, length + 1, depth + 1), _ => Exp(source, index, length + 1, depth) }, }; chars = next } Ok(("", state)) } pub const fn number (digits: &str) -> usize { let mut value = 0; let mut chars = konst::string::char_indices(digits); while let Some(((_, c), next)) = chars.next() { value = 10 * value + Self::digit(c); chars = next } value } pub const fn digit (c: char) -> usize { match c { '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, _ => panic!("not a digit") } } }