use std::rc::Rc; use crate::symbol_table::{SymbolTable, ScopeSegment, ScopeSegmentKind, FullyQualifiedSymbolName}; use crate::ast::*; use crate::util::ScopeStack; type FQSNPrefix = Vec; type NameScopeStack<'t> = ScopeStack<'t, Rc, FQSNPrefix>; pub struct ScopeResolver<'a> { symbol_table: &'a mut SymbolTable, name_scope_stack: ScopeStack<'a, Rc, FQSNPrefix>, } impl<'a> ASTVisitor for ScopeResolver<'a> { fn import(&mut self, import_spec: &ImportSpecifier) { let ImportSpecifier { ref path_components, ref imported_names, .. } = &import_spec; match imported_names { ImportedNames::All => unimplemented!(), ImportedNames::LastOfPath => { let name = path_components.last().unwrap(); //TODO handle better let fqsn_prefix = path_components.iter().map(|c| ScopeSegment { name: c.clone(), kind: ScopeSegmentKind::Type }).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(), kind: ScopeSegmentKind::Type }).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 fqsn = self.lookup_name_in_scope(&qualified_name); let ref id = qualified_name.id; self.symbol_table.map_id_to_fqsn(id, fqsn); } fn named_struct(&mut self, name: &QualifiedName, _fields: &Vec<(Rc, Expression)>) { let ref id = name.id; let fqsn = self.lookup_name_in_scope(&name); self.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: &'a mut SymbolTable) -> ScopeResolver { let name_scope_stack = ScopeStack::new(None); ScopeResolver { symbol_table, name_scope_stack } } pub fn resolve(&mut self, ast: &mut AST) -> Result<(), String> { walk_ast(self, ast); Ok(()) } //TODO this is incomplete fn lookup_name_in_scope(&self, sym_name: &QualifiedName) -> FullyQualifiedSymbolName { let QualifiedName { components: vec, .. } = sym_name; let len = vec.len(); let new_vec: Vec = vec.iter().enumerate().map(|(i, name)| { let kind = if i == (len - 1) { ScopeSegmentKind::Terminal } else { ScopeSegmentKind::Type }; ScopeSegment { name: name.clone(), kind } }).collect(); FullyQualifiedSymbolName(new_vec) } /// 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 id = qualified_name.id; let fqsn = self.lookup_name_in_scope(qualified_name); if self.symbol_table.lookup_by_fqsn(&fqsn).is_some() { self.symbol_table.map_id_to_fqsn(&id, fqsn); } } } #[cfg(test)] mod tests { #[test] fn basic_scope() { } }