remove strum
This commit is contained in:
parent
564d90d061
commit
bbc6c276a8
|
@ -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"
|
|
||||||
|
|
|
@ -4,4 +4,3 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
strum = { version = "0.27", features = ["derive"] }
|
|
||||||
|
|
|
@ -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),* ) )? )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
58
src/lexer.rs
58
src/lexer.rs
|
@ -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))),
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue