diff options
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 67 | ||||
| -rw-r--r-- | lib/xixanta/src/node.rs | 4 | ||||
| -rw-r--r-- | lib/xixanta/src/opcodes.rs | 20 |
3 files changed, 91 insertions, 0 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index c9800d9..a25ba41 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -2391,6 +2391,8 @@ impl<'a> Assembler<'a> { NodeType::Control(ControlType::Lobyte) => self.evaluate_byte(node, false), NodeType::Control(ControlType::Defined) => self.evaluate_defined(node), NodeType::Control(ControlType::Version) => self.evaluate_version(node), + NodeType::Control(ControlType::Max) => self.evaluate_max(node), + NodeType::Control(ControlType::Min) => self.evaluate_min(node), _ => Err(Error { line: node.value.line, message: format!( @@ -2404,6 +2406,47 @@ impl<'a> Assembler<'a> { } } + // Evaluate the args from 'node' and return the bundle from the node which + // contains the maximum value. + fn evaluate_max(&mut self, node: &PNode) -> Result<Bundle, Error> { + let Some(args) = &node.args else { + return Ok(Bundle::default()); + }; + + let mut max = Bundle::default(); + for arg in args { + self.literal_mode = None; + let bundle = self.evaluate_node(arg)?; + + if bundle.value() > max.value() { + max = bundle.clone(); + } + } + Ok(max) + } + + // Evaluate the args from 'node' and return the bundle from the node which + // contains the minimum value. + fn evaluate_min(&mut self, node: &PNode) -> Result<Bundle, Error> { + let Some(args) = &node.args else { + return Ok(Bundle::default()); + }; + + let mut min = Bundle::default(); + min.bytes[0] = 0xFF; + min.bytes[1] = 0xFF; + + for arg in args { + self.literal_mode = None; + let bundle = self.evaluate_node(arg)?; + + if bundle.value() < min.value() { + min = bundle.clone(); + } + } + Ok(min) + } + fn evaluate_byte(&mut self, node: &PNode, high: bool) -> Result<Bundle, Error> { // The parser actually guarantees that the ".hibyte" and ".lobyte" // functions have exactly one argument. Hence, if this is not the case, @@ -4730,6 +4773,30 @@ nop } #[test] + fn min_max() { + let res = just_bundles( + r#" +one = 1 +two = 2 + +lda #.min(one, two, three) +lda #.max(one, two, three) + +three = 3 + "#, + ); + + assert_eq!(res.len(), 2); + let instrs: Vec<[u8; 2]> = vec![[0xA9, 0x01], [0xA9, 0x03]]; + + 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]); + } + } + + #[test] fn warnings_on_empty_proc_scope_macro() { let res = just_assemble( r#".proc Proc diff --git a/lib/xixanta/src/node.rs b/lib/xixanta/src/node.rs index ee3ae24..d91177e 100644 --- a/lib/xixanta/src/node.rs +++ b/lib/xixanta/src/node.rs @@ -156,6 +156,8 @@ pub enum ControlType { Byte, Word, BigEndianWord, + Max, + Min, Addr, IncBin, StartRepeat, @@ -189,6 +191,8 @@ impl fmt::Display for ControlType { ControlType::Byte => write!(f, ".byte/.db"), ControlType::Word => write!(f, ".word/.dw"), ControlType::BigEndianWord => write!(f, ".dbyt/.be/.bigendian"), + ControlType::Max => write!(f, ".max"), + ControlType::Min => write!(f, ".min"), ControlType::Addr => write!(f, ".addr"), ControlType::IncBin => write!(f, ".incbin"), ControlType::StartRepeat => write!(f, ".repeat"), diff --git a/lib/xixanta/src/opcodes.rs b/lib/xixanta/src/opcodes.rs index 25b3add..bc4f1d4 100644 --- a/lib/xixanta/src/opcodes.rs +++ b/lib/xixanta/src/opcodes.rs @@ -1860,6 +1860,26 @@ pub static CONTROL_FUNCTIONS: LazyLock<HashMap<String, Control>> = LazyLock::new }, ); functions.insert( + String::from(".max"), + Control { + control_type: ControlType::Max, + has_identifier: None, + required_args: None, + touches_context: false, + only_string: false, + }, + ); + functions.insert( + String::from(".min"), + Control { + control_type: ControlType::Min, + has_identifier: None, + required_args: None, + touches_context: false, + only_string: false, + }, + ); + functions.insert( String::from(".incbin"), Control { control_type: ControlType::IncBin, |
