#![cfg(test)] use super::*; use crate::util::quick_ast; use assert_matches::assert_matches; fn add_symbols(src: &str) -> (SymbolTable, Result<(), Vec>) { let ast = quick_ast(src); let mut symbol_table = SymbolTable::new(); let result = symbol_table.process_ast(&ast); (symbol_table, result) } fn make_fqsn(strs: &[&str]) -> Fqsn { Fqsn::from_strs(strs) } #[test] fn basic_symbol_table() { let src = "let a = 10; fn b() { 20 }"; let (symbols, _) = add_symbols(src); fn make_fqsn(strs: &[&str]) -> Fqsn { Fqsn::from_strs(strs) } symbols.fq_names.table.get(&make_fqsn(&["b"])).unwrap(); let src = "type Option = Some(T) | None"; let (symbols, _) = add_symbols(src); symbols.types.table.get(&make_fqsn(&["Option"])).unwrap(); symbols .types .table .get(&make_fqsn(&["Option", "Some"])) .unwrap(); symbols .types .table .get(&make_fqsn(&["Option", "None"])) .unwrap(); } #[test] fn no_function_definition_duplicates() { let source = r#" fn a() { 1 } fn b() { 2 } fn a() { 3 } "#; let (_, output) = add_symbols(source); let errs = output.unwrap_err(); assert_matches!(&errs[..], [ SymbolError::DuplicateName { prev_name, ..} ] if prev_name == &Fqsn::from_strs(&["a"]) ); } #[test] fn no_variable_definition_duplicates() { let source = r#" let x = 9 let a = 20 let q = 39 let a = 30 let x = 34 "#; let (_, output) = add_symbols(source); let errs = output.unwrap_err(); assert_matches!(&errs[..], [ SymbolError::DuplicateName { prev_name: pn1, ..}, SymbolError::DuplicateName { prev_name: pn2, ..} ] if pn1 == &Fqsn::from_strs(&["a"]) && pn2 == &Fqsn::from_strs(&["x"]) ); } #[test] fn no_variable_definition_duplicates_in_function() { let source = r#" fn a() { let a = 20 let b = 40 a + b } fn q() { let a = 29 let x = 30 let x = 33 } "#; let (_, output) = add_symbols(source); let errs = output.unwrap_err(); assert_matches!(&errs[..], [ SymbolError::DuplicateName { prev_name: pn1, ..}, ] if pn1 == &Fqsn::from_strs(&["q", "x"]) ); } #[test] fn dont_falsely_detect_duplicates() { let source = r#" let a = 20; fn some_func() { let a = 40; 77 } let q = 39; "#; let (symbols, _) = add_symbols(source); assert!(symbols.fq_names.table.get(&make_fqsn(&["a"])).is_some()); assert!(symbols .fq_names .table .get(&make_fqsn(&["some_func", "a"])) .is_some()); } #[test] fn enclosing_scopes() { let source = r#" fn outer_func(x) { fn inner_func(arg) { arg } x + inner_func(x) }"#; let (symbols, _) = add_symbols(source); assert!(symbols .fq_names .table .get(&make_fqsn(&["outer_func"])) .is_some()); assert!(symbols .fq_names .table .get(&make_fqsn(&["outer_func", "inner_func"])) .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 (symbols, _) = add_symbols(source); assert!(symbols .fq_names .table .get(&make_fqsn(&["outer_func"])) .is_some()); assert!(symbols .fq_names .table .get(&make_fqsn(&["outer_func", "inner_func"])) .is_some()); assert!(symbols .fq_names .table .get(&make_fqsn(&["outer_func", "second_inner_func"])) .is_some()); assert!(symbols .fq_names .table .get(&make_fqsn(&[ "outer_func", "second_inner_func", "another_inner_func" ])) .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 (_, output) = add_symbols(source); let _err = output.unwrap_err(); } #[test] fn modules() { let source = r#" module stuff { fn item() { } } fn item() "#; let (symbols, _) = add_symbols(source); symbols.fq_names.table.get(&make_fqsn(&["stuff"])).unwrap(); symbols.fq_names.table.get(&make_fqsn(&["item"])).unwrap(); symbols .fq_names .table .get(&make_fqsn(&["stuff", "item"])) .unwrap(); } #[test] fn duplicate_modules() { let source = r#" module q { fn foo() { 4 } } module a { fn foo() { 334 } } module a { fn sarat() { 39 } fn foo() { 256.1 } } "#; let (_, output) = add_symbols(source); let errs = output.unwrap_err(); assert_matches!(&errs[..], [ SymbolError::DuplicateName { prev_name: pn1, ..}, ] if pn1 == &Fqsn::from_strs(&["a"]) ); } #[test] fn duplicate_struct_members() { //TODO this is a parser error /* let source = r#" type Tarak = Tarak { loujet: i32, mets: i32, mets: i32, } "#; */ let source = r#" type Tarak = Tarak { loujet: i32, mets: i32, mets: i32 } "#; let (_, output) = add_symbols(source); let errs = output.unwrap_err(); assert_matches!(&errs[..], [ SymbolError::DuplicateRecord { type_name, member, ..}, ] if type_name == &Fqsn::from_strs(&["Tarak", "Tarak"]) && member == "mets" ); }