From fd7e0a944b77d1cbba91e323cd0679bf0d00652b Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Wed, 25 Nov 2015 06:29:43 -0800 Subject: 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. --- lisplib.c | 2 +- share/txr/stdlib/place.tl | 19 +++++++++++++ txr.1 | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) 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 *) -- cgit v1.2.3