use rune_interp::eval;
use rune_lower::lower;
use rune_parse::parse;
use rune_subject::Subject;
fn run(src: &str) -> u64 {
let expr = parse(src).unwrap_or_else(|e| panic!("parse error in {:?}: {}", src, e.message));
let formula = lower(expr).unwrap_or_else(|e| panic!("lower error in {:?}: {}", src, e.message));
let subject = Subject::minimal().to_noun();
let result = eval(&subject, &formula)
.unwrap_or_else(|e| panic!("eval error in {:?}: {}", src, e.message));
match result {
rune_ast::Noun::Atom(n) => n,
_ => panic!("expected atom result for {:?}, got cell", src),
}
}
fn run_against(src: &str, subject: &rune_ast::Noun) -> u64 {
let expr = parse(src).unwrap_or_else(|e| panic!("parse error in {:?}: {}", src, e.message));
let formula = lower(expr).unwrap_or_else(|e| panic!("lower error in {:?}: {}", src, e.message));
match eval(subject, &formula).unwrap_or_else(|e| panic!("eval error in {:?}: {}", src, e.message)) {
rune_ast::Noun::Atom(n) => n,
_ => panic!("expected atom result for {:?}", src),
}
}
#[test]
fn literal_42() {
assert_eq!(run("42"), 42);
}
#[test]
fn tilde_self_reads_the_self_slot() {
let mut s = Subject::minimal();
s.self_neuron = rune_ast::Noun::Atom(99);
assert_eq!(run_against("~self", &s.to_noun()), 99);
}
#[test]
fn address_scries_world_for_its_value() {
let mut s = Subject::minimal();
s.world = rune_subject::world(&[("cyber/truth", rune_ast::Noun::Atom(42))]);
assert_eq!(run_against("#cyber/truth", &s.to_noun()), 42);
}
#[test]
fn address_miss_returns_zero() {
let mut s = Subject::minimal();
s.world = rune_subject::world(&[("cyber/truth", rune_ast::Noun::Atom(42))]);
assert_eq!(run_against("#cyber/rune", &s.to_noun()), 0);
}
#[test]
fn add_5_plus_3() {
assert_eq!(run("5 + 3"), 8);
}
#[test]
fn mul_6_times_7() {
assert_eq!(run("6 * 7"), 42);
}
#[test]
fn let_x_equals_10() {
assert_eq!(run("let x = 10; x"), 10);
}
#[test]
fn if_zero_eq_zero_takes_yes() {
assert_eq!(run("if 0 == 0 { 1 } else { 2 }"), 1);
}
#[test]
fn gate_call_single_arg() {
assert_eq!(run("let double = fn(x) { x * 2 }; double(5)"), 10);
}
#[test]
fn gate_call_two_args() {
assert_eq!(run("let add_pair = fn(x, y) { x + y }; add_pair(3, 4)"), 7);
}
#[test]
fn closure_captures_outer_var() {
assert_eq!(run("let x = 10; let add_x = fn(y) { x + y }; add_x(5)"), 15);
}
#[test]
fn double_function() {
assert_eq!(run("let double = fn(x) { x * 2 }; double(5)"), 10);
}
#[test]
fn fibonacci_10() {
let src = r#"
let fib = fn(n) {
let a = 0;
let b = 1;
let i = 0;
loop {
if i == n {
a
} else {
let next_b = a + b;
rebind a = b;
rebind b = next_b;
rebind i = i + 1;
continue
}
}
};
fib(10)
"#;
assert_eq!(run(src), 55);
}
#[test]
fn factorial_5() {
let src = r#"
let factorial = fn(n) {
let acc = 1;
let i = 1;
loop {
if i > n {
acc
} else {
rebind acc = acc * i;
rebind i = i + 1;
continue
}
}
};
factorial(5)
"#;
assert_eq!(run(src), 120);
}
#[test]
fn lte_operator() {
assert_eq!(run("3 <= 5"), 0);
assert_eq!(run("5 <= 3"), 1);
assert_eq!(run("3 <= 3"), 0);
}
#[test]
fn gte_operator() {
assert_eq!(run("5 >= 3"), 0);
assert_eq!(run("3 >= 5"), 1);
assert_eq!(run("3 >= 3"), 0);
}
#[test]
fn door_arm_call_no_args() {
let src = "let counter = impl { fn get(self) { 42 } }; counter.get()";
assert_eq!(run(src), 42);
}
#[test]
fn door_arm_call_with_arg() {
let src = "let calc = impl { fn double(self, x) { x * 2 } }; calc.double(5)";
assert_eq!(run(src), 10);
}