aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src/lib.rs
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mssola@mssola.com>2026-02-02 19:56:21 +0100
committerMiquel Sabaté Solà <mssola@mssola.com>2026-02-02 19:56:21 +0100
commit930ad1cc4422f19251ea77a625816e3aebcc6eea (patch)
tree6223b56dfc21a7b4278364e953e2457267518b7f /lib/xixanta/src/lib.rs
parente6f6f514cd11e9a512abb00d16b93e800e861c58 (diff)
downloadtools.nes-930ad1cc4422f19251ea77a625816e3aebcc6eea.tar.gz
tools.nes-930ad1cc4422f19251ea77a625816e3aebcc6eea.zip
xixanta: add context from macro expansions
The way macro expansions work is that the evaluated bundles replace the current node, but this throws away the context of the line, the source, etc. from the original line of code. Add a stack that is pushed/popped when expanding macros, and are then cloned for each pending node and error. This way, errors have full context of the original code and can display backtraces for macro expansion. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
Diffstat (limited to 'lib/xixanta/src/lib.rs')
-rw-r--r--lib/xixanta/src/lib.rs33
1 files changed, 30 insertions, 3 deletions
diff --git a/lib/xixanta/src/lib.rs b/lib/xixanta/src/lib.rs
index 8515e23..a45868f 100644
--- a/lib/xixanta/src/lib.rs
+++ b/lib/xixanta/src/lib.rs
@@ -17,6 +17,20 @@ impl Default for SourceInfo {
}
}
+/// Contains all the information relevant for a macro expansion. That is,
+/// whenever expanding a macro call, the assembler is expected to create a new
+/// 'ExpandedFrom' object with all the relevant information so a node underneath
+/// can refer to it whenever an error occurred (e.g. 'I detected an error here
+/// but I was coming from an expansion from "there"').
+#[derive(Clone, Debug, PartialEq)]
+pub struct ExpandedFrom {
+ /// The source from which the expansion happened.
+ pub source: SourceInfo,
+
+ /// The line in the 'source' where the macro expansion happened.
+ pub line: usize,
+}
+
/// Error provides an interface used throughout this crate in which an error
/// message of type String is located through a line and an associated
/// SourceInfo. If global is set to true, then `line` does not matter.
@@ -32,6 +46,11 @@ pub struct Error {
/// Information on the file where the error was found.
pub source: SourceInfo,
+ /// Stack of macro expansions before reaching to the error. This is used for
+ /// the 'Display' trait, so the expansion context is rewinded and shown to
+ /// the user.
+ pub expanded_from: Vec<ExpandedFrom>,
+
/// Human-readable representation of the error. Don't use this field
/// directly, prefer its `std::fmt::Display` implementation. Hence, calling
/// `.to_string()` on it is most probably the way to go.
@@ -57,13 +76,21 @@ impl std::fmt::Display for Error {
} else if self.source.name.is_empty() {
write!(f, "{} (line {})", self.message, self.line + 1)
} else {
- write!(
- f,
+ let mut msg = vec![format!(
"{} ({}: line {})",
self.message,
self.source.name,
self.line + 1
- )
+ )];
+ for ef in &self.expanded_from {
+ msg.push(format!(
+ " >> expanded from {}: line {}.",
+ ef.source.name,
+ ef.line + 1
+ ));
+ }
+
+ write!(f, "{}", msg.join("\n"))
}
}
}