ruricolist/spinneret

Avoid defining macros on keywords

Yehouda opened this issue · 4 comments

(defmacro ,name (&body ,tmp-body)

The macro DEFTAG defines a macro on name, which can be a keyword. Keywords should not used for global names (macros, functions, property names) because of the potential for clashes. See in ANSI CL:
http://www.lispworks.com/documentation/lw50/CLHS/Body/11_abcb.htm

In fact, currently live-deftag-form? has a comment suggesting that this is already an issue.

LispWorks by default gives an error of this, and the test fails because of that.

Since the tag is not really a proper Lisp macro anyway, it should be easy to fix this. Inside DEFTAG add a gensym internal-name, put it in the porperty deftag and define a function with this name:

(eval-always
           (setf (get ',name 'deftag) ',internal-name))
         (defun ,internal-name (,tmp-body)

Then replace live-deftag-form? by something like expand-deftag-form which check if (get (car form) 'deftag) returns non-nil, if it does call it with (cdr form) and return the result. Use expand-deftag-form inside parse-html and when it returns non-nil just use the result as the new form.

The downside here would be that it would no longer be possible to use deftag-generated macros outside of with-html forms, which is currently the case. This might break existing code.

The most sensible behavior might be to have different expansions based on the name: define a macro for a non-keyword symbol, but for a keyword do something like the above.

@aartaka, you brought up using keywords in deftags in #84. Do you use them outside with-html forms?

I would tend to have to have two definers if they define different things, but that would also break user code.

Switching on whether the name is a keyword or not would work. It is somewhat odd interface, but still better than defining macros on keywords.