1
0
dust/tests/interpret.rs

535 lines
12 KiB
Rust
Raw Permalink Normal View History

2023-12-30 03:26:37 +00:00
mod assignment {
use dust_lang::*;
#[test]
fn simple_assignment() {
let test = interpret("x = 1 x");
assert_eq!(Ok(Value::Integer(1)), test);
}
#[test]
fn simple_assignment_with_type() {
let test = interpret("x <int> = 1 x");
assert_eq!(Ok(Value::Integer(1)), test);
}
#[test]
fn list_add_assign() {
let test = interpret(
"
x <[int]> = []
x += 1
x
",
);
assert_eq!(
Ok(Value::List(List::with_items(vec![Value::Integer(1)]))),
test
);
}
#[test]
fn list_add_wrong_type() {
let result = interpret(
"
x <[str]> = []
x += 1
",
);
assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck {
expected: Type::String,
actual: Type::Integer
}))
}
}
2023-12-31 13:36:39 +00:00
mod for_loop {
use dust_lang::*;
#[test]
fn simple_for_loop() {
let result = interpret("for i in [1 2 3] { output(i) }");
assert_eq!(Ok(Value::none()), result);
}
#[test]
fn modify_value() {
let result = interpret(
"
list = []
for i in [1 2 3] { list += i }
list
",
);
assert_eq!(
Ok(Value::List(List::with_items(vec![
Value::Integer(1),
Value::Integer(2),
Value::Integer(3),
]))),
result
);
}
#[test]
fn async_modify_value() {
let result = interpret(
"
list = []
async for i in [1 2 3] { list += i }
length(list)
",
);
assert_eq!(Ok(Value::Integer(3)), result);
}
2023-12-31 13:36:39 +00:00
}
2023-12-30 03:26:37 +00:00
mod logic {
use dust_lang::*;
#[test]
fn complex_logic_sequence() {
let result =
interpret("(length([0]) == 1) && (length([0 0]) == 2) && (length([0 0 0]) == 3)");
assert_eq!(Ok(Value::Boolean(true)), result);
}
}
mod value {
use dust_lang::*;
#[test]
fn empty() {
2023-12-30 03:26:37 +00:00
assert_eq!(interpret("x = 9"), Ok(Value::Option(None)));
assert_eq!(interpret("x = 1 + 1"), Ok(Value::Option(None)));
}
#[test]
fn integer() {
2023-12-30 03:26:37 +00:00
assert_eq!(interpret("1"), Ok(Value::Integer(1)));
assert_eq!(interpret("123"), Ok(Value::Integer(123)));
assert_eq!(interpret("-666"), Ok(Value::Integer(-666)));
}
#[test]
fn float() {
2023-12-30 03:26:37 +00:00
assert_eq!(interpret("0.1"), Ok(Value::Float(0.1)));
assert_eq!(interpret("12.3"), Ok(Value::Float(12.3)));
assert_eq!(interpret("-6.66"), Ok(Value::Float(-6.66)));
}
#[test]
fn string() {
assert_eq!(interpret("\"one\""), Ok(Value::string("one".to_string())));
assert_eq!(interpret("'one'"), Ok(Value::string("one".to_string())));
assert_eq!(interpret("`one`"), Ok(Value::string("one".to_string())));
assert_eq!(interpret("`'one'`"), Ok(Value::string("'one'".to_string())));
assert_eq!(interpret("'`one`'"), Ok(Value::string("`one`".to_string())));
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret("\"'one'\""),
Ok(Value::string("'one'".to_string()))
2023-12-30 03:26:37 +00:00
);
}
#[test]
fn list() {
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret("[1, 2, 'foobar']"),
Ok(Value::List(List::with_items(vec![
Value::Integer(1),
Value::Integer(2),
Value::string("foobar".to_string()),
2023-12-30 03:26:37 +00:00
])))
);
}
#[test]
fn map() {
let mut map = Map::new();
2023-12-30 03:26:37 +00:00
map.set("x".to_string(), Value::Integer(1), None);
map.set("foo".to_string(), Value::string("bar".to_string()), None);
2023-12-30 03:26:37 +00:00
assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
}
#[test]
fn map_types() {
let mut map = Map::new();
2023-12-30 03:26:37 +00:00
map.set("x".to_string(), Value::Integer(1), Some(Type::Integer));
2023-12-30 03:26:37 +00:00
map.set(
"foo".to_string(),
Value::string("bar".to_string()),
2023-12-30 03:26:37 +00:00
Some(Type::String),
);
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret("{ x <int> = 1, foo <str> = 'bar' }"),
Ok(Value::Map(map))
);
}
#[test]
fn map_type_errors() {
2023-12-30 03:26:37 +00:00
assert!(interpret("{ foo <bool> = 'bar' }")
.unwrap_err()
.is_type_check_error(&Error::TypeCheck {
expected: Type::Boolean,
actual: Type::String
}))
}
#[test]
fn function() {
let result = interpret("() <int> { 1 }");
2023-12-30 03:26:37 +00:00
let value = result.unwrap();
let function = value.as_function().unwrap();
2024-01-01 09:59:27 +00:00
let function = if let Function::ContextDefined(function) = function {
function
} else {
panic!("Something is wrong with this test...");
};
2023-12-30 03:26:37 +00:00
assert_eq!(&Vec::<Identifier>::with_capacity(0), function.parameters());
2023-12-31 13:36:39 +00:00
assert_eq!(&Type::Integer, function.return_type());
2023-12-30 03:26:37 +00:00
let result = interpret("(x <bool>) <bool> { true }");
2023-12-30 03:26:37 +00:00
let value = result.unwrap();
let function = value.as_function().unwrap();
2024-01-01 09:59:27 +00:00
let function = if let Function::ContextDefined(function) = function {
function
} else {
panic!("Something is wrong with this test...");
};
2023-12-30 03:26:37 +00:00
assert_eq!(
&vec![Identifier::new("x".to_string())],
function.parameters()
);
2023-12-31 13:36:39 +00:00
assert_eq!(&Type::Boolean, function.return_type());
2023-12-30 03:26:37 +00:00
}
#[test]
fn option() {
2023-12-30 03:26:37 +00:00
let result = interpret("x <option(int)> = some(1); x").unwrap();
assert_eq!(Value::Option(Some(Box::new(Value::Integer(1)))), result);
}
}
mod function_call {
use dust_lang::*;
#[test]
fn function_call() {
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret(
"
foobar = (message <str>) <str> { message }
2023-12-30 03:26:37 +00:00
foobar('Hiya')
",
),
Ok(Value::string("Hiya".to_string()))
2023-12-30 03:26:37 +00:00
);
}
#[test]
fn call_empty_function() {
assert_eq!(
interpret(
"
foobar = (message <str>) <none> {}
foobar('Hiya')
",
),
Ok(Value::none())
);
}
#[test]
fn callback() {
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret(
"
foobar = (cb <() -> str>) <str> {
cb()
}
foobar(() <str> { 'Hiya' })
",
),
Ok(Value::string("Hiya".to_string()))
2023-12-30 03:26:37 +00:00
);
}
#[test]
fn built_in_function_call() {
2023-12-30 03:26:37 +00:00
assert_eq!(interpret("output('Hiya')"), Ok(Value::Option(None)));
}
}
mod if_else {
use dust_lang::*;
#[test]
fn r#if() {
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret("if true { 'true' }"),
Ok(Value::string("true".to_string()))
2023-12-30 03:26:37 +00:00
);
}
#[test]
fn if_else() {
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret("if false { 1 } else { 2 }"),
Ok(Value::Integer(2))
);
assert_eq!(
interpret("if true { 1.0 } else { 42.0 }"),
Ok(Value::Float(1.0))
);
}
#[test]
fn if_else_else_if_else() {
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret(
"
if false {
'no'
} else if 1 + 1 == 3 {
'nope'
} else {
'ok'
}
"
),
Ok(Value::string("ok".to_string()))
2023-12-30 03:26:37 +00:00
);
}
#[test]
fn if_else_if_else_if_else_if_else() {
2023-12-30 03:26:37 +00:00
assert_eq!(
interpret(
"
if false {
'no'
} else if 1 + 1 == 1 {
'nope'
} else if 9 / 2 == 4 {
'nope'
} else if 'foo' == 'bar' {
'nope'
} else {
'ok'
}
"
),
Ok(Value::string("ok".to_string()))
2023-12-30 03:26:37 +00:00
);
}
}
mod index {
use dust_lang::*;
#[test]
fn list_index() {
let test = interpret("x = [1 [2] 3] x:1:0").unwrap();
assert_eq!(Value::Integer(2), test);
}
#[test]
fn map_index() {
let test = interpret("x = {y = {z = 2}} x:y:z").unwrap();
assert_eq!(Value::Integer(2), test);
}
#[test]
2024-01-01 02:46:45 +00:00
fn index_function_calls() {
assert_eq!(
interpret(
"
x = [1 2 3]
y = () <int> { 2 }
x:(y())
2024-01-01 02:46:45 +00:00
",
),
Ok(Value::Integer(3))
);
2023-12-30 03:26:37 +00:00
2024-01-01 02:46:45 +00:00
assert_eq!(
interpret(
"
x = {
y = () <int> { 2 }
}
x:y()
2024-01-01 02:46:45 +00:00
",
),
Ok(Value::Integer(2))
);
2023-12-30 03:26:37 +00:00
}
}
mod r#match {
use dust_lang::*;
#[test]
fn r#match() {
2023-12-30 03:26:37 +00:00
let test = interpret(
"
match 1 {
3 => false
2 => { false }
1 => true
}
",
)
.unwrap();
assert_eq!(Value::Boolean(true), test);
}
#[test]
fn match_assignment() {
2023-12-30 03:26:37 +00:00
let test = interpret(
"
x = match 1 {
3 => false
2 => { false }
1 => true
}
x
",
)
.unwrap();
assert_eq!(Value::Boolean(true), test);
}
}
mod r#while {
use dust_lang::*;
#[test]
fn while_loop() {
2023-12-30 03:26:37 +00:00
assert_eq!(interpret("while false { 'foo' }"), Ok(Value::Option(None)))
}
#[test]
fn while_loop_iteration_count() {
assert_eq!(
interpret("i = 0; while i < 3 { i += 1 }; i"),
Ok(Value::Integer(3))
)
}
}
mod type_definition {
use dust_lang::*;
#[test]
fn simple_type_check() {
let result = interpret("x <bool> = 1");
assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck {
expected: Type::Boolean,
actual: Type::Integer
}));
}
#[test]
fn callback_type_check() {
let result = interpret(
"
x = (cb <() -> bool>) <bool> {
cb()
}
x(() <int> { 1 })
",
);
assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck {
expected: Type::Function {
parameter_types: vec![],
return_type: Box::new(Type::Boolean),
},
actual: Type::Function {
parameter_types: vec![],
return_type: Box::new(Type::Integer),
},
}));
}
}
2023-12-31 19:04:10 +00:00
mod blocks {
use dust_lang::*;
#[test]
fn simple() {
assert_eq!(interpret("{ 1 }"), Ok(Value::Integer(1)));
}
#[test]
fn nested() {
assert_eq!(interpret("{ 1 { 1 + 1 } }"), Ok(Value::Integer(2)));
}
#[test]
fn with_return() {
assert_eq!(interpret("{ return 1; 1 + 1; }"), Ok(Value::Integer(1)));
}
#[test]
fn async_with_return() {
assert_eq!(
interpret(
"
async {
return 1
1 + 1
3
}
"
),
Ok(Value::Integer(1))
);
}
#[test]
fn root_returns_like_block() {
assert_eq!(
interpret(
"
return 1
1 + 1
3
"
),
Ok(Value::Integer(1))
);
}
2023-12-31 19:04:10 +00:00
}
2024-01-01 09:59:27 +00:00
2024-01-01 12:46:47 +00:00
mod built_in_values {
2024-01-01 09:59:27 +00:00
use dust_lang::*;
#[test]
2024-01-01 12:46:47 +00:00
fn args() {
assert!(interpret("args").is_ok_and(|value| value.is_list()));
2024-01-01 09:59:27 +00:00
}
}