diff options
author | Ben Bridle <ben@derelict.engineering> | 2025-02-05 12:58:02 +1300 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-02-05 13:03:36 +1300 |
commit | 80da2af821385b2fc89091e9ac37a047349da4bd (patch) | |
tree | 2ba50368301e041f8d1b99145ab0a1fe28f91571 /src/errors/mod.rs | |
parent | 8d11be64f6c1747e7c4049105a6dd4ea9ab0d27f (diff) | |
download | assembler-80da2af821385b2fc89091e9ac37a047349da4bd.zip |
Implement source unit compilation, symbol resolution, error reporting
This library can now carry out all stages of assembly from collecting
source fragments to resolving symbols to pruning unused libraries to
generating a single compiled source file.
Pretty-printing of state has also been implemented in this library.
The source tree hierarchy, symbol resolution errors, and file read
errors can all be printed in a tidy format.
Diffstat (limited to 'src/errors/mod.rs')
-rw-r--r-- | src/errors/mod.rs | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/src/errors/mod.rs b/src/errors/mod.rs new file mode 100644 index 0000000..b0bf7e4 --- /dev/null +++ b/src/errors/mod.rs @@ -0,0 +1,71 @@ +mod file_error; +mod merge_error; +mod resolver_error; + +pub use file_error::*; +pub use merge_error::*; +pub use resolver_error::*; + +use crate::*; + +use ansi::*; +use log::LogLevel; + + +pub fn report_source_issue(level: LogLevel, context: &Context, message: &str) { + // Prepare variables. + let in_merged = &context.source.in_merged; + let line_num = in_merged.start.line + 1; + let digits = line_num.to_string().len(); + let w = digits + 3; + let arrow = "-->"; + let mut string = message.to_string(); + + macro_rules! push { + ($($tokens:tt)*) => { string.push_str(&format!($($tokens)*)) }; + } + + // Format message and locations. + push!("{NORMAL}\n"); + push!("{BLUE}{arrow:>w$}{NORMAL} {in_merged}\n", w=w); + if let Some(in_source) = &context.source.in_source { + push!("{BLUE}{arrow:>w$}{NORMAL} {in_source}\n", w=w); + } + + // Format source context. + let left = in_merged.start.column; + let right = in_merged.end.column + 1; + let source_line = context.source_code.split('\n').nth(in_merged.start.line) + .unwrap_or("<error reading line from source>"); + let space = " "; + let colour = match level { + LogLevel::Info => BLUE, + LogLevel::Warn => YELLOW, + LogLevel::Error => RED, + LogLevel::Fatal => RED, + }; + + // Print source code line. + push!("{BLUE} {line_num} | {NORMAL}"); + for (i, c) in source_line.chars().enumerate() { + if i == left { push!("{colour}") } + if i == right { push!("{NORMAL}") } + push!("{c}"); + } + push!("{NORMAL}\n"); + + // Print source code underline. + push!("{BLUE} {space:>w$} | {NORMAL}", w=digits); + for _ in 0..left { push!(" "); } + push!("{colour}"); + for _ in left..right { push!("^"); } + push!("{NORMAL}"); + + // Print the completed message. + match level { + LogLevel::Info => log::info!( "{}", string), + LogLevel::Warn => log::warn!( "{}", string), + LogLevel::Error => log::error!("{}", string), + LogLevel::Fatal => log::fatal!("{}", string), + } +} |