mod common;
use grift_eval::*;
use common::{eval_to_string, eval_to_num, eval_is_false};
#[test]
fn test_member_callcc_not_found() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define member-cc
(lambda (x ls)
(call/cc
(lambda (break)
(do ((ls ls (cdr ls)))
((null? ls) #f)
(if (equal? x (car ls))
(break ls)))))))",
)
.unwrap();
assert!(eval_is_false(&lisp, &mut eval, "(member-cc 'd '(a b c))"));
}
#[test]
fn test_member_callcc_found() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define member-cc
(lambda (x ls)
(call/cc
(lambda (break)
(do ((ls ls (cdr ls)))
((null? ls) #f)
(if (equal? x (car ls))
(break ls)))))))",
)
.unwrap();
assert_eq!(
eval_to_string(&lisp, &mut eval, "(member-cc 'b '(a b c))"),
"(b c)"
);
}
#[test]
fn test_dynamic_wind_basic() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define log '())").unwrap();
let result = eval
.eval_str(
"(dynamic-wind
(lambda () (set! log (cons 'in log)))
(lambda () (set! log (cons 'body log)) 42)
(lambda () (set! log (cons 'out log))))",
)
.unwrap();
assert_eq!(lisp.get(result).unwrap().as_number(), Some(42));
assert_eq!(eval_to_string(&lisp, &mut eval, "log"), "(out body in)");
}
#[test]
fn test_unwind_protect() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define-syntax unwind-protect
(syntax-rules ()
((_ body cleanup ...)
(dynamic-wind
(lambda () #f)
(lambda () body)
(lambda () cleanup ...)))))",
)
.unwrap();
let result = eval
.eval_str(
"((call/cc
(let ((x 'a))
(lambda (k)
(unwind-protect
(k (lambda () x))
(set! x 'b))))))",
)
.unwrap();
assert!(lisp.symbol_matches(result, "b").unwrap());
}
#[test]
fn test_fluid_let_basic() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define-syntax fluid-let
(syntax-rules ()
((_ ((x v)) e1 e2 ...)
(let ((y v))
(let ((swap (lambda ()
(let ((t x))
(set! x y)
(set! y t)))))
(dynamic-wind
swap
(lambda () e1 e2 ...)
swap))))))",
)
.unwrap();
assert_eq!(
eval_to_num(
&lisp,
&mut eval,
"(let ((x 3))
(+ (fluid-let ((x 5))
x)
x))"
),
8
);
}
#[test]
fn test_fluid_let_callcc_revert() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define-syntax fluid-let
(syntax-rules ()
((_ ((x v)) e1 e2 ...)
(let ((y v))
(let ((swap (lambda ()
(let ((t x))
(set! x y)
(set! y t)))))
(dynamic-wind
swap
(lambda () e1 e2 ...)
swap))))))",
)
.unwrap();
assert_eq!(
eval_to_string(
&lisp,
&mut eval,
"(let ((x 'a))
(let ((f (lambda () x)))
(cons (call/cc
(lambda (k)
(fluid-let ((x 'b))
(f))))
(f))))"
),
"(b . a)"
);
}
#[test]
fn test_fluid_let_reenter() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define-syntax fluid-let
(syntax-rules ()
((_ ((x v)) e1 e2 ...)
(let ((y v))
(let ((swap (lambda ()
(let ((t x))
(set! x y)
(set! y t)))))
(dynamic-wind
swap
(lambda () e1 e2 ...)
swap))))))",
)
.unwrap();
eval.eval_str("(define reenter #f)").unwrap();
eval.eval_str("(define x 0)").unwrap();
assert_eq!(
eval_to_num(
&lisp,
&mut eval,
"(fluid-let ((x 1))
(call/cc (lambda (k) (set! reenter k)))
(set! x (+ x 1))
x)"
),
2
);
assert_eq!(eval_to_num(&lisp, &mut eval, "x"), 0);
assert_eq!(eval_to_num(&lisp, &mut eval, "(reenter '*)"), 3);
assert_eq!(eval_to_num(&lisp, &mut eval, "(reenter '*)"), 4);
assert_eq!(eval_to_num(&lisp, &mut eval, "x"), 0);
}
#[test]
fn test_delay_force_basic() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(
eval_to_num(&lisp, &mut eval, "(force (delay (+ 1 2)))"),
3
);
}
#[test]
fn test_delay_memoization() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define count 0)").unwrap();
eval.eval_str(
"(define p (delay (begin (set! count (+ count 1)) count)))",
)
.unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(force p)"), 1);
assert_eq!(eval_to_num(&lisp, &mut eval, "(force p)"), 1);
assert_eq!(eval_to_num(&lisp, &mut eval, "count"), 1);
}
#[test]
fn test_streams_basic() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define stream-car
(lambda (s)
(car (force s))))",
)
.unwrap();
eval.eval_str(
"(define stream-cdr
(lambda (s)
(cdr (force s))))",
)
.unwrap();
eval.eval_str(
"(define counters
(let next ((n 1))
(delay (cons n (next (+ n 1))))))",
)
.unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(stream-car counters)"), 1);
assert_eq!(
eval_to_num(&lisp, &mut eval, "(stream-car (stream-cdr counters))"),
2
);
}
#[test]
fn test_stream_add() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define stream-car
(lambda (s)
(car (force s))))",
)
.unwrap();
eval.eval_str(
"(define stream-cdr
(lambda (s)
(cdr (force s))))",
)
.unwrap();
eval.eval_str(
"(define counters
(let next ((n 1))
(delay (cons n (next (+ n 1))))))",
)
.unwrap();
eval.eval_str(
"(define stream-add
(lambda (s1 s2)
(delay (cons
(+ (stream-car s1) (stream-car s2))
(stream-add (stream-cdr s1) (stream-cdr s2))))))",
)
.unwrap();
eval.eval_str("(define even-counters (stream-add counters counters))")
.unwrap();
assert_eq!(
eval_to_num(&lisp, &mut eval, "(stream-car even-counters)"),
2
);
assert_eq!(
eval_to_num(
&lisp,
&mut eval,
"(stream-car (stream-cdr even-counters))"
),
4
);
}
#[test]
fn test_make_promise_force() {
let lisp: Lisp<30000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(
"(define make-promise
(lambda (p)
(let ((val #f) (set? #f))
(lambda ()
(if (not set?)
(let ((x (p)))
(if (not set?)
(begin (set! val x)
(set! set? #t)))))
val))))",
)
.unwrap();
eval.eval_str(
"(define my-force
(lambda (promise)
(promise)))",
)
.unwrap();
eval.eval_str(
"(define my-delay-val (make-promise (lambda () (+ 10 20))))",
)
.unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-force my-delay-val)"), 30);
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-force my-delay-val)"), 30);
}