|
|
@ -23,8 +23,8 @@ macro_rules! fqsn {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mod source_map;
|
|
|
|
mod tables;
|
|
|
|
use source_map::SourceMap;
|
|
|
|
use tables::DeclLocations;
|
|
|
|
mod symbol_trie;
|
|
|
|
mod symbol_trie;
|
|
|
|
use symbol_trie::SymbolTrie;
|
|
|
|
use symbol_trie::SymbolTrie;
|
|
|
|
mod test;
|
|
|
|
mod test;
|
|
|
@ -40,14 +40,14 @@ impl DuplicateNameTrackTable {
|
|
|
|
DuplicateNameTrackTable { table: HashMap::new() }
|
|
|
|
DuplicateNameTrackTable { table: HashMap::new() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn try_register(&mut self, name: &Rc<String>, id: &ItemId, source_map: &SourceMap) -> Result<(), LineNumber> {
|
|
|
|
fn try_register(&mut self, name: &Rc<String>, id: &ItemId, decl_locations: &DeclLocations) -> Result<(), LineNumber> {
|
|
|
|
match self.table.entry(name.clone()) {
|
|
|
|
match self.table.entry(name.clone()) {
|
|
|
|
Entry::Occupied(o) => {
|
|
|
|
Entry::Occupied(o) => {
|
|
|
|
let line_number = o.get();
|
|
|
|
let line_number = o.get();
|
|
|
|
Err(*line_number)
|
|
|
|
Err(*line_number)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Entry::Vacant(v) => {
|
|
|
|
Entry::Vacant(v) => {
|
|
|
|
let line_number = if let Some(loc) = source_map.lookup(id) {
|
|
|
|
let line_number = if let Some(loc) = decl_locations.lookup(id) {
|
|
|
|
loc.line_num
|
|
|
|
loc.line_num
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
0
|
|
|
@ -94,7 +94,7 @@ impl ScopeSegment {
|
|
|
|
|
|
|
|
|
|
|
|
//cf. p. 150 or so of Language Implementation Patterns
|
|
|
|
//cf. p. 150 or so of Language Implementation Patterns
|
|
|
|
pub struct SymbolTable {
|
|
|
|
pub struct SymbolTable {
|
|
|
|
source_map: SourceMap,
|
|
|
|
decl_locations: DeclLocations,
|
|
|
|
symbol_path_to_symbol: HashMap<FullyQualifiedSymbolName, Symbol>,
|
|
|
|
symbol_path_to_symbol: HashMap<FullyQualifiedSymbolName, Symbol>,
|
|
|
|
id_to_fqsn: HashMap<ItemId, FullyQualifiedSymbolName>,
|
|
|
|
id_to_fqsn: HashMap<ItemId, FullyQualifiedSymbolName>,
|
|
|
|
symbol_trie: SymbolTrie,
|
|
|
|
symbol_trie: SymbolTrie,
|
|
|
@ -103,7 +103,7 @@ pub struct SymbolTable {
|
|
|
|
impl SymbolTable {
|
|
|
|
impl SymbolTable {
|
|
|
|
pub fn new() -> SymbolTable {
|
|
|
|
pub fn new() -> SymbolTable {
|
|
|
|
SymbolTable {
|
|
|
|
SymbolTable {
|
|
|
|
source_map: SourceMap::new(),
|
|
|
|
decl_locations: DeclLocations::new(),
|
|
|
|
symbol_path_to_symbol: HashMap::new(),
|
|
|
|
symbol_path_to_symbol: HashMap::new(),
|
|
|
|
id_to_fqsn: HashMap::new(),
|
|
|
|
id_to_fqsn: HashMap::new(),
|
|
|
|
symbol_trie: SymbolTrie::new()
|
|
|
|
symbol_trie: SymbolTrie::new()
|
|
|
@ -139,7 +139,7 @@ impl SymbolTable {
|
|
|
|
#[allow(dead_code)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Symbol {
|
|
|
|
pub struct Symbol {
|
|
|
|
pub local_name: Rc<String>, //TODO does this need to be pub?
|
|
|
|
pub local_name: Rc<String>,
|
|
|
|
fully_qualified_name: FullyQualifiedSymbolName,
|
|
|
|
fully_qualified_name: FullyQualifiedSymbolName,
|
|
|
|
pub spec: SymbolSpec,
|
|
|
|
pub spec: SymbolSpec,
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -200,16 +200,16 @@ impl SymbolTable {
|
|
|
|
for statement in statements.iter() {
|
|
|
|
for statement in statements.iter() {
|
|
|
|
match statement {
|
|
|
|
match statement {
|
|
|
|
Statement { kind: StatementKind::Declaration(decl), id, location, } => {
|
|
|
|
Statement { kind: StatementKind::Declaration(decl), id, location, } => {
|
|
|
|
self.source_map.add_location(id, *location);
|
|
|
|
self.decl_locations.add_location(id, *location);
|
|
|
|
|
|
|
|
|
|
|
|
match decl {
|
|
|
|
match decl {
|
|
|
|
FuncSig(ref signature) => {
|
|
|
|
FuncSig(ref signature) => {
|
|
|
|
seen_identifiers.try_register(&signature.name, &id, &self.source_map)
|
|
|
|
seen_identifiers.try_register(&signature.name, id, &self.decl_locations)
|
|
|
|
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
|
|
|
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
|
|
|
self.add_function_signature(signature, scope_name_stack)?
|
|
|
|
self.add_function_signature(signature, scope_name_stack)?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FuncDecl(ref signature, ref body) => {
|
|
|
|
FuncDecl(ref signature, ref body) => {
|
|
|
|
seen_identifiers.try_register(&signature.name, &id, &self.source_map)
|
|
|
|
seen_identifiers.try_register(&signature.name, id, &self.decl_locations)
|
|
|
|
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
|
|
|
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
|
|
|
self.add_function_signature(signature, scope_name_stack)?;
|
|
|
|
self.add_function_signature(signature, scope_name_stack)?;
|
|
|
|
scope_name_stack.push(ScopeSegment{
|
|
|
|
scope_name_stack.push(ScopeSegment{
|
|
|
@ -220,12 +220,12 @@ impl SymbolTable {
|
|
|
|
output?
|
|
|
|
output?
|
|
|
|
},
|
|
|
|
},
|
|
|
|
TypeDecl { name, body, mutable } => {
|
|
|
|
TypeDecl { name, body, mutable } => {
|
|
|
|
seen_identifiers.try_register(&name.name, &id, &self.source_map)
|
|
|
|
seen_identifiers.try_register(&name.name, &id, &self.decl_locations)
|
|
|
|
.map_err(|line| format!("Duplicate type definition: {}. It's already defined at {}", name.name, line))?;
|
|
|
|
.map_err(|line| format!("Duplicate type definition: {}. It's already defined at {}", name.name, line))?;
|
|
|
|
self.add_type_decl(name, body, mutable, scope_name_stack)?
|
|
|
|
self.add_type_decl(name, body, mutable, scope_name_stack)?
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Binding { name, .. } => {
|
|
|
|
Binding { name, .. } => {
|
|
|
|
seen_identifiers.try_register(&name, &id, &self.source_map)
|
|
|
|
seen_identifiers.try_register(&name, &id, &self.decl_locations)
|
|
|
|
.map_err(|line| format!("Duplicate variable definition: {}. It's already defined at {}", name, line))?;
|
|
|
|
.map_err(|line| format!("Duplicate variable definition: {}. It's already defined at {}", name, line))?;
|
|
|
|
self.add_new_symbol(name, scope_name_stack, SymbolSpec::Binding);
|
|
|
|
self.add_new_symbol(name, scope_name_stack, SymbolSpec::Binding);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -233,8 +233,8 @@ impl SymbolTable {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Statement { kind: StatementKind::Module(ModuleSpecifier { name, contents}), id, location } => {
|
|
|
|
Statement { kind: StatementKind::Module(ModuleSpecifier { name, contents}), id, location } => {
|
|
|
|
self.source_map.add_location(id, *location);
|
|
|
|
self.decl_locations.add_location(id, *location);
|
|
|
|
seen_modules.try_register(&name, &id, &self.source_map)
|
|
|
|
seen_modules.try_register(name, id, &self.decl_locations)
|
|
|
|
.map_err(|line| format!("Duplicate module definition: {}. It's already defined at {}", name, line))?;
|
|
|
|
.map_err(|line| format!("Duplicate module definition: {}. It's already defined at {}", name, line))?;
|
|
|
|
scope_name_stack.push(ScopeSegment { name: name.clone() });
|
|
|
|
scope_name_stack.push(ScopeSegment { name: name.clone() });
|
|
|
|
let output = self.add_symbols_from_scope(contents, scope_name_stack);
|
|
|
|
let output = self.add_symbols_from_scope(contents, scope_name_stack);
|
|
|
@ -248,7 +248,7 @@ impl SymbolTable {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn debug_symbol_table(&self) -> String {
|
|
|
|
pub fn debug_symbol_table(&self) -> String {
|
|
|
|
let mut output = format!("Symbol table\n");
|
|
|
|
let mut output = "Symbol table\n".to_string();
|
|
|
|
let mut sorted_symbols: Vec<(&FullyQualifiedSymbolName, &Symbol)> = self.symbol_path_to_symbol.iter().collect();
|
|
|
|
let mut sorted_symbols: Vec<(&FullyQualifiedSymbolName, &Symbol)> = self.symbol_path_to_symbol.iter().collect();
|
|
|
|
sorted_symbols.sort_by(|(fqsn, _), (other_fqsn, _)| fqsn.cmp(other_fqsn));
|
|
|
|
sorted_symbols.sort_by(|(fqsn, _), (other_fqsn, _)| fqsn.cmp(other_fqsn));
|
|
|
|
for (name, sym) in sorted_symbols.iter() {
|
|
|
|
for (name, sym) in sorted_symbols.iter() {
|
|
|
|