Skip to content


Subversion checkout URL

You can clone with
Download ZIP


declarations for with-html-output and with-html-output-to-string #9

merged 3 commits into from

2 participants


as per the documentation of these macros, they do take declarations. Before the patch they will be placed incorrectly.
The patch try to put them in a more appropriate places. where it puts them under with-output-to-string and let for with-html-output-to-string and with-html-output respectively.


There is a typo here (exctracted)

fixed. Thanks


Please no cl:do in ediware.

I'd changed it to use LOOP. But a side question: any problems with DO macro?


I'd like to see this in the upstream version, with two corrections in util.lisp. Can you supply them?

Adding a dependency on :alexandria and using alexandria:parse-body instead of extract-declarations would be acceptable.

I've made the changes and pushed them. I'd avoided adding :alexandria, since cl-who is still lean (no outside dependencies)


There is nothing wrong with DO except that it is hard to read, but of course, your directly translated loop is not that much easier to read. Sorry. I have proposed to use Alexandria because it has a function that does precisely what you want to do, and in the age of Quicklisp, there is no reason to not use other libraries.

Here is a loop that I'd like:

(defun extract-declarations (forms)
(loop with declarations
for forms on forms
for form = (first forms)
while (eql (first form) 'cl:declare)
do (push form declarations)
finally (return (values (nreverse declarations) forms))))

This works with the note that the last form in the following samples (although many are only for testing purposes - hypothetical) return as a second value (nil), rather than nil. which may case problem upon expansion while in macro.

(extract-declarations '((declare (special x)) (list 1 2 3 5)))
(extract-declarations '((declare (special x)) (declare (fixnum x)) (list 1 2 3 5)))
(extract-declarations '((declare (special x)) (list 1 2 3 5) (declare (fixnum x))))
(extract-declarations '((list 1 2 3 5) (declare (fixnum x))))
(extract-declarations '((declare (special x)) (list 1 2 3 5)))
(extract-declarations '((list 1 2 3 5)))
(extract-declarations '(()))

I'm fine with your implementation, even using Alexandria (although I do not support it). my goal is to get published declarations to work in cl-who macros.

one more side question: in my second variation using LOOP, which part was not clear? was it the termination part? the accumulation part? the stepping part? or all of them?

Kindly point to the one that works best with the long term goals of cl-who library. and I'll push them my fork.

I shall push your LOOP based implementation soon.

For the NIL thing. I meant that if any value of the the two values returned are nil, then this means that part (declarations or remaining forms) was not found.

@hanshuebner hanshuebner merged commit 48516b6 into edicl:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 27, 2012
  1. @fighting-spirit
Commits on May 1, 2012
  1. @fighting-spirit

    corrected a typo, and changed the implementation of extract declarati…

    fighting-spirit authored
    …ons from using cl:do to using cl:loop
  2. @fighting-spirit

    changed the implementation of extract-declarations as per Hans reques…

    fighting-spirit authored
    …t - to be more readable/easier to reason about.
This page is out of date. Refresh to see the latest.
Showing with 16 additions and 2 deletions.
  1. +10 −0 util.lisp
  2. +6 −2 who.lisp
10 util.lisp
@@ -228,3 +228,13 @@ determine whether CHAR must be escaped."
character set."
(escape-string string :test #'non-7bit-ascii-escape-char-p))
+(defun extract-declarations (forms)
+ "Given a FORM, the declarations - if any - will be extracted
+ from the head of the FORM, and will return two values the declarations,
+ and the remaining of FORM"
+ (loop with declarations
+ for forms on forms
+ for form = (first forms)
+ while (eql (first form) 'cl:declare)
+ do (push form declarations)
+ finally (return (values (nreverse declarations) forms))))
8 who.lisp
@@ -273,7 +273,9 @@ into Lisp code to write the corresponding HTML as strings to VAR -
which should either hold a stream or which'll be bound to STREAM if
(declare (ignore prologue))
+ (multiple-value-bind (declarations forms) (extract-declarations body)
`(let ((,var ,(or stream var)))
+ ,@declarations
(macrolet ((htm (&body body)
`(with-html-output (,',var nil :prologue nil :indent ,,indent)
@@ -287,7 +289,7 @@ supplied."
(with-unique-names (result)
`(let ((,result ,thing))
(when ,result (princ ,result ,',var))))))
- ,@(apply 'tree-to-commands body var rest))))
+ ,@(apply 'tree-to-commands forms var rest)))))
(defmacro with-html-output-to-string ((var &optional string-form
&key (element-type #-:lispworks ''character
@@ -297,11 +299,13 @@ supplied."
&body body)
"Transform the enclosed BODY consisting of HTML as s-expressions
into Lisp code which creates the corresponding HTML as a string."
+ (multiple-value-bind (declarations forms) (extract-declarations body)
`(with-output-to-string (,var ,string-form
#-(or :ecl :cmu :sbcl) :element-type
#-(or :ecl :cmu :sbcl) ,element-type)
+ ,@declarations
(with-html-output (,var nil :prologue ,prologue :indent ,indent)
- ,@body)))
+ ,@forms))))
;; stuff for Nikodemus Siivola's HYPERDOC
;; see <>
Something went wrong with that request. Please try again.