help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Simple macro question


From: Ergus
Subject: Re: Simple macro question
Date: Mon, 3 May 2021 13:32:56 +0200

Hi Stefan:

Thanks for the reply.

IIUC then this code:

====================

;;; test.el --- test editing -*- lexical-binding: t; -*-

;;; Commentary:

;;; Code:

(defun test-fun (com)
  "Testfun with COM."
  nil)

(defmacro test-def (thelist)
  "Doc def."
  `(progn ,@(mapcar #'test-fun thelist)))

(test-def (A B C))

(provide 'test)
;;; test ends here

============================

Will require to put the test-fun inside an `eval-and-compile` too?
Because I am getting a similar error, this time test-fun is not defined.

I tried to use eval-and-compile in this case but the problem is that in
my real code test-fun calls another function (a minor mode) that needs
to be defined later (in the same file); and I get an error in that case
too that the minor-mode-function is not defined.

What's the canonical way to do that? use declare function? some trick
with the quoting? Put also the minor mode inside an eval-and-compile?

In case you are interested into why I came into this issues, here is the
code:

https://github.com/Ergus/composable.el/blob/master/composable.el

In the future I want to implement another version using the new
`repeat-mode` api, that will be cleaner, but at the moment it does not
makes sense as there is not any emacs release with the repeat api yet.

Thanks in advance,
Ergus


On Sun, May 02, 2021 at 09:46:30PM -0400, Stefan Monnier wrote:
(defvar test-commands-list '(A B C)
  "List of replaced functions.")
(defmacro test-def ()
  "Doc def."
  `(eval-and-compile ,@(mapcar (lambda (com) nil) test-commands-list)))
(test-def)

[...]

Symbol’s value as variable is void: test-commands-list

macro-expansion takes place during compilation.  During compilation, the
code is mostly translated, not evaluated, but macros are expanded.
So your `(test-def)` macro call is expanded which evaluates the code
inside `test-def` whereas the `(defvar ...)` code is not evaluated (it's
only translated into byte-code) and hence the var is not defined: it
will only be defined much later when the resulting byte-code is run.

One way to work around it is to place the `defvar` within an
`eval-and-compile`.

(defmacro test-def (commands-list)
...

(test-def test-commands-list)

In this second case I get: wrong arguments sequencep test-commands-list
Is this intended?

Yes: the argument to macros are the actual sexp written in the macro
call, not the result of their evaluation.  So your argument
`commands-list` will hold the symbol `test-commands-list` rather than
the list you were hoping to get.  You could use `symbol-value` to get
the content of that symbol as a variable, but then you'd be back to the
previous problem because the `defvar` has not been evaluated yet.


       Stefan




reply via email to

[Prev in Thread] Current Thread [Next in Thread]