Advertisement
Guest User

Common lisp list comprehension (just for lulz)

a guest
Dec 24th, 2014
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 3.04 KB | None | 0 0
  1. (defun reader-macro-[ (stream char)
  2.   (declare (ignore char))
  3.   (let* ((expr (coerce (loop for char = (read-char stream)
  4.                              while (char/= char #\]) collect char)
  5.                        'string))
  6.          (clauses (split-sequence:split-sequence #\, expr))
  7.          (gen-name (gensym))
  8.          bindings conditions side-effects)
  9.     ;; First clause is a 'collect' clause
  10.     (destructuring-bind (collect-form . rest) clauses
  11.       (when rest
  12.         (loop for clause in rest do
  13.              (cond
  14.                ;; Binding
  15.                ((find #\| clause)
  16.                 (destructuring-bind (var value)
  17.                     (split-sequence:split-sequence #\| clause)
  18.                   (let ((var-sym (gensym)))
  19.                     (push (list var-sym
  20.                                 (read-from-string var)
  21.                                 (read-from-string value)) bindings))))
  22.                ;; Side effects
  23.                ((find #\^ clause)
  24.                 (push (read-from-string (remove #\^ clause)) side-effects))
  25.                ;; Condition
  26.                (t
  27.                 (push (read-from-string clause) conditions))))
  28.  
  29.         `(let
  30.              ;; Set environment
  31.              ,(loop for binding in bindings collect
  32.                    (destructuring-bind (sym var value) binding
  33.                      (declare (ignore var))
  34.                      `(,sym ,value)))
  35.  
  36.            (labels ((,gen-name (&optional (offset 0))
  37.              (when (or ,@(loop for binding in bindings
  38.                             for sym = (first binding) collect `(subseq ,sym offset)))
  39.                (prog1
  40.                    ;; Set bindings
  41.                    (let
  42.                        ,(loop for binding in bindings collect
  43.                              (destructuring-bind (sym var value) binding
  44.                                (declare (ignore value))
  45.                                `(,var (nth offset ,sym))))
  46.  
  47.                      (if ,(if conditions `(and ,@conditions) t)
  48.                          (progn
  49.                            ;; Run side effects first
  50.                            ,@side-effects
  51.                            ,(read-from-string collect-form))
  52.                          (,gen-name (1+ offset))))
  53.                ;; Modify lists
  54.                ,@(loop for binding in bindings collect
  55.                       `(setq ,(car binding) (cdr ,(car binding))))))))
  56.              #',gen-name))))))
  57.  
  58. (set-macro-character #\[ #'reader-macro-[)
  59. (set-macro-character #\] (get-macro-character #\)))
  60.  
  61. (defun all (gen)
  62.   (loop for val = (funcall gen)
  63.         while val collect val))
  64.  
  65. (defmacro test (bool)
  66.   `(if (not ,bool)
  67.        (format *error-output* "~a is not t~%" ',bool)))
  68.  
  69. (defun run-tests ()
  70.   (test (equal (all [(* x y), x|'(0 1 1), y|'(2 1 4)]) '(0 1 4)))
  71.   (test (equal (all [x, x|(loop for i below 6 collect i), (oddp x)]) '(1 3 5)))
  72.   (test
  73.    (string= "hihihi"
  74.             (with-output-to-string (out)
  75.               (all
  76.                [x, x|(loop repeat 3 collect t), ^ (format out "hi")])))))
  77. (run-tests)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement