To produce the same results with other CL implementations WHEN the eval order is relevent, I think out following solution:
(defmacro my-define-modify-macro
(name lambda-list function &rest doc-string-and-declarations)
`(progn
(define-modify-macro
,name ,lambda-list ,function ,@doc-string-and-declarations)
#+lispworks
(define-compiler-macro ,name
(&whole form var &rest args)
(if (every #'(lambda (x) (or (atom x)
(eq 'quote (car x))))
args)
(let ((temp (gensym)))
`(let ((,temp (,',function ,var ,@args)))
(setq ,var ,temp)))
form))))
That is: for atom and quote arguments, just don't use LW's DEFINE-MODIFY-MACRO. Now, I got following results:
CL-USER 14 > (funcall (compiler-macro-function 'xxx-modify-macro-using-test)
'(xxx-modify-macro-using-test a 0 'eql nil) nil)
(LET ((#:G940 (XXX-PUSHNEW-FUNCTION-USING-TEST A 0 (QUOTE EQL) NIL))) (SETQ A #:G940))
CL-USER 15 > (funcall (compiler-macro-function 'xxx-modify-macro-using-test)
'(xxx-modify-macro-using-test a 0 (setq a b) nil) nil)
(XXX-MODIFY-MACRO-USING-TEST A 0 (SETQ A B) NIL)
Do you think this will work?
Regards,
Chun Tian (binghe)
On Sat, Mar 14, 2009 at 5:32 AM, Martin Simmons
<martin@lispworks.com> wrote:
>>>>> On Fri, 13 Mar 2009 00:56:32 +0800, Chun Tian (binghe) said:
>
> Hi, LispWorks
>
> Say given following DEFINE-MODIFY-MACRO definition:
>
> (DEFINE-MODIFY-MACRO XXX-MODIFY-MACRO-USING-TEST (XXX-PUSHNEW XXX-
> PUSHNEW-TEST XXX-PUSHNEW-KEY)
> XXX-PUSHNEW-FUNCTION-USING-TEST)
>
> When I try to do (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL
> NIL)), almost every CL give me results like this:
>
> CL-USER(2): (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL NIL))
> (LET* ((#:G100 (XXX-PUSHNEW-FUNCTION-USING-TEST A 0 'EQL NIL)))
> (SETQ A #:G100))
> T
>
> Above happens on Allegro CL, and results from SBCL, Clozure CL are
> almost the same. But LispWorks give me following result:
>
> CL-USER 1 > (macroexpand-1 '(XXX-MODIFY-MACRO-USING-TEST A 0 'EQL NIL))
> (LET* ()
> (LET* ((#:|following-form3994| 0) (#:|following-form3995| 'EQL) (#:|
> following-form3996| NIL))
> (LET ((#:G3993
> (XXX-PUSHNEW-FUNCTION-USING-TEST A
> #:|following-form3994|
> #:|following-form3995|
> #:|following-form3996|)))
> (SETQ A #:G3993))))
> T
>
> When XXX-PUSHNEW-FUNCTION-USING-TEST is NOT a function but macro, the
> macro expansion which generated by LispWorks break my code ...
>
> So I want to ask:
>
> 1) Is that legal if I use a macro symbol on DEFINE-MODIFY-MACRO's last
> argument?
I don't think ANSI specifies what forms appear in the expansion, though it
does specify order of evaluation (see below).
> or
>
> 2) Is the behavior of LW's DEFINE-MODIFY-MACRO right?
Yes and I suspect other implementations are slightly wrong. Consider the
following:
(defun radjoin (list value)
(adjoin value list))
(define-modify-macro rpushnew (value) radjoin)
(let ((the-list (list 1 2)))
(rpushnew the-list (setq the-list (list 4 5)))
the-list)
According to ANSI 5.1.3
http://www.lispworks.com/documentation/HyperSpec/Body/05_ac.htm, the
evaluation proceeds in 6 steps. For the above example, the steps should be
like this:
1. Skipped (there are no preceding-forms).
2. Skipped (there are no subforms of the place the-list).
3. Evaluate the following-form (setq the-list (list 4 5)).
4. Read the-list, giving (4 5).
5. Compute the new value from (radjoin (4 5) (4 5)), giving ((4 5) 4 5).
6. Store ((4 5) 4 5) into the-list.
--
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/
--
Chun Tian (binghe)
NetEase.com, Inc.