Add and pass tests
This commit is contained in:
parent
182ef66f23
commit
9fe3e440ac
@ -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";
|
||||
|
@ -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()
|
||||
|
@ -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!(
|
||||
|
Loading…
Reference in New Issue
Block a user