aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mssola@mssola.com>2026-04-24 12:53:22 +0200
committerMiquel Sabaté Solà <mssola@mssola.com>2026-04-24 12:53:22 +0200
commitf89306f26f7fe26d7553c11111d49d971b174cea (patch)
treec52a459e312e760b62cfafcb0ec4d07c184c4cc9
parent7c01c29cec6f5fcc94abcd154c47d2c78f765a78 (diff)
downloadtools.nes-f89306f26f7fe26d7553c11111d49d971b174cea.tar.gz
tools.nes-f89306f26f7fe26d7553c11111d49d971b174cea.zip
Fix calls with arguments containing addresses
Some macro calls could contain addresses, like this: MACRO_CALL @address Before this commit this was resolved at the "crunch" stage, but only because we were grabbing the value from the part that was not resolved. However, if this unresolved object came from a node which is not just a value (e.g. an arithmetic operation), then it just applied the computation from before the "crunch" stage. So, for something like this: MACRO_CALL @address + 1 the argument would have been computed as simply "1", as that unresolved object only contained the "+ 1" known part. Fix this by re-evaluating the node at "crunch" stage whenever we have an attached "node" member to the given pending definition. This way, we can evaluate the full node and get the proper value from the arithmetic computation. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
-rw-r--r--lib/xixanta/src/assembler.rs47
1 files changed, 46 insertions, 1 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs
index 54ba4c3..a5937ba 100644
--- a/lib/xixanta/src/assembler.rs
+++ b/lib/xixanta/src/assembler.rs
@@ -1015,7 +1015,29 @@ impl<'a> Assembler<'a> {
// locally. These are basically arguments from a macro call.
if let Some(pd) = &pn.pending_defines {
for d in pd {
- let _ = self.context.set_variable(&d.id, &d.obj, true);
+ // Does this definition have a node attach to it? If so,
+ // then evaluate it again but with all the gained context we
+ // have at this stage. This way we will resolve the proper
+ // value for it even if it involved an arithmetical
+ // operation with an address we couldn't resolve before this
+ // stage.
+ let _ = match &d.obj.node {
+ Some(n) => {
+ // Yes! We have to evaluate this node again.
+ self.literal_mode = None;
+ let o = self.evaluate_node(n)?;
+
+ // Re-create the bundle to be passed from this
+ // object member, and set it as the variable's
+ // value.
+ let mut dobj = d.obj.clone();
+ dobj.bundle = o;
+ self.context.set_variable(&d.id, &dobj, true)
+ }
+ // No attached node, we can proceed by setting the
+ // variable as is.
+ None => self.context.set_variable(&d.id, &d.obj, true),
+ };
}
}
@@ -5179,6 +5201,29 @@ MACRO Var1
assert_eq!(res[3].bytes[1], 0xFC);
}
+ #[test]
+ fn arithmetic_on_macro_arg() {
+ let res = just_bundles(
+ r#"
+.macro MC ADDR
+ adc ADDR, y
+.endmacro
+
+MC things + 1
+
+things:
+ .byte $00, $01
+ "#,
+ );
+
+ assert_eq!(res.len(), 3);
+
+ assert_eq!(res[0].size, 3);
+ assert_eq!(res[0].bytes[0], 0x79);
+ assert_eq!(res[0].bytes[1], 0x04);
+ assert_eq!(res[0].bytes[2], 0x80);
+ }
+
// .repeat
#[test]