use core::panic; use std::fmt::Display; use crate::parser::ast::expr::Path; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Ident(pub String); impl Display for Ident { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl Ident { pub fn as_path(self) -> Path { Path(vec![self]) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Number { pub val: usize, pub base: u8, pub signed: bool, } impl Display for Number { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.base { 2 => write!(f, "{:#b}", self.val), 8 => write!(f, "{:#o}", self.val), 10 => { if self.signed { write!(f, "{}", self.val as isize) } else { write!(f, "{}", self.val as usize) } } 16 => write!(f, "{:#x}", self.val), _ => unreachable!() } } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct TString { pub val: String, pub cstr: bool, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Char(pub char); impl Into for Char { fn into(self) -> char { self.0 } } impl From for Char { fn from(value: char) -> Self { Char(value) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Keyword { Fn, If, Else, Struct, Enum, Type, While, For, Break, Continue, Let, Const, Mut, Static, True, False, Include, Extern, Return, As, Loop } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Delimiter { CurlyL, CurlyR, SquareL, SquareR, ParenL, ParenR, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Punctuation { Semi, Colon, Pathsep, Comma, Arrow, FatArrow, Plus, Minus, Ampersand, Star, Div, Mod, Shl, Shr, AndAnd, OrOr, Or, Xor, Not, AddEq, SubEq, DivEq, MulEq, ModEq, ShlEq, ShrEq, AndEq, OrEq, XorEq, Eq, EqEq, Fieldaccess, Pathaccess, Lt, Gt, Le, Ge, Neq } impl Punctuation { // pls help pub fn precedence(&self) -> Option<(usize, usize)> { match self { Punctuation::AddEq | Punctuation::SubEq | Punctuation::DivEq | Punctuation::MulEq | Punctuation::ModEq | Punctuation::ShlEq | Punctuation::ShrEq | Punctuation::AndEq | Punctuation::OrEq | Punctuation::XorEq | Punctuation::Eq => Some((1, 2)), Punctuation::EqEq | Punctuation::Neq => Some((3, 4)), Punctuation::Div | Punctuation::Star | Punctuation::Mod => Some((5,6)), Punctuation::Plus | Punctuation::Minus => Some((7,8)), Punctuation::Shl | Punctuation::Shr => Some((9,10)), Punctuation::Lt | Punctuation::Gt | Punctuation::Le | Punctuation::Ge => Some((11, 12)), Punctuation::Ampersand => Some((13, 14)), Punctuation::Xor => Some((15, 16)), Punctuation::Or => Some((17, 18)), Punctuation::AndAnd => Some((19, 20)), Punctuation::OrOr => Some((21, 22)), _ => None } } } #[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)] pub enum TokenType { Ident(Ident), Number(Number), String(TString), Char(Char), Keyword(Keyword), Delim(Delimiter), Punct(Punctuation), Comment(Comment), } #[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)] pub enum Comment { Line(String), Block(String) } impl TokenType { pub fn unwrap_ident(&self) -> Ident { match self { Self::Ident(i) => i.clone(), _ => panic!("Expected {}, got {self}", Self::ident("")) } } pub fn ident(s: &str) -> Self { Self::Ident(Ident(s.to_string())) } pub fn number(val: usize, base: u8, signed: bool) -> Self { Self::Number(Number { val, base, signed }) } pub fn string(s: &str, cstr: bool) -> Self{ Self::String(TString { val: s.to_string(), cstr }) } pub fn char(v: char) -> Self { Self::Char(Char(v)) } pub fn from_str(s: &str) -> Option { super::TT.get(s).cloned() } pub fn to_str(&self) -> String { for (k, v) in super::TT.iter() { if v == self { return k.to_string(); } } match self { TokenType::Ident(s) => { return format!("Ident(\"{}\")", s.to_string()); }, TokenType::Number(num) => { match num.base { 2 => { assert!(!num.signed, "base 2 (binary) numbers physically cannot be signed"); format!("{:#b}", num.val) } 8 => { assert!(!num.signed, "base 8 (octal) numbers physically cannot be signed"); format!("{:#o}", num.val) } 10 => { if num.signed { format!("{}", num.val as isize) } else { format!("{}", num.val) } } 16 => { assert!(!num.signed, "base 16 (hex) numbers physically cannot be signed"); format!("{:#x}", num.val) } _ => panic!("Invalid base for number, {}", num.base), } }, TokenType::String(s) => { if s.cstr { format!("\"{}\\0\"", s.val) } else { format!("\"{}\"", s.val) } }, TokenType::Char(c) => { format!("'{}'", c.0) } _ => unreachable!("Unreachable, did you add a new token and forget to add reverse lookup?"), } } } impl Display for TokenType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.to_str()) } }