use crate::*; pub enum SemanticTokenType { LabelReference(usize), MacroReference(usize), LabelDefinition(LabelDefinition), MacroDefinition(MacroDefinition), Padding(u16), ByteLiteral(u8), ShortLiteral(u16), Instruction(u8), MacroDefinitionTerminator, Comment, Error(SyntacticTokenType, Error), } pub struct SemanticToken { pub r#type: SemanticTokenType, pub source_location: SourceLocation, pub bytecode_location: BytecodeLocation, pub parent_label: Option, } impl SemanticToken { /// Returns true if an error was printed. pub fn print_error(&self, source_code: &str) -> bool { let mut is_error = false; macro_rules! red {()=>{eprint!("\x1b[31m")};} macro_rules! dim {()=>{eprint!("\x1b[0;2m")};} macro_rules! normal {()=>{eprint!("\x1b[0m")};} if let SemanticTokenType::Error(token, error) = &self.r#type { is_error = true; red!(); eprint!("[ERROR] "); normal!(); let source = &self.source_location.source; match error { Error::UnresolvedReference => { eprintln!("Unresolved reference, no label or macro has been defined with the name '{source}'") } Error::DuplicateDefinition => { eprintln!("Duplicate definition, a label or macro has already been defined with the name '{source}'") } Error::OrphanedMacroDefinitionTerminator => { eprintln!("Unmatched macro definition terminator, no macro definition is in progress") } Error::InvalidPaddingValue => { eprintln!("Invalid value for padding, the value must be at least one and at most four hexadecimal characters") } Error::CyclicMacroReference => { eprintln!("Cyclic macro reference, this macro reference contains a reference to the macro being defined") } Error::InvalidTypeInMacroDefinition => { let name = match token { SyntacticTokenType::Reference(_) => "references", SyntacticTokenType::LabelDefinition(_) => "label definitions", SyntacticTokenType::MacroDefinition(_) => "macro definitions", SyntacticTokenType::MacroDefinitionTerminator => "macro definition terminators", SyntacticTokenType::Padding(_) => "padding", SyntacticTokenType::ByteLiteral(_) => "byte literals", SyntacticTokenType::ShortLiteral(_) => "short literals", SyntacticTokenType::Instruction(_) => "instructions", SyntacticTokenType::Comment => "comments", }; eprintln!("Invalid token in macro definition, macro definitions are not allowed to contain {name}") } } if let Some(label) = &self.parent_label { eprint!(" ... "); red!(); eprint!("| "); dim!(); eprintln!("@{label} "); normal!(); } let line = source_code.split('\n').nth(self.source_location.start.line).unwrap(); eprint!("{:>5} ", self.source_location.start.line+1); red!(); eprint!("| "); normal!(); for (i, c) in line.chars().enumerate() { if i == self.source_location.start.column { red!() } eprint!("{c}"); if i == self.source_location.end.column { normal!() } } eprintln!(); red!(); eprint!(" | "); for i in 0..=self.source_location.end.column { if i < self.source_location.start.column { eprint!(" ") } else { eprint!("^") }; } normal!(); eprintln!(); } else if let SemanticTokenType::MacroDefinition(definition) = &self.r#type { for token in &definition.body_tokens { if token.print_error(source_code) { is_error = true } } } is_error } } pub struct LabelDefinition { pub name: String, pub address: u16, /// A list of pointers to label reference tokens pub references: Vec, } impl LabelDefinition { pub fn new(name: String) -> Self { Self { name, address:0, references:Vec::new() } } } pub struct MacroDefinition { pub name: String, pub body_tokens: Vec, /// A list of pointers to macro reference tokens pub references: Vec, } impl MacroDefinition { pub fn new(name: String) -> Self { Self { name, body_tokens:Vec::new(), references:Vec::new() } } }