Add tests for divide instruction
This commit is contained in:
parent
6e9d5a49d2
commit
07001a03e7
@ -50,3 +50,7 @@ path = "tests/math/subtract.rs"
|
|||||||
[[test]]
|
[[test]]
|
||||||
name = "multiply"
|
name = "multiply"
|
||||||
path = "tests/math/multiply.rs"
|
path = "tests/math/multiply.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "divide"
|
||||||
|
path = "tests/math/divide.rs"
|
||||||
|
@ -353,6 +353,20 @@ impl Instruction {
|
|||||||
|
|
||||||
Operand::Register(destination, left.as_type())
|
Operand::Register(destination, left.as_type())
|
||||||
}
|
}
|
||||||
|
Operation::DIVIDE => {
|
||||||
|
let Divide {
|
||||||
|
destination, left, ..
|
||||||
|
} = Divide::from(*self);
|
||||||
|
|
||||||
|
Operand::Register(destination, left.as_type())
|
||||||
|
}
|
||||||
|
Operation::MODULO => {
|
||||||
|
let Modulo {
|
||||||
|
destination, left, ..
|
||||||
|
} = Modulo::from(*self);
|
||||||
|
|
||||||
|
Operand::Register(destination, left.as_type())
|
||||||
|
}
|
||||||
unsupported => todo!("Support {unsupported}"),
|
unsupported => todo!("Support {unsupported}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -765,8 +765,91 @@ pub fn multiply(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn divide(instruction: InstructionFields, thread: &mut Thread) {}
|
pub fn divide(instruction: InstructionFields, thread: &mut Thread) {
|
||||||
|
let destination = instruction.a_field as usize;
|
||||||
|
let left = instruction.b_field as usize;
|
||||||
|
let left_type = instruction.b_type;
|
||||||
|
let left_is_constant = instruction.b_is_constant;
|
||||||
|
let right = instruction.c_field as usize;
|
||||||
|
let right_type = instruction.c_type;
|
||||||
|
let right_is_constant = instruction.c_is_constant;
|
||||||
|
|
||||||
|
match (left_type, right_type) {
|
||||||
|
(TypeCode::BYTE, TypeCode::BYTE) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_byte().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_byte_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_byte().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_byte_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value.saturating_div(*right_value);
|
||||||
|
let register = Register::Value(result);
|
||||||
|
|
||||||
|
thread.set_byte_register(destination, register);
|
||||||
|
}
|
||||||
|
(TypeCode::FLOAT, TypeCode::FLOAT) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_float().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_float().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_float_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_float().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_float().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_float_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value / right_value;
|
||||||
|
let register = Register::Value(result);
|
||||||
|
|
||||||
|
thread.set_float_register(destination, register);
|
||||||
|
}
|
||||||
|
(TypeCode::INTEGER, TypeCode::INTEGER) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_integer().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_integer_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_integer().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_integer_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value.saturating_div(*right_value);
|
||||||
|
let register = Register::Value(result);
|
||||||
|
|
||||||
|
thread.set_integer_register(destination, register);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn modulo(instruction: InstructionFields, thread: &mut Thread) {}
|
pub fn modulo(instruction: InstructionFields, thread: &mut Thread) {}
|
||||||
|
|
||||||
pub fn test(instruction: InstructionFields, thread: &mut Thread) {}
|
pub fn test(instruction: InstructionFields, thread: &mut Thread) {}
|
||||||
|
171
dust-lang/tests/math/divide.rs
Normal file
171
dust-lang/tests/math/divide.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
use dust_lang::{
|
||||||
|
Chunk, ConcreteValue, FunctionType, Instruction, Operand, Span, Type, Value, compile,
|
||||||
|
instruction::TypeCode, run,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_bytes() {
|
||||||
|
let source = "0x0A / 0x02";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Byte),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, 10, TypeCode::BYTE, false),
|
||||||
|
Instruction::load_encoded(1, 2, TypeCode::BYTE, false),
|
||||||
|
Instruction::divide(
|
||||||
|
2,
|
||||||
|
Operand::Register(0, TypeCode::BYTE),
|
||||||
|
Operand::Register(1, TypeCode::BYTE),
|
||||||
|
),
|
||||||
|
Instruction::r#return(true, 2, TypeCode::BYTE),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 4), Span(7, 11), Span(0, 11), Span(11, 11)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::byte(0x05));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_many_bytes() {
|
||||||
|
let source = "0x0A / 0x02 / 0x02";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Byte),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, 10, TypeCode::BYTE, false),
|
||||||
|
Instruction::load_encoded(1, 2, TypeCode::BYTE, false),
|
||||||
|
Instruction::divide(
|
||||||
|
2,
|
||||||
|
Operand::Register(0, TypeCode::BYTE),
|
||||||
|
Operand::Register(1, TypeCode::BYTE),
|
||||||
|
),
|
||||||
|
Instruction::load_encoded(3, 2, TypeCode::BYTE, false),
|
||||||
|
Instruction::divide(
|
||||||
|
4,
|
||||||
|
Operand::Register(2, TypeCode::BYTE),
|
||||||
|
Operand::Register(3, TypeCode::BYTE),
|
||||||
|
),
|
||||||
|
Instruction::r#return(true, 4, TypeCode::BYTE),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(7, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(14, 18),
|
||||||
|
Span(0, 18),
|
||||||
|
Span(18, 18),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::byte(0x02));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_floats() {
|
||||||
|
let source = "1.0 / 0.25";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Float),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::divide(
|
||||||
|
0,
|
||||||
|
Operand::Constant(0, TypeCode::FLOAT),
|
||||||
|
Operand::Constant(1, TypeCode::FLOAT),
|
||||||
|
),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::FLOAT),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 10), Span(10, 10)],
|
||||||
|
constants: vec![ConcreteValue::Float(1.0), ConcreteValue::Float(0.25)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::float(4.0));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_many_floats() {
|
||||||
|
let source = "1.0 / 0.25 / 0.5";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Float),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::divide(
|
||||||
|
0,
|
||||||
|
Operand::Constant(0, TypeCode::FLOAT),
|
||||||
|
Operand::Constant(1, TypeCode::FLOAT),
|
||||||
|
),
|
||||||
|
Instruction::divide(
|
||||||
|
1,
|
||||||
|
Operand::Register(0, TypeCode::FLOAT),
|
||||||
|
Operand::Constant(2, TypeCode::FLOAT),
|
||||||
|
),
|
||||||
|
Instruction::r#return(true, 1, TypeCode::FLOAT),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 10), Span(0, 16), Span(16, 16)],
|
||||||
|
constants: vec![
|
||||||
|
ConcreteValue::Float(1.0),
|
||||||
|
ConcreteValue::Float(0.25),
|
||||||
|
ConcreteValue::Float(0.5),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::float(8.0));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_integers() {
|
||||||
|
let source = "10 / 2";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Integer),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::divide(
|
||||||
|
0,
|
||||||
|
Operand::Constant(0, TypeCode::INTEGER),
|
||||||
|
Operand::Constant(1, TypeCode::INTEGER),
|
||||||
|
),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::INTEGER),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 6), Span(6, 6)],
|
||||||
|
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(2)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::integer(5));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_many_integers() {
|
||||||
|
let source = "10 / 2 / 2";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Integer),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::divide(
|
||||||
|
0,
|
||||||
|
Operand::Constant(0, TypeCode::INTEGER),
|
||||||
|
Operand::Constant(1, TypeCode::INTEGER),
|
||||||
|
),
|
||||||
|
Instruction::divide(
|
||||||
|
1,
|
||||||
|
Operand::Register(0, TypeCode::INTEGER),
|
||||||
|
Operand::Constant(1, TypeCode::INTEGER),
|
||||||
|
),
|
||||||
|
Instruction::r#return(true, 1, TypeCode::INTEGER),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 6), Span(0, 10), Span(10, 10)],
|
||||||
|
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(2)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::integer(2));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user