From 611e46938d05043a0ae0eafd59ad09326a24e545 Mon Sep 17 00:00:00 2001 From: greg Date: Fri, 30 Aug 2019 18:41:47 -0700 Subject: [PATCH] Make symbol names better Refactor of symbol table to make name lookups more precise, necessary for struct member lookups --- schala-lang/language/src/symbol_table.rs | 97 ++++++++++++++---------- 1 file changed, 59 insertions(+), 38 deletions(-) diff --git a/schala-lang/language/src/symbol_table.rs b/schala-lang/language/src/symbol_table.rs index 042e41f..cfeb8d0 100644 --- a/schala-lang/language/src/symbol_table.rs +++ b/schala-lang/language/src/symbol_table.rs @@ -11,25 +11,46 @@ use crate::typechecking::TypeName; type LineNumber = u32; type SymbolTrackTable = HashMap, LineNumber>; -#[derive(PartialEq, Eq, Hash, Debug)] -struct PathToSymbol(Vec>); +#[derive(PartialEq, Eq, Hash, Debug, Clone)] +pub struct FullyQualifiedSymbolName(Vec); -#[derive(Debug, Clone)] -struct ScopeSegment { - scope_name: Rc, - scope_type: ScopeSegmentKind, +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct ScopeSegment { + name: Rc, //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, - type_name_to_symbol: HashMap, PathToSymbol> + symbol_path_to_symbol: HashMap, } //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, scope_path: &Vec, spec: SymbolSpec) { - let mut vec: Vec> = 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 = 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) -> 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, path: &Vec>) -> 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, 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, //TODO does this need to be pub? - scopes: Vec, + 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]