[cl-who-devel] Macroexpansion of with-html-output body? (follow-up)

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

Have you looked at Parenscript's macro implementation? It seems more natural to use. It would be great to have this in mainline when it's clean.

If you mean process-html-forms (from lib/js-html as of 20071104 release), as afar as I understand, it's just a simplistic alternative to CL-WHO. While all the code examples in the manual are for Allegro's net.html.generator library (more info can be seen here: http://common-lisp.net/pipermail/parenscript-devel/2008-April/000180.html)... And, speaking about naturalness of use, that was exactly my starting point, when I tried to use macros with (as I call them for a lack of a better name) pseudo-html-forms inside w-h-o body just like it could be done for macros with ordinary forms inside of other lisp forms, and saw that it's not possible, because pseudo-html-forms inside w-h-o are not evaluated by the same rules as lisp forms. So I thought, that maybe a good idea would be to add another layer of special processing with the EMB keyword (http://common-lisp.net/pipermail/cl-who-devel/2008-June/000156.html), the same as STR, FMT etc. But keywords add complexity, because you should remember their usage rules. Once again it's not lispy enough, so to say. That's why I moved to the next idea. To conclude, I don't see a way to integrate fully implicit macroexpansion in with-html-output without a substantial refactoring of the library code. By the way, you can see one such attempt here: http://common-lisp.net/pipermail/cl-who-devel/2008-February/000127.html But, again, there arises a dilemma: should there be syntactic hints in the code, that a 'special' cl-who-macro is used. In this variant, there are none. In the variants, I've proposed, there is either EMB keyword or a comma. That's an open topic for discussion, which, I think, can be resolved by Edi Weitz, who will determine how to implement that himself. P.S. Btw, I think, the above link can as well be of interest in the weblocks group. On 7/29/08, Leslie P. Polzer <leslie.polzer@gmx.net> wrote:
Have you looked at Parenscript's macro implementation? It seems more natural to use.
It would be great to have this in mainline when it's clean.
_______________________________________________ cl-who-devel site list cl-who-devel@common-lisp.net http://common-lisp.net/mailman/listinfo/cl-who-devel
participants (2)
-
Leslie P. Polzer
-
Vsevolod