>From 3d85d73858fe0c126277d04db8b99eeb9f09d672 Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" 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