diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-05-23 07:23:52 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-05-23 07:23:52 -0700 |
commit | 76a16fb5d59b9b0d0ac44151a8d1047f19acd044 (patch) | |
tree | db617b7f19ed171eef00e7f7c5f61927bc9efe15 | |
parent | b491768c9377f474c130b4b27b893ae9504929ac (diff) | |
download | lisp-snippets-76a16fb5d59b9b0d0ac44151a8d1047f19acd044.tar.gz lisp-snippets-76a16fb5d59b9b0d0ac44151a8d1047f19acd044.tar.bz2 lisp-snippets-76a16fb5d59b9b0d0ac44151a8d1047f19acd044.zip |
-rw-r--r-- | placelet.lisp | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/placelet.lisp b/placelet.lisp new file mode 100644 index 0000000..72d3c76 --- /dev/null +++ b/placelet.lisp @@ -0,0 +1,72 @@ +;;; +;;; Implementation of TXR Lisp "placelet", in Common Lisp +;;; +;;; Copyright 2019 Kaz Kylheku <kaz@kylheku.com> +;;; +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions are met: +;;; +;;; 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +;;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +;;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +;;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +;;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +;;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +;;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +;;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +;;; POSSIBILITY OF SUCH DAMAGE. +;;; + +;; +;; This is subtly broken. The proxy-place we establish with +;; define-setf-expander is not not actually used. sym ends up being bound to +;; the r-form of the original place, and then we are relying on that form being +;; place. That just happens to work for most well-behaved places. +;; +;; What we need here is a forced full expansion between the symbol-macrolet +;; and macrolet, like in the TXR Lisp implementation. We most process body +;; in an environment in which ,sym to (,proxy-place), but (,proxy-place) +;; doesn't expand to r-form, so that all the occurrences of sym which the +;; body treats as places are treated that way through the ,proxy-place +;; setf expander. When we obtain those expansions, then we impose the +;; macrolet in order to replace the remaining (,proxy-place) references +;; that are not places with the read form. +;; +(defmacro placelet1 (sym place &environment env &body body) + (multiple-value-bind (vars vals store-vars w-form r-form) + (get-setf-expansion place env) + (let ((proxy-place (gensym))) + (define-setf-expander proxy-place () + (values nil nil store-vars w-form r-form)) + `(let* (,@(mapcar #'list vars vals)) + (macrolet ((,proxy-place () ',r-form)) + ;; we need to fully expand this symbol-macrolet, + ;; then insert it into here: ,(full-expand (symbol-macrolet ...)) + (symbol-macrolet ((,sym (,proxy-place))) + ,@body)))))) + + +(defmacro placelet* (sym-place-pairs &body body) + (cond + ((null sym-place-pairs) `(progn ,@body)) + ((atom sym-place-pairs) (error "~s: bad syntax" 'placelet)) + (t (destructuring-bind (sym place) (car sym-place-pairs) + `(placelet1 ,sym ,place ,@(if (cdr sym-place-pairs) + `((placelet ,(cdr sym-place-pairs) ,@body)) + body)))))) + +(defmacro placelet (sym-place-pairs &body body) + (destructuring-bind (syms places) (apply #'mapcar #'list sym-place-pairs) + (let ((temps (mapcar (lambda (sym) (gensym)) syms))) + `(placelet* (,@(mapcar #'list temps places)) + (symbol-macrolet (,@(mapcar #'list syms temps)) + ,@body))))) |