2019-10-16 19:51:43 -07:00
|
|
|
#![cfg(test)]
|
2019-10-23 02:51:34 -07:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::rc::Rc;
|
2019-10-16 19:51:43 -07:00
|
|
|
|
|
|
|
use super::*;
|
|
|
|
use crate::util::quick_ast;
|
|
|
|
|
2019-10-23 14:02:27 -07:00
|
|
|
fn add_symbols_from_source(src: &str) -> (SymbolTable, Result<(), String>) {
|
2019-10-23 14:45:12 -07:00
|
|
|
let (ast, source_map) = quick_ast(src);
|
|
|
|
let source_map = Rc::new(RefCell::new(source_map));
|
2019-10-23 14:02:27 -07:00
|
|
|
let mut symbol_table = SymbolTable::new(source_map);
|
|
|
|
let result = symbol_table.add_top_level_symbols(&ast);
|
|
|
|
(symbol_table, result)
|
|
|
|
}
|
|
|
|
|
2019-10-16 19:51:43 -07:00
|
|
|
macro_rules! values_in_table {
|
2019-10-16 22:46:58 -07:00
|
|
|
($source:literal, $single_value:expr) => {
|
|
|
|
values_in_table!($source | $single_value);
|
|
|
|
};
|
|
|
|
($source:literal | $( $value:expr ),* ) => {
|
2019-10-16 19:51:43 -07:00
|
|
|
{
|
2019-10-23 14:02:27 -07:00
|
|
|
let (symbol_table, _) = add_symbols_from_source($source);
|
2019-10-16 22:46:58 -07:00
|
|
|
$(
|
|
|
|
match symbol_table.lookup_by_fqsn($value) {
|
|
|
|
Some(_spec) => (),
|
|
|
|
None => panic!(),
|
|
|
|
};
|
|
|
|
)*
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
2019-10-16 22:46:58 -07:00
|
|
|
};
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn basic_symbol_table() {
|
2019-10-16 20:22:40 -07:00
|
|
|
values_in_table! { "let a = 10; fn b() { 20 }", &fqsn!("b"; tr) };
|
2019-10-16 22:46:58 -07:00
|
|
|
values_in_table! { "type Option<T> = Some(T) | None" |
|
|
|
|
&fqsn!("Option"; tr),
|
|
|
|
&fqsn!("Option"; ty, "Some"; tr),
|
|
|
|
&fqsn!("Option"; ty, "None"; tr) };
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-10-24 01:34:13 -07:00
|
|
|
fn no_function_definition_duplicates() {
|
2019-10-16 19:51:43 -07:00
|
|
|
let source = r#"
|
|
|
|
fn a() { 1 }
|
|
|
|
fn b() { 2 }
|
|
|
|
fn a() { 3 }
|
|
|
|
"#;
|
2019-10-23 14:02:27 -07:00
|
|
|
let (_, output) = add_symbols_from_source(source);
|
2019-10-24 01:34:13 -07:00
|
|
|
assert!(output.unwrap_err().contains("Duplicate function definition: a"))
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-10-24 01:34:13 -07:00
|
|
|
fn no_variable_definition_duplicates() {
|
2019-10-16 19:51:43 -07:00
|
|
|
let source = r#"
|
2019-10-23 14:45:12 -07:00
|
|
|
let x = 9
|
|
|
|
let a = 20
|
|
|
|
let q = 39
|
|
|
|
let a = 30
|
2019-10-16 19:51:43 -07:00
|
|
|
"#;
|
2019-10-23 14:02:27 -07:00
|
|
|
let (_, output) = add_symbols_from_source(source);
|
|
|
|
let output = output.unwrap_err();
|
2019-10-24 01:34:13 -07:00
|
|
|
assert!(output.contains("Duplicate variable definition: a"));
|
2019-10-23 14:45:12 -07:00
|
|
|
assert!(output.contains("already defined at 2"));
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-10-24 01:34:13 -07:00
|
|
|
fn no_variable_definition_duplicates_in_function() {
|
2019-10-16 19:51:43 -07:00
|
|
|
let source = r#"
|
|
|
|
fn a() {
|
|
|
|
let a = 20
|
|
|
|
let b = 40
|
|
|
|
a + b
|
|
|
|
}
|
|
|
|
|
|
|
|
fn q() {
|
2019-10-24 01:34:13 -07:00
|
|
|
let a = 29
|
2019-10-16 19:51:43 -07:00
|
|
|
let x = 30
|
|
|
|
let x = 33
|
|
|
|
}
|
|
|
|
"#;
|
2019-10-23 14:02:27 -07:00
|
|
|
let (_, output) = add_symbols_from_source(source);
|
2019-10-24 01:34:13 -07:00
|
|
|
assert!(output.unwrap_err().contains("Duplicate variable definition: x"))
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dont_falsely_detect_duplicates() {
|
|
|
|
let source = r#"
|
|
|
|
let a = 20;
|
|
|
|
fn some_func() {
|
|
|
|
let a = 40;
|
|
|
|
77
|
|
|
|
}
|
|
|
|
let q = 39;
|
|
|
|
"#;
|
2019-10-23 14:02:27 -07:00
|
|
|
let (symbol_table, _) = add_symbols_from_source(source);
|
2019-10-16 19:51:43 -07:00
|
|
|
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)
|
|
|
|
}"#;
|
2019-10-23 14:02:27 -07:00
|
|
|
let (symbol_table, _) = add_symbols_from_source(source);
|
2019-10-16 19:51:43 -07:00
|
|
|
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)
|
|
|
|
}"#;
|
2019-10-23 14:02:27 -07:00
|
|
|
let (symbol_table, _) = add_symbols_from_source(source);
|
2019-10-16 19:51:43 -07:00
|
|
|
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)
|
|
|
|
}"#;
|
2019-10-23 14:02:27 -07:00
|
|
|
let (_, output) = add_symbols_from_source(source);
|
|
|
|
assert!(output.unwrap_err().contains("Duplicate"))
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
2019-10-24 01:34:13 -07:00
|
|
|
|
|
|
|
#[test]
|
2019-10-24 02:13:07 -07:00
|
|
|
fn duplicate_modules() {
|
2019-10-24 01:34:13 -07:00
|
|
|
let source = r#"
|
2019-10-24 02:13:07 -07:00
|
|
|
module q {
|
|
|
|
fn foo() { 4 }
|
|
|
|
}
|
2019-10-24 01:34:13 -07:00
|
|
|
|
|
|
|
module a {
|
2019-10-24 02:13:07 -07:00
|
|
|
fn foo() { 334 }
|
2019-10-24 01:34:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
module a {
|
2019-10-24 02:13:07 -07:00
|
|
|
fn foo() { 256.1 }
|
2019-10-24 01:34:13 -07:00
|
|
|
}
|
|
|
|
"#;
|
|
|
|
let (_, output) = add_symbols_from_source(source);
|
2019-10-24 02:13:07 -07:00
|
|
|
let output = output.unwrap_err();
|
|
|
|
assert!(output.contains("Duplicate module"));
|
|
|
|
assert!(output.contains("already defined at 5"));
|
2019-10-24 01:34:13 -07:00
|
|
|
}
|