summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-11-25 06:29:43 -0800
committerKaz Kylheku <kaz@kylheku.com>2015-11-25 06:29:43 -0800
commitfd7e0a944b77d1cbba91e323cd0679bf0d00652b (patch)
tree1d1c3beea176c987eb8b2a6bbd0dbb6d1f545905
parent49133d53e863ddfeeffcb46c7c20575f8c7910c5 (diff)
downloadtxr-fd7e0a944b77d1cbba91e323cd0679bf0d00652b.tar.gz
txr-fd7e0a944b77d1cbba91e323cd0679bf0d00652b.tar.bz2
txr-fd7e0a944b77d1cbba91e323cd0679bf0d00652b.zip
New macro define-accessor.
* lisplib.c (place_set_entries): New entry to trigger autoloading for define-accessor. * share/txr/stdlib/place.tl (sys:register-simple-accessor): New function. (define-accessor): New macro. * txr.1: Documented define-accessor.
-rw-r--r--lisplib.c2
-rw-r--r--share/txr/stdlib/place.tl19
-rw-r--r--txr.172
3 files changed, 92 insertions, 1 deletions
diff --git a/lisplib.c b/lisplib.c
index b33018da..065436bf 100644
--- a/lisplib.c
+++ b/lisplib.c
@@ -71,7 +71,7 @@ static val place_set_entries(val dlt, val fun)
lit("push"), lit("pop"), lit("swap"), lit("shift"), lit("rotate"),
lit("pushnew"), lit("del"),
lit("defplace"), lit("define-place-macro"), lit("define-modify-macro"),
- lit("placelet"), lit("placelet*"),
+ lit("placelet"), lit("placelet*"), lit("define-acessor"),
nil
};
diff --git a/share/txr/stdlib/place.tl b/share/txr/stdlib/place.tl
index c60348e6..81a506a5 100644
--- a/share/txr/stdlib/place.tl
+++ b/share/txr/stdlib/place.tl
@@ -652,6 +652,25 @@
(symacrolet (,*(zip syms temps))
,*body)))))
+(defun sys:register-simple-accessor (get-fun set-fun)
+ (sethash *place-update-expander* get-fun
+ (lambda (getter setter place body)
+ (let* ((args (cdr place))
+ (temps (mapcar (ret (gensym)) args)))
+ ^(let (,(zip temps args))
+ (macrolet ((,getter () ^(,',get-fun ,*',temps))
+ (,setter (val)
+ ^(,',set-fun ,*',temps ,val)))
+ ,body)))))
+ (sethash *place-clobber-expander* get-fun
+ (lambda (ssetter place body)
+ ^(macrolet ((,ssetter (val)
+ ^(,',set-fun ,*(cdr ',place) ,val)))
+ ,body))))
+
+(defmacro define-accessor (get-fun set-fun)
+ ^(sys:register-simple-accessor ',get-fun ',set-fun))
+
(define-place-macro first (obj) ^(car ,obj))
(define-place-macro rest (obj) ^(cdr ,obj))
(define-place-macro second (obj) ^(ref ,obj 1))
diff --git a/txr.1 b/txr.1
index 5f59f01d..aa31fbae 100644
--- a/txr.1
+++ b/txr.1
@@ -25482,6 +25482,78 @@ turning the expression
into
.codn (+ 1 y) .
+.coNP Macro @ define-accessor
+.synb
+.mets (define-accessor < get-function << set-function )
+.syne
+.desc
+The
+.code define-accessor
+macro is used for turning a function into an accessor,
+such that forms which call the function can be treated
+as places.
+
+Arguments to
+.code define-accessor
+are two symbols, which must name functions. When the
+.code define-accessor
+call is evaluated, the
+.meta get-function
+symbol is registered as a syntactic place. Stores to the
+place are handled via calls to
+.metn set-function .
+
+If
+.meta get-function
+names a function which takes N
+arguments,
+.meta set-function
+must name a function which takes N+1 arguments.
+
+Moreover, in order for the accessor semantics to be correct
+.meta set-function
+must treat its rightmost argument as the value being stored,
+and must also return that value.
+
+When a function call form targeting
+.meta get-function
+is treated as a place which is subject
+to an update operation (for instance an increment via the
+.code inc
+macro),
+the accessor definition created by
+.code define-accessor
+ensures that the arguments of
+.meta get-function
+are evaluated only once, even though the update involves
+a call to
+.meta get-function
+and
+.meta set-function
+with the same arguments. The argument forms are evaluated to
+temporary variables, and these temporaries are used as the
+arguments in the calls.
+
+No other assurances are provided by
+.codn define-accessor .
+
+In particular, if
+.meta get-function
+and
+.meta set-function
+internally each perform some redundant calculation over their arguments,
+this cannot be optimized. Moreover, if that calculation has a visible effect,
+that effect is observed multiple times in an update operation.
+
+If further optimization or suppression of multiple effects is required,
+the more general
+.code defplace
+macro must be used to define the accessor. It may also be possible to
+treat the situation in a satisfactory way using a
+.code define-place-macro
+definition, which effectively then supplies inline code whenever a certain form
+is used as a place, and that code itself is treated as a place.
+
.coNP Macro @ with-gensyms
.synb
.mets (with-gensyms <> ( sym *) << body-form *)