use super::*;
use crate::stack::push;
unsafe extern "C" fn pred_always_true(stack: Stack) -> Stack {
unsafe { push(stack, Value::Bool(true)) }
}
unsafe extern "C" fn pred_always_false(stack: Stack) -> Stack {
unsafe { push(stack, Value::Bool(false)) }
}
unsafe extern "C" fn pred_is_zero(stack: Stack) -> Stack {
unsafe {
let val = crate::stack::peek(stack);
match val {
Value::Int(n) => push(stack, Value::Bool(n == 0)),
_ => panic!("pred_is_zero: expected Int"),
}
}
}
unsafe extern "C" fn pred_is_negative(stack: Stack) -> Stack {
unsafe {
let val = crate::stack::peek(stack);
match val {
Value::Int(n) => push(stack, Value::Bool(n < 0)),
_ => panic!("pred_is_negative: expected Int"),
}
}
}
unsafe extern "C" fn body_matched(stack: Stack) -> Stack {
unsafe {
let (stack, _) = pop(stack);
push(
stack,
Value::String(crate::seqstring::global_string("matched".to_string())),
)
}
}
unsafe extern "C" fn body_zero(stack: Stack) -> Stack {
unsafe {
let (stack, _) = pop(stack);
push(
stack,
Value::String(crate::seqstring::global_string("zero".to_string())),
)
}
}
unsafe extern "C" fn body_positive(stack: Stack) -> Stack {
unsafe {
let (stack, _) = pop(stack);
push(
stack,
Value::String(crate::seqstring::global_string("positive".to_string())),
)
}
}
unsafe extern "C" fn body_negative(stack: Stack) -> Stack {
unsafe {
let (stack, _) = pop(stack);
push(
stack,
Value::String(crate::seqstring::global_string("negative".to_string())),
)
}
}
unsafe extern "C" fn body_default(stack: Stack) -> Stack {
unsafe {
let (stack, _) = pop(stack);
push(
stack,
Value::String(crate::seqstring::global_string("default".to_string())),
)
}
}
fn make_quotation(f: unsafe extern "C" fn(Stack) -> Stack) -> Value {
let ptr = f as *const () as usize;
Value::Quotation {
wrapper: ptr,
impl_: ptr,
}
}
#[test]
fn test_cond_single_match() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(42)); let stack = push(stack, make_quotation(pred_always_true));
let stack = push(stack, make_quotation(body_matched));
let stack = push(stack, Value::Int(1));
let stack = cond(stack);
let (_, result) = pop(stack);
match result {
Value::String(s) => assert_eq!(s.as_str(), "matched"),
_ => panic!("Expected String, got {:?}", result),
}
}
}
#[test]
fn test_cond_first_match_wins() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(42)); let stack = push(stack, make_quotation(pred_always_true));
let stack = push(stack, make_quotation(body_matched)); let stack = push(stack, make_quotation(pred_always_true));
let stack = push(stack, make_quotation(body_default)); let stack = push(stack, Value::Int(2));
let stack = cond(stack);
let (_, result) = pop(stack);
match result {
Value::String(s) => assert_eq!(s.as_str(), "matched"), _ => panic!("Expected String, got {:?}", result),
}
}
}
#[test]
fn test_cond_second_match() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(42)); let stack = push(stack, make_quotation(pred_always_false));
let stack = push(stack, make_quotation(body_matched)); let stack = push(stack, make_quotation(pred_always_true));
let stack = push(stack, make_quotation(body_default)); let stack = push(stack, Value::Int(2));
let stack = cond(stack);
let (_, result) = pop(stack);
match result {
Value::String(s) => assert_eq!(s.as_str(), "default"), _ => panic!("Expected String, got {:?}", result),
}
}
}
#[test]
fn test_cond_classify_number() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(-5)); let stack = push(stack, make_quotation(pred_is_negative));
let stack = push(stack, make_quotation(body_negative));
let stack = push(stack, make_quotation(pred_is_zero));
let stack = push(stack, make_quotation(body_zero));
let stack = push(stack, make_quotation(pred_always_true)); let stack = push(stack, make_quotation(body_positive));
let stack = push(stack, Value::Int(3));
let stack = cond(stack);
let (_, result) = pop(stack);
match result {
Value::String(s) => assert_eq!(s.as_str(), "negative"),
_ => panic!("Expected String"),
}
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(0)); let stack = push(stack, make_quotation(pred_is_negative));
let stack = push(stack, make_quotation(body_negative));
let stack = push(stack, make_quotation(pred_is_zero));
let stack = push(stack, make_quotation(body_zero));
let stack = push(stack, make_quotation(pred_always_true)); let stack = push(stack, make_quotation(body_positive));
let stack = push(stack, Value::Int(3));
let stack = cond(stack);
let (_, result) = pop(stack);
match result {
Value::String(s) => assert_eq!(s.as_str(), "zero"),
_ => panic!("Expected String"),
}
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(42)); let stack = push(stack, make_quotation(pred_is_negative));
let stack = push(stack, make_quotation(body_negative));
let stack = push(stack, make_quotation(pred_is_zero));
let stack = push(stack, make_quotation(body_zero));
let stack = push(stack, make_quotation(pred_always_true)); let stack = push(stack, make_quotation(body_positive));
let stack = push(stack, Value::Int(3));
let stack = cond(stack);
let (_, result) = pop(stack);
match result {
Value::String(s) => assert_eq!(s.as_str(), "positive"),
_ => panic!("Expected String"),
}
}
}