
Hi, Once again (hopefully, for the last time) I want to address the question "to use or not to use", so to say, macroexpansion inside w-h-o form, and moreover, how to do it right. I have experimented with the previously proposed solution of introducing additional EMB keyword and have found, that it as well has some drawbacks. More precisely, they exist because of the nature of the w-h-o macro itself, which uses special processing for the forms, contained inside HTM: they are processed before any function application, that is why if you EMBed some macros, which use HTM keyword, which should output to their own streams, the result can be emitted in the unexpected order. To illustrate this vague statement, I can show the piece of the code, that combines cl-who and parenscript forms to make a currency selection form with some javascript backing: (defmacro cur-sel () (w/uniqs (cur) (let ((sel-str `(:select :id "currency" (dolist (,cur *currencies*) (htm (:option :selected (string= ,cur *default-currency*) (str ,cur))))))) `(htm (emb (ps-script* (write-htm (:a :class "toggle" :onclick (ps-inline* `(lambda () ,(write-htm ,sel-str))) (str (ie-val *default-currency*)))))) (:noscript ,sel-str))))) (defmacro write-htm (form) ``(.write document ,(who ,form))) The macro CUR-SEL, that is intended to itself be EMBedded, uses WRITE-HTM to emit HTML forms to string, that will in turn be an argument to javascript document.write(). But, as after macroexpansion of sel-str HTM forms appear as arguments to WRITE-HTM, the output of the containing w-h-o forms goes to the stream, bound by the topmost w-h-o and not the innermost, as it's supposed... Anyway, after some re-thinking of a problem, I've come to a conclusion, that my approach was not the most natural one. Now, I believe, that the more lispy way is to view w-h-o macro as solely a good processor for static pseudo-html data (like '(:p some text (:br) (:a :href ....), and on top of it build macros, which will allow eventually to add macroexpansion ability. My initial target was to be able to use macros with pseudo-html forms, like in the following simple example: (def-who-macro (arg) `(:p some text (:br) (:a :href ,arg))) inside w-h-o body the same way you would use an ordinary macro, but I'd got carried away with modifying the w-h-o macro itself to allow for such usage. It turned out, that it's not hard to implement the separated approach. My variant is below: (defmacro def-who-macro (name (&rest args) pseudo-html-form) "Produces functions for generating pseudo-html forms, which can be embedded in WHO-PAGEs" `(defun ,name (,@args) ,pseudo-html-form)) (defmacro def-who-page (name (&optional stream) pseudo-html-form) "Creates a function to generate an HTML page with the use of WITH-HTML-OUTPUT macro, in which pseudo-html forms, constructed with DEF-WHO-MACRO, can be embedded. If STREAM is nil/not supplied WITH-HTML-OUTPUT-TO-STRING to a throwaway string will be used, otherwise -- WITH-HTML-OUTPUT" `(macrolet ((who-tmp () `(,@',(if stream `(with-html-output (,stream nil :prologue t)) `(with-html-output-to-string (,(gensym) nil :prologue t))) ,,pseudo-html-form))) (defun ,name () (who-tmp)))) (defmacro who (pseudo-html-form) "An analog of DEF-WHO-PAGE, which not only creates an w-h-o pseudo-HTML to HTML translation function, but as well runs it and emits the obtained HTML as a string" `(macrolet ((who-tmp () `(with-html-output-to-string (,(gensym)) ,,pseudo-html-form))) (who-tmp))) And the example usage can be: (def-who-macro ps-script (&body body) `(:script :type "text/javascript" (fmt "~%// <![CDATA[~%") (str (js:ps ,@body)) (fmt "~%// ]]>~%"))) (def-who-page demo-page () `(:html (:head ,(:ps-script (defun hi () (alert "Hello world!")))) (:body (:input :type "button" :value "Click here...")))) The only catch is that DEF-WHO-MACRO actually generates not a macro in Lisp terms, but a function, which constructs lists of pseudo-HTML forms. I hope, the given code will be useful. Best regards, Vsevolod Dyomkin