Make symbol names better
Refactor of symbol table to make name lookups more precise, necessary for struct member lookups
This commit is contained in:
parent
3d6447abb4
commit
611e46938d
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user