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