Ken Tilton <kentilton@gmail.com> wrote:
+---------------
| Rob Warnock wrote:
| > But... but... it's the &BODY argument of a *macro*. Macro arguments
| > *aren't* evaluated!
|
| Of course not. I was speaking loosely. The question is simply "Can i use
| (intern "HTML" :keyword) instead of :html?"
+---------------
The answer, at least for CL-WHO, HTOUT, AllegroServe's HTML, and
maybe some others, is "No". [At least, not without reaching *deep*
under the covers and playing with the internals of the implementation.]
+---------------
| Here, try this:
| Does cl-who expand into code such that a given argument gets evaluated,
| or does it quote that argument in the expansion?
+---------------
Neither, really, or a mixture of both, depending on your viewpoint.
CL-WHO is a *compiler* from "HTML-designating forms" into "HTML-emitting
Common Lisp code". That is, the &BODY argument of WITH-HTML-OUTPUT
expands into pure "inline" Lisp code, primarily WRITE-STRINGs with
constant [well, computed at macroexpansion time] strings as arguments.
A form such as (:FOO "some text") gets compiled into:
(write-string "<foo>some text</foo>")
while ((:FOO :ATTR1 "val1" :ATTR2 "val2") "some more text") gets
compiled into:
(write-string "<foo attr1='val1' attr2='val2'>some more text</foo>")
and (:FOO subforms... ) gets compiled into:
(progn (write-string "<foo>")
,@(translation-of subforms...)
(write-string "</foo>"))
Moreover, CL-WHO tries very hard to aggregate all adjacent output
constant strings into as few strings as possible, e.g.:
> (macroexpand
'(cl-who:with-html-output (*standard-output* nil :prologue nil)
(:html (:head (:title "A small test page"))
(:body (:h1 "Test Page")
"This is only a test."))))
(LET ((*STANDARD-OUTPUT* *STANDARD-OUTPUT*))
(PROGN
NIL
(WRITE-STRING
"<html><head><title>A small test page</title></head><body><h1>Test Page</h1>This is only a test.</body></html>"
*STANDARD-OUTPUT*)))
T
>
See? The *entire* "keyword tree" is gone, replaced by a single
constant string.
Obviously, when one allows Lisp code into the template, the same
degree of collapsing can't be done, but it tries as best it can:
> (macroexpand
'(cl-who:with-html-output (*standard-output* nil :prologue nil)
(:html
(:head (:title "A small test page"))
(:body (:h1 "Test Page")
(loop for i from 1 to 5 do
(htm "This is test line #" (fmt "~d" i) (:br)))
"And this is more text after the LOOP."))))
(LET ((*STANDARD-OUTPUT* *STANDARD-OUTPUT*))
(PROGN
NIL
(WRITE-STRING
"<html><head><title>A small test page</title></head><body><h1>Test Page</h1>"
*STANDARD-OUTPUT*)
(LOOP FOR I FROM 1 TO 5 DO
(PROGN
(WRITE-STRING "This is test line #" *STANDARD-OUTPUT*)
(FORMAT *STANDARD-OUTPUT* "~d" I)
(WRITE-STRING "<br />" *STANDARD-OUTPUT*)))
(WRITE-STRING "And this is more text after the LOOP.</body></html>"
*STANDARD-OUTPUT*)))
T
>
Does this clarify the issue somewhat? [If so, feel free to stop here.]
If not, I'll elaborate an example from my previous reply:
> (macroexpand
'(cl-who:with-html-output (*standard-output* nil :prologue nil)
(:html
(:head (:title "A small test page"))
(:body
(:h1 "Test Page")
(:foo "A FOO with " (:bar "a sample BAR") " in it")))))
(LET ((*STANDARD-OUTPUT* *STANDARD-OUTPUT*))
(PROGN
NIL
(WRITE-STRING
"<html><head><title>A small test page</title></head><body><h1>Test Page</h1><foo>A FOO with <bar>a sample BAR</bar> in it</foo></body></html>"
*STANDARD-OUTPUT*)))
T
>
O.k.? Nothing special about ":FOO", it's just another keyword that
gets transformed into matching starting & ending tag strings.
But when you replace it with a *non*-keyword, then CL-WHO correctly
just passes it through [as it is documented to], on the assumption
that it is Lisp code that you want to execute:
> (macroexpand
'(cl-who:with-html-output (*standard-output* nil :prologue nil)
(:html
(:head (:title "A small test page"))
(:body
(:h1 "Test Page")
((intern "FOO" :keyword)
"A FOO with " (:bar "a sample BAR") " in it")))))
(LET ((*STANDARD-OUTPUT* *STANDARD-OUTPUT*))
(PROGN
NIL
(WRITE-STRING
"<html><head><title>A small test page</title></head><body><h1>Test Page</h1>"
*STANDARD-OUTPUT*)
((INTERN "FOO" :KEYWORD) "A FOO with " (:BAR "a sample BAR") " in it")
(WRITE-STRING "</body></html>" *STANDARD-OUTPUT*)))
T
>
Now ask yourself what's going to happen when the CL system tries
to evaluate that ((INTERN "FOO" :KEYWORD) "A FOO with " ...) form.
*Ka-BLOOEY!* [CMUCL calls it "Error: Illegal function call."]
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607