]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/gv.el
Merge from emacs-24; up to 2012-12-15T12:19:04Z!juri@jurta.org
[gnu-emacs] / lisp / emacs-lisp / gv.el
index 7858c183e4be3744c557d47eb84da654ba27a2fc..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)))
@@ -358,7 +366,8 @@ The return value is the last VAL in the list.
 
 (put 'if 'gv-expander
      (lambda (do test then &rest else)
-       (if (macroexp-small-p (funcall do 'dummy (lambda (_) 'dummy)))
+       (if (or (not lexical-binding)  ;The other code requires lexical-binding.
+               (macroexp-small-p (funcall do 'dummy (lambda (_) 'dummy))))
            ;; This duplicates the `do' code, which is a problem if that
            ;; code is large, but otherwise results in more efficient code.
            `(if ,test ,(gv-get then do)
@@ -376,7 +385,8 @@ The return value is the last VAL in the list.
 
 (put 'cond 'gv-expander
      (lambda (do &rest branches)
-       (if (macroexp-small-p (funcall do 'dummy (lambda (_) 'dummy)))
+       (if (or (not lexical-binding)  ;The other code requires lexical-binding.
+               (macroexp-small-p (funcall do 'dummy (lambda (_) 'dummy))))
            ;; This duplicates the `do' code, which is a problem if that
            ;; code is large, but otherwise results in more efficient code.
            `(cond
@@ -431,6 +441,26 @@ The return value is the last VAL in the list.
                        `(logior (logand ,v ,mask)
                                 (logand ,getter (lognot ,mask))))))))))
 
+;;; References
+
+;;;###autoload
+(defmacro gv-ref (place)
+  "Return a reference to PLACE.
+This is like the `&' operator of the C language."
+  (gv-letplace (getter setter) place
+    `(cons (lambda () ,getter)
+           (lambda (gv--val) ,(funcall setter 'gv--val)))))
+
+(defsubst gv-deref (ref)
+  "Dereference REF, returning the referenced value.
+This is like the `*' operator of the C language.
+REF must have been previously obtained with `gv-ref'."
+  (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.
 
 ;; (defun alist-get (key alist)