diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2025-02-14 09:36:52 +1300 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-03-18 12:23:27 +1300 |
commit | 7d4dd52b8cfc865ae1b975ca3b6a3e72a812ebb9 (patch) | |
tree | 14ca9fa0ddcdd8c5155ddeaac241cd4f55486b6e /src/symbol_resolver.rs | |
parent | f69a8f8c312ded212446082682bcabba8e3a9c9f (diff) | |
download | bedrock-asm-7d4dd52b8cfc865ae1b975ca3b6a3e72a812ebb9.zip |
Rewrite library
Diffstat (limited to 'src/symbol_resolver.rs')
-rw-r--r-- | src/symbol_resolver.rs | 296 |
1 files changed, 0 insertions, 296 deletions
diff --git a/src/symbol_resolver.rs b/src/symbol_resolver.rs deleted file mode 100644 index 0b89fb1..0000000 --- a/src/symbol_resolver.rs +++ /dev/null @@ -1,296 +0,0 @@ -use crate::*; - -use std::mem::take; - - -/// Resolve symbol references across source units. -pub struct SymbolResolver { - pub definitions: Vec<TrackedSymbol>, - /// All resolved references. - pub resolved: Vec<TrackedSymbol>, - /// All unresolved references. - pub unresolved: Vec<TrackedSymbol>, - /// Contains the `definitions` index of the original definition. - pub redefinitions: Vec<(TrackedSymbol, usize)>, - pub source_units: Vec<HeirarchicalSourceUnit>, - pub root_unit_ids: Vec<usize>, - pub unused_library_units: Vec<SourceUnit>, -} - - -impl SymbolResolver { - /// Construct a resolver from a root source unit. - pub fn from_source_unit(source_unit: SourceUnit) -> Self { - let mut new = Self { - definitions: Vec::new(), - resolved: Vec::new(), - unresolved: Vec::new(), - redefinitions: Vec::new(), - source_units: Vec::new(), - root_unit_ids: Vec::new(), - unused_library_units: Vec::new(), - }; - new.add_source_unit(source_unit, None); - return new; - } - - pub fn add_library_units(&mut self, mut source_units: Vec<SourceUnit>) { - self.unused_library_units.append(&mut source_units); - } - - pub fn resolve(&mut self) { - // Repeatedly test if any unused source unit resolves an unresolved symbol, - // breaking the loop when no new resolutions are found. - 'outer: loop { - for (i, source_unit) in self.unused_library_units.iter().enumerate() { - if let Some(id) = self.resolves_reference(&source_unit) { - let source_unit = self.unused_library_units.remove(i); - self.add_source_unit(source_unit, Some(id)); - continue 'outer; - } - } - break; - } - - // For every macro reference in every unit, find the ID of the unit which - // resolves that reference and add it to the .parent_ids field of the - // referencing unit. - for reference in &self.resolved { - let predicate = |d: &&TrackedSymbol| d.symbol.name == reference.symbol.name; - if let Some(definition) = self.definitions.iter().find(predicate) { - let is_self = reference.source_id == definition.source_id; - let is_label = definition.symbol.variant == SymbolVariant::LabelDefinition; - if is_self || is_label { continue; } - let referencing_unit = &mut self.source_units[reference.source_id]; - referencing_unit.parent_ids.push(definition.source_id); - }; - } - } - - /// Add a source unit to the resolver and link it to a parent unit. - pub fn add_source_unit(&mut self, mut source_unit: SourceUnit, parent_id: Option<usize>) { - let source_id = self.source_units.len(); - - // Add all main symbols. - if let Some(definitions) = take(&mut source_unit.main.symbols.definitions) { - self.add_definitions(definitions, source_id, SourceRole::Main); } - if let Some(references) = take(&mut source_unit.main.symbols.references) { - self.add_references(references, source_id, SourceRole::Main); } - - // Add all head symbols. - if let Some(head) = &mut source_unit.head { - if let Some(references) = take(&mut head.symbols.references) { - self.add_references(references, source_id, SourceRole::Head); } - if let Some(definitions) = take(&mut head.symbols.definitions) { - self.add_definitions(definitions, source_id, SourceRole::Head); } - } - - // Add all tail symbols. - if let Some(tail) = &mut source_unit.tail { - if let Some(references) = take(&mut tail.symbols.references) { - self.add_references(references, source_id, SourceRole::Tail); } - if let Some(definitions) = take(&mut tail.symbols.definitions) { - self.add_definitions(definitions, source_id, SourceRole::Tail); } - } - - if let Some(parent_id) = parent_id { - if let Some(parent_unit) = self.source_units.get_mut(parent_id) { - parent_unit.child_ids.push(source_id); - } - } else { - self.root_unit_ids.push(source_id); - } - - self.source_units.push( - HeirarchicalSourceUnit { - source_unit, - child_ids: Vec::new(), - parent_ids: Vec::new(), - } - ); - } - - fn add_references(&mut self, references: Vec<Symbol>, source_id: usize, source_role: SourceRole) { - for symbol in references { - let reference = TrackedSymbol { symbol, source_id, source_role }; - match self.definitions.contains(&reference) { - true => self.resolved.push(reference), - false => self.unresolved.push(reference), - } - } - } - - fn add_definitions(&mut self, definitions: Vec<Symbol>, source_id: usize, source_role: SourceRole) { - for symbol in definitions { - let predicate = |d: &TrackedSymbol| { &d.symbol.name == &symbol.name }; - if let Some(original) = self.definitions.iter().position(predicate) { - let definition = TrackedSymbol { symbol, source_id, source_role }; - let redefinition = (definition, original); - self.redefinitions.push(redefinition); - } else { - let predicate = |s: &mut TrackedSymbol| s.symbol.name == symbol.name; - for symbol in self.unresolved.extract_if(predicate) { - self.resolved.push(symbol); - } - self.unresolved.retain(|s| s.symbol.name != symbol.name); - let definition = TrackedSymbol { symbol, source_id, source_role }; - self.definitions.push(definition); - } - } - } - - /// Returns the ID of the owner of a symbol resolved by this unit. - pub fn resolves_reference(&self, source_unit: &SourceUnit) -> Option<usize> { - if let Some(definitions) = &source_unit.main.symbols.definitions { - if let Some(id) = self.source_id_of_unresolved(&definitions) { - return Some(id); - } - } - if let Some(head) = &source_unit.head { - if let Some(definitions) = &head.symbols.definitions { - if let Some(id) = self.source_id_of_unresolved(&definitions) { - return Some(id); - } - } - } - if let Some(tail) = &source_unit.tail { - if let Some(definitions) = &tail.symbols.definitions { - if let Some(id) = self.source_id_of_unresolved(&definitions) { - return Some(id); - } - } - } - return None; - } - - /// Returns the ID of the owner of a reference to one of these symbols. - fn source_id_of_unresolved(&self, symbols: &[Symbol]) -> Option<usize> { - for symbol in symbols { - let opt = self.unresolved.iter().find(|s| s.symbol.name == symbol.name); - if let Some(unresolved) = opt { - return Some(unresolved.source_id); - } - } - return None; - } - - pub fn get_source_code_for_tracked_symbol(&self, symbol: &TrackedSymbol) -> &str { - let source_unit = &self.source_units[symbol.source_id].source_unit; - match symbol.source_role { - SourceRole::Main => source_unit.main.symbols.source_code.as_str(), - SourceRole::Head => match &source_unit.head { - Some(head) => head.symbols.source_code.as_str(), - None => unreachable!("Failed to find source for token"), - } - SourceRole::Tail => match &source_unit.tail { - Some(tail) => tail.symbols.source_code.as_str(), - None => unreachable!("Failed to find source for token"), - } - } - } - - /// Create a source file by concatenating all source units. - /// If the source unit dependency graph contains a cycle, the IDs of the - /// source units involved in the cycle will be returned. - pub fn get_merged_source_code(&self) -> Result<String, Vec<usize>> { - // The ID of a given source unit will come after the IDs of all - // source units which define at least one symbol referenced in the - // given source unit. - let head_order = { - let mut included_source_ids: Vec<usize> = Vec::new(); - let mut remaining_source_ids: Vec<usize> = Vec::new(); - // Reverse the order so that the root unit is the last to be added. - for i in (0..self.source_units.len()).rev() { - remaining_source_ids.push(i); - } - - 'restart: while !remaining_source_ids.is_empty() { - 'next: for (i, id) in remaining_source_ids.iter().enumerate() { - let unit = &self.source_units[*id]; - for parent_id in &unit.parent_ids { - if !included_source_ids.contains(&parent_id) { - continue 'next; - } - } - included_source_ids.push(*id); - remaining_source_ids.remove(i); - continue 'restart; - } - // All remaining source units depend on at least one remaining - // source unit, indicating a dependency cycle. - return Err(remaining_source_ids); - } - included_source_ids - }; - - let mut source_code = String::new(); - - // Push head source code in macro-definition order. - for id in &head_order { - let source_unit = &self.source_units[*id]; - if let Some(head) = &source_unit.source_unit.head { - push_source_code_to_string(&mut source_code, head); - } - } - // Push main source code in source-added order. - for source_unit in self.source_units.iter() { - let main = &source_unit.source_unit.main; - push_source_code_to_string(&mut source_code, &main); - } - // Push tail source code in reverse source-added order. - for source_unit in self.source_units.iter().rev() { - if let Some(tail) = &source_unit.source_unit.tail { - push_source_code_to_string(&mut source_code, tail); - } - } - return Ok(source_code); - } -} - - -fn push_source_code_to_string(string: &mut String, source_file: &SourceFile) { - // Don't push source code if it contains only whitespace. - let source_code = &source_file.symbols.source_code; - if source_code.chars().all(|c| c.is_whitespace()) { return; } - // Ensure that sections are separated by two newlines. - if !string.is_empty() { - if !string.ends_with('\n') { string.push('\n'); } - if !string.ends_with("\n\n") { string.push('\n'); } - } - // Write a path comment to the string. - let path_str = source_file.path.as_os_str().to_string_lossy(); - let path_comment = format!("(: {path_str} )\n"); - string.push_str(&path_comment); - string.push_str(&source_code); -} - - -pub struct HeirarchicalSourceUnit { - pub source_unit: SourceUnit, - /// IDs of units which were added to resolve symbol references this unit. - pub child_ids: Vec<usize>, - /// IDs of units which resolve macro references in this unit. - pub parent_ids: Vec<usize>, -} - - -pub struct TrackedSymbol { - pub symbol: Symbol, - pub source_id: usize, - pub source_role: SourceRole, -} - - -#[derive(Clone, Copy)] -pub enum SourceRole { - Main, - Head, - Tail, -} - - -impl PartialEq for TrackedSymbol { - fn eq(&self, other: &TrackedSymbol) -> bool { - self.symbol.name.eq(&other.symbol.name) - } -} |