1use crate::*;
2
3
4#[derive(Debug)]
5pub struct SymbolManager<T>
6{
7 decls: Vec<SymbolDecl<T>>,
8 pub(super) globals: std::collections::HashMap<String, util::ItemRef<T>>,
9 span_refs: std::collections::HashMap<diagn::Span, util::ItemRef<T>>,
10 report_as: &'static str,
11}
12
13
14#[derive(Debug)]
15pub struct SymbolDecl<T>
16{
17 pub span: diagn::Span,
18 pub name: String,
19 pub kind: SymbolKind,
20 pub depth: usize,
21 pub ctx: SymbolContext,
22 pub bank_ref: Option<util::ItemRef<asm::Bankdef>>,
23 pub item_ref: util::ItemRef<T>,
24 pub(super) children: std::collections::HashMap<String, util::ItemRef<T>>,
25}
26
27
28#[derive(Copy, Clone, Debug)]
29pub enum SymbolKind
30{
31 Constant,
32 Label,
33 Function,
34 Other,
35}
36
37
38#[derive(Clone, Debug)]
39pub struct SymbolContext
40{
41 hierarchy: Vec<String>,
42}
43
44
45impl SymbolContext
46{
47 pub fn get_hierarchy(&self) -> &[String]
48 {
49 &self.hierarchy
50 }
51}
52
53
54impl<T> SymbolManager<T>
55{
56 pub fn new(report_as: &'static str) -> SymbolManager<T>
57 {
58 SymbolManager {
59 decls: Vec::new(),
60 globals: std::collections::HashMap::new(),
61 span_refs: std::collections::HashMap::new(),
62 report_as,
63 }
64 }
65
66
67 pub fn traverse<S>(
68 &self,
69 parent_ref: Option<util::ItemRef<T>>,
70 hierarchy: &[S])
71 -> Option<util::ItemRef<T>>
72 where S: std::borrow::Borrow<str>
73 {
74 if hierarchy.len() == 0
75 {
76 return None;
77 }
78
79 match self.get_children(parent_ref).get(hierarchy[0].borrow())
80 {
81 None => None,
82 Some(child_ref) =>
83 {
84 if hierarchy.len() == 1
85 {
86 Some(*child_ref)
87 }
88 else
89 {
90 self.traverse(
91 Some(*child_ref),
92 &hierarchy[1..])
93 }
94 }
95 }
96 }
97
98
99 fn get_parent<S>(
100 &self,
101 parent_ref: Option<util::ItemRef<T>>,
102 hierarchy: &[S])
103 -> Option<util::ItemRef<T>>
104 where S: std::borrow::Borrow<str>
105 {
106 if hierarchy.len() == 0
107 {
108 return parent_ref;
109 }
110
111 match self.get_children(parent_ref).get(hierarchy[0].borrow())
112 {
113 None => None,
114 Some(child_ref) =>
115 {
116 self.get_parent(
117 Some(*child_ref),
118 &hierarchy[1..])
119 }
120 }
121 }
122
123
124 fn get_children(
125 &self,
126 parent_ref: Option<util::ItemRef<T>>)
127 -> &std::collections::HashMap<String, util::ItemRef<T>>
128 {
129 match parent_ref
130 {
131 Some(parent_ref) => &self.get(parent_ref).children,
132 None => &self.globals,
133 }
134 }
135
136
137 fn get_children_mut(
138 &mut self,
139 parent_ref: Option<util::ItemRef<T>>)
140 -> &mut std::collections::HashMap<String, util::ItemRef<T>>
141 {
142 match parent_ref
143 {
144 Some(parent_ref) => &mut self.get_mut(parent_ref).children,
145 None => &mut self.globals,
146 }
147 }
148
149
150 pub fn get(
151 &self,
152 item_ref: util::ItemRef<T>)
153 -> &util::SymbolDecl<T>
154 {
155 &self.decls[item_ref.0]
156 }
157
158
159 pub fn get_mut(
160 &mut self,
161 item_ref: util::ItemRef<T>)
162 -> &mut util::SymbolDecl<T>
163 {
164 &mut self.decls[item_ref.0]
165 }
166
167
168 pub fn get_by_name_global(
169 &self,
170 report: &mut diagn::Report,
171 span: diagn::Span,
172 name: &str)
173 -> Result<util::ItemRef<T>, ()>
174 {
175 self.get_by_name(
176 report,
177 span,
178 &SymbolContext::new_global(),
179 0,
180 &[name])
181 }
182
183
184 pub fn try_get_by_name<S>(
185 &self,
186 ctx: &SymbolContext,
187 hierarchy_level: usize,
188 hierarchy: &[S])
189 -> Option<util::ItemRef<T>>
190 where S: std::borrow::Borrow<str> + std::fmt::Debug
191 {
192 if hierarchy_level > ctx.hierarchy.len()
193 {
194 None
195 }
196 else
197 {
198 let parent = self.get_parent(
199 None,
200 &ctx.hierarchy[0..hierarchy_level]);
201
202 self.traverse(
203 parent,
204 hierarchy)
205 }
206 }
207
208
209 pub fn get_by_name<S>(
210 &self,
211 report: &mut diagn::Report,
212 span: diagn::Span,
213 ctx: &SymbolContext,
214 hierarchy_level: usize,
215 hierarchy: &[S])
216 -> Result<util::ItemRef<T>, ()>
217 where S: std::borrow::Borrow<str> + std::fmt::Debug
218 {
219 match self.try_get_by_name(
220 ctx,
221 hierarchy_level,
222 hierarchy)
223 {
224 Some(symbol) => Ok(symbol),
225 None =>
226 {
227 let hierarchy_string = hierarchy
228 .iter()
229 .map(|s| s.borrow().to_string())
230 .collect::<Vec<String>>();
231
232 report.error_span(
233 format!("unknown {} `{}`",
234 self.report_as,
235 self.get_displayable_name(
236 hierarchy_level,
237 &hierarchy_string)),
238 span);
239
240 Err(())
241 }
242 }
243 }
244
245
246 pub fn get_current_label(
247 &self,
248 report: &mut diagn::Report,
249 span: diagn::Span,
250 ctx: &SymbolContext,
251 hierarchy_level: usize)
252 -> Result<util::ItemRef<T>, ()>
253 {
254 if hierarchy_level > ctx.hierarchy.len()
255 {
256 report.error_span(
257 "invalid label hierarchy",
258 span);
259
260 return Err(());
261 }
262
263 let maybe_label = self.get_parent(
264 None,
265 &ctx.hierarchy[0..hierarchy_level]);
266
267 match maybe_label
268 {
269 Some(label) => Ok(label),
270 None =>
271 {
272 report.error_span(
273 "invalid label hierarchy",
274 span);
275
276 return Err(());
277 }
278 }
279 }
280
281
282 pub fn get_displayable_name<S>(
283 &self,
284 hierarchy_level: usize,
285 hierarchy: &[S])
286 -> String
287 where S: std::borrow::Borrow<str>
288 {
289 format!("{}{}",
290 ".".repeat(hierarchy_level),
291 hierarchy.join("."))
292 }
293
294
295 pub fn generate_anonymous_name(&self) -> String
296 {
297 format!(
298 "#anonymous_{}_{}",
299 self.report_as,
300 self.decls.len())
301 }
302
303
304 pub fn declare(
305 &mut self,
306 report: &mut diagn::Report,
307 span: diagn::Span,
308 ctx: &SymbolContext,
309 bank_ref: Option<util::ItemRef<asm::Bankdef>>,
310 name: String,
311 hierarchy_level: usize,
312 kind: SymbolKind)
313 -> Result<util::ItemRef<T>, ()>
314 {
315 if hierarchy_level > ctx.hierarchy.len()
317 {
318 report.error_span(
319 "symbol declaration skips a nesting level",
320 span);
321
322 return Err(());
323 }
324
325
326 let parent_ref = self.get_parent(
328 None,
329 &ctx.hierarchy[0..hierarchy_level]);
330
331 let children = self.get_children(parent_ref);
332
333 if let Some(duplicate_ref) = children.get(&name)
334 {
335 report.push_parent(
336 format!("duplicate {} `{}`", self.report_as, name),
337 span);
338
339 report.note_span(
340 "first declared here",
341 self.get(*duplicate_ref).span);
342
343 report.pop_parent();
344
345 return Err(());
346 }
347
348
349 let index = self.decls.len();
351 let item_ref = util::ItemRef::<T>::new(index);
352
353
354 let parent_ref = self.get_parent(
356 None,
357 &ctx.hierarchy[0..hierarchy_level]);
358
359 let children = self.get_children_mut(parent_ref);
360
361 children.insert(
362 name.clone(),
363 item_ref);
364
365
366 let new_ctx = {
368 let mut new_hierarchy = ctx.hierarchy[0..hierarchy_level]
369 .iter()
370 .cloned()
371 .collect::<Vec<_>>();
372
373 new_hierarchy.push(name.clone());
374
375 SymbolContext {
376 hierarchy: new_hierarchy,
377 }
378 };
379
380
381 let full_name = {
383 let mut s = String::new();
384 if let Some(parent_ref) = parent_ref
385 {
386 s.push_str(&self.get(parent_ref).name);
387 s.push_str(".");
388 }
389
390 s.push_str(&name);
391 s
392 };
393
394 self.decls.push(SymbolDecl {
395 span: span,
396 name: full_name.clone(),
397 kind,
398 depth: hierarchy_level,
399 ctx: new_ctx.clone(),
400 bank_ref,
401 item_ref,
402 children: std::collections::HashMap::new(),
403 });
404
405 self.span_refs.insert(
406 span,
407 item_ref);
408
409
410 Ok(item_ref)
411 }
412
413
414 pub fn add_span_ref(
415 &mut self,
416 span: diagn::Span,
417 item_ref: util::ItemRef<T>)
418 {
419 self.span_refs.insert(span, item_ref);
420 }
421}
422
423
424impl SymbolContext
425{
426 pub const fn new_global() -> SymbolContext
427 {
428 SymbolContext {
429 hierarchy: Vec::new(),
430 }
431 }
432}