diff --git a/schala-lang/language/src/symbol_table/mod.rs b/schala-lang/language/src/symbol_table/mod.rs index 608cfa1..b00e15c 100644 --- a/schala-lang/language/src/symbol_table/mod.rs +++ b/schala-lang/language/src/symbol_table/mod.rs @@ -1,10 +1,13 @@ -use std::collections::{HashMap, hash_map::Entry}; -use std::rc::Rc; +use std::collections::{hash_map::Entry, HashMap}; use std::fmt; +use std::rc::Rc; -use crate::tokenizing::Location; use crate::ast; -use crate::ast::{ItemId, TypeBody, Variant, TypeSingletonName, Declaration, Statement, StatementKind, ModuleSpecifier}; +use crate::ast::{ + Declaration, ItemId, ModuleSpecifier, Statement, StatementKind, TypeBody, TypeSingletonName, + Variant, +}; +use crate::tokenizing::Location; use crate::typechecking::TypeName; mod resolver; @@ -15,67 +18,63 @@ mod test; /// Fully-qualified symbol name #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub struct Fqsn { - //TODO Fqsn's need to be cheaply cloneable - scopes: Vec, //TODO rename to ScopeSegment + //TODO Fqsn's need to be cheaply cloneable + scopes: Vec, //TODO rename to ScopeSegment } impl Fqsn { - fn from_scope_stack(scopes: &[Scope], new_name: Rc) -> Self { - let mut v = Vec::new(); - for s in scopes { - v.push(s.clone()); + fn from_scope_stack(scopes: &[Scope], new_name: Rc) -> Self { + let mut v = Vec::new(); + for s in scopes { + v.push(s.clone()); + } + v.push(Scope::Name(new_name)); + Fqsn { scopes: v } } - v.push(Scope::Name(new_name)); - Fqsn { scopes: v } - } - #[cfg(test)] - fn from_strs(strs: &[&str]) -> Fqsn { - let mut scopes = vec![]; - for s in strs { - scopes.push(Scope::Name(Rc::new(s.to_string()))); + #[cfg(test)] + fn from_strs(strs: &[&str]) -> Fqsn { + let mut scopes = vec![]; + for s in strs { + scopes.push(Scope::Name(Rc::new(s.to_string()))); + } + Fqsn { scopes } } - Fqsn { - scopes - } - } } - - //TODO eventually this should use ItemId's to avoid String-cloning /// One segment within a scope. #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] enum Scope { - Name(Rc) + Name(Rc), } #[allow(dead_code)] #[derive(Debug, Clone)] pub enum SymbolError { - DuplicateName { - prev_name: Fqsn, - location: Location - }, - DuplicateRecord { - type_name: Fqsn, - location: Location, - member: String, - } + DuplicateName { + prev_name: Fqsn, + location: Location, + }, + DuplicateRecord { + type_name: Fqsn, + location: Location, + member: String, + }, } #[allow(dead_code)] #[derive(Debug)] struct NameSpec { - location: Location, - kind: K + location: Location, + kind: K, } #[derive(Debug)] enum NameKind { - Module, - Function, - Binding, + Module, + Function, + Binding, } #[derive(Debug)] @@ -83,300 +82,402 @@ struct TypeKind; /// Keeps track of what names were used in a given namespace. struct NameTable { - table: HashMap> + table: HashMap>, } impl NameTable { - fn new() -> Self { - Self { table: HashMap::new() } - } - - fn register(&mut self, name: Fqsn, spec: NameSpec) -> Result<(), SymbolError> { - match self.table.entry(name.clone()) { - Entry::Occupied(o) => { - Err(SymbolError::DuplicateName { prev_name: name, location: o.get().location }) - }, - Entry::Vacant(v) => { - v.insert(spec); - Ok(()) - } + fn new() -> Self { + Self { + table: HashMap::new(), + } + } + + fn register(&mut self, name: Fqsn, spec: NameSpec) -> Result<(), SymbolError> { + match self.table.entry(name.clone()) { + Entry::Occupied(o) => Err(SymbolError::DuplicateName { + prev_name: name, + location: o.get().location, + }), + Entry::Vacant(v) => { + v.insert(spec); + Ok(()) + } + } } - } } //cf. p. 150 or so of Language Implementation Patterns pub struct SymbolTable { - /// Used for import resolution. - symbol_trie: SymbolTrie, + /// Used for import resolution. + 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, + /// 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. - /// Updated by the item id resolver. - id_to_fqsn: HashMap, + /// A map of the `ItemId`s of instances of use of names to their fully-canonicalized Fqsn form. + /// Updated by the item id resolver. + 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, + /// 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 { - pub fn new() -> SymbolTable { - SymbolTable { - symbol_trie: SymbolTrie::new(), - fq_names: NameTable::new(), - types: NameTable::new(), - id_to_fqsn: HashMap::new(), - fqsn_to_symbol: HashMap::new(), + pub fn new() -> SymbolTable { + SymbolTable { + symbol_trie: SymbolTrie::new(), + fq_names: NameTable::new(), + types: NameTable::new(), + id_to_fqsn: HashMap::new(), + fqsn_to_symbol: HashMap::new(), + } } - } - /// The main entry point into the symbol table. This will traverse the AST in several - /// different ways and populate subtables with information that will be used further in the - /// compilation process. - pub fn process_ast(&mut self, ast: &ast::AST) -> Result<(), Vec> { - - let errs = self.populate_name_tables(ast); - if !errs.is_empty() { - return Err(errs); + /// The main entry point into the symbol table. This will traverse the AST in several + /// different ways and populate subtables with information that will be used further in the + /// compilation process. + pub fn process_ast(&mut self, ast: &ast::AST) -> Result<(), Vec> { + let errs = self.populate_name_tables(ast); + if !errs.is_empty() { + return Err(errs); + } + self.resolve_symbol_ids(ast); + Ok(()) } - self.resolve_symbol_ids(ast); - Ok(()) - } - 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)) - } + 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)) + } } #[allow(dead_code)] #[derive(Debug)] pub struct Symbol { - pub local_name: Rc, - //fully_qualified_name: FullyQualifiedSymbolName, - pub spec: SymbolSpec, + pub local_name: Rc, + //fully_qualified_name: FullyQualifiedSymbolName, + pub spec: SymbolSpec, } impl fmt::Display for Symbol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "", self.local_name, self.spec) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "", self.local_name, self.spec) + } } #[derive(Debug)] pub enum SymbolSpec { - Func(Vec), - DataConstructor { - index: usize, - arity: usize, - type_name: TypeName, //TODO this eventually needs to be some kind of ID - }, - RecordConstructor { - index: usize, - members: HashMap, TypeName>, - type_name: TypeName, - }, - Binding, + Func(Vec), + DataConstructor { + index: usize, + arity: usize, + type_name: TypeName, //TODO this eventually needs to be some kind of ID + }, + RecordConstructor { + index: usize, + members: HashMap, TypeName>, + type_name: TypeName, + }, + Binding, } impl fmt::Display for SymbolSpec { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::SymbolSpec::*; - match self { - Func(type_names) => write!(f, "Func({:?})", type_names), - DataConstructor { index, type_name, arity } => write!(f, "DataConstructor(idx: {}, arity: {}, type: {})", index, arity, type_name), - RecordConstructor { type_name, index, ..} => write!(f, "RecordConstructor(idx: {})( -> {})", index, type_name), - Binding => write!(f, "Binding"), + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::SymbolSpec::*; + match self { + Func(type_names) => write!(f, "Func({:?})", type_names), + DataConstructor { + index, + type_name, + arity, + } => write!( + f, + "DataConstructor(idx: {}, arity: {}, type: {})", + index, arity, type_name + ), + RecordConstructor { + type_name, index, .. + } => write!( + f, + "RecordConstructor(idx: {})( -> {})", + index, type_name + ), + Binding => write!(f, "Binding"), + } } - } } - impl SymbolTable { - /* note: this adds names for *forward reference* but doesn't actually create any types. solve that problem - * later */ + /* note: this adds names for *forward reference* but doesn't actually create any types. solve that problem + * later */ - /// Register a new mapping of a fully-qualified symbol name (e.g. `Option::Some`) - /// to a Symbol, a descriptor of what that name refers to. - fn add_symbol(&mut self, fqsn: Fqsn, symbol: Symbol) { - self.symbol_trie.insert(&fqsn); - self.fqsn_to_symbol.insert(fqsn, symbol); - } - - /// 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) { - let mut resolver = resolver::Resolver::new(self); - resolver.resolve(ast); - } - - /// This function traverses the AST and adds symbol table entries for - /// constants, functions, types, and modules defined within. This simultaneously - /// 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) -> Vec { - let mut scope_stack = vec![]; - self.add_from_scope(ast.statements.as_ref(), &mut scope_stack) - } - - fn add_from_scope<'a>(&'a mut self, statements: &[Statement], scope_stack: &mut Vec) -> Vec { - let mut errors = vec![]; - - for statement in statements { - let Statement { id: _, kind, location } = statement; //TODO I'm not sure if I need to do anything with this ID - let location = *location; - if let Err(err) = self.add_single_statement(kind, location, scope_stack) { - errors.push(err); - } else { // If there's an error with a name, don't recurse into subscopes of that name - let recursive_errs = match kind { - StatementKind::Declaration(Declaration::FuncDecl(signature, body)) => { - let new_scope = Scope::Name(signature.name.clone()); - scope_stack.push(new_scope); - let output = self.add_from_scope(body.as_ref(), scope_stack); - scope_stack.pop(); - output - } - StatementKind::Module(ModuleSpecifier { name, contents }) => { - let new_scope = Scope::Name(name.clone()); - scope_stack.push(new_scope); - let output = self.add_from_scope(contents.as_ref(), scope_stack); - scope_stack.pop(); - output - } - StatementKind::Declaration(Declaration::TypeDecl { name, body, mutable }) => { - self.add_type_members(name, body, mutable, location, scope_stack) - } - _ => vec![] - }; - errors.extend(recursive_errs.into_iter()); - } + /// Register a new mapping of a fully-qualified symbol name (e.g. `Option::Some`) + /// to a Symbol, a descriptor of what that name refers to. + fn add_symbol(&mut self, fqsn: Fqsn, symbol: Symbol) { + self.symbol_trie.insert(&fqsn); + self.fqsn_to_symbol.insert(fqsn, symbol); } - errors - } + /// 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) { + let mut resolver = resolver::Resolver::new(self); + resolver.resolve(ast); + } - fn add_single_statement(&mut self, kind: &StatementKind, location: Location, scope_stack: &[Scope]) -> Result<(), SymbolError> { - match kind { - StatementKind::Declaration(Declaration::FuncSig(signature)) => { - let fq_function = Fqsn::from_scope_stack(scope_stack, signature.name.clone()); - self.fq_names.register(fq_function.clone(), NameSpec { location, kind: NameKind::Function })?; - self.types.register(fq_function.clone(), NameSpec { location, kind: TypeKind } )?; + /// This function traverses the AST and adds symbol table entries for + /// constants, functions, types, and modules defined within. This simultaneously + /// 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) -> Vec { + let mut scope_stack = vec![]; + self.add_from_scope(ast.statements.as_ref(), &mut scope_stack) + } - self.add_symbol(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, ..)) => { - let fn_name = &signature.name; - let fq_function = Fqsn::from_scope_stack(scope_stack, fn_name.clone()); - self.fq_names.register(fq_function.clone(), NameSpec { location, kind: NameKind::Function })?; - self.types.register(fq_function.clone(), NameSpec { location, kind: TypeKind } )?; + fn add_from_scope<'a>( + &'a mut self, + statements: &[Statement], + scope_stack: &mut Vec, + ) -> Vec { + let mut errors = vec![]; - self.add_symbol(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::TypeDecl { name, .. }) => { - let fq_type = Fqsn::from_scope_stack(scope_stack, name.name.clone()); - self.types.register(fq_type, NameSpec { location, kind: TypeKind } )?; - }, - StatementKind::Declaration(Declaration::Binding { name, .. }) => { - let fq_binding = Fqsn::from_scope_stack(scope_stack, name.clone()); - self.fq_names.register(fq_binding.clone(), NameSpec { location, kind: NameKind::Binding })?; - self.add_symbol(fq_binding, Symbol { - local_name: name.clone(), - spec: SymbolSpec::Binding, - }); - } - StatementKind::Module(ModuleSpecifier { name, .. }) => { - let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone()); - self.fq_names.register(fq_module, NameSpec { location, kind: NameKind::Module })?; - }, - _ => (), - } - Ok(()) - } - - fn add_type_members(&mut self, type_name: &TypeSingletonName, type_body: &TypeBody, _mutable: &bool, location: Location, scope_stack: &mut Vec) -> Vec { - let mut member_errors = vec![]; - let mut errors = vec![]; - - 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.add_symbol(fqsn, symbol); - }; - }; - - let TypeBody(variants) = type_body; - let new_scope = Scope::Name(type_name.name.clone()); - scope_stack.push(new_scope); - - for (index, variant) in variants.iter().enumerate() { - match variant { - Variant::UnitStruct(name) => { - let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone()); - let spec = SymbolSpec::DataConstructor { - index, - arity: 0, - type_name: name.clone(), - }; - register(fq_name, spec); - }, - Variant::TupleStruct(name, items) => { - let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone()); - let spec = SymbolSpec::DataConstructor { - index, - arity: items.len(), - type_name: name.clone(), - }; - register(fq_name, spec); - }, - Variant::Record { name, members } => { - let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone()); - - let mut seen_members = HashMap::new(); - for (member_name, _) in members.iter() { - match seen_members.entry(member_name.as_ref()) { - Entry::Occupied(o) => { - let location = *o.get(); - member_errors.push(SymbolError::DuplicateRecord { - type_name: fq_name.clone(), - location, - member: member_name.as_ref().to_string(), - }); - }, - //TODO eventually this should track meaningful locations - Entry::Vacant(v) => { v.insert(Location::default()); } + for statement in statements { + let Statement { + id: _, + kind, + location, + } = statement; //TODO I'm not sure if I need to do anything with this ID + let location = *location; + if let Err(err) = self.add_single_statement(kind, location, scope_stack) { + errors.push(err); + } else { + // If there's an error with a name, don't recurse into subscopes of that name + let recursive_errs = match kind { + StatementKind::Declaration(Declaration::FuncDecl(signature, body)) => { + let new_scope = Scope::Name(signature.name.clone()); + scope_stack.push(new_scope); + let output = self.add_from_scope(body.as_ref(), scope_stack); + scope_stack.pop(); + output + } + StatementKind::Module(ModuleSpecifier { name, contents }) => { + let new_scope = Scope::Name(name.clone()); + scope_stack.push(new_scope); + let output = self.add_from_scope(contents.as_ref(), scope_stack); + scope_stack.pop(); + output + } + StatementKind::Declaration(Declaration::TypeDecl { + name, + body, + mutable, + }) => self.add_type_members(name, body, mutable, location, scope_stack), + _ => vec![], + }; + errors.extend(recursive_errs.into_iter()); } - } - - 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); } - } + + errors } - scope_stack.pop(); - errors.extend(member_errors.into_iter()); - errors - } + fn add_single_statement( + &mut self, + kind: &StatementKind, + location: Location, + scope_stack: &[Scope], + ) -> Result<(), SymbolError> { + match kind { + StatementKind::Declaration(Declaration::FuncSig(signature)) => { + let fq_function = Fqsn::from_scope_stack(scope_stack, signature.name.clone()); + self.fq_names.register( + fq_function.clone(), + NameSpec { + location, + kind: NameKind::Function, + }, + )?; + self.types.register( + fq_function.clone(), + NameSpec { + location, + kind: TypeKind, + }, + )?; + + self.add_symbol( + 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, ..)) => { + let fn_name = &signature.name; + let fq_function = Fqsn::from_scope_stack(scope_stack, fn_name.clone()); + self.fq_names.register( + fq_function.clone(), + NameSpec { + location, + kind: NameKind::Function, + }, + )?; + self.types.register( + fq_function.clone(), + NameSpec { + location, + kind: TypeKind, + }, + )?; + + self.add_symbol( + 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::TypeDecl { name, .. }) => { + let fq_type = Fqsn::from_scope_stack(scope_stack, name.name.clone()); + self.types.register( + fq_type, + NameSpec { + location, + kind: TypeKind, + }, + )?; + } + StatementKind::Declaration(Declaration::Binding { name, .. }) => { + let fq_binding = Fqsn::from_scope_stack(scope_stack, name.clone()); + self.fq_names.register( + fq_binding.clone(), + NameSpec { + location, + kind: NameKind::Binding, + }, + )?; + self.add_symbol( + fq_binding, + Symbol { + local_name: name.clone(), + spec: SymbolSpec::Binding, + }, + ); + } + StatementKind::Module(ModuleSpecifier { name, .. }) => { + let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone()); + self.fq_names.register( + fq_module, + NameSpec { + location, + kind: NameKind::Module, + }, + )?; + } + _ => (), + } + Ok(()) + } + + fn add_type_members( + &mut self, + type_name: &TypeSingletonName, + type_body: &TypeBody, + _mutable: &bool, + location: Location, + scope_stack: &mut Vec, + ) -> Vec { + let mut member_errors = vec![]; + let mut errors = vec![]; + + 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.add_symbol(fqsn, symbol); + }; + }; + + let TypeBody(variants) = type_body; + let new_scope = Scope::Name(type_name.name.clone()); + scope_stack.push(new_scope); + + for (index, variant) in variants.iter().enumerate() { + match variant { + Variant::UnitStruct(name) => { + let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone()); + let spec = SymbolSpec::DataConstructor { + index, + arity: 0, + type_name: name.clone(), + }; + register(fq_name, spec); + } + Variant::TupleStruct(name, items) => { + let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone()); + let spec = SymbolSpec::DataConstructor { + index, + arity: items.len(), + type_name: name.clone(), + }; + register(fq_name, spec); + } + Variant::Record { name, members } => { + let fq_name = Fqsn::from_scope_stack(scope_stack.as_ref(), name.clone()); + + let mut seen_members = HashMap::new(); + for (member_name, _) in members.iter() { + match seen_members.entry(member_name.as_ref()) { + Entry::Occupied(o) => { + let location = *o.get(); + member_errors.push(SymbolError::DuplicateRecord { + type_name: fq_name.clone(), + location, + member: member_name.as_ref().to_string(), + }); + } + //TODO eventually this should track meaningful locations + Entry::Vacant(v) => { + v.insert(Location::default()); + } + } + } + + 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); + } + } + } + + scope_stack.pop(); + errors.extend(member_errors.into_iter()); + errors + } } diff --git a/schala-lang/language/src/symbol_table/resolver.rs b/schala-lang/language/src/symbol_table/resolver.rs index 9727685..82f8e63 100644 --- a/schala-lang/language/src/symbol_table/resolver.rs +++ b/schala-lang/language/src/symbol_table/resolver.rs @@ -1,109 +1,134 @@ use std::rc::Rc; -use crate::symbol_table::{SymbolTable, Fqsn, Scope}; use crate::ast::*; +use crate::symbol_table::{Fqsn, Scope, SymbolTable}; use crate::util::ScopeStack; type FqsnPrefix = Vec; pub struct Resolver<'a> { - symbol_table: &'a mut super::SymbolTable, - name_scope_stack: ScopeStack<'a, Rc, FqsnPrefix>, + 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) { - walk_ast(self, ast); - } - - 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.clone())) - .collect() + 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, } - }, - Some(fqsn_prefix) => { - let mut full_name = fqsn_prefix.clone(); - let rest_of_name: FqsnPrefix = components[1..].iter().map(|name| Scope::Name(name.clone())).collect(); - full_name.extend_from_slice(&rest_of_name); + } + pub fn resolve(&mut self, ast: &AST) { + walk_ast(self, ast); + } - Fqsn { - scopes: full_name + 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.clone())) + .collect(), + }, + Some(fqsn_prefix) => { + let mut full_name = fqsn_prefix.clone(); + let rest_of_name: FqsnPrefix = components[1..] + .iter() + .map(|name| Scope::Name(name.clone())) + .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? + // 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.clone())).collect() + //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.clone())) + .collect(), + }; + let members = self.symbol_table.symbol_trie.get_children(&prefix); + for member in members.into_iter() { + let Scope::Name(n) = member.scopes.last().unwrap(); + let local_name = n.clone(); + self.name_scope_stack.insert(local_name, member.scopes); + } + } + ImportedNames::LastOfPath => { + let name = path_components.last().unwrap(); //TODO handle better + let fqsn_prefix = path_components + .iter() + .map(|c| Scope::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| Scope::Name(c.clone())) + .collect(); + for name in names.iter() { + self.name_scope_stack + .insert(name.clone(), fqsn_prefix.clone()); + } + } }; - let members = self.symbol_table.symbol_trie.get_children(&prefix); - for member in members.into_iter() { - let Scope::Name(n) = member.scopes.last().unwrap(); - let local_name = n.clone(); - self.name_scope_stack.insert(local_name, member.scopes); - } - }, - ImportedNames::LastOfPath => { - let name = path_components.last().unwrap(); //TODO handle better - let fqsn_prefix = path_components.iter() - .map(|c| Scope::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| Scope::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 fqsn = self.lookup_name_in_scope(qualified_name); - self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn); - } + 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: &[ (Rc, Expression) ]) { - 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: &[(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), - }; - } + 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 98ef1da..013df06 100644 --- a/schala-lang/language/src/symbol_table/symbol_trie.rs +++ b/schala-lang/language/src/symbol_table/symbol_trie.rs @@ -1,61 +1,65 @@ +use super::{Fqsn, Scope}; use radix_trie::{Trie, TrieCommon, TrieKey}; -use super::{Scope, Fqsn}; -use std::hash::{Hasher, Hash}; use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; #[derive(Debug)] pub struct SymbolTrie(Trie); impl TrieKey for Fqsn { - fn encode_bytes(&self) -> Vec { - let mut hasher = DefaultHasher::new(); - let mut output = vec![]; - for segment in self.scopes.iter() { - let Scope::Name(s) = segment; - s.as_bytes().hash(&mut hasher); - output.extend_from_slice(&hasher.finish().to_be_bytes()); + fn encode_bytes(&self) -> Vec { + let mut hasher = DefaultHasher::new(); + let mut output = vec![]; + for segment in self.scopes.iter() { + let Scope::Name(s) = segment; + s.as_bytes().hash(&mut hasher); + output.extend_from_slice(&hasher.finish().to_be_bytes()); + } + output } - output - } } impl SymbolTrie { - pub fn new() -> SymbolTrie { - SymbolTrie(Trie::new()) - } + pub fn new() -> SymbolTrie { + SymbolTrie(Trie::new()) + } - pub fn insert(&mut self, fqsn: &Fqsn) { - self.0.insert(fqsn.clone(), ()); - } + pub fn insert(&mut self, fqsn: &Fqsn) { + self.0.insert(fqsn.clone(), ()); + } - 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).cloned().collect(); - output - } + 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) + .cloned() + .collect(); + output + } } #[cfg(test)] mod test { - use super::*; - use crate::symbol_table::Fqsn; + use super::*; + use crate::symbol_table::Fqsn; - fn make_fqsn(strs: &[&str]) -> Fqsn { - Fqsn::from_strs(strs) - } + fn make_fqsn(strs: &[&str]) -> Fqsn { + Fqsn::from_strs(strs) + } -#[test] - fn test_trie_insertion() { - let mut trie = SymbolTrie::new(); + #[test] + fn test_trie_insertion() { + let mut trie = SymbolTrie::new(); - trie.insert(&make_fqsn(&["unrelated","thing"])); - trie.insert(&make_fqsn(&["outer","inner"])); - trie.insert(&make_fqsn(&["outer","inner", "still_inner"])); + 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(&make_fqsn(&["outer", "inner"])); - 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 eb24d84..5a2c66f 100644 --- a/schala-lang/language/src/symbol_table/test.rs +++ b/schala-lang/language/src/symbol_table/test.rs @@ -1,76 +1,83 @@ #![cfg(test)] use super::*; -use assert_matches::assert_matches; use crate::util::quick_ast; +use assert_matches::assert_matches; fn add_symbols(src: &str) -> (SymbolTable, Result<(), Vec>) { - let ast = quick_ast(src); - let mut symbol_table = SymbolTable::new(); - let result = symbol_table.process_ast(&ast); - (symbol_table, result) + let ast = quick_ast(src); + let mut symbol_table = SymbolTable::new(); + let result = symbol_table.process_ast(&ast); + (symbol_table, result) } fn make_fqsn(strs: &[&str]) -> Fqsn { - Fqsn::from_strs(strs) + Fqsn::from_strs(strs) } - #[test] fn basic_symbol_table() { - let src = "let a = 10; fn b() { 20 }"; - let (symbols, _) = add_symbols(src); + let src = "let a = 10; fn b() { 20 }"; + let (symbols, _) = add_symbols(src); - fn make_fqsn(strs: &[&str]) -> Fqsn { - Fqsn::from_strs(strs) - } + fn make_fqsn(strs: &[&str]) -> Fqsn { + Fqsn::from_strs(strs) + } - symbols.fq_names.table.get(&make_fqsn(&["b"])).unwrap(); + symbols.fq_names.table.get(&make_fqsn(&["b"])).unwrap(); - let src = "type Option = Some(T) | None"; - let (symbols, _) = add_symbols(src); + let src = "type Option = Some(T) | None"; + let (symbols, _) = add_symbols(src); - symbols.types.table.get(&make_fqsn(&["Option"])).unwrap(); - symbols.types.table.get(&make_fqsn(&["Option", "Some"])).unwrap(); - symbols.types.table.get(&make_fqsn(&["Option", "None"])).unwrap(); + symbols.types.table.get(&make_fqsn(&["Option"])).unwrap(); + symbols + .types + .table + .get(&make_fqsn(&["Option", "Some"])) + .unwrap(); + symbols + .types + .table + .get(&make_fqsn(&["Option", "None"])) + .unwrap(); } #[test] fn no_function_definition_duplicates() { - let source = r#" + let source = r#" fn a() { 1 } fn b() { 2 } fn a() { 3 } "#; - let (_, output) = add_symbols(source); - let errs = output.unwrap_err(); - assert_matches!(&errs[..], [ - SymbolError::DuplicateName { prev_name, ..} - ] if prev_name == &Fqsn::from_strs(&["a"]) - ); + let (_, output) = add_symbols(source); + let errs = output.unwrap_err(); + assert_matches!(&errs[..], [ + SymbolError::DuplicateName { prev_name, ..} + ] if prev_name == &Fqsn::from_strs(&["a"]) + ); } #[test] fn no_variable_definition_duplicates() { - let source = r#" + let source = r#" let x = 9 let a = 20 let q = 39 let a = 30 let x = 34 "#; - let (_, output) = add_symbols(source); - let errs = output.unwrap_err(); + let (_, output) = add_symbols(source); + let errs = output.unwrap_err(); - assert_matches!(&errs[..], [ - SymbolError::DuplicateName { prev_name: pn1, ..}, - SymbolError::DuplicateName { prev_name: pn2, ..} - ] if pn1 == &Fqsn::from_strs(&["a"]) && pn2 == &Fqsn::from_strs(&["x"]) - ); + assert_matches!(&errs[..], [ + SymbolError::DuplicateName { prev_name: pn1, ..}, + SymbolError::DuplicateName { prev_name: pn2, ..} + ] if pn1 == &Fqsn::from_strs(&["a"]) && pn2 == &Fqsn::from_strs(&["x"]) + ); } #[test] fn no_variable_definition_duplicates_in_function() { - let source = r#" + let source = r#" fn a() { let a = 20 let b = 40 @@ -83,17 +90,17 @@ fn no_variable_definition_duplicates_in_function() { let x = 33 } "#; - let (_, output) = add_symbols(source); - let errs = output.unwrap_err(); - assert_matches!(&errs[..], [ - SymbolError::DuplicateName { prev_name: pn1, ..}, - ] if pn1 == &Fqsn::from_strs(&["q", "x"]) - ); + let (_, output) = add_symbols(source); + let errs = output.unwrap_err(); + assert_matches!(&errs[..], [ + SymbolError::DuplicateName { prev_name: pn1, ..}, + ] if pn1 == &Fqsn::from_strs(&["q", "x"]) + ); } #[test] fn dont_falsely_detect_duplicates() { - let source = r#" + let source = r#" let a = 20; fn some_func() { let a = 40; @@ -101,29 +108,41 @@ fn dont_falsely_detect_duplicates() { } let q = 39; "#; - let (symbols, _) = add_symbols(source); + let (symbols, _) = add_symbols(source); - assert!(symbols.fq_names.table.get(&make_fqsn(&["a"])).is_some()); - assert!(symbols.fq_names.table.get(&make_fqsn(&["some_func", "a"])).is_some()); + assert!(symbols.fq_names.table.get(&make_fqsn(&["a"])).is_some()); + assert!(symbols + .fq_names + .table + .get(&make_fqsn(&["some_func", "a"])) + .is_some()); } #[test] fn enclosing_scopes() { - let source = r#" + let source = r#" fn outer_func(x) { fn inner_func(arg) { arg } x + inner_func(x) }"#; - let (symbols, _) = add_symbols(source); - assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func"])).is_some()); - assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func", "inner_func"])).is_some()); + let (symbols, _) = add_symbols(source); + assert!(symbols + .fq_names + .table + .get(&make_fqsn(&["outer_func"])) + .is_some()); + assert!(symbols + .fq_names + .table + .get(&make_fqsn(&["outer_func", "inner_func"])) + .is_some()); } #[test] fn enclosing_scopes_2() { - let source = r#" + let source = r#" fn outer_func(x) { fn inner_func(arg) { arg @@ -136,16 +155,36 @@ fn second_inner_func() { inner_func(x) }"#; - let (symbols, _) = add_symbols(source); - assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func"])).is_some()); - assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func", "inner_func"])).is_some()); - assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func", "second_inner_func"])).is_some()); - assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func", "second_inner_func", "another_inner_func"])).is_some()); + let (symbols, _) = add_symbols(source); + assert!(symbols + .fq_names + .table + .get(&make_fqsn(&["outer_func"])) + .is_some()); + assert!(symbols + .fq_names + .table + .get(&make_fqsn(&["outer_func", "inner_func"])) + .is_some()); + assert!(symbols + .fq_names + .table + .get(&make_fqsn(&["outer_func", "second_inner_func"])) + .is_some()); + assert!(symbols + .fq_names + .table + .get(&make_fqsn(&[ + "outer_func", + "second_inner_func", + "another_inner_func" + ])) + .is_some()); } #[test] fn enclosing_scopes_3() { - let source = r#" + let source = r#" fn outer_func(x) { fn inner_func(arg) { arg @@ -160,13 +199,13 @@ fn second_inner_func() { inner_func(x) }"#; - let (_, output) = add_symbols(source); - let _err = output.unwrap_err(); + let (_, output) = add_symbols(source); + let _err = output.unwrap_err(); } #[test] fn modules() { - let source = r#" + let source = r#" module stuff { fn item() { } @@ -175,15 +214,19 @@ module stuff { fn item() "#; - let (symbols, _) = add_symbols(source); - symbols.fq_names.table.get(&make_fqsn(&["stuff"])).unwrap(); - symbols.fq_names.table.get(&make_fqsn(&["item"])).unwrap(); - symbols.fq_names.table.get(&make_fqsn(&["stuff", "item"])).unwrap(); + let (symbols, _) = add_symbols(source); + symbols.fq_names.table.get(&make_fqsn(&["stuff"])).unwrap(); + symbols.fq_names.table.get(&make_fqsn(&["item"])).unwrap(); + symbols + .fq_names + .table + .get(&make_fqsn(&["stuff", "item"])) + .unwrap(); } #[test] fn duplicate_modules() { - let source = r#" + let source = r#" module q { fn foo() { 4 } } @@ -197,37 +240,35 @@ fn duplicate_modules() { fn foo() { 256.1 } } "#; - let (_, output) = add_symbols(source); - let errs = output.unwrap_err(); - - assert_matches!(&errs[..], [ - SymbolError::DuplicateName { prev_name: pn1, ..}, - ] if pn1 == &Fqsn::from_strs(&["a"]) - ); + let (_, output) = add_symbols(source); + let errs = output.unwrap_err(); + assert_matches!(&errs[..], [ + SymbolError::DuplicateName { prev_name: pn1, ..}, + ] if pn1 == &Fqsn::from_strs(&["a"]) + ); } #[test] fn duplicate_struct_members() { - //TODO this is a parser error - /* - let source = r#" - type Tarak = Tarak { - loujet: i32, - mets: i32, - mets: i32, - } - "#; - */ + //TODO this is a parser error + /* + let source = r#" + type Tarak = Tarak { + loujet: i32, + mets: i32, + mets: i32, + } + "#; + */ - let source = r#" type Tarak = Tarak { loujet: i32, mets: i32, mets: i32 } "#; - - let (_, output) = add_symbols(source); - let errs = output.unwrap_err(); - assert_matches!(&errs[..], [ - SymbolError::DuplicateRecord { - type_name, member, ..}, - ] if type_name == &Fqsn::from_strs(&["Tarak", "Tarak"]) && member == "mets" - ); + let source = r#" type Tarak = Tarak { loujet: i32, mets: i32, mets: i32 } "#; + let (_, output) = add_symbols(source); + let errs = output.unwrap_err(); + assert_matches!(&errs[..], [ + SymbolError::DuplicateRecord { + type_name, member, ..}, + ] if type_name == &Fqsn::from_strs(&["Tarak", "Tarak"]) && member == "mets" + ); }