【问题标题】:How to create a DSL in Elisp如何在 Elisp 中创建 DSL
【发布时间】:2011-01-10 18:45:44
【问题描述】:

我想在 Elisp 中创建一个如下所示的 DSL:

(install
 ;; do install
 )

(uninstall
 ;; do uninstall
 )

但是,由于 Elisp 有一个全局命名空间,这不是一个好主意。而且给这样的函数加上前缀,实在是太丑了。

(package-install
 ;; do install
 )

(package-uninstall
 ;; do uninstall
 )

所以我认为作为一种折衷方案,所有命令都可以包装在这样的命令调用中:

(commands
 (install
  ;; do install
  )

 (uninstall
  ;; do uninstall
  )

 ;; ...
 )

但由于我不想在全局命名空间中 installuninstall,我不知何故必须在命令宏中,将所有出现的命令替换为可能例如前缀名称,如下所示:

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

 ;; ...
 )

这似乎是一个 hack。另外,如果有任何嵌套命令,它将不起作用。

有什么好的解决方案或者破解方法吗?

谢谢!

【问题讨论】:

  • YASnipper 在它们的函数前面加上yas/,所以你得到yas/expand等等。我一点也不觉得那是丑陋的。我采用了我写的 tfs 集成的约定,所以有tfs/checkouttfs/add 等等。在没有正式支持的情况下,这似乎是一种既便宜又简单的名称范围界定方法。
  • 只是一个风格注释:我不会像在 command 宏的定义中那样使用 setcar/setcdr。创建一个新的cons(这甚至可以使代码更干净)。你不知道,如果你的宏扩展器以破坏性的方式任意修改原始代码树,它可能会产生什么影响。

标签: emacs macros elisp


【解决方案1】:

本地定义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)

【讨论】:

  • 这正是我要找的!非常感谢!
猜你喜欢
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多