From: "Basil L. Contovounesios" <contovob@tcd.ie>
To: Stefan Kangas <stefan@marxist.se>
Cc: 36392@debbugs.gnu.org
Subject: bug#36392: (info "(elisp)Writing Emacs Primitives") might need some clarifications
Date: Wed, 26 Jun 2019 14:09:03 +0100 [thread overview]
Message-ID: <87v9ws8pe8.fsf@tcd.ie> (raw)
In-Reply-To: <CADwFkmnowT8izEov-50qXrbhgxyULA_Tgu649CTGEFmp8qt_Sw@mail.gmail.com> (Stefan Kangas's message of "Wed, 26 Jun 2019 13:31:06 +0200")
[-- Attachment #1: Type: text/plain, Size: 46 bytes --]
tags 36392 + patch
severity 36392 minor
quit
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Clarify-update-elisp-Writing-Emacs-Primitives.patch --]
[-- Type: text/x-diff, Size: 9501 bytes --]
From 3d85d73858fe0c126277d04db8b99eeb9f09d672 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 26 Jun 2019 13:05:51 +0100
Subject: [PATCH] Clarify & update (elisp) Writing Emacs Primitives
* doc/lispref/internals.texi (Writing Emacs Primitives): Replace
outdated For listing with current Fwhile, so that the subsequent
paragraph on maybe_quit still applies. Reconcile other code
listings with their current source. Fix indentation of sample DEFUN
argument lists. Replace ... with @dots{}. Fix argument list of
Ffoo example. Describe UNEVALLED special forms as taking a single
argument. (bug#36392)
---
doc/lispref/internals.texi | 112 ++++++++++++++++++-------------------
1 file changed, 55 insertions(+), 57 deletions(-)
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index cfeb492af4..34dfb3924e 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -695,38 +695,36 @@ Writing Emacs Primitives
C macros. The only way to really understand how to write new C code is
to read the source, but we can explain some things here.
- An example of a special form is the definition of @code{or}, from
+ An example of a special form is the definition of @code{while}, from
@file{eval.c}. (An ordinary function would have the same general
appearance.)
@smallexample
@group
-DEFUN ("or", For, Sor, 0, UNEVALLED, 0,
- doc: /* Eval args until one of them yields non-nil, then return
-that value.
-The remaining args are not evalled at all.
-If all args return nil, return nil.
+DEFUN ("while", Fwhile, Swhile, 1, UNEVALLED, 0,
+ doc: /* If TEST yields non-nil, eval BODY... and repeat.
+The order of execution is thus TEST, BODY, TEST, BODY and so on
+until TEST returns nil.
@end group
@group
-usage: (or CONDITIONS...) */)
+usage: (while TEST BODY...) */)
(Lisp_Object args)
@{
- Lisp_Object val = Qnil;
+ Lisp_Object test, body;
@end group
@group
- while (CONSP (args))
+ test = XCAR (args);
+ body = XCDR (args);
+ while (!NILP (eval_sub (test)))
@{
- val = eval_sub (XCAR (args));
- if (!NILP (val))
- break;
- args = XCDR (args);
maybe_quit ();
+ prog_ignore (body);
@}
@end group
@group
- return val;
+ return Qnil;
@}
@end group
@end smallexample
@@ -742,14 +740,14 @@ Writing Emacs Primitives
@table @var
@item lname
This is the name of the Lisp symbol to define as the function name; in
-the example above, it is @code{or}.
+the example above, it is @code{while}.
@item fname
This is the C function name for this function. This is the name that
is used in C code for calling the function. The name is, by
convention, @samp{F} prepended to the Lisp name, with all dashes
(@samp{-}) in the Lisp name changed to underscores. Thus, to call
-this function from C code, call @code{For}.
+this function from C code, call @code{Fwhile}.
@item sname
This is a C variable name to use for a structure that holds the data for
@@ -761,7 +759,7 @@ Writing Emacs Primitives
@item min
This is the minimum number of arguments that the function requires. The
-function @code{or} allows a minimum of zero arguments.
+function @code{while} allows a minimum of one argument.
@item max
This is the maximum number of arguments that the function accepts, if
@@ -775,21 +773,20 @@ Writing Emacs Primitives
@cindex interactive specification in primitives
@item interactive
This is an interactive specification, a string such as might be used
-as the argument of @code{interactive} in a Lisp function
-(@pxref{Using Interactive}). In the case
-of @code{or}, it is 0 (a null pointer), indicating that @code{or}
-cannot be called interactively. A value of @code{""} indicates a
-function that should receive no arguments when called interactively.
-If the value begins with a @samp{"(}, the string is evaluated as a
-Lisp form. For example:
+as the argument of @code{interactive} in a Lisp function (@pxref{Using
+Interactive}). In the case of @code{while}, it is @code{0} (a null
+pointer), indicating that @code{while} cannot be called interactively.
+A value of @code{""} indicates a function that should receive no
+arguments when called interactively. If the value begins with a
+@samp{"(}, the string is evaluated as a Lisp form. For example:
@example
@group
-DEFUN ("foo", Ffoo, Sfoo, 0, UNEVALLED, 0
+DEFUN ("foo", Ffoo, Sfoo, 0, 3,
"(list (read-char-by-name \"Insert character: \")\
(prefix-numeric-value current-prefix-arg)\
- t))",
- doc: /* @dots{} */)
+ t)",
+ doc: /* @dots{} */)
@end group
@end example
@@ -826,8 +823,8 @@ Writing Emacs Primitives
@example
@group
DEFUN ("bar", Fbar, Sbar, 0, UNEVALLED, 0
- doc: /* @dots{} */
- attributes: @var{attr1} @var{attr2} @dots{})
+ doc: /* @dots{} */
+ attributes: @var{attr1} @var{attr2} @dots{})
@end group
@end example
@@ -863,20 +860,23 @@ Writing Emacs Primitives
arguments, there must be one C argument for each Lisp argument, and
each argument must be of type @code{Lisp_Object}. (Various macros and
functions for creating values of type @code{Lisp_Object} are declared
-in the file @file{lisp.h}.) If the primitive has no upper limit on
-the number of Lisp arguments, it must have exactly two C arguments:
-the first is the number of Lisp arguments, and the second is the
-address of a block containing their values. These have types
-@code{int} and @w{@code{Lisp_Object *}} respectively. Since
-@code{Lisp_Object} can hold any Lisp object of any data type, you
-can determine the actual data type only at run time; so if you want
-a primitive to accept only a certain type of argument, you must check
-the type explicitly using a suitable predicate (@pxref{Type Predicates}).
+in the file @file{lisp.h}.) If the primitive is a special form, it
+must accept a Lisp list containing its unevaluated Lisp arguments as a
+single argument of type @code{Lisp_Object}. If the primitive has no
+upper limit on the number of evaluated Lisp arguments, it must have
+exactly two C arguments: the first is the number of Lisp arguments,
+and the second is the address of a block containing their values.
+These have types @code{ptrdiff_t} and @w{@code{Lisp_Object *}},
+respectively. Since @code{Lisp_Object} can hold any Lisp object of
+any data type, you can determine the actual data type only at run
+time; so if you want a primitive to accept only a certain type of
+argument, you must check the type explicitly using a suitable
+predicate (@pxref{Type Predicates}).
@cindex type checking internals
@cindex garbage collection protection
@cindex protect C variables from garbage collection
- Within the function @code{For} itself, the local variable
+ Within the function @code{Fwhile} itself, the local variable
@code{args} refers to objects controlled by Emacs's stack-marking
garbage collector. Although the garbage collector does not reclaim
objects reachable from C @code{Lisp_Object} stack variables, it may
@@ -890,9 +890,8 @@ Writing Emacs Primitives
Note the call to @code{maybe_quit} inside the loop: this function
checks whether the user pressed @kbd{C-g}, and if so, aborts the
processing. You should do that in any loop that can potentially
-require a large number of iterations; in this case, the list of
-arguments could be very long. This increases Emacs responsiveness and
-improves user experience.
+require a large number of iterations. This increases Emacs
+responsiveness and improves user experience.
You must not use C initializers for static or global variables unless
the variables are never written once Emacs is dumped. These variables
@@ -957,9 +956,9 @@ Writing Emacs Primitives
@smallexample
@group
DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
- Scoordinates_in_window_p, 2, 2, 0,
- doc: /* Return non-nil if COORDINATES are in WINDOW.
- ...
+ Scoordinates_in_window_p, 2, 2, 0,
+ doc: /* Return non-nil if COORDINATES are in WINDOW.
+ @dots{}
@end group
@group
or `right-margin' is returned. */)
@@ -972,43 +971,42 @@ Writing Emacs Primitives
@end group
@group
- CHECK_LIVE_WINDOW (window);
- w = XWINDOW (window);
+ w = decode_live_window (window);
f = XFRAME (w->frame);
CHECK_CONS (coordinates);
lx = Fcar (coordinates);
ly = Fcdr (coordinates);
- CHECK_NUMBER_OR_FLOAT (lx);
- CHECK_NUMBER_OR_FLOAT (ly);
- x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH(f);
- y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH(f);
+ CHECK_NUMBER (lx);
+ CHECK_NUMBER (ly);
+ x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f);
+ y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
@end group
@group
switch (coordinates_in_window (w, x, y))
@{
- case ON_NOTHING: /* NOT in window at all. */
+ case ON_NOTHING:
return Qnil;
@end group
- ...
+ @dots{}
@group
- case ON_MODE_LINE: /* In mode line of window. */
+ case ON_MODE_LINE:
return Qmode_line;
@end group
- ...
+ @dots{}
@group
- case ON_SCROLL_BAR: /* On scroll-bar of window. */
+ case ON_VERTICAL_SCROLL_BAR:
/* Historically we are supposed to return nil in this case. */
return Qnil;
@end group
@group
default:
- abort ();
+ emacs_abort ();
@}
@}
@end group
--
2.20.1
[-- Attachment #3: Type: text/plain, Size: 1814 bytes --]
Stefan Kangas <stefan@marxist.se> writes:
> As a beginner on Emacs Internals, I've been reading:
>
> (info "(elisp)Writing Emacs Primitives")
>
> I hope that you find the following observations useful:
>
> 1. "If the primitive accepts a fixed maximum number of Lisp
> arguments, there must be one C argument for each Lisp argument,
> and each argument must be of type ‘Lisp_Object’. ... If the
> primitive has no upper limit on the number of Lisp arguments, it
> must have exactly two C arguments: the first is the number of Lisp
> arguments, and the second is the address of a block containing
> their values."
>
> The example given is DEFUN( "or", ...)
>
> This function has no upper limit on the number of Lisp arguments, but
> still has only ONE argument. Unless I'm missing something, this
> contradicts the statement above that "it must have exactly TWO C
> arguments" (my emphasis).
Indeed, this is because For is a special form (with UNEVALLED args).
Compare it with the definition for Fapply (with MANY args) in the same
file, and see the macros DEFUN_ARGS_UNEVALLED and DEFUN_ARGS_MANY in
lisp.h.
Does the attached patch, suitable for either master or emacs-26, help
clarify this?
> 2. "Although the garbage collector does not reclaim objects reachable
> from C ‘Lisp_Object’ stack variables, it may move non-object
> components of an object, such as string contents; so functions
> that access non-object components must take care to refetch their
> addresses after performing Lisp evaluation."
>
> I don't think this is very clear. What is non-object components? How
> would I refetch their addresses? How is this relevant to the topic at
> hand?
I don't know about this.
Thanks,
--
Basil
next prev parent reply other threads:[~2019-06-26 13:09 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-26 11:31 bug#36392: (info "(elisp)Writing Emacs Primitives") might need some clarifications Stefan Kangas
2019-06-26 13:09 ` Basil L. Contovounesios [this message]
2019-06-26 15:14 ` Eli Zaretskii
2019-06-26 18:20 ` Basil L. Contovounesios
2019-06-26 18:34 ` Eli Zaretskii
2019-06-26 21:29 ` Basil L. Contovounesios
2019-06-27 1:01 ` Stefan Kangas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87v9ws8pe8.fsf@tcd.ie \
--to=contovob@tcd.ie \
--cc=36392@debbugs.gnu.org \
--cc=stefan@marxist.se \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.