Re: macro that writes macros



Sacha <none@xxxxxxxxxxxx> writes:

jordi.burguet.castell@xxxxxxxxx wrote:
(defmacro new-tag (name)
(let ((sname (string-downcase (symbol-name name))))
`(defmacro ,name (&rest content)
`(progn
(format t "<~a>~%" ,',sname)
,@content
(format t "</~a>~%" ,',sname)))))


This is the occasion for me to ask how to get rid of these ','symbol
things. While in this case it's pretty obvious how they work, it
sometimes make the code pretty hard to read and understand. I recently
came up with a very subtle bug (for me anyways) using such syntax.

So what are you guys usually doing to avoid these ? Do you avoid these
at all ?

Don't use backquote.


(defmacro new-tag (name)
(let ((sname (string-downcase (symbol-name name))))
(list 'defmacro name '(&rest content)
(list 'append
(list 'list (list 'quote 'progn)
(list 'list (list 'quote 'format) (list 'quote 't) (list 'quote '"<~a>~%")
(list 'list (list 'quote 'quote) sname)))
'content
(list 'list
(list 'list (list 'quote 'format) (list 'quote 't) (list 'quote '"</~a>~%")
(list 'list (list 'quote 'quote) sname)))))))


C/USER[67]> (macroexpand-1 '(new-tag div))
(DEFMACRO DIV (&REST CONTENT)
(APPEND (LIST 'PROGN (LIST 'FORMAT 'T '"<~a>~%" (LIST 'QUOTE #1="div"))) CONTENT
(LIST (LIST 'FORMAT 'T '"</~a>~%" (LIST 'QUOTE #1#))))) ;
T


Note that to build these list expressions, this function may be handy:

(defun kind-of-list (list)
(labels ((kol (current slow)
(cond ((null current) :proper)
((atom current) :dotted)
((null (cdr current)) :proper)
((atom (cdr current)) :dotted)
((eq current slow) :circular)
(t (kol (cdr (cdr current)) (cdr slow))))))
(if (null list)
:empty
(kol list (cons nil list)))))

(defmacro dotted-do ((var expression &optional result-form) &body body)
(let ((current (gensym "current-")))
`(do* ((,current ,expression (when (consp ,current) (cdr ,current)))
(,var #1=(if (consp ,current) (car ,current) ,current) #1#))
((null ,current) ,result-form)
,@body)))

(defun meta-form (form free-variables)
;; FORM must not be a circular structure.
(if (null free-variables)
(list 'quote form)
(cond ((symbolp form) (if (member form free-variables)
form
(list 'quote form)))
((atom form) (list 'quote form))
(t (let ((kind (kind-of-list form)))
(ecase kind
(:circular (error "Cannot handle circular lists"))
(:empty 'nil)
((:proper :dotted)
(cons (if (eq :proper kind) 'list 'list*)
(let ((result '()))
(dotted-do (subform form (nreverse result))
(push (meta-form subform free-variables)
result)))))))))))



C/USER[68]> (meta-form '(append
(list 'progn
(list 'format 't '"<~a>~%" (list 'quote sname)))
content
(list (list 'format 't '"</~a>~%" (list 'quote sname))))
'(sname))
(LIST 'APPEND
(LIST 'LIST (LIST 'QUOTE 'PROGN)
(LIST 'LIST (LIST 'QUOTE 'FORMAT) (LIST 'QUOTE 'T) (LIST 'QUOTE '"<~a>~%")
(LIST 'LIST (LIST 'QUOTE 'QUOTE) SNAME)))
'CONTENT
(LIST 'LIST
(LIST 'LIST (LIST 'QUOTE 'FORMAT) (LIST 'QUOTE 'T) (LIST 'QUOTE '"</~a>~%")
(LIST 'LIST (LIST 'QUOTE 'QUOTE) SNAME))))


But honestly, this is less readable than embedded backquotes.
You only have to remember that the coma refer to the closest enclosing backquote.

--
__Pascal Bourguignon__ http://www.informatimago.com/

Nobody can fix the economy. Nobody can be trusted with their finger
on the button. Nobody's perfect. VOTE FOR NOBODY.
.


Quantcast