Mercurial > hg > xemacs-beta
comparison lisp/cl-macs.el @ 5294:bbff29a01820
Add compiler macros and compilation sanity-checks for functions with keywords.
2010-10-25 Aidan Kehoe <kehoea@parhasard.net>
Add compiler macros and compilation sanity-checking for various
functions that take keywords.
* byte-optimize.el (side-effect-free-fns): #'symbol-value is
side-effect free and not error free.
* bytecomp.el (byte-compile-normal-call): Check keyword argument
lists for sanity; store information about the positions where
keyword arguments start using the new byte-compile-keyword-start
property.
* cl-macs.el (cl-const-expr-val): Take a new optional argument,
cl-not-constant, defaulting to nil, in this function; return it if
the expression is not constant.
(cl-non-fixnum-number-p): Make this into a separate function, we
want to pass it to #'every.
(eql): Use it.
(define-star-compiler-macros): Use the same code to generate the
member*, assoc* and rassoc* compiler macros; special-case some
code in #'add-to-list in subr.el.
(remove, remq): Add compiler macros for these two functions, in
preparation for #'remove being in C.
(define-foo-if-compiler-macros): Transform (remove-if-not ...) calls to
(remove ... :if-not) at compile time, which will be a real win
once the latter is in C.
(define-substitute-if-compiler-macros)
(define-subst-if-compiler-macros): Similarly for these functions.
(delete-duplicates): Change this compiler macro to use
#'plists-equal; if we don't have information about the type of
SEQUENCE at compile time, don't bother attempting to inline the
call, the function will be in C soon enough.
(equalp): Remove an old commented-out compiler macro for this, if
we want to see it it's in version control.
(subst-char-in-string): Transform this to a call to nsubstitute or
nsubstitute, if that is appropriate.
* cl.el (ldiff): Don't call setf here, this makes for a load-time
dependency problem in cl-macs.el
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Mon, 25 Oct 2010 13:04:04 +0100 |
parents | 99de5fd48e87 |
children | ec05a30f7148 b9167d522a9a |
comparison
equal
deleted
inserted
replaced
5293:63f247c5da0a | 5294:bbff29a01820 |
---|---|
133 (defun cl-const-exprs-p (xs) | 133 (defun cl-const-exprs-p (xs) |
134 (while (and xs (cl-const-expr-p (car xs))) | 134 (while (and xs (cl-const-expr-p (car xs))) |
135 (setq xs (cdr xs))) | 135 (setq xs (cdr xs))) |
136 (not xs)) | 136 (not xs)) |
137 | 137 |
138 (defun cl-const-expr-val (x) | 138 (defun cl-const-expr-val (x &optional cl-not-constant) |
139 (and (eq (cl-const-expr-p x) t) (if (consp x) (nth 1 x) x))) | 139 (let ((cl-const-expr-p (cl-const-expr-p x))) |
140 (cond ((eq cl-const-expr-p t) (if (consp x) (nth 1 x) x)) | |
141 ((eq cl-const-expr-p 'func) (nth 1 x)) | |
142 (cl-not-constant)))) | |
140 | 143 |
141 (defun cl-expr-access-order (x v) | 144 (defun cl-expr-access-order (x v) |
142 (if (cl-const-expr-p x) v | 145 (if (cl-const-expr-p x) v |
143 (if (consp x) | 146 (if (consp x) |
144 (progn | 147 (progn |
3262 | 3265 |
3263 ;;; Compile-time optimizations for some functions defined in this package. | 3266 ;;; Compile-time optimizations for some functions defined in this package. |
3264 ;;; Note that cl.el arranges to force cl-macs to be loaded at compile-time, | 3267 ;;; Note that cl.el arranges to force cl-macs to be loaded at compile-time, |
3265 ;;; mainly to make sure these macros will be present. | 3268 ;;; mainly to make sure these macros will be present. |
3266 | 3269 |
3270 (defun cl-non-fixnum-number-p (object) | |
3271 (and (numberp object) (not (fixnump object)))) | |
3272 | |
3267 (put 'eql 'byte-compile nil) | 3273 (put 'eql 'byte-compile nil) |
3268 (define-compiler-macro eql (&whole form a b) | 3274 (define-compiler-macro eql (&whole form a b) |
3269 (cond ((eq (cl-const-expr-p a) t) | 3275 (cond ((eq (cl-const-expr-p a) t) |
3270 (let ((val (cl-const-expr-val a))) | 3276 (let ((val (cl-const-expr-val a))) |
3271 (if (and (numberp val) (not (fixnump val))) | 3277 (if (cl-non-fixnum-number-p val) |
3272 (list 'equal a b) | 3278 (list 'equal a b) |
3273 (list 'eq a b)))) | 3279 (list 'eq a b)))) |
3274 ((eq (cl-const-expr-p b) t) | 3280 ((eq (cl-const-expr-p b) t) |
3275 (let ((val (cl-const-expr-val b))) | 3281 (let ((val (cl-const-expr-val b))) |
3276 (if (and (numberp val) (not (fixnump val))) | 3282 (if (cl-non-fixnum-number-p val) |
3277 (list 'equal a b) | 3283 (list 'equal a b) |
3278 (list 'eq a b)))) | 3284 (list 'eq a b)))) |
3279 ((cl-simple-expr-p a 5) | 3285 ((cl-simple-expr-p a 5) |
3280 (list 'if (list 'numberp a) | 3286 (list 'if (list 'numberp a) |
3281 (list 'equal a b) | 3287 (list 'equal a b) |
3285 (list 'if (list 'numberp b) | 3291 (list 'if (list 'numberp b) |
3286 (list 'equal a b) | 3292 (list 'equal a b) |
3287 (list 'eq a b))) | 3293 (list 'eq a b))) |
3288 (t form))) | 3294 (t form))) |
3289 | 3295 |
3290 (define-compiler-macro member* (&whole form a list &rest keys) | 3296 (macrolet |
3291 (let ((test (and (= (length keys) 2) (eq (car keys) :test) | 3297 ((define-star-compiler-macros (&rest macros) |
3292 (cl-const-expr-val (nth 1 keys)))) | 3298 "For `member*', `assoc*' and `rassoc*' with constant ITEM or |
3293 a-val) | 3299 :test arguments, use the versions with explicit tests if that makes sense." |
3294 (cond ((eq test 'eq) (list 'memq a list)) | 3300 (list* |
3295 ((eq test 'equal) (list 'member a list)) | 3301 'progn |
3296 ((or (null keys) (eq test 'eql)) | 3302 (mapcar |
3297 (if (eq (cl-const-expr-p a) t) | 3303 (function* |
3298 (list (if (and (numberp (setq a-val (cl-const-expr-val a))) | 3304 (lambda ((star-function eq-function equal-function)) |
3299 (not (fixnump a-val))) | 3305 `(define-compiler-macro ,star-function (&whole form item list |
3300 'member | 3306 &rest keys) |
3301 'memq) | 3307 (condition-case nil |
3302 a list) | 3308 (symbol-macrolet ((not-constant '#:not-constant)) |
3303 (if (eq (cl-const-expr-p list) t) | 3309 (let* ((test-expr (plist-get keys :test ''eql)) |
3304 (let ((p (cl-const-expr-val list)) (mb nil) (mq nil)) | 3310 (test (cl-const-expr-val test-expr not-constant)) |
3305 (if (not (cdr p)) | 3311 (item-val (cl-const-expr-val item not-constant)) |
3306 (and p (list 'eql a (list 'quote (car p)))) | 3312 (list-val (cl-const-expr-val list not-constant))) |
3307 (while p | 3313 (if (and keys |
3308 (if (and (numberp (car p)) (not (fixnump (car p)))) | 3314 (not (and (eq :test (car keys)) |
3309 (setq mb t) | 3315 (eql 2 (length keys))))) |
3310 (or (fixnump (car p)) (symbolp (car p)) (setq mq t))) | 3316 form |
3311 (setq p (cdr p))) | 3317 (cond ((eq test 'eq) `(,',eq-function ,item ,list)) |
3312 (if (not mb) (list 'memq a list) | 3318 ((eq test 'equal) |
3313 (if (not mq) (list 'member a list) form)))) | 3319 `(,',equal-function ,item ,list)) |
3314 form))) | 3320 ((and (eq test 'eql) |
3315 (t form)))) | 3321 (not (eq not-constant item-val))) |
3316 | 3322 (if (cl-non-fixnum-number-p item-val) |
3317 (define-compiler-macro assoc* (&whole form a list &rest keys) | 3323 `(,',equal-function ,item ,list) |
3318 (let ((test (and (= (length keys) 2) (eq (car keys) :test) | 3324 `(,',eq-function ,item ,list))) |
3319 (cl-const-expr-val (nth 1 keys)))) | 3325 ((and (eq test 'eql) (not (eq not-constant |
3320 a-val) | 3326 list-val))) |
3321 (cond ((eq test 'eq) (list 'assq a list)) | 3327 (if (some 'cl-non-fixnum-number-p list-val) |
3322 ((eq test 'equal) (list 'assoc a list)) | 3328 `(,',equal-function ,item ,list) |
3323 ((and (eq (cl-const-expr-p a) t) (or (null keys) (eq test 'eql))) | 3329 ;; This compiler macro used to limit calls |
3324 (if (and (numberp (setq a-val (cl-const-expr-val a))) | 3330 ;; to ,,eq-function to lists where all |
3325 (not (fixnump a-val))) | 3331 ;; elements were either fixnums or |
3326 (list 'assoc a list) (list 'assq a list))) | 3332 ;; symbols. There's no |
3327 (t form)))) | 3333 ;; reason to do this. |
3334 `(,',eq-function ,item ,list))) | |
3335 ;; This is a hilariously specific case; see | |
3336 ;; add-to-list in subr.el. | |
3337 ((and (eq test not-constant) | |
3338 (eq 'or (car-safe test-expr)) | |
3339 (eql 3 (length test-expr)) | |
3340 (every #'cl-safe-expr-p (cdr form)) | |
3341 `(if ,(second test-expr) | |
3342 (,',star-function ,item ,list :test | |
3343 ,(second test-expr)) | |
3344 (,',star-function | |
3345 ,item ,list :test ,(third test-expr))))) | |
3346 (t form))))) | |
3347 ;; No need to warn about a malformed property list, | |
3348 ;; #'byte-compile-normal-call will do that for us. | |
3349 (malformed-property-list form))))) | |
3350 macros)))) | |
3351 (define-star-compiler-macros | |
3352 (member* memq member) | |
3353 (assoc* assq assoc) | |
3354 (rassoc* rassq rassoc))) | |
3328 | 3355 |
3329 (define-compiler-macro adjoin (&whole form a list &rest keys) | 3356 (define-compiler-macro adjoin (&whole form a list &rest keys) |
3330 (if (and (cl-simple-expr-p a) (cl-simple-expr-p list) | 3357 (if (and (cl-simple-expr-p a) (cl-simple-expr-p list) |
3331 (not (memq :key keys))) | 3358 (not (memq :key keys))) |
3332 (list 'if (list* 'member* a list keys) list (list 'cons a list)) | 3359 (list 'if (list* 'member* a list keys) list (list 'cons a list)) |
3333 form)) | 3360 form)) |
3361 | |
3362 (define-compiler-macro remove (item sequence) | |
3363 `(remove* ,item ,sequence :test #'equal)) | |
3364 | |
3365 (define-compiler-macro remq (item sequence) | |
3366 `(remove* ,item ,sequence :test #'eq)) | |
3367 | |
3368 (macrolet | |
3369 ((define-foo-if-compiler-macros (&rest alist) | |
3370 "Avoid the funcall, variable binding and keyword parsing overhead | |
3371 for the FOO-IF and FOO-IF-NOT functions, transforming to forms using the | |
3372 non-standard :if and :if-not keywords at compile time." | |
3373 (cons | |
3374 'progn | |
3375 (mapcar | |
3376 (function* | |
3377 (lambda ((function-if . function)) | |
3378 (let ((keyword (if (equal (substring (symbol-name function-if) -3) | |
3379 "not") | |
3380 :if-not | |
3381 :if))) | |
3382 `(define-compiler-macro ,function-if (&whole form &rest args) | |
3383 (if (and (nthcdr 2 form) | |
3384 (or (consp (cl-const-expr-val (second form))) | |
3385 (cl-safe-expr-p (second form)))) | |
3386 ;; It doesn't matter what the second argument is, it's | |
3387 ;; ignored by FUNCTION. We know that the symbol | |
3388 ;; FUNCTION is in the constants vector, so use it. | |
3389 `(,',function ',',function ,(third form) ,,keyword | |
3390 ,(second form) ,@(nthcdr 3 form)) | |
3391 form))))) | |
3392 alist)))) | |
3393 (define-foo-if-compiler-macros | |
3394 (remove-if . remove*) | |
3395 (remove-if-not . remove*) | |
3396 (delete-if . delete*) | |
3397 (delete-if-not . delete*) | |
3398 (find-if . find) | |
3399 (find-if-not . find) | |
3400 (position-if . position) | |
3401 (position-if-not . position) | |
3402 (count-if . count) | |
3403 (count-if-not . count) | |
3404 (member-if . member*) | |
3405 (member-if-not . member*) | |
3406 (assoc-if . assoc*) | |
3407 (assoc-if-not . assoc*) | |
3408 (rassoc-if . rassoc*) | |
3409 (rassoc-if-not . rassoc*))) | |
3410 | |
3411 (macrolet | |
3412 ((define-substitute-if-compiler-macros (&rest alist) | |
3413 "Like the above, but for `substitute-if' and friends." | |
3414 (cons | |
3415 'progn | |
3416 (mapcar | |
3417 (function* | |
3418 (lambda ((function-if . function)) | |
3419 (let ((keyword (if (equal (substring (symbol-name function-if) -3) | |
3420 "not") | |
3421 :if-not | |
3422 :if))) | |
3423 `(define-compiler-macro ,function-if (&whole form &rest args) | |
3424 (if (and (nthcdr 3 form) | |
3425 (or (consp (cl-const-expr-val (third form))) | |
3426 (cl-safe-expr-p (third form)))) | |
3427 `(,',function ,(second form) ',',function ,(fourth form) | |
3428 ,,keyword ,(third form) ,@(nthcdr 4 form)) | |
3429 form))))) | |
3430 alist)))) | |
3431 (define-substitute-if-compiler-macros | |
3432 (substitute-if . substitute) | |
3433 (substitute-if-not . substitute) | |
3434 (nsubstitute-if . nsubstitute) | |
3435 (nsubstitute-if-not . nsubstitute))) | |
3436 | |
3437 (macrolet | |
3438 ((define-subst-if-compiler-macros (&rest alist) | |
3439 "Like the above, but for `subst-if' and friends." | |
3440 (cons | |
3441 'progn | |
3442 (mapcar | |
3443 (function* | |
3444 (lambda ((function-if . function)) | |
3445 (let ((keyword (if (equal (substring (symbol-name function-if) -3) | |
3446 "not") | |
3447 :if-not | |
3448 :if))) | |
3449 `(define-compiler-macro ,function-if (&whole form &rest args) | |
3450 (if (and (nthcdr 3 form) | |
3451 (or (consp (cl-const-expr-val (third form))) | |
3452 (cl-safe-expr-p (third form)))) | |
3453 `(,',function ,(if (cl-const-expr-p (second form)) | |
3454 `'((nil . ,(cl-const-expr-val | |
3455 (second form)))) | |
3456 `(list (cons ',',function | |
3457 ,(second form)))) | |
3458 ,(fourth form) ,,keyword ,(third form) | |
3459 ,@(nthcdr 4 form)) | |
3460 form))))) | |
3461 alist)))) | |
3462 (define-subst-if-compiler-macros | |
3463 (subst-if . sublis) | |
3464 (subst-if-not . sublis) | |
3465 (nsubst-if . nsublis) | |
3466 (nsubst-if-not . nsublis))) | |
3334 | 3467 |
3335 (define-compiler-macro list* (arg &rest others) | 3468 (define-compiler-macro list* (arg &rest others) |
3336 (let* ((args (reverse (cons arg others))) | 3469 (let* ((args (reverse (cons arg others))) |
3337 (form (car args))) | 3470 (form (car args))) |
3338 (while (setq args (cdr args)) | 3471 (while (setq args (cdr args)) |
3360 | 3493 |
3361 ;; XEmacs; inline delete-duplicates if it's called with one of the | 3494 ;; XEmacs; inline delete-duplicates if it's called with one of the |
3362 ;; common compile-time constant tests and an optional :from-end | 3495 ;; common compile-time constant tests and an optional :from-end |
3363 ;; argument, we want the speed in font-lock.el. | 3496 ;; argument, we want the speed in font-lock.el. |
3364 (define-compiler-macro delete-duplicates (&whole form cl-seq &rest cl-keys) | 3497 (define-compiler-macro delete-duplicates (&whole form cl-seq &rest cl-keys) |
3365 (let ((listp-check | 3498 (if (not (or (memq (car-safe cl-seq) |
3366 (cond | 3499 ;; No need to check for a list at runtime with |
3367 ((memq (car-safe cl-seq) | 3500 ;; these. We could expand the list, but these are all |
3368 ;; No need to check for a list at runtime with these. We | 3501 ;; the functions in the relevant context at the moment. |
3369 ;; could expand the list, but these are all the functions | 3502 '(nreverse append nconc mapcan mapcar string-to-list)) |
3370 ;; in the relevant context at the moment. | 3503 (and (listp cl-seq) (equal (butlast cl-seq) '(the list))))) |
3371 '(nreverse append nconc mapcan mapcar string-to-list)) | 3504 form |
3372 t) | 3505 (cond |
3373 ((and (listp cl-seq) (eq (first cl-seq) 'the) | 3506 ((or (plists-equal cl-keys '(:test 'eq) t) |
3374 (eq (second cl-seq) 'list)) | 3507 (plists-equal cl-keys '(:test #'eq) t)) |
3375 ;; Allow users to force this, if they really want to. | 3508 `(let* ((begin ,cl-seq) |
3376 t) | 3509 cl-seq) |
3377 (t | 3510 (while (memq (car begin) (cdr begin)) |
3378 '(listp begin))))) | 3511 (setq begin (cdr begin))) |
3379 (cond ((loop | 3512 (setq cl-seq begin) |
3380 for relevant-key-values | 3513 (while (cddr cl-seq) |
3381 in '((:test 'eq) | 3514 (if (memq (cadr cl-seq) (cddr cl-seq)) |
3382 (:test #'eq) | 3515 (setcdr (cdr cl-seq) (cddr cl-seq))) |
3383 (:test 'eq :from-end nil) | 3516 (setq cl-seq (cdr cl-seq))) |
3384 (:test #'eq :from-end nil)) | 3517 begin)) |
3385 ;; One of the above corresponds exactly to CL-KEYS: | 3518 ((or (plists-equal cl-keys '(:test 'eq :from-end t) t) |
3386 thereis (not (set-difference cl-keys relevant-key-values | 3519 (plists-equal cl-keys '(:test #'eq :from-end t) t)) |
3387 :test #'equal))) | 3520 `(let* ((begin ,cl-seq) |
3388 `(let* ((begin ,cl-seq) | 3521 (cl-seq begin)) |
3389 cl-seq) | 3522 (while cl-seq |
3390 (if ,listp-check | 3523 (setq cl-seq (setcdr cl-seq |
3391 (progn | 3524 (delq (car cl-seq) (cdr cl-seq))))) |
3392 (while (memq (car begin) (cdr begin)) | 3525 begin)) |
3393 (setq begin (cdr begin))) | 3526 ((or (plists-equal cl-keys '(:test 'equal) t) |
3394 (setq cl-seq begin) | 3527 (plists-equal cl-keys '(:test #'equal) t)) |
3395 (while (cddr cl-seq) | 3528 `(let* ((begin ,cl-seq) |
3396 (if (memq (cadr cl-seq) (cddr cl-seq)) | 3529 cl-seq) |
3397 (setcdr (cdr cl-seq) (cddr cl-seq))) | 3530 (while (member (car begin) (cdr begin)) |
3398 (setq cl-seq (cdr cl-seq))) | 3531 (setq begin (cdr begin))) |
3399 begin) | 3532 (setq cl-seq begin) |
3400 ;; Call cl-delete-duplicates explicitly, to avoid the form | 3533 (while (cddr cl-seq) |
3401 ;; getting compiler-macroexpanded again: | 3534 (if (member (cadr cl-seq) (cddr cl-seq)) |
3402 (cl-delete-duplicates begin ',cl-keys nil)))) | 3535 (setcdr (cdr cl-seq) (cddr cl-seq))) |
3403 ((loop | 3536 (setq cl-seq (cdr cl-seq))) |
3404 for relevant-key-values | 3537 begin)) |
3405 in '((:test 'eq :from-end t) | 3538 ((or (plists-equal cl-keys '(:test 'equal :from-end t) t) |
3406 (:test #'eq :from-end t)) | 3539 (plists-equal cl-keys '(:test #'equal :from-end t) t)) |
3407 ;; One of the above corresponds exactly to CL-KEYS: | 3540 `(let* ((begin ,cl-seq) |
3408 thereis (not (set-difference cl-keys relevant-key-values | 3541 (cl-seq begin)) |
3409 :test #'equal))) | 3542 (while cl-seq |
3410 `(let* ((begin ,cl-seq) | 3543 (setq cl-seq (setcdr cl-seq (delete (car cl-seq) |
3411 (cl-seq begin)) | 3544 (cdr cl-seq))))) |
3412 (if ,listp-check | 3545 begin)) |
3413 (progn | 3546 (t form)))) |
3414 (while cl-seq | |
3415 (setq cl-seq (setcdr cl-seq | |
3416 (delq (car cl-seq) (cdr cl-seq))))) | |
3417 begin) | |
3418 ;; Call cl-delete-duplicates explicitly, to avoid the form | |
3419 ;; getting compiler-macroexpanded again: | |
3420 (cl-delete-duplicates begin ',cl-keys nil)))) | |
3421 | |
3422 ((loop | |
3423 for relevant-key-values | |
3424 in '((:test 'equal) | |
3425 (:test #'equal) | |
3426 (:test 'equal :from-end nil) | |
3427 (:test #'equal :from-end nil)) | |
3428 ;; One of the above corresponds exactly to CL-KEYS: | |
3429 thereis (not (set-difference cl-keys relevant-key-values | |
3430 :test #'equal))) | |
3431 `(let* ((begin ,cl-seq) | |
3432 cl-seq) | |
3433 (if ,listp-check | |
3434 (progn | |
3435 (while (member (car begin) (cdr begin)) | |
3436 (setq begin (cdr begin))) | |
3437 (setq cl-seq begin) | |
3438 (while (cddr cl-seq) | |
3439 (if (member (cadr cl-seq) (cddr cl-seq)) | |
3440 (setcdr (cdr cl-seq) (cddr cl-seq))) | |
3441 (setq cl-seq (cdr cl-seq))) | |
3442 begin) | |
3443 ;; Call cl-delete-duplicates explicitly, to avoid the form | |
3444 ;; getting compiler-macroexpanded again: | |
3445 (cl-delete-duplicates begin ',cl-keys nil)))) | |
3446 ((loop | |
3447 for relevant-key-values | |
3448 in '((:test 'equal :from-end t) | |
3449 (:test #'equal :from-end t)) | |
3450 ;; One of the above corresponds exactly to CL-KEYS: | |
3451 thereis (not (set-difference cl-keys relevant-key-values | |
3452 :test #'equal))) | |
3453 `(let* ((begin ,cl-seq) | |
3454 (cl-seq begin)) | |
3455 (if ,listp-check | |
3456 (progn | |
3457 (while cl-seq | |
3458 (setq cl-seq | |
3459 (setcdr cl-seq (delete (car cl-seq) (cdr cl-seq))))) | |
3460 begin) | |
3461 ;; Call cl-delete-duplicates explicitly, to avoid the form | |
3462 ;; getting compiler-macroexpanded again: | |
3463 (cl-delete-duplicates begin ',cl-keys nil)))) | |
3464 (t form)))) | |
3465 | 3547 |
3466 ;; XEmacs; it's perfectly reasonable, and often much clearer to those | 3548 ;; XEmacs; it's perfectly reasonable, and often much clearer to those |
3467 ;; reading the code, to call regexp-quote on a constant string, which is | 3549 ;; reading the code, to call regexp-quote on a constant string, which is |
3468 ;; something we can optimise here easily. | 3550 ;; something we can optimise here easily. |
3469 (define-compiler-macro regexp-quote (&whole form string) | 3551 (define-compiler-macro regexp-quote (&whole form string) |
3558 ;; Neither side is a constant expression, do all our evaluation at | 3640 ;; Neither side is a constant expression, do all our evaluation at |
3559 ;; runtime (or both are, and equalp will be called from | 3641 ;; runtime (or both are, and equalp will be called from |
3560 ;; byte-optimize.el). | 3642 ;; byte-optimize.el). |
3561 (t form))))) | 3643 (t form))))) |
3562 | 3644 |
3563 ;;(define-compiler-macro equalp (&whole form x y) | |
3564 ;; "Expand calls to `equalp' where X or Y is a constant expression. | |
3565 ;; | |
3566 ;;Much of the processing that `equalp' does is dependent on the types of both | |
3567 ;;of its arguments, and with type information for one of them, we can | |
3568 ;;eliminate much of the body of the function at compile time. | |
3569 ;; | |
3570 ;;Where both X and Y are constant expressions, `equalp' is evaluated at | |
3571 ;;compile time by byte-optimize.el--this compiler macro passes FORM through to | |
3572 ;;the byte optimizer in those cases." | |
3573 ;; ;; Cases where both arguments are constant are handled in | |
3574 ;; ;; byte-optimize.el, we only need to handle those cases where one is | |
3575 ;; ;; constant here. | |
3576 ;; (let* ((equalp-sym (eval-when-compile (gensym))) | |
3577 ;; (let-form '(progn)) | |
3578 ;; (check-bit-vector t) | |
3579 ;; (check-string t) | |
3580 ;; (original-y y) | |
3581 ;; equalp-temp checked) | |
3582 ;; (macrolet | |
3583 ;; ((unordered-check (check) | |
3584 ;; `(prog1 | |
3585 ;; (setq checked | |
3586 ;; (or ,check | |
3587 ;; (prog1 ,(sublis '((x . y) (y . x)) check :test #'eq) | |
3588 ;; (setq equalp-temp x x y y equalp-temp)))) | |
3589 ;; (when checked | |
3590 ;; (unless (symbolp y) | |
3591 ;; (setq let-form `(let ((,equalp-sym ,y))) y equalp-sym)))))) | |
3592 ;; ;; In the bodies of the below clauses, x is always a constant expression | |
3593 ;; ;; of the type we're interested in, and y is always a symbol that refers | |
3594 ;; ;; to the result non-constant side of the comparison. | |
3595 ;; (cond ((unordered-check (and (arrayp x) (not (cl-const-expr-p y)))) | |
3596 ;; ;; Strings and other arrays. A vector containing the same | |
3597 ;; ;; character elements as a given string is equalp to that string; | |
3598 ;; ;; a bit-vector can only be equalp to a string if both are | |
3599 ;; ;; zero-length. | |
3600 ;; (cond | |
3601 ;; ((member x '("" #* [])) | |
3602 ;; ;; No need to protect against multiple evaluation here: | |
3603 ;; `(and (member ,original-y '("" #* [])) t)) | |
3604 ;; ((stringp x) | |
3605 ;; `(,@let-form | |
3606 ;; (if (stringp ,y) | |
3607 ;; (eq t (compare-strings ,x nil nil | |
3608 ;; ,y nil nil t)) | |
3609 ;; (if (vectorp ,y) | |
3610 ;; (cl-string-vector-equalp ,x ,y))))) | |
3611 ;; ((bit-vector-p x) | |
3612 ;; `(,@let-form | |
3613 ;; (if (bit-vector-p ,y) | |
3614 ;; ;; No need to call equalp on each element here: | |
3615 ;; (equal ,x ,y) | |
3616 ;; (if (vectorp ,y) | |
3617 ;; (cl-bit-vector-vector-equalp ,x ,y))))) | |
3618 ;; (t | |
3619 ;; (loop | |
3620 ;; for elt across x | |
3621 ;; ;; We may not need to check the other argument if it's a | |
3622 ;; ;; string or bit vector, depending on the contents of x: | |
3623 ;; always (progn | |
3624 ;; (unless (characterp elt) (setq check-string nil)) | |
3625 ;; (unless (and (numberp elt) (or (= elt 0) (= elt 1))) | |
3626 ;; (setq check-bit-vector nil)) | |
3627 ;; (or check-string check-bit-vector))) | |
3628 ;; `(,@let-form | |
3629 ;; (cond | |
3630 ;; ,@(if check-string | |
3631 ;; `(((stringp ,y) | |
3632 ;; (cl-string-vector-equalp ,y ,x)))) | |
3633 ;; ,@(if check-bit-vector | |
3634 ;; `(((bit-vector-p ,y) | |
3635 ;; (cl-bit-vector-vector-equalp ,y ,x)))) | |
3636 ;; ((vectorp ,y) | |
3637 ;; (cl-vector-array-equalp ,x ,y))))))) | |
3638 ;; ((unordered-check (and (characterp x) (not (cl-const-expr-p y)))) | |
3639 ;; `(,@let-form | |
3640 ;; (or (eq ,x ,y) | |
3641 ;; ;; eq has a bytecode, char-equal doesn't. | |
3642 ;; (and (characterp ,y) | |
3643 ;; (eq (downcase ,x) (downcase ,y)))))) | |
3644 ;; ((unordered-check (and (numberp x) (not (cl-const-expr-p y)))) | |
3645 ;; `(,@let-form | |
3646 ;; (and (numberp ,y) | |
3647 ;; (= ,x ,y)))) | |
3648 ;; ((unordered-check (and (hash-table-p x) (not (cl-const-expr-p y)))) | |
3649 ;; ;; Hash tables; follow the CL spec. | |
3650 ;; `(,@let-form | |
3651 ;; (and (hash-table-p ,y) | |
3652 ;; (eq ',(hash-table-test x) (hash-table-test ,y)) | |
3653 ;; (= ,(hash-table-count x) (hash-table-count ,y)) | |
3654 ;; (cl-hash-table-contents-equalp ,x ,y)))) | |
3655 ;; ((unordered-check | |
3656 ;; ;; Symbols; eq. | |
3657 ;; (and (not (cl-const-expr-p y)) | |
3658 ;; (or (memq x '(nil t)) | |
3659 ;; (and (eq (car-safe x) 'quote) (symbolp (second x)))))) | |
3660 ;; (cons 'eq (cdr form))) | |
3661 ;; ((unordered-check | |
3662 ;; ;; Compare conses at runtime, there's no real upside to | |
3663 ;; ;; unrolling the function -> they fall through to the next | |
3664 ;; ;; clause in this function. | |
3665 ;; (and (cl-const-expr-p x) (not (consp x)) | |
3666 ;; (not (cl-const-expr-p y)))) | |
3667 ;; ;; All other types; use equal. | |
3668 ;; (cons 'equal (cdr form))) | |
3669 ;; ;; Neither side is a constant expression, do all our evaluation at | |
3670 ;; ;; runtime (or both are, and equalp will be called from | |
3671 ;; ;; byte-optimize.el). | |
3672 ;; (t form))))) | |
3673 | |
3674 (define-compiler-macro notany (&whole form &rest cl-rest) | 3645 (define-compiler-macro notany (&whole form &rest cl-rest) |
3675 `(not (some ,@(cdr form)))) | 3646 `(not (some ,@(cdr form)))) |
3676 | 3647 |
3677 (define-compiler-macro notevery (&whole form &rest cl-rest) | 3648 (define-compiler-macro notevery (&whole form &rest cl-rest) |
3678 `(not (every ,@(cdr form)))) | 3649 `(not (every ,@(cdr form)))) |
3771 (vector (cons 'vconcat (cddr form))) | 3742 (vector (cons 'vconcat (cddr form))) |
3772 (bit-vector (cons 'bvconcat (cddr form))) | 3743 (bit-vector (cons 'bvconcat (cddr form))) |
3773 (string (cons 'concat (cddr form)))) | 3744 (string (cons 'concat (cddr form)))) |
3774 form)) | 3745 form)) |
3775 | 3746 |
3747 (define-compiler-macro subst-char-in-string (&whole form fromchar tochar | |
3748 string &optional inplace) | |
3749 (if (every #'cl-safe-expr-p (cdr form)) | |
3750 `(funcall (if ,inplace #'nsubstitute #'substitute) ,tochar ,fromchar | |
3751 (the string ,string) :test #'eq) | |
3752 form)) | |
3753 | |
3776 (map nil | 3754 (map nil |
3777 #'(lambda (function) | 3755 #'(lambda (function) |
3778 ;; There are byte codes for the two-argument versions of these | 3756 ;; There are byte codes for the two-argument versions of these |
3779 ;; functions; if the form has more arguments and those arguments | 3757 ;; functions; if the form has more arguments and those arguments |
3780 ;; have no side effects, transform to a series of two-argument | 3758 ;; have no side effects, transform to a series of two-argument |