diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2024-10-30 14:48:10 +1300 |
---|---|---|
committer | Ben Bridle <bridle.benjamin@gmail.com> | 2024-10-30 15:40:25 +1300 |
commit | 6cc0bec0e11d5fec757e90aebd7e51ed9393365c (patch) | |
tree | 9561c5a940db2389163ce62ba419c7821bc693a6 /src/print.rs | |
parent | 2cd0c86659479774d092de727e0f0c31e27e49f2 (diff) | |
download | bedrock-asm-6cc0bec0e11d5fec757e90aebd7e51ed9393365c.zip |
Implement an intelligent source merging strategy
The previous source merging strategy was to concatenate source units
in the reverse order that they were added to the resolver, which
generally only worked when each source unit had at most one
macro-resolving parent.
An issue arose when some macros in a source unit were resolved by a
source unit which had been added earlier in the order, as the required
macro definitions would then be merged after they were referenced,
preventing the program from assembling.
The new source merging strategy finds an optimal merge order by first
recording for a given source unit the ID of each unit which resolves a
macro referenced by the given unit, and then only merging those source
units whose macro-defining dependencies have already been merged. In the
case that a cycle is detected, where two or more source units depend on
one another, a message is printed and the assembly is aborted.
Diffstat (limited to 'src/print.rs')
-rw-r--r-- | src/print.rs | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/src/print.rs b/src/print.rs index 7f49db2..0c81c07 100644 --- a/src/print.rs +++ b/src/print.rs @@ -120,6 +120,36 @@ pub fn print_resolver_errors(resolver: &SymbolResolver) -> bool { } +/// The `ids` argument contains a list of the IDs of the source units which +/// cyclicly depend on one another. +pub fn print_cyclic_source_units(ids: &[usize], resolver: &SymbolResolver) { + eprintln!("{BOLD}{RED}[ERROR]{WHITE}: Some libraries contain a dependency cycle{NORMAL}"); + for id in ids { + if let Some(unit) = resolver.source_units.get(*id) { + let path = &unit.source_unit.main.path; + let path_str = path.as_os_str().to_string_lossy(); + if let Some(name_str) = get_unit_name(&unit.source_unit) { + eprintln!("{name_str}{NORMAL}{DIM} ({path_str}){NORMAL}"); + } else { + eprintln!("{path_str}"); + }; + // Print parents involved in dependency cycle. + for parent_id in &unit.parent_ids { + if !ids.contains(parent_id) { continue; } + if let Some(parent_unit) = resolver.source_units.get(*parent_id) { + let parent_path = &parent_unit.source_unit.main.path; + let parent_path_str = parent_path.as_os_str().to_string_lossy(); + let parent_name_str = match get_unit_name(&parent_unit.source_unit) { + Some(parent_name_str) => parent_name_str, + None => parent_path_str.to_string(), + }; + eprintln!(" => {parent_name_str} {DIM}({parent_path_str}){NORMAL}"); + } + } + } + } +} + pub fn print_error(message: &str, context: Context) { print_source_issue(message, context, SourceIssueVariant::Error); @@ -207,10 +237,8 @@ fn print_source_tree_leaf(resolver: &SymbolResolver, id: usize, mut levels: Vec< true => eprint!("└── "), } if let Some(unit) = resolver.source_units.get(id) { - let path = &unit.source_unit.main.path; - let path_str = path.as_os_str().to_string_lossy(); - if let Some(name) = path.file_name() { - let name_str = name.to_string_lossy(); + let path_str = &unit.source_unit.main.path.as_os_str().to_string_lossy(); + if let Some(name_str) = get_unit_name(&unit.source_unit) { eprint!("{name_str}{BLUE}"); if unit.source_unit.head.is_some() { eprint!(" +head") } if unit.source_unit.tail.is_some() { eprint!(" +tail") } @@ -222,7 +250,7 @@ fn print_source_tree_leaf(resolver: &SymbolResolver, id: usize, mut levels: Vec< eprintln!("{NORMAL} {DIM}({path_str}){NORMAL}"); } else { eprintln!("{path_str}"); - }; + } levels.push(end); let len = unit.child_ids.len(); for (i, id) in unit.child_ids.iter().enumerate() { @@ -235,3 +263,6 @@ fn print_source_tree_leaf(resolver: &SymbolResolver, id: usize, mut levels: Vec< } +fn get_unit_name(source_unit: &SourceUnit) -> Option<String> { + source_unit.main.path.file_name().map(|s| s.to_string_lossy().to_string()) +} |