1
0

Add and pass tests

This commit is contained in:
Jeff 2024-09-23 19:16:15 -04:00
parent 182ef66f23
commit 9fe3e440ac
3 changed files with 75 additions and 52 deletions

View File

@ -2,37 +2,6 @@ use crate::Local;
use super::*;
#[test]
fn comparison_chain() {
let source = "1 == 2 > 3 < 4 != 5;";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(
*Instruction::equal(true, 0, 1)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(
*Instruction::equal(true, 1, 2)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(7, 9)
),
(Instruction::jump(1, true), Span(7, 9)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
],
vec![Value::integer(1), Value::integer(2), Value::integer(3)],
vec![]
)),
);
}
#[test]
fn not() {
let source = "!true";

View File

@ -38,16 +38,16 @@ impl Vm {
pub fn run(&mut self) -> Result<Option<Value>, VmError> {
// DRY helper to take constants or clone registers for binary operations
fn take_constants_or_clone(
fn get_arguments(
vm: &mut Vm,
instruction: Instruction,
position: Span,
) -> Result<(Value, &Value), VmError> {
) -> Result<(&Value, &Value), VmError> {
let left = if instruction.first_argument_is_constant() {
vm.chunk
.take_constant(instruction.first_argument(), position)?
.get_constant(instruction.first_argument(), position)?
} else {
vm.clone(instruction.first_argument(), position)?
vm.get(instruction.first_argument(), position)?
};
let right = if instruction.second_argument_is_constant() {
vm.chunk
@ -66,7 +66,7 @@ impl Vm {
Operation::Move => {
let from = instruction.first_argument();
let to = instruction.destination();
let value = self.clone(from, position)?;
let value = self.take(from, position)?;
self.insert(value, to, position)?;
}
@ -149,7 +149,7 @@ impl Vm {
self.insert(value, register_index, position)?;
}
Operation::Add => {
let (left, right) = take_constants_or_clone(self, instruction, position)?;
let (left, right) = get_arguments(self, instruction, position)?;
let sum = left
.add(right)
.map_err(|error| VmError::Value { error, position })?;
@ -157,7 +157,7 @@ impl Vm {
self.insert(sum, instruction.destination(), position)?;
}
Operation::Subtract => {
let (left, right) = take_constants_or_clone(self, instruction, position)?;
let (left, right) = get_arguments(self, instruction, position)?;
let difference = left
.subtract(right)
.map_err(|error| VmError::Value { error, position })?;
@ -165,7 +165,7 @@ impl Vm {
self.insert(difference, instruction.destination(), position)?;
}
Operation::Multiply => {
let (left, right) = take_constants_or_clone(self, instruction, position)?;
let (left, right) = get_arguments(self, instruction, position)?;
let product = left
.multiply(right)
.map_err(|error| VmError::Value { error, position })?;
@ -173,7 +173,7 @@ impl Vm {
self.insert(product, instruction.destination(), position)?;
}
Operation::Divide => {
let (left, right) = take_constants_or_clone(self, instruction, position)?;
let (left, right) = get_arguments(self, instruction, position)?;
let quotient = left
.divide(right)
.map_err(|error| VmError::Value { error, position })?;
@ -181,7 +181,7 @@ impl Vm {
self.insert(quotient, instruction.destination(), position)?;
}
Operation::Modulo => {
let (left, right) = take_constants_or_clone(self, instruction, position)?;
let (left, right) = get_arguments(self, instruction, position)?;
let remainder = left
.modulo(right)
.map_err(|error| VmError::Value { error, position })?;
@ -191,9 +191,9 @@ impl Vm {
Operation::Test => {
let register = instruction.destination();
let test_value = instruction.second_argument_as_boolean();
let value = self.clone(register, position)?;
let value = self.get(register, position)?;
let boolean = value.as_boolean().ok_or_else(|| VmError::ExpectedBoolean {
found: value,
found: value.clone(),
position,
})?;
@ -218,7 +218,7 @@ impl Vm {
}
}
Operation::Equal => {
let (left, right) = take_constants_or_clone(self, instruction, position)?;
let (left, right) = get_arguments(self, instruction, position)?;
let equal = left
.equal(right)
.map_err(|error| VmError::Value { error, position })?;
@ -231,27 +231,27 @@ impl Vm {
}
}
Operation::Less => {
let (left, right) = take_constants_or_clone(self, instruction, position)?;
let (left, right) = get_arguments(self, instruction, position)?;
let less = left
.less_than(right)
.map_err(|error| VmError::Value { error, position })?;
let compare_to = instruction.destination() != 0;
if let Some(boolean) = less.as_boolean() {
if boolean != compare_to {
if boolean == compare_to {
self.ip += 1;
}
}
}
Operation::LessEqual => {
let (left, right) = take_constants_or_clone(self, instruction, position)?;
let (left, right) = get_arguments(self, instruction, position)?;
let less_equal = left
.less_than_or_equal(right)
.map_err(|error| VmError::Value { error, position })?;
let compare_to = instruction.destination() != 0;
if let Some(boolean) = less_equal.as_boolean() {
if boolean != compare_to {
if boolean == compare_to {
self.ip += 1;
}
}
@ -259,9 +259,9 @@ impl Vm {
Operation::Negate => {
let value = if instruction.first_argument_is_constant() {
self.chunk
.take_constant(instruction.first_argument(), position)?
.get_constant(instruction.first_argument(), position)?
} else {
self.clone(instruction.first_argument(), position)?
self.get(instruction.first_argument(), position)?
};
let negated = value
.negate()
@ -272,9 +272,9 @@ impl Vm {
Operation::Not => {
let value = if instruction.first_argument_is_constant() {
self.chunk
.take_constant(instruction.first_argument(), position)?
.get_constant(instruction.first_argument(), position)?
} else {
self.clone(instruction.first_argument(), position)?
self.get(instruction.first_argument(), position)?
};
let not = value
.not()

View File

@ -1,5 +1,59 @@
use dust_lang::*;
#[test]
fn less_than() {
assert_eq!(run("1 < 2"), Ok(Some(Value::boolean(true))));
}
#[test]
fn greater_than() {
assert_eq!(run("1 > 2"), Ok(Some(Value::boolean(false))));
}
#[test]
fn less_than_or_equal() {
assert_eq!(run("1 <= 2"), Ok(Some(Value::boolean(true))));
assert_eq!(run("1 <= 1"), Ok(Some(Value::boolean(true))));
}
#[test]
fn greater_than_or_equal() {
assert_eq!(run("1 >= 2"), Ok(Some(Value::boolean(false))));
assert_eq!(run("1 >= 1"), Ok(Some(Value::boolean(true))));
}
#[test]
fn equal() {
assert_eq!(run("1 == 1"), Ok(Some(Value::boolean(true))));
}
#[test]
fn not_equal() {
assert_eq!(run("1 != 1"), Ok(Some(Value::boolean(false))));
}
#[test]
fn and() {
assert_eq!(run("true && true"), Ok(Some(Value::boolean(true))));
assert_eq!(run("true && false"), Ok(Some(Value::boolean(false))));
assert_eq!(run("false && true"), Ok(Some(Value::boolean(false))));
assert_eq!(run("false && false"), Ok(Some(Value::boolean(false))));
}
#[test]
fn or() {
assert_eq!(run("true || true"), Ok(Some(Value::boolean(true))));
assert_eq!(run("true || false"), Ok(Some(Value::boolean(true))));
assert_eq!(run("false || true"), Ok(Some(Value::boolean(true))));
assert_eq!(run("false || false"), Ok(Some(Value::boolean(false))));
}
#[test]
fn not() {
assert_eq!(run("!true"), Ok(Some(Value::boolean(false))));
assert_eq!(run("!false"), Ok(Some(Value::boolean(true))));
}
#[test]
fn long_math() {
assert_eq!(