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
use crate::semantic::types::SemanticError;
use crate::syntax::sysml::ast::{Element, SysMLFile};
use crate::syntax::sysml::visitor::AstVisitor;
use crate::semantic::adapters::SysmlAdapter;
impl<'a> SysmlAdapter<'a> {
/// Populates the symbol table by visiting all elements in the SysML file.
///
/// # Errors
///
/// Returns a vector of `SemanticError` if any semantic errors are encountered
/// during population, such as duplicate symbol definitions.
pub fn populate(&mut self, file: &SysMLFile) -> Result<(), Vec<SemanticError>> {
// If there's a file-level namespace, enter it first
let namespace_name = if let Some(ref ns) = file.namespace {
self.visit_namespace(ns);
Some(ns.name.clone())
} else {
None
};
// Process all elements in the file
for element in file.elements.iter() {
// Skip Package element if it's the same as the file-level namespace
// (we've already processed it via visit_namespace above)
if let Element::Package(p) = element
&& let Some(ref ns_name) = namespace_name
&& p.name.as_ref() == Some(ns_name)
{
// This is the file-level package - skip it, we've already entered its namespace
// But still process its children
for child in &p.elements {
self.visit_element_with_lifecycle(child);
}
continue;
}
self.visit_element_with_lifecycle(element);
}
if self.errors.is_empty() {
Ok(())
} else {
Err(std::mem::take(&mut self.errors))
}
}
pub(super) fn visit_element_with_lifecycle(&mut self, element: &Element) {
match element {
Element::Package(p) => {
self.visit_package(p);
for child in &p.elements {
self.visit_element_with_lifecycle(child);
}
if p.name.is_some() {
self.exit_namespace();
}
}
Element::Definition(d) => self.visit_definition(d),
Element::Usage(u) => self.visit_usage(u),
Element::Comment(c) => self.visit_comment(c),
Element::Import(i) => self.visit_import(i),
Element::Alias(a) => self.visit_alias(a),
}
}
}