--- /dev/null
+;;; A little backquote implementation without optimizations of any
+;;; kind for lispstrack.
+
+(defun backquote-expand-1 (form)
+ (cond
+ ((symbolp form)
+ (list 'quote form))
+ ((atom form)
+ form)
+ ((eq (car form) 'unquote)
+ (car form))
+ ((eq (car form) 'backquote)
+ (backquote-expand-1 (backquote-expand-1 (cadr form))))
+ (t
+ (cons 'append
+ (mapcar (lambda (s)
+ (cond
+ ((and (listp s) (eq (car s) 'unquote))
+ (list 'list (cadr s)))
+ ((and (listp s) (eq (car s) 'unquote-splicing))
+ (cadr s))
+ (t
+ (list 'list (backquote-expand-1 s)))))
+ form)))))
+
+(defun backquote-expand (form)
+ (if (and (listp form) (eq (car form) 'backquote))
+ (backquote-expand-1 (cadr form))
+ form))
+
+(defmacro backquote (form)
+ (backquote-expand-1 form))
+
+;;; Tests. Compare backquote agains the backquote of the host Lisp.
+(macrolet ((test (form1 form2)
+ `(assert (equal ,form1 ,form2))))
+ (test (backquote (1 2 3 4))
+ `(1 2 3 4))
+ (test (backquote (1 2 (+ 3 4)))
+ `(1 2 (+ 3 4)))
+ (test (backquote (1 2 (unquote (+ 3 4))))
+ `(1 2 ,(+ 3 4)))
+ (test (backquote (1 2 (unquote-splicing '(3 4))))
+ `(1 2 ,@'(3 4)))
+ (test (backquote (backquote x))
+ ``x)
+ (let ((x 10))
+ (test `',x
+ (backquote (quote (unquote x)))))
+ (let ((x 10))
+ (test (eval ``(,,x))
+ (eval (backquote (backquote ((unquote (unquote x)))))))))