Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (defun reader-macro-[ (stream char)
- (declare (ignore char))
- (let* ((expr (coerce (loop for char = (read-char stream)
- while (char/= char #\]) collect char)
- 'string))
- (clauses (split-sequence:split-sequence #\, expr))
- (gen-name (gensym))
- bindings conditions side-effects)
- ;; First clause is a 'collect' clause
- (destructuring-bind (collect-form . rest) clauses
- (when rest
- (loop for clause in rest do
- (cond
- ;; Binding
- ((find #\| clause)
- (destructuring-bind (var value)
- (split-sequence:split-sequence #\| clause)
- (let ((var-sym (gensym)))
- (push (list var-sym
- (read-from-string var)
- (read-from-string value)) bindings))))
- ;; Side effects
- ((find #\^ clause)
- (push (read-from-string (remove #\^ clause)) side-effects))
- ;; Condition
- (t
- (push (read-from-string clause) conditions))))
- `(let
- ;; Set environment
- ,(loop for binding in bindings collect
- (destructuring-bind (sym var value) binding
- (declare (ignore var))
- `(,sym ,value)))
- (labels ((,gen-name (&optional (offset 0))
- (when (or ,@(loop for binding in bindings
- for sym = (first binding) collect `(subseq ,sym offset)))
- (prog1
- ;; Set bindings
- (let
- ,(loop for binding in bindings collect
- (destructuring-bind (sym var value) binding
- (declare (ignore value))
- `(,var (nth offset ,sym))))
- (if ,(if conditions `(and ,@conditions) t)
- (progn
- ;; Run side effects first
- ,@side-effects
- ,(read-from-string collect-form))
- (,gen-name (1+ offset))))
- ;; Modify lists
- ,@(loop for binding in bindings collect
- `(setq ,(car binding) (cdr ,(car binding))))))))
- #',gen-name))))))
- (set-macro-character #\[ #'reader-macro-[)
- (set-macro-character #\] (get-macro-character #\)))
- (defun all (gen)
- (loop for val = (funcall gen)
- while val collect val))
- (defmacro test (bool)
- `(if (not ,bool)
- (format *error-output* "~a is not t~%" ',bool)))
- (defun run-tests ()
- (test (equal (all [(* x y), x|'(0 1 1), y|'(2 1 4)]) '(0 1 4)))
- (test (equal (all [x, x|(loop for i below 6 collect i), (oddp x)]) '(1 3 5)))
- (test
- (string= "hihihi"
- (with-output-to-string (out)
- (all
- [x, x|(loop repeat 3 collect t), ^ (format out "hi")])))))
- (run-tests)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement