mclangc/src/tokeniser/tokentype.rs
2026-01-17 16:31:40 +02:00

243 lines
6.5 KiB
Rust

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<char> for Char {
fn into(self) -> char {
self.0
}
}
impl From<char> 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<Self> {
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())
}
}