Add support for SUBLIS function, including tests
authorAlfredo Beaumont <alfredo.beaumont@gmail.com>
Sun, 12 May 2013 11:46:49 +0000 (13:46 +0200)
committerAlfredo Beaumont <alfredo.beaumont@gmail.com>
Sun, 12 May 2013 11:46:49 +0000 (13:46 +0200)
src/list.lisp
src/toplevel.lisp
tests/list.lisp

index 99e6e7a..45aee57 100644 (file)
 (defun cdddar (x) (cdr (cddar x)))
 (defun cddddr (x) (cdr (cdddr x)))
 
+(defun sublis (alist tree &key key (test #'eql testp) (test-not #'eql test-not-p))
+  (labels ((s (tree)
+             (when (and testp test-not-p)
+               (error "Both test and test-not are set"))
+             (let* ((key-val (if key (funcall key tree) tree))
+                    (replace (if test-not-p
+                                 (assoc key-val alist :test-not test-not)
+                                 (assoc key-val alist :test test)))
+                    (x (if replace (cdr replace) tree)))
+               (if (atom x)
+                   x
+                   (cons (s (car x)) (s (cdr x)))))))
+    (s tree)))
 
 (defun copy-list (x)
   (mapcar #'identity x))
index 0698a0b..0bd763f 100644 (file)
@@ -73,7 +73,7 @@
           prog2 progn psetq push quote rassoc read-from-string remove remove-if
           remove-if-not return return-from revappend reverse rplaca rplacd
           second set setf setq seventh sixth some string string-upcase string=
-          stringp subseq subst symbol-function symbol-name symbol-package
+          stringp sublis subseq subst symbol-function symbol-name symbol-package
           symbol-plist symbol-value symbolp t tagbody tailp tenth third throw
           tree-equal truncate unless unwind-protect values values-list variable
           vector-push-extend warn when write-line write-string zerop))
index 17c3863..f002e1e 100644 (file)
 (test (equal (cdddar '((1 2 3 4))) '(4)))
 (test (equal (cddddr '(1 2 3 4 5)) '(5)))
 
+;; SUBLIS
+(test (equal (sublis '((x . 100) (z . zprime))
+                     '(plus x (minus g z x p) 4 . x))
+             '(PLUS 100 (MINUS G ZPRIME 100 P) 4 . 100)))
+(test (equal (sublis '(((+ x y) . (- x y)) ((- x y) . (+ x y)))
+                     '(* (/ (+ x y) (+ x p)) (- x y))
+                     :test #'equal)
+             '(* (/ (- X Y) (+ X P)) (+ X Y))))
+(let ((tree1 '(1 (1 2) ((1 2 3)) (((1 2 3 4))))))
+  (test (equal (sublis '((3 . "three")) tree1)
+               '(1 (1 2) ((1 2 "three")) (((1 2 "three" 4))))))
+  (test (equal (sublis '((t . "string"))
+                       (sublis '((1 . "") (4 . 44)) tree1)
+                       :key #'stringp)
+               '("string" ("string" 2) (("string" 2 3)) ((("string" 2 3 44))))))
+  (test (equal tree1 '(1 (1 2) ((1 2 3)) (((1 2 3 4)))))))
+(let ((tree2 '("one" ("one" "two") (("one" "Two" "three")))))
+  (test (equal (sublis '(("two" . 2)) tree2)
+               '("one" ("one" "two") (("one" "Two" "three")))))
+  (test (equal tree2 '("one" ("one" "two") (("one" "Two" "three")))))
+  (test (equal (sublis '(("two" . 2)) tree2 :test 'equal)
+               '("one" ("one" 2) (("one" "Two" "three"))))))
+
 ; COPY-TREE
 (test (let* ((foo (list '(1 2) '(3 4)))
              (bar (copy-tree foo)))