]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/gv.el
merge trunk
[gnu-emacs] / lisp / emacs-lisp / gv.el
index 72c2ec607346b267c112eb8d326092abb6c6e0d2..cf090e5e758c8270daa88f7c870abf13c77c5cd7 100644 (file)
@@ -1,6 +1,6 @@
 ;;; gv.el --- generalized variables  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2012  Free Software Foundation, Inc.
+;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: extensions
@@ -111,7 +111,7 @@ DO must return an Elisp expression."
 GETTER will be bound to a copyable expression that returns the value
 of PLACE.
 SETTER will be bound to a function that takes an expression V and returns
-and new expression that sets PLACE to V.
+a new expression that sets PLACE to V.
 BODY should return some Elisp expression E manipulating PLACE via GETTER
 and SETTER.
 The returned value will then be an Elisp expression that first evaluates
@@ -194,7 +194,7 @@ well for simple place forms.
 Assignments of VAL to (NAME ARGS...) are expanded by binding the argument
 forms (VAL ARGS...) according to ARGLIST, then executing BODY, which must
 return a Lisp form that does the assignment.
-The first arg in ARLIST (the one that receives VAL) receives an expression
+The first arg in ARGLIST (the one that receives VAL) receives an expression
 which can do arbitrary things, whereas the other arguments are all guaranteed
 to be pure and copyable.  Example use:
   (gv-define-setter aref (v a i) `(aset ,a ,i ,v))"
@@ -209,13 +209,21 @@ to be pure and copyable.  Example use:
 This macro is an easy-to-use substitute for `gv-define-expander' that works
 well for simple place forms.  Assignments of VAL to (NAME ARGS...) are
 turned into calls of the form (SETTER ARGS... VAL).
+
 If FIX-RETURN is non-nil, then SETTER is not assumed to return VAL and
-instead the assignment is turned into (prog1 VAL (SETTER ARGS... VAL))
+instead the assignment is turned into something equivalent to
+  \(let ((temp VAL))
+    (SETTER ARGS... temp)
+    temp)
 so as to preserve the semantics of `setf'."
   (declare (debug (sexp (&or symbolp lambda-expr) &optional sexp)))
-  (let ((set-call `(cons ',setter (append args (list val)))))
   `(gv-define-setter ,name (val &rest args)
-     ,(if fix-return `(list 'prog1 val ,set-call) set-call))))
+     ,(if fix-return
+          `(macroexp-let2 nil v val
+             `(progn
+                (,',setter ,@(append args (list v)))
+                ,v))
+        `(cons ',setter (append args (list val))))))
 
 ;;; Typical operations on generalized variables.
 
@@ -228,7 +236,7 @@ For example, (setf (cadr x) y) is equivalent to (setcar (cdr x) y).
 The return value is the last VAL in the list.
 
 \(fn PLACE VAL PLACE VAL ...)"
-  (declare (debug (gv-place form)))
+  (declare (debug (&rest [gv-place form])))
   (if (and args (null (cddr args)))
       (let ((place (pop args))
             (val (car args)))
@@ -447,8 +455,11 @@ This is like the `&' operator of the C language."
   "Dereference REF, returning the referenced value.
 This is like the `*' operator of the C language.
 REF must have been previously obtained with `gv-ref'."
-  (declare (gv-setter (lambda (v) `(funcall (cdr ,ref) ,v))))
   (funcall (car ref)))
+;; Don't use `declare' because it seems to introduce circularity problems:
+;; Warning: Eager macro-expansion skipped due to cycle:
+;;  … => (load "gv.el") => (macroexpand-all (defsubst gv-deref …)) => (macroexpand (defun …)) => (load "gv.el")
+(gv-define-setter gv-deref (v ref) `(funcall (cdr ,ref) ,v))
 
 ;;; Vaguely related definitions that should be moved elsewhere.