use crate::ast::Span;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Token {
pub kind: TokenKind,
pub span: Span,
pub lexeme: String,
}
impl Token {
pub fn is(&self, kind: &TokenKind) -> bool {
std::mem::discriminant(&self.kind) == std::mem::discriminant(kind)
}
pub fn is_ident(&self) -> bool {
matches!(self.kind, TokenKind::Ident(_))
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TokenKind {
Ident(String),
String(String),
Number(f64),
Val,
Import,
As,
Unsafe,
Module,
True,
False,
If,
Then,
Else,
Assert,
Hcl,
LParen, RParen, LBrace, RBrace, LBracket, RBracket, Comma, Colon, Dot,
Eq, Arrow, EqEq, BangEq, Lt, LtEq, Gt, GtEq, Bang, And, Or, Plus, Minus, Star, Slash,
Eof,
}
impl TokenKind {
pub fn name(&self) -> &'static str {
match self {
TokenKind::Ident(_) => "identifier",
TokenKind::String(_) => "string",
TokenKind::Number(_) => "number",
TokenKind::Val => "'val'",
TokenKind::Import => "'import'",
TokenKind::As => "'as'",
TokenKind::Unsafe => "'unsafe'",
TokenKind::Module => "'module'",
TokenKind::True => "'true'",
TokenKind::False => "'false'",
TokenKind::If => "'if'",
TokenKind::Then => "'then'",
TokenKind::Else => "'else'",
TokenKind::Assert => "'assert'",
TokenKind::Hcl => "'hcl'",
TokenKind::LParen => "'('",
TokenKind::RParen => "')'",
TokenKind::LBrace => "'{'",
TokenKind::RBrace => "'}'",
TokenKind::LBracket => "'['",
TokenKind::RBracket => "']'",
TokenKind::Comma => "','",
TokenKind::Colon => "':'",
TokenKind::Dot => "'.'",
TokenKind::Eq => "'='",
TokenKind::Arrow => "'=>'",
TokenKind::EqEq => "'=='",
TokenKind::BangEq => "'!='",
TokenKind::Lt => "'<'",
TokenKind::LtEq => "'<='",
TokenKind::Gt => "'>'",
TokenKind::GtEq => "'>='",
TokenKind::Bang => "'!'",
TokenKind::And => "'&&'",
TokenKind::Or => "'||'",
TokenKind::Plus => "'+'",
TokenKind::Minus => "'-'",
TokenKind::Star => "'*'",
TokenKind::Slash => "'/'",
TokenKind::Eof => "end of file",
}
}
}
impl std::fmt::Display for TokenKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TokenKind::Ident(s) => write!(f, "{}", s),
TokenKind::String(s) => write!(f, "\"{}\"", s),
TokenKind::Number(n) => write!(f, "{}", n),
_ => write!(f, "{}", self.name()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_token_kind_name() {
assert_eq!(TokenKind::Val.name(), "'val'");
assert_eq!(TokenKind::Ident("foo".to_string()).name(), "identifier");
}
#[test]
fn test_token_is() {
let token = Token {
kind: TokenKind::Val,
span: Span::dummy(),
lexeme: "val".to_string(),
};
assert!(token.is(&TokenKind::Val));
assert!(!token.is(&TokenKind::Import));
}
}