Make symbol names better

Refactor of symbol table to make name lookups
more precise, necessary for struct member lookups
This commit is contained in:
greg 2019-08-30 18:41:47 -07:00
parent 3d6447abb4
commit 611e46938d
1 changed files with 59 additions and 38 deletions

View File

@ -11,25 +11,46 @@ use crate::typechecking::TypeName;
type LineNumber = u32; type LineNumber = u32;
type SymbolTrackTable = HashMap<Rc<String>, LineNumber>; type SymbolTrackTable = HashMap<Rc<String>, LineNumber>;
#[derive(PartialEq, Eq, Hash, Debug)] #[derive(PartialEq, Eq, Hash, Debug, Clone)]
struct PathToSymbol(Vec<Rc<String>>); pub struct FullyQualifiedSymbolName(Vec<ScopeSegment>);
#[derive(Debug, Clone)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
struct ScopeSegment { pub struct ScopeSegment {
scope_name: Rc<String>, name: Rc<String>, //TODO maybe this could be a &str, for efficiency?
scope_type: ScopeSegmentKind, kind: ScopeSegmentKind,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum ScopeSegmentKind { pub enum ScopeSegmentKind {
Function, Function,
//Type, Type,
Terminal,
}
macro_rules! fqsn {
( $( $name:expr ; $kind:tt),* ) => {
{
let mut vec = vec![];
$(
vec.push(ScopeSegment {
name: Rc::new($name.to_string()),
kind: sym_path_kind!($kind),
});
)*
FullyQualifiedSymbolName(vec)
}
};
}
macro_rules! sym_path_kind {
(fn) => { ScopeSegmentKind::Function };
(ty) => { ScopeSegmentKind::Type };
(tr) => { ScopeSegmentKind::Terminal };
} }
//cf. p. 150 or so of Language Implementation Patterns //cf. p. 150 or so of Language Implementation Patterns
pub struct SymbolTable { pub struct SymbolTable {
symbol_path_to_symbol: HashMap<PathToSymbol, Symbol>, symbol_path_to_symbol: HashMap<FullyQualifiedSymbolName, Symbol>,
type_name_to_symbol: HashMap<Rc<String>, PathToSymbol>
} }
//TODO add various types of lookups here, maybe multiple hash tables internally? //TODO add various types of lookups here, maybe multiple hash tables internally?
@ -37,38 +58,37 @@ impl SymbolTable {
pub fn new() -> SymbolTable { pub fn new() -> SymbolTable {
SymbolTable { SymbolTable {
symbol_path_to_symbol: HashMap::new(), symbol_path_to_symbol: HashMap::new(),
type_name_to_symbol: HashMap::new(),
} }
} }
fn add_new_symbol(&mut self, name: &Rc<String>, scope_path: &Vec<ScopeSegment>, spec: SymbolSpec) { fn add_new_symbol(&mut self, name: &Rc<String>, scope_path: &Vec<ScopeSegment>, spec: SymbolSpec) {
let mut vec: Vec<Rc<String>> = scope_path.iter().map(|segment| segment.scope_name.clone()).collect(); let mut vec: Vec<ScopeSegment> = scope_path.clone();
vec.push(name.clone()); vec.push(ScopeSegment { name: name.clone(), kind: ScopeSegmentKind::Terminal });
let symbol_path = PathToSymbol(vec); let fully_qualified_name = FullyQualifiedSymbolName(vec);
let symbol = Symbol { name: name.clone(), scopes: scope_path.to_vec(), spec }; let symbol = Symbol { name: name.clone(), fully_qualified_name: fully_qualified_name.clone(), spec };
self.symbol_path_to_symbol.insert(symbol_path, symbol); self.symbol_path_to_symbol.insert(fully_qualified_name, symbol);
} }
pub fn lookup_by_name(&self, name: &Rc<String>) -> Option<&Symbol> { pub fn lookup_by_name(&self, name: &Rc<String>) -> Option<&Symbol> {
self.lookup_by_path(name, &vec![]) let vec = vec![
ScopeSegment {
name: name.clone(),
kind: ScopeSegmentKind::Terminal,
}
];
let symbol_path = FullyQualifiedSymbolName(vec);
self.lookup_by_path(&symbol_path)
} }
pub fn lookup_by_path(&self, name: &Rc<String>, path: &Vec<Rc<String>>) -> Option<&Symbol> { pub fn lookup_by_path(&self, fully_qualified_path: &FullyQualifiedSymbolName) -> Option<&Symbol> {
let mut vec = path.clone(); self.symbol_path_to_symbol.get(fully_qualified_path)
vec.push(name.clone());
let symbol_path = PathToSymbol(vec);
self.symbol_path_to_symbol.get(&symbol_path)
}
pub fn lookup_by_type_and_tag(&self, type_name: &Rc<String>, tag: usize) -> Option<&Symbol> {
unimplemented!()
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Symbol { pub struct Symbol {
pub name: Rc<String>, //TODO does this need to be pub? pub name: Rc<String>, //TODO does this need to be pub?
scopes: Vec<ScopeSegment>, fully_qualified_name: FullyQualifiedSymbolName,
pub spec: SymbolSpec, pub spec: SymbolSpec,
} }
@ -146,8 +166,8 @@ impl SymbolTable {
insert_and_check_duplicate_symbol(&mut 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)?;
scope_name_stack.push(ScopeSegment{ scope_name_stack.push(ScopeSegment{
scope_name: signature.name.clone(), name: signature.name.clone(),
scope_type: ScopeSegmentKind::Function, kind: ScopeSegmentKind::Function,
}); });
let output = self.add_symbols_from_scope(body, scope_name_stack); let output = self.add_symbols_from_scope(body, scope_name_stack);
let _ = scope_name_stack.pop(); let _ = scope_name_stack.pop();
@ -155,6 +175,7 @@ impl SymbolTable {
}, },
TypeDecl { name, body, mutable } => { TypeDecl { name, body, mutable } => {
insert_and_check_duplicate_symbol(&mut seen_identifiers, &name.name)?; insert_and_check_duplicate_symbol(&mut seen_identifiers, &name.name)?;
//TODO add ScopeSegmentKind::Type here
self.add_type_decl(name, body, mutable, scope_name_stack)? self.add_type_decl(name, body, mutable, scope_name_stack)?
}, },
Binding { name, .. } => { Binding { name, .. } => {
@ -343,8 +364,8 @@ mod symbol_table_tests {
let mut symbol_table = SymbolTable::new(); let mut symbol_table = SymbolTable::new();
let ast = quick_ast(source); let ast = quick_ast(source);
symbol_table.add_top_level_symbols(&ast).unwrap(); 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(&fqsn!["a"; tr]).is_some());
assert!(symbol_table.lookup_by_path(&rc!(a), &vec![rc!(some_func)]).is_some()); assert!(symbol_table.lookup_by_path(&fqsn!["some_func"; fn, "a";tr]).is_some());
} }
#[test] #[test]
@ -359,8 +380,8 @@ fn outer_func(x) {
let mut symbol_table = SymbolTable::new(); let mut symbol_table = SymbolTable::new();
let ast = quick_ast(source); let ast = quick_ast(source);
symbol_table.add_top_level_symbols(&ast).unwrap(); symbol_table.add_top_level_symbols(&ast).unwrap();
assert!(symbol_table.lookup_by_path(&rc!(outer_func), &vec![]).is_some()); assert!(symbol_table.lookup_by_path(&fqsn!("outer_func"; tr)).is_some());
assert!(symbol_table.lookup_by_path(&rc!(inner_func), &vec![rc!(outer_func)]).is_some()); assert!(symbol_table.lookup_by_path(&fqsn!("outer_func"; fn, "inner_func"; tr)).is_some());
} }
#[test] #[test]
@ -382,10 +403,10 @@ fn outer_func(x) {
let ast = quick_ast(source); let ast = quick_ast(source);
symbol_table.add_top_level_symbols(&ast).unwrap(); symbol_table.add_top_level_symbols(&ast).unwrap();
println!("{}", symbol_table.debug_symbol_table()); println!("{}", symbol_table.debug_symbol_table());
assert!(symbol_table.lookup_by_path(&rc!(outer_func), &vec![]).is_some()); assert!(symbol_table.lookup_by_path(&fqsn!("outer_func"; tr)).is_some());
assert!(symbol_table.lookup_by_path(&rc!(inner_func), &vec![rc!(outer_func)]).is_some()); assert!(symbol_table.lookup_by_path(&fqsn!("outer_func"; fn, "inner_func"; tr)).is_some());
assert!(symbol_table.lookup_by_path(&rc!(second_inner_func), &vec![rc!(outer_func)]).is_some()); assert!(symbol_table.lookup_by_path(&fqsn!("outer_func"; fn, "second_inner_func"; tr)).is_some());
assert!(symbol_table.lookup_by_path(&rc!(another_inner_func), &vec![rc!(outer_func), rc!(second_inner_func)]).is_some()); assert!(symbol_table.lookup_by_path(&fqsn!("outer_func"; fn, "second_inner_func"; fn, "another_inner_func"; tr)).is_some());
} }
#[test] #[test]