diff --git a/src/protocol/parser/symbol_table2.rs b/src/protocol/parser/symbol_table2.rs deleted file mode 100644 index b6b5668e65e700ec1ddb62d4861e57154d3de566..0000000000000000000000000000000000000000 --- a/src/protocol/parser/symbol_table2.rs +++ /dev/null @@ -1,333 +0,0 @@ -/// symbol_table.rs -/// -/// The datastructure used to lookup symbols within particular scopes. Scopes -/// may be module-level or definition level, although imports and definitions -/// within definitions are currently not allowed. -/// -/// TODO: Once the compiler has matured, find out ways to optimize to prevent -/// the repeated HashMap lookup. - -use std::collections::HashMap; -use std::collections::hash_map::Entry; - -use crate::protocol::input_source2::*; -use crate::protocol::ast::*; -use crate::collections::*; - -const RESERVED_SYMBOLS: usize = 32; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SymbolScope { - Global, - Module(RootId), - Definition(DefinitionId), -} - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum SymbolClass { - Module, - Struct, - Enum, - Union, - Function, - Component -} - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum DefinitionClass { - Struct, - Enum, - Union, - Function, - Component, -} - -impl DefinitionClass { - fn as_symbol_class(&self) -> SymbolClass { - match self { - DefinitionClass::Struct => SymbolClass::Struct, - DefinitionClass::Enum => SymbolClass::Enum, - DefinitionClass::Union => SymbolClass::Union, - DefinitionClass::Function => SymbolClass::Function, - DefinitionClass::Component => SymbolClass::Component, - } - } -} - -struct ScopedSymbols { - scope: SymbolScope, - parent_scope: Option, - child_scopes: Vec, - symbols: Vec, -} - -impl ScopedSymbols { - fn get_symbol<'a>(&'a self, name: &StringRef) -> Option<&'a Symbol> { - for symbol in self.symbols.iter() { - if symbol.name == *name { - return Some(symbol); - } - } - - None - } -} - -impl SymbolDefinition { - pub fn symbol_class(&self) -> SymbolClass { - use SymbolDefinition as SD; - use SymbolClass as SC; - - match self { - SD::Module(_) => SC::Module, - SD::Struct(_) => SC::Struct, - SD::Enum(_) => SC::Enum, - SD::Union(_) => SC::Union, - SD::Function(_) => SC::Function, - SD::Component(_) => SC::Component, - } - } -} - -#[derive(Debug)] -pub struct SymbolModule { - pub root_id: RootId, - pub introduced_at: ImportId, -} - -#[derive(Debug, Clone)] -pub struct SymbolDefinition { - // Definition location (not necessarily the place where the symbol - // is introduced, as it may be imported). Builtin symbols will have invalid - // spans and module IDs - pub defined_in_module: RootId, - pub defined_in_scope: SymbolScope, - pub definition_span: InputSpan, // full span of definition - pub identifier_span: InputSpan, // span of just the identifier - // Location where the symbol is introduced in its scope - pub imported_at: Option, - // Definition in the heap, with a utility enum to determine its - // class if the ID is not needed. - pub class: DefinitionClass, - pub definition_id: DefinitionId, -} - -impl SymbolDefinition { - /// Clones the entire data structure, but replaces the `imported_at` field - /// with the supplied `ImportId`. - pub(crate) fn into_imported(mut self, imported_at: ImportId) -> Self { - self.imported_at = Some(imported_at); - self - } -} - -#[derive(Debug)] -pub enum SymbolVariant { - Module(SymbolModule), - Definition(SymbolDefinition), -} - -impl SymbolVariant { - /// Returns the span at which the item was introduced. For an imported - /// item (all modules, and imported types) this returns the span of the - /// import. For a defined type this returns the span of the identifier - pub(crate) fn span_of_introduction(&self, heap: &Heap) -> InputSpan { - match self { - SymbolVariant::Module(v) => heap[v.introduced_at].span(), - SymbolVariant::Definition(v) => if let Some(import_id) = v.imported_at { - heap[import_id].span() - } else { - v.identifier_span - }, - } - } - - pub(crate) fn as_module(&self) -> &SymbolModule { - match self { - SymbolVariant::Module(v) => v, - SymbolVariant::Definition(_) => unreachable!("called 'as_module' on {:?}", self), - } - } - - pub(crate) fn as_definition(&self) -> &SymbolDefinition { - match self { - SymbolVariant::Module(v) => unreachable!("called 'as_definition' on {:?}", self), - SymbolVariant::Definition(v) => v, - } - } - - pub(crate) fn as_definition_mut(&mut self) -> &mut SymbolDefinition { - match self { - SymbolVariant::Module(v) => unreachable!("called 'as_definition_mut' on {:?}", self), - SymbolVariant::Definition(v) => v, - } - } -} - -#[derive(Clone)] -pub struct Symbol { - pub name: StringRef<'static>, - pub variant: SymbolVariant, -} - -impl Symbol { - pub(crate) fn class(&self) -> SymbolClass { - match &self.variant { - SymbolVariant::Module(_) => SymbolClass::Module, - SymbolVariant::Definition(data) => data.class.as_symbol_class(), - } - } -} - -pub struct SymbolTable { - module_lookup: HashMap, RootId>, - scope_lookup: HashMap, -} - -impl SymbolTable { - /// Inserts a new module by its name. Upon module naming conflict the - /// previously associated `RootId` will be returned. - pub(crate) fn insert_module(&mut self, module_name: StringRef<'static>, root_id: RootId) -> Result<(), RootId> { - match self.module_lookup.entry(module_name) { - Entry::Occupied(v) => { - Err(*v.get()) - }, - Entry::Vacant(v) => { - v.insert(root_id); - Ok(()) - } - } - } - - /// Retrieves module `RootId` by name - pub(crate) fn get_module_by_name(&mut self, name: &[u8]) -> Option { - let string_ref = StringRef::new(name); - self.module_lookup.get(&string_ref).map(|v| *v) - } - - /// Inserts a new symbol scope. The parent must have been added to the - /// symbol table before. - pub(crate) fn insert_scope(&mut self, parent_scope: Option, new_scope: SymbolScope) { - debug_assert!( - parent_scope.is_none() || self.scope_lookup.contains_key(parent_scope.as_ref().unwrap()), - "inserting scope {:?} but parent {:?} does not exist", new_scope, parent_scope - ); - debug_assert!(!self.scope_lookup.contains_key(&new_scope), "inserting scope {:?}, but it already exists", new_scope); - - if let Some(parent_scope) = parent_scope { - let parent = self.scope_lookup.get_mut(&parent_scope).unwrap(); - parent.child_scopes.push(new_scope); - } - - let scope = ScopedSymbols { - scope: new_scope, - parent_scope, - child_scopes: Vec::with_capacity(RESERVED_SYMBOLS), - symbols: Vec::with_capacity(RESERVED_SYMBOLS) - }; - self.scope_lookup.insert(new_scope, scope); - } - - /// Inserts a symbol into a particular scope. The symbol's name may not - /// exist in the scope or any of its parents. If it does collide then the - /// symbol will be returned, together with the symbol that has the same - /// name. - pub(crate) fn insert_symbol(&mut self, in_scope: SymbolScope, symbol: Symbol) -> Result<(), (Symbol, &Symbol)> { - debug_assert!(self.scope_lookup.contains_key(&in_scope), "inserting symbol {}, but scope {:?} does not exist", symbol.name.as_str(), in_scope); - let mut seek_scope = in_scope; - loop { - let scoped_symbols = self.scope_lookup.get(&seek_scope).unwrap(); - for existing_symbol in scoped_symbols.symbols.iter() { - if symbol.name == existing_symbol.name { - return Err((symbol, existing_symbol)) - } - } - - match scoped_symbols.parent_scope { - Some(parent_scope) => { seek_scope = parent_scope; }, - None => { break; } - } - } - - // If here, then there is no collision - let scoped_symbols = self.scope_lookup.get_mut(&in_scope).unwrap(); - scoped_symbols.symbols.push(symbol); - Ok(()) - } - - /// Retrieves a symbol by name by searching in a particular scope and that scope's parents. The - /// returned symbol may both be imported as defined within any of the searched scopes. - pub(crate) fn get_symbol_by_name( - &self, mut in_scope: SymbolScope, name: &[u8] - ) -> Option<&Symbol> { - let string_ref = StringRef::new(name); - loop { - let scope = self.scope_lookup.get(&in_scope); - if scope.is_none() { - return None; - } - let scope = scope.unwrap(); - - if let Some(symbol) = scope.get_symbol(&string_ref) { - return Some(symbol); - } else { - // Could not find symbol in current scope, seek in the parent scope if it exists - match &scope.parent_scope { - Some(parent_scope) => { in_scope = *parent_scope; }, - None => return None, - } - } - } - } - - /// Retrieves a symbol by name by searching in a particular scope and that scope's parents. The - /// returned symbol must be defined within any of the searched scopes and may not be imported. - /// In case such an imported symbol exists then this function still returns `None`. - pub(crate) fn get_symbol_by_name_defined_in_scope( - &self, in_scope: SymbolScope, name: &[u8] - ) -> Option<&Symbol> { - match self.get_symbol_by_name(in_scope, name) { - Some(symbol) => { - match &symbol.variant { - SymbolVariant::Module(_) => { - None // in-scope modules are always imported - }, - SymbolVariant::Definition(variant) => { - if variant.imported_at.is_some() || variant.defined_in_scope == SymbolScope::Global { - // Symbol is imported or lives in the global scope. - // Things in the global scope are defined by the - // compiler. - None - } else { - Some(symbol) - } - } - } - }, - None => None, - } - } - - /// Retrieves all symbols that are defined within a particular scope. Imported symbols are - /// ignored. Returns `true` if the scope was found (which may contain 0 defined symbols) and - /// `false` if the scope was not found. - pub(crate) fn get_all_symbols_defined_in_scope(&self, in_scope: SymbolScope, target: &mut Vec) -> bool { - match self.scope_lookup.get(&in_scope) { - Some(scope) => { - for symbol in &scope.symbols { - if let SymbolVariant::Definition(definition) = &symbol.variant { - if definition.imported_at.is_some() { - continue; - } - - // Defined in scope, so push onto target - target.push(symbol.clone()); - } - } - - true - }, - None => false, - } - } -} \ No newline at end of file