Skip to content

Commit

Permalink
Go back to the way is was before.
Browse files Browse the repository at this point in the history
  • Loading branch information
okamsn committed Feb 17, 2024
1 parent ff90412 commit dd124fc
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 72 deletions.
123 changes: 63 additions & 60 deletions loopy-destructure.el
Original file line number Diff line number Diff line change
Expand Up @@ -675,66 +675,69 @@ Returns a list. The elements are:
If ERROR is non-nil, then signal an error in the produced code if
the pattern doesn't match."
(let ((var-list)
(destructuring-expression)
(val-holder (gensym "loopy--pcase-workaround")))
(cl-flet ((signaler (&rest _)
`(signal 'loopy-bad-run-time-destructuring
(list (quote ,var)
,val-holder))))
;; This sets `destructuring-expression' and `var-list'.
(setq destructuring-expression
;; This holding variable seems to be needed for the older method,
;; before the introduction of `pcase-compile-patterns'. In some cases,
;; it just evaluates `VAL' repeatedly, which is bad for functions
;; that work with state and bad for efficiency.
;;
;; Regardless, we also use it to report the value that caused the
;; error.
`(let ((,val-holder ,val))
,(if (fboundp 'pcase-compile-patterns)
(pcase-compile-patterns
val-holder
(remq nil
(list (cons var
(lambda (varvals &rest _)
(cons 'setq (mapcan (cl-function
(lambda ((var val &rest rest))
(push var var-list)
(list var val)))
varvals))))
(when error
(cons '_ #'signaler)))))
;; NOTE: In Emacs versions less than 28, this functionality
;; technically isn't public, but this is what the developers
;; recommend.
(pcase--u
(remq
nil
(list (list (pcase--match val-holder
(pcase--macroexpand
(if error
var
`(or ,var pcase--dontcare))))
(lambda (vars)
(cons 'setq
(mapcan (lambda (v)
(let ((destr-var (car v))
;; Use `cadr' for Emacs 28+, `cdr' for less.
(destr-val (funcall (eval-when-compile
(if (version< emacs-version "28")
#'cdr
#'cadr))
v)))
(push destr-var var-list)
(list destr-var destr-val)))
vars))))
(when error
(list (pcase--match val-holder
(pcase--macroexpand '_))
#'signaler)))))))))
(list destructuring-expression
var-list)))
(if (symbolp var)
`((setq ,var ,val)
,var)
(let ((var-list)
(destructuring-expression)
(val-holder (gensym "loopy--pcase-workaround")))
(cl-flet ((signaler (&rest _)
`(signal 'loopy-bad-run-time-destructuring
(list (quote ,var)
,val-holder))))
;; This sets `destructuring-expression' and `var-list'.
(setq destructuring-expression
;; This holding variable seems to be needed for the older method,
;; before the introduction of `pcase-compile-patterns'. In some cases,
;; it just evaluates `VAL' repeatedly, which is bad for functions
;; that work with state and bad for efficiency.
;;
;; Regardless, we also use it to report the value that caused the
;; error.
`(let ((,val-holder ,val))
,(if (fboundp 'pcase-compile-patterns)
(pcase-compile-patterns
val-holder
(remq nil
(list (cons var
(lambda (varvals &rest _)
(cons 'setq (mapcan (cl-function
(lambda ((var val &rest rest))
(push var var-list)
(list var val)))
varvals))))
(when error
(cons '_ #'signaler)))))
;; NOTE: In Emacs versions less than 28, this functionality
;; technically isn't public, but this is what the developers
;; recommend.
(pcase--u
(remq
nil
(list (list (pcase--match val-holder
(pcase--macroexpand
(if error
var
`(or ,var pcase--dontcare))))
(lambda (vars)
(cons 'setq
(mapcan (lambda (v)
(let ((destr-var (car v))
;; Use `cadr' for Emacs 28+, `cdr' for less.
(destr-val (funcall (eval-when-compile
(if (version< emacs-version "28")
#'cdr
#'cadr))
v)))
(push destr-var var-list)
(list destr-var destr-val)))
vars))))
(when error
(list (pcase--match val-holder
(pcase--macroexpand '_))
#'signaler)))))))))
(list destructuring-expression
var-list))))

(defun loopy--pcase-destructure-for-with-vars (bindings)
"Return a way to destructure BINDINGS by `pcase-let*'.
Expand Down
46 changes: 34 additions & 12 deletions loopy.el
Original file line number Diff line number Diff line change
Expand Up @@ -195,18 +195,40 @@ Returns a list of two elements:
;; 1) We sure that variables are bound even when unmatched.
;; 2) We can signal an error if the pattern doesn't match a value.
;; This keeps the behavior of the old implementation.
(list 'let*
(let ((all-found-vars)
(all-set-exprs))
(dolist (bind bindings)
(pcase-let* ((`(,var ,val) bind)
(`(,set-expr ,found-vars) (loopy--pcase-destructure-for-iteration
`(loopy ,var) val :error t)))
(push set-expr all-set-exprs)
(push found-vars all-found-vars)))
`(,@(mapcar #'list (cl-reduce #'cl-union all-found-vars))
,@(mapcar (lambda (x) `(_ ,x))
(nreverse all-set-exprs))))))
;;
;; Note: Binding the found variables to `nil' would overwrite any values that
;; we might try to access while binding, so we can't do that like we do
;; for iteration commands in which we already know the scope.
;; (let ((new-binds)
;; (all-set-exprs))
;; (dolist (bind bindings)
;; (cl-destructuring-bind (var val)
;; bind
;; (if (symbolp var)
;; (push `(,var ,val) new-binds)
;; (let ((sym (gensym)))
;; (push `(,sym ,val) new-binds)
;; (cl-destructuring-bind (set-expr found-vars)
;; (loopy--pcase-destructure-for-iteration `(loopy ,var) sym :error t)
;; (dolist (v found-vars)
;; (push `(,v nil) new-binds))
;; (push set-expr all-set-exprs))))))
;; (list 'let* (nreverse new-binds) (macroexp-progn (nreverse
;; all-set-exprs))))
(let ((new-binds))
(dolist (bind bindings)
(cl-destructuring-bind (var val)
bind
(if (symbolp var)
(push `(,var ,val) new-binds)
(let ((sym (gensym)))
(push `(,sym ,val) new-binds)
(cl-destructuring-bind (set-expr found-vars)
(loopy--pcase-destructure-for-iteration `(loopy ,var) sym :error t)
(dolist (v found-vars)
(push `(,v nil) new-binds))
(push `(_ ,set-expr) new-binds))))))
(list 'let* (nreverse new-binds))))

(cl-defun loopy--find-special-macro-arguments (names body)
"Find any usages of special macro arguments NAMES in BODY, given aliases.
Expand Down

0 comments on commit dd124fc

Please sign in to comment.