(in-package :cl-user)
(defpackage :quasiquote-2.0-tests
(:use :cl :quasiquote-2.0 :fiveam)
(:export #:run-tests))
(in-package :quasiquote-2.0-tests)
(def-suite quasiquote-2.0)
(in-suite quasiquote-2.0)
(defun run-tests ()
(let ((results (run 'quasiquote-2.0)))
(fiveam:explain! results)
(unless (fiveam:results-status results)
(error "Tests failed."))))
(test basic
(is (equal '(nil :just-quote-it!) (multiple-value-list (%codewalk-dig-form '(dig nil)))))
(is (equal '(nil :just-form-it!) (multiple-value-list (%codewalk-dig-form '(dig (inject a))))))
(is (equal '(nil :just-form-it!) (multiple-value-list (%codewalk-dig-form '(dig 2 (inject 2 a))))))
(is (equal '(((((inject b) c (inject d)) car cdr car) (((inject d)) car cdr cdr cdr car)) nil)
(multiple-value-list (%codewalk-dig-form '(dig (a (inject b) c (inject d)))))))
(is (equal '(nil nil)
(multiple-value-list (%codewalk-dig-form '(dig (dig (a (inject b) c (inject d))))))))
(is (equal '(((((inject 2 d)) car cdr cdr cdr car cdr car)) nil)
(multiple-value-list (%codewalk-dig-form '(dig (dig (a (inject b) c (inject 2 d)))))))))
(test transform
(is (equal '(quote a) (transform-dig-form '(dig a))))
(is (equal '(quote a) (transform-dig-form '(dig 2 a))))
(is (equal 'a (transform-dig-form '(dig (inject a)))))
(is (equal 'a (transform-dig-form '(dig 2 (inject 2 a))))))
(defun foo (b d)
(dig (a (inject b) c (inject d))))
(defun foo1-transparent (x)
(declare (ignorable x))
(dig (dig (a (inject (b (inject x) c))))))
(defun foo1-opaque (x)
(declare (ignorable x))
(dig (dig (a (oinject (b (inject x) c))))))
(defun foo-recursive (x y)
(dig (a (inject (list x (dig (c (inject y))))))))
(test foos
(is (equal '(a 1 c 2) (foo 1 2)))
(is (equal '(a 100 c 200) (foo 100 200))))
(test opaque-vs-transparent
(is (equal '(quote a) (transform-dig-form '(odig a))))
(is (equal '(quote a) (transform-dig-form '(odig 2 a))))
(is (equal 'a (transform-dig-form '(odig (inject a)))))
(is (equal 'a (transform-dig-form '(odig 2 (inject 2 a)))))
(is (equal '(odig (inject 2 a)) (eval (transform-dig-form '(dig (odig (inject 2 a)))))))
(is (equal '(dig (a (inject (b 3 c)))) (foo1-transparent 3)))
(is (equal '(dig (a (oinject (b (inject x) c)))) (foo1-opaque 3))))
(test recursive-compile-time
(is (equal '(a (1 (c 2))) (foo-recursive 1 2))))
(test splicing
(is (equal '(a b c d) (eval (transform-dig-form '(dig (a (splice '(b c)) d))))))
(is (equal '(b c d) (eval (transform-dig-form '(dig ((splice '(b c)) d))))))
(is (equal '(a b c) (eval (transform-dig-form '(dig (a (splice '(b c))))))))
(is (equal '(a b) (eval (transform-dig-form '(dig (a (splice nil) b))))))
(is (equal '(b) (eval (transform-dig-form '(dig ((splice nil) b))))))
(is (equal '(a) (eval (transform-dig-form '(dig (a (splice nil)))))))
(is (equal '() (eval (transform-dig-form '(dig ((splice nil)))))))
(is (equal '(a b) (eval (transform-dig-form '(dig ((splice '(a b)))))))))
(test are-they-macro
(is (not (equal '(dig (a b)) (macroexpand-1 '(dig (a b))))))
(is (not (equal '(odig (a b)) (macroexpand-1 '(odig (a b)))))))
(defmacro triple-var (x)
`((inject ,x) (inject ,x) (inject ,x)))
(test correct-order-of-effects
(is (equal '(a 1 2 3) (let ((x 0))
(dig (a (inject (incf x)) (inject (incf x)) (inject (incf x)))))))
(is (equal '(a (((1))) 2)
(let ((x 0))
(dig (a ((((inject (incf x))))) (inject (incf x))))))))
(test macro-injects
(is (equal '(a (3 3 3)) (let ((x 3))
(dig (a (macro-inject (triple-var x)))))))
(is (equal '(a (1 2 3)) (let ((x 0))
(dig (a (macro-inject (triple-var (incf x))))))))
(macrolet ((frob (form n)
(mapcar (lambda (x)
`(inject ,x))
(make-list n :initial-element form)))
(frob1 (form)
`(frob ,form 4)))
(is (equal '(a (1 2 3 4 5))
(let ((x 0))
(dig (a (macro-inject (frob (incf x) 5)))))))
(is (equal '(a 1 2 3 4 5)
(let ((x 0))
(dig (a (macro-splice (frob (incf x) 5)))))))
(is (equal '(a)
(let ((x 0))
(declare (ignorable x))
(dig (a (macro-splice (frob (incf x) 0)))))))
(is (equal '(a frob (incf x) 4)
(let ((x 0))
(declare (ignorable x))
(dig (a (macro-splice (frob1 (incf x))))))))
(is (equal '(a 1 2 3 4)
(let ((x 0))
(dig (a (macro-splice-all (frob1 (incf x))))))))))
(quasiquote-2.0:enable-quasiquote-2.0)
(test reader
(is (equal '(inject x) ',x))
(is (equal '(inject 3 x) ',,,x))
(is (equal '(splice x) ',@x))
(is (equal '(splice 3 x) ',,,@x))
(is (equal '(omacro-splice-all 4 x) ',,,,!oma@x))
(is (equal '(inject 4 oma@x) ',,,,oma@x)))
(test macro-splices
(macrolet ((splicer (x)
``(splice ,x)))
(is (equal '(a 1 2 3) (let ((x '(1 2 3)))
`(a ,!m(splicer x)))))))
(test repeated-splices
(is (equal '(a) `(a ,@nil ,@nil ,@nil ,@nil)))
(is (equal '(a b c d e f g) `(a ,@(list 'b 'c) ,@(list 'd 'e) ,@nil ,@(list 'f 'g)))))