* Concern around use of eval
@ 2015-03-19 6:53 Les Harris
2015-03-19 8:00 ` Tassilo Horn
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: Les Harris @ 2015-03-19 6:53 UTC (permalink / raw)
To: help-gnu-emacs
I have a situation where I want to generate a bunch of nearly identical
predicate functions. Previously I had just manually defined these things
one by one but was never happy with such an obvious inefficiency (or
maintaining it). Tonight I decided I'd fix this and whacked them and
implemented a way of doing it where I can iterate over a list containing
labels and define these predicate functions using those labels:
,----
| (defvar lh/labels '("label1" "label2" "label3"))
|
| (defmacro lh/gen-predicate (label)
| `(defun ,(intern (concat "lh/" label "-p")) ()
| (member ,label *lh/system-label-store*)))
|
| (defun lh/define-predicates ()
| (dolist (label lh/labels)
| (eval `(lh/gen-predicate ,label))))
| (lh/define-predicates)
`----
Now this all works fine and I get my auto-generated predicates, so
success. My question/concern/niggle is around the use of (eval) in
lh/define-predicates. If I don't put eval in there then the defun the
macro evaluates into never gets evaluated itself. Stylistically, is
there a better way to do this or am I just being weird about (eval) and
should just get over it?
--
Do they only stand
By ignorance, is that their happy state,
The proof of their obedience and their faith?
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: Concern around use of eval
2015-03-19 6:53 Concern around use of eval Les Harris
@ 2015-03-19 8:00 ` Tassilo Horn
[not found] ` <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>
2015-03-19 14:07 ` Stefan Monnier
2 siblings, 0 replies; 14+ messages in thread
From: Tassilo Horn @ 2015-03-19 8:00 UTC (permalink / raw)
To: Les Harris; +Cc: help-gnu-emacs
Les Harris <les@lesharris.com> writes:
Hi Les,
> ,----
> | (defvar lh/labels '("label1" "label2" "label3"))
> |
> | (defmacro lh/gen-predicate (label)
> | `(defun ,(intern (concat "lh/" label "-p")) ()
> | (member ,label *lh/system-label-store*)))
> |
> | (defun lh/define-predicates ()
> | (dolist (label lh/labels)
> | (eval `(lh/gen-predicate ,label))))
> | (lh/define-predicates)
> `----
>
> Now this all works fine and I get my auto-generated predicates, so
> success. My question/concern/niggle is around the use of (eval) in
> lh/define-predicates. If I don't put eval in there then the defun the
> macro evaluates into never gets evaluated itself. Stylistically, is
> there a better way to do this or am I just being weird about (eval) and
> should just get over it?
Well, in case the `lh/label' value is available at compile-time then
`lh/define-predicates' can also be a macro and you can go like this:
--8<---------------cut here---------------start------------->8---
(defvar lh/labels '("label1" "label2" "label3"))
(defmacro lh/gen-predicate (label)
`(defun ,(intern (concat "lh/" label "-p")) ()
(member ,label *lh/system-label-store*)))
(defmacro lh/define-predicates ()
`(progn
,@(mapcar (lambda (label)
`(lh/gen-predicate ,label))
lh/labels)))
(lh/define-predicates)
--8<---------------cut here---------------end--------------->8---
But if you know your labels only at runtime, then I think there's no way
around using `eval'.
Bye,
Tassilo
^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>]
* Re: Concern around use of eval
[not found] ` <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>
@ 2015-03-19 8:12 ` Joost Kremers
2015-03-19 8:31 ` Tassilo Horn
[not found] ` <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>
0 siblings, 2 replies; 14+ messages in thread
From: Joost Kremers @ 2015-03-19 8:12 UTC (permalink / raw)
To: help-gnu-emacs
Tassilo Horn wrote:
> Well, in case the `lh/label' value is available at compile-time then
> `lh/define-predicates' can also be a macro and you can go like this:
>
> --8<---------------cut here---------------start------------->8---
> (defvar lh/labels '("label1" "label2" "label3"))
>
> (defmacro lh/gen-predicate (label)
> `(defun ,(intern (concat "lh/" label "-p")) ()
> (member ,label *lh/system-label-store*)))
>
> (defmacro lh/define-predicates ()
> `(progn
> ,@(mapcar (lambda (label)
> `(lh/gen-predicate ,label))
> lh/labels)))
>
> (lh/define-predicates)
> --8<---------------cut here---------------end--------------->8---
Why not do it at the top level directly? E.g.:
,----
| (defvar lh/labels '("label1" "label2" "label3"))
|
| (defmacro lh/gen-predicate (label)
| `(defun ,(intern (concat "lh/" label "-p")) ()
| (member ,label *lh/system-label-store*)))
|
| (mapc (lambda (label)
| (lh/gen-predicate label))
| lh/labels)
`----
--
Joost Kremers joostkremers@fastmail.fm
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: Concern around use of eval
2015-03-19 8:12 ` Joost Kremers
@ 2015-03-19 8:31 ` Tassilo Horn
[not found] ` <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>
1 sibling, 0 replies; 14+ messages in thread
From: Tassilo Horn @ 2015-03-19 8:31 UTC (permalink / raw)
To: help-gnu-emacs
Joost Kremers <joost.m.kremers@gmail.com> writes:
> Why not do it at the top level directly? E.g.:
>
> ,----
> | (defvar lh/labels '("label1" "label2" "label3"))
> |
> | (defmacro lh/gen-predicate (label)
> | `(defun ,(intern (concat "lh/" label "-p")) ()
> | (member ,label *lh/system-label-store*)))
> |
> | (mapc (lambda (label)
> | (lh/gen-predicate label))
> | lh/labels)
> `----
That won't work because. When reading the mapc form, emacs sees that
`lh/gen-predicate' is a macro and tries to expand it with the symbol
label as argument. The macroexpansion takes place before the actual
execution of the code.
Bye,
Tassilo
^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>]
* Re: Concern around use of eval
[not found] ` <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>
@ 2015-03-20 19:54 ` Joost Kremers
0 siblings, 0 replies; 14+ messages in thread
From: Joost Kremers @ 2015-03-20 19:54 UTC (permalink / raw)
To: help-gnu-emacs
Tassilo Horn wrote:
> Joost Kremers <joost.m.kremers@gmail.com> writes:
>
>> Why not do it at the top level directly? E.g.:
>>
>> ,----
>> | (defvar lh/labels '("label1" "label2" "label3"))
>> |
>> | (defmacro lh/gen-predicate (label)
>> | `(defun ,(intern (concat "lh/" label "-p")) ()
>> | (member ,label *lh/system-label-store*)))
>> |
>> | (mapc (lambda (label)
>> | (lh/gen-predicate label))
>> | lh/labels)
>> `----
>
> That won't work because. When reading the mapc form, emacs sees that
> `lh/gen-predicate' is a macro and tries to expand it with the symbol
> label as argument. The macroexpansion takes place before the actual
> execution of the code.
Thanks, that explains a few things.
--
Joost Kremers joostkremers@fastmail.fm
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: Concern around use of eval
2015-03-19 6:53 Concern around use of eval Les Harris
2015-03-19 8:00 ` Tassilo Horn
[not found] ` <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>
@ 2015-03-19 14:07 ` Stefan Monnier
2015-03-20 15:17 ` Thierry Volpiatto
2 siblings, 1 reply; 14+ messages in thread
From: Stefan Monnier @ 2015-03-19 14:07 UTC (permalink / raw)
To: help-gnu-emacs
> | (defvar lh/labels '("label1" "label2" "label3"))
> |
> | (defmacro lh/gen-predicate (label)
> | `(defun ,(intern (concat "lh/" label "-p")) ()
> | (member ,label *lh/system-label-store*)))
> |
> | (defun lh/define-predicates ()
> | (dolist (label lh/labels)
> | (eval `(lh/gen-predicate ,label))))
> | (lh/define-predicates)
; -*- lexical-binding:t -*-
(defvar lh/labels '("label1" "label2" "label3"))
(defun lh/gen-predicate (label)
(defalias (intern (concat "lh/" label "-p"))
(lambda () (member label *lh/system-label-store*))))
(defun lh/define-predicates ()
(mapc #'lh/gen-predicate lh/labels))
(lh/define-predicates)
> Stylistically, is there a better way to do this or am I just being
> weird about (eval) and should just get over it?
You're not weird about `eval'. It's kind of like self-modifying code:
there are cases where you *really* need it, but they're extremely rare
and every time you use it when it's not *really* indispensable,
kittens die.
Stefan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: Concern around use of eval
2015-03-19 14:07 ` Stefan Monnier
@ 2015-03-20 15:17 ` Thierry Volpiatto
2015-03-20 17:19 ` Bug in Elisp font-locking (was: Concern around use of eval) Tassilo Horn
0 siblings, 1 reply; 14+ messages in thread
From: Thierry Volpiatto @ 2015-03-20 15:17 UTC (permalink / raw)
To: help-gnu-emacs
Stefan Monnier <monnier@iro.umontreal.ca> writes:
> (defun lh/gen-predicate (label)
> (defalias (intern (concat "lh/" label "-p"))
^^^^^^
In this case intern should not be highlighted, isn't it ?.
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
^ permalink raw reply [flat|nested] 14+ messages in thread
* Bug in Elisp font-locking (was: Concern around use of eval)
2015-03-20 15:17 ` Thierry Volpiatto
@ 2015-03-20 17:19 ` Tassilo Horn
2015-03-20 17:31 ` Bug in Elisp font-locking Stefan Monnier
0 siblings, 1 reply; 14+ messages in thread
From: Tassilo Horn @ 2015-03-20 17:19 UTC (permalink / raw)
To: Thierry Volpiatto; +Cc: help-gnu-emacs, emacs-devel
Thierry Volpiatto <thierry.volpiatto@gmail.com> writes:
>> (defun lh/gen-predicate (label)
>> (defalias (intern (concat "lh/" label "-p"))
> ^^^^^^
> In this case intern should not be highlighted, isn't it ?.
Indeed, it shouldn't be. But the font-lock entry for definitions which
applies the function name face here matches next to `defun', `defmacro',
or `defalias' also `cl-defstruct', and that may have the two forms
(defstruct struct-name ...)
(defstruct (struct-name OPTIONS) ...)
and therefore, the regexp simply skips the paren. The following patch
should fix that.
Cc-ing emacs-devel to ask if that's ok to commit. Is it? Or too much
hassle for just `defalias'? (I think that's the only definition form
which is implemented as a function where the name may be provided by a
funcall.)
--8<---------------cut here---------------start------------->8---
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index 6b30773..614fbc6 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -320,14 +320,18 @@
`( ;; Definitions.
(,(concat "(" el-defs-re "\\_>"
;; Any whitespace and defined object.
- "[ \t'\(]*"
- "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
+ "[ \t']*"
+ ;; With defstruct, the name may follow a paren,
+ ;; e.g. (defstruct (foo-struct opts)...).
+ "\\(([ \t']*\\)?\\(\\(?:\\sw\\|\\s_\\)+\\)?")
(1 font-lock-keyword-face)
- (2 (let ((type (get (intern-soft (match-string 1)) 'lisp-define-type)))
- (cond ((eq type 'var) font-lock-variable-name-face)
- ((eq type 'type) font-lock-type-face)
- (t font-lock-function-name-face)))
- nil t))
+ (3 (let ((type (get (intern-soft (match-string 1)) 'lisp-define-type)))
+ (cond ((eq type 'var) font-lock-variable-name-face)
+ ((eq type 'type) font-lock-type-face)
+ ;; If match-string 2 is non-nil, we encountered a
+ ;; form like (defalias (intern (concat s "-p"))).
+ ((not (match-string 2)) font-lock-function-name-face)))
+ nil t))
;; Emacs Lisp autoload cookies. Supports the slightly different
;; forms used by mh-e, calendar, etc.
("^;;;###\\([-a-z]*autoload\\)" 1 font-lock-warning-face prepend))
--8<---------------cut here---------------end--------------->8---
Bye,
Tassilo
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: Bug in Elisp font-locking
2015-03-20 17:19 ` Bug in Elisp font-locking (was: Concern around use of eval) Tassilo Horn
@ 2015-03-20 17:31 ` Stefan Monnier
2015-03-20 17:43 ` Drew Adams
2015-03-20 18:47 ` Tassilo Horn
0 siblings, 2 replies; 14+ messages in thread
From: Stefan Monnier @ 2015-03-20 17:31 UTC (permalink / raw)
To: emacs-devel; +Cc: help-gnu-emacs
> Thierry Volpiatto <thierry.volpiatto@gmail.com> writes:
>>> (defun lh/gen-predicate (label)
>>> (defalias (intern (concat "lh/" label "-p"))
>> ^^^^^^
>> In this case intern should not be highlighted, isn't it ?.
Indeed.
> (defstruct struct-name ...)
> (defstruct (struct-name OPTIONS) ...)
Also for defun in Common-Lisp, there's (defun (setf foo) ...) where the
"setf" probably shouldn't be highlighted but the "foo" should.
> Cc-ing emacs-devel to ask if that's ok to commit.
Could explain what the patch does?
Stefan
^ permalink raw reply [flat|nested] 14+ messages in thread
* RE: Bug in Elisp font-locking
2015-03-20 17:31 ` Bug in Elisp font-locking Stefan Monnier
@ 2015-03-20 17:43 ` Drew Adams
2015-03-20 18:47 ` Tassilo Horn
1 sibling, 0 replies; 14+ messages in thread
From: Drew Adams @ 2015-03-20 17:43 UTC (permalink / raw)
To: Stefan Monnier, emacs-devel; +Cc: help-gnu-emacs
How about dropping emacs-devel or help-gnu-emacs as recipient?
There should be no need to spread this over multiple lists, at
least at this point. Please just move it to whichever you think
is most appropriate.
And if this is indeed about a bug, as the subject line says,
how about dropping them both and moving this to the bug tracker?
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: Bug in Elisp font-locking
2015-03-20 17:31 ` Bug in Elisp font-locking Stefan Monnier
2015-03-20 17:43 ` Drew Adams
@ 2015-03-20 18:47 ` Tassilo Horn
2015-03-20 20:38 ` Stefan Monnier
1 sibling, 1 reply; 14+ messages in thread
From: Tassilo Horn @ 2015-03-20 18:47 UTC (permalink / raw)
To: Stefan Monnier; +Cc: help-gnu-emacs, emacs-devel
Stefan Monnier <monnier@iro.umontreal.ca> writes:
>>>> (defun lh/gen-predicate (label)
>>>> (defalias (intern (concat "lh/" label "-p"))
>>> ^^^^^^
>>> In this case intern should not be highlighted, isn't it ?.
>
> Indeed.
>
>> (defstruct struct-name ...)
>> (defstruct (struct-name OPTIONS) ...)
>
> Also for defun in Common-Lisp, there's (defun (setf foo) ...) where
> the "setf" probably shouldn't be highlighted but the "foo" should.
The `setf' should be highlighted as a macro but not as function name as
it is right now.
>> Cc-ing emacs-devel to ask if that's ok to commit.
>
> Could explain what the patch does?
Instead of skipping over whitespace and opening parens between the
definition macro/function and the defined thing's name, it skips only
over whitespace but captures an optional opening paren. If there's one,
then we don't font-lock with `font-lock-function-name-face'.
The valid cases where the definition macro/function defines a type like
in `cl-defstruct' still highlights the symbol after the paren (but in
`font-lock-type-face').
Or in simpler words: if the name appears after an opening paren, that
cannot be a function name so don't font-lock as such.
Bye,
Tassilo
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: Bug in Elisp font-locking
2015-03-20 18:47 ` Tassilo Horn
@ 2015-03-20 20:38 ` Stefan Monnier
2015-03-20 22:45 ` Tassilo Horn
0 siblings, 1 reply; 14+ messages in thread
From: Stefan Monnier @ 2015-03-20 20:38 UTC (permalink / raw)
To: emacs-devel; +Cc: help-gnu-emacs
>> Could explain what the patch does?
[...]
> Or in simpler words: if the name appears after an opening paren, that
> cannot be a function name so don't font-lock as such.
OK, that sounds right for *Lisp,
Stefan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: Bug in Elisp font-locking
2015-03-20 20:38 ` Stefan Monnier
@ 2015-03-20 22:45 ` Tassilo Horn
2015-03-21 2:33 ` Stefan Monnier
0 siblings, 1 reply; 14+ messages in thread
From: Tassilo Horn @ 2015-03-20 22:45 UTC (permalink / raw)
To: Stefan Monnier; +Cc: help-gnu-emacs, emacs-devel
Stefan Monnier <monnier@IRO.UMontreal.CA> writes:
>>> Could explain what the patch does?
> [...]
>> Or in simpler words: if the name appears after an opening paren, that
>> cannot be a function name so don't font-lock as such.
>
> OK, that sounds right for *Lisp,
I've committed the patch for elisp, and just now also for CL after
scratching my head why its regex explicitly handled "(setf <symbol>" as
function name. Aha, that's a setf-expander. Learned something
again. :-)
Bye,
Tassilo
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2015-03-21 2:33 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-03-19 6:53 Concern around use of eval Les Harris
2015-03-19 8:00 ` Tassilo Horn
[not found] ` <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>
2015-03-19 8:12 ` Joost Kremers
2015-03-19 8:31 ` Tassilo Horn
[not found] ` <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>
2015-03-20 19:54 ` Joost Kremers
2015-03-19 14:07 ` Stefan Monnier
2015-03-20 15:17 ` Thierry Volpiatto
2015-03-20 17:19 ` Bug in Elisp font-locking (was: Concern around use of eval) Tassilo Horn
2015-03-20 17:31 ` Bug in Elisp font-locking Stefan Monnier
2015-03-20 17:43 ` Drew Adams
2015-03-20 18:47 ` Tassilo Horn
2015-03-20 20:38 ` Stefan Monnier
2015-03-20 22:45 ` Tassilo Horn
2015-03-21 2:33 ` Stefan Monnier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).