mod common;
use grift_eval::*;
use common::{eval_to_string, eval_to_num};
#[test]
fn test_or_hygiene_rebound_if() {
let lisp: Lisp<50000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
let result = eval_to_string(&lisp, &mut eval, r#"
(let ((if #f))
(let ((t 'okay))
(or if t)))
"#);
assert_eq!(result, "okay");
}
#[test]
fn test_dolet_hygiene_returns_7() {
let lisp: Lisp<50000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
let result = eval_to_num(&lisp, &mut eval, r#"
(let-syntax ((dolet (lambda (x)
(syntax-case x ()
((_ b)
(syntax (let ((a 3) (b 4))
(+ a b))))))))
(dolet a))
"#);
assert_eq!(result, 7);
}
#[test]
fn test_identifier_syntax_basic() {
let lisp: Lisp<50000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax my-val
(identifier-syntax 42))
"#).unwrap();
let result = eval_to_num(&lisp, &mut eval, "my-val");
assert_eq!(result, 42);
}
#[test]
fn test_named_let_via_syntax_rules() {
let lisp: Lisp<50000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax rec
(syntax-rules ()
((_ x e) (letrec ((x e)) x))))
"#).unwrap();
eval.eval_str(r#"
(define-syntax my-let2
(syntax-rules ()
((_ ((x v) ...) e1 e2 ...)
((lambda (x ...) e1 e2 ...) v ...))
((_ f ((x v) ...) e1 e2 ...)
((rec f (lambda (x ...) e1 e2 ...)) v ...))))
"#).unwrap();
let r1 = eval_to_num(&lisp, &mut eval, "(my-let2 ((a 1) (b 2)) (+ a b))");
assert_eq!(r1, 3);
let r2 = eval_to_num(&lisp, &mut eval, r#"
(my-let2 loop ((i 0) (sum 0))
(if (= i 5) sum (loop (+ i 1) (+ sum i))))
"#);
assert_eq!(r2, 10);
}
#[test]
fn test_cond_bound_else_not_matched() {
let lisp: Lisp<50000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
let result = eval_to_string(&lisp, &mut eval, r#"
(let ((else #f))
(cond (else 42)))
"#);
assert_eq!(result, "#f");
}
#[test]
fn test_identifier_syntax_with_set() {
let lisp: Lisp<80000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
let result = eval_to_string(&lisp, &mut eval, r#"
(let ((x 0))
(define-syntax x++
(identifier-syntax
(let ((t x)) (set! x (+ t 1)) t)))
(let ((a x++))
(list a x)))
"#);
assert_eq!(result, "(0 1)");
}
#[test]
fn test_redefined_cond_free_identifier_eq() {
let lisp: Lisp<50000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();
eval.eval_str(r#"
(define-syntax my-cond
(lambda (x)
(syntax-case x ()
((_ (e0 e1 e2 ...))
(and (identifier? (syntax e0))
(free-identifier=? (syntax e0) (syntax else)))
(syntax (begin e1 e2 ...)))
((_ (e0 e1 e2 ...)) (syntax (if e0 (begin e1 e2 ...))))
((_ (e0 e1 e2 ...) c1 c2 ...)
(syntax (if e0 (begin e1 e2 ...) (my-cond c1 c2 ...)))))))
"#).unwrap();
let result = eval_to_string(&lisp, &mut eval, "(my-cond (else 42))");
assert_eq!(result, "42");
let result = eval_to_string(&lisp, &mut eval, r#"
(let ((else #f))
(my-cond (else 42)))
"#);
assert_eq!(result, "#f",
"locally bound else should NOT match the else keyword in free-identifier=?");
}