diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-11-25 06:29:43 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-11-25 06:29:43 -0800 |
commit | fd7e0a944b77d1cbba91e323cd0679bf0d00652b (patch) | |
tree | 1d1c3beea176c987eb8b2a6bbd0dbb6d1f545905 | |
parent | 49133d53e863ddfeeffcb46c7c20575f8c7910c5 (diff) | |
download | txr-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.c | 2 | ||||
-rw-r--r-- | share/txr/stdlib/place.tl | 19 | ||||
-rw-r--r-- | txr.1 | 72 |
3 files changed, 92 insertions, 1 deletions
@@ -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)) @@ -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 *) |