use std::{fmt, str::FromStr}; use common::prelude::Register; #[derive(Debug, Clone)] #[expect(dead_code)] pub struct Node(pub Option, pub Opcode, pub Vec); impl fmt::Display for Node { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let symbol = match &self.0 { Some(symbol) => format!("{}", symbol), None => "".to_string(), }; write!(f, "Node: {} {} {:?}", symbol, self.1, self.2) } } impl fmt::Display for Symbol { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}::{}", self.module, self.name) } } impl fmt::Display for Module { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Module::Unresolved(name) => write!(f, "{}", name), Module::Resolved(name) => write!(f, "{}", name), } } } impl fmt::Display for Opcode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self) } } #[derive(Debug, Clone)] pub struct Symbol { pub name: String, pub module: Module, } #[derive(Debug, Clone)] pub enum Module { Resolved(u64), Unresolved(String), } #[derive(Debug, Clone)] pub enum Token { Symbol(Symbol), Register(Register), Immediate(u32), StringLit(String), Opcode(Opcode), } #[derive(Debug, PartialEq, Copy, Clone)] pub enum TokenType { Symbol, Register, Immediate, StringLit, Opcode, } impl TokenType { pub fn from_token(token: &Token) -> TokenType { match token { Token::Symbol(_) => TokenType::Symbol, Token::Register(_) => TokenType::Register, Token::Immediate(_) => TokenType::Immediate, Token::StringLit(_) => TokenType::StringLit, Token::Opcode(_) => TokenType::Opcode, } } } #[derive(Debug, Clone, PartialEq)] pub enum Opcode { // Real instructions (0x00-0x26) Nop, Mov, Movs, Ldb, Ldbs, Ldh, Ldhs, Ldw, Stb, Sth, Stw, Lli, Lui, Jmp, Jeq, Jne, Jgt, Jge, Jlt, Jle, Cmp, Inc, Dec, Shl, Shr, Add, Sub, And, Or, Not, Xor, Nand, Nor, Xnor, Int, Irt, Hlt, Iadd, Isub, // Pseudo-instructions Db, Dh, Dw, Resb, Resh, Resw, Push, Pop, Lwi, Include, } #[derive(Debug)] pub enum OpcodeFromStrError { InvalidRegister(&'static str), } impl std::fmt::Display for OpcodeFromStrError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidRegister(reg) => write!(f, "register does not exist: {reg}"), } } } impl std::error::Error for OpcodeFromStrError {} impl FromStr for Opcode { type Err = OpcodeFromStrError; fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { "nop" => Ok(Self::Nop), "mov" => Ok(Self::Mov), "movs" => Ok(Self::Movs), "ldb" => Ok(Self::Ldb), "ldbs" => Ok(Self::Ldbs), "ldh" => Ok(Self::Ldh), "ldhs" => Ok(Self::Ldhs), "ldw" => Ok(Self::Ldw), "stb" => Ok(Self::Stb), "sth" => Ok(Self::Sth), "stw" => Ok(Self::Stw), "lli" => Ok(Self::Lli), "lui" => Ok(Self::Lui), "jmp" => Ok(Self::Jmp), "jeq" => Ok(Self::Jeq), "jne" => Ok(Self::Jne), "jgt" => Ok(Self::Jgt), "jge" => Ok(Self::Jge), "jlt" => Ok(Self::Jlt), "jle" => Ok(Self::Jle), "cmp" => Ok(Self::Cmp), "inc" => Ok(Self::Inc), "dec" => Ok(Self::Dec), "shl" => Ok(Self::Shl), "shr" => Ok(Self::Shr), "add" => Ok(Self::Add), "sub" => Ok(Self::Sub), "and" => Ok(Self::And), "or" => Ok(Self::Or), "not" => Ok(Self::Not), "xor" => Ok(Self::Xor), "nand" => Ok(Self::Nand), "nor" => Ok(Self::Nor), "xnor" => Ok(Self::Xnor), "int" => Ok(Self::Int), "irt" => Ok(Self::Irt), "hlt" => Ok(Self::Hlt), "iadd" => Ok(Self::Iadd), "isub" => Ok(Self::Isub), "db" => Ok(Self::Db), "dh" => Ok(Self::Dh), "dw" => Ok(Self::Dw), "resb" => Ok(Self::Resb), "resh" => Ok(Self::Resh), "resw" => Ok(Self::Resw), "push" => Ok(Self::Push), "pop" => Ok(Self::Pop), "lwi" => Ok(Self::Lwi), "include" => Ok(Self::Include), _ => Err(OpcodeFromStrError::InvalidRegister("unknown opcode")), } } } impl Opcode { pub const OPCODES: &[&str] = &[ // Real instructions (0x00-0x26) "nop", "mov", "movs", "ldb", "ldbs", "ldh", "ldhs", "ldw", "stb", "sth", "stw", "lli", "lui", "jmp", "jeq", "jne", "jgt", "jge", "jlt", "jle", "cmp", "inc", "dec", "shl", "shr", "add", "sub", "and", "or", "not", "xor", "nand", "nor", "xnor", "int", "irt", "hlt", "iadd", "isub", // Pseudo-instructions "db", "dh", "dw", "resb", "resh", "resw", "push", "pop", "lwi", "include", ]; pub fn to_opcode_value(&self) -> Option { match self { Self::Nop => Some(0x00), Self::Mov => Some(0x01), Self::Movs => Some(0x02), Self::Ldb => Some(0x03), Self::Ldbs => Some(0x04), Self::Ldh => Some(0x05), Self::Ldhs => Some(0x06), Self::Ldw => Some(0x07), Self::Stb => Some(0x08), Self::Sth => Some(0x09), Self::Stw => Some(0x0A), Self::Lli => Some(0x0B), Self::Lui => Some(0x0C), Self::Jmp => Some(0x0D), Self::Jeq => Some(0x0E), Self::Jne => Some(0x0F), Self::Jgt => Some(0x10), Self::Jge => Some(0x11), Self::Jlt => Some(0x12), Self::Jle => Some(0x13), Self::Cmp => Some(0x14), Self::Inc => Some(0x15), Self::Dec => Some(0x16), Self::Shl => Some(0x17), Self::Shr => Some(0x18), Self::Add => Some(0x19), Self::Sub => Some(0x1A), Self::And => Some(0x1B), Self::Or => Some(0x1C), Self::Not => Some(0x1D), Self::Xor => Some(0x1E), Self::Nand => Some(0x1F), Self::Nor => Some(0x20), Self::Xnor => Some(0x21), Self::Int => Some(0x22), Self::Irt => Some(0x23), Self::Hlt => Some(0x24), Self::Iadd => Some(0x25), Self::Isub => Some(0x26), // Pseudo-instructions don't have opcode values _ => None, } } pub fn is_pseudo_instruction(&self) -> bool { matches!( self, Self::Db | Self::Dh | Self::Dw | Self::Resb | Self::Resh | Self::Resw | Self::Push | Self::Pop | Self::Lwi ) } }