* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. @ 2023-11-26 14:30 Alan Mackenzie 2023-12-04 17:36 ` Alan Mackenzie [not found] ` <handler.67455.B.170100905232659.ack@debbugs.gnu.org> 0 siblings, 2 replies; 65+ messages in thread From: Alan Mackenzie @ 2023-11-26 14:30 UTC (permalink / raw) To: 67455 Hello, Emacs. The reasons for this bug and the ways to solve it have been discussed extensively in the thread for bug#66750. We will, in functions' and macros' doc strings record the file name and position of the source code, and possibly other items, in a machine parseable format (which has yet to be decided). This is particularly intended for lambda functions, which currently appear in backtraces and *Help* buffers with insufficient information to identify them. These displays will be enhanced to identify these lambda functions satisfactorally. The functions in Emacs which currently use doc strings will be modified so as not to be negatively affected by the new information written into them. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. 2023-11-26 14:30 bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces Alan Mackenzie @ 2023-12-04 17:36 ` Alan Mackenzie 2023-12-04 18:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors [not found] ` <handler.67455.B.170100905232659.ack@debbugs.gnu.org> 1 sibling, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2023-12-04 17:36 UTC (permalink / raw) To: 67455; +Cc: Eli Zaretskii, Stefan Monnier Hello, Stefan and Eli. On Sun, Nov 26, 2023 at 14:30:25 +0000, Alan Mackenzie wrote: > Hello, Emacs. > The reasons for this bug and the ways to solve it have been discussed > extensively in the thread for bug#66750. > We will, in functions' and macros' doc strings record the file name and > position of the source code, and possibly other items, in a machine > parseable format (which has yet to be decided). > This is particularly intended for lambda functions, which currently > appear in backtraces and *Help* buffers with insufficient information to > identify them. These displays will be enhanced to identify these lambda > functions satisfactorally. > The functions in Emacs which currently use doc strings will be modified > so as not to be negatively affected by the new information written into > them. I've committed the first stage of this implementation in the new git branch feature/positioned-lambdas. It creates for compiled functions (but not yet for interpreted ones) doc strings starting with a specially formatted string containing the defining symbol, the source file name, the position of the defining symbol in the file, and the position of the lambda (should we be in one) in the file. To instruct a defining macro to set a defining-symbol, it is only necessary to add a clause like (defining-symbol 1) or (defining-symbol (if (consp struct) (car struct) struct)) to the macro's declare form. This is how defun now works. (Thank you Stefan for the handy "cl.el feature" in byte-run--parse-declarations. ;-) I scanned our Lisp code for debug-spec &define keywords, and added defining-symbol declare clauses to (most of) the ones I found. As yet, no use is made of the new position information (beyond stripping it off for other uses of the doc string). > -- > Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. 2023-12-04 17:36 ` Alan Mackenzie @ 2023-12-04 18:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-12-04 21:32 ` Alan Mackenzie 2023-12-15 18:23 ` Alan Mackenzie 0 siblings, 2 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-04 18:33 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > I've committed the first stage of this implementation in the new git > branch feature/positioned-lambdas. Haven't had enough time to look closely, so just some quick early comment. > It creates for compiled functions (but not yet for interpreted ones) doc > strings starting with a specially formatted string containing the > defining symbol, the source file name, Why include the file name? Presumably we will rely on a `(FILE . POS)` to find that docstring so including FILE in there is rather redundant (and in addition to that, this file name can be wrong if it's absolute since files often get moved between compilation and use). > the position of the defining symbol in the file, and the position of > the lambda (should we be in one) in the file. Why two positions? Why not use the same position info as used in `byte-compile-warn-x`? > To instruct a defining macro to set a defining-symbol, it is only > necessary to add a clause like (defining-symbol 1) Sounds good. [ Hopefully we can eventually use that info for `font-lock` so we can get rid of ad-hoc rules for `defun` and friends. It would require an additional piece of info (not only the position but also the kind of definition, to distinguish `defun` from `defvar`). ] > or (defining-symbol (if (consp struct) (car struct) struct)) [ Haven't seen that yet. ] Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. 2023-12-04 18:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-04 21:32 ` Alan Mackenzie 2023-12-04 21:56 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-12-15 18:23 ` Alan Mackenzie 1 sibling, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2023-12-04 21:32 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. Thanks for such a quick response. On Mon, Dec 04, 2023 at 13:33:25 -0500, Stefan Monnier wrote: > > I've committed the first stage of this implementation in the new git > > branch feature/positioned-lambdas. > Haven't had enough time to look closely, so just some quick early comment. > > It creates for compiled functions (but not yet for interpreted ones) doc > > strings starting with a specially formatted string containing the > > defining symbol, the source file name, > Why include the file name? Presumably we will rely on a `(FILE . POS)` > to find that docstring so including FILE in there is rather redundant > (and in addition to that, this file name can be wrong if it's absolute > since files often get moved between compilation and use). No, the (FILE . POS) is the .elc file, the one I'm putting into the new info is the source file. But you're right about an absolute name (as it currently is) not being the Right Thing. A lot of Emacs users will be using binaries compiled by somebody else on a different machine, so an absolute name is unhelpful, as well as divulging information about the builder's file structure. Maybe it should be lisp/emacs-lisp/bytecomp.el rather than /home/acm/emacs/emacs.git/sub-master-a/lisp/emacs-lisp/bytecomp.el. At least it would be shorter. > > the position of the defining symbol in the file, and the position of > > the lambda (should we be in one) in the file. > Why two positions? > Why not use the same position info as used in `byte-compile-warn-x`? I'm not sure, yet, but I suspect both positions will be useful. If not, it's trivial to change the contents of the new info, at least it is now. > > To instruct a defining macro to set a defining-symbol, it is only > > necessary to add a clause like (defining-symbol 1) > Sounds good. > [ Hopefully we can eventually use that info for `font-lock` so we can > get rid of ad-hoc rules for `defun` and friends. It would require an > additional piece of info (not only the position but also the kind of > definition, to distinguish `defun` from `defvar`). ] > > or (defining-symbol (if (consp struct) (car struct) struct)) > [ Haven't seen that yet. ] Have a look at cl-defgeneric and cl-defmethod in cl-generic.el. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. 2023-12-04 21:32 ` Alan Mackenzie @ 2023-12-04 21:56 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-12-04 22:30 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-04 21:56 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> Why include the file name? Presumably we will rely on a `(FILE . POS)` >> to find that docstring so including FILE in there is rather redundant >> (and in addition to that, this file name can be wrong if it's absolute >> since files often get moved between compilation and use). > No, the (FILE . POS) is the .elc file, the one I'm putting into the new > info is the source file. Until now, Emacs has always lived with the `.elc` file names (e.g. in `load-history`) and managed to find the corresponding `.el` file (when you try to jump to the source via `M-.` or by clicking in `C-h f`). It comes with its share of problems, but we've learned to live with them. Is there any reason you think this new functionality should go through the extra trouble to record the `.el` name (and thus develop its own set of workarounds for the cases where the `.el` doesn't live where we think it should)? >> > the position of the defining symbol in the file, and the position of >> > the lambda (should we be in one) in the file. >> Why two positions? >> Why not use the same position info as used in `byte-compile-warn-x`? > I'm not sure, yet, but I suspect both positions will be useful. Can you give an example scenario? >> > or (defining-symbol (if (consp struct) (car struct) struct)) >> [ Haven't seen that yet. ] > Have a look at cl-defgeneric and cl-defmethod in cl-generic.el. Ah, got it. I like the way you can refer to args by name. So I guess all the (defining-symbol 1) could similarly be replaced with (defining-symbol THE-ARG-NAME). [ I also notice that this extension is somewhat incompatible with the use I proposed for `font-lock`. :-( ] [ As you noted, this info is also related to the `&define` debug spec. I wish we could unify that information. ] Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. 2023-12-04 21:56 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-04 22:30 ` Alan Mackenzie 2023-12-04 22:59 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2023-12-04 22:30 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Mon, Dec 04, 2023 at 16:56:41 -0500, Stefan Monnier wrote: > >> Why include the file name? Presumably we will rely on a `(FILE . POS)` > >> to find that docstring so including FILE in there is rather redundant > >> (and in addition to that, this file name can be wrong if it's absolute > >> since files often get moved between compilation and use). > > No, the (FILE . POS) is the .elc file, the one I'm putting into the new > > info is the source file. > Until now, Emacs has always lived with the `.elc` file names (e.g. in > `load-history`) and managed to find the corresponding `.el` file (when > you try to jump to the source via `M-.` or by clicking in `C-h f`). > It comes with its share of problems, but we've learned to live with them. Yes. I've come to the same conclusion in the last hour or so that, no doubt, early Emacs hackers reached forty years ago. We can find the ..elc full filename from load-history (via symbol-file), but there's no more useful way of finding the corresponding source than removing the 'c' from the end of foo.elc. And if it's not there, it's nowhere. > Is there any reason you think this new functionality should go through > the extra trouble to record the `.el` name (and thus develop its own > set of workarounds for the cases where the `.el` doesn't live where we > think it should)? Not any more, having thought it through. Maybe, though, it would be useful in some circumstances to record the buffer the definition was loaded from if it's not a file. But it's getting rather late here, so I haven't thought this through at all. > >> > the position of the defining symbol in the file, and the position of > >> > the lambda (should we be in one) in the file. > >> Why two positions? > >> Why not use the same position info as used in `byte-compile-warn-x`? > > I'm not sure, yet, but I suspect both positions will be useful. > Can you give an example scenario? Something about a lambda form, when we need to find the lambda itself, but also its containing form. Sorry I can't be more definite, yet. When I start hacking out the code to use all this information, it will become clearer what we actually need. It's very easy to change at this stage. > >> > or (defining-symbol (if (consp struct) (car struct) struct)) > >> [ Haven't seen that yet. ] > > Have a look at cl-defgeneric and cl-defmethod in cl-generic.el. > Ah, got it. I like the way you can refer to args by name. > So I guess all the (defining-symbol 1) could similarly be replaced with > (defining-symbol THE-ARG-NAME). Yes, I hadn't really thought of that. But (defining-symbol 1) matches similar forms like (docstring 3) which are used somewhere. > [ I also notice that this extension is somewhat incompatible with the > use I proposed for `font-lock`. :-( ] > [ As you noted, this info is also related to the `&define` debug spec. > I wish we could unify that information. ] Ah, the debug spec; yet another difficult domain specific language. ;-( > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. 2023-12-04 22:30 ` Alan Mackenzie @ 2023-12-04 22:59 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 0 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-04 22:59 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > Maybe, though, it would be useful in some circumstances to record the > buffer the definition was loaded from if it's not a file. But it's > getting rather late here, so I haven't thought this through at all. I think if it comes from a buffer (and one that's not associated with a file, to boot), it's usually not byte-compiled, so I suspect you'll be better off confining that handling to the interpreted case. >> >> > the position of the defining symbol in the file, and the position of >> >> > the lambda (should we be in one) in the file. >> >> Why two positions? >> >> Why not use the same position info as used in `byte-compile-warn-x`? >> > I'm not sure, yet, but I suspect both positions will be useful. >> Can you give an example scenario? > Something about a lambda form, when we need to find the lambda itself, > but also its containing form. Sorry I can't be more definite, yet. I'm having a hard time imagining why you'd need two positions. Instead, I want to go to *the* position, which should be "the best we can come up with". And that's also what `byte-compile-warn-x` wants and it has access to the same information. IOW if you think you can do better for lambdas-with-pos, then please try and retro fit it into `byte-compile-warn-x`. >> Ah, got it. I like the way you can refer to args by name. >> So I guess all the (defining-symbol 1) could similarly be replaced with >> (defining-symbol THE-ARG-NAME). > Yes, I hadn't really thought of that. But (defining-symbol 1) matches > similar forms like (docstring 3) which are used somewhere. (defining-symbol N) is nice as well. > Ah, the debug spec; yet another difficult domain specific language. ;-( Yup. It's even worse, because at this stage I don't think anyone truly understands its semantics. [ I just wish we had a "similar" DSL that served /all/ those purposes, i.e. would let the macro writer express where the docstring is (if any), where the defining names are, how to indent each part, how to instrument each part, ... And of course, with a well-defined and well-understood semantics, a simple implementation (that works efficiently for all those uses), and a simple&concise syntax. Oh and while at it, it would also be used during macro-expansion to provide meaningful error messages when the macro is used incorrectly. Clearly, [Fortifying macros](https://dl.acm.org/doi/10.1145/1863543.1863577) can provide useful inspiration. ] Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. 2023-12-04 18:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-12-04 21:32 ` Alan Mackenzie @ 2023-12-15 18:23 ` Alan Mackenzie 2023-12-15 23:12 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2023-12-15 18:23 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Mon, Dec 04, 2023 at 13:33:25 -0500, Stefan Monnier wrote: > > I've committed the first stage of this implementation in the new git > > branch feature/positioned-lambdas. > Haven't had enough time to look closely, so just some quick early comment. ..... I'm making steady, if not rapid, progress on the use of doc strings to store position information. There have been several unexpected problems (which is only to be expected), all of which, bar one, I've been able to solve. The problem that has thrown me is the use of the doc string in oclosures for other purposes. For example, in position 2 of a lambda form, appears something like (:documentation 'oclosure-accessor) .. My current code is expecting, on encountering (:documentation ...), for the cadr to be a string, onto which it can add a concat form which will prefix the position information. A solution to this problem would be to move the above symbol to element 2 of the list, something like (:documentation nil 'oclosure-accessor) , so that my new code could place its information in the now vacant position 1, giving something like (:documentation ";POS\36\0\0\0 [ .... ]\n" 'oclosure-accessor) .. What do you think of this idea, and have you any better ideas for a solution to the problem? > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces. 2023-12-15 18:23 ` Alan Mackenzie @ 2023-12-15 23:12 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 0 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-12-15 23:12 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > The problem that has thrown me is the use of the doc string in oclosures > for other purposes. For example, in position 2 of a lambda form, > appears something like > > (:documentation 'oclosure-accessor) Hmm... > .. My current code is expecting, on encountering (:documentation ...), > for the cadr to be a string, `:documentation` is supposed to be followed by an expression (whose evaluation should usually return a string, although indeed we abuse it in the case of OClosures to return a symbol instead). Regardless of OClosures, the `cadr` of a `:documentation` will very rarely be a mere string since you don't need `:documentation` when the docstring can be written as a literal. > onto which it can add a concat form which > will prefix the position information. For the non-OClosure case you should be able to use the equivalent of: (:documentation (concat <YOURINFOHERE> <THEORIGINALEXPRESSIONHERE>)) is that what you mean? > A solution to this problem would be to move the above symbol to element > 2 of the list, something like > > (:documentation nil 'oclosure-accessor) Here you're talking about the source code, right? I think the question is rather what representation to use in the values: OClosures store their type name (symbol) in the slot that normally holds the docstring, so I think the best short term answer is to say that OClosures aren't supported by your new feature. OClosures are a mix of functions and structs, so while it would be nice to make them enjoy your new feature, I think it's perfectly OK to say that in this respect they're more like structs than like functions. Also they come with more introspection features than normal functions, so it's usually easier to figure out where they come from (you can find their type, and then look for the `oclosure-lambda`s which built OClosures of this type. For most OClosure types, there's only one such lambda anyway). > , so that my new code could place its information in the now vacant > position 1, giving something like > > (:documentation ";POS\36\0\0\0 [ .... ]\n" 'oclosure-accessor) > > .. What do you think of this idea, and have you any better ideas for a > solution to the problem? If it works it might be a good option. I don't know how this turns into when we build the corresponding bytecode object, so it's hard to judge. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
[parent not found: <handler.67455.B.170100905232659.ack@debbugs.gnu.org>]
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) [not found] ` <handler.67455.B.170100905232659.ack@debbugs.gnu.org> @ 2024-03-04 15:38 ` Alan Mackenzie 2024-03-09 21:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-06-01 17:40 ` Alan Mackenzie 0 siblings, 2 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-03-04 15:38 UTC (permalink / raw) To: 67455, Eli Zaretskii, Stefan Monnier; +Cc: acm Hello, Eli and Stefan. On Sun, Nov 26, 2023 at 14:31:02 +0000, GNU bug Tracking System wrote: > Thank you for filing a new bug report with debbugs.gnu.org. [ .... ] I've just pushed a large commit to feature/positioned-lambdas, a work in progress commit for bug#67455, putting source position information at the start of doc strings. master was merged into it just before the commit. The main topic of the commit is putting position information into interpreted functions, and into lambda forms created at run time. Still missing is position information for defvars and defconsts, along with the same for cl-defmethods (which are complicated because the doc string has no fixed position). Also missing is the handling of Oclosures. There are also some diagnostic functions still in byte-run.el, as they are still useful. As yet, I'm not doing anything with this information, though I anticipate that will be quite easy. This commit, although it works, is unfinished, and still contains quite a few of my private change annotations, and lots of temporary changes to enable useful backtraces to be produced. make check runs without any errors. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-04 15:38 ` bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) Alan Mackenzie @ 2024-03-09 21:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-10 16:02 ` Alan Mackenzie 2024-06-01 17:40 ` Alan Mackenzie 1 sibling, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-09 21:36 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > I've just pushed a large commit to feature/positioned-lambdas, a work > in progress commit for bug#67455, putting source position information at > the start of doc strings. master was merged into it just before the > commit. I barely started to look at the code, but regarding the following hunk: diff --git a/lisp/emacs-lisp/backquote.el b/lisp/emacs-lisp/backquote.el index 6917128d70a..0d4681bc979 100644 --- a/lisp/emacs-lisp/backquote.el +++ b/lisp/emacs-lisp/backquote.el @@ -172,6 +172,30 @@ backquote-process (backquote-delay-process s (1- level)))) ((eq (car s) backquote-backquote-symbol) (backquote-delay-process s (1+ level))) + ;; Process a (lambda ...) form specially, since otherwise the + ;; lambda symbol would get separated from its introductory (, + ;; preventing this processing from being done elsewhere in macro + ;; expansion. + ((and (eq (car s) 'lambda) + (symbol-with-pos-p (car s)) + (listp (car-safe (cdr s)))) + (let ((kdr (backquote-process (cdr s) level)) + (lambda-pos (symbol-with-pos-pos (car s))) + ) + (if (null byte-compile-in-progress) + (setcar s 'lambda)) ; Strip the position. + (cond + ((= (car kdr) 0) + (cons (car kdr) + (list 'quote + (byte-run-posify-lambda-form + (cons (car s) (car (cdr (cdr kdr)))) ; Two cdr's to strip 'quote. + lambda-pos)))) + (t + (cons 1 + (list 'byte-run-posify-lambda-form + (list 'cons (list 'quote (car s)) (cdr kdr)) + lambda-pos)))))) (t (let ((rest s) item firstlist list lists expression) - Testing `byte-compile-in-progress` can't be right. Do you to test whether the result of this backquote will be byte-compiled or do you really mean to test whether this backquote happens to be executed during compilation (which could be because the compiler ends up loading code while executing `eval-when-compile` or `require`)? - My gut tells me that changing backquote can't be right. (lambda (f) ..) *can* appear within a backquote without it being an actual lambda expression. What alternatives have you considered? Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-09 21:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-10 16:02 ` Alan Mackenzie 2024-03-10 17:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-10 16:02 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. Thanks for looking at my patch! I've got a version almost ready which actually does something, namely prefixes "anonymous" lines of a backtrace with the name of the defining symbol, like {foo} . It'll soon be time to start seriously thinking about what information ought to go there for the live version. Unfortunately, I've still got two blocking issues to resolve - one is a change in functionality to Fbare_symbol, which I've reported as a bug; the other is some new code merged in from master, a with-eval-after-load clause in pcase.el which causes havoc in my build. Still, progress is being made. On Sat, Mar 09, 2024 at 16:36:57 -0500, Stefan Monnier wrote: > > I've just pushed a large commit to feature/positioned-lambdas, a work > > in progress commit for bug#67455, putting source position information at > > the start of doc strings. master was merged into it just before the > > commit. > I barely started to look at the code, but regarding the following hunk: > diff --git a/lisp/emacs-lisp/backquote.el b/lisp/emacs-lisp/backquote.el > index 6917128d70a..0d4681bc979 100644 > --- a/lisp/emacs-lisp/backquote.el > +++ b/lisp/emacs-lisp/backquote.el > @@ -172,6 +172,30 @@ backquote-process > (backquote-delay-process s (1- level)))) > ((eq (car s) backquote-backquote-symbol) > (backquote-delay-process s (1+ level))) > + ;; Process a (lambda ...) form specially, since otherwise the > + ;; lambda symbol would get separated from its introductory (, > + ;; preventing this processing from being done elsewhere in macro > + ;; expansion. > + ((and (eq (car s) 'lambda) > + (symbol-with-pos-p (car s)) > + (listp (car-safe (cdr s)))) > + (let ((kdr (backquote-process (cdr s) level)) > + (lambda-pos (symbol-with-pos-pos (car s))) > + ) > + (if (null byte-compile-in-progress) > + (setcar s 'lambda)) ; Strip the position. > + (cond > + ((= (car kdr) 0) > + (cons (car kdr) > + (list 'quote > + (byte-run-posify-lambda-form > + (cons (car s) (car (cdr (cdr kdr)))) ; Two cdr's to strip 'quote. > + lambda-pos)))) > + (t > + (cons 1 > + (list 'byte-run-posify-lambda-form > + (list 'cons (list 'quote (car s)) (cdr kdr)) > + lambda-pos)))))) > (t > (let ((rest s) > item firstlist list lists expression) > - Testing `byte-compile-in-progress` can't be right. Do you to test > whether the result of this backquote will be byte-compiled or do you > really mean to test whether this backquote happens to be executed > during compilation (which could be because the compiler ends up > loading code while executing `eval-when-compile` or `require`)? Quite simply, during compilation, all symbols (except nil) get read with position, so to strip their positions here would be wrong. Outside of compilation (an evaluation of a defun, for example), only defined symbols get positioned, and these symbols with position would interfere with Emacs's working. So they get stripped of their positions as soon as possible after the info has been transferred to the doc string. For example, SWPs cannot be dumped by the portable dumper. > - My gut tells me that changing backquote can't be right. I tend to agree. I put the code into backquote-process when having problems with things like: (mapatoms #'(lambda (,(car spec)) ,@body) in cl-macs.el, where it's impossible to know where the doc string (if any) is until after the expansion of the backquotes, or even at run time (as here). In the latter case, rather than "posifying" the doc string at macro expansion time, we have to generate code to do it at run time. > (lambda (f) ..) *can* appear within a backquote without it being an > actual lambda expression. > What alternatives have you considered? Not a lot of them, as yet. Maybe testing for (function (lambda ...)) would be safer. But I think I should try and find some other way of solving these problems than altering backquote.el, which should be easier now that the code is basically working. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-10 16:02 ` Alan Mackenzie @ 2024-03-10 17:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-10 19:22 ` Alan Mackenzie 2024-03-10 22:27 ` Alan Mackenzie 0 siblings, 2 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-10 17:19 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > I've got a version almost ready which actually does something, namely > prefixes "anonymous" lines of a backtrace with the name of the defining > symbol, like {foo} . It'll soon be time to start seriously thinking > about what information ought to go there for the live version. Cool! >> - Testing `byte-compile-in-progress` can't be right. Do you to test >> whether the result of this backquote will be byte-compiled or do you >> really mean to test whether this backquote happens to be executed >> during compilation (which could be because the compiler ends up >> loading code while executing `eval-when-compile` or `require`)? > > Quite simply, during compilation, all symbols (except nil) get read with > position, so to strip their positions here would be wrong. This isn't quite right: during compilation, some code is read with positions (the code that we will compile), but some code is read in the normal way (the code we load for the purpose of running). The distinction is important. >> - My gut tells me that changing backquote can't be right. > > I tend to agree. I put the code into backquote-process when having > problems with things like: > > (mapatoms #'(lambda (,(car spec)) ,@body) > > in cl-macs.el, where it's impossible to know where the doc string (if > any) is until after the expansion of the backquotes, or even at run time > (as here). In the latter case, rather than "posifying" the doc string > at macro expansion time, we have to generate code to do it at run time. Hmm... here what you call "run time" is really some later macro-expansion, right? The `lambda` symbol comes from the first macro-expansion (ME1), but the docstring comes from the second (ME2). IIUC the problem you face is that you want to get the function's position info from the `lambda` symbol, which here would be wrong (even if we try to preserve it long enough), is that it? [ Tho, in more complex cases it becomes debatable whether the function's position should point to the position corresponding to ME1 or to that of ME2. ] More generally: what goes wrong in the above example if you just treat that as a list of symbol (stripping them all of their position info). AFAICT when *that* macro is expanded (i.e. ME2) you'll presumably get code like (mapatoms #'(lambda (FOO/p) (DO/p SOME/p (THING/p)))) right? [ where "/p" means that the symbol has a sympos. ] Isn't that sufficient info to add a docstring with position? >> (lambda (f) ..) *can* appear within a backquote without it being an >> actual lambda expression. >> What alternatives have you considered? > Not a lot of them, as yet. Maybe testing for (function (lambda ...)) > would be safer. No matter how many extra tests you add to reduce the frequency, you're fundamentally adding a bug :-( Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-10 17:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-10 19:22 ` Alan Mackenzie 2024-03-10 21:03 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-10 22:27 ` Alan Mackenzie 1 sibling, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-10 19:22 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Sun, Mar 10, 2024 at 13:19:03 -0400, Stefan Monnier wrote: > > I've got a version almost ready which actually does something, namely > > prefixes "anonymous" lines of a backtrace with the name of the defining > > symbol, like {foo} . It'll soon be time to start seriously thinking > > about what information ought to go there for the live version. > Cool! I've finally got something to show. I've just committed a merge and a fix for it to branch feature/positioned-lambdas at savannah. With this Emacs running, type the following into *scratch* (defun foo () "foo doc" (lambda (bar) "lambda doc" (car bar))) .. Either evaluate this or byte compile it with compile-defun. Then do M-: (funcall (foo) 'baz) .. This will produce a backtrace like: Debugger entered--Lisp error: (wrong-type-argument listp baz) car(baz) {foo} #f(compiled-function (bar) "lambda doc" #<bytecode -0x14ae78a46439bbc>)(baz) funcall({foo} #f(compiled-function (bar) "lambda doc" #<bytecode -0x14ae78a46439bbc>) baz) (progn (funcall (foo) 'baz)) eval((progn (funcall (foo) 'baz)) t) elisp--eval-last-sexp(nil) {eval-last-sexp} #f(compiled-function () #<bytecode -0x1e8241efdb3d2890>)() eval-last-sexp(nil) funcall-interactively(eval-last-sexp nil) command-execute(eval-last-sexp) .. Note the {eval-last-sexp} and {foo} on the anonymous functions. :-) > >> - Testing `byte-compile-in-progress` can't be right. Do you to test > >> whether the result of this backquote will be byte-compiled or do you > >> really mean to test whether this backquote happens to be executed > >> during compilation (which could be because the compiler ends up > >> loading code while executing `eval-when-compile` or `require`)? > > Quite simply, during compilation, all symbols (except nil) get read with > > position, so to strip their positions here would be wrong. > This isn't quite right: during compilation, some code is read with > positions (the code that we will compile), but some code is read in the > normal way (the code we load for the purpose of running). > The distinction is important. OK, I wasn't really counting code that we load as "during compilation", but I take the point. > >> - My gut tells me that changing backquote can't be right. > > I tend to agree. I put the code into backquote-process when having > > problems with things like: > > (mapatoms #'(lambda (,(car spec)) ,@body) > > in cl-macs.el, where it's impossible to know where the doc string (if > > any) is until after the expansion of the backquotes, or even at run time > > (as here). In the latter case, rather than "posifying" the doc string > > at macro expansion time, we have to generate code to do it at run time. > Hmm... here what you call "run time" is really some later > macro-expansion, right? The `lambda` symbol comes from the first > macro-expansion (ME1), but the docstring comes from the second (ME2). Yes. I often get confused between lots of different macro expansion times, compile time and run time. It's a lot easier in C. ;-) > IIUC the problem you face is that you want to get the function's > position info from the `lambda` symbol, which here would be wrong (even if we > try to preserve it long enough), is that it? Something like that. The lambda's position currently gets preserved in the generated code so that ME2 can use it. > [ Tho, in more complex cases it becomes debatable whether the function's > position should point to the position corresponding to ME1 or to that > of ME2. ] The code currently preserves both positions. :-) But only one buffer name. My latest thoughts on that are perhaps two file names (relative to the Emacs top directory) would be better than one buffer name. Then I could put buttons on the backtrace display which on being clicked would open either of the source files at the right position. > More generally: what goes wrong in the above example if you just treat > that as a list of symbol (stripping them all of their position info). > AFAICT when *that* macro is expanded (i.e. ME2) you'll presumably get > code like > (mapatoms #'(lambda (FOO/p) (DO/p SOME/p (THING/p)))) > right? [ where "/p" means that the symbol has a sympos. ] > Isn't that sufficient info to add a docstring with position? It's the lambda which has a position rather than the expanded bits from ME2. > >> (lambda (f) ..) *can* appear within a backquote without it being an > >> actual lambda expression. > >> What alternatives have you considered? > > Not a lot of them, as yet. Maybe testing for (function (lambda ...)) > > would be safer. > No matter how many extra tests you add to reduce the frequency, you're > fundamentally adding a bug :-( Yes. I'll see what I can do to remove that extra code from backquote-process. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-10 19:22 ` Alan Mackenzie @ 2024-03-10 21:03 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-24 11:04 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-10 21:03 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> >> - Testing `byte-compile-in-progress` can't be right. Do you to test >> >> whether the result of this backquote will be byte-compiled or do you >> >> really mean to test whether this backquote happens to be executed >> >> during compilation (which could be because the compiler ends up >> >> loading code while executing `eval-when-compile` or `require`)? > >> > Quite simply, during compilation, all symbols (except nil) get read with >> > position, so to strip their positions here would be wrong. > >> This isn't quite right: during compilation, some code is read with >> positions (the code that we will compile), but some code is read in the >> normal way (the code we load for the purpose of running). >> The distinction is important. > > OK, I wasn't really counting code that we load as "during compilation", > but I take the point. The point is that `byte-compile-in-progress` will be non-nil during those loads, so you can't use this variable to get the information you need. >> More generally: what goes wrong in the above example if you just treat >> that as a list of symbol (stripping them all of their position info). >> AFAICT when *that* macro is expanded (i.e. ME2) you'll presumably get >> code like > >> (mapatoms #'(lambda (FOO/p) (DO/p SOME/p (THING/p)))) > >> right? [ where "/p" means that the symbol has a sympos. ] >> Isn't that sufficient info to add a docstring with position? > > It's the lambda which has a position rather than the expanded bits from > ME2. Hmm... then I misunderstand something. How can the `lambda` have a position if you don't include any special treatment of backquote? AFAICT the `lambda` in the result of ME1 should not include position information because at that time we don't know that it will be used to build code rather than be some element of a normal list. And how come the rest doesn't have position information? Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-10 21:03 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-24 11:04 ` Alan Mackenzie 2024-03-25 18:23 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-24 11:04 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Sun, Mar 10, 2024 at 17:03:28 -0400, Stefan Monnier wrote: > >> >> - Testing `byte-compile-in-progress` can't be right. Do you to test > >> >> whether the result of this backquote will be byte-compiled or do you > >> >> really mean to test whether this backquote happens to be executed > >> >> during compilation (which could be because the compiler ends up > >> >> loading code while executing `eval-when-compile` or `require`)? > >> > Quite simply, during compilation, all symbols (except nil) get read with > >> > position, so to strip their positions here would be wrong. > >> This isn't quite right: during compilation, some code is read with > >> positions (the code that we will compile), but some code is read in the > >> normal way (the code we load for the purpose of running). > >> The distinction is important. > > OK, I wasn't really counting code that we load as "during compilation", > > but I take the point. > The point is that `byte-compile-in-progress` will be non-nil during > those loads, so you can't use this variable to get the information you need. Yes. How about binding it to nil around `load' and recursive edits, and possibly one or two other things? > >> More generally: what goes wrong in the above example if you just treat > >> that as a list of symbol (stripping them all of their position info). > >> AFAICT when *that* macro is expanded (i.e. ME2) you'll presumably get > >> code like > >> (mapatoms #'(lambda (FOO/p) (DO/p SOME/p (THING/p)))) > >> right? [ where "/p" means that the symbol has a sympos. ] > >> Isn't that sufficient info to add a docstring with position? > > It's the lambda which has a position rather than the expanded bits from > > ME2. > Hmm... then I misunderstand something. How can the `lambda` have > a position if you don't include any special treatment of backquote? In read-positioning-defined-symbols, lambdas get positioned, along with symbols being defined by defun, defmacro, cl-defmethod, .... This is not to do with backquote handling. > AFAICT the `lambda` in the result of ME1 should not include position > information because at that time we don't know that it will be used to > build code rather than be some element of a normal list. read-positioning-defined-symbols cannot know how (lambda ...) is going to be used. It is up to other code (here, macroexp--expand-all) to strip the position from the lambda when it would be obtrusive. > And how come the rest doesn't have position information? read-positioning-defined-symbols is specifically coded (with a state machine) to position only the lambdas and the defined symbols. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-24 11:04 ` Alan Mackenzie @ 2024-03-25 18:23 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-25 21:03 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-25 18:23 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> The point is that `byte-compile-in-progress` will be non-nil during >> those loads, so you can't use this variable to get the information you need. > Yes. How about binding it to nil around `load' and recursive edits, and > possibly one or two other things? You mean trying to enumerate all the places we can think of where we know that compilation is not taking place? That sounds rather ugly. I'd rather first try and define precisely what is we mean by "compilation in progress". I see the same problem with: DEFVAR_LISP ("defining-symbol", Vdefining_symbol, doc: /* The symbol currently being defined by a defining form. This variable is bound in the read-eval-print loop and certain high-level functions in the byte compiler. It is set to a value by functions and macros such as `defun', `defmacro', and `defvar'. */); Lots and lots of things can happen "during the definition" of a form, including definition of lots of other forms. So I think we'd need to define much more precisely what you meant by "currently". In addition, a definition is "intemporal" (it's declarative), so "currently being defined" is almost like an oxymoron. I'm trying to understand your code, but I clearly lack a high-level overview of the approach you decided to takes, so I don't understand what's going on there. Is that branch trying to provide function-position for compiled functions only, for interpreted functions only, or both? If both, could you split it into two, then? AFAICT doing it only for compiled functions should be significantly simpler than for interpreted functions, so it would be a good stepping stone. On the cosmetic side, you have way too much code in `byte-run.el`. I think most of this code can be moved elsewhere, e.g. somewhere where backquote can be used Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-25 18:23 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-25 21:03 ` Alan Mackenzie 2024-03-25 22:10 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-25 21:03 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. Thanks for taking the time and trouble to review my branch. On Mon, Mar 25, 2024 at 14:23:50 -0400, Stefan Monnier wrote: > >> The point is that `byte-compile-in-progress` will be non-nil during > >> those loads, so you can't use this variable to get the information you need. > > Yes. How about binding it to nil around `load' and recursive edits, and > > possibly one or two other things? > You mean trying to enumerate all the places we can think of where we > know that compilation is not taking place? Yes. > That sounds rather ugly. I'd rather first try and define precisely > what is we mean by "compilation in progress". That the byte compiler is active, and all symbols (bar nil) get positioned. Contrast this with, say, loading a .el file, where only some symbols get positioned. An alternative might be to pass an &optional boolean argument meaning "preserve positions on symbols". > I see the same problem with: > DEFVAR_LISP ("defining-symbol", Vdefining_symbol, > doc: /* The symbol currently being defined by a defining form. > This variable is bound in the read-eval-print loop and certain > high-level functions in the byte compiler. It is set to a value by > functions and macros such as `defun', `defmacro', and `defvar'. */); > Lots and lots of things can happen "during the definition" of a form, > including definition of lots of other forms. So I think we'd need to > define much more precisely what you meant by "currently". > In addition, a definition is "intemporal" (it's declarative), so > "currently being defined" is almost like an oxymoron. By "currently", I mean that a defining form such as defun or defvar has commenced, but not yet terminated; its functions currently occupy stack frames. > I'm trying to understand your code, but I clearly lack a high-level > overview of the approach you decided to takes, so I don't understand > what's going on there. Sorry about that. A quick summary: defined symbols (and lambda) get positioned by the new reader function read-positioning-defined symbols. The new declare clause defining-symbol marks a macro such as defun or cl-defgeneric as a macro which defines such symbols. The conversion of these SWPs into position structures in doc strings happens at macro expansion time, through byte-run-posify-lambda-form. > Is that branch trying to provide function-position for compiled > functions only, for interpreted functions only, or both? It not only tries, but succeeds (modulo remaining bugs) in providing posification for both interpreted and compiled functions. > If both, could you split it into two, then? I'm not sure that would be possible or sensible - both use a common approach. > AFAICT doing it only for compiled functions should be significantly > simpler than for interpreted functions, so it would be a good > stepping stone. The work has already been done, and there is working code. Just as a matter of interest, the branch runs the test suite without errors (not counting "expensive" tests ). > On the cosmetic side, you have way too much code in `byte-run.el`. > I think most of this code can be moved elsewhere, e.g. somewhere where > backquote can be used Yes, I noticed this, too. A lot of the bulk is for diagnostic functions for SWPs, and these can eventually be deleted. Or possibly moved into a new file with-pos.el to be loaded before byte-run.el. byte-run--posify-defining-symbol, the function with the extreme hand expansion of backquotes is used as a declare clause handler, and is needed by defun. Hence it couldn't really be moved to after the loading of backquote.el. There are some additional functions which batch-posify functions and variables defined before the posification mechanism is in place. This must be done ASAP, for the benefit of backtraces in early bootstrap. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-25 21:03 ` Alan Mackenzie @ 2024-03-25 22:10 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 9:48 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-25 22:10 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> That sounds rather ugly. I'd rather first try and define precisely >> what is we mean by "compilation in progress". > That the byte compiler is active, and all symbols (bar nil) get > positioned. That is much too vague to be usable. Which symbols are we talking about? What do we mean by "active"? I think we need to describe it in terms that link the symbol with code in bytecomp.el (not based on time, but based on function bytecomp-FOO calling BAR calling BAZ ... touching that symbol). Note that I also have no idea why we need to care about whether we're in the compiled case or the non-compiled case, so maybe my questions are "XY" style problems. > An alternative might be to pass an &optional boolean argument meaning > "preserve positions on symbols". From where to where should we pass that argument? [ And yes, explicit arguments might be preferable unless the call-trace is too long for it to be practical or unless some of the functions along that call trace can't be changed easily to take such an extra argument. ] BTW, do you really mean "preserve" (meaning that the symbols were sympos to start with)? >> I see the same problem with: > >> DEFVAR_LISP ("defining-symbol", Vdefining_symbol, >> doc: /* The symbol currently being defined by a defining form. >> This variable is bound in the read-eval-print loop and certain >> high-level functions in the byte compiler. It is set to a value by >> functions and macros such as `defun', `defmacro', and `defvar'. */); > >> Lots and lots of things can happen "during the definition" of a form, >> including definition of lots of other forms. So I think we'd need to >> define much more precisely what you meant by "currently". >> In addition, a definition is "intemporal" (it's declarative), so >> "currently being defined" is almost like an oxymoron. > > By "currently", I mean that a defining form such as defun or defvar has > commenced, but not yet terminated; its functions currently occupy stack > frames. So you mean we're inside `Fdefalias` or `Fdefvar_1`? >> I'm trying to understand your code, but I clearly lack a high-level >> overview of the approach you decided to takes, so I don't understand >> what's going on there. > > Sorry about that. A quick summary: defined symbols (and lambda) get > positioned by the new reader function read-positioning-defined symbols. > The new declare clause defining-symbol marks a macro such as defun or > cl-defgeneric as a macro which defines such symbols. > > The conversion of these SWPs into position structures in doc strings > happens at macro expansion time, through byte-run-posify-lambda-form. So, IIUC (defmacro defun (name args docstring &rest body) (declare (defining-symbol 1)) ...) is akin to: (defmacro defun (name args docstring &rest body) (setq docstring (add-pos-to-docstring (symbol-with-pos-pos name) docstring)) ...) ? >> If both, could you split it into two, then? > I'm not sure that would be possible or sensible - both use a common > approach. So, IIUC a first part of the change was to make `load` use `read-positioning-symbols` just like the compiler? >> AFAICT doing it only for compiled functions should be significantly >> simpler than for interpreted functions, so it would be a good >> stepping stone. > The work has already been done, and there is working code. Just as a > matter of interest, the branch runs the test suite without errors (not > counting "expensive" tests ). I'm not talking about a separate branch. I'm talking about splitting your changes into understandable commits. >> On the cosmetic side, you have way too much code in `byte-run.el`. >> I think most of this code can be moved elsewhere, e.g. somewhere where >> backquote can be used > > Yes, I noticed this, too. A lot of the bulk is for diagnostic functions > for SWPs, and these can eventually be deleted. Or possibly moved into a > new file with-pos.el to be loaded before byte-run.el. I don't like the idea of adding another file before byte-run.el. > byte-run--posify-defining-symbol, the function with the extreme hand > expansion of backquotes is used as a declare clause handler, and is > needed by defun. Hence it couldn't really be moved to after the loading > of backquote.el. I think you can simply wait to add the entry to `macro-declarations-alist` until a later time, so the `defining-symbol` thingies will be ignored during the early bootstrap and once we have more infrastructure in place we can then register the handler on `macro-declarations-alist`. > There are some additional functions which batch-posify functions and > variables defined before the posification mechanism is in place. This > must be done ASAP, for the benefit of backtraces in early bootstrap. That complexifies the early bootstrap code. I'd rather keep that code simpler. During early bootstrap, all those functions are interpreted and I can't remember ever having difficulty tracking the origin of those interpreted lambdas during early bootstrap, so I'm rather opposed to such complexity just for the sake of maybe occasionally hypothetically giving a bit of help to the 3 of us who have to deal with those problems. I see functions-with-pos as something mostly targeted at "end users" who aren't expert enough to figure out the origin of anonymous functions by looking at the disassembly of the bytecode and taking an educated guess. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-25 22:10 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 9:48 ` Alan Mackenzie 2024-03-26 13:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 20:30 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 2 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-03-26 9:48 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Mon, Mar 25, 2024 at 18:10:11 -0400, Stefan Monnier wrote: > >> That sounds rather ugly. I'd rather first try and define precisely > >> what is we mean by "compilation in progress". > > That the byte compiler is active, and all symbols (bar nil) get > > positioned. > That is much too vague to be usable. Which symbols are we > talking about? What do we mean by "active"? The symbols read from the source code being compiled by the byte compiler. By "active" I mean that a byte compilation has been started, is not yet complete, and hasn't been temporarily suspended (e.g. for loading another file with (require 'foo)). > I think we need to describe it in terms that link the symbol with code > in bytecomp.el (not based on time, but based on function bytecomp-FOO > calling BAR calling BAZ ... touching that symbol). > Note that I also have no idea why we need to care about whether we're in > the compiled case or the non-compiled case, so maybe my questions are > "XY" style problems. We now have two distinct uses of SWPs: providing warning source locations to the compiler (where we want to keep the position as long as possible) and providing position information for the doc string (where we want to strip the position from the symbol ASAP, to avoid trying to use the SWP when we need a plain symbol). If both of these occur together, we want to keep the SWP. This is the purpose of byte-compile-in-progress. > > An alternative might be to pass an &optional boolean argument meaning > > "preserve positions on symbols". > >From where to where should we pass that argument? > [ And yes, explicit arguments might be preferable unless the > call-trace is too long for it to be practical or unless some of the > functions along that call trace can't be changed easily to take such an > extra argument. ] To macroexp--expand-all from wherever. Here (L423 of macroexp.el) is where the position gets stripped from the SWP in the non compilation case. > BTW, do you really mean "preserve" (meaning that the symbols were sympos > to start with)? Indeed, yes. > >> I see the same problem with: > >> DEFVAR_LISP ("defining-symbol", Vdefining_symbol, > >> doc: /* The symbol currently being defined by a defining form. > >> This variable is bound in the read-eval-print loop and certain > >> high-level functions in the byte compiler. It is set to a value by > >> functions and macros such as `defun', `defmacro', and `defvar'. */); > >> Lots and lots of things can happen "during the definition" of a form, > >> including definition of lots of other forms. So I think we'd need to > >> define much more precisely what you meant by "currently". > >> In addition, a definition is "intemporal" (it's declarative), so > >> "currently being defined" is almost like an oxymoron. > > By "currently", I mean that a defining form such as defun or defvar has > > commenced, but not yet terminated; its functions currently occupy stack > > frames. > So you mean we're inside `Fdefalias` or `Fdefvar_1`? Yes, or inside a macro (defun, defmacro, ...) which expands to a defalias. Ideally, I would like to have bound defining-symbol inside defun. But this would have lost the binding at the end of defun, before evaluating the defalias. It was a tricky problem which I think has been solved. > >> I'm trying to understand your code, but I clearly lack a high-level > >> overview of the approach you decided to takes, so I don't understand > >> what's going on there. > > Sorry about that. A quick summary: defined symbols (and lambda) get > > positioned by the new reader function read-positioning-defined symbols. > > The new declare clause defining-symbol marks a macro such as defun or > > cl-defgeneric as a macro which defines such symbols. > > The conversion of these SWPs into position structures in doc strings > > happens at macro expansion time, through byte-run-posify-lambda-form. > So, IIUC > (defmacro defun (name args docstring &rest body) > (declare (defining-symbol 1)) > ...) > is akin to: > (defmacro defun (name args docstring &rest body) > (setq docstring (add-pos-to-docstring > (symbol-with-pos-pos name) docstring)) > ...) > ? Pretty much, yes. (declare (defining-symbol name docstring)) also informs the reader that NAME is to be positioned when in (defun NAME ....). > >> If both, could you split it into two, then? > > I'm not sure that would be possible or sensible - both use a common > > approach. > So, IIUC a first part of the change was to make `load` use > `read-positioning-symbols` just like the compiler? Fload uses read-positioning-DEFINED-symbols, as contrasted with the compiler, which uses read-positioning-symbols. r-p-d-s positions only lambdas and NAMEs. r-p-s positions all symbols except nil. > >> AFAICT doing it only for compiled functions should be significantly > >> simpler than for interpreted functions, so it would be a good > >> stepping stone. > > The work has already been done, and there is working code. Just as a > > matter of interest, the branch runs the test suite without errors (not > > counting "expensive" tests ). > I'm not talking about a separate branch. I'm talking about splitting > your changes into understandable commits. Ah, right. I hadn't considered this before. The changes are by their very nature essentially complicated and difficult to understand. > >> On the cosmetic side, you have way too much code in `byte-run.el`. > >> I think most of this code can be moved elsewhere, e.g. somewhere where > >> backquote can be used > > Yes, I noticed this, too. A lot of the bulk is for diagnostic functions > > for SWPs, and these can eventually be deleted. Or possibly moved into a > > new file with-pos.el to be loaded before byte-run.el. > I don't like the idea of adding another file before byte-run.el. Neither do I, but it's a possibility. > > byte-run--posify-defining-symbol, the function with the extreme hand > > expansion of backquotes is used as a declare clause handler, and is > > needed by defun. Hence it couldn't really be moved to after the loading > > of backquote.el. > I think you can simply wait to add the entry to > `macro-declarations-alist` until a later time, so the `defining-symbol` > thingies will be ignored during the early bootstrap and once we have > more infrastructure in place we can then register the handler on > `macro-declarations-alist`. This will not be simpler. It would involve re-evaluating defun, then compensating for all the functions up to now whose NAMEs had been read without positions. There is unavoidable conplexity, here. We need defun to build backquote, byte-run--posify-defining-symbol to build defun, and so we need to write b-r--p-d-s without backquote. All that could be done is to shift the complexity to a different arm of that dependency triangle. > > There are some additional functions which batch-posify functions and > > variables defined before the posification mechanism is in place. This > > must be done ASAP, for the benefit of backtraces in early bootstrap. > That complexifies the early bootstrap code. I'd rather keep that code > simpler. During early bootstrap, all those functions are interpreted > and I can't remember ever having difficulty tracking the origin of those > interpreted lambdas during early bootstrap, so I'm rather opposed to > such complexity just for the sake of maybe occasionally hypothetically > giving a bit of help to the 3 of us who have to deal with > those problems. Well all I can say here is that the lack of special cases here has been most helpful in debugging the current code. It's possible (?likely) that somebody will need to look at it again, sometime. > I see functions-with-pos as something mostly targeted at "end users" who > aren't expert enough to figure out the origin of anonymous functions by > looking at the disassembly of the bytecode and taking an educated guess. I see things somewhat differently. We shouldn't increase the debugging burden even on "expert users". My view is that debugging Lisp in Emacs is too difficult and tedious, and can be improved. debug-early.el and getting backtraces from redisplay errors are two already implemented such improvements. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 9:48 ` Alan Mackenzie @ 2024-03-26 13:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 16:55 ` Alan Mackenzie 2024-03-26 20:30 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 13:40 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> > Sorry about that. A quick summary: defined symbols (and lambda) get >> > positioned by the new reader function read-positioning-defined symbols. >> > The new declare clause defining-symbol marks a macro such as defun or >> > cl-defgeneric as a macro which defines such symbols. Since I still don't understand the general picture, let me tell you how I would plan to do it, so you can tell me where it matches your approach and where it doesn't: - Change `load-source-file-function` so it uses `read-positioning-symbols` instead of plain `read`. [ This means that macro-expansion will now almost always have sympos, rather than only during compilation, ] - This in turn requires a strip-sympos pass after the eager-macroexpansion phase of `load-source-file-function`. - Change macros like `lambda` so as to use the extract position info from themselves/theirargs/thecontext (when available, since there will still be corner cases where it's not available, such as during non-eager macro expansion) and stash it in their docstring. This might be as simple as adding a line (setq docstring (add-pos-to-docstring docstring ARG)). - Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 13:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 16:55 ` Alan Mackenzie 2024-03-26 19:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-26 16:55 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Tue, Mar 26, 2024 at 09:40:19 -0400, Stefan Monnier wrote: > >> > Sorry about that. A quick summary: defined symbols (and lambda) get > >> > positioned by the new reader function read-positioning-defined symbols. > >> > The new declare clause defining-symbol marks a macro such as defun or > >> > cl-defgeneric as a macro which defines such symbols. > Since I still don't understand the general picture, let me tell you how > I would plan to do it, so you can tell me where it matches your > approach and where it doesn't: > - Change `load-source-file-function` so it uses > `read-positioning-symbols` instead of plain `read`. > [ This means that macro-expansion will now almost always have sympos, > rather than only during compilation, ] load-source-file-function is set to read-positioning-defined-symbols. (In a change to be committed, it gets bound to this function in Fload). In reading (defun foo () "foo doc" (lambda (bar) "lambda doc" (car bar))) , foo gets positioned (because it follows defun), and so does lambda (because it is a lambda following "("). > - This in turn requires a strip-sympos pass after the > eager-macroexpansion phase of `load-source-file-function`. No such pass is needed, due to the state machine in read-positioning-defined-symbols. > - Change macros like `lambda` so as to use the extract position info > from themselves/theirargs/thecontext (when available, since there will > still be corner cases where it's not available, such as during > non-eager macro expansion) .... The macro lambda has become obsolete; it had no access to the SWP lambda for which it was invoked. It has been replaced by code in macroexpand-1 and Fmacroexpand which wraps the lambda form in (function ....) and preserves the SWP lambda. I'm not entirely sure, but I think in non-eager macro expansion the position information in SWPs is typically available. > .... and stash it in their docstring. > This might be as simple as adding a line > (setq docstring (add-pos-to-docstring docstring ARG)). This posification is done (mainly) in a call to byte-run-posify-lambda-form from the (function (lambda ...)) pcase arm in macroexp--expand-all. > - Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 16:55 ` Alan Mackenzie @ 2024-03-26 19:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 20:21 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 19:40 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> >> > Sorry about that. A quick summary: defined symbols (and lambda) get >> >> > positioned by the new reader function read-positioning-defined symbols. >> >> > The new declare clause defining-symbol marks a macro such as defun or >> >> > cl-defgeneric as a macro which defines such symbols. > >> Since I still don't understand the general picture, let me tell you how >> I would plan to do it, so you can tell me where it matches your >> approach and where it doesn't: > >> - Change `load-source-file-function` so it uses >> `read-positioning-symbols` instead of plain `read`. >> [ This means that macro-expansion will now almost always have sympos, >> rather than only during compilation, ] > > load-source-file-function is set to read-positioning-defined-symbols. [ I see it's `load-read-function`. ] How does this differ from `read-positioning-symbols` and why do we need it to be different? > (In a change to be committed, it gets bound to this function in Fload). > In reading > > (defun foo () "foo doc" (lambda (bar) "lambda doc" (car bar))) > > , foo gets positioned (because it follows defun), and so does lambda > (because it is a lambda following "("). IIUC "gets positioned" means that it is a symbol-with-pos rather than a bare symbol? > I'm not entirely sure, but I think in non-eager macro expansion the > position information in SWPs is typically available. In lazy macro-expansion, SWPs are not available, no. But that's OK, it's rare and there's very little we can do about it (the reason it's lazy is indeed because we only discover very late that those sexps were meant to represent code. It's typically when a sexp is passed to `eval`). Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 19:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 20:21 ` Alan Mackenzie 2024-03-26 20:42 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-26 20:21 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Tue, Mar 26, 2024 at 15:40:05 -0400, Stefan Monnier wrote: > >> >> > Sorry about that. A quick summary: defined symbols (and lambda) get > >> >> > positioned by the new reader function read-positioning-defined symbols. > >> >> > The new declare clause defining-symbol marks a macro such as defun or > >> >> > cl-defgeneric as a macro which defines such symbols. > >> Since I still don't understand the general picture, let me tell you how > >> I would plan to do it, so you can tell me where it matches your > >> approach and where it doesn't: > >> - Change `load-source-file-function` so it uses > >> `read-positioning-symbols` instead of plain `read`. > >> [ This means that macro-expansion will now almost always have sympos, > >> rather than only during compilation, ] > > load-source-file-function is set to read-positioning-defined-symbols. > [ I see it's `load-read-function`. ] Yes! > How does this differ from `read-positioning-symbols` and why do we need > it to be different? r-p-defined-s positions only lambdas and NAMEs defined by defun, defmacro, defvar, .... (around 50 defining symbols). r-p-s positions every symbol apart from nil. They have different purposes. r-p-d-s gets info for the doc strings, which requires SWPs only for some symbols. r-p-s is needed to get warning message locations. Were r-p-s used for the doc string position information, most of the symbols would need to be stripped of their positions before the form could be used. It is simpler and faster not to position them at all. > > (In a change to be committed, it gets bound to this function in Fload). > > In reading > > (defun foo () "foo doc" (lambda (bar) "lambda doc" (car bar))) > > , foo gets positioned (because it follows defun), and so does lambda > > (because it is a lambda following "("). > IIUC "gets positioned" means that it is a symbol-with-pos rather than > a bare symbol? Yes. > > I'm not entirely sure, but I think in non-eager macro expansion the > > position information in SWPs is typically available. > In lazy macro-expansion, SWPs are not available, no. > But that's OK, it's rare and there's very little we can do about it (the > reason it's lazy is indeed because we only discover very late that those > sexps were meant to represent code. It's typically when a sexp is > passed to `eval`). OK. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 20:21 ` Alan Mackenzie @ 2024-03-26 20:42 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-27 3:35 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 20:42 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > r-p-defined-s positions only lambdas and NAMEs defined by defun, > defmacro, defvar, .... (around 50 defining symbols). r-p-s positions > every symbol apart from nil. They have different purposes. r-p-d-s > gets info for the doc strings, which requires SWPs only for some > symbols. r-p-s is needed to get warning message locations. Were r-p-s > used for the doc string position information, most of the symbols would > need to be stripped of their positions before the form could be used. > It is simpler and faster not to position them at all. In terms of code, I can't see why it'd be simpler: we already have the r-p-s function, and we already have a function to strip that info when we don't need it any more, so it would be less new code to write if we just used r-p-s, I think. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 20:42 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-27 3:35 ` Alan Mackenzie 2024-03-27 12:23 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-27 3:35 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Tue, Mar 26, 2024 at 16:42:28 -0400, Stefan Monnier wrote: > > r-p-defined-s positions only lambdas and NAMEs defined by defun, > > defmacro, defvar, .... (around 50 defining symbols). r-p-s positions > > every symbol apart from nil. They have different purposes. r-p-d-s > > gets info for the doc strings, which requires SWPs only for some > > symbols. r-p-s is needed to get warning message locations. Were r-p-s > > used for the doc string position information, most of the symbols would > > need to be stripped of their positions before the form could be used. > > It is simpler and faster not to position them at all. > In terms of code, I can't see why it'd be simpler: we already have the > r-p-s function, .... We also already have r-p-d-s. Both functions (together with plain read) have read0 as their core engine. The enhancement to read0 to support r-p-d-s was only moderate in size and not complicated to anybody who understands finite state machines. > .... and we already have a function to strip that info when we don't > need it any more, so it would be less new code to write if we just > used r-p-s, I think. I think you're envisaging an extensive redesign where SWPs would not be tightly and individually controlled as they are at the moment, but instead would be created en masse and stripped en masse a bit later. There seems to me to be little justification for this. It would need more code in byte-run.el, and would be slower, too. It would take a lot of work to implement and debug. At the moment, some SWPs (to do with "complicated" backquoted lambda forms) survive long term, meaning we would need complicated Lisp code to protect these individually. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-27 3:35 ` Alan Mackenzie @ 2024-03-27 12:23 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-27 22:00 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-27 12:23 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> > r-p-defined-s positions only lambdas and NAMEs defined by defun, >> > defmacro, defvar, .... (around 50 defining symbols). r-p-s positions >> > every symbol apart from nil. They have different purposes. r-p-d-s >> > gets info for the doc strings, which requires SWPs only for some >> > symbols. r-p-s is needed to get warning message locations. Were r-p-s >> > used for the doc string position information, most of the symbols would >> > need to be stripped of their positions before the form could be used. >> > It is simpler and faster not to position them at all. >> In terms of code, I can't see why it'd be simpler: we already have the >> r-p-s function, .... > We also already have r-p-d-s. You're playing on words here: we don't "already have" `r-p-d-s` on master. > Both functions (together with plain read) have read0 as their core > engine. The enhancement to read0 to support r-p-d-s was only moderate > in size and not complicated to anybody who understands finite > state machines. Just because it's not a complex change doesn't mean it's "simpler" than no change at all. >> .... and we already have a function to strip that info when we don't >> need it any more, so it would be less new code to write if we just >> used r-p-s, I think. > I think you're envisaging an extensive redesign where SWPs would not be > tightly and individually controlled as they are at the moment, but > instead would be created en masse and stripped en masse a bit later. Yes, that's the starting design I had in mind (and that I described a few emails back). it's also what we do in the byte-compilation case, so it's code we already have and use. The "en masse" doesn't make it complex. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-27 12:23 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-27 22:00 ` Alan Mackenzie 0 siblings, 0 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-03-27 22:00 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Wed, Mar 27, 2024 at 08:23:52 -0400, Stefan Monnier wrote: > >> > r-p-defined-s positions only lambdas and NAMEs defined by defun, > >> > defmacro, defvar, .... (around 50 defining symbols). r-p-s positions > >> > every symbol apart from nil. They have different purposes. r-p-d-s > >> > gets info for the doc strings, which requires SWPs only for some > >> > symbols. r-p-s is needed to get warning message locations. Were r-p-s > >> > used for the doc string position information, most of the symbols would > >> > need to be stripped of their positions before the form could be used. > >> > It is simpler and faster not to position them at all. > >> In terms of code, I can't see why it'd be simpler: we already have the > >> r-p-s function, .... > > We also already have r-p-d-s. > You're playing on words here: we don't "already have" `r-p-d-s` on master. I'm not playing on words. My point is that read-positioning-defined-symbols exists and works. It is not a speculative "would be nice to have". The work has already been done. > > Both functions (together with plain read) have read0 as their core > > engine. The enhancement to read0 to support r-p-d-s was only moderate > > in size and not complicated to anybody who understands finite > > state machines. > Just because it's not a complex change doesn't mean it's "simpler" than > no change at all. No change isn't an option, here. Something has to determine which symbols are to be positioned / stripped of their positions. Currently, this is done economically in r-p-d-s. > >> .... and we already have a function to strip that info when we don't > >> need it any more, so it would be less new code to write if we just > >> used r-p-s, I think. > > I think you're envisaging an extensive redesign where SWPs would not be > > tightly and individually controlled as they are at the moment, but > > instead would be created en masse and stripped en masse a bit later. > Yes, that's the starting design I had in mind (and that I described > a few emails back). it's also what we do in the byte-compilation case, ... It's not. In each case, the optimum number of symbols gets positioned. Positioning "everything" is sub-optimal for everything bar byte compilation. > so it's code we already have and use. See above. > The "en masse" doesn't make it complex. It changes the design extensively, thus introducing new complications. Why do you think this design change will be better than the existing design? > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 9:48 ` Alan Mackenzie 2024-03-26 13:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 20:30 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 21:13 ` Drew Adams 2024-03-27 10:04 ` Alan Mackenzie 1 sibling, 2 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 20:30 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > We now have two distinct uses of SWPs: providing warning source locations > to the compiler (where we want to keep the position as long as possible) > and providing position information for the doc string (where we want to > strip the position from the symbol ASAP, to avoid trying to use the SWP > when we need a plain symbol). If both of these occur together, we want > to keep the SWP. I think I'm beginning to understand. So in the "load from source case", some of your symbols are SWPs and you want to turn them into bare symbols "on the fly" during macro-expansion rather than via a separate "strip" phase, so you want the macro expansion to know whether it's done for "load from source" or for some other purpose and you use `byte-compile-in-progress` as a proxy for that information. Is that it? If so, (and if the stripping happens within macros), then indeed passing it as a separate argument through all the recursive calls to `macroexp--expand-all` would be cumbersome. But I suggest you use another name for that(e.g. `macroexp-strip-position`) so the intention is made more clear. Better yet: to avoid the problem of dynamic scope extending "too far" (i.e. accidentally applying to nested loads/evals/compile/...), you could put the relevant info into `macroexpand-all-environment`. [ That var is also dynamically bound, but we're already careful to rebind it when needed so it doesn't apply to nested uses of macroexpansion. ] >> > By "currently", I mean that a defining form such as defun or defvar has >> > commenced, but not yet terminated; its functions currently occupy stack >> > frames. >> So you mean we're inside `Fdefalias` or `Fdefvar_1`? > Yes, or inside a macro (defun, defmacro, ...) which expands to a > defalias. These are *very* different times: `Fdefalias` and `Fdefvar_1` are executed long after macroexpansion. And they're small C functions which run almost no external code at all, so they "occupy stack frames" only for a very short time. My crystal ball suggests that "currently" may be the wrong way to think about it: maybe instead of thinking of "when" (as in "during the definition of function FOO") what you're looking for might be "where" (as in "within the body of FOO"). [ That's the same difference as the difference between dynamic and static scoping. ] If my crystal ball is right, then the better place to put that info is probably `macroexpand-all-environment`. > Ideally, I would like to have bound defining-symbol inside defun. (defmacro my-defun (name args &rest body) `(cl-macrolet ((defining-symbol () '',name)) (defun ,name ,args ,@body))) (my-defun my-foo (x) (list x (defining-symbol))) (symbol-function 'my-foo) ==> #f(lambda (x) [t] (list x 'my-foo)) `cl-macrolet` uses `macroexpand-all-environment` for that. > Fload uses read-positioning-DEFINED-symbols, as contrasted with the > compiler, which uses read-positioning-symbols. r-p-d-s positions only > lambdas and NAMEs. r-p-s positions all symbols except nil. I think I'm beginning to understand (I guess I was struggling with your use of "position" as a verb for some reason which made me think that symbols were being moved rather than gaining position information). So, IIUC you use `read-positioning-DEFINED-symbols` instead of `read-positioning-symbols` because it's cheaper? Do you have rough numbers comparing the cost of `read`, `read-positioning-symbols`, and `read-positioning-DEFINED-symbols`? Also, IIUC you don't have a separate phase to strip the SWPs when loading from source, but instead you strip them as you "consume" their info during macroexpansion. If so, how/when/where do you strip the false positives that may occur inside quoted data or in code like: (defmacro foo (lambda bar) ...) (defmacro foo (defun bar) ...) (let* ((lambda foo) (defun bar)) ...) > Ah, right. I hadn't considered this before. The changes are by their > very nature essentially complicated and difficult to understand. [ Hmm... maybe not the best salespitch. ] >> I think you can simply wait to add the entry to >> `macro-declarations-alist` until a later time, so the `defining-symbol` >> thingies will be ignored during the early bootstrap and once we have >> more infrastructure in place we can then register the handler on >> `macro-declarations-alist`. > > This will not be simpler. It would involve re-evaluating defun, then > compensating for all the functions up to now whose NAMEs had been read > without positions. Not at all. Those will remain without position, but only in `src/bootstrap-emacs`. In the real `src/emacs` they will get the position because they'll come from the `.el[cn]` file and by the time we get compile those files `macro-declarations-alist` will be fully populated. > There is unavoidable conplexity, here. I'm definitely not convinced. I suspect you've been asking yourself "can it be made simpler" and you may indeed then convince yourself that the answer is no, because of assumptions you don't reconsider. Try instead to think about "what would it take to remove that complexity?". > I see things somewhat differently. We shouldn't increase the debugging > burden even on "expert users". Yet it's imposing more complexity (and hence more debugging burden) on those same expert users. 🙁 Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 20:30 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-26 21:13 ` Drew Adams 2024-03-27 10:04 ` Alan Mackenzie 1 sibling, 0 replies; 65+ messages in thread From: Drew Adams @ 2024-03-26 21:13 UTC (permalink / raw) To: Stefan Monnier, Alan Mackenzie; +Cc: Eli Zaretskii, 67455@debbugs.gnu.org > I think I'm beginning to understand (I guess I was struggling with your > use of "position" as a verb for some reason which made me think that > symbols were being moved rather than gaining position information). Not following this thread (at all). I suggest that for the new meaning ("gaining position info") you use the (just minted) verb "positionize" instead of "position". Or some other change in vocabulary. ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-26 20:30 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 21:13 ` Drew Adams @ 2024-03-27 10:04 ` Alan Mackenzie 2024-03-27 12:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-27 10:04 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Tue, Mar 26, 2024 at 16:30:06 -0400, Stefan Monnier wrote: > > We now have two distinct uses of SWPs: providing warning source locations > > to the compiler (where we want to keep the position as long as possible) > > and providing position information for the doc string (where we want to > > strip the position from the symbol ASAP, to avoid trying to use the SWP > > when we need a plain symbol). If both of these occur together, we want > > to keep the SWP. > I think I'm beginning to understand. So in the "load from source case", > some of your symbols are SWPs and you want to turn them into bare > symbols "on the fly" during macro-expansion rather than via a separate > "strip" phase, .... More precisely, to @dfn{posify} their containing forms by writing the position information into their doc strings. We do this in the byte compilation case, too. The difference is that in the "load from source" case we want to strip the SWP, in byte compilation, we don't. > .... so you want the macro expansion to know whether it's done > for "load from source" or for some other purpose and you use > `byte-compile-in-progress` as a proxy for that information. > Is that it? More or less. But byte-compile-in-progress isn't a proxy, it's the prime criterion for deciding. > If so, (and if the stripping happens within macros), then indeed passing > it as a separate argument through all the recursive calls to > `macroexp--expand-all` would be cumbersome. But I suggest you use > another name for that(e.g. `macroexp-strip-position`) so the > intention is made more clear. I don't think that is a good name. The byte compiler has no business setting "internal" variables for the posification processing. Instead it should announce it's running and expect the posification to respect that. I think byte-compile-in-progress is a good name for this. > Better yet: to avoid the problem of dynamic scope extending "too far" > (i.e. accidentally applying to nested loads/evals/compile/...), you > could put the relevant info into `macroexpand-all-environment`. > [ That var is also dynamically bound, but we're already careful to > rebind it when needed so it doesn't apply to nested uses > of macroexpansion. ] That variable is only loaded in the 17th loaded Lisp file. The new facility should be working at the earliest stages of loading Lisp, as it does at the moment. Besides, macroexpand-all-environment is not documented anywhere, what it is, what it's for, etc. > >> > By "currently", I mean that a defining form such as defun or defvar has > >> > commenced, but not yet terminated; its functions currently occupy stack > >> > frames. > >> So you mean we're inside `Fdefalias` or `Fdefvar_1`? > > Yes, or inside a macro (defun, defmacro, ...) which expands to a > > defalias. > These are *very* different times: `Fdefalias` and `Fdefvar_1` are > executed long after macroexpansion. And they're small C functions which > run almost no external code at all, so they "occupy stack frames" only > for a very short time. I think we were talking about the handling of defining-symbol. It has a valid binding outside of macros such as defun, and this binding is used to posify the containing form. > My crystal ball suggests that "currently" may be the wrong way to think > about it: maybe instead of thinking of "when" (as in "during the > definition of function FOO") what you're looking for might be "where" > (as in "within the body of FOO"). > [ That's the same difference as the difference between dynamic and > static scoping. ] I'm having trouble understanding what you're saying, here. > If my crystal ball is right, then the better place to put that info is > probably `macroexpand-all-environment`. See above. > > Ideally, I would like to have bound defining-symbol inside defun. > (defmacro my-defun (name args &rest body) > `(cl-macrolet ((defining-symbol () '',name)) > (defun ,name ,args ,@body))) > (my-defun my-foo (x) (list x (defining-symbol))) > (symbol-function 'my-foo) > ==> #f(lambda (x) [t] (list x 'my-foo)) > `cl-macrolet` uses `macroexpand-all-environment` for that. cl-macs gets loaded far too late for such an approach to be useful. > > Fload uses read-positioning-DEFINED-symbols, as contrasted with the > > compiler, which uses read-positioning-symbols. r-p-d-s positions only > > lambdas and NAMEs. r-p-s positions all symbols except nil. > I think I'm beginning to understand (I guess I was struggling with your > use of "position" as a verb for some reason which made me think that > symbols were being moved rather than gaining position information). Sorry about that. > So, IIUC you use `read-positioning-DEFINED-symbols` instead of > `read-positioning-symbols` because it's cheaper? No, because it does the Right Thing. > Do you have rough numbers comparing the cost of `read`, > `read-positioning-symbols`, and `read-positioning-DEFINED-symbols`? No, but they will be very close to eachother (and very cheap) since they use the same engine, read0 (in lread.c). Each of them will be one or two orders of magnitude faster than emulating them in Lisp. > Also, IIUC you don't have a separate phase to strip the SWPs when > loading from source, but instead you strip them as you "consume" their > info during macroexpansion. If so, how/when/where do you strip the > false positives that may occur inside quoted data or in code like: > (defmacro foo (lambda bar) ...) > (defmacro foo (defun bar) ...) > (let* ((lambda foo) > (defun bar)) > ...) There's a pcase arm right at the end of macroexp--expand-all which strips SWPs of their positions. Recursing through macroexp--all-forms will eventually hit this pcase arm for these lambdas. > > Ah, right. I hadn't considered this before. The changes are by their > > very nature essentially complicated and difficult to understand. > [ Hmm... maybe not the best salespitch. ] ;-) It's the truth, though. > >> I think you can simply wait to add the entry to > >> `macro-declarations-alist` until a later time, so the `defining-symbol` > >> thingies will be ignored during the early bootstrap and once we have > >> more infrastructure in place we can then register the handler on > >> `macro-declarations-alist`. > > This will not be simpler. It would involve re-evaluating defun, then > > compensating for all the functions up to now whose NAMEs had been read > > without positions. > Not at all. Those will remain without position, but only in > `src/bootstrap-emacs`. This would be a Bad Thing. The current code is active right after loading byte-run. > In the real `src/emacs` they will get the position because they'll come > from the `.el[cn]` file and by the time we get compile those files > `macro-declarations-alist` will be fully populated. The understanding we reached in November was that loading from source files would be handled, too. > > There is unavoidable conplexity, here. > I'm definitely not convinced. I suspect you've been asking yourself > "can it be made simpler" and you may indeed then convince yourself that > the answer is no, because of assumptions you don't reconsider. > Try instead to think about "what would it take to remove that complexity?". > > I see things somewhat differently. We shouldn't increase the debugging > > burden even on "expert users". > Yet it's imposing more complexity (and hence more debugging burden) on > those same expert users. 🙁 That's a fairly difficult philosophical question. Do we provide full functionality at the cost of more (difficult) source code, or do we restrict the functioality to keep the source simpler? I think with Emacs we usually go with the first alternative. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-27 10:04 ` Alan Mackenzie @ 2024-03-27 12:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-27 21:43 ` Alan Mackenzie 2024-06-02 13:38 ` Alan Mackenzie 0 siblings, 2 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-27 12:22 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > More precisely, to @dfn{posify} their containing forms by writing the > position information into their doc strings. We do this in the byte > compilation case, too. The difference is that in the "load from source" > case we want to strip the SWP, in byte compilation, we don't. [ Nitpick: in byte-compilation, we also do. We want to keep the SWPs longer, but in the end we also want to strip them away necause we don't want them in the resulting compiled code. ] > I don't think that is a good name. The byte compiler has no business > setting "internal" variables for the posification processing. Instead it > should announce it's running and expect the posification to respect that. > I think byte-compile-in-progress is a good name for this. AFAIK we want those SWPs stripped if and only if we're in a "load from source" case. The compilation case is one of those where we don't want to strip them, but it's not the only one, so the compiler should not do anything w.r.t to that. Instead it's the code that does the "load from source" which should set some indicator that stripping is requested. Also, I think as a general rule it's better for the caller to set a callee variable that controls how the callee behaves, rather than for the callee to check a caller variable to decide how to behave, because it's normal for the caller to "know about" its callee (after all, it's the caller which decides to call the callee), whereas it's not normal for the callee to know about specific callers (it creates undesirable dependencies). >> Better yet: to avoid the problem of dynamic scope extending "too far" >> (i.e. accidentally applying to nested loads/evals/compile/...), you >> could put the relevant info into `macroexpand-all-environment`. >> [ That var is also dynamically bound, but we're already careful to >> rebind it when needed so it doesn't apply to nested uses >> of macroexpansion. ] > > That variable is only loaded in the 17th loaded Lisp file. The new > facility should be working at the earliest stages of loading Lisp, as it > does at the moment. The earlier the better, in theory, but not at any cost. Having to write all that code within the very restrictive sublanguage available before subr.el and backquote.el is a cost I don't think justifies it. If we *really* want that, then we should explore other avenues, such as keeping pre-macroexpanded versions of the files (for bootstrapping purposes) but generating those files from files where a more normal coding style can be used. [ Something similar to the ldefs-boot.el. ] > Besides, macroexpand-all-environment is not > documented anywhere, what it is, what it's for, etc. Feel free to disregard my advice if you don't like it. I'm just pointing out that it's probably the tool which gives you the semantics you want. >> My crystal ball suggests that "currently" may be the wrong way to think >> about it: maybe instead of thinking of "when" (as in "during the >> definition of function FOO") what you're looking for might be "where" >> (as in "within the body of FOO"). >> [ That's the same difference as the difference between dynamic and >> static scoping. ] > I'm having trouble understanding what you're saying, here. Is it because you don't understand the difference between dynamic scoping and static scoping, or because you don't see the relationship with that and your notion of "currently being defined"? The above citation is in the context of my question about what you mean by "currently" in: doc: /* The symbol currently being defined by a defining form. I personally don't really understand it, and AFAICT, you don't really understand it either because you haven't been able to describe it. >> > Ideally, I would like to have bound defining-symbol inside defun. > >> (defmacro my-defun (name args &rest body) >> `(cl-macrolet ((defining-symbol () '',name)) >> (defun ,name ,args ,@body))) > >> (my-defun my-foo (x) (list x (defining-symbol))) > >> (symbol-function 'my-foo) >> ==> #f(lambda (x) [t] (list x 'my-foo)) > >> `cl-macrolet` uses `macroexpand-all-environment` for that. > > cl-macs gets loaded far too late for such an approach to be useful. That's not really relevant since we're just trying to understand what you mean by "currently". What is relevant is whether it gives the intended semantics. But if you insist, here's the equivalent version without `cl-macs` (using the same underlying technique as used by `cl-macrolet`): (defmacro my-defun (name args &rest body) (macroexpand-all `(defun ,name ,args ,@body) (cons (cons 'defining-symbol (lambda () `',name)) macroexpand-all-environment))) >> Do you have rough numbers comparing the cost of `read`, >> `read-positioning-symbols`, and `read-positioning-DEFINED-symbols`? > No, but they will be very close to eachother (and very cheap) Then I think we should use `read-positioning-symbols`, which requires fewer code changes. >> Also, IIUC you don't have a separate phase to strip the SWPs when >> loading from source, but instead you strip them as you "consume" their >> info during macroexpansion. If so, how/when/where do you strip the >> false positives that may occur inside quoted data or in code like: > >> (defmacro foo (lambda bar) ...) >> (defmacro foo (defun bar) ...) > >> (let* ((lambda foo) >> (defun bar)) >> ...) > > There's a pcase arm right at the end of macroexp--expand-all which strips > SWPs of their positions. Recursing through macroexp--all-forms will > eventually hit this pcase arm for these lambdas. Ah, so it's like a "strip phase" but "fused" into the macroexpansion phase. >> Not at all. Those will remain without position, but only in >> `src/bootstrap-emacs`. > This would be a Bad Thing. But your current code in byte-run.el is a Bad Thing as well. It's all a question of trade-offs :-( >> In the real `src/emacs` they will get the position because they'll come >> from the `.el[cn]` file and by the time we get compile those files >> `macro-declarations-alist` will be fully populated. > The understanding we reached in November was that loading from source > files would be handled, too. I'm not suggesting to drop support for lambdas loaded from source. I'm saying we don't need to support it for the first N files loaded into `src/emacs-bootstrap`. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-27 12:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-27 21:43 ` Alan Mackenzie 2024-03-28 16:25 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-06-02 13:38 ` Alan Mackenzie 1 sibling, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-27 21:43 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Wed, Mar 27, 2024 at 08:22:27 -0400, Stefan Monnier wrote: > > More precisely, to @dfn{posify} their containing forms by writing the > > position information into their doc strings. We do this in the byte > > compilation case, too. The difference is that in the "load from source" > > case we want to strip the SWP, in byte compilation, we don't. > [ Nitpick: in byte-compilation, we also do. We want to keep the SWPs > longer, but in the end we also want to strip them away necause we don't > want them in the resulting compiled code. ] In byte compilation we want to keeo the SWPs for AS LONG AS POSSIBLE. In other cases, we want to keep them for AS SHORT A TIME AS POSSIBLE. > > I don't think that is a good name. The byte compiler has no business > > setting "internal" variables for the posification processing. Instead it > > should announce it's running and expect the posification to respect that. > > I think byte-compile-in-progress is a good name for this. > AFAIK we want those SWPs stripped if and only if we're in a "load from > source" case. The compilation case is one of those where we don't want > to strip them, but it's not the only one, so the compiler should not do > anything w.r.t to that. Instead it's the code that does the "load from > source" which should set some indicator that stripping is requested. I think it is better to regard the byte compilation as the special case. Only in byte compilation do we want to preserve the SWPs on forms getting posified. > Also, I think as a general rule it's better for the caller to set > a callee variable that controls how the callee behaves, rather than for the > callee to check a caller variable to decide how to behave, because > it's normal for the caller to "know about" its callee (after all, it's > the caller which decides to call the callee), whereas it's not normal > for the callee to know about specific callers (it creates undesirable > dependencies). Byte compilation is NOT calling loading from source. We don't have a caller/callee relationship here. We are doing posification either from byte compilation or from somewhere else. It is analogous to testing lexical binding. Here, the variable is called lexical-binding; it is not named after a particular activity to be carried out differently for l-b and not l-b. > >> Better yet: to avoid the problem of dynamic scope extending "too far" > >> (i.e. accidentally applying to nested loads/evals/compile/...), you > >> could put the relevant info into `macroexpand-all-environment`. > >> [ That var is also dynamically bound, but we're already careful to > >> rebind it when needed so it doesn't apply to nested uses > >> of macroexpansion. ] > > That variable is only loaded in the 17th loaded Lisp file. The new > > facility should be working at the earliest stages of loading Lisp, as it > > does at the moment. > The earlier the better, in theory, but not at any cost. No, the earlier the better, full stop. The earlier an error happens in bootstrapping, the more important it is to provide debugging support. The new facilities were exceptionally helpful whilst debugging the partially finished code. > Having to write all that code within the very restrictive sublanguage > available before subr.el and backquote.el is a cost I don't think > justifies it. The cost has already been paid, by me. The cost of maintaining that code will be small by comparison; byte-run--posify-defining-form is _not_ all that difficult to understand and amend. > If we *really* want that, then we should explore other avenues, such as > keeping pre-macroexpanded versions of the files (for bootstrapping > purposes) but generating those files from files where a more normal > coding style can be used. > [ Something similar to the ldefs-boot.el. ] Possibly - but that will also introduce complications. > > Besides, macroexpand-all-environment is not > > documented anywhere, what it is, what it's for, etc. > Feel free to disregard my advice if you don't like it. > I'm just pointing out that it's probably the tool which gives you the > semantics you want. OK. > >> My crystal ball suggests that "currently" may be the wrong way to think > >> about it: maybe instead of thinking of "when" (as in "during the > >> definition of function FOO") what you're looking for might be "where" > >> (as in "within the body of FOO"). > >> [ That's the same difference as the difference between dynamic and > >> static scoping. ] > > I'm having trouble understanding what you're saying, here. > Is it because you don't understand the difference between dynamic > scoping and static scoping, or because you don't see the relationship > with that and your notion of "currently being defined"? The latter, I think. defining-symbol is entirely dynamically scoped. > The above citation is in the context of my question about what you mean > by "currently" in: > doc: /* The symbol currently being defined by a defining form. > I personally don't really understand it, and AFAICT, you don't really > understand it either because you haven't been able to describe it. I understand it fully. I'm puzzled by your failure to understand what I've written. The flow goes as follows: (i) defining-symbol gets bound to nil in readevalloop_eager_eval_loop. (ii) d-s gets setq'd to NAME in defun, defvar, cl-defgeneric, ..... Usually, the setq has been generated by byte-run--posify-defining-form. (iii) d-s gets used in byte-run-posify-doc-string, which writes its details to a new or existing doc string. By "currently", I mean that d-s holds NAME between (ii) and (iii) and until the process of defining the new form is complete. > >> > Ideally, I would like to have bound defining-symbol inside defun. > >> (defmacro my-defun (name args &rest body) > >> `(cl-macrolet ((defining-symbol () '',name)) > >> (defun ,name ,args ,@body))) > >> (my-defun my-foo (x) (list x (defining-symbol))) > >> (symbol-function 'my-foo) > >> ==> #f(lambda (x) [t] (list x 'my-foo)) > >> `cl-macrolet` uses `macroexpand-all-environment` for that. > > cl-macs gets loaded far too late for such an approach to be useful. > That's not really relevant since we're just trying to understand what > you mean by "currently". What is relevant is whether it gives > the intended semantics. I'm convinced it does. Can you suggest a scenario where the defining-symbol mechanism (outlined above) might fail? > But if you insist, here's the equivalent version without `cl-macs` > (using the same underlying technique as used by `cl-macrolet`): > (defmacro my-defun (name args &rest body) > (macroexpand-all > `(defun ,name ,args ,@body) > (cons > (cons 'defining-symbol (lambda () `',name)) > macroexpand-all-environment))) Thanks. > >> Do you have rough numbers comparing the cost of `read`, > >> `read-positioning-symbols`, and `read-positioning-DEFINED-symbols`? > > No, but they will be very close to eachother (and very cheap) > Then I think we should use `read-positioning-symbols`, which > requires fewer code changes. It won't. Required would be Lisp code to determine whether a particular SWP needs to be stripped or not. This is not going to be simple. It is likely to be about as complicated as the existing enhancements to read0. > >> Also, IIUC you don't have a separate phase to strip the SWPs when > >> loading from source, but instead you strip them as you "consume" their > >> info during macroexpansion. If so, how/when/where do you strip the > >> false positives that may occur inside quoted data or in code like: > >> (defmacro foo (lambda bar) ...) > >> (defmacro foo (defun bar) ...) > >> (let* ((lambda foo) > >> (defun bar)) > >> ...) > > There's a pcase arm right at the end of macroexp--expand-all which strips > > SWPs of their positions. Recursing through macroexp--all-forms will > > eventually hit this pcase arm for these lambdas. > Ah, so it's like a "strip phase" but "fused" into the macroexpansion phase. I suppose so. > >> Not at all. Those will remain without position, but only in > >> `src/bootstrap-emacs`. > > This would be a Bad Thing. > But your current code in byte-run.el is a Bad Thing as well. What, precisely, do you find bad about it? It may be possible to improve it without wholesale redesign. > It's all a question of trade-offs :-( > >> In the real `src/emacs` they will get the position because they'll come > >> from the `.el[cn]` file and by the time we get compile those files > >> `macro-declarations-alist` will be fully populated. > > The understanding we reached in November was that loading from source > > files would be handled, too. > I'm not suggesting to drop support for lambdas loaded from source. > I'm saying we don't need to support it for the first N files loaded into > `src/emacs-bootstrap`. You're suggesting dropping support for many source files, where that support is most needed. You're suggesting introducing awkward special cases where the code won't work. As currently implemented, the code DOES work. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-27 21:43 ` Alan Mackenzie @ 2024-03-28 16:25 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-28 16:48 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors ` (3 more replies) 0 siblings, 4 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-28 16:25 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > I think it is better to regard the byte compilation as the special case. > Only in byte compilation do we want to preserve the SWPs on forms > getting posified. [...] > Byte compilation is NOT calling loading from source. We don't have a > caller/callee relationship here. We are doing posification either from The "callee" I'm talking about is `load-source-file-function` (which is instead another "caller", beside the byte compiler), it is the code that tests `byte-compile-in-progress`. Based on the above two elements, I suggest the name `macroexp--inhibit-strip-sympos` (and set/pass/bind it as needed in the compiler). [ FWIW, the reason I associate this variable with `load-source-file-function` rather than with the compiler is because the macroexp code which tests this variable only strips the SWPs at a very few different spots, more specifically those very spots that are expected to get SWPs in the `load-source-file-function`. Different minds work differently, I guess. 🙂 ] >> Also, I think as a general rule it's better for the caller to set >> a callee variable that controls how the callee behaves, rather than for the >> callee to check a caller variable to decide how to behave, because >> it's normal for the caller to "know about" its callee (after all, it's >> the caller which decides to call the callee), whereas it's not normal >> for the callee to know about specific callers (it creates undesirable >> dependencies). > byte compilation or from somewhere else. It is analogous to testing > lexical binding. Here, the variable is called lexical-binding; it is > not named after a particular activity to be carried out differently for > l-b and not l-b. Indeed testing `lexical-binding` in macros (like we do at a few places) sucks; it's an ugly hack. We use it because that was the least bad option we could come up with given the need to preserve backward compatibility. Here there's no such problem. >> The earlier the better, in theory, but not at any cost. > No, the earlier the better, full stop. Please "full stop" being absolutist. We're talking about opinions and preferences here. When hitting an error, I spend more time reading the code (and modifying it) than looking at debug output, so to me the clarity of the code is more important than whether a few lambdas get some addition positional info, especially since I usually know full well where those lambdas come from. I understand it affects us differently, but the tradeoff is real. >> Having to write all that code within the very restrictive sublanguage >> available before subr.el and backquote.el is a cost I don't think >> justifies it. > The cost has already been paid, by me. Code is not "fire and forget". >> >> My crystal ball suggests that "currently" may be the wrong way to think >> >> about it: maybe instead of thinking of "when" (as in "during the >> >> definition of function FOO") what you're looking for might be "where" >> >> (as in "within the body of FOO"). >> >> [ That's the same difference as the difference between dynamic and >> >> static scoping. ] >> > I'm having trouble understanding what you're saying, here. >> Is it because you don't understand the difference between dynamic >> scoping and static scoping, or because you don't see the relationship >> with that and your notion of "currently being defined"? > The latter, I think. defining-symbol is entirely dynamically scoped. We're still miscommunicating. You're talking about how your code is implemented, apparently, whereas I'm asking about what is the intended behavior. It's like I'm asking what the C spec says and you're answering me by telling me how GCC works. > I'm convinced it does. Can you suggest a scenario where the > defining-symbol mechanism (outlined above) might fail? Without knowing what it is intended to do, the only thing we can say is that it does what it does, so no indeed it won't fail to do what it does, since that's what it does. 🙂 >> >> Do you have rough numbers comparing the cost of `read`, >> >> `read-positioning-symbols`, and `read-positioning-DEFINED-symbols`? >> > No, but they will be very close to eachother (and very cheap) >> Then I think we should use `read-positioning-symbols`, which >> requires fewer code changes. > It won't. Required would be Lisp code to determine whether a particular > SWP needs to be stripped or not. This is not going to be simple. It is > likely to be about as complicated as the existing enhancements to read0. They'd all need to be stripped, AFAICT, so we'd do: (strip-all-symbol-positions (macroexp--expand-all (read-positioning-symbols))) What would be hard about it? >> >> Also, IIUC you don't have a separate phase to strip the SWPs when >> >> loading from source, but instead you strip them as you "consume" their >> >> info during macroexpansion. If so, how/when/where do you strip the >> >> false positives that may occur inside quoted data or in code like: > >> >> (defmacro foo (lambda bar) ...) >> >> (defmacro foo (defun bar) ...) > >> >> (let* ((lambda foo) >> >> (defun bar)) >> >> ...) > >> > There's a pcase arm right at the end of macroexp--expand-all which strips >> > SWPs of their positions. Recursing through macroexp--all-forms will >> > eventually hit this pcase arm for these lambdas. Actually, now that I look at the code I only see: ((guard (and (not byte-compile-in-progress) (symbol-with-pos-p form))) (bare-symbol form)) is that the "arm" you're talking about? AFAICT this will handle only those symbols which appear as Lisp expressions (IOW symbols which are variable references), so it will strip the `bar` in the second example but not the `bar` in my first exmple, nor the two `lambda`s, nor those in '(lambda (defun bar)) >> But your current code in byte-run.el is a Bad Thing as well. > What, precisely, do you find bad about it? It may be possible to improve > it without wholesale redesign. A lot of it is hard to read because it is constrained to a restrictive subset of ELisp. >> I'm not suggesting to drop support for lambdas loaded from source. >> I'm saying we don't need to support it for the first N files loaded into >> `src/emacs-bootstrap`. > You're suggesting dropping support for many source files, where that > support is most needed. "Most needed" according to which criteria? > I'm not playing on words. My point is that > read-positioning-defined-symbols exists and works. It is not a > speculative "would be nice to have". The work has already been done. Code costs by merely existing. > Why do you think this design change will be better than the existing > design? I don't actually know whether it will be better. It just seems it could lead to simpler code, with no change at all to the reader, for example. I'm here asking what lead you to the current design, under the assumption that the complexity you introduced was the result of other experiments. Am I to understand that the current code is basically your first attempt at adding such functionality? Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-28 16:25 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-28 16:48 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-30 9:10 ` Alan Mackenzie ` (2 subsequent siblings) 3 siblings, 0 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-28 16:48 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > The "callee" I'm talking about is `load-source-file-function` (which is ^^^ not > instead another "caller", beside the byte compiler), it is the > code that tests `byte-compile-in-progress`. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-28 16:25 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-28 16:48 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-30 9:10 ` Alan Mackenzie 2024-03-30 9:53 ` Alan Mackenzie 2024-03-30 11:03 ` Alan Mackenzie 3 siblings, 0 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-03-30 9:10 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Thu, Mar 28, 2024 at 12:25:11 -0400, Stefan Monnier wrote: [ .... ] > >> The earlier the better, in theory, but not at any cost. > > No, the earlier the better, full stop. > Please "full stop" being absolutist. We're talking about opinions and > preferences here. What you're proposing is only handling some fuctions because you think we're collectively not clever enough to maintain byte-run--posify-defining-form. This would leave Emacs inconsistent, some functions failing to be handled not for any functional reason, but because of an alleged lack of our capability. > When hitting an error, I spend more time reading the code (and modifying > it) than looking at debug output, so to me the clarity of the code is > more important than whether a few lambdas get some addition positional > info, especially since I usually know full well where those lambdas > come from. My prime method of debugging is reading code, too. But you're conflating the clarity of b-r--p-defining-f with the clarity of the code you're debugging. They're different things. The former is less important than the latter. The whole point in these changes is to give info precisely in those anonymous lambda entries in backtraces which currently contain no information. > I understand it affects us differently, but the tradeoff is real. > >> Having to write all that code within the very restrictive sublanguage > >> available before subr.el and backquote.el is a cost I don't think > >> justifies it. This is done in other functions, too. > > The cost has already been paid, by me. > Code is not "fire and forget". [ .... ] > >> But your current code in byte-run.el is a Bad Thing as well. > > What, precisely, do you find bad about it? It may be possible to improve > > it without wholesale redesign. > A lot of it is hard to read because it is constrained to a restrictive > subset of ELisp. byte-run--posify-defining-form uses the same techniques as other declare clause handlers, such as byte-run--set-interactive-only and many others. Why is b-r--p-defining-f objectionable, but not b-r--s-i-only? It was tedious rather than difficult to write, and it is tedious rather than difficult to read. > >> I'm not suggesting to drop support for lambdas loaded from source. > >> I'm saying we don't need to support it for the first N files loaded into > >> `src/emacs-bootstrap`. > > You're suggesting dropping support for many source files, where that > > support is most needed. > "Most needed" according to which criteria? The difficulty of debugging in early bootstrap compared with when further debugging tools have already been loaded. [ .... ] > Code costs by merely existing. Inconsistencies and sloppy implementation cost too. [ .... ] > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-28 16:25 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-28 16:48 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-30 9:10 ` Alan Mackenzie @ 2024-03-30 9:53 ` Alan Mackenzie 2024-03-31 2:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-30 11:03 ` Alan Mackenzie 3 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-30 9:53 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Thu, Mar 28, 2024 at 12:25:11 -0400, Stefan Monnier wrote: [ .... ] > >> >> My crystal ball suggests that "currently" may be the wrong way to think > >> >> about it: maybe instead of thinking of "when" (as in "during the > >> >> definition of function FOO") what you're looking for might be "where" > >> >> (as in "within the body of FOO"). > >> >> [ That's the same difference as the difference between dynamic and > >> >> static scoping. ] > >> > I'm having trouble understanding what you're saying, here. > >> Is it because you don't understand the difference between dynamic > >> scoping and static scoping, or because you don't see the relationship > >> with that and your notion of "currently being defined"? > > The latter, I think. defining-symbol is entirely dynamically scoped. > We're still miscommunicating. You're talking about how your code is > implemented, apparently, whereas I'm asking about what is the > intended behavior. I am still mystified by your failure to understand "currently being defined", a phrase that to me could hardly be clearer. > It's like I'm asking what the C spec says and you're answering me by > telling me how GCC works. OK, let's try again. defining-symbol records the symbol currently being defined. It's used to set the defining symbol and buffer offset fields in the position structure in that symbol's doc string, and also in the doc strings of contained lambda forms. > > I'm convinced it does. Can you suggest a scenario where the > > defining-symbol mechanism (outlined above) might fail? > Without knowing what it is intended to do, the only thing we can say is > that it does what it does, so no indeed it won't fail to do what it > does, since that's what it does. 🙂 Is my previous paragraph sufficiently clear? If so, can you envisage a scenario where a symbol being defined would fail to get the two fields correctly set in its doc string or a lambda form's doc string? [ .... ] > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-30 9:53 ` Alan Mackenzie @ 2024-03-31 2:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-04-07 11:35 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-31 2:22 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> We're still miscommunicating. You're talking about how your code is >> implemented, apparently, whereas I'm asking about what is the >> intended behavior. > I am still mystified by your failure to understand "currently being > defined", a phrase that to me could hardly be clearer. AFAIK, the definition itself happens inside `Fdefalias`. It's a very short amount of time during which none of your code is executed, so that can't be it. The rest is the actual construction of the value/function object which will make up the definition. This construction is done piecemeal in various phases at potentially various different times, not all of them necessarily on the same machine. Some of the code executed during the course of the construction of this object have nothing at all to do with that object, they just happen to be used by some code which participates in the construction of that object. So "currently" (i.e. referring to *time*) is very problematic because it's only loosely correlated to what you're interested in. >> It's like I'm asking what the C spec says and you're answering me by >> telling me how GCC works. > > OK, let's try again. defining-symbol records the symbol currently being > defined. It's used to set the defining symbol and buffer offset fields > in the position structure in that symbol's doc string, and also in the > doc strings of contained lambda forms. I can try it again also if you want: to do it right, I think you want to store that information in `macroexpand-all-environment`. > Is my previous paragraph sufficiently clear? If so, can you envisage a > scenario where a symbol being defined would fail to get the two fields > correctly set in its doc string or a lambda form's doc string? Yes, for example I can imagine a lazy macroexpansion done to run some code during the eager macroexpansion could mistakenly think that it is part of the eagerly macroexpanded function (whereas it's only part of the code used during the construction of that function). I'm sure there are other cases, by thinking of it makes my head hurt. Which is why I recommend you put that info into `macroexpand-all-environment` which is designed specifically for such purpose of "currently within the scope of something". Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-31 2:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-07 11:35 ` Alan Mackenzie 2024-04-08 2:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-04-07 11:35 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Sat, Mar 30, 2024 at 22:22:52 -0400, Stefan Monnier wrote: > >> We're still miscommunicating. You're talking about how your code is > >> implemented, apparently, whereas I'm asking about what is the > >> intended behavior. > > I am still mystified by your failure to understand "currently being > > defined", a phrase that to me could hardly be clearer. > AFAIK, the definition itself happens inside `Fdefalias`. It's a very > short amount of time during which none of your code is executed, so that > can't be it. The definition starts when the reader reads (defun foo ...). It ends when that Fdefalias has been evaluated. Between those two events, defining-symbol is bound to foo. > The rest is the actual construction of the value/function object which > will make up the definition. This construction is done piecemeal in > various phases at potentially various different times, not all of them > necessarily on the same machine. Really? :-) > Some of the code executed during the course of the construction of this > object have nothing at all to do with that object, they just happen to > be used by some code which participates in the construction of that > object. That's a bit too abstract. I can't see the potential problems that you see, possibly because I've already solved them. > So "currently" (i.e. referring to *time*) is very problematic because > it's only loosely correlated to what you're interested in. Again, I don't see these problems. > >> It's like I'm asking what the C spec says and you're answering me by > >> telling me how GCC works. > > OK, let's try again. defining-symbol records the symbol currently being > > defined. It's used to set the defining symbol and buffer offset fields > > in the position structure in that symbol's doc string, and also in the > > doc strings of contained lambda forms. > I can try it again also if you want: to do it right, I think you want to > store that information in `macroexpand-all-environment`. That variable doesn't exist, yet. > > Is my previous paragraph sufficiently clear? If so, can you envisage a > > scenario where a symbol being defined would fail to get the two fields > > correctly set in its doc string or a lambda form's doc string? > Yes, for example I can imagine a lazy macroexpansion done to run some > code during the eager macroexpansion could mistakenly think that it is > part of the eagerly macroexpanded function (whereas it's only part of > the code used during the construction of that function). The critical thing here is the variable defining-symbol. I think you're suggesting that its value could accidentally find its way into other symbols' position structures. When are those other symbols getting defined? Surely if a secondary defun, defmacro, defvar, ... happens during the main defun, its defining symbol is that of the main defun? > I'm sure there are other cases, by thinking of it makes my head hurt. > Which is why I recommend you put that info into > `macroexpand-all-environment` which is designed specifically for such > purpose of "currently within the scope of something". Well, m-a-e is defined too late. Even if it weren't, how would it solve any of these problems you see? It's just swapping one dynamically bound variable for another. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-04-07 11:35 ` Alan Mackenzie @ 2024-04-08 2:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-04-08 2:56 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-08 2:19 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > The definition starts when the reader reads (defun foo ...). It ends > when that Fdefalias has been evaluated. Between those two events, > defining-symbol is bound to foo. When the code is compiled, years can pass between those two events. > The critical thing here is the variable defining-symbol. I think you're > suggesting that its value could accidentally find its way into other > symbols' position structures. When are those other symbols getting > defined? Surely if a secondary defun, defmacro, defvar, ... happens > during the main defun, its defining symbol is that of the main defun? That secondary symbol might be defined by the macro for its own use, rather than for the use of the returned code. > Well, m-a-e is defined too late. According to your self-imposed rule 🙂 > Even if it weren't, how would it solve any of these problems you see? > It's just swapping one dynamically bound variable for another. Indeed, m-a-e has to fight the same issues, in theory, but in practice, those issues have already been addressed over the years. It's rebound to nil "all the time" to try and make sure its effect doesn't leak. BTW, it would be nice to separate your patches into some that add position info to lambda's docstring, and then others that add "defining symbol" to the available position info. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-04-08 2:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-08 2:56 ` Alan Mackenzie 2024-04-10 8:53 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-04-08 2:56 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Sun, Apr 07, 2024 at 22:19:28 -0400, Stefan Monnier wrote: > > The definition starts when the reader reads (defun foo ...). It ends > > when that Fdefalias has been evaluated. Between those two events, > > defining-symbol is bound to foo. > When the code is compiled, years can pass between those two events. Really? Then defining-symbol would stay bound over these years, too. Where's the problem? > > The critical thing here is the variable defining-symbol. I think you're > > suggesting that its value could accidentally find its way into other > > symbols' position structures. When are those other symbols getting > > defined? Surely if a secondary defun, defmacro, defvar, ... happens > > during the main defun, its defining symbol is that of the main defun? > That secondary symbol might be defined by the macro for its own use, > rather than for the use of the returned code. > > Well, m-a-e is defined too late. > According to your self-imposed rule 🙂 > > Even if it weren't, how would it solve any of these problems you see? > > It's just swapping one dynamically bound variable for another. > Indeed, m-a-e has to fight the same issues, in theory, but in practice, > those issues have already been addressed over the years. It's rebound > to nil "all the time" to try and make sure its effect doesn't leak. defining-symbol isn't bound like this, in order for its value to be available when needed. > BTW, it would be nice to separate your patches into some that add > position info to lambda's docstring, and then others that add > "defining symbol" to the available position info. All this could be moot. Byte compiling is appreciably slower on this branch than on master. make bootstrap is taking me nearly 7 minutes compared with master's 4min 40sec. Running make -j17 check is taking 1min 50sec rather than 50sec. Once compiled, the code runs at the same speed, though. I think this issue needs sorting out first. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-04-08 2:56 ` Alan Mackenzie @ 2024-04-10 8:53 ` Alan Mackenzie 0 siblings, 0 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-04-10 8:53 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Mon, Apr 08, 2024 at 02:56:20 +0000, Alan Mackenzie wrote: [ .... ] > Byte compiling is appreciably slower on this branch than on master. > make bootstrap is taking me nearly 7 minutes compared with master's > 4min 40sec. Running make -j17 check is taking 1min 50sec rather than > 50sec. Once compiled, the code runs at the same speed, though. > I think this issue needs sorting out first. I think I know now why this is. I put a call to byte-run-strip-symbol-positions into readevalloop_eager_expand_eval to get the thing to build. This is probably the cause of the slowdown. It is also surely what is stripping positions from non-function lambdas. This call needs to be taken out, and other things which need it (e.g. Fdefalias) fixed. > > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-28 16:25 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors ` (2 preceding siblings ...) 2024-03-30 9:53 ` Alan Mackenzie @ 2024-03-30 11:03 ` Alan Mackenzie 2024-03-31 2:54 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 3 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-30 11:03 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Thu, Mar 28, 2024 at 12:25:11 -0400, Stefan Monnier wrote: [ .... ] > >> >> Do you have rough numbers comparing the cost of `read`, > >> >> `read-positioning-symbols`, and `read-positioning-DEFINED-symbols`? > >> > No, but they will be very close to eachother (and very cheap) > >> Then I think we should use `read-positioning-symbols`, which > >> requires fewer code changes. > > It won't. Required would be Lisp code to determine whether a particular > > SWP needs to be stripped or not. This is not going to be simple. It is > > likely to be about as complicated as the existing enhancements to read0. > They'd all need to be stripped, AFAICT, so we'd do: > (strip-all-symbol-positions > (macroexp--expand-all > (read-positioning-symbols))) > What would be hard about it? Some symbols must not be stripped. For example, in cl-generic.el L403 we have: (fun `(cl-function (lambda ,plain-args ,@body))) .. There the position on the lambda must be preserved until ME2 time when it becomes clear what the shape of the lambda is. In particular, whether there is already a doc string in ,@body to amend, or we need to insert a new one. > >> >> Also, IIUC you don't have a separate phase to strip the SWPs when > >> >> loading from source, but instead you strip them as you "consume" their > >> >> info during macroexpansion. If so, how/when/where do you strip the > >> >> false positives that may occur inside quoted data or in code like: > >> >> (defmacro foo (lambda bar) ...) (defmacro foo (lambda bar) `(cons ,lambda ,bar)) exoands to (macro closure (t) (lambda bar) ";POS^^^A^A^A [foo *scratch* 158 nil] " (list 'cons lambda bar)) .. > >> >> (defmacro foo (defun bar) ...) > >> >> (let* ((lambda foo) > >> >> (defun bar)) > >> >> ...) Similarly, we get (defun baz () (let ((lambda 'foo) (defun 'bar)) (cons lambda defun))) (symbol-function 'baz) (closure (t) nil ";POS^^^A^A^A [baz *scratch* 323 nil] " (let ((lambda 'foo) (defun 'bar)) (cons lambda defun))) , so it is clear this case is getting handled OK. I'm afraid I can't point out the exact place in the code at the moment where this is getting done. > >> > There's a pcase arm right at the end of macroexp--expand-all which strips > >> > SWPs of their positions. Recursing through macroexp--all-forms will > >> > eventually hit this pcase arm for these lambdas. > Actually, now that I look at the code I only see: > ((guard (and (not byte-compile-in-progress) > (symbol-with-pos-p form))) > (bare-symbol form)) > is that the "arm" you're talking about? Yes. > AFAICT this will handle only those symbols which appear as Lisp > expressions (IOW symbols which are variable references), so it will > strip the `bar` in the second example but not the `bar` in my first > exmple, nor the two `lambda`s, nor those in > '(lambda (defun bar)) See above. [ .... ] > > Why do you think this design change will be better than the existing > > design? > I don't actually know whether it will be better. It just seems it could > lead to simpler code, with no change at all to the reader, for example. The exercise is intrinsically complicated. read0 is largely self contained, meaning any compexity introduced there won't spill over into other functions. What you're suggesting is that the code to decide which SWPs to strip is going to be simpler than the enhancements to the reader. > I'm here asking what lead you to the current design, under the > assumption that the complexity you introduced was the result of > other experiments. The complexity is essential to the task being done. I'm convinced it cannot be avoided, though it could be moved around the code base, to some extent. I don't have a record of the precise reasons for the design. To a large extent it was a sequence of solutions to the often awkward problems the code presented. > Am I to understand that the current code is basically your first attempt > at adding such functionality? By no means. This is the second implementation, the first having been rejected by Eli and you last autumn. I'm very much looking forward to not needing a third implementation. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-30 11:03 ` Alan Mackenzie @ 2024-03-31 2:54 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-04-07 10:57 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-31 2:54 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > Some symbols must not be stripped. For example, in cl-generic.el L403 > we have: > > (fun `(cl-function (lambda ,plain-args ,@body))) > > .. There the position on the lambda must be preserved until ME2 time > when it becomes clear what the shape of the lambda is. In particular, > whether there is already a doc string in ,@body to amend, or we need to > insert a new one. I could see some reasons you *may* want to keep some info here, but it's definitely not a "must" because the source position of those functions should generally not point to `cl-generic.el:403` but to where `cl-defmethod` was used. Also, if you do want to preserve some info there (presumably with the intent to combine it with the more important info that will be available at ME2) it will need cooperation from `cl-generic.el` because, as far as the semantic of Emacs Lisp is concerned, the above constructs a list with a `lambda` symbol inside of it, with no guarantee that it will be used as a function, and even if ever used as a function there's no guarantee that this list will pass through the few places where we strip SWPs, so keeping SWPs in there without some explicit request from `cl-generic.el` would be a bug. IOW, I don't think it's a good reason to rule out (strip-all-symbol-positions (macroexp--expand-all (read-positioning-symbols))) BTW, AFAIK the above is conceptually what the byte-compiler does (except it performs a few more transformations between `macroexp--expand-all` and `strip-all-symbol-positions`). Is it the case that `cl-defmethod` generates a function whose source position (partly) points to `generic.el:403` if `cl-generic.el` was interpreted but not if it compiled? >> >> >> Also, IIUC you don't have a separate phase to strip the SWPs when >> >> >> loading from source, but instead you strip them as you "consume" their >> >> >> info during macroexpansion. If so, how/when/where do you strip the >> >> >> false positives that may occur inside quoted data or in code like: > >> >> >> (defmacro foo (lambda bar) ...) > > (defmacro foo (lambda bar) > `(cons ,lambda ,bar)) > > exoands to > > (macro closure (t) (lambda bar) ";POS^^^A^A^A [foo *scratch* 158 nil] > " (list 'cons lambda bar)) IIUC your reader will make the `lambda` formal argument into an SWP. Where is that SWP stripped? > so it is clear this case is getting handled OK. I'm afraid I can't > point out the exact place in the code at the moment where this is > getting done. I think it would be good to know, so as to be able to decide whether it'll indeed always work right, or we just got lucky this time. >> I don't actually know whether it will be better. It just seems it could >> lead to simpler code, with no change at all to the reader, for example. > The exercise is intrinsically complicated. Could you explain what you think makes it intrinsically complex? > What you're suggesting is that the code to decide which SWPs to strip > is going to be simpler than the enhancements to the reader. As seen above, I suggest to leave the reader unchanged and to strip all SWPs. I'm pretty sure it would give comparable info to what you have and it would be simpler (also, it would make it much less likely to have discrepancies between the compiled case and the interpreted case). My main worry with it would be performance. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-31 2:54 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-07 10:57 ` Alan Mackenzie 2024-04-08 3:16 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-04-07 10:57 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. Sorry about the delay - I lost my email server after an obsolete SSL library got deleted from my system, and one or two other things, too. On Sat, Mar 30, 2024 at 22:54:18 -0400, Stefan Monnier wrote: > > Some symbols must not be stripped. For example, in cl-generic.el L403 > > we have: > > (fun `(cl-function (lambda ,plain-args ,@body))) > > .. There the position on the lambda must be preserved until ME2 time > > when it becomes clear what the shape of the lambda is. In particular, > > whether there is already a doc string in ,@body to amend, or we need to > > insert a new one. > I could see some reasons you *may* want to keep some info here, but it's > definitely not a "must" because the source position of those functions > should generally not point to `cl-generic.el:403` but to where > `cl-defmethod` was used. Pretending the problem doesn't exist won't solve it. In the ;POS... structures for a lambda, there are two pointers - one to the definition of the lambda, the other to the point of use. > Also, if you do want to preserve some info there (presumably with the > intent to combine it with the more important info that will be available > at ME2) it will need cooperation from `cl-generic.el` because, as far as > the semantic of Emacs Lisp is concerned, the above constructs a list > with a `lambda` symbol inside of it, with no guarantee that it will be > used as a function, .... Mostly there is the symbol `function' in that position. Here we've got `cl-function' which expands to function. Surely with (function (lambda ....)) we know we're dealing with a function. > .... and even if ever used as a function there's no guarantee that this > list will pass through the few places where we strip SWPs, so keeping > SWPs in there without some explicit request from `cl-generic.el` would > be a bug. I don't think this is right. The code will pass through macroexp--expand-all, which is where the SWP wii be stripped. > IOW, I don't think it's a good reason to rule out > (strip-all-symbol-positions > (macroexp--expand-all > (read-positioning-symbols))) As I've said, we'd need code to preserve the SWPs on "complicated" lambdas. I haven't even begun to think about how this could work. > BTW, AFAIK the above is conceptually what the byte-compiler does (except > it performs a few more transformations between `macroexp--expand-all` > and `strip-all-symbol-positions`). It is a bad idea to conflate these two radically different uses of SWPs. That can only lead to confusion and bugs. > Is it the case that `cl-defmethod` generates a function whose source > position (partly) points to `generic.el:403` if `cl-generic.el` was > interpreted but not if it compiled? No, the intention is that the source positions are independent of whether the code is compiled. > >> >> >> Also, IIUC you don't have a separate phase to strip the SWPs when > >> >> >> loading from source, but instead you strip them as you "consume" their > >> >> >> info during macroexpansion. If so, how/when/where do you strip the > >> >> >> false positives that may occur inside quoted data or in code like: > >> >> >> (defmacro foo (lambda bar) ...) > > (defmacro foo (lambda bar) > > `(cons ,lambda ,bar)) > > expands to > > (macro closure (t) (lambda bar) ";POS^^^A^A^A [foo *scratch* 158 nil] > > " (list 'cons lambda bar)) > IIUC your reader will make the `lambda` formal argument into an SWP. > Where is that SWP stripped? In macroexp--expand-all in the "guard arm" near the end. > > so it is clear this case is getting handled OK. I'm afraid I can't > > point out the exact place in the code at the moment where this is > > getting done. > I think it would be good to know, so as to be able to decide whether > it'll indeed always work right, or we just got lucky this time. See above. > >> I don't actually know whether it will be better. It just seems it could > >> lead to simpler code, with no change at all to the reader, for example. > > The exercise is intrinsically complicated. > Could you explain what you think makes it intrinsically complex? The mass of detail that needs dealing with that Emacs has collected over the decades. As a counter question, why do you think the exercise ought to be simple (assuming you do think this)? > > What you're suggesting is that the code to decide which SWPs to strip > > is going to be simpler than the enhancements to the reader. > As seen above, I suggest to leave the reader unchanged and to strip all > SWPs. I'm pretty sure it would give comparable info to what you have > and it would be simpler (also, it would make it much less likely to > have discrepancies between the compiled case and the interpreted case). "Comparable" isn't good enough - we need the position info on "complicated" lambdas to endure, somehow. There are no discrepancies between compiled and interpreted forms because they both use the same mechanism in macro expansion. > My main worry with it would be performance. Yhat, too. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-04-07 10:57 ` Alan Mackenzie @ 2024-04-08 3:16 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-04-08 8:32 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-08 3:16 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > Pretending the problem doesn't exist won't solve it. In the ;POS... > structures for a lambda, there are two pointers - one to the definition > of the lambda, the other to the point of use. Fancy. Could you give me an example where I see this in play? [ To help me understand also what you mean by "definition of the lambda" and "point of use"? ] I looked around but all I could see where position info like [foo foo.el 41 nil] which point to "the definition" of the function. >> BTW, AFAIK the above is conceptually what the byte-compiler does (except >> it performs a few more transformations between `macroexp--expand-all` >> and `strip-all-symbol-positions`). > It is a bad idea to conflate these two radically different uses of SWPs. In what way are they radically different uses of SWPs? >> Is it the case that `cl-defmethod` generates a function whose source >> position (partly) points to `generic.el:403` if `cl-generic.el` was >> interpreted but not if it compiled? > No, the intention is that the source positions are independent of whether > the code is compiled. Good. So why do the interpreted and compiled cases need to be "radically different uses of SWPs"? >> > (defmacro foo (lambda bar) >> > `(cons ,lambda ,bar)) > >> > expands to > >> > (macro closure (t) (lambda bar) ";POS^^^A^A^A [foo *scratch* 158 nil] >> > " (list 'cons lambda bar)) > >> IIUC your reader will make the `lambda` formal argument into an SWP. >> Where is that SWP stripped? > > In macroexp--expand-all in the "guard arm" near the end. How? `macroexp--expand-all` will not be passed this `lambda` because it's not an *expression*. `eval-buffer` of a buffer containing the above defmacro does: 1 -> (macroexp--expand-all (defalias 'foo (cons 'macro #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" `(cons ,lambda ,bar))))) | 2 -> (macroexp--expand-all 'foo) | 2 <- macroexp--expand-all: 'foo | 2 -> (macroexp--expand-all (cons 'macro #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" `(cons ,lambda ,bar)))) | | 3 -> (macroexp--expand-all 'macro) | | 3 <- macroexp--expand-all: 'macro | | 3 -> (macroexp--expand-all #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" `(cons ,lambda ,bar))) | | | 4 -> (macroexp--expand-all ";POS\x01\x01 [foo foo.el 41 nil]\n") | | | 4 <- macroexp--expand-all: ";POS\x01\x01 [foo foo.el 41 nil]\n" | | | 4 -> (macroexp--expand-all `(cons ,lambda ,bar)) | | | | 5 -> (macroexp--expand-all 'cons) | | | | 5 <- macroexp--expand-all: 'cons | | | | 5 -> (macroexp--expand-all lambda) | | | | 5 <- macroexp--expand-all: lambda | | | | 5 -> (macroexp--expand-all bar) | | | | 5 <- macroexp--expand-all: bar | | | 4 <- macroexp--expand-all: (list 'cons lambda bar) | | 3 <- macroexp--expand-all: #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" (list 'cons lambda bar)) | 2 <- macroexp--expand-all: (cons 'macro #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" (list 'cons lambda bar))) 1 <- macroexp--expand-all: (defalias 'foo (cons 'macro #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" (list 'cons lambda bar)))) So we see that indeed it returns code where the formal argument `lambda` is (incorrectly) a SYMPOS. Yet somehow the sympos is stripped after macroexpansion somewhere since `(symbol-function 'foo)` shows the resulting function doesn't have any symposes in it. >> > so it is clear this case is getting handled OK. I'm afraid I can't >> > point out the exact place in the code at the moment where this is >> > getting done. >> I think it would be good to know, so as to be able to decide whether >> it'll indeed always work right, or we just got lucky this time. > See above. Yes, please, see above 🙂 >> Could you explain what you think makes it intrinsically complex? > The mass of detail that needs dealing with that Emacs has collected over > the decades. As a counter question, why do you think the exercise ought > to be simple (assuming you do think this)? Because you solved the hard part when you added the symposes for the compiler. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-04-08 3:16 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-08 8:32 ` Alan Mackenzie 2024-04-08 12:00 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-04-08 8:32 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Sun, Apr 07, 2024 at 23:16:13 -0400, Stefan Monnier wrote: > > Pretending the problem doesn't exist won't solve it. In the ;POS... > > structures for a lambda, there are two pointers - one to the definition > > of the lambda, the other to the point of use. > Fancy. Could you give me an example where I see this in play? > [ To help me understand also what you mean by "definition of the > lambda" and "point of use"? ] > I looked around but all I could see where position info like > [foo foo.el 41 nil] > which point to "the definition" of the function. Apologies. I was thinking of my latest not yet committed version, where I've added a fifth element into the position information, the buffer containing the lambda. This should enable buttons to be set on the interactive backtrace, pointing back at the two source code positions. > >> BTW, AFAIK the above is conceptually what the byte-compiler does (except > >> it performs a few more transformations between `macroexp--expand-all` > >> and `strip-all-symbol-positions`). > > It is a bad idea to conflate these two radically different uses of SWPs. > In what way are they radically different uses of SWPs? You're confused in precisely the way I feared. "conceptually what the byte-compiler does" is what it does to strip the SWPs used as WARNING POSITIONS. When the SWPs are used for function position structures (whether in interpreted or compiled code) the handling is radically different - the P in the SWP is stripped as soon as possible after its use. In the warning pos use, the positions are preserved for as long as possible. > >> Is it the case that `cl-defmethod` generates a function whose source > >> position (partly) points to `generic.el:403` if `cl-generic.el` was > >> interpreted but not if it compiled? > > No, the intention is that the source positions are independent of whether > > the code is compiled. > Good. So why do the interpreted and compiled cases need to be > "radically different uses of SWPs"? They're not. It is the use for warning positions that differs from the use for putting pos info into the doc string. > >> > (defmacro foo (lambda bar) > >> > `(cons ,lambda ,bar)) > >> > expands to > >> > (macro closure (t) (lambda bar) ";POS^^^A^A^A [foo *scratch* 158 nil] > >> > " (list 'cons lambda bar)) > >> IIUC your reader will make the `lambda` formal argument into an SWP. > >> Where is that SWP stripped? > > In macroexp--expand-all in the "guard arm" near the end. > How? `macroexp--expand-all` will not be passed this `lambda` because > it's not an *expression*. Well, when I commented out that pcase arm, the lambda no longer got stripped. I'm not sure what you mean by expression. > `eval-buffer` of a buffer containing the above defmacro does: > 1 -> (macroexp--expand-all (defalias 'foo (cons 'macro #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" `(cons ,lambda ,bar))))) > | 2 -> (macroexp--expand-all 'foo) > | 2 <- macroexp--expand-all: 'foo > | 2 -> (macroexp--expand-all (cons 'macro #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" `(cons ,lambda ,bar)))) > | | 3 -> (macroexp--expand-all 'macro) > | | 3 <- macroexp--expand-all: 'macro > | | 3 -> (macroexp--expand-all #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" `(cons ,lambda ,bar))) > | | | 4 -> (macroexp--expand-all ";POS\x01\x01 [foo foo.el 41 nil]\n") > | | | 4 <- macroexp--expand-all: ";POS\x01\x01 [foo foo.el 41 nil]\n" > | | | 4 -> (macroexp--expand-all `(cons ,lambda ,bar)) > | | | | 5 -> (macroexp--expand-all 'cons) > | | | | 5 <- macroexp--expand-all: 'cons > | | | | 5 -> (macroexp--expand-all lambda) > | | | | 5 <- macroexp--expand-all: lambda > | | | | 5 -> (macroexp--expand-all bar) > | | | | 5 <- macroexp--expand-all: bar > | | | 4 <- macroexp--expand-all: (list 'cons lambda bar) > | | 3 <- macroexp--expand-all: #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" (list 'cons lambda bar)) > | 2 <- macroexp--expand-all: (cons 'macro #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" (list 'cons lambda bar))) > 1 <- macroexp--expand-all: (defalias 'foo (cons 'macro #'{foo} (lambda (#<symbol lambda at 46> bar) ";POS\x01\x01 [foo foo.el 41 nil]\n" (list 'cons lambda bar)))) > So we see that indeed it returns code where the formal argument `lambda` > is (incorrectly) a SYMPOS. Yet somehow the sympos is stripped after > macroexpansion somewhere since `(symbol-function 'foo)` shows the > resulting function doesn't have any symposes in it. OK, this needs clearing up. > >> > so it is clear this case is getting handled OK. I'm afraid I can't > >> > point out the exact place in the code at the moment where this is > >> > getting done. > >> I think it would be good to know, so as to be able to decide whether > >> it'll indeed always work right, or we just got lucky this time. > > See above. > Yes, please, see above 🙂 > >> Could you explain what you think makes it intrinsically complex? > > The mass of detail that needs dealing with that Emacs has collected over > > the decades. As a counter question, why do you think the exercise ought > > to be simple (assuming you do think this)? > Because you solved the hard part when you added the symposes for the compiler. OK, but that's not the way things turned out. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-04-08 8:32 ` Alan Mackenzie @ 2024-04-08 12:00 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 0 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-08 12:00 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> How? `macroexp--expand-all` will not be passed this `lambda` because >> it's not an *expression*. > Well, when I commented out that pcase arm, the lambda no longer got > stripped. I'm not sure what you mean by expression. In Edebug specs we call it `form`. The ((x 3) (y 4)) in a `let` is not an expression, for example. (4 . 5) could appear in a piece of code in the position where we expect an expression but it is not a valid expression (it will result in a syntax error at compile- or run-time). The grammar of ELisp is made of various elements, one of which would traditionally be called "expressions". If we could specify it in EBNF it could look something like the following: <formalargs> ::= "(" <id>* [ "&optional" <id>* [ "&rest" <id> ]] ")" <decls> ::= "(" <decl>* ")" <decl> ::= <id> | "(" <id> <exp> ")" <func> ::= <id> | "(" "lambda" <formalargs> <exp>* ")" ... <exp> ::= <id> | "(" <func> <exp>* ")" | "(" "quote" <sexp> ")" | "(" "let" <decls> <exp>* ")" | "(" "function" <func> ")" | ... Only the <exp> parts go through `macroexp--expand-all`. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-27 12:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-27 21:43 ` Alan Mackenzie @ 2024-06-02 13:38 ` Alan Mackenzie 2024-06-03 4:52 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-06-02 13:38 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Wed, Mar 27, 2024 at 08:22:27 -0400, Stefan Monnier wrote: A bit of context: back in March, you took exception to the extensive hand expanded backquote forms in byte-run--posify-defining-form, on the ground that such code was too awkward for maintenance. I insisted that the function was needed by the macro defun. We ended up not agreeing. [ .... ] > The earlier the better, in theory, but not at any cost. Having to write > all that code within the very restrictive sublanguage available before > subr.el and backquote.el is a cost I don't think justifies it. > If we *really* want that, then we should explore other avenues, such as > keeping pre-macroexpanded versions of the files (for bootstrapping > purposes) but generating those files from files where a more normal > coding style can be used. > [ Something similar to the ldefs-boot.el. ] The solution now seems obvious: In loadup.el, we should load backquote.el before byte-run.el, and rewrite all our hand expanded backquotes in byte-run.el (including in byte-run--posify-defining-form) as actual backquote forms. backquote.el doesn't actually need anything in byte-run.el bar the macro defun itself. It would be a simple job to replace each (defun backquote-foo ...) in the file with (defalias 'backquote-foo #'(lambda ....)). What do you think? [ .... ] > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-06-02 13:38 ` Alan Mackenzie @ 2024-06-03 4:52 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-06-05 15:01 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-03 4:52 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > The solution now seems obvious: In loadup.el, we should load > backquote.el before byte-run.el, and rewrite all our hand expanded > backquotes in byte-run.el (including in byte-run--posify-defining-form) > as actual backquote forms. > > backquote.el doesn't actually need anything in byte-run.el bar the macro > defun itself. It would be a simple job to replace each (defun > backquote-foo ...) in the file with (defalias 'backquote-foo #'(lambda > ....)). Well, it uses both `defun` and `defmacro`. But rather than hand-expand them, we might be able to get the same result by prepending some minimal definitions of those two, as in: (if (fboundp 'defun) nil ;; This file is loaded before `byte-run.el' so when loading the .el ;; file, defun/defmacro may not be defined yet, so we provide ;; some minimalist fallback replacement. (fset 'defmacro (cons 'macro #'(lambda (name args &rest body) (list 'defalias (list 'quote name) (list 'cons ''macro (list 'function (cons 'lambda (cons args body)))))))) (defmacro defun (name args &rest body) (list 'defalias (list 'quote name) (list 'function (cons 'lambda (cons args body)))))) These would be used only at the beginning of the bootstrap and thus shouldn't affect the final `src/emacs`. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-06-03 4:52 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-05 15:01 ` Alan Mackenzie 0 siblings, 0 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-06-05 15:01 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Mon, Jun 03, 2024 at 00:52:07 -0400, Stefan Monnier wrote: > > The solution now seems obvious: In loadup.el, we should load > > backquote.el before byte-run.el, and rewrite all our hand expanded > > backquotes in byte-run.el (including in byte-run--posify-defining-form) > > as actual backquote forms. > > backquote.el doesn't actually need anything in byte-run.el bar the macro > > defun itself. It would be a simple job to replace each (defun > > backquote-foo ...) in the file with (defalias 'backquote-foo #'(lambda > > ....)). > Well, it uses both `defun` and `defmacro`. Yes, my mistake. But that doesn't change the thrust of my last post. > But rather than hand-expand them, we might be able to get the same > result by prepending some minimal definitions of those two, as in: > (if (fboundp 'defun) nil > ;; This file is loaded before `byte-run.el' so when loading the .el > ;; file, defun/defmacro may not be defined yet, so we provide > ;; some minimalist fallback replacement. > (fset 'defmacro > (cons 'macro > #'(lambda (name args &rest body) > (list 'defalias (list 'quote name) > (list 'cons ''macro > (list 'function > (cons 'lambda (cons args body)))))))) > (defmacro defun (name args &rest body) > (list 'defalias (list 'quote name) > (list 'function (cons 'lambda (cons args body)))))) > These would be used only at the beginning of the bootstrap and thus > shouldn't affect the final `src/emacs`. I'm not sure whether or not it's worth constructing these temporary macros defmacro and defun - We've only got 2 defmacros and 4 defuns for them to process, after all. But I'm glad you seem to agree with the idea as a way of getting rid of the extensive hand expanded backquote forms in byte-run.el. By the way, I'm still working on the feature/positioned-lambda branch after finding a bug there. I'll get around to answering your reply to my earlier post soon, hopefully. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-10 17:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-10 19:22 ` Alan Mackenzie @ 2024-03-10 22:27 ` Alan Mackenzie 2024-03-11 0:50 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-10 22:27 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello again, Stefan. On Sun, Mar 10, 2024 at 13:19:03 -0400, Stefan Monnier wrote: [ .... ] > >> - My gut tells me that changing backquote can't be right. > > I tend to agree. I put the code into backquote-process when having > > problems with things like: > > (mapatoms #'(lambda (,(car spec)) ,@body) [ .... ] > >> (lambda (f) ..) *can* appear within a backquote without it being an > >> actual lambda expression. > >> What alternatives have you considered? > > Not a lot of them, as yet. Maybe testing for (function (lambda ...)) > > would be safer. > No matter how many extra tests you add to reduce the frequency, you're > fundamentally adding a bug :-( Well, macroexp--expand-all has treated (function (lambda ...)) as a function long before I started on this project in November. Would trusting the same thing in backquote-process be any more dangerous? Anyway, I've started looking at getting that extra code out of backquote.el. Simply commenting it out produces build time errors, which shows that it's not totally redundant. How about adding (an) extra arm(s) to the large pcase in macroexp--expand-all which would recognise backquote's output for "evaluated" lambdas. What we get back from backquote looks like: (cons 'lambda (cons plain-args body)) or (list 'lambda args)) or maybe one or two other forms. So I could extend such code fragments to add posification code quite easily. I'm not sure it'd be more elegant than what's currently in backquote.el, though. I think I'll give it a try. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-10 22:27 ` Alan Mackenzie @ 2024-03-11 0:50 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-13 10:54 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-11 0:50 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 >> No matter how many extra tests you add to reduce the frequency, you're >> fundamentally adding a bug :-( > > Well, macroexp--expand-all has treated (function (lambda ...)) as a > function long before I started on this project in November. Of course it does, and that's correct, because by definition the argument to `macroexp--expand-all` must be source code expression. > Would trusting the same thing in backquote-process be any > more dangerous? Yup, because backquote has no guarantee that the code it must produce is one that will build a source code expression. > How about adding (an) extra arm(s) to the large pcase in > macroexp--expand-all which would recognise backquote's output for > "evaluated" lambdas. > > What we get back from backquote looks like: > > (cons 'lambda (cons plain-args body)) or > (list 'lambda args)) or maybe one or two other forms. Same problem: (cons 'lambda (cons plain-args body)) constructs something that may look like a function but that may not be intended to be used as a function. All we know is that it should build a list with a `lambda` symbol in it. It's only when the result of the execution of this code is passed to `macroexp--expand-all` that we discover that it was meant to build a list that represents the source code of a function; and only at *that* point are we allowed to modify that list by macro-expanding expressions in its body, modifying its docstring, byte-compiling, etc... Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-11 0:50 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-13 10:54 ` Alan Mackenzie 2024-03-13 11:52 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-13 10:54 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Sun, Mar 10, 2024 at 20:50:05 -0400, Stefan Monnier wrote: > >> No matter how many extra tests you add to reduce the frequency, you're > >> fundamentally adding a bug :-( > > Well, macroexp--expand-all has treated (function (lambda ...)) as a > > function long before I started on this project in November. > Of course it does, and that's correct, because by definition the > argument to `macroexp--expand-all` must be source code expression. > > Would trusting the same thing in backquote-process be any > > more dangerous? > Yup, because backquote has no guarantee that the code it must produce is > one that will build a source code expression. > > How about adding (an) extra arm(s) to the large pcase in > > macroexp--expand-all which would recognise backquote's output for > > "evaluated" lambdas. > > What we get back from backquote looks like: > > (cons 'lambda (cons plain-args body)) or > > (list 'lambda args)) or maybe one or two other forms. > Same problem: > (cons 'lambda (cons plain-args body)) > constructs something that may look like a function but that may not be > intended to be used as a function. All we know is that it should build > a list with a `lambda` symbol in it. > It's only when the result of the execution of this code is passed to > `macroexp--expand-all` that we discover that it was meant to build > a list that represents the source code of a function; and only at *that* > point are we allowed to modify that list by macro-expanding expressions > in its body, modifying its docstring, byte-compiling, etc... OK, so it seems like I'll need a new pcase arm in macroexp--expand-all, and this new code will need to handle (function (cons 'lambda ...)), and the like. I'll not actually be able to do too much in the next few days, though. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-13 10:54 ` Alan Mackenzie @ 2024-03-13 11:52 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-19 16:18 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-13 11:52 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > OK, so it seems like I'll need a new pcase arm in macroexp--expand-all, > and this new code will need to handle (function (cons 'lambda ...)), and > the like. If macroexp--expand-all receives code of the form (function (cons 'lambda ...)) it means it received broken code. IOW, such an arm will never do anything useful (the best it can do is emit a warning). I suspect what you're looking for is yet different. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-13 11:52 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-19 16:18 ` Alan Mackenzie 2024-03-19 20:47 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 65+ messages in thread From: Alan Mackenzie @ 2024-03-19 16:18 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello Stefan. On Wed, Mar 13, 2024 at 07:52:50 -0400, Stefan Monnier wrote: > > OK, so it seems like I'll need a new pcase arm in macroexp--expand-all, > > and this new code will need to handle (function (cons 'lambda ...)), and > > the like. > If macroexp--expand-all receives code of the form > (function (cons 'lambda ...)) > it means it received broken code. > IOW, such an arm will never do anything useful (the best it can do is > emit a warning). > I suspect what you're looking for is yet different. How about the following (as yet vague) idea? (i) Amend backquote slightly so that the integer part of the result of backquote-process gets transmitted to the caller, somehow. This would let macroexp--expand-all know it's dealing with smething awkward like `#'(lambda ,@args . ,body). (ii) On encountering such, m--e-all would insert a call to (new macro) macroexp--maybe-posify-lamda-form at ME1 time. (iii) At ME2 time, m--e-all should be able to tell whether or not the lambda form is "real". In this case the macro would be replaced by a call to (existing) byte-run--posify-lambda-position. Whether or not this is done, the SWP lambda would be stripped of its position. This might work. What do you think? > Stefan -- Alan Mackenzie (Nuremberg, Germany) ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-19 16:18 ` Alan Mackenzie @ 2024-03-19 20:47 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-19 21:40 ` Alan Mackenzie 0 siblings, 1 reply; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-19 20:47 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > This might work. What do you think? I don't know what is the problem you're trying to fix, so it's hard for me to have an opinion. Could you clarify what is the problem when backquote is not changed at all (after all, this is the problem that will also occur if the programmer happened to use `cons/list` instead of backquote)? Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-19 20:47 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-19 21:40 ` Alan Mackenzie 2024-03-19 22:32 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-24 11:21 ` Alan Mackenzie 0 siblings, 2 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-03-19 21:40 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Tue, Mar 19, 2024 at 16:47:46 -0400, Stefan Monnier wrote: > > This might work. What do you think? > I don't know what is the problem you're trying to fix, so it's hard for > me to have an opinion. > Could you clarify what is the problem when backquote is not changed > at all (after all, this is the problem that will also occur if the > programmer happened to use `cons/list` instead of backquote)? When Lisp gets read for interpretation, defined symbols (e.g. folliowing defun or cl-defgneric) get positioned, as do lambdas. When there are ,s or ,@s on the arg list or the doc string of the lambda, the lambda currently gets posified by the new code in backquote-process. Without the new code, the "complicated" lambdas retain their positions, which cause errors in pdump, which doesn't (and shouldn't) handle SWPs. You're right about my sketched approach not working if the programmer uses cons/list instead of `, ,, and ,@. (Thanks!) Maybe I can somehow wait until (cons 'lambda (cons args body)) has been evaluated in ME2, before posifying the lambda. And also take the change out of backquote-process. With this idea, most of the new code would go into the (`(function ,(and f `(lambda ,_ . ,_))) ...) pcase arm of macrexp--expand-all, with possibly a new arm to catch and "neutralise" the remaining lambdas, which aren't functions. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-19 21:40 ` Alan Mackenzie @ 2024-03-19 22:32 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-24 11:21 ` Alan Mackenzie 1 sibling, 0 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-19 22:32 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > When Lisp gets read for interpretation, defined symbols (e.g. folliowing > defun or cl-defgneric) get positioned, as do lambdas. I don't know what that means. > When there are ,s or ,@s on the arg list or the doc string of the > lambda, the lambda currently gets posified by the new code in > backquote-process. Are you talking about "lambda" as in "the symbol" or as in "a (lambda ...) expression". If it's "the symbol", then I can't see where a , or ,@ can appear. If the other, then if there's a , or ,@ in there it presumably means we don't yet know whether it *will* be a lambda-expression or just a list with a lambda symbol: at that point, it's just data and we don't know if it will be used to build code. > Without the new code, the "complicated" lambdas retain their > positions, which cause errors in pdump, which doesn't (and shouldn't) > handle SWPs. So, IIUC, your "get positioned" above means you preserve/add (rather than strip) the position info on some symbols, most notably those `lambda`s which "you" predict will be used for code, and if your prediction is wrong then those sympos end up escaping into the wild. > You're right about my sketched approach not working if the programmer > uses cons/list instead of `, ,, and ,@. (Thanks!) Maybe I can somehow > wait until (cons 'lambda (cons args body)) has been evaluated in ME2, > before posifying the lambda. And also take the change out of > backquote-process. Sounds about right. You'll lose information about the place where the `lambda` symbol was found in the code, but it's hard to do much better with what we have, We could introduce a new `backquote-lisp-form` which works just like backquote but which additionally asserts that what it builds will be used as a Lisp form rather than as data. BTW, we already have such a thing under the name "edebug-\`". > With this idea, most of the new code would go into the (`(function ,(and > f `(lambda ,_ . ,_))) ...) pcase arm of macrexp--expand-all, with > possibly a new arm to catch and "neutralise" the remaining lambdas, which > aren't functions. Not sure what other lambdas you're thinking of. Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-19 21:40 ` Alan Mackenzie 2024-03-19 22:32 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-24 11:21 ` Alan Mackenzie 1 sibling, 0 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-03-24 11:21 UTC (permalink / raw) To: Stefan Monnier; +Cc: acm, Eli Zaretskii, 67455 Hello, Stefan. On Tue, Mar 19, 2024 at 21:40:12 +0000, Alan Mackenzie wrote: > On Tue, Mar 19, 2024 at 16:47:46 -0400, Stefan Monnier wrote: > > > This might work. What do you think? > > I don't know what is the problem you're trying to fix, so it's hard for > > me to have an opinion. > > Could you clarify what is the problem when backquote is not changed > > at all (after all, this is the problem that will also occur if the > > programmer happened to use `cons/list` instead of backquote)? > When Lisp gets read for interpretation, defined symbols (e.g. folliowing > defun or cl-defgneric) get positioned, as do lambdas. When there are ,s > or ,@s on the arg list or the doc string of the lambda, the lambda > currently gets posified by the new code in backquote-process. Without > the new code, the "complicated" lambdas retain their positions, which > cause errors in pdump, which doesn't (and shouldn't) handle SWPs. I was possibly too dogmatic about this. I've actually amended pdumper.c to handle SWPs, and this appears to be working well. The SWPs from "complicated" lambdas get recorded in the dumped image, and later used in ME2. I've reverted my changes to backquote.el. :-) > You're right about my sketched approach not working if the programmer > uses cons/list instead of `, ,, and ,@. (Thanks!) Maybe I can somehow > wait until (cons 'lambda (cons args body)) has been evaluated in ME2, > before posifying the lambda. And also take the change out of > backquote-process. Now coded up. > With this idea, most of the new code would go into the (`(function ,(and > f `(lambda ,_ . ,_))) ...) pcase arm of macrexp--expand-all, with > possibly a new arm to catch and "neutralise" the remaining lambdas, which > aren't functions. It turns out there was little (?nothing) to change in macroexp--expand-all. The code was there already. > > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-03-04 15:38 ` bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) Alan Mackenzie 2024-03-09 21:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-01 17:40 ` Alan Mackenzie 2024-06-01 18:01 ` Eli Zaretskii 2024-06-01 23:14 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 2 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-06-01 17:40 UTC (permalink / raw) To: 67455, Eli Zaretskii, Stefan Monnier Hello, Stefan and Eli. On Mon, Mar 04, 2024 at 15:38:14 +0000, Alan Mackenzie wrote: [ .... ] > I've just pushed a large commit to feature/positioned-lambdas, a work > in progress commit for bug#67455, putting source position information at > the start of doc strings. master was merged into it just before the > commit. I've just pushed another large commit, which now works, for generous values of "works". [ .... ] > Still missing is position information for defvars and defconsts, along > with the same for cl-defmethods (which are complicated because the doc > string has no fixed position). This is now implemented. > Also missing is the handling of Oclosures. This is still missing. [ .... ] What has held me back over the last weeks was handling ambiguous constructs - things that might be evaluated, but might not. Things like '(defun ...) or (lambda ...) in the middle of a constant, or things like (memq (car form) '(defun defsubst)) in elint.el, where defsubst is definitely not a function being defined. Currently, I have coped with this using heuristics. For example that '(defun ...) is not a function definition because of the '. Or that (list 'lambda (list foo bar) ....) is the expansion of a backquote form, thus must be an evaluatable form. This is clearly unsatisfactory. I think a moderately radical change in approach is needed. Something like the following: (i) "Ambiguous" constructs should be left with symbols with position. (ii) We should enhance the evaluator to handle these symbols with position. (iii) For the sake of run time speed, typical SWPs will be posified as they are at the moment, the details getting written into their doc strings. (iv) We'll need a read syntax for symbols with position, and they will get written to .elc files with this syntax. (v) SWPs may need enhancing with a new element representing the buffer the symbol occurred in. Or, we could have an alist (or hash table) associating the SWPs with their buffers. Such currently exists for lambdas. .... or something like that. What do you think? -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-06-01 17:40 ` Alan Mackenzie @ 2024-06-01 18:01 ` Eli Zaretskii 2024-06-01 18:15 ` Eli Zaretskii 2024-06-01 18:17 ` Alan Mackenzie 2024-06-01 23:14 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 2 replies; 65+ messages in thread From: Eli Zaretskii @ 2024-06-01 18:01 UTC (permalink / raw) To: Alan Mackenzie; +Cc: monnier, 67455 > Date: Sat, 1 Jun 2024 17:40:47 +0000 > From: Alan Mackenzie <acm@muc.de> > > > I've just pushed a large commit to feature/positioned-lambdas, a work > > in progress commit for bug#67455, putting source position information at > > the start of doc strings. master was merged into it just before the > > commit. > > I've just pushed another large commit, which now works, for generous > values of "works". So now the master branch, soon to become the emacs-20 release branch, is completely destabilized? Can we perhaps revert and wait until after the branch? ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-06-01 18:01 ` Eli Zaretskii @ 2024-06-01 18:15 ` Eli Zaretskii 2024-06-01 18:17 ` Alan Mackenzie 1 sibling, 0 replies; 65+ messages in thread From: Eli Zaretskii @ 2024-06-01 18:15 UTC (permalink / raw) To: acm, monnier; +Cc: 67455 > Cc: monnier@iro.umontreal.ca, 67455@debbugs.gnu.org > Date: Sat, 01 Jun 2024 21:01:11 +0300 > From: Eli Zaretskii <eliz@gnu.org> > > So now the master branch, soon to become the emacs-20 release branch, > is completely destabilized? ^^^^^^^^ I meant emacs-30, of course. ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-06-01 18:01 ` Eli Zaretskii 2024-06-01 18:15 ` Eli Zaretskii @ 2024-06-01 18:17 ` Alan Mackenzie 1 sibling, 0 replies; 65+ messages in thread From: Alan Mackenzie @ 2024-06-01 18:17 UTC (permalink / raw) To: Eli Zaretskii; +Cc: monnier, 67455 Hello, Eli. On Sat, Jun 01, 2024 at 21:01:11 +0300, Eli Zaretskii wrote: > > Date: Sat, 1 Jun 2024 17:40:47 +0000 > > From: Alan Mackenzie <acm@muc.de> > > > I've just pushed a large commit to feature/positioned-lambdas, a work > > > in progress commit for bug#67455, putting source position information at > > > the start of doc strings. master was merged into it just before the > > > commit. > > I've just pushed another large commit, which now works, for generous > > values of "works". > So now the master branch, soon to become the emacs-20 release branch, > is completely destabilized? No, I only committed the change to branch feature/positioned-lambdas, unless I've made some mistake with git. I wouldn't merge it to master without getting your agreement, first. > Can we perhaps revert and wait until after the branch? I hope that's not needed. :-) -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 65+ messages in thread
* bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) 2024-06-01 17:40 ` Alan Mackenzie 2024-06-01 18:01 ` Eli Zaretskii @ 2024-06-01 23:14 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 0 replies; 65+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-01 23:14 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, 67455 > I think a moderately radical change in approach is needed. Something > like the following: > > (i) "Ambiguous" constructs should be left with symbols with position. > (ii) We should enhance the evaluator to handle these symbols with > position. > (iii) For the sake of run time speed, typical SWPs will be posified as > they are at the moment, the details getting written into their doc > strings. > (iv) We'll need a read syntax for symbols with position, and they will > get written to .elc files with this syntax. > (v) SWPs may need enhancing with a new element representing the buffer > the symbol occurred in. Or, we could have an alist (or hash table) > associating the SWPs with their buffers. Such currently exists for > lambdas. > > .... or something like that. > > What do you think? I don't think I can see the problem clearly enough to have a good idea of what we should do. Do you have a concrete and worked out example where we need to preserve sympos info from data (i.e. from a quoted value, IOW the thing you describe as an "ambiguous construct", IIUC), showing how that data is later turned into code, which sympos info *that* code gets, what "source position" we ideally want to get into the compiled/interpreted code, and finally how that info will be used? Stefan ^ permalink raw reply [flat|nested] 65+ messages in thread
end of thread, other threads:[~2024-06-05 15:01 UTC | newest] Thread overview: 65+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-11-26 14:30 bug#67455: Record source position, etc., in doc strings, and use this in *Help* and backtraces Alan Mackenzie 2023-12-04 17:36 ` Alan Mackenzie 2023-12-04 18:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-12-04 21:32 ` Alan Mackenzie 2023-12-04 21:56 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-12-04 22:30 ` Alan Mackenzie 2023-12-04 22:59 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-12-15 18:23 ` Alan Mackenzie 2023-12-15 23:12 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors [not found] ` <handler.67455.B.170100905232659.ack@debbugs.gnu.org> 2024-03-04 15:38 ` bug#67455: (Record source position, etc., in doc strings, and use this in *Help* and backtraces.) Alan Mackenzie 2024-03-09 21:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-10 16:02 ` Alan Mackenzie 2024-03-10 17:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-10 19:22 ` Alan Mackenzie 2024-03-10 21:03 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-24 11:04 ` Alan Mackenzie 2024-03-25 18:23 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-25 21:03 ` Alan Mackenzie 2024-03-25 22:10 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 9:48 ` Alan Mackenzie 2024-03-26 13:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 16:55 ` Alan Mackenzie 2024-03-26 19:40 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 20:21 ` Alan Mackenzie 2024-03-26 20:42 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-27 3:35 ` Alan Mackenzie 2024-03-27 12:23 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-27 22:00 ` Alan Mackenzie 2024-03-26 20:30 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-26 21:13 ` Drew Adams 2024-03-27 10:04 ` Alan Mackenzie 2024-03-27 12:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-27 21:43 ` Alan Mackenzie 2024-03-28 16:25 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-28 16:48 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-30 9:10 ` Alan Mackenzie 2024-03-30 9:53 ` Alan Mackenzie 2024-03-31 2:22 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-04-07 11:35 ` Alan Mackenzie 2024-04-08 2:19 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-04-08 2:56 ` Alan Mackenzie 2024-04-10 8:53 ` Alan Mackenzie 2024-03-30 11:03 ` Alan Mackenzie 2024-03-31 2:54 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-04-07 10:57 ` Alan Mackenzie 2024-04-08 3:16 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-04-08 8:32 ` Alan Mackenzie 2024-04-08 12:00 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-06-02 13:38 ` Alan Mackenzie 2024-06-03 4:52 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-06-05 15:01 ` Alan Mackenzie 2024-03-10 22:27 ` Alan Mackenzie 2024-03-11 0:50 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-13 10:54 ` Alan Mackenzie 2024-03-13 11:52 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-19 16:18 ` Alan Mackenzie 2024-03-19 20:47 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-19 21:40 ` Alan Mackenzie 2024-03-19 22:32 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-03-24 11:21 ` Alan Mackenzie 2024-06-01 17:40 ` Alan Mackenzie 2024-06-01 18:01 ` Eli Zaretskii 2024-06-01 18:15 ` Eli Zaretskii 2024-06-01 18:17 ` Alan Mackenzie 2024-06-01 23:14 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git 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).