From 8b724cf0ff97c6495b68d5493cfb31df7e3b4adf Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Tue, 19 Oct 2021 13:48:00 -0700 Subject: [PATCH] Big refactor of symbol table --- schala-lang/language/src/eval/test.rs | 9 +- schala-lang/language/src/lib.rs | 1 - schala-lang/language/src/reduced_ast.rs | 38 ++-- schala-lang/language/src/schala.rs | 9 +- schala-lang/language/src/symbol_table/mod.rs | 166 +++++++++++------- .../language/src/symbol_table/resolver.rs | 112 ++++++++++++ .../language/src/symbol_table/symbol_trie.rs | 49 ++++-- schala-lang/language/src/symbol_table/test.rs | 1 - 8 files changed, 266 insertions(+), 119 deletions(-) create mode 100644 schala-lang/language/src/symbol_table/resolver.rs diff --git a/schala-lang/language/src/eval/test.rs b/schala-lang/language/src/eval/test.rs index 60837fd..1002cd9 100644 --- a/schala-lang/language/src/eval/test.rs +++ b/schala-lang/language/src/eval/test.rs @@ -4,18 +4,15 @@ use std::cell::RefCell; use std::rc::Rc; use crate::symbol_table::SymbolTable; -use crate::scope_resolution::ScopeResolver; use crate::reduced_ast::reduce; use crate::eval::State; fn evaluate_all_outputs(input: &str) -> Vec> { - let mut ast = crate::util::quick_ast(input); + let ast = crate::util::quick_ast(input); let symbol_table = Rc::new(RefCell::new(SymbolTable::new())); symbol_table.borrow_mut().add_top_level_symbols(&ast).unwrap(); - { - let mut scope_resolver = ScopeResolver::new(symbol_table.clone()); - let _ = scope_resolver.resolve(&mut ast); - } + + symbol_table.borrow_mut().process_ast(&ast).unwrap(); let reduced = reduce(&ast, &symbol_table.borrow()); let mut state = State::new(); diff --git a/schala-lang/language/src/lib.rs b/schala-lang/language/src/lib.rs index 789d813..6a8803d 100644 --- a/schala-lang/language/src/lib.rs +++ b/schala-lang/language/src/lib.rs @@ -25,7 +25,6 @@ mod builtin; mod error; mod eval; mod reduced_ast; -mod scope_resolution; mod schala; diff --git a/schala-lang/language/src/reduced_ast.rs b/schala-lang/language/src/reduced_ast.rs index b838f10..a0f0859 100644 --- a/schala-lang/language/src/reduced_ast.rs +++ b/schala-lang/language/src/reduced_ast.rs @@ -178,16 +178,7 @@ impl<'a> Reducer<'a> { } fn value(&mut self, qualified_name: &QualifiedName) -> Expr { - let sym_name = match self.symbol_table.get_fqsn_from_id(&qualified_name.id) { - Some(fqsn) => fqsn, - None => return Expr::ReductionError(format!("FQSN lookup for Value {:?} failed", qualified_name)), - }; - - //TODO this probably needs to change - let FullyQualifiedSymbolName(ref v) = sym_name; - //let name = v.last().unwrap().name.clone(); - - let Symbol { local_name, spec, .. } = match self.symbol_table.lookup_by_fqsn(&sym_name) { + let Symbol { local_name, spec, .. } = match self.symbol_table.lookup_symbol(&qualified_name.id) { Some(s) => s, //TODO this causes several evaluation tests to fail, figure out what's going on here //None => return Expr::ReductionError(format!("Symbol {:?} not found", sym_name)), @@ -220,17 +211,16 @@ impl<'a> Reducer<'a> { } fn reduce_named_struct(&mut self, name: &QualifiedName, fields: &Vec<(Rc, Expression)>) -> Expr { - let ref sym_name = match self.symbol_table.get_fqsn_from_id(&name.id) { + let symbol = match self.symbol_table.lookup_symbol(&name.id) { Some(fqsn) => fqsn, None => return Expr::ReductionError(format!("FQSN lookup for name {:?} failed", name)), }; - let FullyQualifiedSymbolName(ref v) = sym_name; - let ref name = v.last().unwrap().name; - let (type_name, index, members_from_table) = match self.symbol_table.lookup_by_fqsn(&sym_name) { - Some(Symbol { spec: SymbolSpec::RecordConstructor { members, type_name, index }, .. }) => (type_name.clone(), index, members), + let (type_name, index, members_from_table) = match &symbol.spec { + SymbolSpec::RecordConstructor { members, type_name, index } => (type_name.clone(), index, members), _ => return Expr::ReductionError("Not a record constructor".to_string()), }; + let arity = members_from_table.len(); let mut args: Vec<(Rc, Expr)> = fields.iter() @@ -243,7 +233,7 @@ impl<'a> Reducer<'a> { let args = args.into_iter().map(|(_, expr)| expr).collect(); //TODO make sure this sorting actually works - let f = box Expr::Constructor { type_name, name: name.clone(), tag: *index, arity, }; + let f = box Expr::Constructor { type_name, name: symbol.local_name.clone(), tag: *index, arity, }; Expr::Call { f, args } } @@ -387,8 +377,7 @@ fn handle_symbol(symbol: Option<&Symbol>, inner_patterns: &Vec, symbol_ }); let bound_vars = inner_patterns.iter().map(|p| match p { VarOrName(qualified_name) => { - let fqsn = symbol_table.get_fqsn_from_id(&qualified_name.id); - let symbol_exists = fqsn.and_then(|fqsn| symbol_table.lookup_by_fqsn(&fqsn)).is_some(); + let symbol_exists = symbol_table.lookup_symbol(&qualified_name.id).is_some(); if symbol_exists { None } else { @@ -448,12 +437,9 @@ impl Pattern { use self::Pattern::*; match self { TupleStruct(QualifiedName{ components, id }, inner_patterns) => { - let fqsn = symbol_table.get_fqsn_from_id(id); - match fqsn.and_then(|fqsn| symbol_table.lookup_by_fqsn(&fqsn)) { + match symbol_table.lookup_symbol(id) { Some(symbol) => handle_symbol(Some(symbol), inner_patterns, symbol_table), - None => { - panic!("Symbol {:?} not found", components); - } + None => panic!("Symbol {:?} not found", components) } }, TuplePattern(inner_patterns) => handle_symbol(None, inner_patterns, symbol_table), @@ -463,12 +449,12 @@ impl Pattern { Ignored => Subpattern { tag: None, subpatterns: vec![], guard: None, bound_vars: vec![] }, Literal(lit) => lit.to_subpattern(symbol_table), VarOrName(QualifiedName { components, id }) => { - // if fqsn is Some, treat this as a symbol pattern. If it's None, treat it + // if symbol is Some, treat this as a symbol pattern. If it's None, treat it // as a variable. - let fqsn = symbol_table.get_fqsn_from_id(id); - match fqsn.as_ref().and_then(|fqsn| symbol_table.lookup_by_fqsn(fqsn)) { + match symbol_table.lookup_symbol(id) { Some(symbol) => handle_symbol(Some(symbol), &vec![], symbol_table), None => { + println!("Components: {:?}", components); let name = if components.len() == 1 { components[0].clone() } else { diff --git a/schala-lang/language/src/schala.rs b/schala-lang/language/src/schala.rs index 2ebc441..8afc497 100644 --- a/schala-lang/language/src/schala.rs +++ b/schala-lang/language/src/schala.rs @@ -20,7 +20,6 @@ pub struct Schala { state: eval::State<'static>, /// Keeps track of symbols and scopes symbol_table: SymbolTableHandle, - resolver: crate::scope_resolution::ScopeResolver<'static>, /// Contains information for type-checking type_context: typechecking::TypeContext<'static>, /// Schala Parser @@ -45,7 +44,6 @@ impl Schala { Schala { source_reference: SourceReference::new(), symbol_table: symbols.clone(), - resolver: crate::scope_resolution::ScopeResolver::new(symbols.clone()), state: eval::State::new(), type_context: typechecking::TypeContext::new(), active_parser: parsing::Parser::new() @@ -78,18 +76,13 @@ impl Schala { //2nd stage - parsing self.active_parser.add_new_tokens(tokens); - let mut ast = self.active_parser.parse() + let ast = self.active_parser.parse() .map_err(|err| SchalaError::from_parse_error(err, &self.source_reference))?; // Symbol table self.symbol_table.borrow_mut().add_top_level_symbols(&ast) .map_err(|err| SchalaError::from_string(err, Stage::Symbols))?; - // Scope resolution - requires mutating AST - self.resolver.resolve(&mut ast) - .map_err(|err| SchalaError::from_string(err, Stage::ScopeResolution))?; - - //WIP - new symbol table self.symbol_table.borrow_mut().process_ast(&ast) .map_err(|err| SchalaError::from_string(err, Stage::Symbols))?; diff --git a/schala-lang/language/src/symbol_table/mod.rs b/schala-lang/language/src/symbol_table/mod.rs index 2c07818..9568d7b 100644 --- a/schala-lang/language/src/symbol_table/mod.rs +++ b/schala-lang/language/src/symbol_table/mod.rs @@ -9,32 +9,18 @@ use crate::ast; use crate::ast::{ItemId, TypeBody, Variant, TypeSingletonName, Signature, Declaration, Statement, StatementKind, ModuleSpecifier}; use crate::typechecking::TypeName; - -#[allow(unused_macros)] -macro_rules! fqsn { - ( $( $name:expr ; $kind:tt),* ) => { - { - let mut vec = vec![]; - $( - vec.push(crate::symbol_table::ScopeSegment::new(std::rc::Rc::new($name.to_string()))); - )* - FullyQualifiedSymbolName(vec) - } - }; -} - +mod resolver; mod tables; use tables::DeclLocations; mod symbol_trie; use symbol_trie::SymbolTrie; mod test; - - /// Fully-qualified symbol name #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] -struct FQSN { - scopes: Vec, +pub struct FQSN { + //TODO FQSN's need to be cheaply cloneable + scopes: Vec, //TODO rename to ScopeSegment } impl FQSN { @@ -58,7 +44,6 @@ impl FQSN { /// One segment within a scope. #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] enum Scope { - Top, Name(String) } @@ -141,12 +126,21 @@ impl ScopeSegment { //cf. p. 150 or so of Language Implementation Patterns pub struct SymbolTable { - decl_locations: DeclLocations, + decl_locations: DeclLocations, //TODO delete this symbol_path_to_symbol: HashMap, - id_to_fqsn: HashMap, symbol_trie: SymbolTrie, + + /// These tables are responsible for preventing duplicate names. fq_names: NameTable, //Note that presence of two tables implies that a type and other binding with the same name can co-exist types: NameTable, + + /// A map of the `ItemId`s of instances of use of names to their fully-canonicalized FQSN form. + id_to_fqsn: HashMap, + + /// A map of the FQSN of an AST definition to a Symbol data structure, which contains + /// some basic information about what that symbol is and (ideally) references to other tables + /// (e.g. typechecking tables) with more information about that symbol. + fqsn_to_symbol: HashMap, } impl SymbolTable { @@ -154,44 +148,35 @@ impl SymbolTable { SymbolTable { decl_locations: DeclLocations::new(), symbol_path_to_symbol: HashMap::new(), - id_to_fqsn: HashMap::new(), symbol_trie: SymbolTrie::new(), + fq_names: NameTable::new(), types: NameTable::new(), + id_to_fqsn: HashMap::new(), + fqsn_to_symbol: HashMap::new(), } } - pub fn map_id_to_fqsn(&mut self, id: &ItemId, fqsn: FullyQualifiedSymbolName) { - self.id_to_fqsn.insert(id.clone(), fqsn); - } - - pub fn get_fqsn_from_id(&self, id: &ItemId) -> Option { - self.id_to_fqsn.get(&id).cloned() + pub fn lookup_symbol(&self, id: &ItemId) -> Option<&Symbol> { + let fqsn = self.id_to_fqsn.get(id); + fqsn.and_then(|fqsn| self.fqsn_to_symbol.get(fqsn)) } fn add_new_symbol(&mut self, local_name: &Rc, scope_path: &Vec, spec: SymbolSpec) { let mut vec: Vec = scope_path.clone(); vec.push(ScopeSegment { name: local_name.clone() }); let fully_qualified_name = FullyQualifiedSymbolName(vec); - let symbol = Symbol { local_name: local_name.clone(), fully_qualified_name: fully_qualified_name.clone(), spec }; - self.symbol_trie.insert(&fully_qualified_name); + let symbol = Symbol { local_name: local_name.clone(), /*fully_qualified_name: fully_qualified_name.clone(),*/ spec }; + //self.symbol_trie.insert(&fully_qualified_name); self.symbol_path_to_symbol.insert(fully_qualified_name, symbol); } - - pub fn lookup_by_fqsn(&self, fully_qualified_path: &FullyQualifiedSymbolName) -> Option<&Symbol> { - self.symbol_path_to_symbol.get(fully_qualified_path) - } - - pub fn lookup_children_of_fqsn(&self, path: &FullyQualifiedSymbolName) -> Vec { - self.symbol_trie.get_children(path) - } } #[allow(dead_code)] #[derive(Debug)] pub struct Symbol { pub local_name: Rc, - fully_qualified_name: FullyQualifiedSymbolName, + //fully_qualified_name: FullyQualifiedSymbolName, pub spec: SymbolSpec, } @@ -206,8 +191,8 @@ pub enum SymbolSpec { Func(Vec), DataConstructor { index: usize, - type_name: TypeName, - type_args: Vec>, + type_name: TypeName, //TODO this eventually needs to be some kind of ID + type_args: Vec>, //TODO this should be a lookup table into type information, it's not the concern of the symbol table }, RecordConstructor { index: usize, @@ -249,8 +234,11 @@ impl SymbolTable { Ok(()) } - //TODO does the same thing scope resolution... but maybe I don't need that + /// Walks the AST, matching the ID of an identifier used in some expression to + /// the corresponding Symbol. fn resolve_symbol_ids(&mut self, ast: &ast::AST) -> Result<(), String> { + let mut resolver = resolver::Resolver::new(self); + resolver.resolve(ast)?; Ok(()) } @@ -259,7 +247,7 @@ impl SymbolTable { /// checks for dupicate definitions (and returns errors if discovered), and sets /// up name tables that will be used by further parts of the compiler fn populate_name_tables(&mut self, ast: &ast::AST) -> Result<(), String> { - let mut scope_stack = vec![Scope::Top]; + let mut scope_stack = vec![]; self.add_from_scope(ast.statements.as_ref(), &mut scope_stack) .map_err(|err| format!("{:?}", err))?; Ok(()) @@ -268,21 +256,32 @@ impl SymbolTable { //TODO this should probably return a vector of duplicate name errors fn add_from_scope<'a>(&'a mut self, statements: &[Statement], scope_stack: &mut Vec) -> Result<(), DuplicateName> { for statement in statements { - let Statement { id: _, kind, location } = statement; + let Statement { id, kind, location } = statement; let location = *location; match kind { StatementKind::Declaration(Declaration::FuncSig(signature)) => { let fn_name: String = signature.name.as_str().to_owned(); let fq_function = FQSN::from_scope_stack(scope_stack.as_ref(), fn_name); self.fq_names.register(fq_function.clone(), NameSpec { location, kind: NameKind::Function })?; - self.types.register(fq_function, NameSpec { location, kind: TypeKind } )?; + self.types.register(fq_function.clone(), NameSpec { location, kind: TypeKind } )?; + + self.fqsn_to_symbol.insert(fq_function, Symbol { + local_name: signature.name.clone(), + spec: SymbolSpec::Func(vec![]), //TODO does this inner vec need to exist at all? + }); } StatementKind::Declaration(Declaration::FuncDecl(signature, body)) => { let fn_name: String = signature.name.as_str().to_owned(); let new_scope = Scope::Name(fn_name.clone()); let fq_function = FQSN::from_scope_stack(scope_stack.as_ref(), fn_name); self.fq_names.register(fq_function.clone(), NameSpec { location, kind: NameKind::Function })?; - self.types.register(fq_function, NameSpec { location, kind: TypeKind } )?; + self.types.register(fq_function.clone(), NameSpec { location, kind: TypeKind } )?; + + self.fqsn_to_symbol.insert(fq_function, Symbol { + local_name: signature.name.clone(), + spec: SymbolSpec::Func(vec![]), //TODO does this inner vec need to exist at all? + }); + scope_stack.push(new_scope); let output = self.add_from_scope(body.as_ref(), scope_stack); scope_stack.pop(); @@ -291,13 +290,17 @@ impl SymbolTable { StatementKind::Declaration(Declaration::TypeDecl { name, body, mutable }) => { let fq_type = FQSN::from_scope_stack(scope_stack.as_ref(), name.name.as_ref().to_owned()); self.types.register(fq_type, NameSpec { location, kind: TypeKind } )?; - if let Err(errors) = self.add_type_members(name, body, mutable, location, scope_stack) { + if let Err(errors) = self.add_type_members(id, name, body, mutable, location, scope_stack) { return Err(errors[0].clone()); } }, StatementKind::Declaration(Declaration::Binding { name, .. }) => { let fq_binding = FQSN::from_scope_stack(scope_stack.as_ref(), name.as_str().to_owned()); - self.fq_names.register(fq_binding, NameSpec { location, kind: NameKind::Binding })?; + self.fq_names.register(fq_binding.clone(), NameSpec { location, kind: NameKind::Binding })?; + self.fqsn_to_symbol.insert(fq_binding, Symbol { + local_name: name.clone(), + spec: SymbolSpec::Binding, + }); } StatementKind::Module(ModuleSpecifier { name, contents }) => { let mod_name = name.as_str().to_owned(); @@ -315,33 +318,75 @@ impl SymbolTable { Ok(()) } - fn add_type_members(&mut self, type_name: &TypeSingletonName, type_body: &TypeBody, _mutable: &bool, location: Location, scope_stack: &mut Vec) -> Result<(), Vec> { + fn add_type_members(&mut self, id: &ItemId, type_name: &TypeSingletonName, type_body: &TypeBody, _mutable: &bool, location: Location, scope_stack: &mut Vec) -> Result<(), Vec> { let mut errors = vec![]; - let mut register = |fqsn: FQSN| { - let spec = NameSpec { location, kind: TypeKind }; - if let Err(err) = self.types.register(fqsn, spec) { + let mut register = |fqsn: FQSN, spec: SymbolSpec| { + let name_spec = NameSpec { location, kind: TypeKind }; + if let Err(err) = self.types.register(fqsn.clone(), name_spec) { errors.push(err); - } + } else { + let local_name = match spec { + SymbolSpec::DataConstructor { ref type_name, ..} | SymbolSpec::RecordConstructor { ref type_name, .. } => type_name.clone(), + _ => panic!("This should never happen"), + }; + let symbol = Symbol { local_name, spec }; + self.fqsn_to_symbol.insert(fqsn, symbol); + }; }; let TypeBody(variants) = type_body; let new_scope = Scope::Name(type_name.name.as_ref().to_owned()); scope_stack.push(new_scope); - for variant in variants { + for (index, variant) in variants.iter().enumerate() { match variant { - Variant::UnitStruct(name) | Variant::TupleStruct(name, _) => { + Variant::UnitStruct(name) => { let fq_name = FQSN::from_scope_stack(scope_stack.as_ref(), name.as_ref().to_owned()); - register(fq_name); + let spec = SymbolSpec::DataConstructor { + index, + type_name: name.clone(), + type_args: vec![], + }; + register(fq_name, spec); + }, + Variant::TupleStruct(name, items) => { + let fq_name = FQSN::from_scope_stack(scope_stack.as_ref(), name.as_ref().to_owned()); + let spec = SymbolSpec::DataConstructor { + index, + type_name: name.clone(), + type_args: items.iter().map(|_| Rc::new("DUMMY_TYPE_ID".to_string())).collect() + }; + register(fq_name, spec); }, Variant::Record { name, members } => { let fq_name = FQSN::from_scope_stack(scope_stack.as_ref(), name.as_ref().to_owned()); - register(fq_name.clone()); - for (field_name, _) in members { - let fq_field_name = fq_name.extend(field_name.as_str().to_owned()); - register(fq_field_name); + let spec = SymbolSpec::RecordConstructor { + index, + type_name: name.clone(), + members: members.iter() + .map(|(_, _)| (Rc::new("DUMMY_FIELD".to_string()), Rc::new("DUMMY_TYPE_ID".to_string()))).collect() + }; + register(fq_name, spec); + //TODO check for duplicates among struct member definitions + /* + + let mut duplicate_member_definitions = Vec::new(); + for (member_name, member_type) in defined_members { + match members.entry(member_name.clone()) { + Entry::Occupied(_) => duplicate_member_definitions.push(member_name.clone()), + Entry::Vacant(v) => { + v.insert(match member_type { + TypeIdentifier::Singleton(TypeSingletonName { name, ..}) => name.clone(), + TypeIdentifier::Tuple(_) => unimplemented!(), + }); + } + } } + if duplicate_member_definitions.len() != 0 { + return Err(format!("Duplicate member(s) in definition of type {}: {:?}", type_name, duplicate_member_definitions)); + } + */ } } } @@ -355,7 +400,6 @@ impl SymbolTable { } } - pub fn add_top_level_symbols(&mut self, ast: &ast::AST) -> Result<(), String> { let mut scope_name_stack = Vec::new(); self.add_symbols_from_scope(&ast.statements, &mut scope_name_stack) diff --git a/schala-lang/language/src/symbol_table/resolver.rs b/schala-lang/language/src/symbol_table/resolver.rs new file mode 100644 index 0000000..a4d0c47 --- /dev/null +++ b/schala-lang/language/src/symbol_table/resolver.rs @@ -0,0 +1,112 @@ +use std::rc::Rc; + +use crate::symbol_table::{SymbolTable, ScopeSegment, FullyQualifiedSymbolName, FQSN, Scope}; +use crate::ast::*; +use crate::util::ScopeStack; + +type FQSNPrefix = Vec; + +pub struct Resolver<'a> { + symbol_table: &'a mut super::SymbolTable, + name_scope_stack: ScopeStack<'a, Rc, FQSNPrefix>, +} + +impl<'a> Resolver<'a> { + pub fn new(symbol_table: &'a mut SymbolTable) -> Self { + let name_scope_stack: ScopeStack<'a, Rc, FQSNPrefix> = ScopeStack::new(None); + Self { symbol_table, name_scope_stack } + } + pub fn resolve(&mut self, ast: &AST) -> Result<(), String> { + walk_ast(self, ast); + Ok(()) + } + + fn lookup_name_in_scope(&self, sym_name: &QualifiedName) -> FQSN { + let QualifiedName { components, .. } = sym_name; + let first_component = &components[0]; + match self.name_scope_stack.lookup(first_component) { + None => { + FQSN { + scopes: components.iter() + .map(|name| Scope::Name(name.as_ref().to_owned())) + .collect() + } + }, + Some(fqsn_prefix) => { + let mut full_name = fqsn_prefix.clone(); + let rest_of_name: FQSNPrefix = components[1..].iter().map(|name| Scope::Name(name.as_ref().to_owned())).collect(); + full_name.extend_from_slice(&rest_of_name); + + FQSN { + scopes: full_name + } + } + } + } + + // This might be a variable or a pattern, depending on whether this symbol + // already exists in the table. + fn qualified_name_in_pattern(&mut self, qualified_name: &QualifiedName) { + let fqsn = self.lookup_name_in_scope(qualified_name); + if self.symbol_table.fqsn_to_symbol.get(&fqsn).is_some() { + self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn); //TODO maybe set this to an explicit value if none? + } + } +} + +impl<'a> ASTVisitor for Resolver<'a> { + //TODO need to un-insert these - maybe need to rethink visitor + fn import(&mut self, import_spec: &ImportSpecifier) { + let ImportSpecifier { ref path_components, ref imported_names, .. } = &import_spec; + match imported_names { + ImportedNames::All => { + let prefix = FQSN { + scopes: path_components.iter().map(|c| Scope::Name(c.as_ref().to_owned())).collect() + }; + let members = self.symbol_table.symbol_trie.get_children(&prefix); + for member in members.into_iter() { + let local_name = match member.scopes.last().unwrap() { + Scope::Name(n) => Rc::new(n.clone()), + _ => panic!("LOL bad"), + }; + self.name_scope_stack.insert(local_name.clone(), member.scopes); + } + }, + ImportedNames::LastOfPath => { + let name = path_components.last().unwrap(); //TODO handle better + let fqsn_prefix = path_components.iter() + .map(|c| Scope::Name(c.as_ref().to_owned())) + .collect(); + self.name_scope_stack.insert(name.clone(), fqsn_prefix); + } + ImportedNames::List(ref names) => { + let fqsn_prefix: FQSNPrefix = path_components.iter() + .map(|c| Scope::Name(c.as_ref().to_owned())) + .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); + self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn); + } + + fn named_struct(&mut self, qualified_name: &QualifiedName, _fields: &Vec<(Rc, Expression)>) { + let fqsn = self.lookup_name_in_scope(&qualified_name); + self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn); + } + + fn pattern(&mut self, pat: &Pattern) { + use Pattern::*; + match pat { + //TODO I think not handling TuplePattern is an oversight + TuplePattern(_) => (), + Literal(_) | Ignored => (), + TupleStruct(name, _) | Record(name, _) | VarOrName(name) => self.qualified_name_in_pattern(name), + }; + } +} diff --git a/schala-lang/language/src/symbol_table/symbol_trie.rs b/schala-lang/language/src/symbol_table/symbol_trie.rs index 4e7176a..e387c02 100644 --- a/schala-lang/language/src/symbol_table/symbol_trie.rs +++ b/schala-lang/language/src/symbol_table/symbol_trie.rs @@ -1,18 +1,19 @@ use radix_trie::{Trie, TrieCommon, TrieKey}; -use super::FullyQualifiedSymbolName; +use super::{Scope, FQSN}; use std::hash::{Hasher, Hash}; use std::collections::hash_map::DefaultHasher; #[derive(Debug)] -pub struct SymbolTrie(Trie); +pub struct SymbolTrie(Trie); -impl TrieKey for FullyQualifiedSymbolName { +impl TrieKey for FQSN { fn encode_bytes(&self) -> Vec { let mut hasher = DefaultHasher::new(); let mut output = vec![]; - let FullyQualifiedSymbolName(scopes) = self; - for segment in scopes.iter() { - segment.name.as_bytes().hash(&mut hasher); + for segment in self.scopes.iter() { + if let Scope::Name(s) = segment { + s.as_bytes().hash(&mut hasher); + } output.extend_from_slice(&hasher.finish().to_be_bytes()); } output @@ -24,28 +25,44 @@ impl SymbolTrie { SymbolTrie(Trie::new()) } - pub fn insert(&mut self, fqsn: &FullyQualifiedSymbolName) { + pub fn insert(&mut self, fqsn: &FQSN) { self.0.insert(fqsn.clone(), ()); } - pub fn get_children(&self, fqsn: &FullyQualifiedSymbolName) -> Vec { + pub fn get_children(&self, fqsn: &FQSN) -> Vec { let subtrie = match self.0.subtrie(fqsn) { Some(s) => s, None => return vec![] }; - let output: Vec = subtrie.keys().filter(|cur_key| **cur_key != *fqsn).map(|fqsn| fqsn.clone()).collect(); + let output: Vec = subtrie.keys().filter(|cur_key| **cur_key != *fqsn).map(|fqsn| fqsn.clone()).collect(); output } } +#[cfg(test)] +mod test { + use super::*; + use crate::symbol_table::{Scope, FQSN}; + + fn make_fqsn(strs: &[&str]) -> FQSN { + let mut scopes = vec![]; + for s in strs { + scopes.push(Scope::Name(s.to_string())); + } + FQSN { + scopes + } + } + #[test] -fn test_trie_insertion() { - let mut trie = SymbolTrie::new(); + fn test_trie_insertion() { + let mut trie = SymbolTrie::new(); - trie.insert(&fqsn!("unrelated"; ty, "thing"; tr)); - trie.insert(&fqsn!("outer"; ty, "inner"; tr)); - trie.insert(&fqsn!("outer"; ty, "inner"; ty, "still_inner"; tr)); + trie.insert(&make_fqsn(&["unrelated","thing"])); + trie.insert(&make_fqsn(&["outer","inner"])); + trie.insert(&make_fqsn(&["outer","inner", "still_inner"])); - let children = trie.get_children(&fqsn!("outer"; ty, "inner"; tr)); - assert_eq!(children.len(), 1); + let children = trie.get_children(&make_fqsn(&["outer", "inner"])); + assert_eq!(children.len(), 1); + } } diff --git a/schala-lang/language/src/symbol_table/test.rs b/schala-lang/language/src/symbol_table/test.rs index b8979f0..62e73a0 100644 --- a/schala-lang/language/src/symbol_table/test.rs +++ b/schala-lang/language/src/symbol_table/test.rs @@ -11,7 +11,6 @@ fn add_symbols(src: &str) -> (SymbolTable, Result<(), String>) { fn make_fqsn(strs: &[&str]) -> FQSN { let mut scopes = vec![]; - scopes.push(Scope::Top); for s in strs { scopes.push(Scope::Name(s.to_string())); }