remove strum

This commit is contained in:
minish 2025-07-17 20:28:23 -04:00
parent 564d90d061
commit bbc6c276a8
6 changed files with 73 additions and 106 deletions

72
Cargo.lock generated
View File

@ -2,78 +2,6 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "leaf" name = "leaf"
version = "0.1.0" version = "0.1.0"
dependencies = [
"strum",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "strum"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"

View File

@ -4,4 +4,3 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
strum = { version = "0.27", features = ["derive"] }

36
src/kind.rs Normal file
View File

@ -0,0 +1,36 @@
pub trait Kind {
type Kinds;
fn kind(&self) -> Self::Kinds;
}
#[macro_export]
macro_rules! kinds {
($b:ident, $k:ident, $( $v:ident $( ( $($vty:ty = $vval:expr),* ) )?),* $(,)?) => {
#[derive(Debug)]
pub enum $b {
$( $v $( ( $($vty),* ) )?, )*
}
impl $crate::kind::Kind for $b {
type Kinds = $k;
fn kind(&self) -> $k {
$k (std::mem::discriminant(self))
}
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct $k(std::mem::Discriminant<$b>);
impl $k {
$(
#[allow(non_upper_case_globals, dead_code)]
pub const $v: Self = $k (
std::mem::discriminant(
&( $b::$v $( ( $($vval),* ) )? )
)
);
)*
}
};
}

View File

@ -1,6 +1,6 @@
use std::{fmt, iter::Peekable}; use std::{fmt, iter::Peekable, num::ParseIntError};
use strum::EnumDiscriminants; use crate::kinds;
#[derive(Debug)] #[derive(Debug)]
pub struct Ident(String); pub struct Ident(String);
@ -30,47 +30,38 @@ impl fmt::Display for Literal {
} }
} }
#[derive(Debug, EnumDiscriminants)] kinds!(
#[strum_discriminants(name(TokenKind))] Token,
pub enum Token { TokenKind,
Equals, Equals,
Plus, Plus,
Minus, Minus,
Star, Star,
Slash, Slash,
Percent, Percent,
Caret, Caret,
CurlyOpen, CurlyOpen,
CurlyClose, CurlyClose,
ParenOpen, ParenOpen,
ParenClose, ParenClose,
Comma, Comma,
Semicolon, Semicolon,
Eol,
Func, Func,
If, If,
Else, Else,
Return, Return,
Not, Not,
EqualTo, EqualTo,
NotEqualTo, NotEqualTo,
And, And,
Or, Or,
LessThan, LessThan,
LessThanOrEqualTo, LessThanOrEqualTo,
GreaterThan, GreaterThan,
GreaterThanOrEqualTo, GreaterThanOrEqualTo,
Literal(Literal = Literal::Nil),
Literal(Literal), );
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Precedence { pub enum Precedence {
Min, Min,
@ -116,6 +107,7 @@ impl Token {
#[derive(Debug)] #[derive(Debug)]
pub enum LexError { pub enum LexError {
InvalidInteger(ParseIntError),
InvalidEscape(char), InvalidEscape(char),
UnexpectedCharacter(char), UnexpectedCharacter(char),
UnexpectedEnd, UnexpectedEnd,
@ -123,12 +115,18 @@ pub enum LexError {
impl fmt::Display for LexError { impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::InvalidInteger(err) => write!(f, "invalid integer: {err}"),
Self::UnexpectedEnd => write!(f, "unexpected end of source"), Self::UnexpectedEnd => write!(f, "unexpected end of source"),
Self::UnexpectedCharacter(c) => write!(f, "unexpected char '{c}'"), Self::UnexpectedCharacter(c) => write!(f, "unexpected char '{c}'"),
Self::InvalidEscape(c) => write!(f, "\"\\{c}\" is not a valid string escape"), Self::InvalidEscape(c) => write!(f, "\"\\{c}\" is not a valid string escape"),
} }
} }
} }
impl From<ParseIntError> for LexError {
fn from(err: ParseIntError) -> Self {
Self::InvalidInteger(err)
}
}
pub type Result<T> = std::result::Result<T, LexError>; pub type Result<T> = std::result::Result<T, LexError>;
@ -139,6 +137,10 @@ where
chars: Peekable<I>, chars: Peekable<I>,
} }
fn t(tk: Token) -> Option<Result<Token>> {
Some(Ok(tk))
}
impl<I> Lexer<I> impl<I> Lexer<I>
where where
I: Iterator<Item = char>, I: Iterator<Item = char>,
@ -209,7 +211,7 @@ where
} }
} }
fn lex_integer(&mut self) -> Token { fn lex_integer(&mut self) -> Result<Token> {
let mut n_str = String::new(); let mut n_str = String::new();
// we don't lex negatives. the impl for that is // we don't lex negatives. the impl for that is
@ -221,9 +223,9 @@ where
// we can only read digits 0 to 9 so this should not fail // we can only read digits 0 to 9 so this should not fail
// .. unless we overflow // .. unless we overflow
let n = n_str.parse().unwrap(); let n = n_str.parse()?;
Token::Literal(Literal::Integer(n)) Ok(Token::Literal(Literal::Integer(n)))
} }
fn lex_string(&mut self) -> Result<Token> { fn lex_string(&mut self) -> Result<Token> {
@ -283,18 +285,21 @@ where
// , comma // , comma
',' => self.eat_to(Token::Comma), ',' => self.eat_to(Token::Comma),
// ; semicolon
';' => self.eat_to(Token::Semicolon),
// = equals // = equals
// or == equal to // or == equal to
'=' => match self.eat_peek() { '=' => match self.eat_peek() {
Some('=') => self.eat_to(Token::EqualTo), Some('=') => self.eat_to(Token::EqualTo),
_ => Some(Ok(Token::Equals)), _ => t(Token::Equals),
}, },
// ! not // ! not
// or != not equal to // or != not equal to
'!' => match self.eat_peek() { '!' => match self.eat_peek() {
Some('=') => self.eat_to(Token::NotEqualTo), Some('=') => self.eat_to(Token::NotEqualTo),
_ => Some(Ok(Token::Not)), _ => t(Token::Not),
}, },
// && and // && and
@ -307,21 +312,21 @@ where
// or >= greater than/equal to // or >= greater than/equal to
'>' => match self.eat_peek() { '>' => match self.eat_peek() {
Some('=') => self.eat_to(Token::GreaterThanOrEqualTo), Some('=') => self.eat_to(Token::GreaterThanOrEqualTo),
_ => Some(Ok(Token::GreaterThan)), _ => t(Token::GreaterThan),
}, },
// < less than // < less than
// or <= less than/equal to // or <= less than/equal to
'<' => match self.eat_peek() { '<' => match self.eat_peek() {
Some('=') => self.eat_to(Token::LessThanOrEqualTo), Some('=') => self.eat_to(Token::LessThanOrEqualTo),
_ => Some(Ok(Token::LessThan)), _ => t(Token::LessThan),
}, },
// a-zA-Z_ start of word // a-zA-Z_ start of word
'a'..='z' | 'A'..='Z' | '_' => Some(Ok(self.lex_word())), 'a'..='z' | 'A'..='Z' | '_' => Some(Ok(self.lex_word())),
// 0-9 integer // 0-9 integer
'0'..='9' => Some(Ok(self.lex_integer())), '0'..='9' => Some(self.lex_integer()),
// " strings // " strings
'"' => Some(self.lex_string()), '"' => Some(self.lex_string()),
@ -336,9 +341,6 @@ where
continue; continue;
} }
// ; semicolon
';' => self.eat_to(Token::Semicolon),
// unexpected character // unexpected character
c => Some(Err(LexError::UnexpectedCharacter(c))), c => Some(Err(LexError::UnexpectedCharacter(c))),
}; };

View File

@ -2,6 +2,7 @@ use std::time::Instant;
use crate::{lexer::Lexer, parser::Parser}; use crate::{lexer::Lexer, parser::Parser};
mod kind;
mod lexer; mod lexer;
mod parser; mod parser;

View File

@ -1,8 +1,9 @@
use std::{fmt, iter::Peekable}; use std::{fmt, iter::Peekable};
use strum::IntoDiscriminant; use crate::{
kind::Kind,
use crate::lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind}; lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind},
};
pub mod util; pub mod util;
@ -96,7 +97,7 @@ where
fn expect_next(&mut self, kind: TokenKind) -> Result<()> { fn expect_next(&mut self, kind: TokenKind) -> Result<()> {
let t = self.try_next()?; let t = self.try_next()?;
if t.discriminant() != kind { if t.kind() != kind {
return Err(ParseError::UnexpectedToken(t)); return Err(ParseError::UnexpectedToken(t));
} }
@ -104,7 +105,7 @@ where
} }
fn is_next(&mut self, kind: Option<TokenKind>) -> bool { fn is_next(&mut self, kind: Option<TokenKind>) -> bool {
match self.try_peek() { match self.try_peek() {
Ok(t) if Some(t.discriminant()) == kind => true, Ok(t) if Some(t.kind()) == kind => true,
Ok(_) => false, Ok(_) => false,
Err(ParseError::UnexpectedEnd) if kind.is_none() => true, Err(ParseError::UnexpectedEnd) if kind.is_none() => true,