Further speed up rpm completion, by caching the installed packages
[bpt/emacs.git] / lisp / emacs-lisp / cl-macs.el
CommitLineData
d9857e53 1;;; cl-macs.el --- Common Lisp macros -*- lexical-binding: t; coding: utf-8 -*-
fcd73769 2
acaf905b 3;; Copyright (C) 1993, 2001-2012 Free Software Foundation, Inc.
fcd73769
RS
4
5;; Author: Dave Gillespie <daveg@synaptics.com>
6;; Version: 2.02
7;; Keywords: extensions
bd78fa1d 8;; Package: emacs
fcd73769
RS
9
10;; This file is part of GNU Emacs.
11
d6cba7ae 12;; GNU Emacs is free software: you can redistribute it and/or modify
fcd73769 13;; it under the terms of the GNU General Public License as published by
d6cba7ae
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
fcd73769
RS
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
d6cba7ae 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
fcd73769 24
07b3798c 25;;; Commentary:
fcd73769
RS
26
27;; These are extensions to Emacs Lisp that provide a degree of
28;; Common Lisp compatibility, beyond what is already built-in
29;; in Emacs Lisp.
30;;
31;; This package was written by Dave Gillespie; it is a complete
32;; rewrite of Cesar Quiroz's original cl.el package of December 1986.
33;;
fcd73769
RS
34;; Bug reports, comments, and suggestions are welcome!
35
36;; This file contains the portions of the Common Lisp extensions
37;; package which should be autoloaded, but need only be present
38;; if the compiler or interpreter is used---this file is not
39;; necessary for executing compiled code.
40
41;; See cl.el for Change Log.
42
43
07b3798c 44;;; Code:
fcd73769 45
7c1898a7 46(require 'cl-lib)
4dd1c416 47(require 'macroexp)
fcd73769 48
fcd73769 49(defmacro cl-pop2 (place)
7c1898a7 50 (declare (debug edebug-sexps))
03fef3e6
SM
51 `(prog1 (car (cdr ,place))
52 (setq ,place (cdr (cdr ,place)))))
fcd73769 53
fcd73769
RS
54(defvar cl-optimize-safety)
55(defvar cl-optimize-speed)
56
fcd73769
RS
57;;; Initialization.
58
4dd1c416
SM
59;;; Some predicates for analyzing Lisp forms.
60;; These are used by various
61;; macro expanders to optimize the results in certain common cases.
fcd73769 62
4dd1c416 63(defconst cl--simple-funcs '(car cdr nth aref elt if and or + - 1+ 1- min max
b7b95a1e 64 car-safe cdr-safe progn prog1 prog2))
4dd1c416 65(defconst cl--safe-funcs '(* / % length memq list vector vectorp
b7b95a1e
DL
66 < > <= >= = error))
67
4dd1c416
SM
68(defun cl--simple-expr-p (x &optional size)
69 "Check if no side effects, and executes quickly."
b7b95a1e 70 (or size (setq size 10))
7c1898a7 71 (if (and (consp x) (not (memq (car x) '(quote function cl-function))))
b7b95a1e 72 (and (symbolp (car x))
4dd1c416 73 (or (memq (car x) cl--simple-funcs)
b7b95a1e
DL
74 (get (car x) 'side-effect-free))
75 (progn
76 (setq size (1- size))
77 (while (and (setq x (cdr x))
4dd1c416 78 (setq size (cl--simple-expr-p (car x) size))))
b7b95a1e
DL
79 (and (null x) (>= size 0) size)))
80 (and (> size 0) (1- size))))
81
4dd1c416
SM
82(defun cl--simple-exprs-p (xs)
83 (while (and xs (cl--simple-expr-p (car xs)))
b7b95a1e
DL
84 (setq xs (cdr xs)))
85 (not xs))
86
4dd1c416
SM
87(defun cl--safe-expr-p (x)
88 "Check if no side effects."
7c1898a7 89 (or (not (and (consp x) (not (memq (car x) '(quote function cl-function)))))
b7b95a1e 90 (and (symbolp (car x))
4dd1c416
SM
91 (or (memq (car x) cl--simple-funcs)
92 (memq (car x) cl--safe-funcs)
b7b95a1e
DL
93 (get (car x) 'side-effect-free))
94 (progn
4dd1c416 95 (while (and (setq x (cdr x)) (cl--safe-expr-p (car x))))
b7b95a1e
DL
96 (null x)))))
97
98;;; Check if constant (i.e., no side effects or dependencies).
4dd1c416 99(defun cl--const-expr-p (x)
b7b95a1e
DL
100 (cond ((consp x)
101 (or (eq (car x) 'quote)
7c1898a7 102 (and (memq (car x) '(function cl-function))
b7b95a1e
DL
103 (or (symbolp (nth 1 x))
104 (and (eq (car-safe (nth 1 x)) 'lambda) 'func)))))
105 ((symbolp x) (and (memq x '(nil t)) t))
106 (t t)))
107
4dd1c416
SM
108(defun cl--const-expr-val (x)
109 (and (macroexp-const-p x) (if (consp x) (nth 1 x) x)))
b7b95a1e
DL
110
111(defun cl-expr-access-order (x v)
e754e83b
SM
112 ;; This apparently tries to return nil iff the expression X evaluates
113 ;; the variables V in the same order as they appear in V (so as to
114 ;; be able to replace those vars with the expressions they're bound
115 ;; to).
116 ;; FIXME: This is very naive, it doesn't even check to see if those
117 ;; variables appear more than once.
4dd1c416 118 (if (macroexp-const-p x) v
b7b95a1e
DL
119 (if (consp x)
120 (progn
121 (while (setq x (cdr x)) (setq v (cl-expr-access-order (car x) v)))
122 v)
123 (if (eq x (car v)) (cdr v) '(t)))))
124
4dd1c416
SM
125(defun cl--expr-contains (x y)
126 "Count number of times X refers to Y. Return nil for 0 times."
7c1898a7 127 ;; FIXME: This is naive, and it will cl-count Y as referred twice in
e129292c
CS
128 ;; (let ((Y 1)) Y) even though it should be 0. Also it is often called on
129 ;; non-macroexpanded code, so it may also miss some occurrences that would
130 ;; only appear in the expanded code.
b7b95a1e 131 (cond ((equal y x) 1)
7c1898a7 132 ((and (consp x) (not (memq (car x) '(quote function cl-function))))
b7b95a1e 133 (let ((sum 0))
e129292c 134 (while (consp x)
4dd1c416
SM
135 (setq sum (+ sum (or (cl--expr-contains (pop x) y) 0))))
136 (setq sum (+ sum (or (cl--expr-contains x y) 0)))
b7b95a1e
DL
137 (and (> sum 0) sum)))
138 (t nil)))
139
4dd1c416
SM
140(defun cl--expr-contains-any (x y)
141 (while (and y (not (cl--expr-contains x (car y)))) (pop y))
b7b95a1e
DL
142 y)
143
4dd1c416
SM
144(defun cl--expr-depends-p (x y)
145 "Check whether X may depend on any of the symbols in Y."
146 (and (not (macroexp-const-p x))
147 (or (not (cl--safe-expr-p x)) (cl--expr-contains-any x y))))
b7b95a1e 148
fcd73769
RS
149;;; Symbols.
150
4735906a 151(defvar cl--gensym-counter)
ebacfcc6 152;;;###autoload
7c1898a7 153(defun cl-gensym (&optional prefix)
fcd73769
RS
154 "Generate a new uninterned symbol.
155The name is made by appending a number to PREFIX, default \"G\"."
a766dfa1
JB
156 (let ((pfix (if (stringp prefix) prefix "G"))
157 (num (if (integerp prefix) prefix
4735906a
SM
158 (prog1 cl--gensym-counter
159 (setq cl--gensym-counter (1+ cl--gensym-counter))))))
a766dfa1 160 (make-symbol (format "%s%d" pfix num))))
fcd73769 161
ebacfcc6 162;;;###autoload
7c1898a7 163(defun cl-gentemp (&optional prefix)
fcd73769
RS
164 "Generate a new interned symbol with a unique name.
165The name is made by appending a number to PREFIX, default \"G\"."
a766dfa1 166 (let ((pfix (if (stringp prefix) prefix "G"))
fcd73769 167 name)
4735906a
SM
168 (while (intern-soft (setq name (format "%s%d" pfix cl--gensym-counter)))
169 (setq cl--gensym-counter (1+ cl--gensym-counter)))
fcd73769
RS
170 (intern name)))
171
172
173;;; Program structure.
174
b1198e17 175(def-edebug-spec cl-declarations
7c1898a7 176 (&rest ("cl-declare" &rest sexp)))
b1198e17
SM
177
178(def-edebug-spec cl-declarations-or-string
179 (&or stringp cl-declarations))
180
181(def-edebug-spec cl-lambda-list
182 (([&rest arg]
183 [&optional ["&optional" cl-&optional-arg &rest cl-&optional-arg]]
184 [&optional ["&rest" arg]]
185 [&optional ["&key" [cl-&key-arg &rest cl-&key-arg]
186 &optional "&allow-other-keys"]]
187 [&optional ["&aux" &rest
188 &or (symbolp &optional def-form) symbolp]]
189 )))
190
191(def-edebug-spec cl-&optional-arg
192 (&or (arg &optional def-form arg) arg))
193
194(def-edebug-spec cl-&key-arg
195 (&or ([&or (symbolp arg) arg] &optional def-form arg) arg))
196
bb3faf5b
SM
197(defconst cl--lambda-list-keywords
198 '(&optional &rest &key &allow-other-keys &aux &whole &body &environment))
199
200(defvar cl--bind-block) (defvar cl--bind-defs) (defvar cl--bind-enquote)
201(defvar cl--bind-inits) (defvar cl--bind-lets) (defvar cl--bind-forms)
202
203(defun cl--transform-lambda (form bind-block)
204 (let* ((args (car form)) (body (cdr form)) (orig-args args)
205 (cl--bind-block bind-block) (cl--bind-defs nil) (cl--bind-enquote nil)
206 (cl--bind-inits nil) (cl--bind-lets nil) (cl--bind-forms nil)
207 (header nil) (simple-args nil))
208 (while (or (stringp (car body))
209 (memq (car-safe (car body)) '(interactive cl-declare)))
210 (push (pop body) header))
211 (setq args (if (listp args) (cl-copy-list args) (list '&rest args)))
212 (let ((p (last args))) (if (cdr p) (setcdr p (list '&rest (cdr p)))))
213 (if (setq cl--bind-defs (cadr (memq '&cl-defs args)))
214 (setq args (delq '&cl-defs (delq cl--bind-defs args))
215 cl--bind-defs (cadr cl--bind-defs)))
216 (if (setq cl--bind-enquote (memq '&cl-quote args))
217 (setq args (delq '&cl-quote args)))
218 (if (memq '&whole args) (error "&whole not currently implemented"))
219 (let* ((p (memq '&environment args)) (v (cadr p))
220 (env-exp 'macroexpand-all-environment))
221 (if p (setq args (nconc (delq (car p) (delq v args))
222 (list '&aux (list v env-exp))))))
223 (while (and args (symbolp (car args))
224 (not (memq (car args) '(nil &rest &body &key &aux)))
225 (not (and (eq (car args) '&optional)
226 (or cl--bind-defs (consp (cadr args))))))
227 (push (pop args) simple-args))
228 (or (eq cl--bind-block 'cl-none)
229 (setq body (list `(cl-block ,cl--bind-block ,@body))))
230 (if (null args)
231 (cl-list* nil (nreverse simple-args) (nconc (nreverse header) body))
232 (if (memq '&optional simple-args) (push '&optional args))
233 (cl--do-arglist args nil (- (length simple-args)
234 (if (memq '&optional simple-args) 1 0)))
235 (setq cl--bind-lets (nreverse cl--bind-lets))
236 (cl-list* (and cl--bind-inits `(cl-eval-when (compile load eval)
237 ,@(nreverse cl--bind-inits)))
238 (nconc (nreverse simple-args)
239 (list '&rest (car (pop cl--bind-lets))))
240 (nconc (let ((hdr (nreverse header)))
241 ;; Macro expansion can take place in the middle of
242 ;; apparently harmless computation, so it should not
243 ;; touch the match-data.
244 (save-match-data
245 (require 'help-fns)
246 (cons (help-add-fundoc-usage
247 (if (stringp (car hdr)) (pop hdr))
248 (format "%S"
249 (cons 'fn
250 (cl--make-usage-args orig-args))))
251 hdr)))
252 (list `(let* ,cl--bind-lets
253 ,@(nreverse cl--bind-forms)
254 ,@body)))))))
255
ebacfcc6 256;;;###autoload
7c1898a7 257(defmacro cl-defun (name args &rest body)
69d8fb1e 258 "Define NAME as a function.
fcd73769 259Like normal `defun', except ARGLIST allows full Common Lisp conventions,
7c1898a7 260and BODY is implicitly surrounded by (cl-block NAME ...).
69d8fb1e
SM
261
262\(fn NAME ARGLIST [DOCSTRING] BODY...)"
b1198e17
SM
263 (declare (debug
264 ;; Same as defun but use cl-lambda-list.
7c1898a7 265 (&define [&or name ("cl-setf" :name cl-setf name)]
b1198e17
SM
266 cl-lambda-list
267 cl-declarations-or-string
268 [&optional ("interactive" interactive)]
70b8ef8f 269 def-body))
b581bb5c 270 (doc-string 3)
70b8ef8f 271 (indent 2))
4dd1c416 272 (let* ((res (cl--transform-lambda (cons args body) name))
03fef3e6
SM
273 (form `(defun ,name ,@(cdr res))))
274 (if (car res) `(progn ,(car res) ,form) form)))
fcd73769 275
b1198e17
SM
276;; The lambda list for macros is different from that of normal lambdas.
277;; Note that &environment is only allowed as first or last items in the
278;; top level list.
279
280(def-edebug-spec cl-macro-list
281 (([&optional "&environment" arg]
282 [&rest cl-macro-arg]
283 [&optional ["&optional" &rest
284 &or (cl-macro-arg &optional def-form cl-macro-arg) arg]]
285 [&optional [[&or "&rest" "&body"] cl-macro-arg]]
286 [&optional ["&key" [&rest
287 [&or ([&or (symbolp cl-macro-arg) arg]
288 &optional def-form cl-macro-arg)
289 arg]]
290 &optional "&allow-other-keys"]]
291 [&optional ["&aux" &rest
292 &or (symbolp &optional def-form) symbolp]]
293 [&optional "&environment" arg]
294 )))
295
296(def-edebug-spec cl-macro-arg
297 (&or arg cl-macro-list1))
298
299(def-edebug-spec cl-macro-list1
300 (([&optional "&whole" arg] ;; only allowed at lower levels
301 [&rest cl-macro-arg]
302 [&optional ["&optional" &rest
303 &or (cl-macro-arg &optional def-form cl-macro-arg) arg]]
304 [&optional [[&or "&rest" "&body"] cl-macro-arg]]
305 [&optional ["&key" [&rest
306 [&or ([&or (symbolp cl-macro-arg) arg]
307 &optional def-form cl-macro-arg)
308 arg]]
309 &optional "&allow-other-keys"]]
310 [&optional ["&aux" &rest
311 &or (symbolp &optional def-form) symbolp]]
312 . [&or arg nil])))
313
ebacfcc6 314;;;###autoload
7c1898a7 315(defmacro cl-defmacro (name args &rest body)
69d8fb1e 316 "Define NAME as a macro.
fcd73769 317Like normal `defmacro', except ARGLIST allows full Common Lisp conventions,
7c1898a7 318and BODY is implicitly surrounded by (cl-block NAME ...).
69d8fb1e
SM
319
320\(fn NAME ARGLIST [DOCSTRING] BODY...)"
b1198e17 321 (declare (debug
70b8ef8f 322 (&define name cl-macro-list cl-declarations-or-string def-body))
b581bb5c 323 (doc-string 3)
70b8ef8f 324 (indent 2))
4dd1c416 325 (let* ((res (cl--transform-lambda (cons args body) name))
03fef3e6
SM
326 (form `(defmacro ,name ,@(cdr res))))
327 (if (car res) `(progn ,(car res) ,form) form)))
fcd73769 328
b1198e17
SM
329(def-edebug-spec cl-lambda-expr
330 (&define ("lambda" cl-lambda-list
331 ;;cl-declarations-or-string
332 ;;[&optional ("interactive" interactive)]
333 def-body)))
334
7c1898a7 335;; Redefine function-form to also match cl-function
b1198e17
SM
336(def-edebug-spec function-form
337 ;; form at the end could also handle "function",
338 ;; but recognize it specially to avoid wrapping function forms.
339 (&or ([&or "quote" "function"] &or symbolp lambda-expr)
7c1898a7 340 ("cl-function" cl-function)
b1198e17
SM
341 form))
342
ebacfcc6 343;;;###autoload
7c1898a7 344(defmacro cl-function (func)
64a4c526 345 "Introduce a function.
3187ba1c
JB
346Like normal `function', except that if argument is a lambda form,
347its argument list allows full Common Lisp conventions."
b1198e17 348 (declare (debug (&or symbolp cl-lambda-expr)))
fcd73769 349 (if (eq (car-safe func) 'lambda)
4dd1c416 350 (let* ((res (cl--transform-lambda (cdr func) 'cl-none))
03fef3e6
SM
351 (form `(function (lambda . ,(cdr res)))))
352 (if (car res) `(progn ,(car res) ,form) form))
353 `(function ,func)))
fcd73769 354
b4587710
JB
355(declare-function help-add-fundoc-usage "help-fns" (docstring arglist))
356
673e08bb
SM
357(defun cl--make-usage-var (x)
358 "X can be a var or a (destructuring) lambda-list."
359 (cond
360 ((symbolp x) (make-symbol (upcase (symbol-name x))))
361 ((consp x) (cl--make-usage-args x))
362 (t x)))
363
364(defun cl--make-usage-args (arglist)
365 ;; `orig-args' can contain &cl-defs (an internal
366 ;; CL thingy I don't understand), so remove it.
367 (let ((x (memq '&cl-defs arglist)))
368 (when x (setq arglist (delq (car x) (remq (cadr x) arglist)))))
369 (let ((state nil))
370 (mapcar (lambda (x)
371 (cond
372 ((symbolp x)
373 (if (eq ?\& (aref (symbol-name x) 0))
374 (setq state x)
375 (make-symbol (upcase (symbol-name x)))))
376 ((not (consp x)) x)
377 ((memq state '(nil &rest)) (cl--make-usage-args x))
378 (t ;(VAR INITFORM SVAR) or ((KEYWORD VAR) INITFORM SVAR).
7c1898a7 379 (cl-list*
673e08bb
SM
380 (if (and (consp (car x)) (eq state '&key))
381 (list (caar x) (cl--make-usage-var (nth 1 (car x))))
382 (cl--make-usage-var (car x)))
383 (nth 1 x) ;INITFORM.
384 (cl--make-usage-args (nthcdr 2 x)) ;SVAR.
385 ))))
386 arglist)))
387
4dd1c416 388(defun cl--do-arglist (args expr &optional num) ; uses bind-*
fcd73769 389 (if (nlistp args)
bb3faf5b 390 (if (or (memq args cl--lambda-list-keywords) (not (symbolp args)))
fcd73769 391 (error "Invalid argument name: %s" args)
513749ee 392 (push (list args expr) cl--bind-lets))
7c1898a7 393 (setq args (cl-copy-list args))
fcd73769
RS
394 (let ((p (last args))) (if (cdr p) (setcdr p (list '&rest (cdr p)))))
395 (let ((p (memq '&body args))) (if p (setcar p '&rest)))
396 (if (memq '&environment args) (error "&environment used incorrectly"))
397 (let ((save-args args)
398 (restarg (memq '&rest args))
bb3faf5b 399 (safety (if (cl--compiling-file) cl-optimize-safety 3))
fcd73769
RS
400 (keys nil)
401 (laterarg nil) (exactarg nil) minarg)
402 (or num (setq num 0))
403 (if (listp (cadr restarg))
e542ea4b 404 (setq restarg (make-symbol "--cl-rest--"))
fcd73769 405 (setq restarg (cadr restarg)))
513749ee 406 (push (list restarg expr) cl--bind-lets)
fcd73769 407 (if (eq (car args) '&whole)
513749ee 408 (push (list (cl-pop2 args) restarg) cl--bind-lets))
fcd73769
RS
409 (let ((p args))
410 (setq minarg restarg)
bb3faf5b 411 (while (and p (not (memq (car p) cl--lambda-list-keywords)))
fcd73769
RS
412 (or (eq p args) (setq minarg (list 'cdr minarg)))
413 (setq p (cdr p)))
414 (if (memq (car p) '(nil &aux))
03fef3e6 415 (setq minarg `(= (length ,restarg)
7c1898a7 416 ,(length (cl-ldiff args p)))
fcd73769 417 exactarg (not (eq args p)))))
bb3faf5b 418 (while (and args (not (memq (car args) cl--lambda-list-keywords)))
fcd73769
RS
419 (let ((poparg (list (if (or (cdr args) (not exactarg)) 'pop 'car)
420 restarg)))
4dd1c416 421 (cl--do-arglist
69d8fb1e 422 (pop args)
fcd73769 423 (if (or laterarg (= safety 0)) poparg
03fef3e6
SM
424 `(if ,minarg ,poparg
425 (signal 'wrong-number-of-arguments
513749ee
SM
426 (list ,(and (not (eq cl--bind-block 'cl-none))
427 `',cl--bind-block)
03fef3e6 428 (length ,restarg)))))))
fcd73769 429 (setq num (1+ num) laterarg t))
69d8fb1e 430 (while (and (eq (car args) '&optional) (pop args))
bb3faf5b 431 (while (and args (not (memq (car args) cl--lambda-list-keywords)))
69d8fb1e 432 (let ((arg (pop args)))
fcd73769 433 (or (consp arg) (setq arg (list arg)))
4dd1c416 434 (if (cddr arg) (cl--do-arglist (nth 2 arg) `(and ,restarg t)))
fcd73769 435 (let ((def (if (cdr arg) (nth 1 arg)
513749ee
SM
436 (or (car cl--bind-defs)
437 (nth 1 (assq (car arg) cl--bind-defs)))))
03fef3e6 438 (poparg `(pop ,restarg)))
513749ee 439 (and def cl--bind-enquote (setq def `',def))
4dd1c416 440 (cl--do-arglist (car arg)
03fef3e6 441 (if def `(if ,restarg ,poparg ,def) poparg))
fcd73769
RS
442 (setq num (1+ num))))))
443 (if (eq (car args) '&rest)
444 (let ((arg (cl-pop2 args)))
4dd1c416 445 (if (consp arg) (cl--do-arglist arg restarg)))
fcd73769 446 (or (eq (car args) '&key) (= safety 0) exactarg
03fef3e6
SM
447 (push `(if ,restarg
448 (signal 'wrong-number-of-arguments
449 (list
513749ee
SM
450 ,(and (not (eq cl--bind-block 'cl-none))
451 `',cl--bind-block)
03fef3e6 452 (+ ,num (length ,restarg)))))
513749ee 453 cl--bind-forms)))
69d8fb1e 454 (while (and (eq (car args) '&key) (pop args))
bb3faf5b 455 (while (and args (not (memq (car args) cl--lambda-list-keywords)))
69d8fb1e 456 (let ((arg (pop args)))
dd441b46 457 (or (consp arg) (setq arg (list arg)))
fcd73769
RS
458 (let* ((karg (if (consp (car arg)) (caar arg)
459 (intern (format ":%s" (car arg)))))
7c1898a7 460 (varg (if (consp (car arg)) (cl-cadar arg) (car arg)))
fcd73769 461 (def (if (cdr arg) (cadr arg)
513749ee 462 (or (car cl--bind-defs) (cadr (assq varg cl--bind-defs)))))
03fef3e6 463 (look `(memq ',karg ,restarg)))
513749ee 464 (and def cl--bind-enquote (setq def `',def))
fcd73769 465 (if (cddr arg)
e542ea4b 466 (let* ((temp (or (nth 2 arg) (make-symbol "--cl-var--")))
03fef3e6 467 (val `(car (cdr ,temp))))
4dd1c416
SM
468 (cl--do-arglist temp look)
469 (cl--do-arglist varg
03fef3e6
SM
470 `(if ,temp
471 (prog1 ,val (setq ,temp t))
472 ,def)))
4dd1c416 473 (cl--do-arglist
fcd73769 474 varg
03fef3e6 475 `(car (cdr ,(if (null def)
fcd73769 476 look
03fef3e6 477 `(or ,look
4dd1c416
SM
478 ,(if (eq (cl--const-expr-p def) t)
479 `'(nil ,(cl--const-expr-val def))
03fef3e6 480 `(list nil ,def))))))))
69d8fb1e 481 (push karg keys)))))
fcd73769 482 (setq keys (nreverse keys))
69d8fb1e 483 (or (and (eq (car args) '&allow-other-keys) (pop args))
fcd73769 484 (null keys) (= safety 0)
e542ea4b 485 (let* ((var (make-symbol "--cl-keys--"))
fcd73769 486 (allow '(:allow-other-keys))
03fef3e6
SM
487 (check `(while ,var
488 (cond
489 ((memq (car ,var) ',(append keys allow))
490 (setq ,var (cdr (cdr ,var))))
491 ((car (cdr (memq (quote ,@allow) ,restarg)))
492 (setq ,var nil))
493 (t
494 (error
495 ,(format "Keyword argument %%s not one of %s"
496 keys)
497 (car ,var)))))))
513749ee 498 (push `(let ((,var ,restarg)) ,check) cl--bind-forms)))
69d8fb1e 499 (while (and (eq (car args) '&aux) (pop args))
bb3faf5b 500 (while (and args (not (memq (car args) cl--lambda-list-keywords)))
fcd73769 501 (if (consp (car args))
513749ee 502 (if (and cl--bind-enquote (cl-cadar args))
4dd1c416 503 (cl--do-arglist (caar args)
03fef3e6 504 `',(cadr (pop args)))
4dd1c416
SM
505 (cl--do-arglist (caar args) (cadr (pop args))))
506 (cl--do-arglist (pop args) nil))))
fcd73769
RS
507 (if args (error "Malformed argument list %s" save-args)))))
508
4dd1c416 509(defun cl--arglist-args (args)
fcd73769
RS
510 (if (nlistp args) (list args)
511 (let ((res nil) (kind nil) arg)
512 (while (consp args)
69d8fb1e 513 (setq arg (pop args))
bb3faf5b 514 (if (memq arg cl--lambda-list-keywords) (setq kind arg)
69d8fb1e 515 (if (eq arg '&cl-defs) (pop args)
fcd73769
RS
516 (and (consp arg) kind (setq arg (car arg)))
517 (and (consp arg) (cdr arg) (eq kind '&key) (setq arg (cadr arg)))
4dd1c416 518 (setq res (nconc res (cl--arglist-args arg))))))
fcd73769
RS
519 (nconc res (and args (list args))))))
520
ebacfcc6 521;;;###autoload
7c1898a7 522(defmacro cl-destructuring-bind (args expr &rest body)
70b8ef8f
SM
523 (declare (indent 2)
524 (debug (&define cl-macro-list def-form cl-declarations def-body)))
513749ee
SM
525 (let* ((cl--bind-lets nil) (cl--bind-forms nil) (cl--bind-inits nil)
526 (cl--bind-defs nil) (cl--bind-block 'cl-none) (cl--bind-enquote nil))
4dd1c416 527 (cl--do-arglist (or args '(&aux)) expr)
513749ee
SM
528 (append '(progn) cl--bind-inits
529 (list `(let* ,(nreverse cl--bind-lets)
530 ,@(nreverse cl--bind-forms) ,@body)))))
fcd73769
RS
531
532
7c1898a7 533;;; The `cl-eval-when' form.
fcd73769
RS
534
535(defvar cl-not-toplevel nil)
536
ebacfcc6 537;;;###autoload
7c1898a7 538(defmacro cl-eval-when (when &rest body)
69d8fb1e 539 "Control when BODY is evaluated.
fcd73769
RS
540If `compile' is in WHEN, BODY is evaluated when compiled at top-level.
541If `load' is in WHEN, BODY is evaluated when loaded after top-level compile.
69d8fb1e
SM
542If `eval' is in WHEN, BODY is evaluated when interpreted or at non-top-level.
543
544\(fn (WHEN...) BODY...)"
70b8ef8f 545 (declare (indent 1) (debug ((&rest &or "compile" "load" "eval") body)))
bb3faf5b 546 (if (and (fboundp 'cl--compiling-file) (cl--compiling-file)
fcd73769 547 (not cl-not-toplevel) (not (boundp 'for-effect))) ; horrible kludge
64a4c526 548 (let ((comp (or (memq 'compile when) (memq :compile-toplevel when)))
fcd73769 549 (cl-not-toplevel t))
64a4c526 550 (if (or (memq 'load when) (memq :load-toplevel when))
4dd1c416 551 (if comp (cons 'progn (mapcar 'cl--compile-time-too body))
03fef3e6 552 `(if nil nil ,@body))
fcd73769 553 (progn (if comp (eval (cons 'progn body))) nil)))
64a4c526 554 (and (or (memq 'eval when) (memq :execute when))
fcd73769
RS
555 (cons 'progn body))))
556
4dd1c416 557(defun cl--compile-time-too (form)
fcd73769
RS
558 (or (and (symbolp (car-safe form)) (get (car-safe form) 'byte-hunk-handler))
559 (setq form (macroexpand
7c1898a7 560 form (cons '(cl-eval-when) byte-compile-macro-environment))))
fcd73769 561 (cond ((eq (car-safe form) 'progn)
4dd1c416 562 (cons 'progn (mapcar 'cl--compile-time-too (cdr form))))
7c1898a7 563 ((eq (car-safe form) 'cl-eval-when)
fcd73769 564 (let ((when (nth 1 form)))
64a4c526 565 (if (or (memq 'eval when) (memq :execute when))
7c1898a7 566 `(cl-eval-when (compile ,@when) ,@(cddr form))
fcd73769
RS
567 form)))
568 (t (eval form) form)))
569
ebacfcc6 570;;;###autoload
513749ee 571(defmacro cl-load-time-value (form &optional _read-only)
fcd73769
RS
572 "Like `progn', but evaluates the body at load time.
573The result of the body appears to the compiler as a quoted constant."
b1198e17 574 (declare (debug (form &optional sexp)))
bb3faf5b 575 (if (cl--compiling-file)
7c1898a7 576 (let* ((temp (cl-gentemp "--cl-load-time--"))
03fef3e6 577 (set `(set ',temp ,form)))
fcd73769
RS
578 (if (and (fboundp 'byte-compile-file-form-defmumble)
579 (boundp 'this-kind) (boundp 'that-one))
580 (fset 'byte-compile-file-form
03fef3e6
SM
581 `(lambda (form)
582 (fset 'byte-compile-file-form
583 ',(symbol-function 'byte-compile-file-form))
584 (byte-compile-file-form ',set)
585 (byte-compile-file-form form)))
7200d79c 586 (print set (symbol-value 'byte-compile--outbuffer)))
03fef3e6
SM
587 `(symbol-value ',temp))
588 `',(eval form)))
fcd73769
RS
589
590
591;;; Conditional control structures.
592
ebacfcc6 593;;;###autoload
7c1898a7 594(defmacro cl-case (expr &rest clauses)
3187ba1c 595 "Eval EXPR and choose among clauses on that value.
fcd73769
RS
596Each clause looks like (KEYLIST BODY...). EXPR is evaluated and compared
597against each key in each KEYLIST; the corresponding BODY is evaluated.
7c1898a7 598If no clause succeeds, cl-case returns nil. A single atom may be used in
a8ea72a0 599place of a KEYLIST of one atom. A KEYLIST of t or `otherwise' is
fcd73769 600allowed only in the final clause, and matches if no other keys match.
3187ba1c
JB
601Key values are compared by `eql'.
602\n(fn EXPR (KEYLIST BODY...)...)"
70b8ef8f 603 (declare (indent 1) (debug (form &rest (sexp body))))
4dd1c416 604 (let* ((temp (if (cl--simple-expr-p expr 3) expr (make-symbol "--cl-var--")))
fcd73769
RS
605 (head-list nil)
606 (body (cons
607 'cond
608 (mapcar
609 (function
610 (lambda (c)
611 (cons (cond ((memq (car c) '(t otherwise)) t)
7c1898a7
SM
612 ((eq (car c) 'cl--ecase-error-flag)
613 `(error "cl-ecase failed: %s, %s"
03fef3e6 614 ,temp ',(reverse head-list)))
fcd73769
RS
615 ((listp (car c))
616 (setq head-list (append (car c) head-list))
7c1898a7 617 `(cl-member ,temp ',(car c)))
fcd73769
RS
618 (t
619 (if (memq (car c) head-list)
620 (error "Duplicate key in case: %s"
621 (car c)))
69d8fb1e 622 (push (car c) head-list)
03fef3e6 623 `(eql ,temp ',(car c))))
fcd73769
RS
624 (or (cdr c) '(nil)))))
625 clauses))))
626 (if (eq temp expr) body
03fef3e6 627 `(let ((,temp ,expr)) ,body))))
fcd73769 628
ebacfcc6 629;;;###autoload
7c1898a7
SM
630(defmacro cl-ecase (expr &rest clauses)
631 "Like `cl-case', but error if no cl-case fits.
3187ba1c
JB
632`otherwise'-clauses are not allowed.
633\n(fn EXPR (KEYLIST BODY...)...)"
7c1898a7
SM
634 (declare (indent 1) (debug cl-case))
635 `(cl-case ,expr ,@clauses (cl--ecase-error-flag)))
fcd73769 636
ebacfcc6 637;;;###autoload
7c1898a7 638(defmacro cl-typecase (expr &rest clauses)
3187ba1c 639 "Evals EXPR, chooses among clauses on that value.
fcd73769
RS
640Each clause looks like (TYPE BODY...). EXPR is evaluated and, if it
641satisfies TYPE, the corresponding BODY is evaluated. If no clause succeeds,
7c1898a7 642cl-typecase returns nil. A TYPE of t or `otherwise' is allowed only in the
3187ba1c
JB
643final clause, and matches if no other keys match.
644\n(fn EXPR (TYPE BODY...)...)"
70b8ef8f
SM
645 (declare (indent 1)
646 (debug (form &rest ([&or cl-type-spec "otherwise"] body))))
4dd1c416 647 (let* ((temp (if (cl--simple-expr-p expr 3) expr (make-symbol "--cl-var--")))
fcd73769
RS
648 (type-list nil)
649 (body (cons
650 'cond
651 (mapcar
652 (function
653 (lambda (c)
654 (cons (cond ((eq (car c) 'otherwise) t)
7c1898a7
SM
655 ((eq (car c) 'cl--ecase-error-flag)
656 `(error "cl-etypecase failed: %s, %s"
03fef3e6 657 ,temp ',(reverse type-list)))
fcd73769 658 (t
69d8fb1e 659 (push (car c) type-list)
4dd1c416 660 (cl--make-type-test temp (car c))))
fcd73769
RS
661 (or (cdr c) '(nil)))))
662 clauses))))
663 (if (eq temp expr) body
03fef3e6 664 `(let ((,temp ,expr)) ,body))))
fcd73769 665
ebacfcc6 666;;;###autoload
7c1898a7
SM
667(defmacro cl-etypecase (expr &rest clauses)
668 "Like `cl-typecase', but error if no case fits.
3187ba1c
JB
669`otherwise'-clauses are not allowed.
670\n(fn EXPR (TYPE BODY...)...)"
7c1898a7
SM
671 (declare (indent 1) (debug cl-typecase))
672 `(cl-typecase ,expr ,@clauses (cl--ecase-error-flag)))
fcd73769
RS
673
674
675;;; Blocks and exits.
676
ebacfcc6 677;;;###autoload
7c1898a7 678(defmacro cl-block (name &rest body)
64a4c526 679 "Define a lexically-scoped block named NAME.
7c1898a7 680NAME may be any symbol. Code inside the BODY forms can call `cl-return-from'
fcd73769
RS
681to jump prematurely out of the block. This differs from `catch' and `throw'
682in two respects: First, the NAME is an unevaluated symbol rather than a
683quoted symbol or other form; and second, NAME is lexically rather than
684dynamically scoped: Only references to it within BODY will work. These
685references may appear inside macro expansions, but not inside functions
686called from BODY."
70b8ef8f 687 (declare (indent 1) (debug (symbolp body)))
4dd1c416 688 (if (cl--safe-expr-p `(progn ,@body)) `(progn ,@body)
bb3faf5b 689 `(cl--block-wrapper
03fef3e6
SM
690 (catch ',(intern (format "--cl-block-%s--" name))
691 ,@body))))
fcd73769 692
ebacfcc6 693;;;###autoload
7c1898a7 694(defmacro cl-return (&optional result)
64a4c526 695 "Return from the block named nil.
7c1898a7 696This is equivalent to `(cl-return-from nil RESULT)'."
b1198e17 697 (declare (debug (&optional form)))
7c1898a7 698 `(cl-return-from nil ,result))
fcd73769 699
ebacfcc6 700;;;###autoload
7c1898a7 701(defmacro cl-return-from (name &optional result)
64a4c526 702 "Return from the block named NAME.
7c1898a7 703This jumps out to the innermost enclosing `(cl-block NAME ...)' form,
fcd73769
RS
704returning RESULT from that form (or nil if RESULT is omitted).
705This is compatible with Common Lisp, but note that `defun' and
706`defmacro' do not create implicit blocks as they do in Common Lisp."
70b8ef8f 707 (declare (indent 1) (debug (symbolp &optional form)))
fcd73769 708 (let ((name2 (intern (format "--cl-block-%s--" name))))
bb3faf5b 709 `(cl--block-throw ',name2 ,result)))
fcd73769
RS
710
711
7c1898a7 712;;; The "cl-loop" macro.
fcd73769 713
4dd1c416
SM
714(defvar cl--loop-args) (defvar cl--loop-accum-var) (defvar cl--loop-accum-vars)
715(defvar cl--loop-bindings) (defvar cl--loop-body) (defvar cl--loop-destr-temps)
716(defvar cl--loop-finally) (defvar cl--loop-finish-flag)
717(defvar cl--loop-first-flag)
718(defvar cl--loop-initially) (defvar cl--loop-map-form) (defvar cl--loop-name)
719(defvar cl--loop-result) (defvar cl--loop-result-explicit)
720(defvar cl--loop-result-var) (defvar cl--loop-steps) (defvar cl--loop-symbol-macs)
fcd73769 721
ebacfcc6 722;;;###autoload
513749ee 723(defmacro cl-loop (&rest loop-args)
7c1898a7 724 "The Common Lisp `cl-loop' macro.
fcd73769
RS
725Valid clauses are:
726 for VAR from/upfrom/downfrom NUM to/upto/downto/above/below NUM by NUM,
727 for VAR in LIST by FUNC, for VAR on LIST by FUNC, for VAR = INIT then EXPR,
728 for VAR across ARRAY, repeat NUM, with VAR = INIT, while COND, until COND,
729 always COND, never COND, thereis COND, collect EXPR into VAR,
730 append EXPR into VAR, nconc EXPR into VAR, sum EXPR into VAR,
731 count EXPR into VAR, maximize EXPR into VAR, minimize EXPR into VAR,
732 if COND CLAUSE [and CLAUSE]... else CLAUSE [and CLAUSE...],
733 unless COND CLAUSE [and CLAUSE]... else CLAUSE [and CLAUSE...],
734 do EXPRS..., initially EXPRS..., finally EXPRS..., return EXPR,
69d8fb1e
SM
735 finally return EXPR, named NAME.
736
737\(fn CLAUSE...)"
b1198e17 738 (declare (debug (&rest &or symbolp form)))
513749ee
SM
739 (if (not (memq t (mapcar 'symbolp (delq nil (delq t (cl-copy-list loop-args))))))
740 `(cl-block nil (while t ,@loop-args))
741 (let ((cl--loop-args loop-args) (cl--loop-name nil) (cl--loop-bindings nil)
4dd1c416
SM
742 (cl--loop-body nil) (cl--loop-steps nil)
743 (cl--loop-result nil) (cl--loop-result-explicit nil)
744 (cl--loop-result-var nil) (cl--loop-finish-flag nil)
745 (cl--loop-accum-var nil) (cl--loop-accum-vars nil)
746 (cl--loop-initially nil) (cl--loop-finally nil)
747 (cl--loop-map-form nil) (cl--loop-first-flag nil)
748 (cl--loop-destr-temps nil) (cl--loop-symbol-macs nil))
749 (setq cl--loop-args (append cl--loop-args '(cl-end-loop)))
750 (while (not (eq (car cl--loop-args) 'cl-end-loop)) (cl-parse-loop-clause))
751 (if cl--loop-finish-flag
752 (push `((,cl--loop-finish-flag t)) cl--loop-bindings))
753 (if cl--loop-first-flag
754 (progn (push `((,cl--loop-first-flag t)) cl--loop-bindings)
755 (push `(setq ,cl--loop-first-flag nil) cl--loop-steps)))
756 (let* ((epilogue (nconc (nreverse cl--loop-finally)
757 (list (or cl--loop-result-explicit cl--loop-result))))
758 (ands (cl--loop-build-ands (nreverse cl--loop-body)))
759 (while-body (nconc (cadr ands) (nreverse cl--loop-steps)))
fcd73769 760 (body (append
4dd1c416
SM
761 (nreverse cl--loop-initially)
762 (list (if cl--loop-map-form
7c1898a7
SM
763 `(cl-block --cl-finish--
764 ,(cl-subst
03fef3e6
SM
765 (if (eq (car ands) t) while-body
766 (cons `(or ,(car ands)
7c1898a7 767 (cl-return-from --cl-finish--
03fef3e6
SM
768 nil))
769 while-body))
4dd1c416 770 '--cl-map cl--loop-map-form))
03fef3e6 771 `(while ,(car ands) ,@while-body)))
4dd1c416
SM
772 (if cl--loop-finish-flag
773 (if (equal epilogue '(nil)) (list cl--loop-result-var)
774 `((if ,cl--loop-finish-flag
775 (progn ,@epilogue) ,cl--loop-result-var)))
fcd73769 776 epilogue))))
4dd1c416
SM
777 (if cl--loop-result-var (push (list cl--loop-result-var) cl--loop-bindings))
778 (while cl--loop-bindings
779 (if (cdar cl--loop-bindings)
780 (setq body (list (cl--loop-let (pop cl--loop-bindings) body t)))
fcd73769 781 (let ((lets nil))
4dd1c416
SM
782 (while (and cl--loop-bindings
783 (not (cdar cl--loop-bindings)))
784 (push (car (pop cl--loop-bindings)) lets))
785 (setq body (list (cl--loop-let lets body nil))))))
786 (if cl--loop-symbol-macs
787 (setq body (list `(cl-symbol-macrolet ,cl--loop-symbol-macs ,@body))))
788 `(cl-block ,cl--loop-name ,@body)))))
fcd73769 789
7c1898a7 790;; Below is a complete spec for cl-loop, in several parts that correspond
b1198e17
SM
791;; to the syntax given in CLtL2. The specs do more than specify where
792;; the forms are; it also specifies, as much as Edebug allows, all the
7c1898a7 793;; syntactically valid cl-loop clauses. The disadvantage of this
b1198e17
SM
794;; completeness is rigidity, but the "for ... being" clause allows
795;; arbitrary extensions of the form: [symbolp &rest &or symbolp form].
796
7c1898a7 797;; (def-edebug-spec cl-loop
b1198e17
SM
798;; ([&optional ["named" symbolp]]
799;; [&rest
800;; &or
801;; ["repeat" form]
802;; loop-for-as
803;; loop-with
804;; loop-initial-final]
805;; [&rest loop-clause]
806;; ))
807
808;; (def-edebug-spec loop-with
809;; ("with" loop-var
810;; loop-type-spec
811;; [&optional ["=" form]]
812;; &rest ["and" loop-var
813;; loop-type-spec
814;; [&optional ["=" form]]]))
815
816;; (def-edebug-spec loop-for-as
817;; ([&or "for" "as"] loop-for-as-subclause
818;; &rest ["and" loop-for-as-subclause]))
819
820;; (def-edebug-spec loop-for-as-subclause
821;; (loop-var
822;; loop-type-spec
823;; &or
824;; [[&or "in" "on" "in-ref" "across-ref"]
825;; form &optional ["by" function-form]]
826
827;; ["=" form &optional ["then" form]]
828;; ["across" form]
829;; ["being"
830;; [&or "the" "each"]
831;; &or
832;; [[&or "element" "elements"]
833;; [&or "of" "in" "of-ref"] form
834;; &optional "using" ["index" symbolp]];; is this right?
835;; [[&or "hash-key" "hash-keys"
836;; "hash-value" "hash-values"]
837;; [&or "of" "in"]
838;; hash-table-p &optional ["using" ([&or "hash-value" "hash-values"
839;; "hash-key" "hash-keys"] sexp)]]
840
841;; [[&or "symbol" "present-symbol" "external-symbol"
842;; "symbols" "present-symbols" "external-symbols"]
843;; [&or "in" "of"] package-p]
844
845;; ;; Extensions for Emacs Lisp, including Lucid Emacs.
846;; [[&or "frame" "frames"
847;; "screen" "screens"
848;; "buffer" "buffers"]]
849
850;; [[&or "window" "windows"]
851;; [&or "of" "in"] form]
852
853;; [[&or "overlay" "overlays"
854;; "extent" "extents"]
855;; [&or "of" "in"] form
856;; &optional [[&or "from" "to"] form]]
857
858;; [[&or "interval" "intervals"]
859;; [&or "in" "of"] form
860;; &optional [[&or "from" "to"] form]
861;; ["property" form]]
862
863;; [[&or "key-code" "key-codes"
864;; "key-seq" "key-seqs"
865;; "key-binding" "key-bindings"]
866;; [&or "in" "of"] form
867;; &optional ["using" ([&or "key-code" "key-codes"
868;; "key-seq" "key-seqs"
869;; "key-binding" "key-bindings"]
870;; sexp)]]
871;; ;; For arbitrary extensions, recognize anything else.
872;; [symbolp &rest &or symbolp form]
873;; ]
874
875;; ;; arithmetic - must be last since all parts are optional.
876;; [[&optional [[&or "from" "downfrom" "upfrom"] form]]
877;; [&optional [[&or "to" "downto" "upto" "below" "above"] form]]
878;; [&optional ["by" form]]
879;; ]))
880
881;; (def-edebug-spec loop-initial-final
882;; (&or ["initially"
883;; ;; [&optional &or "do" "doing"] ;; CLtL2 doesn't allow this.
884;; &rest loop-non-atomic-expr]
885;; ["finally" &or
886;; [[&optional &or "do" "doing"] &rest loop-non-atomic-expr]
887;; ["return" form]]))
888
889;; (def-edebug-spec loop-and-clause
890;; (loop-clause &rest ["and" loop-clause]))
891
892;; (def-edebug-spec loop-clause
893;; (&or
894;; [[&or "while" "until" "always" "never" "thereis"] form]
895
896;; [[&or "collect" "collecting"
897;; "append" "appending"
898;; "nconc" "nconcing"
899;; "concat" "vconcat"] form
900;; [&optional ["into" loop-var]]]
901
902;; [[&or "count" "counting"
903;; "sum" "summing"
904;; "maximize" "maximizing"
905;; "minimize" "minimizing"] form
906;; [&optional ["into" loop-var]]
907;; loop-type-spec]
908
909;; [[&or "if" "when" "unless"]
910;; form loop-and-clause
911;; [&optional ["else" loop-and-clause]]
912;; [&optional "end"]]
913
914;; [[&or "do" "doing"] &rest loop-non-atomic-expr]
915
916;; ["return" form]
917;; loop-initial-final
918;; ))
919
920;; (def-edebug-spec loop-non-atomic-expr
921;; ([&not atom] form))
922
923;; (def-edebug-spec loop-var
924;; ;; The symbolp must be last alternative to recognize e.g. (a b . c)
925;; ;; loop-var =>
926;; ;; (loop-var . [&or nil loop-var])
927;; ;; (symbolp . [&or nil loop-var])
928;; ;; (symbolp . loop-var)
929;; ;; (symbolp . (symbolp . [&or nil loop-var]))
930;; ;; (symbolp . (symbolp . loop-var))
931;; ;; (symbolp . (symbolp . symbolp)) == (symbolp symbolp . symbolp)
932;; (&or (loop-var . [&or nil loop-var]) [gate symbolp]))
933
934;; (def-edebug-spec loop-type-spec
935;; (&optional ["of-type" loop-d-type-spec]))
936
937;; (def-edebug-spec loop-d-type-spec
938;; (&or (loop-d-type-spec . [&or nil loop-d-type-spec]) cl-type-spec))
939
940
941
215461a8 942(defun cl-parse-loop-clause () ; uses loop-*
4dd1c416 943 (let ((word (pop cl--loop-args))
fcd73769
RS
944 (hash-types '(hash-key hash-keys hash-value hash-values))
945 (key-types '(key-code key-codes key-seq key-seqs
946 key-binding key-bindings)))
947 (cond
948
4dd1c416 949 ((null cl--loop-args)
7c1898a7 950 (error "Malformed `cl-loop' macro"))
fcd73769
RS
951
952 ((eq word 'named)
4dd1c416 953 (setq cl--loop-name (pop cl--loop-args)))
fcd73769
RS
954
955 ((eq word 'initially)
4dd1c416
SM
956 (if (memq (car cl--loop-args) '(do doing)) (pop cl--loop-args))
957 (or (consp (car cl--loop-args)) (error "Syntax error on `initially' clause"))
958 (while (consp (car cl--loop-args))
959 (push (pop cl--loop-args) cl--loop-initially)))
fcd73769
RS
960
961 ((eq word 'finally)
4dd1c416
SM
962 (if (eq (car cl--loop-args) 'return)
963 (setq cl--loop-result-explicit (or (cl-pop2 cl--loop-args) '(quote nil)))
964 (if (memq (car cl--loop-args) '(do doing)) (pop cl--loop-args))
965 (or (consp (car cl--loop-args)) (error "Syntax error on `finally' clause"))
966 (if (and (eq (caar cl--loop-args) 'return) (null cl--loop-name))
967 (setq cl--loop-result-explicit (or (nth 1 (pop cl--loop-args)) '(quote nil)))
968 (while (consp (car cl--loop-args))
969 (push (pop cl--loop-args) cl--loop-finally)))))
fcd73769
RS
970
971 ((memq word '(for as))
972 (let ((loop-for-bindings nil) (loop-for-sets nil) (loop-for-steps nil)
973 (ands nil))
974 (while
7c1898a7 975 ;; Use `cl-gensym' rather than `make-symbol'. It's important that
443b961a 976 ;; (not (eq (symbol-name var1) (symbol-name var2))) because
4dd1c416
SM
977 ;; these vars get added to the macro-environment.
978 (let ((var (or (pop cl--loop-args) (cl-gensym "--cl-var--"))))
979 (setq word (pop cl--loop-args))
980 (if (eq word 'being) (setq word (pop cl--loop-args)))
981 (if (memq word '(the each)) (setq word (pop cl--loop-args)))
fcd73769 982 (if (memq word '(buffer buffers))
4dd1c416 983 (setq word 'in cl--loop-args (cons '(buffer-list) cl--loop-args)))
fcd73769
RS
984 (cond
985
986 ((memq word '(from downfrom upfrom to downto upto
987 above below by))
4dd1c416
SM
988 (push word cl--loop-args)
989 (if (memq (car cl--loop-args) '(downto above))
7c1898a7 990 (error "Must specify `from' value for downward cl-loop"))
4dd1c416
SM
991 (let* ((down (or (eq (car cl--loop-args) 'downfrom)
992 (memq (cl-caddr cl--loop-args) '(downto above))))
993 (excl (or (memq (car cl--loop-args) '(above below))
994 (memq (cl-caddr cl--loop-args) '(above below))))
995 (start (and (memq (car cl--loop-args) '(from upfrom downfrom))
996 (cl-pop2 cl--loop-args)))
997 (end (and (memq (car cl--loop-args)
fcd73769 998 '(to upto downto above below))
4dd1c416
SM
999 (cl-pop2 cl--loop-args)))
1000 (step (and (eq (car cl--loop-args) 'by) (cl-pop2 cl--loop-args)))
1001 (end-var (and (not (macroexp-const-p end))
e542ea4b 1002 (make-symbol "--cl-var--")))
4dd1c416 1003 (step-var (and (not (macroexp-const-p step))
e542ea4b 1004 (make-symbol "--cl-var--"))))
fcd73769
RS
1005 (and step (numberp step) (<= step 0)
1006 (error "Loop `by' value is not positive: %s" step))
69d8fb1e
SM
1007 (push (list var (or start 0)) loop-for-bindings)
1008 (if end-var (push (list end-var end) loop-for-bindings))
1009 (if step-var (push (list step-var step)
e542ea4b 1010 loop-for-bindings))
fcd73769 1011 (if end
69d8fb1e 1012 (push (list
e542ea4b 1013 (if down (if excl '> '>=) (if excl '< '<=))
4dd1c416 1014 var (or end-var end)) cl--loop-body))
69d8fb1e 1015 (push (list var (list (if down '- '+) var
e542ea4b
SM
1016 (or step-var step 1)))
1017 loop-for-steps)))
fcd73769
RS
1018
1019 ((memq word '(in in-ref on))
1020 (let* ((on (eq word 'on))
e542ea4b
SM
1021 (temp (if (and on (symbolp var))
1022 var (make-symbol "--cl-var--"))))
4dd1c416
SM
1023 (push (list temp (pop cl--loop-args)) loop-for-bindings)
1024 (push `(consp ,temp) cl--loop-body)
fcd73769 1025 (if (eq word 'in-ref)
4dd1c416 1026 (push (list var `(car ,temp)) cl--loop-symbol-macs)
fcd73769
RS
1027 (or (eq temp var)
1028 (progn
69d8fb1e 1029 (push (list var nil) loop-for-bindings)
03fef3e6 1030 (push (list var (if on temp `(car ,temp)))
e542ea4b 1031 loop-for-sets))))
69d8fb1e 1032 (push (list temp
4dd1c416
SM
1033 (if (eq (car cl--loop-args) 'by)
1034 (let ((step (cl-pop2 cl--loop-args)))
e542ea4b
SM
1035 (if (and (memq (car-safe step)
1036 '(quote function
7c1898a7 1037 cl-function))
e542ea4b
SM
1038 (symbolp (nth 1 step)))
1039 (list (nth 1 step) temp)
03fef3e6
SM
1040 `(funcall ,step ,temp)))
1041 `(cdr ,temp)))
e542ea4b 1042 loop-for-steps)))
fcd73769
RS
1043
1044 ((eq word '=)
4dd1c416
SM
1045 (let* ((start (pop cl--loop-args))
1046 (then (if (eq (car cl--loop-args) 'then) (cl-pop2 cl--loop-args) start)))
69d8fb1e 1047 (push (list var nil) loop-for-bindings)
4dd1c416 1048 (if (or ands (eq (car cl--loop-args) 'and))
fcd73769 1049 (progn
e542ea4b 1050 (push `(,var
4dd1c416
SM
1051 (if ,(or cl--loop-first-flag
1052 (setq cl--loop-first-flag
e542ea4b
SM
1053 (make-symbol "--cl-var--")))
1054 ,start ,var))
1055 loop-for-sets)
69d8fb1e
SM
1056 (push (list var then) loop-for-steps))
1057 (push (list var
e542ea4b 1058 (if (eq start then) start
4dd1c416
SM
1059 `(if ,(or cl--loop-first-flag
1060 (setq cl--loop-first-flag
e542ea4b
SM
1061 (make-symbol "--cl-var--")))
1062 ,start ,then)))
1063 loop-for-sets))))
fcd73769
RS
1064
1065 ((memq word '(across across-ref))
e542ea4b
SM
1066 (let ((temp-vec (make-symbol "--cl-vec--"))
1067 (temp-idx (make-symbol "--cl-idx--")))
4dd1c416 1068 (push (list temp-vec (pop cl--loop-args)) loop-for-bindings)
69d8fb1e 1069 (push (list temp-idx -1) loop-for-bindings)
03fef3e6 1070 (push `(< (setq ,temp-idx (1+ ,temp-idx))
4dd1c416 1071 (length ,temp-vec)) cl--loop-body)
fcd73769 1072 (if (eq word 'across-ref)
03fef3e6 1073 (push (list var `(aref ,temp-vec ,temp-idx))
4dd1c416 1074 cl--loop-symbol-macs)
69d8fb1e 1075 (push (list var nil) loop-for-bindings)
03fef3e6 1076 (push (list var `(aref ,temp-vec ,temp-idx))
e542ea4b 1077 loop-for-sets))))
fcd73769
RS
1078
1079 ((memq word '(element elements))
4dd1c416
SM
1080 (let ((ref (or (memq (car cl--loop-args) '(in-ref of-ref))
1081 (and (not (memq (car cl--loop-args) '(in of)))
fcd73769 1082 (error "Expected `of'"))))
4dd1c416 1083 (seq (cl-pop2 cl--loop-args))
e542ea4b 1084 (temp-seq (make-symbol "--cl-seq--"))
4dd1c416
SM
1085 (temp-idx (if (eq (car cl--loop-args) 'using)
1086 (if (and (= (length (cadr cl--loop-args)) 2)
1087 (eq (cl-caadr cl--loop-args) 'index))
1088 (cadr (cl-pop2 cl--loop-args))
fcd73769 1089 (error "Bad `using' clause"))
e542ea4b 1090 (make-symbol "--cl-idx--"))))
69d8fb1e
SM
1091 (push (list temp-seq seq) loop-for-bindings)
1092 (push (list temp-idx 0) loop-for-bindings)
fcd73769 1093 (if ref
e542ea4b 1094 (let ((temp-len (make-symbol "--cl-len--")))
03fef3e6 1095 (push (list temp-len `(length ,temp-seq))
e542ea4b 1096 loop-for-bindings)
2eb87922 1097 (push (list var `(elt ,temp-seq ,temp-idx))
4dd1c416
SM
1098 cl--loop-symbol-macs)
1099 (push `(< ,temp-idx ,temp-len) cl--loop-body))
69d8fb1e 1100 (push (list var nil) loop-for-bindings)
03fef3e6
SM
1101 (push `(and ,temp-seq
1102 (or (consp ,temp-seq)
1103 (< ,temp-idx (length ,temp-seq))))
4dd1c416 1104 cl--loop-body)
03fef3e6
SM
1105 (push (list var `(if (consp ,temp-seq)
1106 (pop ,temp-seq)
1107 (aref ,temp-seq ,temp-idx)))
e542ea4b 1108 loop-for-sets))
03fef3e6 1109 (push (list temp-idx `(1+ ,temp-idx))
e542ea4b 1110 loop-for-steps)))
fcd73769
RS
1111
1112 ((memq word hash-types)
4dd1c416
SM
1113 (or (memq (car cl--loop-args) '(in of)) (error "Expected `of'"))
1114 (let* ((table (cl-pop2 cl--loop-args))
1115 (other (if (eq (car cl--loop-args) 'using)
1116 (if (and (= (length (cadr cl--loop-args)) 2)
1117 (memq (cl-caadr cl--loop-args) hash-types)
1118 (not (eq (cl-caadr cl--loop-args) word)))
1119 (cadr (cl-pop2 cl--loop-args))
fcd73769 1120 (error "Bad `using' clause"))
e542ea4b 1121 (make-symbol "--cl-var--"))))
fcd73769
RS
1122 (if (memq word '(hash-value hash-values))
1123 (setq var (prog1 other (setq other var))))
4dd1c416 1124 (setq cl--loop-map-form
e542ea4b 1125 `(maphash (lambda (,var ,other) . --cl-map) ,table))))
fcd73769
RS
1126
1127 ((memq word '(symbol present-symbol external-symbol
1128 symbols present-symbols external-symbols))
4dd1c416
SM
1129 (let ((ob (and (memq (car cl--loop-args) '(in of)) (cl-pop2 cl--loop-args))))
1130 (setq cl--loop-map-form
e542ea4b 1131 `(mapatoms (lambda (,var) . --cl-map) ,ob))))
fcd73769
RS
1132
1133 ((memq word '(overlay overlays extent extents))
1134 (let ((buf nil) (from nil) (to nil))
4dd1c416
SM
1135 (while (memq (car cl--loop-args) '(in of from to))
1136 (cond ((eq (car cl--loop-args) 'from) (setq from (cl-pop2 cl--loop-args)))
1137 ((eq (car cl--loop-args) 'to) (setq to (cl-pop2 cl--loop-args)))
1138 (t (setq buf (cl-pop2 cl--loop-args)))))
1139 (setq cl--loop-map-form
bb3faf5b 1140 `(cl--map-overlays
e542ea4b
SM
1141 (lambda (,var ,(make-symbol "--cl-var--"))
1142 (progn . --cl-map) nil)
1143 ,buf ,from ,to))))
fcd73769
RS
1144
1145 ((memq word '(interval intervals))
1146 (let ((buf nil) (prop nil) (from nil) (to nil)
e542ea4b
SM
1147 (var1 (make-symbol "--cl-var1--"))
1148 (var2 (make-symbol "--cl-var2--")))
4dd1c416
SM
1149 (while (memq (car cl--loop-args) '(in of property from to))
1150 (cond ((eq (car cl--loop-args) 'from) (setq from (cl-pop2 cl--loop-args)))
1151 ((eq (car cl--loop-args) 'to) (setq to (cl-pop2 cl--loop-args)))
1152 ((eq (car cl--loop-args) 'property)
1153 (setq prop (cl-pop2 cl--loop-args)))
1154 (t (setq buf (cl-pop2 cl--loop-args)))))
fcd73769
RS
1155 (if (and (consp var) (symbolp (car var)) (symbolp (cdr var)))
1156 (setq var1 (car var) var2 (cdr var))
03fef3e6 1157 (push (list var `(cons ,var1 ,var2)) loop-for-sets))
4dd1c416 1158 (setq cl--loop-map-form
bb3faf5b 1159 `(cl--map-intervals
e542ea4b
SM
1160 (lambda (,var1 ,var2) . --cl-map)
1161 ,buf ,prop ,from ,to))))
fcd73769
RS
1162
1163 ((memq word key-types)
4dd1c416
SM
1164 (or (memq (car cl--loop-args) '(in of)) (error "Expected `of'"))
1165 (let ((cl-map (cl-pop2 cl--loop-args))
1166 (other (if (eq (car cl--loop-args) 'using)
1167 (if (and (= (length (cadr cl--loop-args)) 2)
1168 (memq (cl-caadr cl--loop-args) key-types)
1169 (not (eq (cl-caadr cl--loop-args) word)))
1170 (cadr (cl-pop2 cl--loop-args))
fcd73769 1171 (error "Bad `using' clause"))
e542ea4b 1172 (make-symbol "--cl-var--"))))
fcd73769
RS
1173 (if (memq word '(key-binding key-bindings))
1174 (setq var (prog1 other (setq other var))))
4dd1c416 1175 (setq cl--loop-map-form
e542ea4b 1176 `(,(if (memq word '(key-seq key-seqs))
bb3faf5b 1177 'cl--map-keymap-recursively 'map-keymap)
7c1898a7 1178 (lambda (,var ,other) . --cl-map) ,cl-map))))
fcd73769
RS
1179
1180 ((memq word '(frame frames screen screens))
e542ea4b 1181 (let ((temp (make-symbol "--cl-var--")))
69d8fb1e 1182 (push (list var '(selected-frame))
e542ea4b 1183 loop-for-bindings)
69d8fb1e 1184 (push (list temp nil) loop-for-bindings)
03fef3e6
SM
1185 (push `(prog1 (not (eq ,var ,temp))
1186 (or ,temp (setq ,temp ,var)))
4dd1c416 1187 cl--loop-body)
03fef3e6 1188 (push (list var `(next-frame ,var))
e542ea4b 1189 loop-for-steps)))
fcd73769
RS
1190
1191 ((memq word '(window windows))
4dd1c416 1192 (let ((scr (and (memq (car cl--loop-args) '(in of)) (cl-pop2 cl--loop-args)))
05907bb3
GM
1193 (temp (make-symbol "--cl-var--"))
1194 (minip (make-symbol "--cl-minip--")))
69d8fb1e 1195 (push (list var (if scr
03fef3e6 1196 `(frame-selected-window ,scr)
e542ea4b
SM
1197 '(selected-window)))
1198 loop-for-bindings)
05907bb3
GM
1199 ;; If we started in the minibuffer, we need to
1200 ;; ensure that next-window will bring us back there
1201 ;; at some point. (Bug#7492).
7c1898a7 1202 ;; (Consider using walk-windows instead of cl-loop if
05907bb3
GM
1203 ;; you care about such things.)
1204 (push (list minip `(minibufferp (window-buffer ,var)))
1205 loop-for-bindings)
69d8fb1e 1206 (push (list temp nil) loop-for-bindings)
03fef3e6
SM
1207 (push `(prog1 (not (eq ,var ,temp))
1208 (or ,temp (setq ,temp ,var)))
4dd1c416 1209 cl--loop-body)
03fef3e6 1210 (push (list var `(next-window ,var ,minip))
05907bb3 1211 loop-for-steps)))
fcd73769
RS
1212
1213 (t
1214 (let ((handler (and (symbolp word)
4dd1c416 1215 (get word 'cl--loop-for-handler))))
fcd73769
RS
1216 (if handler
1217 (funcall handler var)
1218 (error "Expected a `for' preposition, found %s" word)))))
4dd1c416 1219 (eq (car cl--loop-args) 'and))
fcd73769 1220 (setq ands t)
4dd1c416 1221 (pop cl--loop-args))
fcd73769 1222 (if (and ands loop-for-bindings)
4dd1c416
SM
1223 (push (nreverse loop-for-bindings) cl--loop-bindings)
1224 (setq cl--loop-bindings (nconc (mapcar 'list loop-for-bindings)
1225 cl--loop-bindings)))
fcd73769 1226 (if loop-for-sets
03fef3e6 1227 (push `(progn
4dd1c416
SM
1228 ,(cl--loop-let (nreverse loop-for-sets) 'setq ands)
1229 t) cl--loop-body))
fcd73769 1230 (if loop-for-steps
7c1898a7 1231 (push (cons (if ands 'cl-psetq 'setq)
e542ea4b 1232 (apply 'append (nreverse loop-for-steps)))
4dd1c416 1233 cl--loop-steps))))
fcd73769
RS
1234
1235 ((eq word 'repeat)
e542ea4b 1236 (let ((temp (make-symbol "--cl-var--")))
4dd1c416
SM
1237 (push (list (list temp (pop cl--loop-args))) cl--loop-bindings)
1238 (push `(>= (setq ,temp (1- ,temp)) 0) cl--loop-body)))
fcd73769 1239
ae1aa776 1240 ((memq word '(collect collecting))
4dd1c416
SM
1241 (let ((what (pop cl--loop-args))
1242 (var (cl--loop-handle-accum nil 'nreverse)))
1243 (if (eq var cl--loop-accum-var)
1244 (push `(progn (push ,what ,var) t) cl--loop-body)
03fef3e6
SM
1245 (push `(progn
1246 (setq ,var (nconc ,var (list ,what)))
4dd1c416 1247 t) cl--loop-body))))
fcd73769
RS
1248
1249 ((memq word '(nconc nconcing append appending))
4dd1c416
SM
1250 (let ((what (pop cl--loop-args))
1251 (var (cl--loop-handle-accum nil 'nreverse)))
03fef3e6
SM
1252 (push `(progn
1253 (setq ,var
4dd1c416 1254 ,(if (eq var cl--loop-accum-var)
03fef3e6
SM
1255 `(nconc
1256 (,(if (memq word '(nconc nconcing))
1257 #'nreverse #'reverse)
1258 ,what)
1259 ,var)
1260 `(,(if (memq word '(nconc nconcing))
1261 #'nconc #'append)
4dd1c416 1262 ,var ,what))) t) cl--loop-body)))
fcd73769
RS
1263
1264 ((memq word '(concat concating))
4dd1c416
SM
1265 (let ((what (pop cl--loop-args))
1266 (var (cl--loop-handle-accum "")))
1267 (push `(progn (cl-callf concat ,var ,what) t) cl--loop-body)))
fcd73769
RS
1268
1269 ((memq word '(vconcat vconcating))
4dd1c416
SM
1270 (let ((what (pop cl--loop-args))
1271 (var (cl--loop-handle-accum [])))
1272 (push `(progn (cl-callf vconcat ,var ,what) t) cl--loop-body)))
fcd73769
RS
1273
1274 ((memq word '(sum summing))
4dd1c416
SM
1275 (let ((what (pop cl--loop-args))
1276 (var (cl--loop-handle-accum 0)))
1277 (push `(progn (cl-incf ,var ,what) t) cl--loop-body)))
fcd73769
RS
1278
1279 ((memq word '(count counting))
4dd1c416
SM
1280 (let ((what (pop cl--loop-args))
1281 (var (cl--loop-handle-accum 0)))
1282 (push `(progn (if ,what (cl-incf ,var)) t) cl--loop-body)))
fcd73769
RS
1283
1284 ((memq word '(minimize minimizing maximize maximizing))
4dd1c416
SM
1285 (let* ((what (pop cl--loop-args))
1286 (temp (if (cl--simple-expr-p what) what (make-symbol "--cl-var--")))
1287 (var (cl--loop-handle-accum nil))
fcd73769 1288 (func (intern (substring (symbol-name word) 0 3)))
03fef3e6
SM
1289 (set `(setq ,var (if ,var (,func ,var ,temp) ,temp))))
1290 (push `(progn ,(if (eq temp what) set
1291 `(let ((,temp ,what)) ,set))
4dd1c416 1292 t) cl--loop-body)))
fcd73769
RS
1293
1294 ((eq word 'with)
1295 (let ((bindings nil))
4dd1c416
SM
1296 (while (progn (push (list (pop cl--loop-args)
1297 (and (eq (car cl--loop-args) '=) (cl-pop2 cl--loop-args)))
e542ea4b 1298 bindings)
4dd1c416
SM
1299 (eq (car cl--loop-args) 'and))
1300 (pop cl--loop-args))
1301 (push (nreverse bindings) cl--loop-bindings)))
fcd73769
RS
1302
1303 ((eq word 'while)
4dd1c416 1304 (push (pop cl--loop-args) cl--loop-body))
fcd73769
RS
1305
1306 ((eq word 'until)
4dd1c416 1307 (push `(not ,(pop cl--loop-args)) cl--loop-body))
fcd73769
RS
1308
1309 ((eq word 'always)
4dd1c416
SM
1310 (or cl--loop-finish-flag (setq cl--loop-finish-flag (make-symbol "--cl-flag--")))
1311 (push `(setq ,cl--loop-finish-flag ,(pop cl--loop-args)) cl--loop-body)
1312 (setq cl--loop-result t))
fcd73769
RS
1313
1314 ((eq word 'never)
4dd1c416
SM
1315 (or cl--loop-finish-flag (setq cl--loop-finish-flag (make-symbol "--cl-flag--")))
1316 (push `(setq ,cl--loop-finish-flag (not ,(pop cl--loop-args)))
1317 cl--loop-body)
1318 (setq cl--loop-result t))
fcd73769
RS
1319
1320 ((eq word 'thereis)
4dd1c416
SM
1321 (or cl--loop-finish-flag (setq cl--loop-finish-flag (make-symbol "--cl-flag--")))
1322 (or cl--loop-result-var (setq cl--loop-result-var (make-symbol "--cl-var--")))
1323 (push `(setq ,cl--loop-finish-flag
1324 (not (setq ,cl--loop-result-var ,(pop cl--loop-args))))
1325 cl--loop-body))
fcd73769
RS
1326
1327 ((memq word '(if when unless))
4dd1c416
SM
1328 (let* ((cond (pop cl--loop-args))
1329 (then (let ((cl--loop-body nil))
fcd73769 1330 (cl-parse-loop-clause)
4dd1c416
SM
1331 (cl--loop-build-ands (nreverse cl--loop-body))))
1332 (else (let ((cl--loop-body nil))
1333 (if (eq (car cl--loop-args) 'else)
1334 (progn (pop cl--loop-args) (cl-parse-loop-clause)))
1335 (cl--loop-build-ands (nreverse cl--loop-body))))
fcd73769 1336 (simple (and (eq (car then) t) (eq (car else) t))))
4dd1c416 1337 (if (eq (car cl--loop-args) 'end) (pop cl--loop-args))
fcd73769
RS
1338 (if (eq word 'unless) (setq then (prog1 else (setq else then))))
1339 (let ((form (cons (if simple (cons 'progn (nth 1 then)) (nth 2 then))
1340 (if simple (nth 1 else) (list (nth 2 else))))))
4dd1c416 1341 (if (cl--expr-contains form 'it)
e542ea4b 1342 (let ((temp (make-symbol "--cl-var--")))
4dd1c416 1343 (push (list temp) cl--loop-bindings)
03fef3e6 1344 (setq form `(if (setq ,temp ,cond)
7c1898a7 1345 ,@(cl-subst temp 'it form))))
03fef3e6 1346 (setq form `(if ,cond ,@form)))
4dd1c416 1347 (push (if simple `(progn ,form t) form) cl--loop-body))))
fcd73769
RS
1348
1349 ((memq word '(do doing))
1350 (let ((body nil))
4dd1c416
SM
1351 (or (consp (car cl--loop-args)) (error "Syntax error on `do' clause"))
1352 (while (consp (car cl--loop-args)) (push (pop cl--loop-args) body))
1353 (push (cons 'progn (nreverse (cons t body))) cl--loop-body)))
fcd73769
RS
1354
1355 ((eq word 'return)
4dd1c416
SM
1356 (or cl--loop-finish-flag (setq cl--loop-finish-flag (make-symbol "--cl-var--")))
1357 (or cl--loop-result-var (setq cl--loop-result-var (make-symbol "--cl-var--")))
1358 (push `(setq ,cl--loop-result-var ,(pop cl--loop-args)
1359 ,cl--loop-finish-flag nil) cl--loop-body))
fcd73769
RS
1360
1361 (t
4dd1c416 1362 (let ((handler (and (symbolp word) (get word 'cl--loop-handler))))
7c1898a7 1363 (or handler (error "Expected a cl-loop keyword, found %s" word))
fcd73769 1364 (funcall handler))))
4dd1c416
SM
1365 (if (eq (car cl--loop-args) 'and)
1366 (progn (pop cl--loop-args) (cl-parse-loop-clause)))))
fcd73769 1367
4dd1c416 1368(defun cl--loop-let (specs body par) ; uses loop-*
fcd73769 1369 (let ((p specs) (temps nil) (new nil))
7c1898a7 1370 (while (and p (or (symbolp (car-safe (car p))) (null (cl-cadar p))))
fcd73769
RS
1371 (setq p (cdr p)))
1372 (and par p
1373 (progn
1374 (setq par nil p specs)
1375 (while p
4dd1c416 1376 (or (macroexp-const-p (cl-cadar p))
e542ea4b 1377 (let ((temp (make-symbol "--cl-var--")))
7c1898a7 1378 (push (list temp (cl-cadar p)) temps)
fcd73769
RS
1379 (setcar (cdar p) temp)))
1380 (setq p (cdr p)))))
1381 (while specs
1382 (if (and (consp (car specs)) (listp (caar specs)))
1383 (let* ((spec (caar specs)) (nspecs nil)
69d8fb1e 1384 (expr (cadr (pop specs)))
4dd1c416 1385 (temp (cdr (or (assq spec cl--loop-destr-temps)
69d8fb1e 1386 (car (push (cons spec (or (last spec 0)
e542ea4b 1387 (make-symbol "--cl-var--")))
4dd1c416 1388 cl--loop-destr-temps))))))
69d8fb1e 1389 (push (list temp expr) new)
fcd73769 1390 (while (consp spec)
69d8fb1e 1391 (push (list (pop spec)
fcd73769
RS
1392 (and expr (list (if spec 'pop 'car) temp)))
1393 nspecs))
1394 (setq specs (nconc (nreverse nspecs) specs)))
69d8fb1e 1395 (push (pop specs) new)))
fcd73769 1396 (if (eq body 'setq)
7c1898a7 1397 (let ((set (cons (if par 'cl-psetq 'setq) (apply 'nconc (nreverse new)))))
03fef3e6
SM
1398 (if temps `(let* ,(nreverse temps) ,set) set))
1399 `(,(if par 'let 'let*)
1400 ,(nconc (nreverse temps) (nreverse new)) ,@body))))
fcd73769 1401
4dd1c416
SM
1402(defun cl--loop-handle-accum (def &optional func) ; uses loop-*
1403 (if (eq (car cl--loop-args) 'into)
1404 (let ((var (cl-pop2 cl--loop-args)))
1405 (or (memq var cl--loop-accum-vars)
1406 (progn (push (list (list var def)) cl--loop-bindings)
1407 (push var cl--loop-accum-vars)))
fcd73769 1408 var)
4dd1c416 1409 (or cl--loop-accum-var
fcd73769 1410 (progn
4dd1c416
SM
1411 (push (list (list (setq cl--loop-accum-var (make-symbol "--cl-var--")) def))
1412 cl--loop-bindings)
1413 (setq cl--loop-result (if func (list func cl--loop-accum-var)
1414 cl--loop-accum-var))
1415 cl--loop-accum-var))))
fcd73769 1416
4dd1c416 1417(defun cl--loop-build-ands (clauses)
fcd73769
RS
1418 (let ((ands nil)
1419 (body nil))
1420 (while clauses
1421 (if (and (eq (car-safe (car clauses)) 'progn)
1422 (eq (car (last (car clauses))) t))
1423 (if (cdr clauses)
1424 (setq clauses (cons (nconc (butlast (car clauses))
1425 (if (eq (car-safe (cadr clauses))
1426 'progn)
7c1898a7 1427 (cl-cdadr clauses)
fcd73769
RS
1428 (list (cadr clauses))))
1429 (cddr clauses)))
69d8fb1e
SM
1430 (setq body (cdr (butlast (pop clauses)))))
1431 (push (pop clauses) ands)))
fcd73769
RS
1432 (setq ands (or (nreverse ands) (list t)))
1433 (list (if (cdr ands) (cons 'and ands) (car ands))
1434 body
1435 (let ((full (if body
1436 (append ands (list (cons 'progn (append body '(t)))))
1437 ands)))
1438 (if (cdr full) (cons 'and full) (car full))))))
1439
1440
1441;;; Other iteration control structures.
1442
ebacfcc6 1443;;;###autoload
7c1898a7
SM
1444(defmacro cl-do (steps endtest &rest body)
1445 "The Common Lisp `cl-do' loop.
a766dfa1
JB
1446
1447\(fn ((VAR INIT [STEP])...) (END-TEST [RESULT...]) BODY...)"
70b8ef8f
SM
1448 (declare (indent 2)
1449 (debug
b1198e17
SM
1450 ((&rest &or symbolp (symbolp &optional form form))
1451 (form body)
1452 cl-declarations body)))
fcd73769
RS
1453 (cl-expand-do-loop steps endtest body nil))
1454
ebacfcc6 1455;;;###autoload
7c1898a7
SM
1456(defmacro cl-do* (steps endtest &rest body)
1457 "The Common Lisp `cl-do*' loop.
a766dfa1
JB
1458
1459\(fn ((VAR INIT [STEP])...) (END-TEST [RESULT...]) BODY...)"
7c1898a7 1460 (declare (indent 2) (debug cl-do))
fcd73769
RS
1461 (cl-expand-do-loop steps endtest body t))
1462
1463(defun cl-expand-do-loop (steps endtest body star)
7c1898a7 1464 `(cl-block nil
03fef3e6
SM
1465 (,(if star 'let* 'let)
1466 ,(mapcar (lambda (c) (if (consp c) (list (car c) (nth 1 c)) c))
1467 steps)
1468 (while (not ,(car endtest))
1469 ,@body
1470 ,@(let ((sets (mapcar (lambda (c)
1471 (and (consp c) (cdr (cdr c))
1472 (list (car c) (nth 2 c))))
1473 steps)))
1474 (setq sets (delq nil sets))
1475 (and sets
1476 (list (cons (if (or star (not (cdr sets)))
7c1898a7 1477 'setq 'cl-psetq)
03fef3e6
SM
1478 (apply 'append sets))))))
1479 ,@(or (cdr endtest) '(nil)))))
fcd73769 1480
ebacfcc6 1481;;;###autoload
7c1898a7 1482(defmacro cl-dolist (spec &rest body)
69d8fb1e 1483 "Loop over a list.
63744c0f 1484Evaluate BODY with VAR bound to each `car' from LIST, in turn.
69d8fb1e 1485Then evaluate RESULT to get return value, default nil.
ce887515 1486An implicit nil block is established around the loop.
69d8fb1e
SM
1487
1488\(fn (VAR LIST [RESULT]) BODY...)"
b1198e17 1489 (declare (debug ((symbolp form &optional form) cl-declarations body)))
e542ea4b 1490 (let ((temp (make-symbol "--cl-dolist-temp--")))
2462470b 1491 ;; FIXME: Copy&pasted from subr.el.
7c1898a7 1492 `(cl-block nil
2462470b
SM
1493 ;; This is not a reliable test, but it does not matter because both
1494 ;; semantics are acceptable, tho one is slightly faster with dynamic
1495 ;; scoping and the other is slightly faster (and has cleaner semantics)
1496 ;; with lexical scoping.
1497 ,(if lexical-binding
1498 `(let ((,temp ,(nth 1 spec)))
1499 (while ,temp
1500 (let ((,(car spec) (car ,temp)))
1501 ,@body
1502 (setq ,temp (cdr ,temp))))
1503 ,@(if (cdr (cdr spec))
1504 ;; FIXME: This let often leads to "unused var" warnings.
1505 `((let ((,(car spec) nil)) ,@(cdr (cdr spec))))))
1506 `(let ((,temp ,(nth 1 spec))
1507 ,(car spec))
1508 (while ,temp
1509 (setq ,(car spec) (car ,temp))
1510 ,@body
1511 (setq ,temp (cdr ,temp)))
1512 ,@(if (cdr (cdr spec))
1513 `((setq ,(car spec) nil) ,@(cddr spec))))))))
63744c0f 1514
ebacfcc6 1515;;;###autoload
7c1898a7 1516(defmacro cl-dotimes (spec &rest body)
69d8fb1e 1517 "Loop a certain number of times.
63744c0f
DL
1518Evaluate BODY with VAR bound to successive integers from 0, inclusive,
1519to COUNT, exclusive. Then evaluate RESULT to get return value, default
69d8fb1e
SM
1520nil.
1521
1522\(fn (VAR COUNT [RESULT]) BODY...)"
7c1898a7 1523 (declare (debug cl-dolist))
2462470b
SM
1524 (let ((temp (make-symbol "--cl-dotimes-temp--"))
1525 (end (nth 1 spec)))
1526 ;; FIXME: Copy&pasted from subr.el.
7c1898a7 1527 `(cl-block nil
2462470b
SM
1528 ;; This is not a reliable test, but it does not matter because both
1529 ;; semantics are acceptable, tho one is slightly faster with dynamic
1530 ;; scoping and the other has cleaner semantics.
1531 ,(if lexical-binding
1532 (let ((counter '--dotimes-counter--))
1533 `(let ((,temp ,end)
1534 (,counter 0))
1535 (while (< ,counter ,temp)
1536 (let ((,(car spec) ,counter))
1537 ,@body)
1538 (setq ,counter (1+ ,counter)))
1539 ,@(if (cddr spec)
1540 ;; FIXME: This let often leads to "unused var" warnings.
1541 `((let ((,(car spec) ,counter)) ,@(cddr spec))))))
1542 `(let ((,temp ,end)
1543 (,(car spec) 0))
1544 (while (< ,(car spec) ,temp)
1545 ,@body
7c1898a7 1546 (cl-incf ,(car spec)))
2462470b 1547 ,@(cdr (cdr spec)))))))
63744c0f 1548
ebacfcc6 1549;;;###autoload
7c1898a7 1550(defmacro cl-do-symbols (spec &rest body)
69d8fb1e 1551 "Loop over all symbols.
fcd73769 1552Evaluate BODY with VAR bound to each interned symbol, or to each symbol
69d8fb1e
SM
1553from OBARRAY.
1554
1555\(fn (VAR [OBARRAY [RESULT]]) BODY...)"
70b8ef8f
SM
1556 (declare (indent 1)
1557 (debug ((symbolp &optional form form) cl-declarations body)))
fcd73769 1558 ;; Apparently this doesn't have an implicit block.
7c1898a7 1559 `(cl-block nil
03fef3e6
SM
1560 (let (,(car spec))
1561 (mapatoms #'(lambda (,(car spec)) ,@body)
1562 ,@(and (cadr spec) (list (cadr spec))))
7c1898a7 1563 ,(cl-caddr spec))))
fcd73769 1564
ebacfcc6 1565;;;###autoload
7c1898a7 1566(defmacro cl-do-all-symbols (spec &rest body)
70b8ef8f 1567 (declare (indent 1) (debug ((symbolp &optional form) cl-declarations body)))
7c1898a7 1568 `(cl-do-symbols (,(car spec) nil ,(cadr spec)) ,@body))
fcd73769
RS
1569
1570
1571;;; Assignments.
1572
ebacfcc6 1573;;;###autoload
7c1898a7 1574(defmacro cl-psetq (&rest args)
69d8fb1e 1575 "Set SYMs to the values VALs in parallel.
fcd73769 1576This is like `setq', except that all VAL forms are evaluated (in order)
69d8fb1e
SM
1577before assigning any symbols SYM to the corresponding values.
1578
1579\(fn SYM VAL SYM VAL ...)"
b1198e17 1580 (declare (debug setq))
7c1898a7 1581 (cons 'cl-psetf args))
fcd73769
RS
1582
1583
1584;;; Binding control structures.
1585
ebacfcc6 1586;;;###autoload
7c1898a7 1587(defmacro cl-progv (symbols values &rest body)
64a4c526 1588 "Bind SYMBOLS to VALUES dynamically in BODY.
fcd73769 1589The forms SYMBOLS and VALUES are evaluated, and must evaluate to lists.
3187ba1c 1590Each symbol in the first list is bound to the corresponding value in the
fcd73769
RS
1591second list (or made unbound if VALUES is shorter than SYMBOLS); then the
1592BODY forms are executed and their result is returned. This is much like
1593a `let' form, except that the list of symbols can be computed at run-time."
70b8ef8f 1594 (declare (indent 2) (debug (form form body)))
bb3faf5b 1595 `(let ((cl--progv-save nil))
03fef3e6 1596 (unwind-protect
bb3faf5b
SM
1597 (progn (cl--progv-before ,symbols ,values) ,@body)
1598 (cl--progv-after))))
fcd73769 1599
de7e2b36
SM
1600(defvar cl--labels-convert-cache nil)
1601
1602(defun cl--labels-convert (f)
1603 "Special macro-expander to rename (function F) references in `cl-labels'."
1604 (cond
1605 ;; ¡¡Big Ugly Hack!! We can't use a compiler-macro because those are checked
1606 ;; *after* handling `function', but we want to stop macroexpansion from
1607 ;; being applied infinitely, so we use a cache to return the exact `form'
1608 ;; being expanded even though we don't receive it.
1609 ((eq f (car cl--labels-convert-cache)) (cdr cl--labels-convert-cache))
1610 (t
1611 (let ((found (assq f macroexpand-all-environment)))
1612 (if (and found (ignore-errors
1613 (eq (cadr (cl-caddr found)) 'cl-labels-args)))
1614 (cadr (cl-caddr (cl-cadddr found)))
1615 (let ((res `(function ,f)))
1616 (setq cl--labels-convert-cache (cons f res))
1617 res))))))
1618
fcd73769 1619;;; This should really have some way to shadow 'byte-compile properties, etc.
ebacfcc6 1620;;;###autoload
7c1898a7 1621(defmacro cl-flet (bindings &rest body)
3187ba1c 1622 "Make temporary function definitions.
de7e2b36 1623Like `cl-labels' but the definitions are not recursive.
69d8fb1e
SM
1624
1625\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
7c1898a7 1626 (declare (indent 1) (debug ((&rest (cl-defun)) cl-declarations body)))
de7e2b36
SM
1627 (let ((binds ()) (newenv macroexpand-all-environment))
1628 (dolist (binding bindings)
1629 (let ((var (make-symbol (format "--cl-%s--" (car binding)))))
1630 (push (list var `(cl-function (lambda . ,(cdr binding)))) binds)
1631 (push (cons (car binding)
1632 `(lambda (&rest cl-labels-args)
1633 (cl-list* 'funcall ',var
1634 cl-labels-args)))
1635 newenv)))
1636 `(let ,(nreverse binds)
1637 ,@(macroexp-unprogn
1638 (macroexpand-all
1639 `(progn ,@body)
1640 ;; Don't override lexical-let's macro-expander.
1641 (if (assq 'function newenv) newenv
1642 (cons (cons 'function #'cl--labels-convert) newenv)))))))
fcd73769 1643
ebacfcc6 1644;;;###autoload
7c1898a7 1645(defmacro cl-labels (bindings &rest body)
3187ba1c 1646 "Make temporary function bindings.
de7e2b36 1647The bindings can be recursive. Assumes the use of `lexical-binding'.
69d8fb1e
SM
1648
1649\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
7c1898a7 1650 (declare (indent 1) (debug cl-flet))
de7e2b36
SM
1651 (let ((binds ()) (newenv macroexpand-all-environment))
1652 (dolist (binding bindings)
1653 (let ((var (make-symbol (format "--cl-%s--" (car binding)))))
1654 (push (list var `(cl-function (lambda . ,(cdr binding)))) binds)
1655 (push (cons (car binding)
4dd1c416
SM
1656 `(lambda (&rest cl-labels-args)
1657 (cl-list* 'funcall ',var
1658 cl-labels-args)))
6fa6c4ae 1659 newenv)))
de7e2b36
SM
1660 (macroexpand-all `(letrec ,(nreverse binds) ,@body)
1661 ;; Don't override lexical-let's macro-expander.
1662 (if (assq 'function newenv) newenv
1663 (cons (cons 'function #'cl--labels-convert) newenv)))))
fcd73769
RS
1664
1665;; The following ought to have a better definition for use with newer
1666;; byte compilers.
ebacfcc6 1667;;;###autoload
7c1898a7 1668(defmacro cl-macrolet (bindings &rest body)
4342e957 1669 "Make temporary macro definitions.
7c1898a7 1670This is like `cl-flet', but for macros instead of functions.
69d8fb1e
SM
1671
1672\(fn ((NAME ARGLIST BODY...) ...) FORM...)"
70b8ef8f
SM
1673 (declare (indent 1)
1674 (debug
b1198e17
SM
1675 ((&rest (&define name (&rest arg) cl-declarations-or-string
1676 def-body))
1677 cl-declarations body)))
fcd73769 1678 (if (cdr bindings)
7c1898a7 1679 `(cl-macrolet (,(car bindings)) (cl-macrolet ,(cdr bindings) ,@body))
fcd73769
RS
1680 (if (null bindings) (cons 'progn body)
1681 (let* ((name (caar bindings))
4dd1c416 1682 (res (cl--transform-lambda (cdar bindings) name)))
fcd73769 1683 (eval (car res))
6fa6c4ae
SM
1684 (macroexpand-all (cons 'progn body)
1685 (cons (cons name `(lambda ,@(cdr res)))
1686 macroexpand-all-environment))))))
1687
1688(defconst cl--old-macroexpand
1689 (if (and (boundp 'cl--old-macroexpand)
1690 (eq (symbol-function 'macroexpand)
1691 #'cl--sm-macroexpand))
1692 cl--old-macroexpand
1693 (symbol-function 'macroexpand)))
1694
1695(defun cl--sm-macroexpand (cl-macro &optional cl-env)
1696 "Special macro expander used inside `cl-symbol-macrolet'.
1697This function replaces `macroexpand' during macro expansion
1698of `cl-symbol-macrolet', and does the same thing as `macroexpand'
1699except that it additionally expands symbol macros."
1700 (let ((macroexpand-all-environment cl-env))
1701 (while
1702 (progn
1703 (setq cl-macro (funcall cl--old-macroexpand cl-macro cl-env))
1704 (cond
1705 ((symbolp cl-macro)
1706 ;; Perform symbol-macro expansion.
1707 (when (cdr (assq (symbol-name cl-macro) cl-env))
1708 (setq cl-macro (cadr (assq (symbol-name cl-macro) cl-env)))))
1709 ((eq 'setq (car-safe cl-macro))
1710 ;; Convert setq to cl-setf if required by symbol-macro expansion.
1711 (let* ((args (mapcar (lambda (f) (cl--sm-macroexpand f cl-env))
1712 (cdr cl-macro)))
1713 (p args))
1714 (while (and p (symbolp (car p))) (setq p (cddr p)))
1715 (if p (setq cl-macro (cons 'cl-setf args))
1716 (setq cl-macro (cons 'setq args))
1717 ;; Don't loop further.
1718 nil))))))
1719 cl-macro))
fcd73769 1720
ebacfcc6 1721;;;###autoload
7c1898a7 1722(defmacro cl-symbol-macrolet (bindings &rest body)
4342e957 1723 "Make symbol macro definitions.
fcd73769 1724Within the body FORMs, references to the variable NAME will be replaced
7c1898a7 1725by EXPANSION, and (setq NAME ...) will act like (cl-setf EXPANSION ...).
69d8fb1e
SM
1726
1727\(fn ((NAME EXPANSION) ...) FORM...)"
70b8ef8f 1728 (declare (indent 1) (debug ((&rest (symbol sexp)) cl-declarations body)))
6fa6c4ae
SM
1729 (cond
1730 ((cdr bindings)
7c1898a7 1731 `(cl-symbol-macrolet (,(car bindings))
6fa6c4ae
SM
1732 (cl-symbol-macrolet ,(cdr bindings) ,@body)))
1733 ((null bindings) (macroexp-progn body))
1734 (t
1735 (let ((previous-macroexpand (symbol-function 'macroexpand)))
1736 (unwind-protect
1737 (progn
1738 (fset 'macroexpand #'cl--sm-macroexpand)
1739 ;; FIXME: For N bindings, this will traverse `body' N times!
1740 (macroexpand-all (cons 'progn body)
fcd73769 1741 (cons (list (symbol-name (caar bindings))
7c1898a7 1742 (cl-cadar bindings))
6fa6c4ae
SM
1743 macroexpand-all-environment)))
1744 (fset 'macroexpand previous-macroexpand))))))
fcd73769 1745
fcd73769
RS
1746;;; Multiple values.
1747
ebacfcc6 1748;;;###autoload
7c1898a7 1749(defmacro cl-multiple-value-bind (vars form &rest body)
69d8fb1e 1750 "Collect multiple return values.
fcd73769
RS
1751FORM must return a list; the BODY is then executed with the first N elements
1752of this list bound (`let'-style) to each of the symbols SYM in turn. This
7c1898a7
SM
1753is analogous to the Common Lisp `cl-multiple-value-bind' macro, using lists to
1754simulate true multiple return values. For compatibility, (cl-values A B C) is
69d8fb1e
SM
1755a synonym for (list A B C).
1756
3187ba1c 1757\(fn (SYM...) FORM BODY)"
70b8ef8f 1758 (declare (indent 2) (debug ((&rest symbolp) form body)))
e542ea4b 1759 (let ((temp (make-symbol "--cl-var--")) (n -1))
03fef3e6
SM
1760 `(let* ((,temp ,form)
1761 ,@(mapcar (lambda (v)
1762 (list v `(nth ,(setq n (1+ n)) ,temp)))
1763 vars))
1764 ,@body)))
fcd73769 1765
ebacfcc6 1766;;;###autoload
7c1898a7 1767(defmacro cl-multiple-value-setq (vars form)
69d8fb1e 1768 "Collect multiple return values.
fcd73769
RS
1769FORM must return a list; the first N elements of this list are stored in
1770each of the symbols SYM in turn. This is analogous to the Common Lisp
7c1898a7
SM
1771`cl-multiple-value-setq' macro, using lists to simulate true multiple return
1772values. For compatibility, (cl-values A B C) is a synonym for (list A B C).
69d8fb1e 1773
3187ba1c 1774\(fn (SYM...) FORM)"
70b8ef8f 1775 (declare (indent 1) (debug ((&rest symbolp) form)))
03fef3e6
SM
1776 (cond ((null vars) `(progn ,form nil))
1777 ((null (cdr vars)) `(setq ,(car vars) (car ,form)))
fcd73769 1778 (t
e542ea4b 1779 (let* ((temp (make-symbol "--cl-var--")) (n 0))
03fef3e6
SM
1780 `(let ((,temp ,form))
1781 (prog1 (setq ,(pop vars) (car ,temp))
1782 (setq ,@(apply #'nconc
1783 (mapcar (lambda (v)
1784 (list v `(nth ,(setq n (1+ n))
1785 ,temp)))
1786 vars)))))))))
fcd73769
RS
1787
1788
1789;;; Declarations.
1790
ebacfcc6 1791;;;###autoload
7c1898a7 1792(defmacro cl-locally (&rest body)
b1198e17
SM
1793 (declare (debug t))
1794 (cons 'progn body))
ebacfcc6 1795;;;###autoload
513749ee 1796(defmacro cl-the (_type form)
70b8ef8f 1797 (declare (indent 1) (debug (cl-type-spec form)))
b1198e17 1798 form)
fcd73769
RS
1799
1800(defvar cl-proclaim-history t) ; for future compilers
1801(defvar cl-declare-stack t) ; for future compilers
1802
1803(defun cl-do-proclaim (spec hist)
69d8fb1e 1804 (and hist (listp cl-proclaim-history) (push spec cl-proclaim-history))
fcd73769
RS
1805 (cond ((eq (car-safe spec) 'special)
1806 (if (boundp 'byte-compile-bound-variables)
1807 (setq byte-compile-bound-variables
1808 (append (cdr spec) byte-compile-bound-variables))))
1809
1810 ((eq (car-safe spec) 'inline)
1811 (while (setq spec (cdr spec))
1812 (or (memq (get (car spec) 'byte-optimizer)
1813 '(nil byte-compile-inline-expand))
1814 (error "%s already has a byte-optimizer, can't make it inline"
1815 (car spec)))
1816 (put (car spec) 'byte-optimizer 'byte-compile-inline-expand)))
1817
1818 ((eq (car-safe spec) 'notinline)
1819 (while (setq spec (cdr spec))
1820 (if (eq (get (car spec) 'byte-optimizer)
1821 'byte-compile-inline-expand)
1822 (put (car spec) 'byte-optimizer nil))))
1823
1824 ((eq (car-safe spec) 'optimize)
1825 (let ((speed (assq (nth 1 (assq 'speed (cdr spec)))
1826 '((0 nil) (1 t) (2 t) (3 t))))
1827 (safety (assq (nth 1 (assq 'safety (cdr spec)))
1828 '((0 t) (1 t) (2 t) (3 nil)))))
1829 (if speed (setq cl-optimize-speed (car speed)
1830 byte-optimize (nth 1 speed)))
1831 (if safety (setq cl-optimize-safety (car safety)
1832 byte-compile-delete-errors (nth 1 safety)))))
1833
1834 ((and (eq (car-safe spec) 'warn) (boundp 'byte-compile-warnings))
fcd73769
RS
1835 (while (setq spec (cdr spec))
1836 (if (consp (car spec))
7c1898a7 1837 (if (eq (cl-cadar spec) 0)
bc8ce89b
GM
1838 (byte-compile-disable-warning (caar spec))
1839 (byte-compile-enable-warning (caar spec)))))))
fcd73769
RS
1840 nil)
1841
1842;;; Process any proclamations made before cl-macs was loaded.
1843(defvar cl-proclaims-deferred)
1844(let ((p (reverse cl-proclaims-deferred)))
69d8fb1e 1845 (while p (cl-do-proclaim (pop p) t))
fcd73769
RS
1846 (setq cl-proclaims-deferred nil))
1847
ebacfcc6 1848;;;###autoload
7c1898a7 1849(defmacro cl-declare (&rest specs)
c39da690 1850 "Declare SPECS about the current function while compiling.
4bf0979f
LMI
1851For instance
1852
7c1898a7 1853 \(cl-declare (warn 0))
4bf0979f 1854
dbc44fcd
LMI
1855will turn off byte-compile warnings in the function.
1856See Info node `(cl)Declarations' for details."
bb3faf5b 1857 (if (cl--compiling-file)
fcd73769 1858 (while specs
69d8fb1e
SM
1859 (if (listp cl-declare-stack) (push (car specs) cl-declare-stack))
1860 (cl-do-proclaim (pop specs) nil)))
fcd73769
RS
1861 nil)
1862
1863
1864
1865;;; Generalized variables.
1866
ebacfcc6 1867;;;###autoload
4dd1c416 1868(defmacro cl-define-setf-expander (func args &rest body)
7c1898a7
SM
1869 "Define a `cl-setf' method.
1870This method shows how to handle `cl-setf's to places of the form (NAME ARGS...).
fcd73769
RS
1871The argument forms ARGS are bound according to ARGLIST, as if NAME were
1872going to be expanded as a macro, then the BODY forms are executed and must
1873return a list of five elements: a temporary-variables list, a value-forms
1874list, a store-variables list (of length one), a store-form, and an access-
7c1898a7 1875form. See `cl-defsetf' for a simpler way to define most setf-methods.
69d8fb1e
SM
1876
1877\(fn NAME ARGLIST BODY...)"
b1198e17
SM
1878 (declare (debug
1879 (&define name cl-lambda-list cl-declarations-or-string def-body)))
7c1898a7 1880 `(cl-eval-when (compile load eval)
03fef3e6
SM
1881 ,@(if (stringp (car body))
1882 (list `(put ',func 'setf-documentation ,(pop body))))
4302f5ba 1883 (put ',func 'setf-method (cl-function (lambda ,args ,@body)))))
fcd73769 1884
ebacfcc6 1885;;;###autoload
7c1898a7
SM
1886(defmacro cl-defsetf (func arg1 &rest args)
1887 "Define a `cl-setf' method.
4dd1c416 1888This macro is an easy-to-use substitute for `cl-define-setf-expander' that works
7c1898a7
SM
1889well for simple place forms. In the simple `cl-defsetf' form, `cl-setf's of
1890the form (cl-setf (NAME ARGS...) VAL) are transformed to function or macro
358e4d6d
JB
1891calls of the form (FUNC ARGS... VAL). Example:
1892
7c1898a7 1893 (cl-defsetf aref aset)
358e4d6d 1894
7c1898a7
SM
1895Alternate form: (cl-defsetf NAME ARGLIST (STORE) BODY...).
1896Here, the above `cl-setf' call is expanded by binding the argument forms ARGS
fcd73769 1897according to ARGLIST, binding the value form VAL to STORE, then executing
7c1898a7 1898BODY, which must return a Lisp form that does the necessary `cl-setf' operation.
fcd73769
RS
1899Actually, ARGLIST and STORE may be bound to temporary variables which are
1900introduced automatically to preserve proper execution order of the arguments.
358e4d6d
JB
1901Example:
1902
7c1898a7 1903 (cl-defsetf nth (n x) (v) `(setcar (nthcdr ,n ,x) ,v))
358e4d6d
JB
1904
1905\(fn NAME [FUNC | ARGLIST (STORE) BODY...])"
b1198e17
SM
1906 (declare (debug
1907 (&define name
1908 [&or [symbolp &optional stringp]
1909 [cl-lambda-list (symbolp)]]
1910 cl-declarations-or-string def-body)))
cb7d9531 1911 (if (and (listp arg1) (consp args))
fcd73769
RS
1912 (let* ((largs nil) (largsr nil)
1913 (temps nil) (tempsr nil)
1914 (restarg nil) (rest-temps nil)
1915 (store-var (car (prog1 (car args) (setq args (cdr args)))))
1916 (store-temp (intern (format "--%s--temp--" store-var)))
1917 (lets1 nil) (lets2 nil)
1918 (docstr nil) (p arg1))
1919 (if (stringp (car args))
1920 (setq docstr (prog1 (car args) (setq args (cdr args)))))
1921 (while (and p (not (eq (car p) '&aux)))
1922 (if (eq (car p) '&rest)
1923 (setq p (cdr p) restarg (car p))
1924 (or (memq (car p) '(&optional &key &allow-other-keys))
1925 (setq largs (cons (if (consp (car p)) (car (car p)) (car p))
1926 largs)
1927 temps (cons (intern (format "--%s--temp--" (car largs)))
1928 temps))))
1929 (setq p (cdr p)))
1930 (setq largs (nreverse largs) temps (nreverse temps))
1931 (if restarg
1932 (setq largsr (append largs (list restarg))
1933 rest-temps (intern (format "--%s--temp--" restarg))
1934 tempsr (append temps (list rest-temps)))
1935 (setq largsr largs tempsr temps))
1936 (let ((p1 largs) (p2 temps))
1937 (while p1
e542ea4b
SM
1938 (setq lets1 (cons `(,(car p2)
1939 (make-symbol ,(format "--cl-%s--" (car p1))))
fcd73769
RS
1940 lets1)
1941 lets2 (cons (list (car p1) (car p2)) lets2)
1942 p1 (cdr p1) p2 (cdr p2))))
1943 (if restarg (setq lets2 (cons (list restarg rest-temps) lets2)))
4dd1c416 1944 `(cl-define-setf-expander ,func ,arg1
e542ea4b
SM
1945 ,@(and docstr (list docstr))
1946 (let*
1947 ,(nreverse
1948 (cons `(,store-temp
1949 (make-symbol ,(format "--cl-%s--" store-var)))
1950 (if restarg
1951 `((,rest-temps
1952 (mapcar (lambda (_) (make-symbol "--cl-var--"))
1953 ,restarg))
1954 ,@lets1)
1955 lets1)))
1956 (list ; 'values
7c1898a7
SM
1957 (,(if restarg 'cl-list* 'list) ,@tempsr)
1958 (,(if restarg 'cl-list* 'list) ,@largsr)
e542ea4b
SM
1959 (list ,store-temp)
1960 (let*
1961 ,(nreverse
1962 (cons (list store-var store-temp)
1963 lets2))
1964 ,@args)
7c1898a7 1965 (,(if restarg 'cl-list* 'list)
03fef3e6 1966 ,@(cons `',func tempsr))))))
7c1898a7 1967 `(cl-defsetf ,func (&rest args) (store)
e542ea4b
SM
1968 ,(let ((call `(cons ',arg1
1969 (append args (list store)))))
1970 (if (car args)
1971 `(list 'progn ,call store)
1972 call)))))
fcd73769
RS
1973
1974;;; Some standard place types from Common Lisp.
7c1898a7
SM
1975(cl-defsetf aref aset)
1976(cl-defsetf car setcar)
1977(cl-defsetf cdr setcdr)
1978(cl-defsetf caar (x) (val) `(setcar (car ,x) ,val))
1979(cl-defsetf cadr (x) (val) `(setcar (cdr ,x) ,val))
1980(cl-defsetf cdar (x) (val) `(setcdr (car ,x) ,val))
1981(cl-defsetf cddr (x) (val) `(setcdr (cdr ,x) ,val))
1982(cl-defsetf elt (seq n) (store)
03fef3e6
SM
1983 `(if (listp ,seq) (setcar (nthcdr ,n ,seq) ,store)
1984 (aset ,seq ,n ,store)))
7c1898a7
SM
1985(cl-defsetf get put)
1986(cl-defsetf cl-get (x y &optional d) (store) `(put ,x ,y ,store))
1987(cl-defsetf gethash (x h &optional d) (store) `(puthash ,x ,store ,h))
1988(cl-defsetf nth (n x) (store) `(setcar (nthcdr ,n ,x) ,store))
1989(cl-defsetf cl-subseq (seq start &optional end) (new)
1990 `(progn (cl-replace ,seq ,new :start1 ,start :end1 ,end) ,new))
1991(cl-defsetf symbol-function fset)
1992(cl-defsetf symbol-plist setplist)
1993(cl-defsetf symbol-value set)
fcd73769
RS
1994
1995;;; Various car/cdr aliases. Note that `cadr' is handled specially.
7c1898a7
SM
1996(cl-defsetf cl-first setcar)
1997(cl-defsetf cl-second (x) (store) `(setcar (cdr ,x) ,store))
1998(cl-defsetf cl-third (x) (store) `(setcar (cddr ,x) ,store))
1999(cl-defsetf cl-fourth (x) (store) `(setcar (cl-cdddr ,x) ,store))
2000(cl-defsetf cl-fifth (x) (store) `(setcar (nthcdr 4 ,x) ,store))
2001(cl-defsetf cl-sixth (x) (store) `(setcar (nthcdr 5 ,x) ,store))
2002(cl-defsetf cl-seventh (x) (store) `(setcar (nthcdr 6 ,x) ,store))
2003(cl-defsetf cl-eighth (x) (store) `(setcar (nthcdr 7 ,x) ,store))
2004(cl-defsetf cl-ninth (x) (store) `(setcar (nthcdr 8 ,x) ,store))
2005(cl-defsetf cl-tenth (x) (store) `(setcar (nthcdr 9 ,x) ,store))
2006(cl-defsetf cl-rest setcdr)
fcd73769
RS
2007
2008;;; Some more Emacs-related place types.
7c1898a7
SM
2009(cl-defsetf buffer-file-name set-visited-file-name t)
2010(cl-defsetf buffer-modified-p (&optional buf) (flag)
03fef3e6
SM
2011 `(with-current-buffer ,buf
2012 (set-buffer-modified-p ,flag)))
7c1898a7
SM
2013(cl-defsetf buffer-name rename-buffer t)
2014(cl-defsetf buffer-string () (store)
03fef3e6 2015 `(progn (erase-buffer) (insert ,store)))
bb3faf5b 2016(cl-defsetf buffer-substring cl--set-buffer-substring)
7c1898a7
SM
2017(cl-defsetf current-buffer set-buffer)
2018(cl-defsetf current-case-table set-case-table)
2019(cl-defsetf current-column move-to-column t)
2020(cl-defsetf current-global-map use-global-map t)
2021(cl-defsetf current-input-mode () (store)
03fef3e6 2022 `(progn (apply #'set-input-mode ,store) ,store))
7c1898a7
SM
2023(cl-defsetf current-local-map use-local-map t)
2024(cl-defsetf current-window-configuration set-window-configuration t)
2025(cl-defsetf default-file-modes set-default-file-modes t)
2026(cl-defsetf default-value set-default)
2027(cl-defsetf documentation-property put)
2028(cl-defsetf face-background (f &optional s) (x) `(set-face-background ,f ,x ,s))
2029(cl-defsetf face-background-pixmap (f &optional s) (x)
03fef3e6 2030 `(set-face-background-pixmap ,f ,x ,s))
7c1898a7
SM
2031(cl-defsetf face-font (f &optional s) (x) `(set-face-font ,f ,x ,s))
2032(cl-defsetf face-foreground (f &optional s) (x) `(set-face-foreground ,f ,x ,s))
2033(cl-defsetf face-underline-p (f &optional s) (x)
03fef3e6 2034 `(set-face-underline-p ,f ,x ,s))
7c1898a7
SM
2035(cl-defsetf file-modes set-file-modes t)
2036(cl-defsetf frame-height set-screen-height t)
2037(cl-defsetf frame-parameters modify-frame-parameters t)
bb3faf5b 2038(cl-defsetf frame-visible-p cl--set-frame-visible-p)
7c1898a7
SM
2039(cl-defsetf frame-width set-screen-width t)
2040(cl-defsetf frame-parameter set-frame-parameter t)
2041(cl-defsetf terminal-parameter set-terminal-parameter)
2042(cl-defsetf getenv setenv t)
2043(cl-defsetf get-register set-register)
2044(cl-defsetf global-key-binding global-set-key)
2045(cl-defsetf keymap-parent set-keymap-parent)
2046(cl-defsetf local-key-binding local-set-key)
2047(cl-defsetf mark set-mark t)
2048(cl-defsetf mark-marker set-mark t)
2049(cl-defsetf marker-position set-marker t)
2050(cl-defsetf match-data set-match-data t)
2051(cl-defsetf mouse-position (scr) (store)
03fef3e6
SM
2052 `(set-mouse-position ,scr (car ,store) (cadr ,store)
2053 (cddr ,store)))
7c1898a7
SM
2054(cl-defsetf overlay-get overlay-put)
2055(cl-defsetf overlay-start (ov) (store)
03fef3e6 2056 `(progn (move-overlay ,ov ,store (overlay-end ,ov)) ,store))
7c1898a7 2057(cl-defsetf overlay-end (ov) (store)
03fef3e6 2058 `(progn (move-overlay ,ov (overlay-start ,ov) ,store) ,store))
7c1898a7
SM
2059(cl-defsetf point goto-char)
2060(cl-defsetf point-marker goto-char t)
2061(cl-defsetf point-max () (store)
03fef3e6 2062 `(progn (narrow-to-region (point-min) ,store) ,store))
7c1898a7 2063(cl-defsetf point-min () (store)
03fef3e6 2064 `(progn (narrow-to-region ,store (point-max)) ,store))
7c1898a7
SM
2065(cl-defsetf process-buffer set-process-buffer)
2066(cl-defsetf process-filter set-process-filter)
2067(cl-defsetf process-sentinel set-process-sentinel)
2068(cl-defsetf process-get process-put)
2069(cl-defsetf read-mouse-position (scr) (store)
03fef3e6 2070 `(set-mouse-position ,scr (car ,store) (cdr ,store)))
7c1898a7
SM
2071(cl-defsetf screen-height set-screen-height t)
2072(cl-defsetf screen-width set-screen-width t)
2073(cl-defsetf selected-window select-window)
2074(cl-defsetf selected-screen select-screen)
2075(cl-defsetf selected-frame select-frame)
2076(cl-defsetf standard-case-table set-standard-case-table)
2077(cl-defsetf syntax-table set-syntax-table)
2078(cl-defsetf visited-file-modtime set-visited-file-modtime t)
2079(cl-defsetf window-buffer set-window-buffer t)
2080(cl-defsetf window-display-table set-window-display-table t)
2081(cl-defsetf window-dedicated-p set-window-dedicated-p t)
2082(cl-defsetf window-height () (store)
03fef3e6 2083 `(progn (enlarge-window (- ,store (window-height))) ,store))
7c1898a7
SM
2084(cl-defsetf window-hscroll set-window-hscroll)
2085(cl-defsetf window-parameter set-window-parameter)
2086(cl-defsetf window-point set-window-point)
2087(cl-defsetf window-start set-window-start)
2088(cl-defsetf window-width () (store)
03fef3e6 2089 `(progn (enlarge-window (- ,store (window-width)) t) ,store))
7c1898a7
SM
2090(cl-defsetf x-get-secondary-selection x-own-secondary-selection t)
2091(cl-defsetf x-get-selection x-own-selection t)
fcd73769 2092
7c1898a7 2093;; This is a hack that allows (cl-setf (eq a 7) B) to mean either
f44379e7
SM
2094;; (setq a 7) or (setq a nil) depending on whether B is nil or not.
2095;; This is useful when you have control over the PLACE but not over
2096;; the VALUE, as is the case in define-minor-mode's :variable.
4dd1c416 2097(cl-define-setf-expander eq (place val)
6fa6c4ae 2098 (let ((method (cl-get-setf-method place macroexpand-all-environment))
80ac5d4d
SM
2099 (val-temp (make-symbol "--eq-val--"))
2100 (store-temp (make-symbol "--eq-store--")))
2101 (list (append (nth 0 method) (list val-temp))
2102 (append (nth 1 method) (list val))
2103 (list store-temp)
2104 `(let ((,(car (nth 2 method))
2105 (if ,store-temp ,val-temp (not ,val-temp))))
2106 ,(nth 3 method) ,store-temp)
2107 `(eq ,(nth 4 method) ,val-temp))))
f44379e7 2108
fcd73769 2109;;; More complex setf-methods.
f44379e7
SM
2110;; These should take &environment arguments, but since full arglists aren't
2111;; available while compiling cl-macs, we fake it by referring to the global
6fa6c4ae 2112;; variable macroexpand-all-environment directly.
fcd73769 2113
4dd1c416 2114(cl-define-setf-expander apply (func arg1 &rest rest)
7c1898a7 2115 (or (and (memq (car-safe func) '(quote function cl-function))
fcd73769 2116 (symbolp (car-safe (cdr-safe func))))
7c1898a7 2117 (error "First arg to apply in cl-setf is not (function SYM): %s" func))
fcd73769 2118 (let* ((form (cons (nth 1 func) (cons arg1 rest)))
6fa6c4ae 2119 (method (cl-get-setf-method form macroexpand-all-environment)))
fcd73769
RS
2120 (list (car method) (nth 1 method) (nth 2 method)
2121 (cl-setf-make-apply (nth 3 method) (cadr func) (car method))
2122 (cl-setf-make-apply (nth 4 method) (cadr func) (car method)))))
2123
2124(defun cl-setf-make-apply (form func temps)
2125 (if (eq (car form) 'progn)
03fef3e6 2126 `(progn ,(cl-setf-make-apply (cadr form) func temps) ,@(cddr form))
fcd73769
RS
2127 (or (equal (last form) (last temps))
2128 (error "%s is not suitable for use with setf-of-apply" func))
03fef3e6 2129 `(apply ',(car form) ,@(cdr form))))
fcd73769 2130
4dd1c416 2131(cl-define-setf-expander nthcdr (n place)
6fa6c4ae 2132 (let ((method (cl-get-setf-method place macroexpand-all-environment))
e542ea4b
SM
2133 (n-temp (make-symbol "--cl-nthcdr-n--"))
2134 (store-temp (make-symbol "--cl-nthcdr-store--")))
fcd73769
RS
2135 (list (cons n-temp (car method))
2136 (cons n (nth 1 method))
2137 (list store-temp)
03fef3e6 2138 `(let ((,(car (nth 2 method))
bb3faf5b
SM
2139 (cl--set-nthcdr ,n-temp ,(nth 4 method)
2140 ,store-temp)))
03fef3e6
SM
2141 ,(nth 3 method) ,store-temp)
2142 `(nthcdr ,n-temp ,(nth 4 method)))))
fcd73769 2143
4dd1c416 2144(cl-define-setf-expander cl-getf (place tag &optional def)
6fa6c4ae 2145 (let ((method (cl-get-setf-method place macroexpand-all-environment))
e542ea4b
SM
2146 (tag-temp (make-symbol "--cl-getf-tag--"))
2147 (def-temp (make-symbol "--cl-getf-def--"))
2148 (store-temp (make-symbol "--cl-getf-store--")))
fcd73769
RS
2149 (list (append (car method) (list tag-temp def-temp))
2150 (append (nth 1 method) (list tag def))
2151 (list store-temp)
03fef3e6 2152 `(let ((,(car (nth 2 method))
bb3faf5b 2153 (cl--set-getf ,(nth 4 method) ,tag-temp ,store-temp)))
03fef3e6 2154 ,(nth 3 method) ,store-temp)
7c1898a7 2155 `(cl-getf ,(nth 4 method) ,tag-temp ,def-temp))))
fcd73769 2156
4dd1c416 2157(cl-define-setf-expander substring (place from &optional to)
6fa6c4ae 2158 (let ((method (cl-get-setf-method place macroexpand-all-environment))
e542ea4b
SM
2159 (from-temp (make-symbol "--cl-substring-from--"))
2160 (to-temp (make-symbol "--cl-substring-to--"))
2161 (store-temp (make-symbol "--cl-substring-store--")))
fcd73769
RS
2162 (list (append (car method) (list from-temp to-temp))
2163 (append (nth 1 method) (list from to))
2164 (list store-temp)
03fef3e6 2165 `(let ((,(car (nth 2 method))
bb3faf5b
SM
2166 (cl--set-substring ,(nth 4 method)
2167 ,from-temp ,to-temp ,store-temp)))
03fef3e6
SM
2168 ,(nth 3 method) ,store-temp)
2169 `(substring ,(nth 4 method) ,from-temp ,to-temp))))
fcd73769
RS
2170
2171;;; Getting and optimizing setf-methods.
ebacfcc6 2172;;;###autoload
7c1898a7 2173(defun cl-get-setf-method (place &optional env)
fcd73769
RS
2174 "Return a list of five values describing the setf-method for PLACE.
2175PLACE may be any Lisp form which can appear as the PLACE argument to
7c1898a7 2176a macro like `cl-setf' or `cl-incf'."
fcd73769 2177 (if (symbolp place)
e542ea4b 2178 (let ((temp (make-symbol "--cl-setf--")))
03fef3e6 2179 (list nil nil (list temp) `(setq ,place ,temp) place))
fcd73769
RS
2180 (or (and (symbolp (car place))
2181 (let* ((func (car place))
2182 (name (symbol-name func))
2183 (method (get func 'setf-method))
2184 (case-fold-search nil))
2185 (or (and method
6fa6c4ae 2186 (let ((macroexpand-all-environment env))
fcd73769
RS
2187 (setq method (apply method (cdr place))))
2188 (if (and (consp method) (= (length method) 5))
2189 method
2190 (error "Setf-method for %s returns malformed method"
2191 func)))
20e3d3f1 2192 (and (string-match-p "\\`c[ad][ad][ad]?[ad]?r\\'" name)
7c1898a7 2193 (cl-get-setf-method (cl-compiler-macroexpand place)))
fcd73769 2194 (and (eq func 'edebug-after)
7c1898a7 2195 (cl-get-setf-method (nth (1- (length place)) place)
fcd73769
RS
2196 env)))))
2197 (if (eq place (setq place (macroexpand place env)))
2198 (if (and (symbolp (car place)) (fboundp (car place))
2199 (symbolp (symbol-function (car place))))
7c1898a7 2200 (cl-get-setf-method (cons (symbol-function (car place))
fcd73769
RS
2201 (cdr place)) env)
2202 (error "No setf-method known for %s" (car place)))
7c1898a7 2203 (cl-get-setf-method place env)))))
fcd73769
RS
2204
2205(defun cl-setf-do-modify (place opt-expr)
6fa6c4ae 2206 (let* ((method (cl-get-setf-method place macroexpand-all-environment))
fcd73769
RS
2207 (temps (car method)) (values (nth 1 method))
2208 (lets nil) (subs nil)
2209 (optimize (and (not (eq opt-expr 'no-opt))
2210 (or (and (not (eq opt-expr 'unsafe))
4dd1c416 2211 (cl--safe-expr-p opt-expr))
fcd73769
RS
2212 (cl-setf-simple-store-p (car (nth 2 method))
2213 (nth 3 method)))))
4dd1c416 2214 (simple (and optimize (consp place) (cl--simple-exprs-p (cdr place)))))
fcd73769 2215 (while values
4dd1c416 2216 (if (or simple (macroexp-const-p (car values)))
69d8fb1e
SM
2217 (push (cons (pop temps) (pop values)) subs)
2218 (push (list (pop temps) (pop values)) lets)))
fcd73769 2219 (list (nreverse lets)
7c1898a7
SM
2220 (cons (car (nth 2 method)) (cl-sublis subs (nth 3 method)))
2221 (cl-sublis subs (nth 4 method)))))
fcd73769
RS
2222
2223(defun cl-setf-do-store (spec val)
2224 (let ((sym (car spec))
2225 (form (cdr spec)))
4dd1c416
SM
2226 (if (or (macroexp-const-p val)
2227 (and (cl--simple-expr-p val) (eq (cl--expr-contains form sym) 1))
fcd73769 2228 (cl-setf-simple-store-p sym form))
7c1898a7 2229 (cl-subst val sym form)
03fef3e6 2230 `(let ((,sym ,val)) ,form))))
fcd73769
RS
2231
2232(defun cl-setf-simple-store-p (sym form)
4dd1c416 2233 (and (consp form) (eq (cl--expr-contains form sym) 1)
fcd73769
RS
2234 (eq (nth (1- (length form)) form) sym)
2235 (symbolp (car form)) (fboundp (car form))
2236 (not (eq (car-safe (symbol-function (car form))) 'macro))))
2237
2238;;; The standard modify macros.
ebacfcc6 2239;;;###autoload
7c1898a7 2240(defmacro cl-setf (&rest args)
69d8fb1e 2241 "Set each PLACE to the value of its VAL.
fcd73769
RS
2242This is a generalized version of `setq'; the PLACEs may be symbolic
2243references such as (car x) or (aref x i), as well as plain symbols.
7c1898a7 2244For example, (cl-setf (cl-cadar x) y) is equivalent to (setcar (cdar x) y).
69d8fb1e
SM
2245The return value is the last VAL in the list.
2246
2247\(fn PLACE VAL PLACE VAL ...)"
b1198e17 2248 (declare (debug (&rest [place form])))
fcd73769
RS
2249 (if (cdr (cdr args))
2250 (let ((sets nil))
7c1898a7 2251 (while args (push `(cl-setf ,(pop args) ,(pop args)) sets))
fcd73769
RS
2252 (cons 'progn (nreverse sets)))
2253 (if (symbolp (car args))
2254 (and args (cons 'setq args))
2255 (let* ((method (cl-setf-do-modify (car args) (nth 1 args)))
2256 (store (cl-setf-do-store (nth 1 method) (nth 1 args))))
03fef3e6 2257 (if (car method) `(let* ,(car method) ,store) store)))))
fcd73769 2258
ebacfcc6 2259;;;###autoload
7c1898a7 2260(defmacro cl-psetf (&rest args)
69d8fb1e 2261 "Set PLACEs to the values VALs in parallel.
7c1898a7 2262This is like `cl-setf', except that all VAL forms are evaluated (in order)
69d8fb1e
SM
2263before assigning any PLACEs to the corresponding values.
2264
2265\(fn PLACE VAL PLACE VAL ...)"
7c1898a7 2266 (declare (debug cl-setf))
fcd73769
RS
2267 (let ((p args) (simple t) (vars nil))
2268 (while p
4dd1c416 2269 (if (or (not (symbolp (car p))) (cl--expr-depends-p (nth 1 p) vars))
fcd73769
RS
2270 (setq simple nil))
2271 (if (memq (car p) vars)
2272 (error "Destination duplicated in psetf: %s" (car p)))
69d8fb1e 2273 (push (pop p) vars)
7c1898a7 2274 (or p (error "Odd number of arguments to cl-psetf"))
69d8fb1e 2275 (pop p))
fcd73769 2276 (if simple
7c1898a7 2277 `(progn (cl-setf ,@args) nil)
fcd73769 2278 (setq args (reverse args))
7c1898a7 2279 (let ((expr `(cl-setf ,(cadr args) ,(car args))))
fcd73769 2280 (while (setq args (cddr args))
7c1898a7 2281 (setq expr `(cl-setf ,(cadr args) (prog1 ,(car args) ,expr))))
03fef3e6 2282 `(progn ,expr nil)))))
fcd73769 2283
ebacfcc6 2284;;;###autoload
fcd73769 2285(defun cl-do-pop (place)
4dd1c416 2286 (if (cl--simple-expr-p place)
7c1898a7 2287 `(prog1 (car ,place) (cl-setf ,place (cdr ,place)))
fcd73769 2288 (let* ((method (cl-setf-do-modify place t))
e542ea4b 2289 (temp (make-symbol "--cl-pop--")))
03fef3e6
SM
2290 `(let* (,@(car method)
2291 (,temp ,(nth 2 method)))
2292 (prog1 (car ,temp)
2293 ,(cl-setf-do-store (nth 1 method) `(cdr ,temp)))))))
fcd73769 2294
ebacfcc6 2295;;;###autoload
7c1898a7 2296(defmacro cl-remf (place tag)
64a4c526 2297 "Remove TAG from property list PLACE.
7c1898a7 2298PLACE may be a symbol, or any generalized variable allowed by `cl-setf'.
fcd73769 2299The form returns true if TAG was found and removed, nil otherwise."
b1198e17 2300 (declare (debug (place form)))
fcd73769 2301 (let* ((method (cl-setf-do-modify place t))
4dd1c416
SM
2302 (tag-temp (and (not (macroexp-const-p tag)) (make-symbol "--cl-remf-tag--")))
2303 (val-temp (and (not (cl--simple-expr-p place))
e542ea4b 2304 (make-symbol "--cl-remf-place--")))
fcd73769
RS
2305 (ttag (or tag-temp tag))
2306 (tval (or val-temp (nth 2 method))))
03fef3e6
SM
2307 `(let* (,@(car method)
2308 ,@(and val-temp `((,val-temp ,(nth 2 method))))
2309 ,@(and tag-temp `((,tag-temp ,tag))))
2310 (if (eq ,ttag (car ,tval))
2311 (progn ,(cl-setf-do-store (nth 1 method) `(cddr ,tval))
2312 t)
ad4d226c 2313 (cl--do-remf ,tval ,ttag)))))
fcd73769 2314
ebacfcc6 2315;;;###autoload
7c1898a7 2316(defmacro cl-shiftf (place &rest args)
69d8fb1e 2317 "Shift left among PLACEs.
7c1898a7
SM
2318Example: (cl-shiftf A B C) sets A to B, B to C, and returns the old A.
2319Each PLACE may be a symbol, or any generalized variable allowed by `cl-setf'.
69d8fb1e 2320
3187ba1c 2321\(fn PLACE... VAL)"
b1198e17 2322 (declare (debug (&rest place)))
2fa5eef4
SM
2323 (cond
2324 ((null args) place)
7c1898a7 2325 ((symbolp place) `(prog1 ,place (setq ,place (cl-shiftf ,@args))))
2fa5eef4
SM
2326 (t
2327 (let ((method (cl-setf-do-modify place 'unsafe)))
2328 `(let* ,(car method)
2329 (prog1 ,(nth 2 method)
7c1898a7 2330 ,(cl-setf-do-store (nth 1 method) `(cl-shiftf ,@args))))))))
fcd73769 2331
ebacfcc6 2332;;;###autoload
7c1898a7 2333(defmacro cl-rotatef (&rest args)
69d8fb1e 2334 "Rotate left among PLACEs.
7c1898a7
SM
2335Example: (cl-rotatef A B C) sets A to B, B to C, and C to A. It returns nil.
2336Each PLACE may be a symbol, or any generalized variable allowed by `cl-setf'.
69d8fb1e
SM
2337
2338\(fn PLACE...)"
b1198e17 2339 (declare (debug (&rest place)))
fcd73769
RS
2340 (if (not (memq nil (mapcar 'symbolp args)))
2341 (and (cdr args)
2342 (let ((sets nil)
2343 (first (car args)))
2344 (while (cdr args)
69d8fb1e 2345 (setq sets (nconc sets (list (pop args) (car args)))))
7c1898a7 2346 `(cl-psetf ,@sets ,(car args) ,first)))
fcd73769 2347 (let* ((places (reverse args))
e542ea4b 2348 (temp (make-symbol "--cl-rotatef--"))
fcd73769
RS
2349 (form temp))
2350 (while (cdr places)
69d8fb1e 2351 (let ((method (cl-setf-do-modify (pop places) 'unsafe)))
03fef3e6
SM
2352 (setq form `(let* ,(car method)
2353 (prog1 ,(nth 2 method)
2354 ,(cl-setf-do-store (nth 1 method) form))))))
fcd73769 2355 (let ((method (cl-setf-do-modify (car places) 'unsafe)))
03fef3e6
SM
2356 `(let* (,@(car method) (,temp ,(nth 2 method)))
2357 ,(cl-setf-do-store (nth 1 method) form) nil)))))
fcd73769 2358
ebacfcc6 2359;;;###autoload
7c1898a7 2360(defmacro cl-letf (bindings &rest body)
69d8fb1e 2361 "Temporarily bind to PLACEs.
fcd73769 2362This is the analogue of `let', but with generalized variables (in the
7c1898a7 2363sense of `cl-setf') for the PLACEs. Each PLACE is set to the corresponding
fcd73769
RS
2364VALUE, then the BODY forms are executed. On exit, either normally or
2365because of a `throw' or error, the PLACEs are set back to their original
2366values. Note that this macro is *not* available in Common Lisp.
2367As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)',
69d8fb1e
SM
2368the PLACE is not modified before executing BODY.
2369
2370\(fn ((PLACE VALUE) ...) BODY...)"
70b8ef8f 2371 (declare (indent 1) (debug ((&rest (gate place &optional form)) body)))
fcd73769 2372 (if (and (not (cdr bindings)) (cdar bindings) (symbolp (caar bindings)))
03fef3e6 2373 `(let ,bindings ,@body)
513749ee
SM
2374 (let ((lets nil)
2375 (rev (reverse bindings)))
fcd73769
RS
2376 (while rev
2377 (let* ((place (if (symbolp (caar rev))
03fef3e6 2378 `(symbol-value ',(caar rev))
fcd73769 2379 (caar rev)))
7c1898a7 2380 (value (cl-cadar rev))
fcd73769 2381 (method (cl-setf-do-modify place 'no-opt))
e542ea4b 2382 (save (make-symbol "--cl-letf-save--"))
fcd73769 2383 (bound (and (memq (car place) '(symbol-value symbol-function))
e542ea4b 2384 (make-symbol "--cl-letf-bound--")))
4dd1c416 2385 (temp (and (not (macroexp-const-p value)) (cdr bindings)
e542ea4b 2386 (make-symbol "--cl-letf-val--"))))
fcd73769
RS
2387 (setq lets (nconc (car method)
2388 (if bound
2389 (list (list bound
2390 (list (if (eq (car place)
2391 'symbol-value)
2392 'boundp 'fboundp)
2393 (nth 1 (nth 2 method))))
03fef3e6
SM
2394 (list save `(and ,bound
2395 ,(nth 2 method))))
fcd73769
RS
2396 (list (list save (nth 2 method))))
2397 (and temp (list (list temp value)))
2398 lets)
2399 body (list
03fef3e6
SM
2400 `(unwind-protect
2401 (progn
2402 ,@(if (cdr (car rev))
2403 (cons (cl-setf-do-store (nth 1 method)
2404 (or temp value))
2405 body)
2406 body))
2407 ,(if bound
2408 `(if ,bound
2409 ,(cl-setf-do-store (nth 1 method) save)
2410 (,(if (eq (car place) 'symbol-value)
2411 #'makunbound #'fmakunbound)
2412 ,(nth 1 (nth 2 method))))
2413 (cl-setf-do-store (nth 1 method) save))))
fcd73769 2414 rev (cdr rev))))
03fef3e6
SM
2415 `(let* ,lets ,@body))))
2416
fcd73769 2417
ebacfcc6 2418;;;###autoload
7c1898a7 2419(defmacro cl-letf* (bindings &rest body)
69d8fb1e 2420 "Temporarily bind to PLACEs.
fcd73769 2421This is the analogue of `let*', but with generalized variables (in the
7c1898a7 2422sense of `cl-setf') for the PLACEs. Each PLACE is set to the corresponding
fcd73769
RS
2423VALUE, then the BODY forms are executed. On exit, either normally or
2424because of a `throw' or error, the PLACEs are set back to their original
2425values. Note that this macro is *not* available in Common Lisp.
2426As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)',
69d8fb1e
SM
2427the PLACE is not modified before executing BODY.
2428
2429\(fn ((PLACE VALUE) ...) BODY...)"
7c1898a7 2430 (declare (indent 1) (debug cl-letf))
fcd73769
RS
2431 (if (null bindings)
2432 (cons 'progn body)
2433 (setq bindings (reverse bindings))
2434 (while bindings
7c1898a7 2435 (setq body (list `(cl-letf (,(pop bindings)) ,@body))))
fcd73769
RS
2436 (car body)))
2437
ebacfcc6 2438;;;###autoload
7c1898a7 2439(defmacro cl-callf (func place &rest args)
69d8fb1e 2440 "Set PLACE to (FUNC PLACE ARGS...).
fcd73769 2441FUNC should be an unquoted function name. PLACE may be a symbol,
7c1898a7 2442or any generalized variable allowed by `cl-setf'.
69d8fb1e
SM
2443
2444\(fn FUNC PLACE ARGS...)"
7c1898a7 2445 (declare (indent 2) (debug (cl-function place &rest form)))
fcd73769
RS
2446 (let* ((method (cl-setf-do-modify place (cons 'list args)))
2447 (rargs (cons (nth 2 method) args)))
03fef3e6
SM
2448 `(let* ,(car method)
2449 ,(cl-setf-do-store (nth 1 method)
2450 (if (symbolp func) (cons func rargs)
2451 `(funcall #',func ,@rargs))))))
fcd73769 2452
ebacfcc6 2453;;;###autoload
7c1898a7 2454(defmacro cl-callf2 (func arg1 place &rest args)
69d8fb1e 2455 "Set PLACE to (FUNC ARG1 PLACE ARGS...).
7c1898a7 2456Like `cl-callf', but PLACE is the second argument of FUNC, not the first.
69d8fb1e
SM
2457
2458\(fn FUNC ARG1 PLACE ARGS...)"
7c1898a7 2459 (declare (indent 3) (debug (cl-function form place &rest form)))
4dd1c416 2460 (if (and (cl--safe-expr-p arg1) (cl--simple-expr-p place) (symbolp func))
7c1898a7 2461 `(cl-setf ,place (,func ,arg1 ,place ,@args))
fcd73769 2462 (let* ((method (cl-setf-do-modify place (cons 'list args)))
4dd1c416 2463 (temp (and (not (macroexp-const-p arg1)) (make-symbol "--cl-arg1--")))
7c1898a7 2464 (rargs (cl-list* (or temp arg1) (nth 2 method) args)))
03fef3e6
SM
2465 `(let* (,@(and temp (list (list temp arg1))) ,@(car method))
2466 ,(cl-setf-do-store (nth 1 method)
2467 (if (symbolp func) (cons func rargs)
2468 `(funcall #',func ,@rargs)))))))
fcd73769 2469
ebacfcc6 2470;;;###autoload
7c1898a7
SM
2471(defmacro cl-define-modify-macro (name arglist func &optional doc)
2472 "Define a `cl-setf'-like modify macro.
fcd73769 2473If NAME is called, it combines its PLACE argument with the other arguments
7c1898a7 2474from ARGLIST using FUNC: (cl-define-modify-macro cl-incf (&optional (n 1)) +)"
b1198e17
SM
2475 (declare (debug
2476 (&define name cl-lambda-list ;; should exclude &key
2477 symbolp &optional stringp)))
7c1898a7 2478 (if (memq '&key arglist) (error "&key not allowed in cl-define-modify-macro"))
e542ea4b 2479 (let ((place (make-symbol "--cl-place--")))
7c1898a7 2480 `(cl-defmacro ,name (,place ,@arglist)
03fef3e6 2481 ,doc
7c1898a7
SM
2482 (,(if (memq '&rest arglist) #'cl-list* #'list)
2483 #'cl-callf ',func ,place
4dd1c416 2484 ,@(cl--arglist-args arglist)))))
fcd73769
RS
2485
2486
2487;;; Structures.
2488
ebacfcc6 2489;;;###autoload
7c1898a7 2490(defmacro cl-defstruct (struct &rest descs)
69d8fb1e 2491 "Define a struct type.
c7dc1ac1
CY
2492This macro defines a new data type called NAME that stores data
2493in SLOTs. It defines a `make-NAME' constructor, a `copy-NAME'
2494copier, a `NAME-p' predicate, and slot accessors named `NAME-SLOT'.
7c1898a7 2495You can use the accessors to set the corresponding slots, via `cl-setf'.
69d8fb1e 2496
c7dc1ac1
CY
2497NAME may instead take the form (NAME OPTIONS...), where each
2498OPTION is either a single keyword or (KEYWORD VALUE).
2499See Info node `(cl)Structures' for a list of valid keywords.
2500
2501Each SLOT may instead take the form (SLOT SLOT-OPTS...), where
2502SLOT-OPTS are keyword-value pairs for that slot. Currently, only
2503one keyword is supported, `:read-only'. If this has a non-nil
7c1898a7 2504value, that slot cannot be set via `cl-setf'.
c7dc1ac1
CY
2505
2506\(fn NAME SLOTS...)"
b581bb5c
SM
2507 (declare (doc-string 2)
2508 (debug
b1198e17
SM
2509 (&define ;Makes top-level form not be wrapped.
2510 [&or symbolp
2511 (gate
2512 symbolp &rest
2513 (&or [":conc-name" symbolp]
2514 [":constructor" symbolp &optional cl-lambda-list]
2515 [":copier" symbolp]
2516 [":predicate" symbolp]
2517 [":include" symbolp &rest sexp] ;; Not finished.
2518 ;; The following are not supported.
2519 ;; [":print-function" ...]
2520 ;; [":type" ...]
2521 ;; [":initial-offset" ...]
2522 ))]
2523 [&optional stringp]
2524 ;; All the above is for the following def-form.
2525 &rest &or symbolp (symbolp def-form
2526 &optional ":read-only" sexp))))
fcd73769
RS
2527 (let* ((name (if (consp struct) (car struct) struct))
2528 (opts (cdr-safe struct))
2529 (slots nil)
2530 (defaults nil)
2531 (conc-name (concat (symbol-name name) "-"))
2532 (constructor (intern (format "make-%s" name)))
2533 (constrs nil)
2534 (copier (intern (format "copy-%s" name)))
2535 (predicate (intern (format "%s-p" name)))
2536 (print-func nil) (print-auto nil)
bb3faf5b 2537 (safety (if (cl--compiling-file) cl-optimize-safety 3))
fcd73769
RS
2538 (include nil)
2539 (tag (intern (format "cl-struct-%s" name)))
2540 (tag-symbol (intern (format "cl-struct-%s-tags" name)))
2541 (include-descs nil)
fcd73769
RS
2542 (side-eff nil)
2543 (type nil)
2544 (named nil)
2545 (forms nil)
2546 pred-form pred-check)
2547 (if (stringp (car descs))
03fef3e6
SM
2548 (push `(put ',name 'structure-documentation
2549 ,(pop descs)) forms))
fcd73769
RS
2550 (setq descs (cons '(cl-tag-slot)
2551 (mapcar (function (lambda (x) (if (consp x) x (list x))))
2552 descs)))
2553 (while opts
2554 (let ((opt (if (consp (car opts)) (caar opts) (car opts)))
69d8fb1e 2555 (args (cdr-safe (pop opts))))
64a4c526 2556 (cond ((eq opt :conc-name)
fcd73769
RS
2557 (if args
2558 (setq conc-name (if (car args)
2559 (symbol-name (car args)) ""))))
64a4c526 2560 ((eq opt :constructor)
fcd73769 2561 (if (cdr args)
40e8a6c3
SM
2562 (progn
2563 ;; If this defines a constructor of the same name as
2564 ;; the default one, don't define the default.
2565 (if (eq (car args) constructor)
2566 (setq constructor nil))
2567 (push args constrs))
fcd73769 2568 (if args (setq constructor (car args)))))
64a4c526 2569 ((eq opt :copier)
fcd73769 2570 (if args (setq copier (car args))))
64a4c526 2571 ((eq opt :predicate)
fcd73769 2572 (if args (setq predicate (car args))))
64a4c526 2573 ((eq opt :include)
fcd73769
RS
2574 (setq include (car args)
2575 include-descs (mapcar (function
2576 (lambda (x)
2577 (if (consp x) x (list x))))
36f0f2b1 2578 (cdr args))))
64a4c526 2579 ((eq opt :print-function)
fcd73769 2580 (setq print-func (car args)))
64a4c526 2581 ((eq opt :type)
fcd73769 2582 (setq type (car args)))
64a4c526 2583 ((eq opt :named)
fcd73769 2584 (setq named t))
64a4c526 2585 ((eq opt :initial-offset)
fcd73769
RS
2586 (setq descs (nconc (make-list (car args) '(cl-skip-slot))
2587 descs)))
2588 (t
2589 (error "Slot option %s unrecognized" opt)))))
2590 (if print-func
03fef3e6
SM
2591 (setq print-func
2592 `(progn (funcall #',print-func cl-x cl-s cl-n) t))
fcd73769
RS
2593 (or type (and include (not (get include 'cl-struct-print)))
2594 (setq print-auto t
2595 print-func (and (or (not (or include type)) (null print-func))
03fef3e6
SM
2596 `(progn
2597 (princ ,(format "#S(%s" name) cl-s))))))
fcd73769
RS
2598 (if include
2599 (let ((inc-type (get include 'cl-struct-type))
2600 (old-descs (get include 'cl-struct-slots)))
2601 (or inc-type (error "%s is not a struct name" include))
2602 (and type (not (eq (car inc-type) type))
2603 (error ":type disagrees with :include for %s" name))
2604 (while include-descs
2605 (setcar (memq (or (assq (caar include-descs) old-descs)
2606 (error "No slot %s in included struct %s"
2607 (caar include-descs) include))
2608 old-descs)
69d8fb1e 2609 (pop include-descs)))
fcd73769
RS
2610 (setq descs (append old-descs (delq (assq 'cl-tag-slot descs) descs))
2611 type (car inc-type)
2612 named (assq 'cl-tag-slot descs))
2613 (if (cadr inc-type) (setq tag name named t))
36f0f2b1
RS
2614 (let ((incl include))
2615 (while incl
7c1898a7 2616 (push `(cl-pushnew ',tag
03fef3e6
SM
2617 ,(intern (format "cl-struct-%s-tags" incl)))
2618 forms)
36f0f2b1 2619 (setq incl (get incl 'cl-struct-include)))))
fcd73769
RS
2620 (if type
2621 (progn
2622 (or (memq type '(vector list))
4920bd1e 2623 (error "Invalid :type specifier: %s" type))
fcd73769
RS
2624 (if named (setq tag name)))
2625 (setq type 'vector named 'true)))
2626 (or named (setq descs (delq (assq 'cl-tag-slot descs) descs)))
03fef3e6 2627 (push `(defvar ,tag-symbol) forms)
fcd73769
RS
2628 (setq pred-form (and named
2629 (let ((pos (- (length descs)
2630 (length (memq (assq 'cl-tag-slot descs)
2631 descs)))))
2632 (if (eq type 'vector)
03fef3e6
SM
2633 `(and (vectorp cl-x)
2634 (>= (length cl-x) ,(length descs))
2635 (memq (aref cl-x ,pos) ,tag-symbol))
fcd73769 2636 (if (= pos 0)
03fef3e6
SM
2637 `(memq (car-safe cl-x) ,tag-symbol)
2638 `(and (consp cl-x)
2639 (memq (nth ,pos cl-x) ,tag-symbol))))))
fcd73769 2640 pred-check (and pred-form (> safety 0)
7c1898a7 2641 (if (and (eq (cl-caadr pred-form) 'vectorp)
fcd73769 2642 (= safety 1))
7c1898a7 2643 (cons 'and (cl-cdddr pred-form)) pred-form)))
fcd73769
RS
2644 (let ((pos 0) (descp descs))
2645 (while descp
69d8fb1e 2646 (let* ((desc (pop descp))
fcd73769
RS
2647 (slot (car desc)))
2648 (if (memq slot '(cl-tag-slot cl-skip-slot))
2649 (progn
69d8fb1e 2650 (push nil slots)
03fef3e6 2651 (push (and (eq slot 'cl-tag-slot) `',tag)
fcd73769
RS
2652 defaults))
2653 (if (assq slot descp)
2654 (error "Duplicate slots named %s in %s" slot name))
2655 (let ((accessor (intern (format "%s%s" conc-name slot))))
69d8fb1e
SM
2656 (push slot slots)
2657 (push (nth 1 desc) defaults)
7c1898a7
SM
2658 (push (cl-list*
2659 'cl-defsubst accessor '(cl-x)
fcd73769
RS
2660 (append
2661 (and pred-check
03fef3e6
SM
2662 (list `(or ,pred-check
2663 (error "%s accessing a non-%s"
2664 ',accessor ',name))))
2665 (list (if (eq type 'vector) `(aref cl-x ,pos)
fcd73769 2666 (if (= pos 0) '(car cl-x)
03fef3e6 2667 `(nth ,pos cl-x)))))) forms)
69d8fb1e 2668 (push (cons accessor t) side-eff)
4dd1c416 2669 (push `(cl-define-setf-expander ,accessor (cl-x)
03fef3e6
SM
2670 ,(if (cadr (memq :read-only (cddr desc)))
2671 `(progn (ignore cl-x)
2672 (error "%s is a read-only slot"
2673 ',accessor))
2674 ;; If cl is loaded only for compilation,
2675 ;; the call to cl-struct-setf-expander would
2676 ;; cause a warning because it may not be
2677 ;; defined at run time. Suppress that warning.
2678 `(progn
2679 (declare-function
2680 cl-struct-setf-expander "cl-macs"
2681 (x name accessor pred-form pos))
2682 (cl-struct-setf-expander
2683 cl-x ',name ',accessor
2684 ,(and pred-check `',pred-check)
2685 ,pos))))
2686 forms)
fcd73769
RS
2687 (if print-auto
2688 (nconc print-func
03fef3e6
SM
2689 (list `(princ ,(format " %s" slot) cl-s)
2690 `(prin1 (,accessor cl-x) cl-s)))))))
fcd73769
RS
2691 (setq pos (1+ pos))))
2692 (setq slots (nreverse slots)
2693 defaults (nreverse defaults))
2694 (and predicate pred-form
7c1898a7 2695 (progn (push `(cl-defsubst ,predicate (cl-x)
03fef3e6
SM
2696 ,(if (eq (car pred-form) 'and)
2697 (append pred-form '(t))
2698 `(and ,pred-form t))) forms)
69d8fb1e 2699 (push (cons predicate 'error-free) side-eff)))
fcd73769 2700 (and copier
03fef3e6 2701 (progn (push `(defun ,copier (x) (copy-sequence x)) forms)
69d8fb1e 2702 (push (cons copier t) side-eff)))
fcd73769 2703 (if constructor
69d8fb1e 2704 (push (list constructor
fcd73769
RS
2705 (cons '&key (delq nil (copy-sequence slots))))
2706 constrs))
2707 (while constrs
2708 (let* ((name (caar constrs))
69d8fb1e 2709 (args (cadr (pop constrs)))
4dd1c416 2710 (anames (cl--arglist-args args))
7c1898a7 2711 (make (cl-mapcar (function (lambda (s d) (if (memq s anames) s d)))
fcd73769 2712 slots defaults)))
7c1898a7 2713 (push `(cl-defsubst ,name
03fef3e6
SM
2714 (&cl-defs '(nil ,@descs) ,@args)
2715 (,type ,@make)) forms)
4dd1c416 2716 (if (cl--safe-expr-p `(progn ,@(mapcar #'cl-second descs)))
69d8fb1e 2717 (push (cons name t) side-eff))))
fcd73769 2718 (if print-auto (nconc print-func (list '(princ ")" cl-s) t)))
5a315f9c
SM
2719 ;; Don't bother adding to cl-custom-print-functions since it's not used
2720 ;; by anything anyway!
2721 ;;(if print-func
2722 ;; (push `(if (boundp 'cl-custom-print-functions)
2723 ;; (push
2724 ;; ;; The auto-generated function does not pay attention to
2725 ;; ;; the depth argument cl-n.
2726 ;; (lambda (cl-x cl-s ,(if print-auto '_cl-n 'cl-n))
2727 ;; (and ,pred-form ,print-func))
2728 ;; cl-custom-print-functions))
2729 ;; forms))
03fef3e6 2730 (push `(setq ,tag-symbol (list ',tag)) forms)
7c1898a7 2731 (push `(cl-eval-when (compile load eval)
03fef3e6
SM
2732 (put ',name 'cl-struct-slots ',descs)
2733 (put ',name 'cl-struct-type ',(list type (eq named t)))
2734 (put ',name 'cl-struct-include ',include)
2735 (put ',name 'cl-struct-print ,print-auto)
2736 ,@(mapcar (lambda (x)
2737 `(put ',(car x) 'side-effect-free ',(cdr x)))
2738 side-eff))
2739 forms)
2740 `(progn ,@(nreverse (cons `',name forms)))))
fcd73769 2741
ebacfcc6 2742;;;###autoload
fcd73769 2743(defun cl-struct-setf-expander (x name accessor pred-form pos)
e542ea4b 2744 (let* ((temp (make-symbol "--cl-x--")) (store (make-symbol "--cl-store--")))
fcd73769 2745 (list (list temp) (list x) (list store)
03fef3e6
SM
2746 `(progn
2747 ,@(and pred-form
7c1898a7 2748 (list `(or ,(cl-subst temp 'cl-x pred-form)
03fef3e6
SM
2749 (error ,(format
2750 "%s storing a non-%s"
2751 accessor name)))))
2752 ,(if (eq (car (get name 'cl-struct-type)) 'vector)
2753 `(aset ,temp ,pos ,store)
2754 `(setcar
2755 ,(if (<= pos 5)
2756 (let ((xx temp))
2757 (while (>= (setq pos (1- pos)) 0)
2758 (setq xx `(cdr ,xx)))
2759 xx)
2760 `(nthcdr ,pos ,temp))
2761 ,store)))
fcd73769
RS
2762 (list accessor temp))))
2763
2764
2765;;; Types and assertions.
2766
15120dec 2767;;;###autoload
7c1898a7 2768(defmacro cl-deftype (name arglist &rest body)
64a4c526 2769 "Define NAME as a new data type.
7c1898a7
SM
2770The type name can then be used in `cl-typecase', `cl-check-type', etc."
2771 (declare (debug cl-defmacro) (doc-string 3))
2772 `(cl-eval-when (compile load eval)
4302f5ba
SM
2773 (put ',name 'cl-deftype-handler
2774 (cl-function (lambda (&cl-defs '('*) ,@arglist) ,@body)))))
fcd73769 2775
4dd1c416 2776(defun cl--make-type-test (val type)
fcd73769
RS
2777 (if (symbolp type)
2778 (cond ((get type 'cl-deftype-handler)
4dd1c416 2779 (cl--make-type-test val (funcall (get type 'cl-deftype-handler))))
fcd73769 2780 ((memq type '(nil t)) type)
e0b16322 2781 ((eq type 'null) `(null ,val))
578f8106 2782 ((eq type 'atom) `(atom ,val))
7c1898a7 2783 ((eq type 'float) `(cl-floatp-safe ,val))
e0b16322
SM
2784 ((eq type 'real) `(numberp ,val))
2785 ((eq type 'fixnum) `(integerp ,val))
7c1898a7 2786 ;; FIXME: Should `character' accept things like ?\C-\M-a ? --Stef
31ff0ac1 2787 ((memq type '(character string-char)) `(characterp ,val))
fcd73769
RS
2788 (t
2789 (let* ((name (symbol-name type))
2790 (namep (intern (concat name "p"))))
2791 (if (fboundp namep) (list namep val)
2792 (list (intern (concat name "-p")) val)))))
2793 (cond ((get (car type) 'cl-deftype-handler)
4dd1c416 2794 (cl--make-type-test val (apply (get (car type) 'cl-deftype-handler)
fcd73769 2795 (cdr type))))
e0b16322 2796 ((memq (car type) '(integer float real number))
4dd1c416 2797 (delq t `(and ,(cl--make-type-test val (car type))
03fef3e6 2798 ,(if (memq (cadr type) '(* nil)) t
7c1898a7 2799 (if (consp (cadr type)) `(> ,val ,(cl-caadr type))
03fef3e6 2800 `(>= ,val ,(cadr type))))
7c1898a7
SM
2801 ,(if (memq (cl-caddr type) '(* nil)) t
2802 (if (consp (cl-caddr type)) `(< ,val ,(cl-caaddr type))
2803 `(<= ,val ,(cl-caddr type)))))))
e0b16322 2804 ((memq (car type) '(and or not))
fcd73769 2805 (cons (car type)
4dd1c416 2806 (mapcar (function (lambda (x) (cl--make-type-test val x)))
fcd73769 2807 (cdr type))))
7c1898a7
SM
2808 ((memq (car type) '(member cl-member))
2809 `(and (cl-member ,val ',(cdr type)) t))
e0b16322 2810 ((eq (car type) 'satisfies) (list (cadr type) val))
fcd73769
RS
2811 (t (error "Bad type spec: %s" type)))))
2812
513749ee 2813(defvar cl--object)
ebacfcc6 2814;;;###autoload
7c1898a7 2815(defun cl-typep (object type) ; See compiler macro below.
fcd73769
RS
2816 "Check that OBJECT is of type TYPE.
2817TYPE is a Common Lisp-style type specifier."
513749ee
SM
2818 (let ((cl--object object)) ;; Yuck!!
2819 (eval (cl--make-type-test 'cl--object type))))
fcd73769 2820
ebacfcc6 2821;;;###autoload
7c1898a7 2822(defmacro cl-check-type (form type &optional string)
fcd73769
RS
2823 "Verify that FORM is of type TYPE; signal an error if not.
2824STRING is an optional description of the desired type."
b1198e17 2825 (declare (debug (place cl-type-spec &optional stringp)))
bb3faf5b 2826 (and (or (not (cl--compiling-file))
fcd73769 2827 (< cl-optimize-speed 3) (= cl-optimize-safety 3))
4dd1c416 2828 (let* ((temp (if (cl--simple-expr-p form 3)
e542ea4b 2829 form (make-symbol "--cl-var--")))
4dd1c416 2830 (body `(or ,(cl--make-type-test temp type)
03fef3e6
SM
2831 (signal 'wrong-type-argument
2832 (list ,(or string `',type)
2833 ,temp ',form)))))
2834 (if (eq temp form) `(progn ,body nil)
2835 `(let ((,temp ,form)) ,body nil)))))
fcd73769 2836
ebacfcc6 2837;;;###autoload
7c1898a7 2838(defmacro cl-assert (form &optional show-args string &rest args)
fcd73769
RS
2839 "Verify that FORM returns non-nil; signal an error if not.
2840Second arg SHOW-ARGS means to include arguments of FORM in message.
2841Other args STRING and ARGS... are arguments to be passed to `error'.
2842They are not evaluated unless the assertion fails. If STRING is
2843omitted, a default message listing FORM itself is used."
b1198e17 2844 (declare (debug (form &rest form)))
bb3faf5b 2845 (and (or (not (cl--compiling-file))
fcd73769 2846 (< cl-optimize-speed 3) (= cl-optimize-safety 3))
2b88d62a 2847 (let ((sargs (and show-args
4dd1c416
SM
2848 (delq nil (mapcar (lambda (x)
2849 (unless (macroexp-const-p x)
2850 x))
2851 (cdr form))))))
03fef3e6
SM
2852 `(progn
2853 (or ,form
2854 ,(if string
2855 `(error ,string ,@sargs ,@args)
2856 `(signal 'cl-assertion-failed
2857 (list ',form ,@sargs))))
2858 nil))))
fcd73769 2859
fcd73769
RS
2860;;; Compiler macros.
2861
ebacfcc6 2862;;;###autoload
7c1898a7 2863(defmacro cl-define-compiler-macro (func args &rest body)
64a4c526 2864 "Define a compiler-only macro.
fcd73769
RS
2865This is like `defmacro', but macro expansion occurs only if the call to
2866FUNC is compiled (i.e., not interpreted). Compiler macros should be used
2867for optimizing the way calls to FUNC are compiled; the form returned by
2868BODY should do the same thing as a call to the normal function called
2869FUNC, though possibly more efficiently. Note that, like regular macros,
2870compiler macros are expanded repeatedly until no further expansions are
2871possible. Unlike regular macros, BODY can decide to \"punt\" and leave the
2872original function call alone by declaring an initial `&whole foo' parameter
2873and then returning foo."
7c1898a7 2874 (declare (debug cl-defmacro))
16c9c10f 2875 (let ((p args) (res nil))
69d8fb1e 2876 (while (consp p) (push (pop p) res))
16c9c10f 2877 (setq args (nconc (nreverse res) (and p (list '&rest p)))))
7c1898a7 2878 `(cl-eval-when (compile load eval)
4302f5ba
SM
2879 (put ',func 'compiler-macro
2880 (cl-function (lambda ,(if (memq '&whole args) (delq '&whole args)
2881 (cons '_cl-whole-arg args))
2882 ,@body)))
57a7d507
SM
2883 ;; This is so that describe-function can locate
2884 ;; the macro definition.
2885 (let ((file ,(or buffer-file-name
2886 (and (boundp 'byte-compile-current-file)
2887 (stringp byte-compile-current-file)
2888 byte-compile-current-file))))
2889 (if file (put ',func 'compiler-macro-file
2890 (purecopy (file-name-nondirectory file)))))))
fcd73769 2891
ebacfcc6 2892;;;###autoload
7c1898a7 2893(defun cl-compiler-macroexpand (form)
fcd73769
RS
2894 (while
2895 (let ((func (car-safe form)) (handler nil))
2896 (while (and (symbolp func)
57a7d507 2897 (not (setq handler (get func 'compiler-macro)))
fcd73769
RS
2898 (fboundp func)
2899 (or (not (eq (car-safe (symbol-function func)) 'autoload))
2900 (load (nth 1 (symbol-function func)))))
2901 (setq func (symbol-function func)))
2902 (and handler
2903 (not (eq form (setq form (apply handler form (cdr form))))))))
2904 form)
2905
414dbb00
SM
2906;; Optimize away unused block-wrappers.
2907
4dd1c416 2908(defvar cl--active-block-names nil)
414dbb00 2909
bb3faf5b 2910(cl-define-compiler-macro cl--block-wrapper (cl-form)
414dbb00 2911 (let* ((cl-entry (cons (nth 1 (nth 1 cl-form)) nil))
4dd1c416 2912 (cl--active-block-names (cons cl-entry cl--active-block-names))
414dbb00
SM
2913 (cl-body (macroexpand-all ;Performs compiler-macro expansions.
2914 (cons 'progn (cddr cl-form))
2915 macroexpand-all-environment)))
2916 ;; FIXME: To avoid re-applying macroexpand-all, we'd like to be able
2917 ;; to indicate that this return value is already fully expanded.
2918 (if (cdr cl-entry)
a08a25d7 2919 `(catch ,(nth 1 cl-form) ,@(cdr cl-body))
414dbb00
SM
2920 cl-body)))
2921
bb3faf5b 2922(cl-define-compiler-macro cl--block-throw (cl-tag cl-value)
4dd1c416 2923 (let ((cl-found (assq (nth 1 cl-tag) cl--active-block-names)))
414dbb00
SM
2924 (if cl-found (setcdr cl-found t)))
2925 `(throw ,cl-tag ,cl-value))
2926
eb123b12 2927;;;###autoload
7c1898a7 2928(defmacro cl-defsubst (name args &rest body)
69d8fb1e 2929 "Define NAME as a function.
fcd73769
RS
2930Like `defun', except the function is automatically declared `inline',
2931ARGLIST allows full Common Lisp conventions, and BODY is implicitly
7c1898a7 2932surrounded by (cl-block NAME ...).
69d8fb1e
SM
2933
2934\(fn NAME ARGLIST [DOCSTRING] BODY...)"
7c1898a7 2935 (declare (debug cl-defun))
4dd1c416 2936 (let* ((argns (cl--arglist-args args)) (p argns)
fcd73769 2937 (pbody (cons 'progn body))
4dd1c416
SM
2938 (unsafe (not (cl--safe-expr-p pbody))))
2939 (while (and p (eq (cl--expr-contains args (car p)) 1)) (pop p))
03fef3e6
SM
2940 `(progn
2941 ,(if p nil ; give up if defaults refer to earlier args
7c1898a7 2942 `(cl-define-compiler-macro ,name
03fef3e6
SM
2943 ,(if (memq '&key args)
2944 `(&whole cl-whole &cl-quote ,@args)
2945 (cons '&cl-quote args))
bb3faf5b 2946 (cl--defsubst-expand
7c1898a7 2947 ',argns '(cl-block ,name ,@body)
03fef3e6
SM
2948 ;; We used to pass `simple' as
2949 ;; (not (or unsafe (cl-expr-access-order pbody argns)))
2950 ;; But this is much too simplistic since it
2951 ;; does not pay attention to the argvs (and
2952 ;; cl-expr-access-order itself is also too naive).
2953 nil
2954 ,(and (memq '&key args) 'cl-whole) ,unsafe ,@argns)))
7c1898a7 2955 (cl-defun ,name ,args ,@body))))
fcd73769 2956
bb3faf5b 2957(defun cl--defsubst-expand (argns body simple whole unsafe &rest argvs)
4dd1c416
SM
2958 (if (and whole (not (cl--safe-expr-p (cons 'progn argvs)))) whole
2959 (if (cl--simple-exprs-p argvs) (setq simple t))
e754e83b
SM
2960 (let* ((substs ())
2961 (lets (delq nil
7c1898a7 2962 (cl-mapcar (lambda (argn argv)
4dd1c416 2963 (if (or simple (macroexp-const-p argv))
7c1898a7
SM
2964 (progn (push (cons argn argv) substs)
2965 (and unsafe (list argn argv)))
2966 (list argn argv)))
2967 argns argvs))))
e754e83b
SM
2968 ;; FIXME: `sublis/subst' will happily substitute the symbol
2969 ;; `argn' in places where it's not used as a reference
2970 ;; to a variable.
2971 ;; FIXME: `sublis/subst' will happily copy `argv' to a different
2972 ;; scope, leading to name capture.
2973 (setq body (cond ((null substs) body)
2974 ((null (cdr substs))
7c1898a7
SM
2975 (cl-subst (cdar substs) (caar substs) body))
2976 (t (cl-sublis substs body))))
03fef3e6 2977 (if lets `(let ,lets ,body) body))))
fcd73769
RS
2978
2979
9b77469a
SM
2980;; Compile-time optimizations for some functions defined in this package.
2981;; Note that cl.el arranges to force cl-macs to be loaded at compile-time,
2982;; mainly to make sure these macros will be present.
fcd73769 2983
d9857e53 2984(defun cl--compiler-macro-member (form a list &rest keys)
64a4c526 2985 (let ((test (and (= (length keys) 2) (eq (car keys) :test)
4dd1c416 2986 (cl--const-expr-val (nth 1 keys)))))
03fef3e6
SM
2987 (cond ((eq test 'eq) `(memq ,a ,list))
2988 ((eq test 'equal) `(member ,a ,list))
2989 ((or (null keys) (eq test 'eql)) `(memql ,a ,list))
fcd73769
RS
2990 (t form))))
2991
d9857e53 2992(defun cl--compiler-macro-assoc (form a list &rest keys)
64a4c526 2993 (let ((test (and (= (length keys) 2) (eq (car keys) :test)
4dd1c416 2994 (cl--const-expr-val (nth 1 keys)))))
03fef3e6
SM
2995 (cond ((eq test 'eq) `(assq ,a ,list))
2996 ((eq test 'equal) `(assoc ,a ,list))
4dd1c416
SM
2997 ((and (macroexp-const-p a) (or (null keys) (eq test 'eql)))
2998 (if (cl-floatp-safe (cl--const-expr-val a))
03fef3e6 2999 `(assoc ,a ,list) `(assq ,a ,list)))
fcd73769
RS
3000 (t form))))
3001
71adb94b 3002;;;###autoload
d9857e53 3003(defun cl--compiler-macro-adjoin (form a list &rest keys)
4dd1c416 3004 (if (and (cl--simple-expr-p a) (cl--simple-expr-p list)
64a4c526 3005 (not (memq :key keys)))
7c1898a7 3006 `(if (cl-member ,a ,list ,@keys) ,list (cons ,a ,list))
fcd73769
RS
3007 form))
3008
71adb94b 3009;;;###autoload
d9857e53 3010(defun cl--compiler-macro-list* (_form arg &rest others)
fcd73769
RS
3011 (let* ((args (reverse (cons arg others)))
3012 (form (car args)))
3013 (while (setq args (cdr args))
03fef3e6 3014 (setq form `(cons ,(car args) ,form)))
fcd73769
RS
3015 form))
3016
d9857e53 3017(defun cl--compiler-macro-get (_form sym prop &optional def)
fcd73769 3018 (if def
7c1898a7 3019 `(cl-getf (symbol-plist ,sym) ,prop ,def)
03fef3e6 3020 `(get ,sym ,prop)))
fcd73769 3021
7c1898a7 3022(cl-define-compiler-macro cl-typep (&whole form val type)
4dd1c416 3023 (if (macroexp-const-p type)
d9857e53
SM
3024 (macroexp-let² macroexp-copyable-p temp val
3025 (cl--make-type-test temp (cl--const-expr-val type)))
fcd73769
RS
3026 form))
3027
71adb94b
SM
3028;;;###autoload
3029(defun cl--compiler-macro-cXXr (form x)
3030 (let* ((head (car form))
3031 (n (symbol-name (car form)))
3032 (i (- (length n) 2)))
3033 (if (not (string-match "c[ad]+r\\'" n))
3034 (if (and (fboundp head) (symbolp (symbol-function head)))
3035 (cl--compiler-macro-cXXr (cons (symbol-function head) (cdr form))
3036 x)
3037 (error "Compiler macro for cXXr applied to non-cXXr form"))
3038 (while (> i (match-beginning 0))
3039 (setq x (list (if (eq (aref n i) ?a) 'car 'cdr) x))
3040 (setq i (1- i)))
3041 x)))
3042
3043(dolist (y '(cl-first cl-second cl-third cl-fourth
3044 cl-fifth cl-sixth cl-seventh
3045 cl-eighth cl-ninth cl-tenth
3046 cl-rest cl-endp cl-plusp cl-minusp
3047 cl-caaar cl-caadr cl-cadar
3048 cl-caddr cl-cdaar cl-cdadr
3049 cl-cddar cl-cdddr cl-caaaar
3050 cl-caaadr cl-caadar cl-caaddr
3051 cl-cadaar cl-cadadr cl-caddar
3052 cl-cadddr cl-cdaaar cl-cdaadr
3053 cl-cdadar cl-cdaddr cl-cddaar
3054 cl-cddadr cl-cdddar cl-cddddr))
3055 (put y 'side-effect-free t))
fcd73769
RS
3056
3057;;; Things that are inline.
7c1898a7 3058(cl-proclaim '(inline cl-floatp-safe cl-acons cl-map cl-concatenate cl-notany cl-notevery
bb3faf5b 3059 cl--set-elt cl-revappend cl-nreconc gethash))
fcd73769
RS
3060
3061;;; Things that are side-effect-free.
e542ea4b 3062(mapc (lambda (x) (put x 'side-effect-free t))
7c1898a7
SM
3063 '(cl-oddp cl-evenp cl-signum last butlast cl-ldiff cl-pairlis cl-gcd cl-lcm
3064 cl-isqrt cl-floor cl-ceiling cl-truncate cl-round cl-mod cl-rem cl-subseq
3065 cl-list-length cl-get cl-getf))
fcd73769
RS
3066
3067;;; Things that are side-effect-and-error-free.
e542ea4b 3068(mapc (lambda (x) (put x 'side-effect-free 'error-free))
7c1898a7
SM
3069 '(eql cl-floatp-safe cl-list* cl-subst cl-acons cl-equalp cl-random-state-p
3070 copy-tree cl-sublis))
fcd73769
RS
3071
3072
3073(run-hooks 'cl-macs-load-hook)
3074
ebacfcc6 3075;; Local variables:
bc8ce89b
GM
3076;; byte-compile-dynamic: t
3077;; byte-compile-warnings: (not cl-functions)
ebacfcc6
SM
3078;; generated-autoload-file: "cl-loaddefs.el"
3079;; End:
b69a3374 3080
de7e2b36
SM
3081(provide 'cl-macs)
3082
fcd73769 3083;;; cl-macs.el ends here