Add tests for comparison operators; Implement comparison operators in the VM
This commit is contained in:
parent
f2ee01d66f
commit
a53cfb9cf6
@ -62,3 +62,23 @@ path = "tests/math/modulo.rs"
|
|||||||
[[test]]
|
[[test]]
|
||||||
name = "less"
|
name = "less"
|
||||||
path = "tests/comparison/less.rs"
|
path = "tests/comparison/less.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "equal"
|
||||||
|
path = "tests/comparison/equal.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "less_equal"
|
||||||
|
path = "tests/comparison/less_equal.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "greater"
|
||||||
|
path = "tests/comparison/greater.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "not_equal"
|
||||||
|
path = "tests/comparison/not_equal.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "greater_equal"
|
||||||
|
path = "tests/comparison/greater_equal.rs"
|
||||||
|
@ -171,7 +171,7 @@ pub fn point(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
|
|
||||||
thread.set_list_register(destination, register);
|
thread.set_list_register(destination, register);
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +216,7 @@ pub fn close(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
thread.close_list_register(register_index);
|
thread.close_list_register(register_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
|
|
||||||
thread.set_string_register(destination, register);
|
thread.set_string_register(destination, register);
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if jump_next {
|
if jump_next {
|
||||||
@ -360,7 +360,7 @@ pub fn load_list(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
|
|
||||||
Pointer::RegisterList(register_index)
|
Pointer::RegisterList(register_index)
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
item_pointers.push(pointer);
|
item_pointers.push(pointer);
|
||||||
@ -589,7 +589,7 @@ pub fn add(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
|
|
||||||
thread.set_string_register(destination, register);
|
thread.set_string_register(destination, register);
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -761,7 +761,7 @@ pub fn multiply(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
|
|
||||||
thread.set_integer_register(destination, register);
|
thread.set_integer_register(destination, register);
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,7 +949,181 @@ pub fn test(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
|
|
||||||
pub fn test_set(instruction: InstructionFields, thread: &mut Thread) {}
|
pub fn test_set(instruction: InstructionFields, thread: &mut Thread) {}
|
||||||
|
|
||||||
pub fn equal(instruction: InstructionFields, thread: &mut Thread) {}
|
pub fn equal(instruction: InstructionFields, thread: &mut Thread) {
|
||||||
|
let comparator = instruction.d_field;
|
||||||
|
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::BOOLEAN, TypeCode::BOOLEAN) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_boolean().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_boolean().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_boolean_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_boolean().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_boolean().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_boolean_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value == right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(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 == right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(TypeCode::CHARACTER, TypeCode::CHARACTER) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_character().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_character().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_character_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_character().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_character().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_character_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value == right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(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;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(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 == right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(TypeCode::STRING, TypeCode::STRING) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_string().unwrap().clone()
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
thread
|
||||||
|
.get_constant(left)
|
||||||
|
.as_string()
|
||||||
|
.unwrap_unchecked()
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_string_register(left).clone()
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_string().unwrap().clone()
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
thread
|
||||||
|
.get_constant(right)
|
||||||
|
.as_string()
|
||||||
|
.unwrap_unchecked()
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_string_register(right).clone()
|
||||||
|
};
|
||||||
|
let result = left_value == right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn less(instruction: InstructionFields, thread: &mut Thread) {
|
pub fn less(instruction: InstructionFields, thread: &mut Thread) {
|
||||||
let comparator = instruction.d_field;
|
let comparator = instruction.d_field;
|
||||||
@ -961,6 +1135,31 @@ pub fn less(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
let right_is_constant = instruction.c_is_constant;
|
let right_is_constant = instruction.c_is_constant;
|
||||||
|
|
||||||
match (left_type, right_type) {
|
match (left_type, right_type) {
|
||||||
|
(TypeCode::BOOLEAN, TypeCode::BOOLEAN) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_boolean().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_boolean().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_boolean_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_boolean().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_boolean().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_boolean_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value < right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
(TypeCode::BYTE, TypeCode::BYTE) => {
|
(TypeCode::BYTE, TypeCode::BYTE) => {
|
||||||
let left_value = if left_is_constant {
|
let left_value = if left_is_constant {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
@ -1098,11 +1297,185 @@ pub fn less(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
thread.current_frame_mut().ip += 1;
|
thread.current_frame_mut().ip += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) {}
|
pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) {
|
||||||
|
let comparator = instruction.d_field;
|
||||||
|
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::BOOLEAN, TypeCode::BOOLEAN) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_boolean().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_boolean().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_boolean_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_boolean().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_boolean().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_boolean_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value <= right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(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 <= right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(TypeCode::CHARACTER, TypeCode::CHARACTER) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_character().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(left).as_character().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_character_register(left)
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_character().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { thread.get_constant(right).as_character().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_character_register(right)
|
||||||
|
};
|
||||||
|
let result = left_value <= right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(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;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(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 <= right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(TypeCode::STRING, TypeCode::STRING) => {
|
||||||
|
let left_value = if left_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_string().unwrap().clone()
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
thread
|
||||||
|
.get_constant(left)
|
||||||
|
.as_string()
|
||||||
|
.unwrap_unchecked()
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_string_register(left).clone()
|
||||||
|
};
|
||||||
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(right).as_string().unwrap().clone()
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
thread
|
||||||
|
.get_constant(right)
|
||||||
|
.as_string()
|
||||||
|
.unwrap_unchecked()
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_string_register(right).clone()
|
||||||
|
};
|
||||||
|
let result = left_value <= right_value;
|
||||||
|
|
||||||
|
if result == comparator {
|
||||||
|
thread.current_frame_mut().ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn negate(instruction: InstructionFields, thread: &mut Thread) {}
|
pub fn negate(instruction: InstructionFields, thread: &mut Thread) {}
|
||||||
|
|
||||||
@ -1169,7 +1542,7 @@ pub fn r#return(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
item_type: abstract_list.item_type,
|
item_type: abstract_list.item_type,
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thread.return_value = Some(None);
|
thread.return_value = Some(None);
|
||||||
|
164
dust-lang/tests/comparison/equal.rs
Normal file
164
dust-lang/tests/comparison/equal.rs
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
use dust_lang::{
|
||||||
|
Chunk, ConcreteValue, DustString, FunctionType, Instruction, Operand, Span, Type, Value,
|
||||||
|
compile, instruction::TypeCode, run,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn equal_bytes() {
|
||||||
|
let source = "0x0A == 0x03";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, 0x0A, TypeCode::BYTE, false),
|
||||||
|
Instruction::load_encoded(1, 0x03, TypeCode::BYTE, false),
|
||||||
|
Instruction::equal(
|
||||||
|
true,
|
||||||
|
Operand::Register(0, TypeCode::BYTE),
|
||||||
|
Operand::Register(1, TypeCode::BYTE),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(8, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(12, 12),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn equal_characters() {
|
||||||
|
let source = "'a' == 'b'";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::equal(
|
||||||
|
true,
|
||||||
|
Operand::Constant(0, TypeCode::CHARACTER),
|
||||||
|
Operand::Constant(1, TypeCode::CHARACTER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(10, 10),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn equal_floats() {
|
||||||
|
let source = "10.0 == 3.0";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::equal(
|
||||||
|
true,
|
||||||
|
Operand::Constant(0, TypeCode::FLOAT),
|
||||||
|
Operand::Constant(1, TypeCode::FLOAT),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(11, 11),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Float(10.0), ConcreteValue::Float(3.0)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn equal_integers() {
|
||||||
|
let source = "10 == 3";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::equal(
|
||||||
|
true,
|
||||||
|
Operand::Constant(0, TypeCode::INTEGER),
|
||||||
|
Operand::Constant(1, TypeCode::INTEGER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 7), Span(0, 7), Span(0, 7), Span(0, 7), Span(7, 7)],
|
||||||
|
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(3)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn equal_strings() {
|
||||||
|
let source = "\"abc\" == \"def\"";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::equal(
|
||||||
|
true,
|
||||||
|
Operand::Constant(0, TypeCode::STRING),
|
||||||
|
Operand::Constant(1, TypeCode::STRING),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(14, 14),
|
||||||
|
],
|
||||||
|
constants: vec![
|
||||||
|
ConcreteValue::String(DustString::from("abc")),
|
||||||
|
ConcreteValue::String(DustString::from("def")),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
158
dust-lang/tests/comparison/greater.rs
Normal file
158
dust-lang/tests/comparison/greater.rs
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
use dust_lang::{
|
||||||
|
Chunk, ConcreteValue, DustString, FunctionType, Instruction, Operand, Span, Type, Value,
|
||||||
|
compile, instruction::TypeCode, run,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_bytes() {
|
||||||
|
let source = "0x0A > 0x03";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, 0x0A, TypeCode::BYTE, false),
|
||||||
|
Instruction::load_encoded(1, 0x03, TypeCode::BYTE, false),
|
||||||
|
Instruction::less_equal(
|
||||||
|
false,
|
||||||
|
Operand::Register(0, TypeCode::BYTE),
|
||||||
|
Operand::Register(1, TypeCode::BYTE),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(7, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(11, 11),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_characters() {
|
||||||
|
let source = "'a' > 'b'";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less_equal(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::CHARACTER),
|
||||||
|
Operand::Constant(1, TypeCode::CHARACTER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 9), Span(0, 9), Span(0, 9), Span(0, 9), Span(9, 9)],
|
||||||
|
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_floats() {
|
||||||
|
let source = "10.0 > 3.0";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less_equal(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::FLOAT),
|
||||||
|
Operand::Constant(1, TypeCode::FLOAT),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(10, 10),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Float(10.0), ConcreteValue::Float(3.0)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_integers() {
|
||||||
|
let source = "10 > 3";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less_equal(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::INTEGER),
|
||||||
|
Operand::Constant(1, TypeCode::INTEGER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 6), Span(0, 6), Span(0, 6), Span(0, 6), Span(6, 6)],
|
||||||
|
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(3)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_strings() {
|
||||||
|
let source = "\"abc\" > \"def\"";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less_equal(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::STRING),
|
||||||
|
Operand::Constant(1, TypeCode::STRING),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(13, 13),
|
||||||
|
],
|
||||||
|
constants: vec![
|
||||||
|
ConcreteValue::String(DustString::from("abc")),
|
||||||
|
ConcreteValue::String(DustString::from("def")),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
199
dust-lang/tests/comparison/greater_equal.rs
Normal file
199
dust-lang/tests/comparison/greater_equal.rs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
use dust_lang::{
|
||||||
|
Chunk, ConcreteValue, DustString, FunctionType, Instruction, Operand, Span, Type, Value,
|
||||||
|
compile, instruction::TypeCode, run,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn great_equal_booleans() {
|
||||||
|
let source = "true >= false";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::load_encoded(1, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::less(
|
||||||
|
false,
|
||||||
|
Operand::Register(0, TypeCode::BOOLEAN),
|
||||||
|
Operand::Register(1, TypeCode::BOOLEAN),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(2, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(2, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 2, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(8, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(13, 13),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_equal_bytes() {
|
||||||
|
let source = "0x0A >= 0x03";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, 0x0A, TypeCode::BYTE, false),
|
||||||
|
Instruction::load_encoded(1, 0x03, TypeCode::BYTE, false),
|
||||||
|
Instruction::less(
|
||||||
|
false,
|
||||||
|
Operand::Register(0, TypeCode::BYTE),
|
||||||
|
Operand::Register(1, TypeCode::BYTE),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(8, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(12, 12),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_equal_characters() {
|
||||||
|
let source = "'a' >= 'b'";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::CHARACTER),
|
||||||
|
Operand::Constant(1, TypeCode::CHARACTER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(10, 10),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_equal_floats() {
|
||||||
|
let source = "10.0 >= 3.0";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::FLOAT),
|
||||||
|
Operand::Constant(1, TypeCode::FLOAT),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(11, 11),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Float(10.0), ConcreteValue::Float(3.0)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_equal_integers() {
|
||||||
|
let source = "10 >= 3";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::INTEGER),
|
||||||
|
Operand::Constant(1, TypeCode::INTEGER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 7), Span(0, 7), Span(0, 7), Span(0, 7), Span(7, 7)],
|
||||||
|
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(3)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn greater_equal_strings() {
|
||||||
|
let source = "\"abc\" >= \"def\"";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::STRING),
|
||||||
|
Operand::Constant(1, TypeCode::STRING),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(14, 14),
|
||||||
|
],
|
||||||
|
constants: vec![
|
||||||
|
ConcreteValue::String(DustString::from("abc")),
|
||||||
|
ConcreteValue::String(DustString::from("def")),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
@ -3,6 +3,41 @@ use dust_lang::{
|
|||||||
compile, instruction::TypeCode, run,
|
compile, instruction::TypeCode, run,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn less_booleans() {
|
||||||
|
let source = "true < false";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::load_encoded(1, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::less(
|
||||||
|
true,
|
||||||
|
Operand::Register(0, TypeCode::BOOLEAN),
|
||||||
|
Operand::Register(1, TypeCode::BOOLEAN),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(2, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(2, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 2, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(7, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(12, 12),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn less_bytes() {
|
fn less_bytes() {
|
||||||
let source = "0x0A < 0x03";
|
let source = "0x0A < 0x03";
|
||||||
|
199
dust-lang/tests/comparison/less_equal.rs
Normal file
199
dust-lang/tests/comparison/less_equal.rs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
use dust_lang::{
|
||||||
|
Chunk, ConcreteValue, DustString, FunctionType, Instruction, Operand, Span, Type, Value,
|
||||||
|
compile, instruction::TypeCode, run,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn less_equal_booleans() {
|
||||||
|
let source = "true <= false";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::load_encoded(1, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::less_equal(
|
||||||
|
true,
|
||||||
|
Operand::Register(0, TypeCode::BOOLEAN),
|
||||||
|
Operand::Register(1, TypeCode::BOOLEAN),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(2, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(2, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 2, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(8, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(13, 13),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn less_equal_bytes() {
|
||||||
|
let source = "0x0A <= 0x03";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, 0x0A, TypeCode::BYTE, false),
|
||||||
|
Instruction::load_encoded(1, 0x03, TypeCode::BYTE, false),
|
||||||
|
Instruction::less_equal(
|
||||||
|
true,
|
||||||
|
Operand::Register(0, TypeCode::BYTE),
|
||||||
|
Operand::Register(1, TypeCode::BYTE),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(8, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(12, 12),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn less_equal_characters() {
|
||||||
|
let source = "'a' <= 'b'";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less_equal(
|
||||||
|
true,
|
||||||
|
Operand::Constant(0, TypeCode::CHARACTER),
|
||||||
|
Operand::Constant(1, TypeCode::CHARACTER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(10, 10),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn less_equal_floats() {
|
||||||
|
let source = "10.0 <= 3.0";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less_equal(
|
||||||
|
true,
|
||||||
|
Operand::Constant(0, TypeCode::FLOAT),
|
||||||
|
Operand::Constant(1, TypeCode::FLOAT),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(11, 11),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Float(10.0), ConcreteValue::Float(3.0)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn less_equal_integers() {
|
||||||
|
let source = "10 <= 3";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less_equal(
|
||||||
|
true,
|
||||||
|
Operand::Constant(0, TypeCode::INTEGER),
|
||||||
|
Operand::Constant(1, TypeCode::INTEGER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 7), Span(0, 7), Span(0, 7), Span(0, 7), Span(7, 7)],
|
||||||
|
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(3)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(false));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn less_equal_strings() {
|
||||||
|
let source = "\"abc\" <= \"def\"";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::less_equal(
|
||||||
|
true,
|
||||||
|
Operand::Constant(0, TypeCode::STRING),
|
||||||
|
Operand::Constant(1, TypeCode::STRING),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(14, 14),
|
||||||
|
],
|
||||||
|
constants: vec![
|
||||||
|
ConcreteValue::String(DustString::from("abc")),
|
||||||
|
ConcreteValue::String(DustString::from("def")),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
199
dust-lang/tests/comparison/not_equal.rs
Normal file
199
dust-lang/tests/comparison/not_equal.rs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
use dust_lang::{
|
||||||
|
Chunk, ConcreteValue, DustString, FunctionType, Instruction, Operand, Span, Type, Value,
|
||||||
|
compile, instruction::TypeCode, run,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_equal_booleans() {
|
||||||
|
let source = "true != false";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::load_encoded(1, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::equal(
|
||||||
|
false,
|
||||||
|
Operand::Register(0, TypeCode::BOOLEAN),
|
||||||
|
Operand::Register(1, TypeCode::BOOLEAN),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(2, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(2, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 2, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(8, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(0, 13),
|
||||||
|
Span(13, 13),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_equal_bytes() {
|
||||||
|
let source = "0x0A != 0x03";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::load_encoded(0, 0x0A, TypeCode::BYTE, false),
|
||||||
|
Instruction::load_encoded(1, 0x03, TypeCode::BYTE, false),
|
||||||
|
Instruction::equal(
|
||||||
|
false,
|
||||||
|
Operand::Register(0, TypeCode::BYTE),
|
||||||
|
Operand::Register(1, TypeCode::BYTE),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 4),
|
||||||
|
Span(8, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(0, 12),
|
||||||
|
Span(12, 12),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_equal_characters() {
|
||||||
|
let source = "'a' != 'b'";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::equal(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::CHARACTER),
|
||||||
|
Operand::Constant(1, TypeCode::CHARACTER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(0, 10),
|
||||||
|
Span(10, 10),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_equal_floats() {
|
||||||
|
let source = "10.0 != 3.0";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::equal(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::FLOAT),
|
||||||
|
Operand::Constant(1, TypeCode::FLOAT),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(0, 11),
|
||||||
|
Span(11, 11),
|
||||||
|
],
|
||||||
|
constants: vec![ConcreteValue::Float(10.0), ConcreteValue::Float(3.0)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_equal_integers() {
|
||||||
|
let source = "10 != 3";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::equal(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::INTEGER),
|
||||||
|
Operand::Constant(1, TypeCode::INTEGER),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![Span(0, 7), Span(0, 7), Span(0, 7), Span(0, 7), Span(7, 7)],
|
||||||
|
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(3)],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_equal_strings() {
|
||||||
|
let source = "\"abc\" != \"def\"";
|
||||||
|
let chunk = Chunk {
|
||||||
|
r#type: FunctionType::new([], [], Type::Boolean),
|
||||||
|
instructions: vec![
|
||||||
|
Instruction::equal(
|
||||||
|
false,
|
||||||
|
Operand::Constant(0, TypeCode::STRING),
|
||||||
|
Operand::Constant(1, TypeCode::STRING),
|
||||||
|
),
|
||||||
|
Instruction::jump(1, true),
|
||||||
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, true),
|
||||||
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||||
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||||
|
],
|
||||||
|
positions: vec![
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(0, 14),
|
||||||
|
Span(14, 14),
|
||||||
|
],
|
||||||
|
constants: vec![
|
||||||
|
ConcreteValue::String(DustString::from("abc")),
|
||||||
|
ConcreteValue::String(DustString::from("def")),
|
||||||
|
],
|
||||||
|
..Chunk::default()
|
||||||
|
};
|
||||||
|
let return_value = Some(Value::boolean(true));
|
||||||
|
|
||||||
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user