Refactor a lot of symbol table in prep for modules
This commit is contained in:
parent
d6019e6f9a
commit
cc0ac83709
@ -28,7 +28,35 @@ mod symbol_trie;
|
|||||||
use symbol_trie::SymbolTrie;
|
use symbol_trie::SymbolTrie;
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
type SymbolTrackTable = HashMap<Rc<String>, LineNumber>;
|
/// Keeps track of what names were used in a given namespace. Call try_register to add a name to
|
||||||
|
/// the table, or report an error if a name already exists.
|
||||||
|
struct DuplicateNameTrackTable {
|
||||||
|
table: HashMap<Rc<String>, LineNumber>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DuplicateNameTrackTable {
|
||||||
|
fn new() -> DuplicateNameTrackTable {
|
||||||
|
DuplicateNameTrackTable { table: HashMap::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_register(&mut self, name: &Rc<String>, id: &ItemId, source_map: &SourceMap) -> Result<(), LineNumber> {
|
||||||
|
match self.table.entry(name.clone()) {
|
||||||
|
Entry::Occupied(o) => {
|
||||||
|
let line_number = o.get();
|
||||||
|
Err(*line_number)
|
||||||
|
},
|
||||||
|
Entry::Vacant(v) => {
|
||||||
|
let line_number = if let Some(loc) = source_map.lookup(id) {
|
||||||
|
loc.line_num
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
v.insert(line_number);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Debug, Clone, PartialOrd, Ord)]
|
#[derive(PartialEq, Eq, Hash, Debug, Clone, PartialOrd, Ord)]
|
||||||
pub struct FullyQualifiedSymbolName(pub Vec<ScopeSegment>);
|
pub struct FullyQualifiedSymbolName(pub Vec<ScopeSegment>);
|
||||||
@ -163,53 +191,48 @@ impl SymbolTable {
|
|||||||
fn add_symbols_from_scope<'a>(&'a mut self, statements: &Vec<Statement>, scope_name_stack: &mut Vec<ScopeSegment>) -> Result<(), String> {
|
fn add_symbols_from_scope<'a>(&'a mut self, statements: &Vec<Statement>, scope_name_stack: &mut Vec<ScopeSegment>) -> Result<(), String> {
|
||||||
use self::ast::Declaration::*;
|
use self::ast::Declaration::*;
|
||||||
|
|
||||||
fn insert_and_check_duplicate_symbol(table: &mut SymbolTrackTable, name: &Rc<String>, id: &ItemId, source_map: &SourceMap) -> Result<(), String> {
|
//Err(format!("Duplicate definition: {}. It's already defined at {}", name, line_number))
|
||||||
match table.entry(name.clone()) {
|
|
||||||
Entry::Occupied(o) => {
|
|
||||||
let line_number = o.get();
|
|
||||||
Err(format!("Duplicate definition: {}. It's already defined at {}", name, line_number))
|
|
||||||
},
|
|
||||||
Entry::Vacant(v) => {
|
|
||||||
let line_number = if let Some(loc) = source_map.lookup(id) {
|
|
||||||
loc.line_num
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
v.insert(line_number);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut seen_identifiers: SymbolTrackTable = HashMap::new();
|
let mut seen_identifiers = DuplicateNameTrackTable::new();
|
||||||
|
let mut seen_modules = DuplicateNameTrackTable::new();
|
||||||
|
|
||||||
for statement in statements.iter() {
|
for statement in statements.iter() {
|
||||||
if let Statement { kind: StatementKind::Declaration(decl), id } = statement {
|
match statement {
|
||||||
match decl {
|
Statement { kind: StatementKind::Declaration(decl), id } => {
|
||||||
FuncSig(ref signature) => {
|
match decl {
|
||||||
insert_and_check_duplicate_symbol(&mut seen_identifiers, &signature.name, &id, &self.source_map_handle.borrow())?;
|
FuncSig(ref signature) => {
|
||||||
self.add_function_signature(signature, scope_name_stack)?
|
seen_identifiers.try_register(&signature.name, &id, &self.source_map_handle.borrow())
|
||||||
|
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
||||||
|
self.add_function_signature(signature, scope_name_stack)?
|
||||||
|
}
|
||||||
|
FuncDecl(ref signature, ref body) => {
|
||||||
|
seen_identifiers.try_register(&signature.name, &id, &self.source_map_handle.borrow())
|
||||||
|
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
||||||
|
self.add_function_signature(signature, scope_name_stack)?;
|
||||||
|
scope_name_stack.push(ScopeSegment{
|
||||||
|
name: signature.name.clone(),
|
||||||
|
});
|
||||||
|
let output = self.add_symbols_from_scope(body, scope_name_stack);
|
||||||
|
let _ = scope_name_stack.pop();
|
||||||
|
output?
|
||||||
|
},
|
||||||
|
TypeDecl { name, body, mutable } => {
|
||||||
|
seen_identifiers.try_register(&name.name, &id, &self.source_map_handle.borrow())
|
||||||
|
.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)?
|
||||||
|
},
|
||||||
|
Binding { name, .. } => {
|
||||||
|
seen_identifiers.try_register(&name, &id, &self.source_map_handle.borrow())
|
||||||
|
.map_err(|line| format!("Duplicate variable definition: {}. It's already defined at {}", name, line))?;
|
||||||
|
self.add_new_symbol(name, scope_name_stack, SymbolSpec::Binding);
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
}
|
}
|
||||||
FuncDecl(ref signature, ref body) => {
|
},
|
||||||
insert_and_check_duplicate_symbol(&mut seen_identifiers, &signature.name, &id, &self.source_map_handle.borrow())?;
|
Statement { kind: StatementKind::Module(mod_spec), id } => {
|
||||||
self.add_function_signature(signature, scope_name_stack)?;
|
()
|
||||||
scope_name_stack.push(ScopeSegment{
|
},
|
||||||
name: signature.name.clone(),
|
_ => ()
|
||||||
});
|
|
||||||
let output = self.add_symbols_from_scope(body, scope_name_stack);
|
|
||||||
let _ = scope_name_stack.pop();
|
|
||||||
output?
|
|
||||||
},
|
|
||||||
TypeDecl { name, body, mutable } => {
|
|
||||||
insert_and_check_duplicate_symbol(&mut seen_identifiers, &name.name, &id, &self.source_map_handle.borrow())?;
|
|
||||||
self.add_type_decl(name, body, mutable, scope_name_stack)?
|
|
||||||
},
|
|
||||||
Binding { name, .. } => {
|
|
||||||
insert_and_check_duplicate_symbol(&mut seen_identifiers, name, &id, &self.source_map_handle.borrow())?;
|
|
||||||
self.add_new_symbol(name, scope_name_stack, SymbolSpec::Binding);
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -40,18 +40,18 @@ fn basic_symbol_table() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_duplicates() {
|
fn no_function_definition_duplicates() {
|
||||||
let source = r#"
|
let source = r#"
|
||||||
fn a() { 1 }
|
fn a() { 1 }
|
||||||
fn b() { 2 }
|
fn b() { 2 }
|
||||||
fn a() { 3 }
|
fn a() { 3 }
|
||||||
"#;
|
"#;
|
||||||
let (_, output) = add_symbols_from_source(source);
|
let (_, output) = add_symbols_from_source(source);
|
||||||
assert!(output.unwrap_err().contains("Duplicate"))
|
assert!(output.unwrap_err().contains("Duplicate function definition: a"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_duplicates_2() {
|
fn no_variable_definition_duplicates() {
|
||||||
let source = r#"
|
let source = r#"
|
||||||
let x = 9
|
let x = 9
|
||||||
let a = 20
|
let a = 20
|
||||||
@ -60,12 +60,12 @@ fn no_duplicates_2() {
|
|||||||
"#;
|
"#;
|
||||||
let (_, output) = add_symbols_from_source(source);
|
let (_, output) = add_symbols_from_source(source);
|
||||||
let output = output.unwrap_err();
|
let output = output.unwrap_err();
|
||||||
assert!(output.contains("Duplicate definition: a"));
|
assert!(output.contains("Duplicate variable definition: a"));
|
||||||
assert!(output.contains("already defined at 2"));
|
assert!(output.contains("already defined at 2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_duplicates_3() {
|
fn no_variable_definition_duplicates_in_function() {
|
||||||
let source = r#"
|
let source = r#"
|
||||||
fn a() {
|
fn a() {
|
||||||
let a = 20
|
let a = 20
|
||||||
@ -74,12 +74,13 @@ fn no_duplicates_3() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn q() {
|
fn q() {
|
||||||
|
let a = 29
|
||||||
let x = 30
|
let x = 30
|
||||||
let x = 33
|
let x = 33
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let (_, output) = add_symbols_from_source(source);
|
let (_, output) = add_symbols_from_source(source);
|
||||||
assert!(output.unwrap_err().contains("Duplicate"))
|
assert!(output.unwrap_err().contains("Duplicate variable definition: x"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -153,3 +154,18 @@ inner_func(x)
|
|||||||
let (_, output) = add_symbols_from_source(source);
|
let (_, output) = add_symbols_from_source(source);
|
||||||
assert!(output.unwrap_err().contains("Duplicate"))
|
assert!(output.unwrap_err().contains("Duplicate"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn modules() {
|
||||||
|
let source = r#"
|
||||||
|
|
||||||
|
module a {
|
||||||
|
}
|
||||||
|
|
||||||
|
module a {
|
||||||
|
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let (_, output) = add_symbols_from_source(source);
|
||||||
|
//assert!(output.unwrap_err().contains("Duplicate"))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user