Detect duplicate variable declarations correctly
Later I'll probably want to make it so that you can explicitly override the value of a declared variable
This commit is contained in:
parent
8f176543c7
commit
c64f53a050
@ -483,8 +483,14 @@ impl<'a> State<'a> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
SymbolSpec::RecordConstructor { .. } => return Err(format!("This shouldn't be a record!")),
|
SymbolSpec::RecordConstructor { .. } => return Err(format!("This shouldn't be a record!")),
|
||||||
|
SymbolSpec::Binding => match self.values.lookup(&name) {
|
||||||
|
Some(Binding { val, .. }) => val.clone(),
|
||||||
|
None => return Err(format!("Symbol {} exists in symbol table but not in evaluator table", name))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/* see if it's an ordinary variable TODO make variables go in symbol table */
|
//TODO ideally this should be returning a runtime error if this is ever None, but it's not
|
||||||
|
//handling all bindings correctly yet
|
||||||
|
//None => return Err(format!("Couldn't find value {}", name)),
|
||||||
None => match self.values.lookup(&name) {
|
None => match self.values.lookup(&name) {
|
||||||
Some(Binding { val, .. }) => val.clone(),
|
Some(Binding { val, .. }) => val.clone(),
|
||||||
None => return Err(format!("Couldn't find value {}", name)),
|
None => return Err(format!("Couldn't find value {}", name)),
|
||||||
|
@ -76,7 +76,8 @@ pub enum SymbolSpec {
|
|||||||
},
|
},
|
||||||
RecordConstructor {
|
RecordConstructor {
|
||||||
fields: HashMap<Rc<String>, Rc<String>>
|
fields: HashMap<Rc<String>, Rc<String>>
|
||||||
}
|
},
|
||||||
|
Binding
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SymbolSpec {
|
impl fmt::Display for SymbolSpec {
|
||||||
@ -86,6 +87,7 @@ impl fmt::Display for SymbolSpec {
|
|||||||
Func(type_names) => write!(f, "Func({:?})", type_names),
|
Func(type_names) => write!(f, "Func({:?})", type_names),
|
||||||
DataConstructor { index, type_name, type_args } => write!(f, "DataConstructor(idx: {})({:?} -> {})", index, type_args, type_name),
|
DataConstructor { index, type_name, type_args } => write!(f, "DataConstructor(idx: {})({:?} -> {})", index, type_args, type_name),
|
||||||
RecordConstructor { fields: _fields } => write!(f, "RecordConstructor( <fields> )"),
|
RecordConstructor { fields: _fields } => write!(f, "RecordConstructor( <fields> )"),
|
||||||
|
Binding => write!(f, "Binding"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,18 +97,14 @@ impl SymbolTable {
|
|||||||
* later */
|
* later */
|
||||||
|
|
||||||
pub fn add_top_level_symbols(&mut self, ast: &ast::AST) -> Result<(), String> {
|
pub fn add_top_level_symbols(&mut self, ast: &ast::AST) -> Result<(), String> {
|
||||||
let mut seen_identifiers = HashMap::new();
|
|
||||||
let mut scope_name_stack = Vec::new();
|
let mut scope_name_stack = Vec::new();
|
||||||
self.add_symbols_from_scope(&ast.0, &mut scope_name_stack, &mut seen_identifiers)
|
self.add_symbols_from_scope(&ast.0, &mut scope_name_stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_symbols_from_scope<'a>(&'a mut self,
|
fn add_symbols_from_scope<'a>(&'a mut self, statements: &Vec<Meta<Statement>>, scope_name_stack: &mut Vec<Rc<String>>) -> Result<(), String> {
|
||||||
statements: &Vec<Meta<Statement>>,
|
|
||||||
scope_name_stack: &mut Vec<Rc<String>>,
|
|
||||||
seen_identifiers: &mut SymbolTrackTable) -> Result<(), String> {
|
|
||||||
use self::ast::Declaration::*;
|
use self::ast::Declaration::*;
|
||||||
|
|
||||||
fn check_symbol(table: &mut SymbolTrackTable, name: &Rc<String>) -> Result<(), String> {
|
fn insert_and_check_duplicate_symbol(table: &mut SymbolTrackTable, name: &Rc<String>) -> Result<(), String> {
|
||||||
match table.entry(name.clone()) {
|
match table.entry(name.clone()) {
|
||||||
Entry::Occupied(o) => {
|
Entry::Occupied(o) => {
|
||||||
let line_number = o.get(); //TODO make this actually work
|
let line_number = o.get(); //TODO make this actually work
|
||||||
@ -120,24 +118,33 @@ impl SymbolTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut seen_identifiers: SymbolTrackTable = HashMap::new();
|
||||||
|
|
||||||
for meta in statements.iter() {
|
for meta in statements.iter() {
|
||||||
let statement = meta.node();
|
let statement = meta.node();
|
||||||
if let Statement::Declaration(decl) = statement {
|
if let Statement::Declaration(decl) = statement {
|
||||||
match decl {
|
match decl {
|
||||||
FuncSig(ref signature) => {
|
FuncSig(ref signature) => {
|
||||||
check_symbol(seen_identifiers, &signature.name)?;
|
insert_and_check_duplicate_symbol(&mut seen_identifiers, &signature.name)?;
|
||||||
self.add_function_signature(signature, scope_name_stack)?
|
self.add_function_signature(signature, scope_name_stack)?
|
||||||
}
|
}
|
||||||
FuncDecl(ref signature, ref body) => {
|
FuncDecl(ref signature, ref body) => {
|
||||||
check_symbol(seen_identifiers, &signature.name)?;
|
insert_and_check_duplicate_symbol(&mut seen_identifiers, &signature.name)?;
|
||||||
self.add_function_signature(signature, scope_name_stack)?;
|
self.add_function_signature(signature, scope_name_stack)?;
|
||||||
let mut subscope_seen_identifiers = HashMap::new();
|
|
||||||
scope_name_stack.push(signature.name.clone());
|
scope_name_stack.push(signature.name.clone());
|
||||||
let output = self.add_symbols_from_scope(body, scope_name_stack, &mut subscope_seen_identifiers);
|
let output = self.add_symbols_from_scope(body, scope_name_stack);
|
||||||
let _ = scope_name_stack.pop();
|
let _ = scope_name_stack.pop();
|
||||||
output?
|
output?
|
||||||
},
|
},
|
||||||
TypeDecl { name, body, mutable } => self.add_type_decl(name, body, mutable, scope_name_stack)?,
|
TypeDecl { name, body, mutable } => {
|
||||||
|
insert_and_check_duplicate_symbol(&mut seen_identifiers, &name.name)?;
|
||||||
|
self.add_type_decl(name, body, mutable, scope_name_stack)?
|
||||||
|
},
|
||||||
|
Binding { name, .. } => {
|
||||||
|
insert_and_check_duplicate_symbol(&mut seen_identifiers, name)?;
|
||||||
|
let symbol = Symbol { name: name.clone(), spec: SymbolSpec::Binding };
|
||||||
|
self.add_new_symbol(name, scope_name_stack, symbol);
|
||||||
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,6 +270,55 @@ mod symbol_table_tests {
|
|||||||
assert!(output.contains("Duplicate"))
|
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"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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_path(&rc!(a), &vec![]).is_some());
|
||||||
|
assert!(symbol_table.lookup_by_path(&rc!(a), &vec![rc!(some_func)]).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn enclosing_scopes() {
|
fn enclosing_scopes() {
|
||||||
let source = r#"
|
let source = r#"
|
||||||
|
Loading…
Reference in New Issue
Block a user