1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
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,
}
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! 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}") }
}
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<usize>,
}
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<SemanticToken>,
/// A list of pointers to macro reference tokens
pub references: Vec<usize>,
}
impl MacroDefinition {
pub fn new(name: String) -> Self {
Self { name, body_tokens:Vec::new(), references:Vec::new() }
}
}
|