diff --git a/schala-lang/language/src/symbol_table.rs b/schala-lang/language/src/symbol_table.rs index 2485047..cae4c9b 100644 --- a/schala-lang/language/src/symbol_table.rs +++ b/schala-lang/language/src/symbol_table.rs @@ -8,6 +8,32 @@ use crate::ast; use crate::ast::{ItemId, TypeBody, TypeSingletonName, Signature, Statement, StatementKind}; use crate::typechecking::TypeName; +#[allow(unused_macros)] +macro_rules! sym_path_kind { + (fn) => { ScopeSegmentKind::Function }; + (ty) => { ScopeSegmentKind::Type }; + (tr) => { ScopeSegmentKind::Terminal }; +} + +#[allow(unused_macros)] +macro_rules! fqsn { + ( $( $name:expr ; $kind:tt),* ) => { + { + let mut vec = vec![]; + $( + vec.push(ScopeSegment::new( + Rc::new($name.to_string()), + sym_path_kind!($kind), + )); + )* + FullyQualifiedSymbolName(vec) + } + }; +} + + +mod test; + type LineNumber = u32; type SymbolTrackTable = HashMap, LineNumber>; @@ -57,29 +83,6 @@ pub enum ScopeSegmentKind { //Module } -#[allow(unused_macros)] -macro_rules! fqsn { - ( $( $name:expr ; $kind:tt),* ) => { - { - let mut vec = vec![]; - $( - vec.push(ScopeSegment::new( - Rc::new($name.to_string()), - sym_path_kind!($kind), - )); - )* - FullyQualifiedSymbolName(vec) - } - }; -} - -#[allow(unused_macros)] -macro_rules! sym_path_kind { - (fn) => { ScopeSegmentKind::Function }; - (ty) => { ScopeSegmentKind::Type }; - (tr) => { ScopeSegmentKind::Terminal }; -} - //cf. p. 150 or so of Language Implementation Patterns pub struct SymbolTable { symbol_path_to_symbol: HashMap, @@ -313,156 +316,3 @@ impl LocalTypeContext { } } - -#[cfg(test)] -mod symbol_table_tests { - use super::*; - use crate::util::quick_ast; - - macro_rules! values_in_table { - //TODO multiple values - ($source:expr, $single_value:expr) => { - { - let mut symbol_table = SymbolTable::new(); - let ast = quick_ast($source); - symbol_table.add_top_level_symbols(&ast).unwrap(); - match symbol_table.lookup_by_fqsn($single_value) { - Some(_spec) => (), - None => panic!(), - }; - } - } - } - - #[test] - fn basic_symbol_table() { - values_in_table! { "let a = 10; fn b() { 20 }", &fqsn!("b"; tr) } - } - - #[test] - fn no_duplicates() { - let source = r#" - fn a() { 1 } - fn b() { 2 } - fn a() { 3 } - "#; - let mut symbol_table = SymbolTable::new(); - let ast = quick_ast(source); - let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); - assert!(output.contains("Duplicate")) - } - - #[test] - fn no_duplicates_2() { - let source = r#" - let a = 20; - let q = 39; - let a = 30; - "#; - let mut symbol_table = SymbolTable::new(); - let ast = quick_ast(source); - let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); - assert!(output.contains("Duplicate")) - } - - #[test] - fn no_duplicates_3() { - let source = r#" - fn a() { - let a = 20 - let b = 40 - a + b - } - - fn q() { - let x = 30 - let x = 33 - } - "#; - let mut symbol_table = SymbolTable::new(); - let ast = quick_ast(source); - let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); - assert!(output.contains("Duplicate")) - } - - #[test] - fn dont_falsely_detect_duplicates() { - let source = r#" - let a = 20; - fn some_func() { - let a = 40; - 77 - } - let q = 39; - "#; - let mut symbol_table = SymbolTable::new(); - let ast = quick_ast(source); - symbol_table.add_top_level_symbols(&ast).unwrap(); - assert!(symbol_table.lookup_by_fqsn(&fqsn!["a"; tr]).is_some()); - assert!(symbol_table.lookup_by_fqsn(&fqsn!["some_func"; fn, "a";tr]).is_some()); - } - - #[test] - fn enclosing_scopes() { - let source = r#" -fn outer_func(x) { - fn inner_func(arg) { - arg - } - x + inner_func(x) -}"#; - let mut symbol_table = SymbolTable::new(); - let ast = quick_ast(source); - symbol_table.add_top_level_symbols(&ast).unwrap(); - assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; tr)).is_some()); - assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "inner_func"; tr)).is_some()); - } - - #[test] - fn enclosing_scopes_2() { - let source = r#" -fn outer_func(x) { - fn inner_func(arg) { - arg - } - - fn second_inner_func() { - fn another_inner_func() { - } - } - - inner_func(x) -}"#; - let mut symbol_table = SymbolTable::new(); - let ast = quick_ast(source); - symbol_table.add_top_level_symbols(&ast).unwrap(); - assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; tr)).is_some()); - assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "inner_func"; tr)).is_some()); - assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "second_inner_func"; tr)).is_some()); - assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "second_inner_func"; fn, "another_inner_func"; tr)).is_some()); - } - - #[test] - fn enclosing_scopes_3() { - let source = r#" -fn outer_func(x) { - fn inner_func(arg) { - arg - } - - fn second_inner_func() { - fn another_inner_func() { - } - fn another_inner_func() { - } - } - - inner_func(x) -}"#; - let mut symbol_table = SymbolTable::new(); - let ast = quick_ast(source); - let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); - assert!(output.contains("Duplicate")) - } -} - diff --git a/schala-lang/language/src/symbol_table/test.rs b/schala-lang/language/src/symbol_table/test.rs new file mode 100644 index 0000000..31d3583 --- /dev/null +++ b/schala-lang/language/src/symbol_table/test.rs @@ -0,0 +1,151 @@ +#![cfg(test)] + +#[macro_use] +use super::*; +use crate::util::quick_ast; + +macro_rules! values_in_table { + //TODO multiple values + ($source:expr, $single_value:expr) => { + { + let mut symbol_table = SymbolTable::new(); + let ast = quick_ast($source); + symbol_table.add_top_level_symbols(&ast).unwrap(); + match symbol_table.lookup_by_fqsn($single_value) { + Some(_spec) => (), + None => panic!(), + }; + } + } +} + +#[test] +fn basic_symbol_table() { + values_in_table! { "let a = 10; fn b() { 20 }", &fqsn!("b"; tr) } +} + +#[test] +fn no_duplicates() { + let source = r#" + fn a() { 1 } + fn b() { 2 } + fn a() { 3 } + "#; + let mut symbol_table = SymbolTable::new(); + let ast = quick_ast(source); + let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); + assert!(output.contains("Duplicate")) +} + +#[test] +fn no_duplicates_2() { + let source = r#" + let a = 20; + let q = 39; + let a = 30; + "#; + let mut symbol_table = SymbolTable::new(); + let ast = quick_ast(source); + let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); + assert!(output.contains("Duplicate")) +} + +#[test] +fn no_duplicates_3() { + let source = r#" + fn a() { + let a = 20 + let b = 40 + a + b + } + + fn q() { + let x = 30 + let x = 33 + } + "#; + let mut symbol_table = SymbolTable::new(); + let ast = quick_ast(source); + let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); + assert!(output.contains("Duplicate")) +} + +#[test] +fn dont_falsely_detect_duplicates() { + let source = r#" + let a = 20; + fn some_func() { + let a = 40; + 77 + } + let q = 39; + "#; + let mut symbol_table = SymbolTable::new(); + let ast = quick_ast(source); + symbol_table.add_top_level_symbols(&ast).unwrap(); + assert!(symbol_table.lookup_by_fqsn(&fqsn!["a"; tr]).is_some()); + assert!(symbol_table.lookup_by_fqsn(&fqsn!["some_func"; fn, "a";tr]).is_some()); +} + +#[test] +fn enclosing_scopes() { + let source = r#" +fn outer_func(x) { +fn inner_func(arg) { + arg +} +x + inner_func(x) +}"#; + let mut symbol_table = SymbolTable::new(); + let ast = quick_ast(source); + symbol_table.add_top_level_symbols(&ast).unwrap(); + assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; tr)).is_some()); + assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "inner_func"; tr)).is_some()); +} + +#[test] +fn enclosing_scopes_2() { + let source = r#" +fn outer_func(x) { +fn inner_func(arg) { + arg +} + +fn second_inner_func() { + fn another_inner_func() { + } +} + +inner_func(x) +}"#; + let mut symbol_table = SymbolTable::new(); + let ast = quick_ast(source); + symbol_table.add_top_level_symbols(&ast).unwrap(); + assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; tr)).is_some()); + assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "inner_func"; tr)).is_some()); + assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "second_inner_func"; tr)).is_some()); + assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "second_inner_func"; fn, "another_inner_func"; tr)).is_some()); +} + +#[test] +fn enclosing_scopes_3() { + let source = r#" +fn outer_func(x) { +fn inner_func(arg) { + arg +} + +fn second_inner_func() { + fn another_inner_func() { + } + fn another_inner_func() { + } +} + +inner_func(x) +}"#; + let mut symbol_table = SymbolTable::new(); + let ast = quick_ast(source); + let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); + assert!(output.contains("Duplicate")) +}