Mercurial > hg > xemacs-beta
comparison lisp/cl-macs.el @ 4962:e813cf16c015
merge
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 01 Feb 2010 05:29:05 -0600 |
parents | 6ef8256a020a |
children | 6bc1f3f6cf0d |
comparison
equal
deleted
inserted
replaced
4961:b90f8cf474e0 | 4962:e813cf16c015 |
---|---|
1 ;;; cl-macs.el --- Common Lisp extensions for XEmacs Lisp (part four) | 1 ;;; cl-macs.el --- Common Lisp extensions for XEmacs Lisp (part four) |
2 | 2 |
3 ;; Copyright (C) 1993, 2003, 2004 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1993, 2003, 2004 Free Software Foundation, Inc. |
4 ;; Copyright (C) 2002 Ben Wing. | 4 ;; Copyright (C) 2002, 2010 Ben Wing. |
5 | 5 |
6 ;; Author: Dave Gillespie <daveg@synaptics.com> | 6 ;; Author: Dave Gillespie <daveg@synaptics.com> |
7 ;; Version: 2.02 | 7 ;; Version: 2.02 |
8 ;; Keywords: extensions | 8 ;; Keywords: extensions |
9 | 9 |
3355 (define-compiler-macro regexp-quote (&whole form string) | 3355 (define-compiler-macro regexp-quote (&whole form string) |
3356 (if (stringp string) | 3356 (if (stringp string) |
3357 (regexp-quote string) | 3357 (regexp-quote string) |
3358 form)) | 3358 form)) |
3359 | 3359 |
3360 ;; NOTE: `equalp' is now a primitive, although as of yet it still doesn't | |
3361 ;; have a byte-compiler opcode for it. The compiler-macro for `equalp' used | |
3362 ;; to try and remove as much as possible of the logic of the Lisp `equalp' as | |
3363 ;; possible whenever one of the arguments is a constant, boiling things down | |
3364 ;; to a few if-statements and some calls to various no-longer-defined | |
3365 ;; helper functions. Besides the fact that the helper functions aren't | |
3366 ;; defined, there's little point in doing any of that expansion, since it will | |
3367 ;; end up executing in Lisp what would otherwise be done in C by a direct | |
3368 ;; call to `equalp'. The only exception is when the reduction is quite | |
3369 ;; simple and is to functions that do have op-codes; that may gain something. | |
3370 ;; However, if `equalp' becomes an opcode itself, consider removing everything | |
3371 ;; here except maybe when the call can directly be reduced to `equal' or `eq'. | |
3372 ;; | |
3373 ;; --ben | |
3374 | |
3360 (define-compiler-macro equalp (&whole form x y) | 3375 (define-compiler-macro equalp (&whole form x y) |
3361 "Expand calls to `equalp' where X or Y is a constant expression. | 3376 "Expand calls to `equalp' where X or Y is a constant expression. |
3362 | 3377 |
3363 Much of the processing that `equalp' does is dependent on the types of both | 3378 Much of the processing that `equalp' does is dependent on the types of both |
3364 of its arguments, and with type information for one of them, we can | 3379 of its arguments, and with type information for one of them, we can |
3370 ;; Cases where both arguments are constant are handled in | 3385 ;; Cases where both arguments are constant are handled in |
3371 ;; byte-optimize.el, we only need to handle those cases where one is | 3386 ;; byte-optimize.el, we only need to handle those cases where one is |
3372 ;; constant here. | 3387 ;; constant here. |
3373 (let* ((equalp-sym (eval-when-compile (gensym))) | 3388 (let* ((equalp-sym (eval-when-compile (gensym))) |
3374 (let-form '(progn)) | 3389 (let-form '(progn)) |
3375 (check-bit-vector t) | |
3376 (check-string t) | |
3377 (original-y y) | 3390 (original-y y) |
3378 equalp-temp checked) | 3391 equalp-temp checked) |
3379 (macrolet | 3392 (macrolet |
3380 ((unordered-check (check) | 3393 ((unordered-check (check) |
3381 `(prog1 | 3394 `(prog1 |
3396 ;; zero-length. | 3409 ;; zero-length. |
3397 (cond | 3410 (cond |
3398 ((member x '("" #* [])) | 3411 ((member x '("" #* [])) |
3399 ;; No need to protect against multiple evaluation here: | 3412 ;; No need to protect against multiple evaluation here: |
3400 `(and (member ,original-y '("" #* [])) t)) | 3413 `(and (member ,original-y '("" #* [])) t)) |
3401 ((stringp x) | 3414 (t form))) |
3402 `(,@let-form | |
3403 (if (stringp ,y) | |
3404 (eq t (compare-strings ,x nil nil | |
3405 ,y nil nil t)) | |
3406 (if (vectorp ,y) | |
3407 (cl-string-vector-equalp ,x ,y))))) | |
3408 ((bit-vector-p x) | |
3409 `(,@let-form | |
3410 (if (bit-vector-p ,y) | |
3411 ;; No need to call equalp on each element here: | |
3412 (equal ,x ,y) | |
3413 (if (vectorp ,y) | |
3414 (cl-bit-vector-vector-equalp ,x ,y))))) | |
3415 (t | |
3416 (loop | |
3417 for elt across x | |
3418 ;; We may not need to check the other argument if it's a | |
3419 ;; string or bit vector, depending on the contents of x: | |
3420 always (progn | |
3421 (unless (characterp elt) (setq check-string nil)) | |
3422 (unless (and (numberp elt) (or (= elt 0) (= elt 1))) | |
3423 (setq check-bit-vector nil)) | |
3424 (or check-string check-bit-vector))) | |
3425 `(,@let-form | |
3426 (cond | |
3427 ,@(if check-string | |
3428 `(((stringp ,y) | |
3429 (cl-string-vector-equalp ,y ,x)))) | |
3430 ,@(if check-bit-vector | |
3431 `(((bit-vector-p ,y) | |
3432 (cl-bit-vector-vector-equalp ,y ,x)))) | |
3433 ((vectorp ,y) | |
3434 (cl-vector-array-equalp ,x ,y))))))) | |
3435 ((unordered-check (and (characterp x) (not (cl-const-expr-p y)))) | 3415 ((unordered-check (and (characterp x) (not (cl-const-expr-p y)))) |
3436 `(,@let-form | 3416 `(,@let-form |
3437 (or (eq ,x ,y) | 3417 (or (eq ,x ,y) |
3438 ;; eq has a bytecode, char-equal doesn't. | 3418 ;; eq has a bytecode, char-equal doesn't. |
3439 (and (characterp ,y) | 3419 (and (characterp ,y) |
3440 (eq (downcase ,x) (downcase ,y)))))) | 3420 (eq (downcase ,x) (downcase ,y)))))) |
3441 ((unordered-check (and (numberp x) (not (cl-const-expr-p y)))) | 3421 ((unordered-check (and (numberp x) (not (cl-const-expr-p y)))) |
3442 `(,@let-form | 3422 `(,@let-form |
3443 (and (numberp ,y) | 3423 (and (numberp ,y) |
3444 (= ,x ,y)))) | 3424 (= ,x ,y)))) |
3445 ((unordered-check (and (hash-table-p x) (not (cl-const-expr-p y)))) | 3425 ((unordered-check (and (hash-table-p x) (not (cl-const-expr-p y)))) |
3446 ;; Hash tables; follow the CL spec. | 3426 form) |
3447 `(,@let-form | |
3448 (and (hash-table-p ,y) | |
3449 (eq ',(hash-table-test x) (hash-table-test ,y)) | |
3450 (= ,(hash-table-count x) (hash-table-count ,y)) | |
3451 (cl-hash-table-contents-equalp ,x ,y)))) | |
3452 ((unordered-check | 3427 ((unordered-check |
3453 ;; Symbols; eq. | 3428 ;; Symbols; eq. |
3454 (and (not (cl-const-expr-p y)) | 3429 (and (not (cl-const-expr-p y)) |
3455 (or (memq x '(nil t)) | 3430 (or (memq x '(nil t)) |
3456 (and (eq (car-safe x) 'quote) (symbolp (second x)))))) | 3431 (and (eq (car-safe x) 'quote) (symbolp (second x)))))) |
3457 (cons 'eq (cdr form))) | 3432 (cons 'eq (cdr form))) |
3458 ((unordered-check | 3433 |
3459 ;; Compare conses at runtime, there's no real upside to | 3434 ;; This clause is wrong -- e.g. when comparing a constant char-table |
3460 ;; unrolling the function -> they fall through to the next | 3435 ;; against a non-constant expression that evaluates to a char-table, |
3461 ;; clause in this function. | 3436 ;; or some for range tables or certain other types, `equalp' is |
3462 (and (cl-const-expr-p x) (not (consp x)) | 3437 ;; not the same as `equal'. We could insert the known list of |
3463 (not (cl-const-expr-p y)))) | 3438 ;; types with special `equalp' property, but it's fragile and may |
3464 ;; All other types; use equal. | 3439 ;; not be much of an optimization, esp. since these types don't |
3465 (cons 'equal (cdr form))) | 3440 ;; occur that often are often big. |
3441 ;;((unordered-check | |
3442 ;; ;; Compare conses at runtime, there's no real upside to | |
3443 ;; ;; unrolling the function -> they fall through to the next | |
3444 ;; ;; clause in this function. | |
3445 ;; (and (cl-const-expr-p x) (not (consp x)) | |
3446 ;; (not (cl-const-expr-p y)))) | |
3447 ;; ;; All other types; use equal. | |
3448 ;; (cons 'equal (cdr form))) | |
3449 | |
3466 ;; Neither side is a constant expression, do all our evaluation at | 3450 ;; Neither side is a constant expression, do all our evaluation at |
3467 ;; runtime (or both are, and equalp will be called from | 3451 ;; runtime (or both are, and equalp will be called from |
3468 ;; byte-optimize.el). | 3452 ;; byte-optimize.el). |
3469 (t form))))) | 3453 (t form))))) |
3454 | |
3455 ;;(define-compiler-macro equalp (&whole form x y) | |
3456 ;; "Expand calls to `equalp' where X or Y is a constant expression. | |
3457 ;; | |
3458 ;;Much of the processing that `equalp' does is dependent on the types of both | |
3459 ;;of its arguments, and with type information for one of them, we can | |
3460 ;;eliminate much of the body of the function at compile time. | |
3461 ;; | |
3462 ;;Where both X and Y are constant expressions, `equalp' is evaluated at | |
3463 ;;compile time by byte-optimize.el--this compiler macro passes FORM through to | |
3464 ;;the byte optimizer in those cases." | |
3465 ;; ;; Cases where both arguments are constant are handled in | |
3466 ;; ;; byte-optimize.el, we only need to handle those cases where one is | |
3467 ;; ;; constant here. | |
3468 ;; (let* ((equalp-sym (eval-when-compile (gensym))) | |
3469 ;; (let-form '(progn)) | |
3470 ;; (check-bit-vector t) | |
3471 ;; (check-string t) | |
3472 ;; (original-y y) | |
3473 ;; equalp-temp checked) | |
3474 ;; (macrolet | |
3475 ;; ((unordered-check (check) | |
3476 ;; `(prog1 | |
3477 ;; (setq checked | |
3478 ;; (or ,check | |
3479 ;; (prog1 ,(sublis '((x . y) (y . x)) check :test #'eq) | |
3480 ;; (setq equalp-temp x x y y equalp-temp)))) | |
3481 ;; (when checked | |
3482 ;; (unless (symbolp y) | |
3483 ;; (setq let-form `(let ((,equalp-sym ,y))) y equalp-sym)))))) | |
3484 ;; ;; In the bodies of the below clauses, x is always a constant expression | |
3485 ;; ;; of the type we're interested in, and y is always a symbol that refers | |
3486 ;; ;; to the result non-constant side of the comparison. | |
3487 ;; (cond ((unordered-check (and (arrayp x) (not (cl-const-expr-p y)))) | |
3488 ;; ;; Strings and other arrays. A vector containing the same | |
3489 ;; ;; character elements as a given string is equalp to that string; | |
3490 ;; ;; a bit-vector can only be equalp to a string if both are | |
3491 ;; ;; zero-length. | |
3492 ;; (cond | |
3493 ;; ((member x '("" #* [])) | |
3494 ;; ;; No need to protect against multiple evaluation here: | |
3495 ;; `(and (member ,original-y '("" #* [])) t)) | |
3496 ;; ((stringp x) | |
3497 ;; `(,@let-form | |
3498 ;; (if (stringp ,y) | |
3499 ;; (eq t (compare-strings ,x nil nil | |
3500 ;; ,y nil nil t)) | |
3501 ;; (if (vectorp ,y) | |
3502 ;; (cl-string-vector-equalp ,x ,y))))) | |
3503 ;; ((bit-vector-p x) | |
3504 ;; `(,@let-form | |
3505 ;; (if (bit-vector-p ,y) | |
3506 ;; ;; No need to call equalp on each element here: | |
3507 ;; (equal ,x ,y) | |
3508 ;; (if (vectorp ,y) | |
3509 ;; (cl-bit-vector-vector-equalp ,x ,y))))) | |
3510 ;; (t | |
3511 ;; (loop | |
3512 ;; for elt across x | |
3513 ;; ;; We may not need to check the other argument if it's a | |
3514 ;; ;; string or bit vector, depending on the contents of x: | |
3515 ;; always (progn | |
3516 ;; (unless (characterp elt) (setq check-string nil)) | |
3517 ;; (unless (and (numberp elt) (or (= elt 0) (= elt 1))) | |
3518 ;; (setq check-bit-vector nil)) | |
3519 ;; (or check-string check-bit-vector))) | |
3520 ;; `(,@let-form | |
3521 ;; (cond | |
3522 ;; ,@(if check-string | |
3523 ;; `(((stringp ,y) | |
3524 ;; (cl-string-vector-equalp ,y ,x)))) | |
3525 ;; ,@(if check-bit-vector | |
3526 ;; `(((bit-vector-p ,y) | |
3527 ;; (cl-bit-vector-vector-equalp ,y ,x)))) | |
3528 ;; ((vectorp ,y) | |
3529 ;; (cl-vector-array-equalp ,x ,y))))))) | |
3530 ;; ((unordered-check (and (characterp x) (not (cl-const-expr-p y)))) | |
3531 ;; `(,@let-form | |
3532 ;; (or (eq ,x ,y) | |
3533 ;; ;; eq has a bytecode, char-equal doesn't. | |
3534 ;; (and (characterp ,y) | |
3535 ;; (eq (downcase ,x) (downcase ,y)))))) | |
3536 ;; ((unordered-check (and (numberp x) (not (cl-const-expr-p y)))) | |
3537 ;; `(,@let-form | |
3538 ;; (and (numberp ,y) | |
3539 ;; (= ,x ,y)))) | |
3540 ;; ((unordered-check (and (hash-table-p x) (not (cl-const-expr-p y)))) | |
3541 ;; ;; Hash tables; follow the CL spec. | |
3542 ;; `(,@let-form | |
3543 ;; (and (hash-table-p ,y) | |
3544 ;; (eq ',(hash-table-test x) (hash-table-test ,y)) | |
3545 ;; (= ,(hash-table-count x) (hash-table-count ,y)) | |
3546 ;; (cl-hash-table-contents-equalp ,x ,y)))) | |
3547 ;; ((unordered-check | |
3548 ;; ;; Symbols; eq. | |
3549 ;; (and (not (cl-const-expr-p y)) | |
3550 ;; (or (memq x '(nil t)) | |
3551 ;; (and (eq (car-safe x) 'quote) (symbolp (second x)))))) | |
3552 ;; (cons 'eq (cdr form))) | |
3553 ;; ((unordered-check | |
3554 ;; ;; Compare conses at runtime, there's no real upside to | |
3555 ;; ;; unrolling the function -> they fall through to the next | |
3556 ;; ;; clause in this function. | |
3557 ;; (and (cl-const-expr-p x) (not (consp x)) | |
3558 ;; (not (cl-const-expr-p y)))) | |
3559 ;; ;; All other types; use equal. | |
3560 ;; (cons 'equal (cdr form))) | |
3561 ;; ;; Neither side is a constant expression, do all our evaluation at | |
3562 ;; ;; runtime (or both are, and equalp will be called from | |
3563 ;; ;; byte-optimize.el). | |
3564 ;; (t form))))) | |
3470 | 3565 |
3471 (define-compiler-macro map (&whole form cl-type cl-func cl-seq | 3566 (define-compiler-macro map (&whole form cl-type cl-func cl-seq |
3472 &rest cl-rest) | 3567 &rest cl-rest) |
3473 "If CL-TYPE is a constant expression that we know how to handle, transform | 3568 "If CL-TYPE is a constant expression that we know how to handle, transform |
3474 the call to `map' to a more efficient expression." | 3569 the call to `map' to a more efficient expression." |