use std::rc::Rc; use crate::schala::SymbolTableHandle; use crate::symbol_table::{ScopeSegment, FullyQualifiedSymbolName}; use crate::ast::*; use crate::util::ScopeStack; type FQSNPrefix = Vec; pub struct ScopeResolver<'a> { symbol_table_handle: SymbolTableHandle, name_scope_stack: ScopeStack<'a, Rc, FQSNPrefix>, } impl<'a> ASTVisitor for ScopeResolver<'a> { //TODO need to un-insert these - maybe need to rethink visitor fn import(&mut self, import_spec: &ImportSpecifier) { let ref symbol_table = self.symbol_table_handle.borrow(); let ImportSpecifier { ref path_components, ref imported_names, .. } = &import_spec; match imported_names { ImportedNames::All => { let prefix = FullyQualifiedSymbolName(path_components.iter().map(|c| ScopeSegment { name: c.clone(), }).collect()); let members = symbol_table.lookup_children_of_fqsn(&prefix); for member in members.into_iter() { let local_name = member.0.last().unwrap().name.clone(); self.name_scope_stack.insert(local_name.clone(), member.0); } }, ImportedNames::LastOfPath => { let name = path_components.last().unwrap(); //TODO handle better let fqsn_prefix = path_components.iter().map(|c| ScopeSegment { name: c.clone(), }).collect(); self.name_scope_stack.insert(name.clone(), fqsn_prefix); } ImportedNames::List(ref names) => { let fqsn_prefix: FQSNPrefix = path_components.iter().map(|c| ScopeSegment { name: c.clone(), }).collect(); for name in names.iter() { self.name_scope_stack.insert(name.clone(), fqsn_prefix.clone()); } } }; } fn qualified_name(&mut self, qualified_name: &QualifiedName) { let ref mut symbol_table = self.symbol_table_handle.borrow_mut(); let fqsn = self.lookup_name_in_scope(&qualified_name); let ref id = qualified_name.id; symbol_table.map_id_to_fqsn(id, fqsn); } fn named_struct(&mut self, name: &QualifiedName, _fields: &Vec<(Rc, Expression)>) { let ref mut symbol_table = self.symbol_table_handle.borrow_mut(); let ref id = name.id; let fqsn = self.lookup_name_in_scope(&name); symbol_table.map_id_to_fqsn(id, fqsn); } fn pattern(&mut self, pat: &Pattern) { use Pattern::*; match pat { Ignored => (), TuplePattern(_) => (), Literal(_) => (), TupleStruct(name, _) => self.qualified_name_in_pattern(name), Record(name, _) => self.qualified_name_in_pattern(name), VarOrName(name) => self.qualified_name_in_pattern(name), }; } } impl<'a> ScopeResolver<'a> { pub fn new(symbol_table_handle: SymbolTableHandle) -> ScopeResolver<'static> { let name_scope_stack = ScopeStack::new(None); ScopeResolver { symbol_table_handle, name_scope_stack } } pub fn resolve(&mut self, ast: &mut AST) -> Result<(), String> { walk_ast(self, ast); Ok(()) } fn lookup_name_in_scope(&self, sym_name: &QualifiedName) -> FullyQualifiedSymbolName { let QualifiedName { components, .. } = sym_name; let first_component = &components[0]; match self.name_scope_stack.lookup(first_component) { None => { FullyQualifiedSymbolName(components.iter().map(|name| ScopeSegment { name: name.clone() }).collect()) }, Some(fqsn_prefix) => { let mut full_name = fqsn_prefix.clone(); let rest_of_name: FQSNPrefix = components[1..].iter().map(|name| ScopeSegment { name: name.clone() }).collect(); full_name.extend_from_slice(&rest_of_name); FullyQualifiedSymbolName(full_name) } } } /// this might be a variable or a pattern. if a variable, set to none fn qualified_name_in_pattern(&mut self, qualified_name: &QualifiedName) { let ref mut symbol_table = self.symbol_table_handle.borrow_mut(); let ref id = qualified_name.id; let fqsn = self.lookup_name_in_scope(qualified_name); if symbol_table.lookup_by_fqsn(&fqsn).is_some() { symbol_table.map_id_to_fqsn(&id, fqsn); } } } #[cfg(test)] mod tests { #[test] fn basic_scope() { } }