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
|
use crate::*;
use std::collections::{HashMap, HashSet};
pub fn parse_semantic(syntactic: Vec<Tracked<SyntacticToken>>) -> Result<Program, Vec<Tracked<SemanticError>>> {
// Record all label definitions and macro names up front.
let mut definitions = HashMap::new();
let mut macro_names = HashSet::new();
for token in &syntactic {
match &token.value {
SyntacticToken::LabelDefinition(name) => {
let name = name.clone();
let definition = Definition::new(0, DefinitionKind::LabelDefinition);
let tracked = Tracked::from(definition, token.source.clone());
if let Some(_) = definitions.insert(name.clone(), tracked) {
unreachable!("Uncaught duplicate label definition '{name}'");
}
}
SyntacticToken::MacroDefinition(definition) => {
let name = definition.name.clone();
if !macro_names.insert(name.clone()) {
unreachable!("Uncaught duplicate macro definition '{name}'")
}
}
_ => (),
}
}
// Convert syntactic tokens to semantic tokens.
let mut tokens: Vec<Tracked<SemanticToken>> = Vec::new();
let mut errors = Vec::new();
let mut stack = Vec::new();
for syn_token in syntactic {
let i = tokens.len();
let sem_token = match syn_token.value {
SyntacticToken::Comment(string) => SemanticToken::Comment(string),
SyntacticToken::LabelDefinition(name) => {
let definition = definitions.get_mut(&name).unwrap();
definition.value.definition = i;
SemanticToken::LabelDefinition(name)
}
SyntacticToken::MacroDefinition(definition) => {
let source = definition.name.source.clone();
let name = definition.name.clone();
let mut body: Vec<Tracked<SemanticToken>> = Vec::new();
let mut body_stack = Vec::new();
for syn_token in definition.body {
let j = body.len();
let sem_token = match syn_token.value {
SyntacticToken::Comment(string) =>
SemanticToken::Comment(string),
SyntacticToken::LabelDefinition(label) =>
unreachable!("Uncaught label definition '{label}' in macro '{name}'"),
SyntacticToken::MacroDefinition(definition) =>
unreachable!("Uncaught macro definition '{}' in macro '{name}'", definition.name),
SyntacticToken::RawValue(value) => SemanticToken::RawValue(value),
SyntacticToken::Instruction(instruction) => SemanticToken::Instruction(instruction),
SyntacticToken::Invocation(symbol) => {
if let Some(definition) = definitions.get_mut(&symbol) {
definition.value.deep_references.push((i, j));
} else if let Some(definition) = macro_names.get(&symbol) {
let error = SemanticError::InvocationBeforeDefinition;
let source = syn_token.source.wrap(definition.source.clone());
errors.push(Tracked::from(error, source));
} else {
unreachable!("Uncaught undefined symbol '{symbol}'");
};
SemanticToken::Invocation(symbol)
}
SyntacticToken::Padding(value) => SemanticToken::Padding(value),
SyntacticToken::String(bytes) => SemanticToken::String(bytes),
SyntacticToken::BlockOpen => {
body_stack.push(j);
SemanticToken::BlockOpen(0)
}
SyntacticToken::BlockClose => {
let Some(k) = body_stack.pop() else {
unreachable!("Uncaught unmatched block terminator in macro {name}");
};
body[k].value = SemanticToken::BlockOpen(j);
SemanticToken::BlockClose(k)
}
};
body.push(Tracked::from(sem_token, syn_token.source));
}
let kind = DefinitionKind::MacroDefinition(body);
let tracked = Tracked::from(Definition::new(i, kind), source);
if let Some(_) = definitions.insert(name.value.clone(), tracked) {
unreachable!("Uncaught duplicate definition '{name}'")
};
if !body_stack.is_empty() {
unreachable!("Uncaught unterminated block in macro {name}");
}
SemanticToken::MacroDefinition(name)
}
SyntacticToken::RawValue(value) => SemanticToken::RawValue(value),
SyntacticToken::Instruction(instruction) => SemanticToken::Instruction(instruction),
SyntacticToken::Invocation(symbol) => {
if let Some(definition) = definitions.get_mut(&symbol) {
definition.value.references.push(i);
} else if let Some(definition) = macro_names.get(&symbol) {
let error = SemanticError::InvocationBeforeDefinition;
let source = syn_token.source.wrap(definition.source.clone());
errors.push(Tracked::from(error, source));
} else {
unreachable!("Uncaught undefined symbol '{symbol}'");
};
SemanticToken::Invocation(symbol)
}
SyntacticToken::Padding(value) => SemanticToken::Padding(value),
SyntacticToken::String(bytes) => SemanticToken::String(bytes),
SyntacticToken::BlockOpen => {
stack.push(i);
SemanticToken::BlockOpen(0)
}
SyntacticToken::BlockClose => {
let Some(k) = stack.pop() else {
unreachable!("Uncaught unmatched block terminator");
};
tokens[k].value = SemanticToken::BlockOpen(i);
SemanticToken::BlockClose(k)
}
};
tokens.push(Tracked::from(sem_token, syn_token.source));
}
if !stack.is_empty() {
unreachable!("Uncaught unterminated block");
}
match errors.is_empty() {
true => Ok(Program { definitions, tokens }),
false => Err(errors),
}
}
|