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::*; 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] #[test]
fn not() { fn not() {
let source = "!true"; let source = "!true";

View File

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

View File

@ -1,5 +1,59 @@
use dust_lang::*; 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] #[test]
fn long_math() { fn long_math() {
assert_eq!( assert_eq!(