diff --git a/schala-lang/language/src/symbol_table.rs b/schala-lang/language/src/symbol_table.rs index 58d9227..2ab5c69 100644 --- a/schala-lang/language/src/symbol_table.rs +++ b/schala-lang/language/src/symbol_table.rs @@ -28,7 +28,35 @@ mod symbol_trie; use symbol_trie::SymbolTrie; mod test; -type SymbolTrackTable = HashMap, 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, LineNumber>, +} + +impl DuplicateNameTrackTable { + fn new() -> DuplicateNameTrackTable { + DuplicateNameTrackTable { table: HashMap::new() } + } + + fn try_register(&mut self, name: &Rc, 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)] pub struct FullyQualifiedSymbolName(pub Vec); @@ -163,53 +191,48 @@ impl SymbolTable { fn add_symbols_from_scope<'a>(&'a mut self, statements: &Vec, scope_name_stack: &mut Vec) -> Result<(), String> { use self::ast::Declaration::*; - fn insert_and_check_duplicate_symbol(table: &mut SymbolTrackTable, name: &Rc, id: &ItemId, source_map: &SourceMap) -> Result<(), String> { - 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(()) - } - } - } + //Err(format!("Duplicate definition: {}. It's already defined at {}", name, line_number)) - let mut seen_identifiers: SymbolTrackTable = HashMap::new(); + let mut seen_identifiers = DuplicateNameTrackTable::new(); + let mut seen_modules = DuplicateNameTrackTable::new(); for statement in statements.iter() { - if let Statement { kind: StatementKind::Declaration(decl), id } = statement { - match decl { - FuncSig(ref signature) => { - insert_and_check_duplicate_symbol(&mut seen_identifiers, &signature.name, &id, &self.source_map_handle.borrow())?; - self.add_function_signature(signature, scope_name_stack)? + match statement { + Statement { kind: StatementKind::Declaration(decl), id } => { + match decl { + FuncSig(ref signature) => { + 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())?; - 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); - } - _ => () - } + }, + Statement { kind: StatementKind::Module(mod_spec), id } => { + () + }, + _ => () } } Ok(()) diff --git a/schala-lang/language/src/symbol_table/test.rs b/schala-lang/language/src/symbol_table/test.rs index 949d825..96c147a 100644 --- a/schala-lang/language/src/symbol_table/test.rs +++ b/schala-lang/language/src/symbol_table/test.rs @@ -40,18 +40,18 @@ fn basic_symbol_table() { } #[test] -fn no_duplicates() { +fn no_function_definition_duplicates() { let source = r#" fn a() { 1 } fn b() { 2 } fn a() { 3 } "#; let (_, output) = add_symbols_from_source(source); - assert!(output.unwrap_err().contains("Duplicate")) + assert!(output.unwrap_err().contains("Duplicate function definition: a")) } #[test] -fn no_duplicates_2() { +fn no_variable_definition_duplicates() { let source = r#" let x = 9 let a = 20 @@ -60,12 +60,12 @@ fn no_duplicates_2() { "#; let (_, output) = add_symbols_from_source(source); 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")); } #[test] -fn no_duplicates_3() { +fn no_variable_definition_duplicates_in_function() { let source = r#" fn a() { let a = 20 @@ -74,12 +74,13 @@ fn no_duplicates_3() { } fn q() { + let a = 29 let x = 30 let x = 33 } "#; let (_, output) = add_symbols_from_source(source); - assert!(output.unwrap_err().contains("Duplicate")) + assert!(output.unwrap_err().contains("Duplicate variable definition: x")) } #[test] @@ -153,3 +154,18 @@ inner_func(x) let (_, output) = add_symbols_from_source(source); 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")) +}