243 lines
6.5 KiB
Rust
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())
|
|
}
|
|
}
|