aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorArtur Malabarba2014-12-19 18:25:06 -0200
committerArtur Malabarba2014-12-19 18:30:26 -0200
commitf447d33fdb082ce8e5d336be6034df24339b4c45 (patch)
tree7ad100c335eb0e84024c0aab266f674e2078ff47 /lisp
parent948fa912de164a1374c87e9206cddca741b7fa33 (diff)
downloademacs-f447d33fdb082ce8e5d336be6034df24339b4c45.tar.gz
emacs-f447d33fdb082ce8e5d336be6034df24339b4c45.zip
* let-alist.el (let-alist): Enable access to deeper alists
Acces them by using extra dots inside the dotted symbols.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog5
-rw-r--r--lisp/let-alist.el71
2 files changed, 59 insertions, 17 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 12530a997ba..b658cc1d0fa 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,8 @@
12014-12-19 Artur Malabarba <bruce.connor.am@gmail.com>
2
3 * let-alist.el (let-alist): Enable access to deeper alists by
4 using dots inside the dotted symbols.
5
12014-12-19 Alan Mackenzie <acm@muc.de> 62014-12-19 Alan Mackenzie <acm@muc.de>
2 7
3 Make C++11 uniform init syntax work. New keywords "final" and "override" 8 Make C++11 uniform init syntax work. New keywords "final" and "override"
diff --git a/lisp/let-alist.el b/lisp/let-alist.el
index 813b8417aaa..692beba16dd 100644
--- a/lisp/let-alist.el
+++ b/lisp/let-alist.el
@@ -4,7 +4,7 @@
4 4
5;; Author: Artur Malabarba <bruce.connor.am@gmail.com> 5;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
6;; Maintainer: Artur Malabarba <bruce.connor.am@gmail.com> 6;; Maintainer: Artur Malabarba <bruce.connor.am@gmail.com>
7;; Version: 1.0.1 7;; Version: 1.0.2
8;; Keywords: extensions lisp 8;; Keywords: extensions lisp
9;; Prefix: let-alist 9;; Prefix: let-alist
10;; Separator: - 10;; Separator: -
@@ -39,21 +39,25 @@
39;; (let-alist alist 39;; (let-alist alist
40;; (if (and .title .body) 40;; (if (and .title .body)
41;; .body 41;; .body
42;; .site)) 42;; .site
43;; .site.contents))
43;; 44;;
44;; expands to 45;; essentially expands to
45;; 46;;
46;; (let ((.title (cdr (assq 'title alist))) 47;; (let ((.title (cdr (assq 'title alist)))
47;; (.body (cdr (assq 'body alist))) 48;; (.body (cdr (assq 'body alist)))
48;; (.site (cdr (assq 'site alist)))) 49;; (.site (cdr (assq 'site alist)))
50;; (.site.contents (cdr (assq 'contents (cdr (assq 'site alist))))))
49;; (if (and .title .body) 51;; (if (and .title .body)
50;; .body 52;; .body
51;; .site)) 53;; .site
54;; .site.contents))
55;;
56;; If you nest `let-alist' invocations, the inner one can't access
57;; the variables of the outer one. You can, however, access alists
58;; inside the original alist by using dots inside the symbol, as
59;; displayed in the example above by the `.site.contents'.
52;; 60;;
53;; Note that only one level is supported. If you nest `let-alist'
54;; invocations, the inner one can't access the variables of the outer
55;; one.
56
57;;; Code: 61;;; Code:
58 62
59 63
@@ -72,6 +76,31 @@ symbol, and each cdr is the same symbol without the `.'."
72 (t (apply #'append 76 (t (apply #'append
73 (mapcar #'let-alist--deep-dot-search data))))) 77 (mapcar #'let-alist--deep-dot-search data)))))
74 78
79(defun let-alist--access-sexp (symbol variable)
80 "Return a sexp used to acess SYMBOL inside VARIABLE."
81 (let* ((clean (let-alist--remove-dot symbol))
82 (name (symbol-name clean)))
83 (if (string-match "\\`\\." name)
84 clean
85 (let-alist--list-to-sexp
86 (mapcar #'intern (nreverse (split-string name "\\.")))
87 variable))))
88
89(defun let-alist--list-to-sexp (list var)
90 "Turn symbols LIST into recursive calls to `cdr' `assq' on VAR."
91 `(cdr (assq ',(car list)
92 ,(if (cdr list) (let-alist--list-to-sexp (cdr list) var)
93 var))))
94
95(defun let-alist--remove-dot (symbol)
96 "Return SYMBOL, sans an initial dot."
97 (let ((name (symbol-name symbol)))
98 (if (string-match "\\`\\." name)
99 (intern (replace-match "" nil nil name))
100 symbol)))
101
102
103;;; The actual macro.
75;;;###autoload 104;;;###autoload
76(defmacro let-alist (alist &rest body) 105(defmacro let-alist (alist &rest body)
77 "Let-bind dotted symbols to their cdrs in ALIST and execute BODY. 106 "Let-bind dotted symbols to their cdrs in ALIST and execute BODY.
@@ -83,20 +112,28 @@ For instance, the following code
83 (let-alist alist 112 (let-alist alist
84 (if (and .title .body) 113 (if (and .title .body)
85 .body 114 .body
86 .site)) 115 .site
116 .site.contents))
87 117
88expands to 118essentially expands to
89 119
90 (let ((.title (cdr (assq 'title alist))) 120 (let ((.title (cdr (assq 'title alist)))
91 (.body (cdr (assq 'body alist))) 121 (.body (cdr (assq 'body alist)))
92 (.site (cdr (assq 'site alist)))) 122 (.site (cdr (assq 'site alist)))
123 (.site.contents (cdr (assq 'contents (cdr (assq 'site alist))))))
93 (if (and .title .body) 124 (if (and .title .body)
94 .body 125 .body
95 .site))" 126 .site
127 .site.contents))
128
129If you nest `let-alist' invocations, the inner one can't access
130the variables of the outer one. You can, however, access alists
131inside the original alist by using dots inside the symbol, as
132displayed in the example above."
96 (declare (indent 1) (debug t)) 133 (declare (indent 1) (debug t))
97 (let ((var (gensym "let-alist"))) 134 (let ((var (gensym "alist")))
98 `(let ((,var ,alist)) 135 `(let ((,var ,alist))
99 (let ,(mapcar (lambda (x) `(,(car x) (cdr (assq ',(cdr x) ,var)))) 136 (let ,(mapcar (lambda (x) `(,(car x) ,(let-alist--access-sexp (car x) var)))
100 (delete-dups (let-alist--deep-dot-search body))) 137 (delete-dups (let-alist--deep-dot-search body)))
101 ,@body)))) 138 ,@body))))
102 139