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.
version = 4
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "leaf"
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"
[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)]
pub struct Ident(String);
@ -30,47 +30,38 @@ impl fmt::Display for Literal {
}
}
#[derive(Debug, EnumDiscriminants)]
#[strum_discriminants(name(TokenKind))]
pub enum Token {
kinds!(
Token,
TokenKind,
Equals,
Plus,
Minus,
Star,
Slash,
Percent,
Caret,
CurlyOpen,
CurlyClose,
ParenOpen,
ParenClose,
Comma,
Semicolon,
Eol,
Func,
If,
Else,
Return,
Not,
EqualTo,
NotEqualTo,
And,
Or,
LessThan,
LessThanOrEqualTo,
GreaterThan,
GreaterThanOrEqualTo,
Literal(Literal),
}
Literal(Literal = Literal::Nil),
);
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Precedence {
Min,
@ -116,6 +107,7 @@ impl Token {
#[derive(Debug)]
pub enum LexError {
InvalidInteger(ParseIntError),
InvalidEscape(char),
UnexpectedCharacter(char),
UnexpectedEnd,
@ -123,12 +115,18 @@ pub enum LexError {
impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidInteger(err) => write!(f, "invalid integer: {err}"),
Self::UnexpectedEnd => write!(f, "unexpected end of source"),
Self::UnexpectedCharacter(c) => write!(f, "unexpected char '{c}'"),
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>;
@ -139,6 +137,10 @@ where
chars: Peekable<I>,
}
fn t(tk: Token) -> Option<Result<Token>> {
Some(Ok(tk))
}
impl<I> Lexer<I>
where
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();
// 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
// .. 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> {
@ -283,18 +285,21 @@ where
// , comma
',' => self.eat_to(Token::Comma),
// ; semicolon
';' => self.eat_to(Token::Semicolon),
// = equals
// or == equal to
'=' => match self.eat_peek() {
Some('=') => self.eat_to(Token::EqualTo),
_ => Some(Ok(Token::Equals)),
_ => t(Token::Equals),
},
// ! not
// or != not equal to
'!' => match self.eat_peek() {
Some('=') => self.eat_to(Token::NotEqualTo),
_ => Some(Ok(Token::Not)),
_ => t(Token::Not),
},
// && and
@ -307,21 +312,21 @@ where
// or >= greater than/equal to
'>' => match self.eat_peek() {
Some('=') => self.eat_to(Token::GreaterThanOrEqualTo),
_ => Some(Ok(Token::GreaterThan)),
_ => t(Token::GreaterThan),
},
// < less than
// or <= less than/equal to
'<' => match self.eat_peek() {
Some('=') => self.eat_to(Token::LessThanOrEqualTo),
_ => Some(Ok(Token::LessThan)),
_ => t(Token::LessThan),
},
// a-zA-Z_ start of word
'a'..='z' | 'A'..='Z' | '_' => Some(Ok(self.lex_word())),
// 0-9 integer
'0'..='9' => Some(Ok(self.lex_integer())),
'0'..='9' => Some(self.lex_integer()),
// " strings
'"' => Some(self.lex_string()),
@ -336,9 +341,6 @@ where
continue;
}
// ; semicolon
';' => self.eat_to(Token::Semicolon),
// unexpected character
c => Some(Err(LexError::UnexpectedCharacter(c))),
};

View File

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

View File

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