mod common;
use grift_eval::*;
use common::{eval_to_num, eval_is_true, eval_is_false};
#[test]
fn test_syntax_case_empty_pattern() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax always-42
(lambda (x)
(syntax-case x ()
((_) (syntax 42)))))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(always-42)"), 42);
}
#[test]
fn test_syntax_case_single_pattern() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax double
(lambda (stx)
(syntax-case stx ()
((_ x) (syntax (* x 2))))))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(double 5)"), 10);
assert_eq!(eval_to_num(&lisp, &mut eval, "(double (+ 1 2))"), 6);
}
#[test]
fn test_syntax_case_multiple_patterns() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax my-add
(lambda (stx)
(syntax-case stx ()
((_ a b) (syntax (+ a b))))))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-add 3 4)"), 7);
}
#[test]
fn test_syntax_case_multiple_clauses() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax my-add2
(lambda (stx)
(syntax-case stx ()
((_ a) (syntax a))
((_ a b) (syntax (+ a b)))
((_ a b c) (syntax (+ a b c))))))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-add2 5)"), 5);
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-add2 5 10)"), 15);
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-add2 5 10 15)"), 30);
}
#[test]
fn test_syntax_case_ellipsis() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax my-list
(lambda (stx)
(syntax-case stx ()
((_ x ...) (syntax (list x ...))))))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(length (my-list 1 2 3 4 5))"), 5);
assert_eq!(eval_to_num(&lisp, &mut eval, "(car (my-list 10 20 30))"), 10);
}
#[test]
fn test_syntax_case_nested_ellipsis() {
}
#[test]
fn test_syntax_case_with_literals() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax with-value
(lambda (stx)
(syntax-case stx (is)
((_ name is value) (syntax (let ((name value)) name))))))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(with-value x is 42)"), 42);
}
#[test]
fn test_let_syntax_basic() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, r#"
(let-syntax ((add1 (lambda (stx)
(syntax-case stx ()
((_ x) (syntax (+ x 1)))))))
(add1 10))
"#), 11);
}
#[test]
fn test_let_syntax_scoping() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define outer-value 100)").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, r#"
(let-syntax ((get-outer (lambda (stx)
(syntax-case stx ()
((_) (syntax outer-value))))))
(get-outer))
"#), 100);
}
#[test]
fn test_let_syntax_nested() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, r#"
(let-syntax ((outer (lambda (stx)
(syntax-case stx ()
((_ x) (syntax (* x 2)))))))
(let-syntax ((inner (lambda (stx)
(syntax-case stx ()
((_ x) (syntax (+ x 10)))))))
(outer (inner 5))))
"#), 30); }
#[test]
fn test_letrec_syntax_basic() {
}
#[test]
fn test_identifier_check() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
}
#[test]
fn test_define_syntax_top_level() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax square
(lambda (stx)
(syntax-case stx ()
((_ x) (syntax (* x x))))))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(square 5)"), 25);
assert_eq!(eval_to_num(&lisp, &mut eval, "(square (+ 1 2))"), 9);
}
#[test]
fn test_define_syntax_shadowing() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define inc (lambda (x) (+ x 1)))").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(inc 10)"), 11);
eval.eval_str(r#"
(define-syntax inc-macro
(lambda (stx)
(syntax-case stx ()
((_ x) (syntax (+ x 100))))))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(inc-macro 10)"), 110);
assert_eq!(eval_to_num(&lisp, &mut eval, "(inc 10)"), 11);
}
#[test]
fn test_macro_with_begin() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax do-both
(lambda (stx)
(syntax-case stx ()
((_ a b) (syntax (begin a b))))))
"#).unwrap();
eval.eval_str("(define x 0)").unwrap();
eval.eval_str("(do-both (set! x 10) (set! x (+ x 5)))").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "x"), 15);
}
#[test]
fn test_macro_with_lambda() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax make-adder
(lambda (stx)
(syntax-case stx ()
((_ n) (syntax (lambda (x) (+ x n)))))))
"#).unwrap();
eval.eval_str("(define add5 (make-adder 5))").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(add5 10)"), 15);
}
#[test]
fn test_macro_recursive_expansion() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert!(eval_is_true(&lisp, &mut eval, "(and #t #t #t)"));
assert!(eval_is_false(&lisp, &mut eval, "(and #t #f #t)"));
assert!(eval_is_true(&lisp, &mut eval, "(and)"));
}
#[test]
fn test_hygiene_basic() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax swap!
(lambda (stx)
(syntax-case stx ()
((_ a b)
(syntax (let ((temp a))
(set! a b)
(set! b temp)))))))
"#).unwrap();
eval.eval_str("(define temp 999)").unwrap();
eval.eval_str("(define x 1)").unwrap();
eval.eval_str("(define y 2)").unwrap();
eval.eval_str("(swap! x y)").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "x"), 2);
assert_eq!(eval_to_num(&lisp, &mut eval, "y"), 1);
assert_eq!(eval_to_num(&lisp, &mut eval, "temp"), 999);
}
#[test]
fn test_when_true() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define x 0)").unwrap();
eval.eval_str("(when #t (set! x 42))").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "x"), 42);
}
#[test]
fn test_when_false() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define x 0)").unwrap();
eval.eval_str("(when #f (set! x 42))").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "x"), 0);
}
#[test]
fn test_unless_true() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define x 0)").unwrap();
eval.eval_str("(unless #t (set! x 42))").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "x"), 0);
}
#[test]
fn test_unless_false() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define x 0)").unwrap();
eval.eval_str("(unless #f (set! x 42))").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "x"), 42);
}
#[test]
fn test_cond_first_true() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(cond (#t 1) (#f 2))"), 1);
}
#[test]
fn test_cond_second_true() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(cond (#f 1) (#t 2))"), 2);
}
#[test]
fn test_cond_else() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(cond (#f 1) (#f 2) (else 3))"), 3);
}
#[test]
fn test_cond_multiple_expressions() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define y 0)").unwrap();
eval.eval_str("(cond (#t (set! y 10) (set! y (+ y 5))))").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "y"), 15);
}
#[test]
fn test_case_single_datum() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(case 'a ((a) 1) ((b) 2))"), 1);
assert_eq!(eval_to_num(&lisp, &mut eval, "(case 'b ((a) 1) ((b) 2))"), 2);
}
#[test]
fn test_case_multiple_data() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(case 'b ((a b c) 1) ((d e) 2))"), 1);
assert_eq!(eval_to_num(&lisp, &mut eval, "(case 'e ((a b c) 1) ((d e) 2))"), 2);
}
#[test]
fn test_case_else() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(case 'z ((a) 1) ((b) 2) (else 99))"), 99);
}
#[test]
fn test_do_basic() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
let result = eval.eval_str(r#"
(do ((i 1 (+ i 1))
(sum 0 (+ sum i)))
((> i 5) sum))
"#).unwrap();
assert_eq!(lisp.get(result).unwrap().as_number(), Some(15));
}
#[test]
fn test_do_with_body() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str("(define counter 0)").unwrap();
eval.eval_str(r#"
(do ((i 0 (+ i 1)))
((>= i 3) counter)
(set! counter (+ counter 1)))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "counter"), 3);
}
#[test]
fn test_define_syntax_shorthand_form() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax (my-ten stx)
(syntax-case stx ()
((_) #'10)))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-ten)"), 10);
}
#[test]
fn test_define_syntax_shorthand_multiple_clauses() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax (my-val stx)
(syntax-case stx (foo)
((_) #'10)
((_ (foo)) #'67)))
"#).unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-val)"), 10);
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-val (foo))"), 67);
}
#[test]
fn test_nested_define_syntax_via_syntax_rules() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax make-macro3
(syntax-rules (foo bar baz)
((_ name)
(define-syntax name
(syntax-rules (foo bar baz)
((_) 100))))))
"#).unwrap();
eval.eval_str("(make-macro3 my-hundred)").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-hundred)"), 100);
}
#[test]
fn test_nested_define_syntax_shorthand_via_syntax_rules() {
let lisp: Lisp<20000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax make-macro4
(syntax-rules ()
((_ name)
(define-syntax (name stx)
(syntax-case stx (foo bar baz)
((_) #'10)
((_ (foo)) #'67))))))
"#).unwrap();
eval.eval_str("(make-macro4 my-bar)").unwrap();
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-bar)"), 10);
assert_eq!(eval_to_num(&lisp, &mut eval, "(my-bar (foo))"), 67);
}