Search code examples
emacselisp

"cl-labels with dynamic scoping is not implemented"


I'm trying to use cl-labels in an Emacs package I'm writing. A user has filed a bug report with a problem that I'm not observing in my own Emacs at version 24.3.1, but this user is on 24.3.2.

https://github.com/d11wtq/fiplr/issues/3

`cl-labels' with dynamic scoping is not implemented

I'm using cl-labels here: https://github.com/d11wtq/fiplr/blob/f368e84410d2ee57117b2d6501c0cf42359bc252/fiplr.el#L154-L177

;; Builds a gigantic `find' shell command with -prune, -o, -not and shit.
(defun fiplr-list-files-shell-command (type path ignored-globs)
  "Builds the `find' command to locate all project files & directories."
  "Path is the base directory to recurse from."
  "Ignored-globs is an alist with keys 'directories and 'files."
  (cl-labels ((type-abbrev (assoc-type)
                (cl-case assoc-type
                  ('directories "d")
                  ('files "f")))
              (name-matcher (glob)
                (mapconcat 'identity
                           `("-name" ,(shell-quote-argument glob))
                           " "))
              (grouped-name-matchers (type)
                (mapconcat 'identity
                           `(,(shell-quote-argument "(")
                             ,(mapconcat #'name-matcher
                                      (cadr (assoc type ignored-globs))
                                      " -o ")
                             ,(shell-quote-argument ")"))
                           " "))
              (matcher (assoc-type)
                (mapconcat 'identity
                           `(,(shell-quote-argument "(")
                             "-type"
                             ,(type-abbrev assoc-type)
                             ,(grouped-name-matchers assoc-type)
                             ,(shell-quote-argument ")"))
                           " ")))
    (mapconcat 'identity
               `("find"
                 ,(shell-quote-argument (directory-file-name path))
                 ,(matcher 'directories)
                 "-prune"
                 "-o"
                 "-not"
                 ,(matcher 'files)
                 "-type"
                 ,(type-abbrev type)
                 "-print")
               " ")))

Now, the only reason I'm using cl-labels is to allow some private internal functions to be used, and each of those functions depends on others one declared in the cl-labels definition.

I don't need dynamic scoping neither. Is there a macro the gives me what I want, or should I just switch to longer named global functions? (which does kind of suck given how irrelevant these functions are to other parts of the code)

Basically I need something like letrec from Scheme, or labels from Common Lisp.

EDIT | I ended up just using a liberal combination of (lambda () .. ), (funcall ...) and (let* ...). Would love to know if there's a more elegant solution that actually works in Emacs Lisp.


Solution

  • Your code looks perfectly fine. And there's no error like the one you cite in Emacs's own source code, so the error is signaled by some external package. Finally There's no "24.3.1" or "24.3.2" release. There's only a "24.3" release, and the additional ".1" or ".2" is just a build number, so your bug-reporter is using the same version of Emacs as you. He probably happens to be using a package that has a bug.