diff options
| author | Miquel Sabaté Solà <mssola@mssola.com> | 2026-04-24 12:53:22 +0200 |
|---|---|---|
| committer | Miquel Sabaté Solà <mssola@mssola.com> | 2026-04-24 12:53:22 +0200 |
| commit | f89306f26f7fe26d7553c11111d49d971b174cea (patch) | |
| tree | c52a459e312e760b62cfafcb0ec4d07c184c4cc9 /lib/xixanta | |
| parent | 7c01c29cec6f5fcc94abcd154c47d2c78f765a78 (diff) | |
| download | tools.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>
Diffstat (limited to 'lib/xixanta')
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 47 |
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] |
