comparison lisp/cl-macs.el @ 4742:4cf435fcebbc

Make #'letf not error if handed a #'values form. lisp/ChangeLog addition: 2009-11-14 Aidan Kehoe <kehoea@parhasard.net> * cl-macs.el (letf): Check whether arguments to #'values are bound, and make them unbound after evaluating BODY; document the limitations of this macro. tests/ChangeLog addition: 2009-11-14 Aidan Kehoe <kehoea@parhasard.net> * automated/lisp-tests.el: Don't call Known-Bug-Expect-Failure now that the particular letf bug it tickled is fixed.
author Aidan Kehoe <kehoea@parhasard.net>
date Sat, 14 Nov 2009 11:43:09 +0000
parents ebca981a0012
children e29fcfd8df5f
comparison
equal deleted inserted replaced
4741:e14f9fdd5096 4742:4cf435fcebbc
2585 (cl-setf-do-store (nth 1 method) form)))))) 2585 (cl-setf-do-store (nth 1 method) form))))))
2586 (let ((method (cl-setf-do-modify (car places) 'unsafe))) 2586 (let ((method (cl-setf-do-modify (car places) 'unsafe)))
2587 (list 'let* (append (car method) (list (list temp (nth 2 method)))) 2587 (list 'let* (append (car method) (list (list temp (nth 2 method))))
2588 (cl-setf-do-store (nth 1 method) form) nil))))) 2588 (cl-setf-do-store (nth 1 method) form) nil)))))
2589 2589
2590 ;; This function is not in Common Lisp, and there are gaps in its structure and
2591 ;; implementation that reflect that it was never well-specified. E.g. with
2592 ;; setf, the question of whether a PLACE is bound or not and how to make it
2593 ;; unbound doesn't arise, but we need some way of specifying that for letf to
2594 ;; be sensible for gethash, symbol-value and so on; currently we just hard-code
2595 ;; symbol-value, symbol-function and values (the latter is XEmacs work that
2596 ;; I've just done) in the body of this function, and the following gives the
2597 ;; wrong behaviour for gethash:
2598 ;;
2599 ;; (setq my-hash-table #s(hash-table test equal data ())
2600 ;; print-gensym t)
2601 ;; => t
2602 ;; (gethash "my-key" my-hash-table (gensym))
2603 ;; => #:G68010
2604 ;; (letf (((gethash "my-key" my-hash-table) 4000))
2605 ;; (message "key value is %S" (gethash "my-key" my-hash-table)))
2606 ;; => "key value is 4000"
2607 ;; (gethash "my-key" my-hash-table (gensym))
2608 ;; => nil ;; should be an uninterned symbol.
2609 ;;
2610 ;; Aidan Kehoe, Fr Nov 13 16:12:21 GMT 2009
2611
2590 ;;;###autoload 2612 ;;;###autoload
2591 (defmacro letf (bindings &rest body) 2613 (defmacro letf (bindings &rest body)
2592 "(letf ((PLACE VALUE) ...) BODY...): temporarily bind to PLACEs. 2614 "(letf ((PLACE VALUE) ...) BODY...): temporarily bind to PLACEs.
2593 This is the analogue of `let', but with generalized variables (in the 2615 This is the analogue of `let', but with generalized variables (in the
2594 sense of `setf') for the PLACEs. Each PLACE is set to the corresponding 2616 sense of `setf') for the PLACEs. Each PLACE is set to the corresponding
2606 (list 'symbol-value (list 'quote (caar rev))) 2628 (list 'symbol-value (list 'quote (caar rev)))
2607 (caar rev))) 2629 (caar rev)))
2608 (value (cadar rev)) 2630 (value (cadar rev))
2609 (method (cl-setf-do-modify place 'no-opt)) 2631 (method (cl-setf-do-modify place 'no-opt))
2610 (save (gensym "--letf-save--")) 2632 (save (gensym "--letf-save--"))
2611 (bound (and (memq (car place) '(symbol-value symbol-function)) 2633 (bound (and (memq (car place)
2634 '(symbol-value symbol-function values))
2612 (gensym "--letf-bound--"))) 2635 (gensym "--letf-bound--")))
2613 (temp (and (not (cl-const-expr-p value)) (cdr bindings) 2636 (temp (and (not (cl-const-expr-p value)) (cdr bindings)
2614 (gensym "--letf-val--")))) 2637 (gensym "--letf-val--")))
2638 (syms (and (eq 'values (car place))
2639 (gensym "--letf-syms--")))
2640 (cursor (and syms (gensym "--letf-cursor--")))
2641 (sym (and syms (gensym "--letf-sym--"))))
2615 (setq lets (nconc (car method) 2642 (setq lets (nconc (car method)
2616 (if bound 2643 (cond
2617 (list (list bound 2644 (syms
2618 (list (if (eq (car place) 2645 `((,syms ',(loop
2619 'symbol-value) 2646 for sym in (cdr place)
2620 'boundp 'fboundp) 2647 nconc (if (symbolp sym) (list sym))))
2621 (nth 1 (nth 2 method)))) 2648 (,cursor ,syms)
2622 (list save (list 'and bound 2649 (,bound nil)
2623 (nth 2 method)))) 2650 (,save
2624 (list (list save (nth 2 method)))) 2651 (prog2
2652 (while (consp ,cursor)
2653 (setq ,bound
2654 (cons (and (boundp (car ,cursor))
2655 (symbol-value
2656 (car ,cursor)))
2657 ,bound)
2658 ,cursor (cdr ,cursor)))
2659 ;; Just using ,bound as a temporary
2660 ;; variable here, to initialise ,save:
2661 (nreverse ,bound)
2662 ;; Now, really initialise ,bound:
2663 (setq ,cursor ,syms
2664 ,bound nil
2665 ,bound
2666 (progn (while (consp ,cursor)
2667 (setq ,bound
2668 (cons
2669 (boundp (car ,cursor))
2670 ,bound)
2671 ,cursor (cdr ,cursor)))
2672 (nreverse ,bound)))))))
2673 (bound
2674 (list (list bound
2675 (list (if (eq (car place)
2676 'symbol-value)
2677 'boundp 'fboundp)
2678 (nth 1 (nth 2 method))))
2679 (list save (list 'and bound
2680 (nth 2 method)))))
2681 (t
2682 (list (list save (nth 2 method)))))
2625 (and temp (list (list temp value))) 2683 (and temp (list (list temp value)))
2626 lets) 2684 lets)
2627 body (list 2685 body (list
2628 (list 'unwind-protect 2686 (list 'unwind-protect
2629 (cons 'progn 2687 (cons 'progn
2630 (if (cdr (car rev)) 2688 (if (cdr (car rev))
2631 (cons (cl-setf-do-store (nth 1 method) 2689 (cons (cl-setf-do-store (nth 1 method)
2632 (or temp value)) 2690 (or temp value))
2633 body) 2691 body)
2634 body)) 2692 body))
2635 (if bound 2693 (cond
2636 (list 'if bound 2694 (syms
2637 (cl-setf-do-store (nth 1 method) save) 2695 `(while (consp ,syms)
2638 (list (if (eq (car place) 'symbol-value) 2696 (if (car ,bound)
2639 'makunbound 'fmakunbound) 2697 (set (car ,syms) (car ,save))
2640 (nth 1 (nth 2 method)))) 2698 (makunbound (car ,syms)))
2641 (cl-setf-do-store (nth 1 method) save)))) 2699 (setq ,syms (cdr ,syms)
2700 ,bound (cdr ,bound)
2701 ,save (cdr ,save))))
2702 (bound
2703 (list 'if bound
2704 (cl-setf-do-store (nth 1 method) save)
2705 (list (if (eq (car place)
2706 'symbol-function)
2707 'fmakunbound
2708 'makunbound)
2709 (nth 1 (nth 2 method)))))
2710 (t
2711 (cl-setf-do-store (nth 1 method) save)))))
2642 rev (cdr rev)))) 2712 rev (cdr rev))))
2643 (list* 'let* lets body)))) 2713 (list* 'let* lets body))))
2644 2714
2645 ;;;###autoload 2715 ;;;###autoload
2646 (defmacro letf* (bindings &rest body) 2716 (defmacro letf* (bindings &rest body)