summaryrefslogtreecommitdiffstats
path: root/share
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-06-20 08:07:18 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-06-20 08:07:18 -0700
commitd1e775648cba50537070b3bb598ed7dc7e5cbb64 (patch)
tree312260a6fb5bfcc315253389d0ae1544b55d3299 /share
parent55a691ccd9972e8c7dc077107e6cd065b0c37259 (diff)
downloadtxr-d1e775648cba50537070b3bb598ed7dc7e5cbb64.tar.gz
txr-d1e775648cba50537070b3bb598ed7dc7e5cbb64.tar.bz2
txr-d1e775648cba50537070b3bb598ed7dc7e5cbb64.zip
Remove places.h generation hack.
* Makefile (GEN_HDRS, LISP_TO_C_STRING): Variables removed. (%.h: %.tl): Rule removed. The place.h header is no longer generated from place.tl. * lisplib.c (place_instantiate): Load place.tl from stdlib directory, rather than obtaining it from a string literal in generated header place.h. * place.tl: Moved to share/txr/stdlib directory. * genvim.txr: Refer to place.tl in stdlib.
Diffstat (limited to 'share')
-rw-r--r--share/txr/stdlib/place.tl557
1 files changed, 557 insertions, 0 deletions
diff --git a/share/txr/stdlib/place.tl b/share/txr/stdlib/place.tl
new file mode 100644
index 00000000..83c2d813
--- /dev/null
+++ b/share/txr/stdlib/place.tl
@@ -0,0 +1,557 @@
+;; Copyright 2015
+;; Kaz Kylheku <kaz@kylheku.com>
+;; Vancouver, Canada
+;; All rights reserved.
+;;
+;; Redistribution of this software in source and binary forms, with or without
+;; modification, is permitted provided that the following two conditions are met.
+;;
+;; Use of this software in any manner constitutes agreement with the disclaimer
+;; which follows the two conditions.
+;;
+;; 1. Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; 2. Redistributions in binary form must reproduce the above copyright
+;; notice, this list of conditions and the following disclaimer in
+;; the documentation and/or other materials provided with the
+;; distribution.
+;;
+;; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+;; WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE
+;; COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DAMAGES, HOWEVER CAUSED,
+;; AND UNDER ANY THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF THE USE OF THIS
+;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(progn
+ (macro-time
+ (defvar *place-clobber-expander* (hash))
+ (defvar *place-update-expander* (hash))
+ (defvar *place-delete-expander* (hash))
+ (defvar sys:*lisp1* nil)
+
+ (defun sys:eval-err (. params)
+ (throwf 'eval-error . params))
+
+ (defmacro sys:l1-setq (sym new-val :env e)
+ (caseq (lexical-lisp1-binding e sym)
+ (:var ^(sys:setq ,sym ,new-val))
+ (:symacro (sys:eval-err "sys:l1-setq: invalid use on symbol macro"))
+ (t (if (boundp sym)
+ ^(sys:setq ,sym ,new-val)
+ ^(sys:lisp1-setq ,sym ,new-val)))))
+
+ (defmacro sys:l1-val (u-expr :env e)
+ (let ((e-expr (macroexpand u-expr e)))
+ (if (and (symbolp e-expr) (not (constantp e-expr)))
+ (caseq (lexical-lisp1-binding e e-expr)
+ (:fun ^(fun ,u-expr))
+ (:var u-expr)
+ (nil (if (boundp e-expr)
+ u-expr
+ ^(sys:lisp1-value ,u-expr)))
+ (t (sys:eval-err "sys:l1-val: invalid case")))
+ u-expr)))
+
+ (defun sys:sym-update-expander (getter-name setter-name
+ place-expr op-body)
+ (if sys:*lisp1*
+ ^(macrolet ((,getter-name () ^(sys:l1-val ,',place-expr))
+ (,setter-name (val-expr) ^(sys:l1-setq ,',place-expr
+ ,val-expr)))
+ ,op-body)
+ ^(macrolet ((,getter-name () ',place-expr)
+ (,setter-name (val-expr) ^(sys:setq ,',place-expr
+ ,val-expr)))
+ ,op-body)))
+
+ (defun sys:sym-clobber-expander (simple-setter-name
+ place-expr op-body)
+ ^(macrolet ((,simple-setter-name (val-expr)
+ ^(,(if sys:*lisp1* 'sys:l1-setq 'sys:setq)
+ ,',place-expr ,val-expr)))
+ ,op-body))
+
+ (defun sys:sym-delete-expander (deleter-name
+ place-expr . op-body)
+ ^(macrolet ((,deleter-name (:env env)
+ (when (lexical-var-p env ',place-expr)
+ (sys:eval-err "~s is a lexical variable, thus not deletable"
+ ',place-expr))
+ ^(prog1
+ (symbol-value ',',place-expr)
+ (makunbound ',',place-expr))))
+ ,*op-body))
+
+ (defun get-update-expander (place)
+ (cond
+ ((symbolp place) (fun sys:sym-update-expander))
+ ((consp place) (or [*place-update-expander* (car place)]
+ (sys:eval-err "~s is not an assignable place" place)))
+ (t (sys:eval-err "form ~s is not syntax denoting an assignable place" place))))
+
+ (defun get-clobber-expander (place)
+ (cond
+ ((symbolp place) (fun sys:sym-clobber-expander))
+ ((consp place) (or [*place-clobber-expander* (car place)]
+ (iflet ((fun [*place-update-expander* (car place)]))
+ (op apply fun (gensym) @1 @2 @rest))
+ (sys:eval-err "~s is not an assignable place" place)))
+ (t (sys:eval-err "form ~s is not syntax denoting an assignable place" place))))
+
+ (defun get-delete-expander (place)
+ (cond
+ ((symbolp place) (fun sys:sym-delete-expander))
+ ((consp place) (or [*place-delete-expander* (car place)]
+ (sys:eval-err "~s is not a deletable place" place)))
+ (t (sys:eval-err "form ~s is not syntax denoting a deletable place" place)))))
+
+ (defmacro rlet (bindings :env e . body)
+ (let ((exp-bindings (mapcar (aret ^(,@1 ,(macroexpand @2 e))) bindings)))
+ (let ((renames [keep-if constantp exp-bindings second])
+ (regular [remove-if constantp exp-bindings second]))
+ (cond ((and renames regular)
+ ^(symacrolet ,renames
+ (let ,regular ,*body)))
+ (renames ^(symacrolet ,renames ,*body))
+ (regular ^(let ,regular ,*body))
+ (t ^(progn ,*body))))))
+
+ (defmacro with-gensyms (syms . body)
+ ^(let ,(zip syms (repeat '((gensym)))) ,*body))
+
+ (macro-time
+ (defun call-update-expander (getter setter unex-place env body)
+ (let* ((place (sys:expand unex-place env))
+ (expander (get-update-expander place)))
+ [expander getter setter place body]))
+
+ (defun call-clobber-expander (ssetter unex-place env body)
+ (let* ((place (sys:expand unex-place env))
+ (expander (get-clobber-expander place)))
+ [expander ssetter place body]))
+
+ (defun call-delete-expander (deleter unex-place env body)
+ (let* ((place (sys:expand unex-place env))
+ (expander (get-delete-expander place)))
+ [expander deleter place body])))
+
+ (defmacro with-update-expander ((getter setter) unex-place env body)
+ ^(with-gensyms (,getter ,setter)
+ (call-update-expander ,getter ,setter ,unex-place ,env ,body)))
+
+ (defmacro with-clobber-expander ((ssetter) unex-place env body)
+ ^(with-gensyms (,ssetter)
+ (call-clobber-expander ,ssetter ,unex-place ,env ,body)))
+
+ (defmacro with-delete-expander ((deleter) unex-place env body)
+ ^(with-gensyms (,deleter)
+ (call-delete-expander ,deleter ,unex-place ,env ,body)))
+
+ (defmacro set (:env env . place-value-pairs)
+ (let ((assign-forms (mapcar (tb ((place : (value nil value-present-p)))
+ (unless value-present-p
+ (sys:eval-err "set: arguments must be pairs"))
+ (with-clobber-expander (ssetter) place env
+ ^(,ssetter ,value)))
+ (tuples 2 place-value-pairs))))
+ (if (cdr assign-forms)
+ ^(progn ,*assign-forms)
+ (car assign-forms))))
+
+ (defmacro pset (:env env . place-value-pairs)
+ (let ((len (length place-value-pairs)))
+ (cond
+ ((oddp len) (sys:eval-err "pset: arguments must be pairs"))
+ ((<= len 2) ^(set ,*place-value-pairs))
+ (t (let* ((pvtgs (mapcar (tb ((a b))
+ (list a b (gensym) (gensym) (gensym)))
+ (tuples 2 place-value-pairs)))
+ (ls (reduce-left (tb ((lets stores) (place value temp getter setter))
+ (list ^((,temp ,value) ,*lets)
+ ^((,setter ,temp) ,*stores)))
+ pvtgs '(nil nil)))
+ (lets (first ls))
+ (stores (second ls))
+ (body-form ^(let (,*lets) ,*stores)))
+ (reduce-left (tb (accum-form (place value temp getter setter))
+ (call-update-expander getter setter
+ place env accum-form))
+ pvtgs body-form))))))
+
+ (defmacro zap (place :env env)
+ (with-update-expander (getter setter) place env
+ ^(prog1 (,getter) (,setter nil))))
+
+ (defmacro flip (place :env env)
+ (with-update-expander (getter setter) place env
+ ^(,setter (not (,getter)))))
+
+ (defmacro inc (place : (delta 1) :env env)
+ (with-update-expander (getter setter) place env
+ (caseql delta
+ (0 ^(,setter (,getter)))
+ (1 ^(,setter (succ (,getter))))
+ (2 ^(,setter (ssucc (,getter))))
+ (3 ^(,setter (sssucc (,getter))))
+ (t ^(,setter (+ (,getter) ,delta))))))
+
+ (defmacro dec (place : (delta 1) :env env)
+ (with-update-expander (getter setter) place env
+ (caseql delta
+ (0 ^(,setter (,getter)))
+ (1 ^(,setter (pred (,getter))))
+ (2 ^(,setter (ppred (,getter))))
+ (3 ^(,setter (pppred (,getter))))
+ (t ^(,setter (- (,getter) ,delta))))))
+
+ (defmacro swap (place-0 place-1 :env env)
+ (with-gensyms (tmp)
+ (with-update-expander (getter-0 setter-0) place-0 env
+ (with-update-expander (getter-1 setter-1) place-1 env
+ ^(let ((,tmp (,getter-0)))
+ (,setter-0 (,getter-1))
+ (,setter-1 ,tmp))))))
+
+ (defmacro push (new-item place :env env)
+ (with-gensyms (new-sym)
+ ^(let ((,new-sym ,new-item))
+ ,(with-update-expander (getter setter) place env
+ ^(,setter (cons ,new-sym (,getter)))))))
+
+ (defmacro pop (place :env env)
+ (with-gensyms (tmp)
+ (with-update-expander (getter setter) place env
+ ^(let ((,tmp (,getter)))
+ (prog1 (car ,tmp) (,setter (cdr ,tmp)))))))
+
+ (defmacro pushnew (new-item place :env env :
+ (testfun :)
+ (keyfun :))
+ (with-update-expander (getter setter) place env
+ (with-gensyms (new-item-sym old-list-sym)
+ ^(let ((,new-item-sym ,new-item))
+ ,(with-update-expander (getter setter) place env
+ ^(let ((,old-list-sym (,getter)))
+ (if (member ,new-item-sym ,old-list-sym ,testfun ,keyfun)
+ ,old-list-sym
+ (,setter (cons ,new-item-sym ,old-list-sym)))))))))
+
+ (defmacro shift (:env env . places)
+ (tree-case places
+ (() (sys:eval-err "shift: need at least two arguments"))
+ ((place) (sys:eval-err "shift: need at least two arguments"))
+ ((place newvalue)
+ (with-update-expander (getter setter) place env
+ ^(prog1 (,getter) (,setter ,newvalue))))
+ ((place . others)
+ (with-update-expander (getter setter) place env
+ ^(prog1 (,getter) (,setter (shift ,*others)))))))
+
+ (defmacro rotate (:env env . places)
+ (tree-case places
+ (() ())
+ ((fplace) fplace)
+ ((fplace . rplaces)
+ (with-gensyms (tmp)
+ (with-update-expander (getter-f setter-f) fplace env
+ ^(let ((,tmp (,getter-f)))
+ (,setter-f (shift ,*rplaces ,tmp))
+ ,tmp))))))
+
+ (defmacro del (place :env env)
+ (with-delete-expander (deleter) place env
+ ^(,deleter)))
+
+ (defmacro defplace (place-destructuring-args body-sym
+ (getter-sym setter-sym update-body) :
+ ((ssetter-sym clobber-body))
+ ((deleter-sym delete-body)))
+ (symacrolet ((name (car place-destructuring-args))
+ (args (cdr place-destructuring-args)))
+ (unless (and name
+ (symbolp name)
+ (not (keywordp name))
+ (not (eq t name)))
+ (sys:eval-err "~s: ~s cannot be used as a place name"
+ 'defplace name))
+ (with-gensyms (place)
+ ^(macro-time
+ (sethash *place-update-expander* ',name
+ (lambda (,getter-sym ,setter-sym ,place ,body-sym)
+ (tree-bind ,args (cdr ,place)
+ ,update-body)))
+ ,*(if ssetter-sym
+ ^((sethash *place-clobber-expander* ',name
+ (lambda (,ssetter-sym ,place ,body-sym)
+ (tree-bind ,args (cdr ,place)
+ ,clobber-body)))))
+ ,*(if deleter-sym
+ ^((sethash *place-delete-expander* ',name
+ (lambda (,deleter-sym ,place ,body-sym)
+ (tree-bind ,args (cdr ,place)
+ ,delete-body)))))))))
+
+ (defplace (car cell) body
+ (getter setter
+ (with-gensyms (cell-sym)
+ ^(rlet ((,cell-sym ,cell))
+ (macrolet ((,getter () ^(car ,',cell-sym))
+ (,setter (val) ^(sys:rplaca ,',cell-sym ,val)))
+ ,body))))
+ (ssetter
+ ^(macrolet ((,ssetter (val) ^(sys:rplaca ,',cell ,val)))
+ ,body))
+ (deleter
+ ^(macrolet ((,deleter () ^(pop ,',cell)))
+ ,body)))
+
+ (defplace (cdr cell) body
+ (getter setter
+ (with-gensyms (cell-sym)
+ ^(rlet ((,cell-sym ,cell))
+ (macrolet ((,getter () ^(cdr ,',cell-sym))
+ (,setter (val) ^(sys:rplacd ,',cell-sym ,val)))
+ ,body))))
+ (ssetter
+ ^(macrolet ((,ssetter (val) ^(sys:rplacd ,',cell ,val)))
+ ,body))
+ (deleter
+ ^(macrolet ((,deleter () ^(zap (cdr ,',cell))))
+ ,body)))
+
+ (defplace (vecref vector index :whole args) body
+ (getter setter
+ (with-gensyms (vec-sym ind-sym)
+ ^(rlet ((,vec-sym ,vector)
+ (,ind-sym ,index))
+ (macrolet ((,getter () ^(vecref ,',vec-sym ,',ind-sym))
+ (,setter (val) ^(refset ,',vec-sym ,',ind-sym ,val)))
+ ,body))))
+ (ssetter
+ ^(macrolet ((,ssetter (val) ^(refset ,*',args ,val)))
+ ,body))
+ (deleter
+ (with-gensyms (vec-sym ind-sym)
+ ^(rlet ((,vec-sym ,vector)
+ (,ind-sym ,index))
+ (macrolet ((,deleter ()
+ ^(prog1 (vecref ,',vec-sym ,',ind-sym)
+ (replace-vec ,',vec-sym nil
+ ,',ind-sym (succ ,',ind-sym)))))
+ ,body)))))
+
+ (defplace (chr-str string index :whole args) body
+ (getter setter
+ (with-gensyms (str-sym ind-sym)
+ ^(rlet ((,str-sym ,string)
+ (,ind-sym ,index))
+ (macrolet ((,getter () ^(chr-str ,',str-sym ,',ind-sym))
+ (,setter (val) ^(chr-str-set ,',str-sym ,',ind-sym ,val)))
+ ,body))))
+ (ssetter
+ ^(macrolet ((,ssetter (val) ^(chr-str-set ,*',args ,val)))
+ ,body))
+ (deleter
+ (with-gensyms (str-sym ind-sym)
+ ^(rlet ((,str-sym ,string)
+ (,ind-sym ,index))
+ (macrolet ((,deleter ()
+ ^(prog1 (chr-str ,',str-sym ,',ind-sym)
+ (replace-str ,',str-sym nil
+ ,',ind-sym (succ ,',ind-sym)))))
+ ,body)))))
+
+ (defplace (ref seq index :whole args) body
+ (getter setter
+ (with-gensyms (seq-sym ind-sym)
+ ^(rlet ((,seq-sym ,seq)
+ (,ind-sym ,index))
+ (macrolet ((,getter () ^(ref ,',seq-sym ,',ind-sym))
+ (,setter (val) ^(refset ,',seq-sym ,',ind-sym ,val)))
+ ,body))))
+ (ssetter
+ ^(macrolet ((,ssetter (val) ^(refset ,*',args ,val)))
+ ,body))
+ (deleter
+ (with-gensyms (seq-sym ind-sym)
+ ^(rlet ((,seq-sym ,seq)
+ (,ind-sym ,index))
+ (macrolet ((,deleter ()
+ ^(prog1 (ref ,',seq-sym ,',ind-sym)
+ (replace ,',seq-sym nil
+ ,',ind-sym (succ ,',ind-sym)))))
+ ,body)))))
+
+ (defplace (gethash hash key : (default nil have-default-p)) body
+ (getter setter
+ (with-gensyms (entry-sym)
+ ^(let ((,entry-sym (inhash ,hash ,key ,default)))
+ (macrolet ((,getter () ^(cdr ,',entry-sym))
+ (,setter (val) ^(sys:rplacd ,',entry-sym ,val)))
+ ,body))))
+ :
+ (deleter
+ ^(macrolet ((,deleter ()
+ (if ,have-default-p
+ (with-gensyms (entry-sym
+ dfl-sym)
+ ^(rlet ((,entry-sym (inhash ,',hash ,',key))
+ (,dfl-sym ,',default))
+ (if ,entry-sym
+ (remhash ,',hash ,',key)
+ ,dfl-sym)))
+ ^(remhash ,',hash ,',key))))
+ ,body)))
+
+ (defplace (dwim obj-place index : (default nil have-default-p) :env env) body
+ (getter setter
+ (with-gensyms (ogetter-sym osetter-sym obj-sym
+ oldval-sym newval-sym
+ index-sym index-sym
+ oldval-sym dflval-sym)
+ (let ((sys:*lisp1* (or (symbolp obj-place) sys:*lisp1*)))
+ (with-update-expander (ogetter-sym osetter-sym) obj-place nil
+ ^(rlet ((,obj-sym (,ogetter-sym))
+ (,index-sym (sys:l1-val ,index))
+ ,*(if have-default-p
+ ^((,dflval-sym (sys:l1-val ,default)))))
+ (let ((,oldval-sym [,obj-sym
+ ,index-sym
+ ,*(if have-default-p ^(,dflval-sym))]))
+ (macrolet ((,getter () ',oldval-sym)
+ (,setter (val)
+ ^(rlet ((,',newval-sym ,val))
+ (,',osetter-sym
+ (sys:dwim-set ,',obj-sym
+ ,',index-sym ,',newval-sym))
+ ,',newval-sym)))
+ ,body)))))))
+ (ssetter
+ (with-gensyms (osetter-sym ogetter-sym
+ obj-sym newval-sym index-sym)
+ (let ((sys:*lisp1* (or (symbolp obj-place) sys:*lisp1*)))
+ (with-update-expander (ogetter-sym osetter-sym) obj-place nil
+ ^(macrolet ((,ssetter (val)
+ ^(rlet ((,',obj-sym (,',ogetter-sym))
+ (,',index-sym (sys:l1-val ,',index))
+ (,',newval-sym ,val))
+ (,',osetter-sym
+ (sys:dwim-set ,',obj-sym
+ ,*(if ,have-default-p
+ ^((prog1
+ ,',index-sym
+ (sys:l1-val ,',default)))
+ ^(,',index-sym))
+ ,',newval-sym))
+ ,',newval-sym)))
+ ,body)))))
+
+ (deleter
+ (with-gensyms (osetter-sym ogetter-sym
+ obj-sym index-sym oldval-sym
+ dflval-sym)
+ (let ((sys:*lisp1* (or (symbolp obj-place) sys:*lisp1*)))
+ (with-update-expander (ogetter-sym osetter-sym) obj-place nil
+ ^(macrolet ((,deleter () ;; todo: place must not have optional val
+ ^(rlet ((,',obj-sym (,',ogetter-sym)))
+ (let* ((,',index-sym (sys:l1-val ,',index))
+ (,',oldval-sym [,',obj-sym
+ ,',index-sym
+ ,*(if ,have-default-p
+ ^(,',default))]))
+ (progn
+ (,',osetter-sym
+ (sys:dwim-del ,',obj-sym ,',index-sym))
+ ,',oldval-sym)))))
+ ,body))))))
+
+ (defplace (force promise) body
+ (getter setter
+ (with-gensyms (promise-sym)
+ ^(rlet ((,promise-sym ,promise))
+ (macrolet ((,getter ()
+ ^(force ,',promise-sym))
+ (,setter (val)
+ ^(set (car (cdr ,',promise-sym)) ,val)))
+ ,body))))
+ (ssetter
+ (with-gensyms (promise-sym)
+ ^(rlet ((,promise-sym ,promise))
+ (macrolet ((,ssetter (val)
+ ^(prog1
+ (set (car (cdr ,',promise-sym)) ,val)
+ (set (car ,',promise-sym) 'sys:promise-forced))))
+ ,body)))))
+
+ (defplace (errno) body
+ (getter setter
+ ^(macrolet ((,getter () '(errno))
+ (,setter (val-expr)
+ (with-gensyms (val-sym)
+ ^(rlet ((,val-sym ,val-expr))
+ (progn (errno ,val-sym) ,val-sym)))))
+ ,body)))
+
+ (defplace (fun sym) body
+ (getter setter
+ ^(macrolet ((,getter () ^(fun ,',sym))
+ (,setter (val) ^(sys:setqf ,',sym ,val)))
+ ,*body))
+ :
+ (deleter
+ ^(macrolet ((,deleter (:env env)
+ (when (lexical-fun-p env ',sym)
+ (sys:eval-err "~s is a lexical function, \
+ \ thus not deletable"
+ ',sym))
+ ^(fmakunbound ',',sym)))
+ ,*body)))
+
+ (defun sys:get-fb (sym)
+ (or (gethash sys:top-fb sym)
+ (sys:eval-err "unbound function ~s" sym)))
+
+ (defplace (symbol-function sym-expr) body
+ (getter setter
+ (with-gensyms (binding-sym)
+ ^(let ((,binding-sym (sys:get-fb ,sym-expr)))
+ (macrolet ((,getter () ^(cdr ,',binding-sym))
+ (,setter (val) ^(sys:rplacd ,',binding-sym ,val)))
+ ,*body))))
+ :
+ (deleter
+ ^(macrolet ((,deleter () ^(fmakunbound ,',sym-expr)))
+ ,*body)))
+
+ (defun sys:get-vb (sym)
+ (or (gethash sys:top-vb sym)
+ (sys:eval-err "unbound variable ~s" sym)))
+
+ (defplace (symbol-value sym-expr) body
+ (getter setter
+ (with-gensyms (binding-sym)
+ ^(let ((,binding-sym (sys:get-vb ,sym-expr)))
+ (macrolet ((,getter () ^(cdr ,',binding-sym))
+ (,setter (val) ^(sys:rplacd ,',binding-sym ,val)))
+ ,*body))))
+ :
+ (deleter
+ ^(macrolet ((,deleter () ^(makunbound ,',sym-expr)))
+ ,*body)))
+
+ (macro-time
+ (each ((from '(car cdr))
+ (to '(first rest)))
+ (each ((table (list *place-update-expander*
+ *place-clobber-expander*
+ *place-delete-expander*)))
+ (set [table to] [table from]))))
+
+ (defmacro define-modify-macro (name lambda-list function)
+ (let ((cleaned-lambda-list (mapcar [iffi consp car]
+ (remql : lambda-list))))
+ (with-gensyms (place-sym args-sym)
+ ^(defmacro ,name (:env env ,place-sym ,*lambda-list)
+ (with-update-expander (getter setter) ,place-sym env
+ ^(,setter (,',function (,getter) ,,*cleaned-lambda-list))))))))