Search code examples
emacselisplexical-scope

Why isn't this form evaluated inside the lexical context of the let form


I am trying to make a macro that creates a function that takes S-expresions and evaluates them inside the lexical context of the fixture. Here is the macro I wrote:

(defmacro def-fixture (name bindings)
  "Return a function that takes the form to execute but is wrapped between a let of the bindings"
  `(defun ,(intern (symbol-name name)) (body)
     (let (,bindings)
       (unwind-protect
           (progn
             body)))))

But when I run it it appears to be executing outside the lexical context I provided

(def-fixture test-fixture '(zxvf 1))

(test-fixture '(= zxvf 1))
let: Symbol's value as variable is void: zxvf

Btw, I have enabled the variable lexical binding. Any ideas as to what is my mistake?


Solution

  • This has nothing to do with lexical scoping. Your macro call expands to:

    (defun test-fixture (body)
      (let ((quote (zxvf 1)))
        (unwind-protect (progn body))))
    

    Which is of course not what you intended. I do not believe that (test-fixture '(= zxvf 1)) signals the error you cite (i.e. variable is void). Instead, the call signals (void-function zxvf) because it tries to evaluate (zxvf 1). The (= zxvf 1) expression is never evaluated, since it's quoted.

    You might like to try something more like:

    (defmacro def-fixture (name bindings)
      "Return a macro that takes the form to execute but is wrapped between a let of the bindings"
      `(defmacro ,name (body)
         `(let (,',bindings)
            (unwind-protect
              (progn
                ,body)))))
    

    and then use it as in:

    (def-fixture test-fixture (zxvf 1))
    (test-fixture (= zxvf 1))