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
139
140
141
142
143
144
145
146
147
148
149
|
use crate::*;
#[derive(Clone)]
pub enum IntermediateToken {
Word(IntermediateWord),
PinnedAddress(Tracked<usize>),
LabelDefinition(String),
}
#[derive(Clone)]
pub struct IntermediateWord {
pub value: usize,
/// Width of the word in bits.
pub width: u32,
pub fields: Vec<Tracked<IntermediateField>>,
}
#[derive(Clone)]
pub struct IntermediateField {
pub value: Tracked<IntermediateInteger>,
/// Width of the field in bits.
pub width: u32,
/// Number of bits to the right of the field in the word.
pub shift: u32,
}
#[derive(Clone)]
pub enum IntermediateInteger {
Integer(isize),
Expression(IntermediateExpression),
LabelReference(Tracked<String>),
}
#[derive(Clone)]
pub struct IntermediateExpression {
pub tokens: Vec<Tracked<IntermediateExpressionToken>>,
}
#[derive(Clone)]
pub enum IntermediateExpressionToken {
Integer(IntermediateInteger),
Operator(Operator),
}
#[derive(Clone)]
pub enum IntermediateValue {
Integer(Tracked<IntermediateInteger>),
Block(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,
ListExhausted,
LabelReferenceInConditionPredicate,
LabelDefinitionInConditionBody,
LabelReferenceInPinnedAddress,
StackError(Tracked<StackError>),
InvocationBeforeDefinition,
/// expected, received
IncorrectArgumentCount(usize, usize),
/// expected, received
IncorrectArgumentType(ArgumentType, ArgumentType),
}
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::ListExhausted =>
"This string is shorter than another string passed to the same invocation",
IntermediateError::LabelReferenceInConditionPredicate =>
"The predicate of a conditional block cannot contain a label reference",
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::StackError(stack_error) => {
report_stack_error(stack_error, source_code); return; },
IntermediateError::InvocationBeforeDefinition =>
&format!("Macro cannot be invoked before it has been defined"),
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"),
};
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);
for field in &word.fields {
print_intermediate_integer(i+1, &field.value.value);
}
}
IntermediateToken::PinnedAddress(address) =>
indent!(i, "PinnedAddress({address})"),
IntermediateToken::LabelDefinition(name) =>
indent!(i, "LabelDefinition({name})"),
}
}
fn print_intermediate_integer(i: usize, integer: &IntermediateInteger) {
match integer {
IntermediateInteger::Integer(value) =>
indent!(i, "Integer({value})"),
IntermediateInteger::LabelReference(name) =>
indent!(i, "LabelReference({name})"),
IntermediateInteger::Expression(expression) => {
indent!(i, "Expression");
for token in &expression.tokens {
match &token.value {
IntermediateExpressionToken::Integer(integer) =>
print_intermediate_integer(i+1, integer),
IntermediateExpressionToken::Operator(operator) =>
indent!(i+1, "Operator({operator})"),
}
}
}
}
}
|