1
0
dust/dust-lang/src/instruction.rs

827 lines
24 KiB
Rust
Raw Normal View History

2024-10-09 02:56:01 +00:00
use serde::{Deserialize, Serialize};
use crate::{Chunk, Operation, Span};
2024-09-10 03:24:22 +00:00
2024-10-09 02:56:01 +00:00
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
2024-09-15 05:24:04 +00:00
pub struct Instruction(u32);
2024-09-10 03:24:22 +00:00
impl Instruction {
pub fn r#move(to_register: u8, from_register: u8) -> Instruction {
2024-09-15 05:24:04 +00:00
let mut instruction = Instruction(Operation::Move as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(from_register);
2024-09-15 05:24:04 +00:00
instruction
2024-09-10 03:24:22 +00:00
}
2024-09-18 03:06:58 +00:00
pub fn close(from_register: u8, to_register: u8) -> Instruction {
2024-09-15 05:24:04 +00:00
let mut instruction = Instruction(Operation::Close as u32);
2024-09-24 20:49:17 +00:00
instruction.set_b(from_register);
instruction.set_c(to_register);
2024-09-15 05:24:04 +00:00
instruction
}
2024-09-10 22:19:59 +00:00
pub fn load_boolean(to_register: u8, value: bool, skip: bool) -> Instruction {
let mut instruction = Instruction(Operation::LoadBoolean as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(if value { 1 } else { 0 });
instruction.set_c(if skip { 1 } else { 0 });
instruction
}
pub fn load_constant(to_register: u8, constant_index: u8, skip: bool) -> Instruction {
2024-09-15 05:24:04 +00:00
let mut instruction = Instruction(Operation::LoadConstant as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(constant_index);
instruction.set_c_to_boolean(skip);
2024-09-15 05:24:04 +00:00
instruction
}
pub fn load_list(to_register: u8, start_register: u8, end_register: u8) -> Instruction {
2024-09-17 23:35:33 +00:00
let mut instruction = Instruction(Operation::LoadList as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(start_register);
instruction.set_c(end_register);
2024-09-17 23:35:33 +00:00
instruction
}
2024-09-19 15:41:18 +00:00
pub fn define_local(to_register: u8, local_index: u8, is_mutable: bool) -> Instruction {
2024-09-18 15:27:41 +00:00
let mut instruction = Instruction(Operation::DefineLocal as u32);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(local_index);
instruction.set_c(if is_mutable { 1 } else { 0 });
2024-09-15 05:24:04 +00:00
instruction
}
2024-09-19 15:41:18 +00:00
pub fn get_local(to_register: u8, local_index: u8) -> Instruction {
2024-09-15 05:24:04 +00:00
let mut instruction = Instruction(Operation::GetLocal as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(local_index);
2024-09-15 05:24:04 +00:00
instruction
}
2024-09-19 15:41:18 +00:00
pub fn set_local(from_register: u8, local_index: u8) -> Instruction {
2024-09-15 05:24:04 +00:00
let mut instruction = Instruction(Operation::SetLocal as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(from_register);
instruction.set_b(local_index);
2024-09-15 05:24:04 +00:00
instruction
}
2024-09-15 05:24:04 +00:00
pub fn add(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Add as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(left_index);
instruction.set_c(right_index);
2024-09-15 05:24:04 +00:00
instruction
}
2024-09-15 05:24:04 +00:00
pub fn subtract(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Subtract as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(left_index);
instruction.set_c(right_index);
2024-09-15 05:24:04 +00:00
instruction
}
2024-09-15 05:24:04 +00:00
pub fn multiply(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Multiply as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(left_index);
instruction.set_c(right_index);
2024-09-15 05:24:04 +00:00
instruction
}
2024-09-15 05:24:04 +00:00
pub fn divide(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Divide as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(left_index);
instruction.set_c(right_index);
2024-09-15 05:24:04 +00:00
instruction
}
pub fn modulo(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Modulo as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(left_index);
instruction.set_c(right_index);
instruction
}
2024-09-19 15:41:18 +00:00
pub fn test(to_register: u8, test_value: bool) -> Instruction {
let mut instruction = Instruction(Operation::Test as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_c_to_boolean(test_value);
instruction
}
2024-09-19 15:41:18 +00:00
pub fn test_set(to_register: u8, argument_index: u8, test_value: bool) -> Instruction {
let mut instruction = Instruction(Operation::TestSet as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(argument_index);
instruction.set_c_to_boolean(test_value);
instruction
}
pub fn equal(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Equal as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(if comparison_boolean { 1 } else { 0 });
instruction.set_b(left_index);
instruction.set_c(right_index);
instruction
}
2024-09-22 22:17:21 +00:00
pub fn less(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Less as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(if comparison_boolean { 1 } else { 0 });
instruction.set_b(left_index);
instruction.set_c(right_index);
2024-09-22 22:17:21 +00:00
instruction
}
pub fn less_equal(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::LessEqual as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(if comparison_boolean { 1 } else { 0 });
instruction.set_b(left_index);
instruction.set_c(right_index);
2024-09-22 22:17:21 +00:00
instruction
}
2024-09-15 05:24:04 +00:00
pub fn negate(to_register: u8, from_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Negate as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(from_index);
2024-09-15 05:24:04 +00:00
instruction
}
pub fn not(to_register: u8, from_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Not as u32);
2024-09-24 20:49:17 +00:00
instruction.set_a(to_register);
instruction.set_b(from_index);
instruction
}
pub fn jump(offset: u8, is_positive: bool) -> Instruction {
let mut instruction = Instruction(Operation::Jump as u32);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b(offset);
instruction.set_c(if is_positive { 1 } else { 0 });
instruction
2024-09-15 05:24:04 +00:00
}
2024-10-12 14:55:34 +00:00
pub fn call(function_index: u8, argument_count: u8) -> Instruction {
let mut instruction = Instruction(Operation::Call as u32);
instruction.set_a(function_index);
instruction.set_b(argument_count);
instruction
}
pub fn r#return(should_return_value: bool) -> Instruction {
let mut instruction = Instruction(Operation::Return as u32);
instruction.set_b(if should_return_value { 1 } else { 0 });
instruction
2024-09-15 05:24:04 +00:00
}
pub fn operation(&self) -> Operation {
Operation::from((self.0 & 0b0000_0000_0011_1111) as u8)
2024-09-15 05:24:04 +00:00
}
pub fn set_operation(&mut self, operation: Operation) {
self.0 |= u8::from(operation) as u32;
2024-09-15 05:24:04 +00:00
}
2024-09-24 20:49:17 +00:00
pub fn data(&self) -> (Operation, u8, u8, u8, bool, bool) {
(
self.operation(),
self.a(),
self.b(),
self.c(),
self.b_is_constant(),
self.c_is_constant(),
)
2024-09-15 05:24:04 +00:00
}
2024-09-24 20:49:17 +00:00
pub fn a(&self) -> u8 {
(self.0 >> 24) as u8
}
2024-09-24 20:49:17 +00:00
pub fn b(&self) -> u8 {
(self.0 >> 16) as u8
}
2024-09-19 00:02:12 +00:00
2024-09-24 20:49:17 +00:00
pub fn c(&self) -> u8 {
(self.0 >> 8) as u8
2024-09-19 00:02:12 +00:00
}
2024-09-24 20:49:17 +00:00
pub fn a_as_boolean(&self) -> bool {
self.a() != 0
2024-09-15 05:24:04 +00:00
}
2024-09-24 20:49:17 +00:00
pub fn b_as_boolean(&self) -> bool {
self.b() != 0
2024-09-15 05:24:04 +00:00
}
2024-09-24 20:49:17 +00:00
pub fn c_as_boolean(&self) -> bool {
self.c() != 0
}
2024-09-24 20:49:17 +00:00
pub fn set_a_to_boolean(&mut self, boolean: bool) -> &mut Self {
self.set_a(if boolean { 1 } else { 0 });
self
}
2024-09-24 20:49:17 +00:00
pub fn set_b_to_boolean(&mut self, boolean: bool) -> &mut Self {
self.set_b(if boolean { 1 } else { 0 });
2024-09-19 00:02:12 +00:00
self
}
2024-09-24 20:49:17 +00:00
pub fn set_c_to_boolean(&mut self, boolean: bool) -> &mut Self {
self.set_c(if boolean { 1 } else { 0 });
self
}
2024-09-24 20:49:17 +00:00
pub fn set_a(&mut self, destination: u8) {
self.0 |= (destination as u32) << 24;
}
pub fn set_b(&mut self, argument: u8) {
2024-09-15 05:24:04 +00:00
self.0 |= (argument as u32) << 16;
}
2024-09-24 20:49:17 +00:00
pub fn set_c(&mut self, argument: u8) {
self.0 |= (argument as u32) << 8;
2024-09-15 05:24:04 +00:00
}
2024-09-24 20:49:17 +00:00
pub fn b_is_constant(&self) -> bool {
self.0 & 0b1000_0000 != 0
2024-09-15 05:24:04 +00:00
}
2024-09-24 20:49:17 +00:00
pub fn c_is_constant(&self) -> bool {
self.0 & 0b0100_0000 != 0
2024-09-15 05:24:04 +00:00
}
2024-09-24 20:49:17 +00:00
pub fn set_b_is_constant(&mut self) -> &mut Self {
self.0 |= 0b1000_0000;
2024-09-19 00:02:12 +00:00
self
}
2024-09-24 20:49:17 +00:00
pub fn set_c_is_constant(&mut self) -> &mut Self {
self.0 |= 0b0100_0000;
self
}
2024-10-09 16:16:46 +00:00
pub fn is_expression(&self) -> bool {
let operation = self.operation();
if operation.is_math() {
return if !self.b_is_constant() {
self.a() != self.b()
} else if !self.c_is_constant() {
self.a() != self.c()
} else {
true
};
}
matches!(
operation,
Operation::Not
| Operation::Negate
| Operation::Equal
| Operation::Less
| Operation::LessEqual
| Operation::Add
| Operation::Subtract
| Operation::Multiply
| Operation::Divide
| Operation::Modulo
| Operation::Test
| Operation::GetLocal
| Operation::LoadBoolean
| Operation::LoadConstant
| Operation::LoadList
)
}
2024-09-24 12:29:33 +00:00
pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> (Option<String>, Option<isize>) {
2024-09-18 01:10:44 +00:00
let format_arguments = || {
2024-09-24 20:49:17 +00:00
let first_argument = if self.b_is_constant() {
format!("C{}", self.b())
2024-09-18 01:10:44 +00:00
} else {
2024-09-24 20:49:17 +00:00
format!("R{}", self.b())
2024-09-18 01:10:44 +00:00
};
2024-09-24 20:49:17 +00:00
let second_argument = if self.c_is_constant() {
format!("C{}", self.c())
2024-09-18 01:10:44 +00:00
} else {
2024-09-24 20:49:17 +00:00
format!("R{}", self.c())
2024-09-18 01:10:44 +00:00
};
(first_argument, second_argument)
};
2024-09-24 12:29:33 +00:00
let mut jump_offset = None;
2024-09-18 01:10:44 +00:00
2024-09-15 05:24:04 +00:00
let info = match self.operation() {
2024-09-24 20:49:17 +00:00
Operation::Move => Some(format!("R{} = R{}", self.a(), self.b())),
2024-09-18 03:06:58 +00:00
Operation::Close => {
2024-09-24 20:49:17 +00:00
let from_register = self.b();
let to_register = self.c().saturating_sub(1);
2024-09-18 03:06:58 +00:00
2024-09-24 12:29:33 +00:00
Some(format!("R{from_register}..=R{to_register}"))
2024-09-18 03:06:58 +00:00
}
Operation::LoadBoolean => {
2024-09-24 20:49:17 +00:00
let to_register = self.a();
let boolean = self.b_as_boolean();
let jump = self.c_as_boolean();
2024-09-24 12:29:33 +00:00
let info = if jump {
jump_offset = Some(1);
format!("R{to_register} = {boolean} && JUMP")
} else {
2024-09-24 12:29:33 +00:00
format!("R{to_register} = {boolean}")
};
2024-09-24 12:29:33 +00:00
Some(info)
}
Operation::LoadConstant => {
let register_index = self.a();
2024-09-24 20:49:17 +00:00
let constant_index = self.b();
let jump = if self.c_as_boolean() {
jump_offset = Some(1);
"&& JUMP"
} else {
""
};
let constant = if let Some(chunk) = chunk {
match chunk.get_constant(constant_index, Span(0, 0)) {
Ok(value) => value.to_string(),
Err(error) => format!("{error:?}"),
}
} else {
"???".to_string()
};
Some(format!(
"R{register_index} = C{constant_index} ({constant}) {jump}",
))
}
2024-09-17 23:35:33 +00:00
Operation::LoadList => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
let first_index = self.b();
let last_index = self.c();
2024-09-17 23:35:33 +00:00
Some(format!("R{destination} = [R{first_index}..=R{last_index}]",))
2024-09-17 23:35:33 +00:00
}
2024-09-18 15:27:41 +00:00
Operation::DefineLocal => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
let local_index = self.b();
let identifier_display = if let Some(chunk) = chunk {
2024-09-15 01:05:03 +00:00
match chunk.get_identifier(local_index) {
Some(identifier) => identifier.to_string(),
None => "???".to_string(),
}
} else {
"???".to_string()
};
let mutable_display = if self.c_as_boolean() { "mut" } else { "" };
2024-09-24 12:29:33 +00:00
Some(format!(
"L{local_index} = R{destination} {mutable_display} {identifier_display}"
2024-09-24 12:29:33 +00:00
))
}
Operation::GetLocal => {
2024-09-24 20:49:17 +00:00
let local_index = self.b();
2024-09-24 20:49:17 +00:00
Some(format!("R{} = L{}", self.a(), local_index))
}
Operation::SetLocal => {
2024-09-24 20:49:17 +00:00
let local_index = self.b();
let identifier_display = if let Some(chunk) = chunk {
2024-09-15 01:05:03 +00:00
match chunk.get_identifier(local_index) {
Some(identifier) => identifier.to_string(),
None => "???".to_string(),
}
} else {
"???".to_string()
};
2024-09-24 12:29:33 +00:00
Some(format!(
2024-09-19 00:02:12 +00:00
"L{} = R{} {}",
2024-09-15 05:24:04 +00:00
local_index,
2024-09-24 20:49:17 +00:00
self.a(),
2024-09-15 05:24:04 +00:00
identifier_display
2024-09-24 12:29:33 +00:00
))
}
Operation::Add => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
2024-09-18 01:10:44 +00:00
let (first_argument, second_argument) = format_arguments();
2024-09-15 05:24:04 +00:00
2024-09-24 12:29:33 +00:00
Some(format!(
"R{destination} = {first_argument} + {second_argument}",
))
}
Operation::Subtract => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
2024-09-18 01:10:44 +00:00
let (first_argument, second_argument) = format_arguments();
2024-09-15 05:24:04 +00:00
2024-09-24 12:29:33 +00:00
Some(format!(
"R{destination} = {first_argument} - {second_argument}",
))
}
Operation::Multiply => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
2024-09-18 01:10:44 +00:00
let (first_argument, second_argument) = format_arguments();
2024-09-15 05:24:04 +00:00
2024-09-24 12:29:33 +00:00
Some(format!(
"R{destination} = {first_argument} * {second_argument}",
))
}
Operation::Divide => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
2024-09-18 01:10:44 +00:00
let (first_argument, second_argument) = format_arguments();
2024-09-15 05:24:04 +00:00
2024-09-24 12:29:33 +00:00
Some(format!(
"R{destination} = {first_argument} / {second_argument}",
))
}
Operation::Modulo => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
2024-09-18 01:10:44 +00:00
let (first_argument, second_argument) = format_arguments();
2024-09-24 12:29:33 +00:00
Some(format!(
"R{destination} = {first_argument} % {second_argument}",
))
}
2024-09-19 15:41:18 +00:00
Operation::Test => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
let test_value = self.c_as_boolean();
2024-09-24 12:29:33 +00:00
jump_offset = Some(1);
2024-09-24 20:49:17 +00:00
Some(format!("if R{destination} != {test_value} {{ JUMP }}",))
}
2024-09-19 15:41:18 +00:00
Operation::TestSet => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
let argument = format!("R{}", self.b());
let test_value = self.c_as_boolean();
2024-09-19 15:41:18 +00:00
let bang = if test_value { "" } else { "!" };
2024-09-24 12:29:33 +00:00
jump_offset = Some(1);
Some(format!(
"if {bang}R{destination} {{ R{destination} = R{argument} }}",
))
}
Operation::Equal => {
2024-09-24 20:49:17 +00:00
let comparison_symbol = if self.a_as_boolean() { "==" } else { "!=" };
let (first_argument, second_argument) = format_arguments();
2024-09-24 12:29:33 +00:00
jump_offset = Some(1);
2024-09-24 12:29:33 +00:00
Some(format!(
"if {first_argument} {comparison_symbol} {second_argument} {{ JUMP }}",
))
}
Operation::Less => {
2024-09-24 20:49:17 +00:00
let comparison_symbol = if self.a_as_boolean() { "<" } else { ">=" };
let (first_argument, second_argument) = format_arguments();
2024-09-24 12:29:33 +00:00
jump_offset = Some(1);
2024-09-24 12:29:33 +00:00
Some(format!(
"if {first_argument} {comparison_symbol} {second_argument}",
))
}
Operation::LessEqual => {
2024-09-24 20:49:17 +00:00
let comparison_symbol = if self.a_as_boolean() { "<=" } else { ">" };
let (first_argument, second_argument) = format_arguments();
2024-09-24 12:29:33 +00:00
jump_offset = Some(1);
2024-09-24 12:29:33 +00:00
Some(format!(
"if {first_argument} {comparison_symbol} {second_argument}",
))
}
Operation::Negate => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
let argument = if self.b_is_constant() {
format!("C{}", self.b())
2024-09-17 21:23:37 +00:00
} else {
2024-09-24 20:49:17 +00:00
format!("R{}", self.b())
2024-09-17 21:23:37 +00:00
};
2024-09-24 12:29:33 +00:00
Some(format!("R{destination} = -{argument}"))
}
Operation::Not => {
2024-09-24 20:49:17 +00:00
let destination = self.a();
let argument = if self.b_is_constant() {
format!("C{}", self.b())
} else {
2024-09-24 20:49:17 +00:00
format!("R{}", self.b())
};
2024-09-24 12:29:33 +00:00
Some(format!("R{destination} = !{argument}"))
}
Operation::Jump => {
2024-09-24 20:49:17 +00:00
let offset = self.b() as isize;
let is_positive = self.c_as_boolean();
2024-09-24 12:29:33 +00:00
if is_positive {
jump_offset = Some(offset);
} else {
2024-09-24 12:29:33 +00:00
jump_offset = Some(-offset);
}
2024-09-24 12:29:33 +00:00
None
}
2024-10-12 14:55:34 +00:00
Operation::Call => {
let function_index = self.a();
let argument_count = self.b();
let last_argument = function_index + argument_count;
let mut output = format!("R{function_index}(");
for register in function_index..last_argument {
if register != last_argument - 1 {
output.push_str(", ");
}
output.push_str(&format!("R{}", register));
}
output.push(')');
Some(output)
}
Operation::Return => None,
2024-09-24 12:29:33 +00:00
};
2024-09-24 12:29:33 +00:00
(info, jump_offset)
2024-09-10 03:24:22 +00:00
}
}
2024-09-19 15:53:41 +00:00
impl From<&Instruction> for u32 {
fn from(instruction: &Instruction) -> Self {
instruction.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
2024-09-15 05:24:04 +00:00
fn r#move() {
let mut instruction = Instruction::r#move(0, 1);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
instruction.set_c_is_constant();
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::Move);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 0);
assert_eq!(instruction.b(), 1);
assert!(instruction.b_is_constant());
assert!(instruction.b_is_constant());
2024-09-15 05:24:04 +00:00
}
#[test]
fn close() {
2024-09-18 03:06:58 +00:00
let instruction = Instruction::close(1, 2);
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::Close);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.b(), 1);
assert_eq!(instruction.c(), 2);
2024-09-15 05:24:04 +00:00
}
#[test]
fn load_boolean() {
let instruction = Instruction::load_boolean(4, true, true);
assert_eq!(instruction.operation(), Operation::LoadBoolean);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 4);
assert!(instruction.a_as_boolean());
assert!(instruction.c_as_boolean());
}
2024-09-15 05:24:04 +00:00
#[test]
fn load_constant() {
let mut instruction = Instruction::load_constant(0, 1, true);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
instruction.set_c_is_constant();
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::LoadConstant);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 0);
assert_eq!(instruction.b(), 1);
assert!(instruction.b_is_constant());
assert!(instruction.b_is_constant());
assert!(instruction.c_as_boolean());
2024-09-15 05:24:04 +00:00
}
#[test]
fn declare_local() {
2024-09-18 15:27:41 +00:00
let mut instruction = Instruction::define_local(0, 1, true);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
2024-09-15 05:24:04 +00:00
2024-09-18 15:27:41 +00:00
assert_eq!(instruction.operation(), Operation::DefineLocal);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 0);
assert_eq!(instruction.b(), 1);
assert_eq!(instruction.c(), true as u8);
assert!(instruction.b_is_constant());
2024-09-15 05:24:04 +00:00
}
#[test]
fn add() {
2024-09-15 14:20:43 +00:00
let mut instruction = Instruction::add(1, 1, 0);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::Add);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 1);
assert_eq!(instruction.b(), 1);
assert_eq!(instruction.c(), 0);
assert!(instruction.b_is_constant());
2024-09-15 05:24:04 +00:00
}
#[test]
fn subtract() {
let mut instruction = Instruction::subtract(0, 1, 2);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
instruction.set_c_is_constant();
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::Subtract);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 0);
assert_eq!(instruction.b(), 1);
assert_eq!(instruction.c(), 2);
assert!(instruction.b_is_constant());
assert!(instruction.b_is_constant());
2024-09-15 05:24:04 +00:00
}
#[test]
fn multiply() {
let mut instruction = Instruction::multiply(0, 1, 2);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
instruction.set_c_is_constant();
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::Multiply);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 0);
assert_eq!(instruction.b(), 1);
assert_eq!(instruction.c(), 2);
assert!(instruction.b_is_constant());
assert!(instruction.b_is_constant());
2024-09-15 05:24:04 +00:00
}
#[test]
fn divide() {
let mut instruction = Instruction::divide(0, 1, 2);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
instruction.set_c_is_constant();
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::Divide);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 0);
assert_eq!(instruction.b(), 1);
assert_eq!(instruction.c(), 2);
assert!(instruction.b_is_constant());
assert!(instruction.b_is_constant());
2024-09-15 05:24:04 +00:00
}
#[test]
fn and() {
2024-09-19 15:41:18 +00:00
let instruction = Instruction::test(4, true);
2024-09-19 15:41:18 +00:00
assert_eq!(instruction.operation(), Operation::Test);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 4);
assert!(instruction.c_as_boolean());
}
#[test]
fn or() {
2024-09-19 15:41:18 +00:00
let instruction = Instruction::test_set(4, 1, true);
2024-09-19 15:41:18 +00:00
assert_eq!(instruction.operation(), Operation::TestSet);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 4);
assert_eq!(instruction.b(), 1);
assert!(instruction.c_as_boolean());
}
#[test]
fn equal() {
let mut instruction = Instruction::equal(true, 1, 2);
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
instruction.set_c_is_constant();
assert_eq!(instruction.operation(), Operation::Equal);
2024-09-24 20:49:17 +00:00
assert!(instruction.a_as_boolean());
assert_eq!(instruction.b(), 1);
assert_eq!(instruction.c(), 2);
assert!(instruction.b_is_constant());
assert!(instruction.b_is_constant());
}
2024-09-15 05:24:04 +00:00
#[test]
fn negate() {
let mut instruction = Instruction::negate(0, 1);
2024-09-15 05:24:04 +00:00
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
instruction.set_c_is_constant();
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::Negate);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 0);
assert_eq!(instruction.b(), 1);
assert!(instruction.b_is_constant());
assert!(instruction.b_is_constant());
2024-09-15 05:24:04 +00:00
}
#[test]
fn not() {
let mut instruction = Instruction::not(0, 1);
2024-09-24 20:49:17 +00:00
instruction.set_b_is_constant();
instruction.set_c_is_constant();
assert_eq!(instruction.operation(), Operation::Not);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.a(), 0);
assert_eq!(instruction.b(), 1);
assert!(instruction.b_is_constant());
assert!(instruction.b_is_constant());
}
#[test]
fn jump() {
2024-09-19 15:41:18 +00:00
let instruction = Instruction::jump(4, true);
assert_eq!(instruction.operation(), Operation::Jump);
2024-09-24 20:49:17 +00:00
assert_eq!(instruction.b(), 4);
assert!(instruction.c_as_boolean());
}
2024-10-12 14:55:34 +00:00
#[test]
fn call() {
let instruction = Instruction::call(4, 1);
assert_eq!(instruction.operation(), Operation::Call);
assert_eq!(instruction.a(), 4);
assert_eq!(instruction.b(), 1);
}
2024-09-15 05:24:04 +00:00
#[test]
fn r#return() {
let instruction = Instruction::r#return(true);
2024-09-15 05:24:04 +00:00
assert_eq!(instruction.operation(), Operation::Return);
assert!(instruction.b_as_boolean());
2024-09-10 14:44:15 +00:00
}
}