use logos::Logos;
use std::ops::Range;
#[derive(Logos, Clone, Copy, Debug, PartialEq, Eq)]
pub enum TokenKind {
#[regex(r"[\n\r]+")]
NewLine,
#[regex(r"[ \t]+")]
Whitespace,
#[regex(r"//.*")]
Comment,
#[token("==")]
Eq,
#[token("!=")]
NotEq,
#[token("~==")]
ApproxEq,
#[token("~!=")]
ApproxNotEq,
#[token("+")]
Add,
#[token("-")]
Sub,
#[token("*")]
Mul,
#[token("/")]
Div,
#[token("%")]
Mod,
#[token("^")]
Exp,
#[token(">")]
Greater,
#[token(">=")]
GreaterEq,
#[token("<")]
Less,
#[token("<=")]
LessEq,
#[token("not")]
Not,
#[token("!")]
Factorial,
#[token("&&")]
And,
#[token("||")]
Or,
#[token("&")]
BitAnd,
#[token("|")]
BitOr,
#[token("~")]
BitNot,
#[token(">>")]
BitRight,
#[token("<<")]
BitLeft,
#[token("=")]
Assign,
#[token("+=")]
AddAssign,
#[token("-=")]
SubAssign,
#[token("*=")]
MulAssign,
#[token("/=")]
DivAssign,
#[token("%=")]
ModAssign,
#[token("^=")]
ExpAssign,
#[token("&&=")]
AndAssign,
#[token("||=")]
OrAssign,
#[token("&=")]
BitAndAssign,
#[token("|=")]
BitOrAssign,
#[token(">>=")]
BitRightAssign,
#[token("<<=")]
BitLeftAssign,
#[token("0b")]
Bin,
#[token("0o")]
Oct,
#[token("0x")]
Hex,
#[regex(r"[a-zA-Z_]+|atan2")] Name,
#[regex(r"let|if|then|else|for|sum|product|in|of|loop|while|break|continue|return")]
Keyword,
#[token(",")]
Comma,
#[token("(")]
OpenParen,
#[token(")")]
CloseParen,
#[token("{")]
OpenCurly,
#[token("}")]
CloseCurly,
#[token("[")]
OpenSquare,
#[token("]")]
CloseSquare,
#[token("'")]
Quote,
#[token(";")]
Semicolon,
#[regex(r"\d+")]
Int,
#[regex(r"(true|false)")]
Boolean,
#[token(".")]
Dot,
#[token("..")]
RangeHalfOpen,
#[token("..=")]
RangeClosed,
#[regex(r".", priority = 0)]
Symbol,
}
impl TokenKind {
pub fn is_ignore(self) -> bool {
matches!(self, TokenKind::Whitespace | TokenKind::NewLine | TokenKind::Comment)
}
pub fn is_significant_whitespace(self) -> bool {
matches!(self, TokenKind::NewLine)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Token<'source> {
pub span: Range<usize>,
pub kind: TokenKind,
pub lexeme: &'source str,
}
impl Token<'_> {
pub fn is_ignore(&self) -> bool {
self.kind.is_ignore()
}
pub fn is_significant_whitespace(&self) -> bool {
self.kind.is_significant_whitespace()
}
}