-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a1b8392
commit 3c2bca5
Showing
2 changed files
with
117 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
|
||
;; Author: Nicolas Petton <[email protected]> | ||
;; Keywords: sequences | ||
;; Version: 1.5 | ||
;; Version: 1.7 | ||
;; Package: seq | ||
|
||
;; Maintainer: [email protected] | ||
|
@@ -65,6 +65,39 @@ Evaluate BODY with VAR bound to each element of SEQ, in turn. | |
(pop ,index)))) | ||
,@body))))) | ||
|
||
(if (fboundp 'pcase-defmacro) | ||
;; Implementation of `seq-let' based on a `pcase' | ||
;; pattern. Requires Emacs>=25.1. | ||
(progn | ||
(pcase-defmacro seq (&rest args) | ||
"pcase pattern matching sequence elements. | ||
Matches if the object is a sequence (list, string or vector), and | ||
binds each element of ARGS to the corresponding element of the | ||
sequence." | ||
`(and (pred seq-p) | ||
,@(seq--make-pcase-bindings args))) | ||
|
||
(defmacro seq-let (args seq &rest body) | ||
"Bind the variables in ARGS to the elements of SEQ then evaluate BODY. | ||
ARGS can also include the `&rest' marker followed by a variable | ||
name to be bound to the rest of SEQ." | ||
(declare (indent 2) (debug t)) | ||
`(pcase-let ((,(seq--make-pcase-patterns args) ,seq)) | ||
,@body))) | ||
|
||
;; Implementation of `seq-let' compatible with Emacs<25.1. | ||
(defmacro seq-let (args seq &rest body) | ||
"Bind the variables in ARGS to the elements of SEQ then evaluate BODY. | ||
ARGS can also include the `&rest' marker followed by a variable | ||
name to be bound to the rest of SEQ." | ||
(declare (indent 2) (debug t)) | ||
(let ((seq-var (make-symbol "seq"))) | ||
`(let* ((,seq-var ,seq) | ||
,@(seq--make-bindings args seq-var)) | ||
,@body)))) | ||
|
||
(defun seq-drop (seq n) | ||
"Return a subsequence of SEQ without its first N elements. | ||
The result is a sequence of the same type as SEQ. | ||
|
@@ -333,17 +366,78 @@ This is an optimization for lists in `seq-take-while'." | |
(setq n (+ 1 n))) | ||
n)) | ||
|
||
(defun seq--make-pcase-bindings (args) | ||
"Return a list of bindings of the variables in ARGS to the elements of a sequence." | ||
(let ((bindings '()) | ||
(index 0) | ||
(rest-marker nil)) | ||
(seq-doseq (name args) | ||
(unless rest-marker | ||
(pcase name | ||
(`&rest | ||
(progn (push `(app (pcase--flip seq-drop ,index) | ||
,(seq--elt-safe args (1+ index))) | ||
bindings) | ||
(setq rest-marker t))) | ||
(t | ||
(push `(app (pcase--flip seq--elt-safe ,index) ,name) bindings)))) | ||
(setq index (1+ index))) | ||
bindings)) | ||
|
||
(defun seq--make-pcase-patterns (args) | ||
"Return a list of `(seq ...)' pcase patterns from the argument list ARGS." | ||
(cons 'seq | ||
(seq-map (lambda (elt) | ||
(if (seq-p elt) | ||
(seq--make-pcase-patterns elt) | ||
elt)) | ||
args))) | ||
|
||
;; Helper function for the Backward-compatible version of `seq-let' | ||
;; for Emacs<25.1. | ||
(defun seq--make-bindings (args seq &optional bindings) | ||
"Return a list of bindings of the variables in ARGS to the elements of a sequence. | ||
if BINDINGS is non-nil, append new bindings to it, and return | ||
BINDINGS." | ||
(let ((index 0) | ||
(rest-marker nil)) | ||
(seq-doseq (name args) | ||
(unless rest-marker | ||
(pcase name | ||
((pred seq-p) | ||
(setq bindings (seq--make-bindings (seq--elt-safe args index) | ||
`(seq--elt-safe ,seq ,index) | ||
bindings))) | ||
(`&rest | ||
(progn (push `(,(seq--elt-safe args (1+ index)) | ||
(seq-drop ,seq ,index)) | ||
bindings) | ||
(setq rest-marker t))) | ||
(t | ||
(push `(,name (seq--elt-safe ,seq ,index)) bindings)))) | ||
(setq index (1+ index))) | ||
bindings)) | ||
|
||
(defun seq--elt-safe (seq n) | ||
"Return element of SEQ at the index N. | ||
If no element is found, return nil." | ||
(when (or (listp seq) | ||
(and (sequencep seq) | ||
(> (seq-length seq) n))) | ||
(seq-elt seq n))) | ||
|
||
(defun seq--activate-font-lock-keywords () | ||
"Activate font-lock keywords for some symbols defined in seq." | ||
(font-lock-add-keywords 'emacs-lisp-mode | ||
'("\\<seq-doseq\\>"))) | ||
'("\\<seq-doseq\\>" "\\<seq-let\\>"))) | ||
|
||
(defalias 'seq-copy #'copy-sequence) | ||
(defalias 'seq-elt #'elt) | ||
(defalias 'seq-length #'length) | ||
(defalias 'seq-do #'mapc) | ||
(defalias 'seq-each #'seq-do) | ||
(defalias 'seq-map #'mapcar) | ||
(defalias 'seq-p #'sequencep) | ||
|
||
(unless (fboundp 'elisp--font-lock-flush-elisp-buffers) | ||
;; In Emacs≥25, (via elisp--font-lock-flush-elisp-buffers and a few others) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters