customasm/util/
symbol_manager.rs

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        // Check skips in nesting level
316        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        // Check for duplicates at the same nesting level
327        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        // Generate the ItemRef
350        let index = self.decls.len();
351        let item_ref = util::ItemRef::<T>::new(index);
352
353
354        // Insert ItemRef into the parent's children-list
355        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        // Generate new SymbolContext
367        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        // Create a new declaration and add a Span reference
382        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}