talc/talc-lang/tests/vm.rs
2024-11-14 14:16:33 -05:00

130 lines
2.5 KiB
Rust

use std::rc::Rc;
use talc_lang::{compiler::compile, optimize::optimize, parser, value::Value, vm::Vm};
fn assert_eval(src: &str, value: Value) {
let mut ex = parser::parse(src).expect(&format!("failed to parse expression"));
optimize(&mut ex);
let f = compile(&ex, None).expect("failed to compile expression");
let f = Rc::new(f);
let mut vm = Vm::new(16, Vec::new());
let res = vm
.run_function(f.clone(), vec![f.into()])
.expect("vm produced an exception");
assert_eq!(
res.get_type().name(),
value.get_type().name(),
"result and target types differ"
);
assert_eq!(res, value, "result and target differ");
}
#[test]
fn scope() {
assert_eval(
"
var x = 7
var y = 10
do
var x = 200
y = 100
end
x + y
",
Value::Int(7 + 100),
);
assert_eval(
"
var cond = true
var z = 2
if cond then var z = 5 else var z = 6 end
z
",
Value::Int(2),
);
assert_eval(
"
var i = 55
var j = 66
for i in 0..10 do
j = i
end
i + j
",
Value::Int(55 + 9),
);
}
#[test]
fn forloop() {
assert_eval(
"
sum = 0
for i in 0..5 do
for j in 0..10 do
sum += i*j
end
end
sum
",
Value::Int(45 * 10),
);
assert_eval(
"
map = {a=3, b=2, c=4, d=7}
prod = 1
for k in map do
prod *= map[k]
end
prod
",
Value::Int(3 * 2 * 4 * 7),
);
}
#[test]
fn closures() {
assert_eval(
"
var x = 2
next = \\. do x = x * 2 + 1 end
next() + next() + next()
",
Value::Int(5 + 11 + 23),
);
assert_eval(
"
var x = 0
fn outer(n) do
fn inner() do
x += n
n += 1
x
end
end
var f = outer(2)
var g = outer(6)
f() + f() + g() + g() + f()
",
Value::Int(2 + 5 + 11 + 18 + 22),
);
}
#[test]
fn tailcall() {
assert_eval(
"
fn test(n, a) do
if n <= 0 then
a
else
self(n-1, n+a)
end
end
test(24, 0)
",
Value::Int(300),
) // = 24 + 23 + ... + 1
}