Common Lisp Macro to T-Sql Experiment

So just another jump into the unknown, I wondered great wonders about creating a macro in Common Lisp that would just print out what I type between the () into T-Sql. Essentially, I want to type this:

(select user.name age)

And get:

"SELECT user.name, age"

Now there are probably a billion (or slightly less) examples of using keywords like:

(select 'user.name...

or:

(select :user name)

Or whatever.  Not good enough for me. I am more demanding.

So the first stab was something simple;  Just take an arbitrarily (I actually spelled that correctly the first time) long list of names, and create a string from it. And here it was:

(defmacro select (&rest args)
  `(mapcar #'write-to-string (list ,@args)))

Basically, take the parameter “args”, strip the () surrounding it, create a new list, and create a string from every member. A quick macroexpand show the outcome:

(macroexpand-1 '(select 'test 'me)) 
  -> (MAPCAR #'WRITE-TO-STRING (LIST 'TEST 'ME)) 
    -> ("TEST" "ME")

As shown, that is just a list of “test” and “me”. Doesn’t make the cut, mostly because I had to use “APOSTROPHEtest” instead of just “test”. Oh and there’s no string. Time to take care of that:

(defmacro select (&rest args)
  `(concatenate 'string  ,@(mapcar #'write-to-string args)))

So now it should take the list of strings ‘(“TEST” “ME”)’, and make it a nice string. DOES IT?!?!?

(macroexpand-1 '(select 'test 'me))
  -> (CONCATENATE 'STRING "'TEST" "'ME")
    -> OOPS

Go figure, it left the APOSTROPHE on the words. Actually, this is good sign. It means I don need to prefix the names with an APOSTROPHE  anymore. Next attempt:

(macroexpand-1 '(select test me))
  -> (CONCATENATE 'STRING "TEST" "ME")
    -> "TESTME"

Now it’s getting there. Only thing is: There needs to be a separation added. Duh, right? Might as well throw in the “SELECT” part too.

(defmacro select (&rest args)
  `(concatenate 'string "SELECT "
     ,@(mapcar #'(lambda (z) (concatenate 'string (write-to-string z) ", ")) args)))

Big change here was adding the “, ” to the converted keywords, then take the newly created partial string and make one long string.

(macroexpand-1 '(select user.name age))
  -> (CONCATENATE 'STRING "SELECT " "USER.NAME, " "AGE, ")
    -> "SELECT USER.NAME, AGE, "

And there it is. Can’t get much better than that.

One thought on “Common Lisp Macro to T-Sql Experiment”

  1. why not just
    “`
    (defmacro select (&rest args)
    (format nil “SELECT ~{~a~^, ~}” args))
    “`
    and if you want the case of the names being preserved you can also `(setf (readtable-case *readtable*) :preserve)`

    but this macro is stupid anyway

Comments are closed.