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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
use crate::*;
#[derive(Clone)]
pub enum IntermediateToken {
Word(Word),
PinnedAddress(usize),
}
#[derive(Clone)]
pub struct Word {
pub value: usize,
/// Width of the word in bits.
pub width: u32,
}
impl std::fmt::Display for Word {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
if self.width == 0 {
write!(f, "0")
} else {
for i in (0..self.width).rev() {
let is_first_bit = i+1 == self.width;
if !is_first_bit && (i+1) % 4 == 0 {
write!(f, "_")?;
}
match (self.value >> i) & 1 {
0 => write!(f, "0")?,
_ => write!(f, "1")?,
}
}
Ok(())
}
}
}
#[derive(Clone)]
pub enum IntermediateValue {
Integer(IntermediateInteger),
List(IntermediateList),
Block(IntermediateBlock),
}
pub type IntermediateInteger = Tracked<isize>;
pub type IntermediateList = Vec<Tracked<isize>>;
pub type IntermediateBlock = Vec<Tracked<IntermediateToken>>;
pub enum RepeatedArgument {
Loop(IntermediateValue),
List(Vec<IntermediateValue>),
}
impl RepeatedArgument {
pub fn len(&self) -> usize {
match self {
Self::Loop(_) => 1,
Self::List(list) => list.len(),
}
}
}
pub enum IntermediateError {
ExpectedInteger,
ExpectedBlock,
ExpectedList,
ListExhausted,
LabelDefinitionInConditionBody,
LabelReferenceInPinnedAddress,
InvalidBlockInExpression,
ExpressionError(Tracked<ExpressionError>),
/// expected, received
IncorrectArgumentCount(usize, usize),
/// expected, received
IncorrectArgumentType(ArgumentType, ArgumentType),
/// pinned, real
PinnedAddressBacktrack(usize, usize),
/// expected, received
ValueTooWide(u32, u32),
LabelNeverStabilised(String),
MaxRecursionDepthExceeded,
}
pub fn report_intermediate_errors(errors: &[Tracked<IntermediateError>], source_code: &str) {
for error in errors {
report_intermediate_error(error, source_code);
}
}
fn report_intermediate_error(error: &Tracked<IntermediateError>, source_code: &str) {
let context = Context { source_code: &source_code, source: &error.source };
let message = match &error.value {
IntermediateError::ExpectedInteger =>
"An integer value was expected here",
IntermediateError::ExpectedBlock =>
"A block value was expected here",
IntermediateError::ExpectedList =>
"A string value was expected here",
IntermediateError::ListExhausted =>
"This list is shorter than another list passed to the same invocation",
IntermediateError::LabelDefinitionInConditionBody =>
"The body of a conditional block cannot contain a label definition",
IntermediateError::LabelReferenceInPinnedAddress =>
"The value of a pinned address cannot contain a label reference",
IntermediateError::InvalidBlockInExpression =>
"Expression cannot contain an invocation that expands to a block value",
IntermediateError::ExpressionError(expression_error) => {
report_expression_error(expression_error, source_code); return; },
IntermediateError::IncorrectArgumentCount(expected, received) =>
&format!("Expected {expected} arguments, but received {received} instead"),
IntermediateError::IncorrectArgumentType(expected, received) =>
&format!("Expected {expected} value but received {received} value instead"),
IntermediateError::PinnedAddressBacktrack(pinned, real) =>
&format!("Cannot pin to address {pinned} when address is already {real}"),
IntermediateError::ValueTooWide(expected, received) =>
&format!("Field is {expected} bits wide, but received a value that is {received} bits wide"),
IntermediateError::LabelNeverStabilised(name) =>
&format!("Label '{name}' never stabilised"),
IntermediateError::MaxRecursionDepthExceeded =>
&format!("Macro invocation exceededs the maximum recursion depth of {MAX_RECURSION_DEPTH}"),
};
report_source_issue(LogLevel::Error, &context, message);
}
pub fn print_intermediate_token(i: usize, token: &IntermediateToken) {
match token {
IntermediateToken::Word(word) => {
indent!(i, "Word({:>0w$b})", word.value, w = word.width as usize);
}
IntermediateToken::PinnedAddress(address) => {
indent!(i, "PinnedAddress({address})");
}
}
}
|