mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
92 lines
3.7 KiB
Rust
92 lines
3.7 KiB
Rust
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") }
|
|
}
|
|
}
|