diff options
author | Ben Bridle <ben@derelict.engineering> | 2025-03-08 14:22:38 +1300 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-03-08 14:22:53 +1300 |
commit | 869d9b4b9c6f5d095084c851af33d8590bd3edee (patch) | |
tree | af5c427178868121aee2cd32af892a98a1c21ba0 | |
parent | f9537f8109ca6976a97d88acd0d48dd600f4844d (diff) | |
download | assembler-869d9b4b9c6f5d095084c851af33d8590bd3edee.zip |
Show an error when a source file fails to parse
Previously, if a source file failed to parse, no symbols would be
returned and symbol resolution would continue as normal. This would
obscure the source of any errors, as well as the fact that any error
had occurred at all.
We don't want all errors in all source files to be printed at symbol
resolution time, because this could bury any errors in the actual
program being assembled with potentially irrelevant library errors,
and errors in the program being assembled will be printed all over
again once a merged source file has been produced.
Instead, we allow the parser function to return a None value if the
file could not be parsed, and a single line is printed as a warning
for every library file that failed to parse.
-rw-r--r-- | src/resolver.rs | 39 | ||||
-rw-r--r-- | src/source_unit.rs | 67 |
2 files changed, 65 insertions, 41 deletions
diff --git a/src/resolver.rs b/src/resolver.rs index 2b49055..8d3a16d 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -43,12 +43,20 @@ impl Resolver { let source_id = self.source_units.len(); use std::mem::take; - info!("Including source file at {:?}", source_unit.main.path); - self.include_symbols(take(&mut source_unit.main.symbols), source_id, SourceRole::Main); + info!("Including source unit at {:?}", source_unit.main.path); + if let Some(symbols) = &mut source_unit.main.symbols { + self.include_symbols(take(symbols), source_id, SourceRole::Main); + } if let Some(head) = &mut source_unit.head { - self.include_symbols(take(&mut head.symbols), source_id, SourceRole::Head); } + if let Some(symbols) = &mut head.symbols { + self.include_symbols(take(symbols), source_id, SourceRole::Head); + } + } if let Some(tail) = &mut source_unit.tail { - self.include_symbols(take(&mut tail.symbols), source_id, SourceRole::Tail); } + if let Some(symbols) = &mut tail.symbols { + self.include_symbols(take(symbols), source_id, SourceRole::Tail); + } + } match parent_id { Some(parent_id) => match self.source_units.get_mut(parent_id) { @@ -153,19 +161,18 @@ impl Resolver { /// Return the ID of a source unit that contains an unresolved reference /// to a symbol defined by this unit. fn unit_resolved_by_unit(&self, source_unit: &SourceUnit) -> Option<usize> { - if let Some(id) = self.unit_resolved_by_symbol(&source_unit.main.symbols) { - return Some(id); - } - if let Some(head) = &source_unit.head { - if let Some(id) = self.unit_resolved_by_symbol(&head.symbols) { - return Some(id); - } - } - if let Some(tail) = &source_unit.tail { - if let Some(id) = self.unit_resolved_by_symbol(&tail.symbols) { - return Some(id); - } + macro_rules! return_resolved_unit { + ($file:expr) => { + if let Some(symbols) = &$file.symbols { + if let Some(id) = self.unit_resolved_by_symbol(&symbols) { + return Some(id); + } + } + }; } + return_resolved_unit!(&source_unit.main); + if let Some(head) = &source_unit.head { return_resolved_unit!(&head) } + if let Some(tail) = &source_unit.tail { return_resolved_unit!(&tail) } return None; } diff --git a/src/source_unit.rs b/src/source_unit.rs index 3e30284..9c51ccb 100644 --- a/src/source_unit.rs +++ b/src/source_unit.rs @@ -1,10 +1,10 @@ use crate::*; -use log::info; +use log::{info, warn}; use vagabond::*; -type ParseFn = fn(&str, Option<&Path>) -> Vec<Symbol>; +type ParseFn = fn(&str, Option<&Path>) -> Option<Vec<Symbol>>; /// Gather all source units with a given extension using a PATH-style environment variable. @@ -22,20 +22,39 @@ pub fn gather_from_path_variable(variable: &str, extension: Option<&str>, parse: /// Gather source units with a given extension at or descending from a path. pub fn gather_from_path(path: &Path, extension: Option<&str>, parse: ParseFn) -> Vec<SourceUnit> { let mut source_units = Vec::new(); + let check_optional_file = |file: &Option<SourceFile>| -> bool { + match file { + Some(file) => match file.symbols { + Some(_) => { info!("Found source file at {:?}", file.path); true } + None => { warn!("Could not parse source file at {:?}", file.path); false } + } + None => true, + } + }; + let mut gather_source_unit = |path: &Path| { + if let Ok(unit) = SourceUnit::from_path(&path, extension, parse) { + if unit.main.symbols.is_some() { + info!("Found source file at {:?}", unit.main.path); + let head_good = check_optional_file(&unit.head); + let tail_good = check_optional_file(&unit.tail); + if head_good && tail_good { + source_units.push(unit); + } + } else { + warn!("Could not parse source file at {path:?}"); + check_optional_file(&unit.head); + check_optional_file(&unit.tail); + } + } + }; if let Ok(entry) = Entry::from_path(path) { if EntryType::File == entry.entry_type { - if let Ok(unit) = SourceUnit::from_path(&entry.path, extension, parse) { - info!("Found source file at {path:?}"); - source_units.push(unit); - } + gather_source_unit(&entry.path) } else if EntryType::Directory == entry.entry_type { info!("Traversing directory {path:?} for source files"); if let Ok(entries) = traverse_directory(entry.path) { for entry in entries { - if let Ok(unit) = SourceUnit::from_path(&entry.path, extension, parse) { - info!("Found source file at {:?}", entry.path); - source_units.push(unit); - } + gather_source_unit(&entry.path) } } } @@ -66,29 +85,27 @@ impl SourceUnit { // Head and tail files will be picked up later along with the main file. if !is_main || is_head || is_tail { return Err(FileError::InvalidExtension); } + let parse_file = |path: PathBuf| { + if let Ok(source_code) = read_file(&path) { + let symbols = parse(&source_code, Some(&path)); + return Some(SourceFile { symbols, source_code, path: path }); + } + return None; + }; + let head = head_extension.map_or(None, |ext| parse_file(main_path.with_extension(&ext))); + let tail = tail_extension.map_or(None, |ext| parse_file(main_path.with_extension(&ext))); let source_code = read_file(path.as_ref())?; let symbols = parse(&source_code, Some(path.as_ref())); - macro_rules! parse_file { - ($path:expr) => { - read_file(&$path).ok().map(|source_code| { - let symbols = parse(&source_code, Some(&$path)); - let path = $path; - SourceFile { symbols, source_code, path } - }) - }; - } - - let head = head_extension.map_or(None, |ext| parse_file!(main_path.with_extension(&ext))); - let tail = tail_extension.map_or(None, |ext| parse_file!(main_path.with_extension(&ext))); let main = SourceFile { path: main_path, source_code, symbols }; - Ok( SourceUnit { main, head, tail } ) + Ok(SourceUnit { main, head, tail }) } /// Load from a string of source code. pub fn from_string<P: AsRef<Path>>(source_code: String, path: P, parse: ParseFn) -> Self { let path = { path.as_ref().canonicalize().unwrap_or_else(|_| path.as_ref().to_path_buf()) }; let symbols = parse(&source_code, Some(&path)); - Self { main: SourceFile { path, source_code, symbols }, head: None, tail: None } + let main = SourceFile { path, source_code, symbols }; + Self { main, head: None, tail: None } } pub fn name(&self) -> Option<String> { @@ -105,7 +122,7 @@ impl SourceUnit { pub struct SourceFile { pub path: PathBuf, pub source_code: String, - pub symbols: Vec<Symbol>, + pub symbols: Option<Vec<Symbol>>, } pub struct Symbol { |