Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a DSL in Elisp

I want to create a DSL in Elisp looking something like this:

(install
 ;; do install
 )

(uninstall
 ;; do uninstall
 )

However, since Elisp have a global namespace, this is not a good idea. And prefixing the functions like this, is so darn ugly.

(package-install
 ;; do install
 )

(package-uninstall
 ;; do uninstall
 )

So I thought as a compromise all commands could be wrapped in a commands call like this:

(commands
 (install
  ;; do install
  )

 (uninstall
  ;; do uninstall
  )

 ;; ...
 )

But since I don't want install and uninstall in the global namespace, I somehow have to in the commands macro, replace all occurrences of the commands with maybe for example the prefix names, like this:

(defmacro commands (&rest body)
  (mapcar
   (lambda (exp)
     (setcar exp (intern (concat "package-" (symbol-name (car exp)))))
     (setcdr exp (list (cons 'progn (cdr exp)))))
   body)
  `(progn ,@body))

(commands
 (install
  ;; do install
  )

 (uninstall
  ;; do uninstall
  )

 ;; ...
 )

This seems like such a hack. Plus it will not work if there are any nested commands.

Is there any good solution for this or is hack the way to go?

Thanks!

like image 387
rejeep Avatar asked Jan 10 '11 18:01

rejeep


1 Answers

How about locally defining install and friends? This won't hide standard functions, but it doesn't look like that's what you're really after.

(defmacro commands (&rest body)
  `(flet ((install (&rest args) (apply 'package-install args))
          (uninstall (&rest args) (apply 'package-uninstall args)))
     ,@body))

Of course you'd want to generate that list of flet arguments automatically. You do need a list of your package's elements somewhere, possibly using (feature-symbols 'package).

like image 165
Gilles 'SO- stop being evil' Avatar answered Sep 28 '22 07:09

Gilles 'SO- stop being evil'