diff options
| author | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-01-16 16:14:40 +0100 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-01-16 16:14:40 +0100 |
| commit | a3a630dfee207c111213d2cad85ceb983df7625a (patch) | |
| tree | 314d3c55e62f437596648704fbd7a81d2c332e44 /lib/xixanta | |
| parent | 161d7b406b7fba75a2057b8d9e780f521b9bc6bf (diff) | |
| download | tools.nes-a3a630dfee207c111213d2cad85ceb983df7625a.tar.gz tools.nes-a3a630dfee207c111213d2cad85ceb983df7625a.zip | |
Implement .def/.defined expressions
This can be combined with .if/.elsif statements just like any other
expression.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta')
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 53 | ||||
| -rw-r--r-- | lib/xixanta/src/node.rs | 2 | ||||
| -rw-r--r-- | lib/xixanta/src/opcodes.rs | 2 |
3 files changed, 57 insertions, 0 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index ce34983..d0a0e6e 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -1550,6 +1550,7 @@ impl<'a> Assembler<'a> { match node.node_type { NodeType::Control(ControlType::Hibyte) => self.evaluate_byte(node, true), NodeType::Control(ControlType::Lobyte) => self.evaluate_byte(node, false), + NodeType::Control(ControlType::Defined) => self.evaluate_defined(node), _ => Err(Error { line: node.value.line, message: format!( @@ -1585,6 +1586,24 @@ impl<'a> Assembler<'a> { Ok(bundle) } + // Returns a bundle containing a boolean value on whether the symbol + // referenced in the given `node` is actually defined on this context or + // not. + fn evaluate_defined(&mut self, node: &PNode) -> Result<Bundle, Error> { + // Guaranteed by the parser to be only one argument. + let name = node.args.as_ref().unwrap().first().unwrap(); + + if self + .context + .get_variable(&name.value, &self.mappings) + .is_ok() + { + Ok(Bundle::fill(0x01)) + } else { + Ok(Bundle::fill(0x00)) + } + } + fn push_evaluated_arguments(&mut self, node: &PNode, nbytes: u8) -> Result<(), Error> { match &node.args { Some(args) => { @@ -3372,6 +3391,40 @@ jsr Movement::update ); } + #[test] + fn defined() { + let res = just_bundles( + r#"Var = 0 +.if .defined(Var) + lda #1 +.else + lda #0 +.endif + +.if .defined(Var1) + lda #1 +.else + lda #0 +.endif + +.if !.defined(Var1) + lda #1 +.else + lda #0 +.endif +"#, + ); + + assert_eq!(res.len(), 3); + + let instrs: Vec<[u8; 2]> = vec![[0xA9, 0x01], [0xA9, 0x00], [0xA9, 0x01]]; + for i in 0..instrs.len() { + assert_eq!(res[i].size, 2); + assert_eq!(res[i].bytes[0], instrs[i][0]); + assert_eq!(res[i].bytes[1], instrs[i][1]); + } + } + // Macros #[test] diff --git a/lib/xixanta/src/node.rs b/lib/xixanta/src/node.rs index ae79f1e..f1eb558 100644 --- a/lib/xixanta/src/node.rs +++ b/lib/xixanta/src/node.rs @@ -147,6 +147,7 @@ pub enum ControlType { Elsif, Else, EndIf, + Defined, } impl fmt::Display for ControlType { @@ -174,6 +175,7 @@ impl fmt::Display for ControlType { ControlType::Elsif => write!(f, ".elsif"), ControlType::Else => write!(f, ".else"), ControlType::EndIf => write!(f, ".endif"), + ControlType::Defined => write!(f, ".defined"), } } } diff --git a/lib/xixanta/src/opcodes.rs b/lib/xixanta/src/opcodes.rs index 8488b77..80878ec 100644 --- a/lib/xixanta/src/opcodes.rs +++ b/lib/xixanta/src/opcodes.rs @@ -761,6 +761,8 @@ lazy_static! { functions.insert(String::from(".elsif"), Control { control_type: ControlType::Elsif, has_identifier: None, required_args: Some((1, 1)), touches_context: false, only_string: false }); functions.insert(String::from(".else"), Control { control_type: ControlType::Else, has_identifier: None, required_args: Some((0, 0)), touches_context: false, only_string: false }); functions.insert(String::from(".endif"), Control { control_type: ControlType::EndIf, has_identifier: None, required_args: Some((0, 0)), touches_context: false, only_string: false }); + functions.insert(String::from(".def"), Control { control_type: ControlType::Defined, has_identifier: None, required_args: Some((1, 1)), touches_context: false, only_string: false }); + functions.insert(String::from(".defined"), Control { control_type: ControlType::Defined, has_identifier: None, required_args: Some((1, 1)), touches_context: false, only_string: false }); functions }; |
