2011-01-10 56 views
6

创建DSL我想创建一个elisp的DSL看起来像这样:如何elisp的

(install 
;; do install 
) 

(uninstall 
;; do uninstall 
) 

然而,由于elisp的有一个全局命名空间,这不是一个好主意。像这样的功能前缀,是如此丑陋。

(package-install 
;; do install 
) 

(package-uninstall 
;; do uninstall 
) 

所以我想作为一种折中的所有命令可以被包裹在一个命令调用是这样的:

(commands 
(install 
    ;; do install 
) 

(uninstall 
    ;; do uninstall 
) 

;; ... 
) 

但因为我不想安装卸载在全局命名空间,我不知何故必须在命令宏中,用例如前缀名称替换所有出现的命令,如下所示:

(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 
) 

;; ... 
) 

这似乎是这样的黑客攻击。另外,如果有嵌套命令,它将不起作用。

有没有什么好的解决方案,或者是黑客的路要走?

谢谢!

+0

YASnipper用`yas /`前缀他们的函数,所以你得到`yas/expand`等等。我根本不认为这很丑陋。我采用了我写的tfs集成的约定,所以有`tfs/checkout`,`tfs/add`等等。在没有正式支持的情况下,这似乎是一种简单易行的名称范围界定方法。 – Cheeso 2011-01-10 20:50:47

+0

只是一个文体注释:我不会像在`command`宏的定义中那样使用`setcar` /`setcdr`。创建一个新的`cons`(甚至可以使代码更清洁)。如果宏扩展器以破坏性方式任意修改原始代码树,您不知道它会产生什么效果。 – Dirk 2011-01-10 21:02:36

回答

8

如何在本地定义install和朋友?这不会隐藏标准函数,但它看起来并不像你真的那样。

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

当然,您想要自动生成flet参数列表。您确实需要某个地方的软件包元素列表,可能使用(feature-symbols 'package)