(defmacro lc (&rest body) "Remove indentation. - var := exp - Bind exp to var. - ! exp - Eval exp. - (when p exp) - Branch when p. - (unless p exp) - Branch when (not p). CPS helpers: - arg-list :<> exp - Turn rest into a lambda bound to <>. Use in exp. - :<> exp - A shorthand for (&rest _) :<> exp." (let* ((b body) (fs '()) (res)) (while (not res) (pcase b ;; var := exp (`(,(and var (pred symbolp)) := ,exp . ,rest) (-> (lambda (body) `(let ((,var ,exp)) ,body)) (push fs)) (setq b rest)) ;; lambda-list :<> exp (`(,arglist :<> ,exp . ,rest) (-> (lambda (body) `(let ((<> (lambda ,arglist ,body))) ,exp)) (push fs)) (setq b rest)) ;; :<>! exp (`(:<>! ,exp . ,rest) (-> (lambda (body) `(let ((<> (lambda (&rest ,(gensym)) ,body))) ,exp)) (push fs)) (setq b rest)) ;; (when pred body ...) (`((when ,p . ,then) . ,else-rest) (-> (lambda (else) `(if ,p (progn ,@then) ,else)) (push fs)) (setq b else-rest)) ;; (unless pred body ...) (`((unless ,p . ,then) . ,else-rest) (-> (lambda (else) `(if (not ,p) (progn ,@then) ,else)) (push fs)) (setq b else-rest)) ;; ! exp (`(! ,exp . ,rest) (-> (lambda (body) `(progn ,exp ,body)) (push fs)) (setq b rest)) ;; (else body ...) (`((else . ,rest)) (setq res (-reduce-r-from #'funcall `(progn ,@rest) (reverse fs)))) ('() (error "lc: Missing else")) (f (error "lc: Unrecognized form %S" f)))) res))