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