summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2012-01-16 23:16:22 -0800
committerKaz Kylheku <kaz@kylheku.com>2012-01-16 23:16:22 -0800
commit8e929366ee8e10b6380090a58acd71a34c0de5f7 (patch)
tree4432f76c52148d8fbf1302751125c5183a74f6a6
parent50db60e534115bd2d340c959904145a169025515 (diff)
downloadlisp-snippets-8e929366ee8e10b6380090a58acd71a34c0de5f7.tar.gz
lisp-snippets-8e929366ee8e10b6380090a58acd71a34c0de5f7.tar.bz2
lisp-snippets-8e929366ee8e10b6380090a58acd71a34c0de5f7.zip
Adding refs.
-rw-r--r--refs.lisp51
1 files changed, 51 insertions, 0 deletions
diff --git a/refs.lisp b/refs.lisp
new file mode 100644
index 0000000..de36c51
--- /dev/null
+++ b/refs.lisp
@@ -0,0 +1,51 @@
+;;;
+;;; Lisp references: pointer-like place locators that can be passed around.
+;;;
+;;; Copyright 2012 Kaz Kylheku <kaz@kylheku.com>
+;;;
+;;; How to use:
+;;;
+;;; Produce a reference which "lifts" the place designated
+;;; by form P:
+;;;
+;;; (ref p)
+;;;
+;;; Dereference a reference R to designate the original place:
+;;;
+;;; (deref r)
+;;; (setf (deref r) 42) ;; store new value 42
+;;;
+;;; Shorthand notation instead of writing a lot of (deref)
+;;; Over FORMS, A is a symbol macro which expands to
+;;; (DEREF RA), B expands to (DEREF RB):
+;;;
+;;; (with-refs ((a ra) (b rb) ...)
+;;;
+;;; ... forms)
+;;;
+(defstruct ref
+ (get-func)
+ (set-func))
+
+(defun deref (ref)
+ (funcall (ref-get-func ref)))
+
+(defun (setf deref) (val ref)
+ (funcall (ref-set-func ref) val))
+
+(defmacro ref (place-expression &environment env)
+ (multiple-value-bind (temp-syms val-forms
+ store-vars store-form access-form)
+ (get-setf-expansion place-expression env)
+ (when (cdr store-vars)
+ (error "REF: cannot take ref of multiple-value place"))
+ `(multiple-value-bind (,@temp-syms) (values ,@val-forms)
+ (make-ref
+ :get-func (lambda () ,access-form)
+ :set-func (lambda (,@store-vars) ,store-form)))))
+
+(defmacro with-refs ((&rest ref-specs) &body forms)
+ `(symbol-macrolet
+ ,(loop for (var ref) in ref-specs
+ collecting (list var `(deref ,ref)))
+ ,@forms))