Symbol table detects some duplicate symbols
This commit is contained in:
parent
956353cd80
commit
9716b5e55b
5
TODO.md
5
TODO.md
@ -1,5 +1,10 @@
|
|||||||
#Typechecking Notes
|
#Typechecking Notes
|
||||||
|
|
||||||
|
|
||||||
|
IDEA: - if you have a pattern-match where one variant has a variable and the other lacks it
|
||||||
|
instead of treating this as a type error, promote the bound variable to an option type
|
||||||
|
|
||||||
|
|
||||||
IS BOX SYNTAX READY????
|
IS BOX SYNTAX READY????
|
||||||
|
|
||||||
(cf. cardelli paper)
|
(cf. cardelli paper)
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
use std::iter::IntoIterator;
|
||||||
|
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
use crate::ast::{TypeBody, TypeSingletonName, Signature};
|
use crate::ast::{Meta, TypeBody, TypeSingletonName, Signature, Statement};
|
||||||
use crate::typechecking::TypeName;
|
use crate::typechecking::TypeName;
|
||||||
|
|
||||||
|
type LineNumber = u32;
|
||||||
|
type SymbolTrackTable = HashMap<Rc<String>, LineNumber>;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||||
struct SymbolPath {
|
struct SymbolPath {
|
||||||
name: Rc<String>,
|
name: Rc<String>,
|
||||||
@ -85,14 +90,43 @@ impl fmt::Display for SymbolSpec {
|
|||||||
impl SymbolTable {
|
impl SymbolTable {
|
||||||
/* note: this adds names for *forward reference* but doesn't actually create any types. solve that problem
|
/* note: this adds names for *forward reference* but doesn't actually create any types. solve that problem
|
||||||
* 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> {
|
||||||
use self::ast::Statement;
|
let mut seen_identifiers = HashMap::new();
|
||||||
|
self.add_symbols_from_scope(&ast.0, &mut seen_identifiers)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_symbols_from_scope<'a>(&'a mut self, statements: &Vec<Meta<Statement>>, seen_identifiers: &mut SymbolTrackTable) -> Result<(), String> {
|
||||||
use self::ast::Declaration::*;
|
use self::ast::Declaration::*;
|
||||||
for statement in ast.0.iter() {
|
|
||||||
let statement = statement.node();
|
fn check_symbol(table: &mut SymbolTrackTable, name: &Rc<String>) -> Result<(), String> {
|
||||||
|
match table.entry(name.clone()) {
|
||||||
|
Entry::Occupied(o) => {
|
||||||
|
let line_number = o.get(); //TODO make this actually work
|
||||||
|
Err(format!("Duplicate definition: {}. It's already defined at {}", name, line_number))
|
||||||
|
},
|
||||||
|
Entry::Vacant(v) => {
|
||||||
|
let line_number = 0; //TODO should work
|
||||||
|
v.insert(line_number);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for meta in statements.iter() {
|
||||||
|
let statement = meta.node();
|
||||||
if let Statement::Declaration(decl) = statement {
|
if let Statement::Declaration(decl) = statement {
|
||||||
match decl {
|
match decl {
|
||||||
FuncSig(signature) | FuncDecl(signature, _) => self.add_function_signature(signature)?,
|
FuncSig(ref signature) => {
|
||||||
|
check_symbol(seen_identifiers, &signature.name)?;
|
||||||
|
self.add_function_signature(signature)?
|
||||||
|
}
|
||||||
|
FuncDecl(ref signature, ref body) => {
|
||||||
|
check_symbol(seen_identifiers, &signature.name)?;
|
||||||
|
self.add_function_signature(signature)?;
|
||||||
|
let mut subscope_seen_identifiers = HashMap::new();
|
||||||
|
self.add_symbols_from_scope(body, &mut subscope_seen_identifiers)?
|
||||||
|
},
|
||||||
TypeDecl { name, body, mutable } => self.add_type_decl(name, body, mutable)?,
|
TypeDecl { name, body, mutable } => self.add_type_decl(name, body, mutable)?,
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
@ -204,5 +238,18 @@ mod symbol_table_tests {
|
|||||||
fn basic_symbol_table() {
|
fn basic_symbol_table() {
|
||||||
values_in_table! { "let a = 10; fn b() { 20 }", &rc!(b) };
|
values_in_table! { "let a = 10; fn b() { 20 }", &rc!(b) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_duplicates() {
|
||||||
|
let source = r#"
|
||||||
|
fn a() { 1 }
|
||||||
|
fn b() { 2 }
|
||||||
|
fn a() { 3 }
|
||||||
|
"#;
|
||||||
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
let ast = crate::util::quick_ast(source);
|
||||||
|
let output = symbol_table.add_top_level_symbols(&ast).unwrap_err();
|
||||||
|
assert!(output.contains("Duplicate"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,12 +42,14 @@ impl<'a, T, V> ScopeStack<'a, T, V> where T: Hash + Eq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// this is intended for use in tests, and does no error-handling whatsoever
|
/// this is intended for use in tests, and does no error-handling whatsoever
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn quick_ast(input: &str) -> crate::ast::AST {
|
pub fn quick_ast(input: &str) -> crate::ast::AST {
|
||||||
let tokens = crate::tokenizing::tokenize(input);
|
let tokens = crate::tokenizing::tokenize(input);
|
||||||
let mut parser = crate::parsing::Parser::new(tokens);
|
let mut parser = crate::parsing::Parser::new(tokens);
|
||||||
parser.parse().unwrap()
|
parser.parse().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
macro_rules! rc {
|
macro_rules! rc {
|
||||||
($string:tt) => { Rc::new(stringify!($string).to_string()) }
|
($string:tt) => { Rc::new(stringify!($string).to_string()) }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user