summaryrefslogtreecommitdiff
path: root/src/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c902
1 files changed, 588 insertions, 314 deletions
diff --git a/src/eval.c b/src/eval.c
index b94712d4579..b1747387471 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -22,6 +22,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
#include "lisp.h"
#include "blockinput.h"
#include "commands.h"
@@ -31,7 +32,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
/* Chain of condition and catch handlers currently in effect. */
-struct handler *handlerlist;
+/* struct handler *handlerlist; */
/* Non-nil means record all fset's and provide's, to be undone
if the file being autoloaded is not fully loaded.
@@ -45,23 +46,25 @@ Lisp_Object Vautoload_queue;
is shutting down. */
Lisp_Object Vrun_hooks;
+/* The commented-out variables below are macros defined in thread.h. */
+
/* Current number of specbindings allocated in specpdl, not counting
the dummy entry specpdl[-1]. */
-ptrdiff_t specpdl_size;
+/* ptrdiff_t specpdl_size; */
/* Pointer to beginning of specpdl. A dummy entry specpdl[-1] exists
only so that its address can be taken. */
-union specbinding *specpdl;
+/* union specbinding *specpdl; */
/* Pointer to first unused element in specpdl. */
-union specbinding *specpdl_ptr;
+/* union specbinding *specpdl_ptr; */
/* Depth in Lisp evaluations and function calls. */
-static EMACS_INT lisp_eval_depth;
+/* static EMACS_INT lisp_eval_depth; */
/* The value of num_nonmacro_input_events as of the last time we
started to enter the debugger. If we decide to enter the debugger
@@ -90,6 +93,7 @@ union specbinding *backtrace_top (void) EXTERNALLY_VISIBLE;
static Lisp_Object funcall_lambda (Lisp_Object, ptrdiff_t, Lisp_Object *);
static Lisp_Object apply_lambda (Lisp_Object, Lisp_Object, ptrdiff_t);
+static Lisp_Object lambda_arity (Lisp_Object);
static Lisp_Object
specpdl_symbol (union specbinding *pdl)
@@ -98,6 +102,13 @@ specpdl_symbol (union specbinding *pdl)
return pdl->let.symbol;
}
+static enum specbind_tag
+specpdl_kind (union specbinding *pdl)
+{
+ eassert (pdl->kind >= SPECPDL_LET);
+ return pdl->let.kind;
+}
+
static Lisp_Object
specpdl_old_value (union specbinding *pdl)
{
@@ -120,6 +131,13 @@ specpdl_where (union specbinding *pdl)
}
static Lisp_Object
+specpdl_saved_value (union specbinding *pdl)
+{
+ eassert (pdl->kind >= SPECPDL_LET);
+ return pdl->let.saved_value;
+}
+
+static Lisp_Object
specpdl_arg (union specbinding *pdl)
{
eassert (pdl->kind == SPECPDL_UNWIND);
@@ -216,21 +234,21 @@ init_eval_once (void)
Vrun_hooks = Qnil;
}
-static struct handler handlerlist_sentinel;
+/* static struct handler handlerlist_sentinel; */
void
init_eval (void)
{
- byte_stack_list = 0;
specpdl_ptr = specpdl;
{ /* Put a dummy catcher at top-level so that handlerlist is never NULL.
This is important since handlerlist->nextfree holds the freelist
which would otherwise leak every time we unwind back to top-level. */
- handlerlist = handlerlist_sentinel.nextfree = &handlerlist_sentinel;
+ handlerlist_sentinel = xzalloc (sizeof (struct handler));
+ handlerlist = handlerlist_sentinel->nextfree = handlerlist_sentinel;
struct handler *c = push_handler (Qunbound, CATCHER);
- eassert (c == &handlerlist_sentinel);
- handlerlist_sentinel.nextfree = NULL;
- handlerlist_sentinel.next = NULL;
+ eassert (c == handlerlist_sentinel);
+ handlerlist_sentinel->nextfree = NULL;
+ handlerlist_sentinel->next = NULL;
}
Vquit_flag = Qnil;
debug_on_next_call = 0;
@@ -435,11 +453,10 @@ usage: (progn BODY...) */)
return val;
}
-/* Evaluate BODY sequentially, discarding its value. Suitable for
- record_unwind_protect. */
+/* Evaluate BODY sequentially, discarding its value. */
void
-unwind_body (Lisp_Object body)
+prog_ignore (Lisp_Object body)
{
Fprogn (body);
}
@@ -451,16 +468,8 @@ whose values are discarded.
usage: (prog1 FIRST BODY...) */)
(Lisp_Object args)
{
- Lisp_Object val;
- Lisp_Object args_left;
-
- args_left = args;
- val = args;
-
- val = eval_sub (XCAR (args_left));
- while (CONSP (args_left = XCDR (args_left)))
- eval_sub (XCAR (args_left));
-
+ Lisp_Object val = eval_sub (XCAR (args));
+ prog_ignore (XCDR (args));
return val;
}
@@ -592,12 +601,12 @@ The return value is BASE-VARIABLE. */)
CHECK_SYMBOL (new_alias);
CHECK_SYMBOL (base_variable);
- sym = XSYMBOL (new_alias);
-
- if (sym->constant)
- /* Not sure why, but why not? */
+ if (SYMBOL_CONSTANT_P (new_alias))
+ /* Making it an alias effectively changes its value. */
error ("Cannot make a constant an alias");
+ sym = XSYMBOL (new_alias);
+
switch (sym->redirect)
{
case SYMBOL_FORWARDED:
@@ -616,8 +625,8 @@ The return value is BASE-VARIABLE. */)
so that old-code that affects n_a before the aliasing is setup
still works. */
if (NILP (Fboundp (base_variable)))
- set_internal (base_variable, find_symbol_value (new_alias), Qnil, 1);
-
+ set_internal (base_variable, find_symbol_value (new_alias),
+ Qnil, SET_INTERNAL_BIND);
{
union specbinding *p;
@@ -627,11 +636,14 @@ The return value is BASE-VARIABLE. */)
error ("Don't know how to make a let-bound variable an alias");
}
+ if (sym->trapped_write == SYMBOL_TRAPPED_WRITE)
+ notify_variable_watchers (new_alias, base_variable, Qdefvaralias, Qnil);
+
sym->declared_special = 1;
XSYMBOL (base_variable)->declared_special = 1;
sym->redirect = SYMBOL_VARALIAS;
SET_SYMBOL_ALIAS (sym, XSYMBOL (base_variable));
- sym->constant = SYMBOL_CONSTANT_P (base_variable);
+ sym->trapped_write = XSYMBOL (base_variable)->trapped_write;
LOADHIST_ATTACH (new_alias);
/* Even if docstring is nil: remove old docstring. */
Fput (new_alias, Qvariable_documentation, docstring);
@@ -704,10 +716,11 @@ can be referred to by the Emacs help facilities and other programming
tools. The `defvar' form also declares the variable as \"special\",
so that it is always dynamically bound even if `lexical-binding' is t.
-The optional argument INITVALUE is evaluated, and used to set SYMBOL,
-only if SYMBOL's value is void. If SYMBOL is buffer-local, its
-default value is what is set; buffer-local values are not affected.
-If INITVALUE is missing, SYMBOL's value is not set.
+If SYMBOL's value is void and the optional argument INITVALUE is
+provided, INITVALUE is evaluated and the result used to set SYMBOL's
+value. If SYMBOL is buffer-local, its default value is what is set;
+buffer-local values are not affected. If INITVALUE is missing,
+SYMBOL's value is not set.
If SYMBOL has a local binding, then this form affects the local
binding. This is usually not what you want. Thus, if you need to
@@ -967,7 +980,7 @@ usage: (while TEST BODY...) */)
while (!NILP (eval_sub (test)))
{
QUIT;
- Fprogn (body);
+ prog_ignore (body);
}
return Qnil;
@@ -1056,11 +1069,11 @@ usage: (catch TAG BODY...) */)
return internal_catch (tag, Fprogn, XCDR (args));
}
-/* Assert that E is true, as a comment only. Use this instead of
+/* Assert that E is true, but do not evaluate E. Use this instead of
eassert (E) when E contains variables that might be clobbered by a
longjmp. */
-#define clobbered_eassert(E) ((void) 0)
+#define clobbered_eassert(E) verify (sizeof (E) != 0)
/* Set up a catch, then call C function FUNC on argument ARG.
FUNC should return a Lisp_Object.
@@ -1077,8 +1090,8 @@ internal_catch (Lisp_Object tag,
if (! sys_setjmp (c->jmp))
{
Lisp_Object val = func (arg);
- clobbered_eassert (handlerlist == c);
- handlerlist = handlerlist->next;
+ eassert (handlerlist == c);
+ handlerlist = c->next;
return val;
}
else
@@ -1134,8 +1147,7 @@ unwind_to_catch (struct handler *catch, Lisp_Object value)
eassert (handlerlist == catch);
- byte_stack_list = catch->byte_stack;
- lisp_eval_depth = catch->lisp_eval_depth;
+ lisp_eval_depth = catch->f_lisp_eval_depth;
sys_longjmp (catch->jmp, 1);
}
@@ -1171,7 +1183,7 @@ usage: (unwind-protect BODYFORM UNWINDFORMS...) */)
Lisp_Object val;
ptrdiff_t count = SPECPDL_INDEX ();
- record_unwind_protect (unwind_body, XCDR (args));
+ record_unwind_protect (prog_ignore, XCDR (args));
val = eval_sub (XCAR (args));
return unbind_to (count, val);
}
@@ -1312,8 +1324,8 @@ internal_condition_case (Lisp_Object (*bfun) (void), Lisp_Object handlers,
else
{
Lisp_Object val = bfun ();
- clobbered_eassert (handlerlist == c);
- handlerlist = handlerlist->next;
+ eassert (handlerlist == c);
+ handlerlist = c->next;
return val;
}
}
@@ -1336,8 +1348,8 @@ internal_condition_case_1 (Lisp_Object (*bfun) (Lisp_Object), Lisp_Object arg,
else
{
Lisp_Object val = bfun (arg);
- clobbered_eassert (handlerlist == c);
- handlerlist = handlerlist->next;
+ eassert (handlerlist == c);
+ handlerlist = c->next;
return val;
}
}
@@ -1363,8 +1375,8 @@ internal_condition_case_2 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object),
else
{
Lisp_Object val = bfun (arg1, arg2);
- clobbered_eassert (handlerlist == c);
- handlerlist = handlerlist->next;
+ eassert (handlerlist == c);
+ handlerlist = c->next;
return val;
}
}
@@ -1392,8 +1404,8 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *),
else
{
Lisp_Object val = bfun (nargs, args);
- clobbered_eassert (handlerlist == c);
- handlerlist = handlerlist->next;
+ eassert (handlerlist == c);
+ handlerlist = c->next;
return val;
}
}
@@ -1425,16 +1437,16 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
c->tag_or_ch = tag_ch_val;
c->val = Qnil;
c->next = handlerlist;
- c->lisp_eval_depth = lisp_eval_depth;
+ c->f_lisp_eval_depth = lisp_eval_depth;
c->pdlcount = SPECPDL_INDEX ();
c->poll_suppress_count = poll_suppress_count;
c->interrupt_input_blocked = interrupt_input_blocked;
- c->byte_stack = byte_stack_list;
handlerlist = c;
return c;
}
+static Lisp_Object signal_or_quit (Lisp_Object, Lisp_Object, bool);
static Lisp_Object find_handler_clause (Lisp_Object, Lisp_Object);
static bool maybe_call_debugger (Lisp_Object conditions, Lisp_Object sig,
Lisp_Object data);
@@ -1448,7 +1460,7 @@ process_quit_flag (void)
Fkill_emacs (Qnil);
if (EQ (Vthrow_on_input, flag))
Fthrow (Vthrow_on_input, Qt);
- Fsignal (Qquit, Qnil);
+ quit ();
}
DEFUN ("signal", Fsignal, Ssignal, 2, 2, 0,
@@ -1464,9 +1476,29 @@ DATA should be a list. Its elements are printed as part of the error message.
See Info anchor `(elisp)Definition of signal' for some details on how this
error message is constructed.
If the signal is handled, DATA is made available to the handler.
-See also the function `condition-case'. */)
+See also the function `condition-case'. */
+ attributes: noreturn)
(Lisp_Object error_symbol, Lisp_Object data)
{
+ signal_or_quit (error_symbol, data, false);
+ eassume (false);
+}
+
+/* Quit, in response to a keyboard quit request. */
+Lisp_Object
+quit (void)
+{
+ return signal_or_quit (Qquit, Qnil, true);
+}
+
+/* Signal an error, or quit. ERROR_SYMBOL and DATA are as with Fsignal.
+ If KEYBOARD_QUIT, this is a quit; ERROR_SYMBOL should be
+ Qquit and DATA should be Qnil, and this function may return.
+ Otherwise this function is like Fsignal and does not return. */
+
+static Lisp_Object
+signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
+{
/* When memory is full, ERROR-SYMBOL is nil,
and DATA is (REAL-ERROR-SYMBOL . REAL-DATA).
That is a special case--don't do this in other situations. */
@@ -1478,7 +1510,6 @@ See also the function `condition-case'. */)
struct handler *h;
immediate_quit = 0;
- abort_on_gc = 0;
if (gc_in_progress || waiting_for_input)
emacs_abort ();
@@ -1546,7 +1577,7 @@ See also the function `condition-case'. */)
= maybe_call_debugger (conditions, error_symbol, data);
/* We can't return values to code which signaled an error, but we
can continue code which has signaled a quit. */
- if (debugger_called && EQ (real_error_symbol, Qquit))
+ if (keyboard_quit && debugger_called && EQ (real_error_symbol, Qquit))
return Qnil;
}
@@ -1559,7 +1590,7 @@ See also the function `condition-case'. */)
}
else
{
- if (handlerlist != &handlerlist_sentinel)
+ if (handlerlist != handlerlist_sentinel)
/* FIXME: This will come right back here if there's no `top-level'
catcher. A better solution would be to abort here, and instead
add a catch-all condition handler so we never come here. */
@@ -1573,16 +1604,6 @@ See also the function `condition-case'. */)
fatal ("%s", SDATA (string));
}
-/* Internal version of Fsignal that never returns.
- Used for anything but Qquit (which can return from Fsignal). */
-
-void
-xsignal (Lisp_Object error_symbol, Lisp_Object data)
-{
- Fsignal (error_symbol, data);
- emacs_abort ();
-}
-
/* Like xsignal, but takes 0, 1, 2, or 3 args instead of a list. */
void
@@ -1756,9 +1777,9 @@ find_handler_clause (Lisp_Object handlers, Lisp_Object conditions)
}
-/* Dump an error message; called like vprintf. */
-void
-verror (const char *m, va_list ap)
+/* Format and return a string; called like vprintf. */
+Lisp_Object
+vformat_string (const char *m, va_list ap)
{
char buf[4000];
ptrdiff_t size = sizeof buf;
@@ -1772,7 +1793,14 @@ verror (const char *m, va_list ap)
if (buffer != buf)
xfree (buffer);
- xsignal1 (Qerror, string);
+ return string;
+}
+
+/* Dump an error message; called like vprintf. */
+void
+verror (const char *m, va_list ap)
+{
+ xsignal1 (Qerror, vformat_string (m, ap));
}
@@ -1929,6 +1957,28 @@ it defines a macro. */)
if (!CONSP (fundef) || !EQ (Qautoload, XCAR (fundef)))
return fundef;
+ /* In the special case that we are generating ldefs-boot-auto.el,
+ then be noisy about the autoload. */
+ if( generating_ldefs_boot )
+ {
+ fprintf(stderr, "(autoload '");
+ Fprin1(funname,Qexternal_debugging_output);
+ fprintf(stderr, " ");
+ Fprin1(Fcar (Fcdr (fundef)),Qexternal_debugging_output);
+ fprintf(stderr, " nil nil ");
+
+ Lisp_Object kind = Fnth (make_number (4), fundef);
+ if (! (EQ (kind, Qt) || EQ (kind, Qmacro)))
+ {
+ fprintf(stderr, "nil");
+ }
+ else
+ {
+ fprintf(stderr, "t");
+ }
+ fprintf(stderr, ")\n");
+ }
+
if (EQ (macro_only, Qmacro))
{
Lisp_Object kind = Fnth (make_number (4), fundef);
@@ -1972,7 +2022,8 @@ it defines a macro. */)
Lisp_Object fun = Findirect_function (funname, Qnil);
if (!NILP (Fequal (fun, fundef)))
- error ("Autoloading failed to define function %s",
+ error ("Autoloading file %s failed to define function %s",
+ SDATA (Fcar (Fcar (Vload_history))),
SDATA (SYMBOL_NAME (funname)));
else
return fun;
@@ -2618,6 +2669,37 @@ DEFUN ("functionp", Ffunctionp, Sfunctionp, 1, 1, 0,
return Qnil;
}
+bool
+FUNCTIONP (Lisp_Object object)
+{
+ if (SYMBOLP (object) && !NILP (Ffboundp (object)))
+ {
+ object = Findirect_function (object, Qt);
+
+ if (CONSP (object) && EQ (XCAR (object), Qautoload))
+ {
+ /* Autoloaded symbols are functions, except if they load
+ macros or keymaps. */
+ for (int i = 0; i < 4 && CONSP (object); i++)
+ object = XCDR (object);
+
+ return ! (CONSP (object) && !NILP (XCAR (object)));
+ }
+ }
+
+ if (SUBRP (object))
+ return XSUBR (object)->max_args != UNEVALLED;
+ else if (COMPILEDP (object))
+ return true;
+ else if (CONSP (object))
+ {
+ Lisp_Object car = XCAR (object);
+ return EQ (car, Qlambda) || EQ (car, Qclosure);
+ }
+ else
+ return false;
+}
+
DEFUN ("funcall", Ffuncall, Sfuncall, 1, MANY, 0,
doc: /* Call first argument as a function, passing remaining arguments to it.
Return the value that function returns.
@@ -2628,9 +2710,7 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
Lisp_Object fun, original_fun;
Lisp_Object funcar;
ptrdiff_t numargs = nargs - 1;
- Lisp_Object lisp_numargs;
Lisp_Object val;
- Lisp_Object *internal_args;
ptrdiff_t count;
QUIT;
@@ -2663,86 +2743,7 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
fun = indirect_function (fun);
if (SUBRP (fun))
- {
- if (numargs < XSUBR (fun)->min_args
- || (XSUBR (fun)->max_args >= 0 && XSUBR (fun)->max_args < numargs))
- {
- XSETFASTINT (lisp_numargs, numargs);
- xsignal2 (Qwrong_number_of_arguments, original_fun, lisp_numargs);
- }
-
- else if (XSUBR (fun)->max_args == UNEVALLED)
- xsignal1 (Qinvalid_function, original_fun);
-
- else if (XSUBR (fun)->max_args == MANY)
- val = (XSUBR (fun)->function.aMANY) (numargs, args + 1);
- else
- {
- Lisp_Object internal_argbuf[8];
- if (XSUBR (fun)->max_args > numargs)
- {
- eassert (XSUBR (fun)->max_args <= ARRAYELTS (internal_argbuf));
- internal_args = internal_argbuf;
- memcpy (internal_args, args + 1, numargs * word_size);
- memclear (internal_args + numargs,
- (XSUBR (fun)->max_args - numargs) * word_size);
- }
- else
- internal_args = args + 1;
- switch (XSUBR (fun)->max_args)
- {
- case 0:
- val = (XSUBR (fun)->function.a0 ());
- break;
- case 1:
- val = (XSUBR (fun)->function.a1 (internal_args[0]));
- break;
- case 2:
- val = (XSUBR (fun)->function.a2
- (internal_args[0], internal_args[1]));
- break;
- case 3:
- val = (XSUBR (fun)->function.a3
- (internal_args[0], internal_args[1], internal_args[2]));
- break;
- case 4:
- val = (XSUBR (fun)->function.a4
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3]));
- break;
- case 5:
- val = (XSUBR (fun)->function.a5
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3], internal_args[4]));
- break;
- case 6:
- val = (XSUBR (fun)->function.a6
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3], internal_args[4], internal_args[5]));
- break;
- case 7:
- val = (XSUBR (fun)->function.a7
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3], internal_args[4], internal_args[5],
- internal_args[6]));
- break;
-
- case 8:
- val = (XSUBR (fun)->function.a8
- (internal_args[0], internal_args[1], internal_args[2],
- internal_args[3], internal_args[4], internal_args[5],
- internal_args[6], internal_args[7]));
- break;
-
- default:
-
- /* If a subr takes more than 8 arguments without using MANY
- or UNEVALLED, we need to extend this function to support it.
- Until this is done, there is no way to call the function. */
- emacs_abort ();
- }
- }
- }
+ val = funcall_subr (XSUBR (fun), numargs, args + 1);
else if (COMPILEDP (fun))
val = funcall_lambda (fun, numargs, args + 1);
else
@@ -2774,6 +2775,89 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
return val;
}
+
+/* Apply a C subroutine SUBR to the NUMARGS evaluated arguments in ARG_VECTOR
+ and return the result of evaluation. */
+
+Lisp_Object
+funcall_subr (struct Lisp_Subr *subr, ptrdiff_t numargs, Lisp_Object *args)
+{
+ if (numargs < subr->min_args
+ || (subr->max_args >= 0 && subr->max_args < numargs))
+ {
+ Lisp_Object fun;
+ XSETSUBR (fun, subr);
+ xsignal2 (Qwrong_number_of_arguments, fun, make_number (numargs));
+ }
+
+ else if (subr->max_args == UNEVALLED)
+ {
+ Lisp_Object fun;
+ XSETSUBR (fun, subr);
+ xsignal1 (Qinvalid_function, fun);
+ }
+
+ else if (subr->max_args == MANY)
+ return (subr->function.aMANY) (numargs, args);
+ else
+ {
+ Lisp_Object internal_argbuf[8];
+ Lisp_Object *internal_args;
+ if (subr->max_args > numargs)
+ {
+ eassert (subr->max_args <= ARRAYELTS (internal_argbuf));
+ internal_args = internal_argbuf;
+ memcpy (internal_args, args, numargs * word_size);
+ memclear (internal_args + numargs,
+ (subr->max_args - numargs) * word_size);
+ }
+ else
+ internal_args = args;
+ switch (subr->max_args)
+ {
+ case 0:
+ return (subr->function.a0 ());
+ case 1:
+ return (subr->function.a1 (internal_args[0]));
+ case 2:
+ return (subr->function.a2
+ (internal_args[0], internal_args[1]));
+ case 3:
+ return (subr->function.a3
+ (internal_args[0], internal_args[1], internal_args[2]));
+ case 4:
+ return (subr->function.a4
+ (internal_args[0], internal_args[1], internal_args[2],
+ internal_args[3]));
+ case 5:
+ return (subr->function.a5
+ (internal_args[0], internal_args[1], internal_args[2],
+ internal_args[3], internal_args[4]));
+ case 6:
+ return (subr->function.a6
+ (internal_args[0], internal_args[1], internal_args[2],
+ internal_args[3], internal_args[4], internal_args[5]));
+ case 7:
+ return (subr->function.a7
+ (internal_args[0], internal_args[1], internal_args[2],
+ internal_args[3], internal_args[4], internal_args[5],
+ internal_args[6]));
+ case 8:
+ return (subr->function.a8
+ (internal_args[0], internal_args[1], internal_args[2],
+ internal_args[3], internal_args[4], internal_args[5],
+ internal_args[6], internal_args[7]));
+
+ default:
+
+ /* If a subr takes more than 8 arguments without using MANY
+ or UNEVALLED, we need to extend this function to support it.
+ Until this is done, there is no way to call the function. */
+ emacs_abort ();
+ }
+ }
+}
+
static Lisp_Object
apply_lambda (Lisp_Object fun, Lisp_Object args, ptrdiff_t count)
{
@@ -2846,14 +2930,14 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
xsignal1 (Qinvalid_function, fun);
syms_left = AREF (fun, COMPILED_ARGLIST);
if (INTEGERP (syms_left))
- /* A byte-code object with a non-nil `push args' slot means we
+ /* A byte-code object with an integer args template means we
shouldn't bind any arguments, instead just call the byte-code
interpreter directly; it will push arguments as necessary.
- Byte-code objects with either a non-existent, or a nil value for
- the `push args' slot (the default), have dynamically-bound
- arguments, and use the argument-binding code below instead (as do
- all interpreted functions, even lexically bound ones). */
+ Byte-code objects with a nil args template (the default)
+ have dynamically-bound arguments, and use the
+ argument-binding code below instead (as do all interpreted
+ functions, even lexically bound ones). */
{
/* If we have not actually read the bytecode string
and constants vector yet, fetch them from the file. */
@@ -2871,6 +2955,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
emacs_abort ();
i = optional = rest = 0;
+ bool previous_optional_or_rest = false;
for (; CONSP (syms_left); syms_left = XCDR (syms_left))
{
QUIT;
@@ -2880,9 +2965,19 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
xsignal1 (Qinvalid_function, fun);
if (EQ (next, Qand_rest))
- rest = 1;
+ {
+ if (rest || previous_optional_or_rest)
+ xsignal1 (Qinvalid_function, fun);
+ rest = 1;
+ previous_optional_or_rest = true;
+ }
else if (EQ (next, Qand_optional))
- optional = 1;
+ {
+ if (optional || rest || previous_optional_or_rest)
+ xsignal1 (Qinvalid_function, fun);
+ optional = 1;
+ previous_optional_or_rest = true;
+ }
else
{
Lisp_Object arg;
@@ -2905,10 +3000,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
else
/* Dynamically bind NEXT. */
specbind (next, arg);
+ previous_optional_or_rest = false;
}
}
- if (!NILP (syms_left))
+ if (!NILP (syms_left) || previous_optional_or_rest)
xsignal1 (Qinvalid_function, fun);
else if (i < nargs)
xsignal2 (Qwrong_number_of_arguments, fun, make_number (nargs));
@@ -2934,6 +3030,118 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
return unbind_to (count, val);
}
+DEFUN ("func-arity", Ffunc_arity, Sfunc_arity, 1, 1, 0,
+ doc: /* Return minimum and maximum number of args allowed for FUNCTION.
+FUNCTION must be a function of some kind.
+The returned value is a cons cell (MIN . MAX). MIN is the minimum number
+of args. MAX is the maximum number, or the symbol `many', for a
+function with `&rest' args, or `unevalled' for a special form. */)
+ (Lisp_Object function)
+{
+ Lisp_Object original;
+ Lisp_Object funcar;
+ Lisp_Object result;
+
+ original = function;
+
+ retry:
+
+ /* Optimize for no indirection. */
+ function = original;
+ if (SYMBOLP (function) && !NILP (function))
+ {
+ function = XSYMBOL (function)->function;
+ if (SYMBOLP (function))
+ function = indirect_function (function);
+ }
+
+ if (CONSP (function) && EQ (XCAR (function), Qmacro))
+ function = XCDR (function);
+
+ if (SUBRP (function))
+ result = Fsubr_arity (function);
+ else if (COMPILEDP (function))
+ result = lambda_arity (function);
+ else
+ {
+ if (NILP (function))
+ xsignal1 (Qvoid_function, original);
+ if (!CONSP (function))
+ xsignal1 (Qinvalid_function, original);
+ funcar = XCAR (function);
+ if (!SYMBOLP (funcar))
+ xsignal1 (Qinvalid_function, original);
+ if (EQ (funcar, Qlambda)
+ || EQ (funcar, Qclosure))
+ result = lambda_arity (function);
+ else if (EQ (funcar, Qautoload))
+ {
+ Fautoload_do_load (function, original, Qnil);
+ goto retry;
+ }
+ else
+ xsignal1 (Qinvalid_function, original);
+ }
+ return result;
+}
+
+/* FUN must be either a lambda-expression or a compiled-code object. */
+static Lisp_Object
+lambda_arity (Lisp_Object fun)
+{
+ Lisp_Object syms_left;
+
+ if (CONSP (fun))
+ {
+ if (EQ (XCAR (fun), Qclosure))
+ {
+ fun = XCDR (fun); /* Drop `closure'. */
+ CHECK_LIST_CONS (fun, fun);
+ }
+ syms_left = XCDR (fun);
+ if (CONSP (syms_left))
+ syms_left = XCAR (syms_left);
+ else
+ xsignal1 (Qinvalid_function, fun);
+ }
+ else if (COMPILEDP (fun))
+ {
+ ptrdiff_t size = ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK;
+ if (size <= COMPILED_STACK_DEPTH)
+ xsignal1 (Qinvalid_function, fun);
+ syms_left = AREF (fun, COMPILED_ARGLIST);
+ if (INTEGERP (syms_left))
+ return get_byte_code_arity (syms_left);
+ }
+ else
+ emacs_abort ();
+
+ EMACS_INT minargs = 0, maxargs = 0;
+ bool optional = false;
+ for (; CONSP (syms_left); syms_left = XCDR (syms_left))
+ {
+ Lisp_Object next = XCAR (syms_left);
+ if (!SYMBOLP (next))
+ xsignal1 (Qinvalid_function, fun);
+
+ if (EQ (next, Qand_rest))
+ return Fcons (make_number (minargs), Qmany);
+ else if (EQ (next, Qand_optional))
+ optional = true;
+ else
+ {
+ if (!optional)
+ minargs++;
+ maxargs++;
+ }
+ }
+
+ if (!NILP (syms_left))
+ xsignal1 (Qinvalid_function, fun);
+
+ return Fcons (make_number (minargs), make_number (maxargs));
+}
+
DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
1, 1, 0,
doc: /* If byte-compiled OBJECT is lazy-loaded, fetch it now. */)
@@ -2998,6 +3206,36 @@ let_shadows_global_binding_p (Lisp_Object symbol)
return 0;
}
+static void
+do_specbind (struct Lisp_Symbol *sym, union specbinding *bind,
+ Lisp_Object value, enum Set_Internal_Bind bindflag)
+{
+ switch (sym->redirect)
+ {
+ case SYMBOL_PLAINVAL:
+ if (!sym->trapped_write)
+ SET_SYMBOL_VAL (sym, value);
+ else
+ set_internal (specpdl_symbol (bind), value, Qnil, bindflag);
+ break;
+
+ case SYMBOL_FORWARDED:
+ if (BUFFER_OBJFWDP (SYMBOL_FWD (sym))
+ && specpdl_kind (bind) == SPECPDL_LET_DEFAULT)
+ {
+ set_default_internal (specpdl_symbol (bind), value, bindflag);
+ return;
+ }
+ /* FALLTHROUGH */
+ case SYMBOL_LOCALIZED:
+ set_internal (specpdl_symbol (bind), value, Qnil, bindflag);
+ break;
+
+ default:
+ emacs_abort ();
+ }
+}
+
/* `specpdl_ptr' describes which variable is
let-bound, so it can be properly undone when we unbind_to.
It can be either a plain SPECPDL_LET or a SPECPDL_LET_LOCAL/DEFAULT.
@@ -3029,15 +3267,11 @@ specbind (Lisp_Object symbol, Lisp_Object value)
specpdl_ptr->let.kind = SPECPDL_LET;
specpdl_ptr->let.symbol = symbol;
specpdl_ptr->let.old_value = SYMBOL_VAL (sym);
+ specpdl_ptr->let.saved_value = Qnil;
grow_specpdl ();
- if (!sym->constant)
- SET_SYMBOL_VAL (sym, value);
- else
- set_internal (symbol, value, Qnil, 1);
+ do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
break;
case SYMBOL_LOCALIZED:
- if (SYMBOL_BLV (sym)->frame_local)
- error ("Frame-local vars cannot be let-bound");
case SYMBOL_FORWARDED:
{
Lisp_Object ovalue = find_symbol_value (symbol);
@@ -3045,6 +3279,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
specpdl_ptr->let.symbol = symbol;
specpdl_ptr->let.old_value = ovalue;
specpdl_ptr->let.where = Fcurrent_buffer ();
+ specpdl_ptr->let.saved_value = Qnil;
eassert (sym->redirect != SYMBOL_LOCALIZED
|| (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ())));
@@ -3065,7 +3300,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
{
specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
grow_specpdl ();
- Fset_default (symbol, value);
+ do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
return;
}
}
@@ -3073,7 +3308,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
specpdl_ptr->let.kind = SPECPDL_LET;
grow_specpdl ();
- set_internal (symbol, value, Qnil, 1);
+ do_specbind (sym, specpdl_ptr - 1, value, SET_INTERNAL_BIND);
break;
}
default: emacs_abort ();
@@ -3117,6 +3352,85 @@ record_unwind_protect_void (void (*function) (void))
grow_specpdl ();
}
+void
+rebind_for_thread_switch (void)
+{
+ union specbinding *bind;
+
+ for (bind = specpdl; bind != specpdl_ptr; ++bind)
+ {
+ if (bind->kind >= SPECPDL_LET)
+ {
+ Lisp_Object value = specpdl_saved_value (bind);
+ Lisp_Object sym = specpdl_symbol (bind);
+ bind->let.saved_value = Qnil;
+ do_specbind (XSYMBOL (sym), bind, value,
+ SET_INTERNAL_THREAD_SWITCH);
+ }
+ }
+}
+
+static void
+do_one_unbind (union specbinding *this_binding, bool unwinding,
+ enum Set_Internal_Bind bindflag)
+{
+ eassert (unwinding || this_binding->kind >= SPECPDL_LET);
+ switch (this_binding->kind)
+ {
+ case SPECPDL_UNWIND:
+ this_binding->unwind.func (this_binding->unwind.arg);
+ break;
+ case SPECPDL_UNWIND_PTR:
+ this_binding->unwind_ptr.func (this_binding->unwind_ptr.arg);
+ break;
+ case SPECPDL_UNWIND_INT:
+ this_binding->unwind_int.func (this_binding->unwind_int.arg);
+ break;
+ case SPECPDL_UNWIND_VOID:
+ this_binding->unwind_void.func ();
+ break;
+ case SPECPDL_BACKTRACE:
+ break;
+ case SPECPDL_LET:
+ { /* If variable has a trivial value (no forwarding), and isn't
+ trapped, we can just set it. */
+ Lisp_Object sym = specpdl_symbol (this_binding);
+ if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL)
+ {
+ if (XSYMBOL (sym)->trapped_write == SYMBOL_UNTRAPPED_WRITE)
+ SET_SYMBOL_VAL (XSYMBOL (sym), specpdl_old_value (this_binding));
+ else
+ set_internal (sym, specpdl_old_value (this_binding),
+ Qnil, bindflag);
+ break;
+ }
+ else
+ { /* FALLTHROUGH!!
+ NOTE: we only ever come here if make_local_foo was used for
+ the first time on this var within this let. */
+ }
+ }
+ case SPECPDL_LET_DEFAULT:
+ set_default_internal (specpdl_symbol (this_binding),
+ specpdl_old_value (this_binding),
+ bindflag);
+ break;
+ case SPECPDL_LET_LOCAL:
+ {
+ Lisp_Object symbol = specpdl_symbol (this_binding);
+ Lisp_Object where = specpdl_where (this_binding);
+ Lisp_Object old_value = specpdl_old_value (this_binding);
+ eassert (BUFFERP (where));
+
+ /* If this was a local binding, reset the value in the appropriate
+ buffer, but only if that buffer's binding still exists. */
+ if (!NILP (Flocal_variable_p (symbol, where)))
+ set_internal (symbol, old_value, where, bindflag);
+ }
+ break;
+ }
+}
+
static void
do_nothing (void)
{}
@@ -3176,64 +3490,16 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
while (specpdl_ptr != specpdl + count)
{
- /* Decrement specpdl_ptr before we do the work to unbind it, so
- that an error in unbinding won't try to unbind the same entry
- again. Take care to copy any parts of the binding needed
- before invoking any code that can make more bindings. */
-
- specpdl_ptr--;
+ /* Copy the binding, and decrement specpdl_ptr, before we do
+ the work to unbind it. We decrement first
+ so that an error in unbinding won't try to unbind
+ the same entry again, and we copy the binding first
+ in case more bindings are made during some of the code we run. */
- switch (specpdl_ptr->kind)
- {
- case SPECPDL_UNWIND:
- specpdl_ptr->unwind.func (specpdl_ptr->unwind.arg);
- break;
- case SPECPDL_UNWIND_PTR:
- specpdl_ptr->unwind_ptr.func (specpdl_ptr->unwind_ptr.arg);
- break;
- case SPECPDL_UNWIND_INT:
- specpdl_ptr->unwind_int.func (specpdl_ptr->unwind_int.arg);
- break;
- case SPECPDL_UNWIND_VOID:
- specpdl_ptr->unwind_void.func ();
- break;
- case SPECPDL_BACKTRACE:
- break;
- case SPECPDL_LET:
- { /* If variable has a trivial value (no forwarding), we can
- just set it. No need to check for constant symbols here,
- since that was already done by specbind. */
- Lisp_Object sym = specpdl_symbol (specpdl_ptr);
- if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL)
- {
- SET_SYMBOL_VAL (XSYMBOL (sym),
- specpdl_old_value (specpdl_ptr));
- break;
- }
- else
- { /* FALLTHROUGH!!
- NOTE: we only ever come here if make_local_foo was used for
- the first time on this var within this let. */
- }
- }
- case SPECPDL_LET_DEFAULT:
- Fset_default (specpdl_symbol (specpdl_ptr),
- specpdl_old_value (specpdl_ptr));
- break;
- case SPECPDL_LET_LOCAL:
- {
- Lisp_Object symbol = specpdl_symbol (specpdl_ptr);
- Lisp_Object where = specpdl_where (specpdl_ptr);
- Lisp_Object old_value = specpdl_old_value (specpdl_ptr);
- eassert (BUFFERP (where));
+ union specbinding this_binding;
+ this_binding = *--specpdl_ptr;
- /* If this was a local binding, reset the value in the appropriate
- buffer, but only if that buffer's binding still exists. */
- if (!NILP (Flocal_variable_p (symbol, where)))
- set_internal (symbol, old_value, where, 1);
- }
- break;
- }
+ do_one_unbind (&this_binding, true, SET_INTERNAL_UNBIND);
}
if (NILP (Vquit_flag) && !NILP (quitf))
@@ -3242,6 +3508,22 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
return value;
}
+void
+unbind_for_thread_switch (struct thread_state *thr)
+{
+ union specbinding *bind;
+
+ for (bind = thr->m_specpdl_ptr; bind > thr->m_specpdl;)
+ {
+ if ((--bind)->kind >= SPECPDL_LET)
+ {
+ Lisp_Object sym = specpdl_symbol (bind);
+ bind->let.saved_value = find_symbol_value (sym);
+ do_one_unbind (bind, false, SET_INTERNAL_THREAD_SWITCH);
+ }
+ }
+}
+
DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0,
doc: /* Return non-nil if SYMBOL's global binding has been declared special.
A special variable is one that will be bound dynamically, even in a
@@ -3253,83 +3535,29 @@ context where binding is lexical by default. */)
}
-DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 2, 0,
- doc: /* Set the debug-on-exit flag of eval frame LEVEL levels down to FLAG.
-The debugger is entered when that frame exits, if the flag is non-nil. */)
- (Lisp_Object level, Lisp_Object flag)
-{
- union specbinding *pdl = backtrace_top ();
- register EMACS_INT i;
-
- CHECK_NUMBER (level);
-
- for (i = 0; backtrace_p (pdl) && i < XINT (level); i++)
- pdl = backtrace_next (pdl);
-
- if (backtrace_p (pdl))
- set_backtrace_debug_on_exit (pdl, !NILP (flag));
-
- return flag;
-}
-
-DEFUN ("backtrace", Fbacktrace, Sbacktrace, 0, 0, "",
- doc: /* Print a trace of Lisp function calls currently active.
-Output stream used is value of `standard-output'. */)
- (void)
+static union specbinding *
+get_backtrace_starting_at (Lisp_Object base)
{
union specbinding *pdl = backtrace_top ();
- Lisp_Object tem;
- Lisp_Object old_print_level = Vprint_level;
-
- if (NILP (Vprint_level))
- XSETFASTINT (Vprint_level, 8);
- while (backtrace_p (pdl))
- {
- write_string (backtrace_debug_on_exit (pdl) ? "* " : " ");
- if (backtrace_nargs (pdl) == UNEVALLED)
- {
- Fprin1 (Fcons (backtrace_function (pdl), *backtrace_args (pdl)),
- Qnil);
- write_string ("\n");
- }
- else
- {
- tem = backtrace_function (pdl);
- Fprin1 (tem, Qnil); /* This can QUIT. */
- write_string ("(");
- {
- ptrdiff_t i;
- for (i = 0; i < backtrace_nargs (pdl); i++)
- {
- if (i) write_string (" ");
- Fprin1 (backtrace_args (pdl)[i], Qnil);
- }
- }
- write_string (")\n");
- }
- pdl = backtrace_next (pdl);
+ if (!NILP (base))
+ { /* Skip up to `base'. */
+ base = Findirect_function (base, Qt);
+ while (backtrace_p (pdl)
+ && !EQ (base, Findirect_function (backtrace_function (pdl), Qt)))
+ pdl = backtrace_next (pdl);
}
- Vprint_level = old_print_level;
- return Qnil;
+ return pdl;
}
static union specbinding *
get_backtrace_frame (Lisp_Object nframes, Lisp_Object base)
{
- union specbinding *pdl = backtrace_top ();
register EMACS_INT i;
CHECK_NATNUM (nframes);
-
- if (!NILP (base))
- { /* Skip up to `base'. */
- base = Findirect_function (base, Qt);
- while (backtrace_p (pdl)
- && !EQ (base, Findirect_function (backtrace_function (pdl), Qt)))
- pdl = backtrace_next (pdl);
- }
+ union specbinding *pdl = get_backtrace_starting_at (base);
/* Find the frame requested. */
for (i = XFASTINT (nframes); i > 0 && backtrace_p (pdl); i--)
@@ -3338,33 +3566,71 @@ get_backtrace_frame (Lisp_Object nframes, Lisp_Object base)
return pdl;
}
-DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 2, NULL,
- doc: /* Return the function and arguments NFRAMES up from current execution point.
-If that frame has not evaluated the arguments yet (or is a special form),
-the value is (nil FUNCTION ARG-FORMS...).
-If that frame has evaluated its arguments and called its function already,
-the value is (t FUNCTION ARG-VALUES...).
-A &rest arg is represented as the tail of the list ARG-VALUES.
-FUNCTION is whatever was supplied as car of evaluated list,
-or a lambda expression for macro calls.
-If NFRAMES is more than the number of frames, the value is nil.
-If BASE is non-nil, it should be a function and NFRAMES counts from its
-nearest activation frame. */)
- (Lisp_Object nframes, Lisp_Object base)
+static Lisp_Object
+backtrace_frame_apply (Lisp_Object function, union specbinding *pdl)
{
- union specbinding *pdl = get_backtrace_frame (nframes, base);
-
if (!backtrace_p (pdl))
return Qnil;
+
+ Lisp_Object flags = Qnil;
+ if (backtrace_debug_on_exit (pdl))
+ flags = Fcons (QCdebug_on_exit, Fcons (Qt, Qnil));
+
if (backtrace_nargs (pdl) == UNEVALLED)
- return Fcons (Qnil,
- Fcons (backtrace_function (pdl), *backtrace_args (pdl)));
+ return call4 (function, Qnil, backtrace_function (pdl), *backtrace_args (pdl), flags);
else
{
Lisp_Object tem = Flist (backtrace_nargs (pdl), backtrace_args (pdl));
+ return call4 (function, Qt, backtrace_function (pdl), tem, flags);
+ }
+}
- return Fcons (Qt, Fcons (backtrace_function (pdl), tem));
+DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 2, 0,
+ doc: /* Set the debug-on-exit flag of eval frame LEVEL levels down to FLAG.
+The debugger is entered when that frame exits, if the flag is non-nil. */)
+ (Lisp_Object level, Lisp_Object flag)
+{
+ CHECK_NUMBER (level);
+ union specbinding *pdl = get_backtrace_frame(level, Qnil);
+
+ if (backtrace_p (pdl))
+ set_backtrace_debug_on_exit (pdl, !NILP (flag));
+
+ return flag;
+}
+
+DEFUN ("mapbacktrace", Fmapbacktrace, Smapbacktrace, 1, 2, 0,
+ doc: /* Call FUNCTION for each frame in backtrace.
+If BASE is non-nil, it should be a function and iteration will start
+from its nearest activation frame.
+FUNCTION is called with 4 arguments: EVALD, FUNC, ARGS, and FLAGS. If
+a frame has not evaluated its arguments yet or is a special form,
+EVALD is nil and ARGS is a list of forms. If a frame has evaluated
+its arguments and called its function already, EVALD is t and ARGS is
+a list of values.
+FLAGS is a plist of properties of the current frame: currently, the
+only supported property is :debug-on-exit. `mapbacktrace' always
+returns nil. */)
+ (Lisp_Object function, Lisp_Object base)
+{
+ union specbinding *pdl = get_backtrace_starting_at (base);
+
+ while (backtrace_p (pdl))
+ {
+ backtrace_frame_apply (function, pdl);
+ pdl = backtrace_next (pdl);
}
+
+ return Qnil;
+}
+
+DEFUN ("backtrace-frame--internal", Fbacktrace_frame_internal,
+ Sbacktrace_frame_internal, 3, 3, NULL,
+ doc: /* Call FUNCTION on stack frame NFRAMES away from BASE.
+Return the result of FUNCTION, or nil if no matching frame could be found. */)
+ (Lisp_Object function, Lisp_Object nframes, Lisp_Object base)
+{
+ return backtrace_frame_apply (function, get_backtrace_frame (nframes, base));
}
/* For backtrace-eval, we want to temporarily unwind the last few elements of
@@ -3451,7 +3717,7 @@ backtrace_eval_unrewind (int distance)
{
set_specpdl_old_value
(tmp, Fbuffer_local_value (symbol, where));
- set_internal (symbol, old_value, where, 1);
+ set_internal (symbol, old_value, where, SET_INTERNAL_UNBIND);
}
}
break;
@@ -3560,10 +3826,10 @@ NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'.
void
-mark_specpdl (void)
+mark_specpdl (union specbinding *first, union specbinding *ptr)
{
union specbinding *pdl;
- for (pdl = specpdl; pdl != specpdl_ptr; pdl++)
+ for (pdl = first; pdl != ptr; pdl++)
{
switch (pdl->kind)
{
@@ -3589,6 +3855,7 @@ mark_specpdl (void)
case SPECPDL_LET:
mark_object (specpdl_symbol (pdl));
mark_object (specpdl_old_value (pdl));
+ mark_object (specpdl_saved_value (pdl));
break;
case SPECPDL_UNWIND_PTR:
@@ -3725,6 +3992,10 @@ This is nil when the debugger is called under circumstances where it
might not be safe to continue. */);
debugger_may_continue = 1;
+ DEFVAR_BOOL ("debugger-stack-frame-as-list", debugger_stack_frame_as_list,
+ doc: /* Non-nil means display call stack frames as lists. */);
+ debugger_stack_frame_as_list = 0;
+
DEFVAR_LISP ("debugger", Vdebugger,
doc: /* Function to call to invoke debugger.
If due to frame exit, args are `exit' and the value being returned;
@@ -3791,6 +4062,7 @@ alist of active lexical bindings. */);
defsubr (&Sset_default_toplevel_value);
defsubr (&Sdefvar);
defsubr (&Sdefvaralias);
+ DEFSYM (Qdefvaralias, "defvaralias");
defsubr (&Sdefconst);
defsubr (&Smake_var_non_special);
defsubr (&Slet);
@@ -3808,6 +4080,7 @@ alist of active lexical bindings. */);
defsubr (&Seval);
defsubr (&Sapply);
defsubr (&Sfuncall);
+ defsubr (&Sfunc_arity);
defsubr (&Srun_hooks);
defsubr (&Srun_hook_with_args);
defsubr (&Srun_hook_with_args_until_success);
@@ -3815,8 +4088,9 @@ alist of active lexical bindings. */);
defsubr (&Srun_hook_wrapped);
defsubr (&Sfetch_bytecode);
defsubr (&Sbacktrace_debug);
- defsubr (&Sbacktrace);
- defsubr (&Sbacktrace_frame);
+ DEFSYM (QCdebug_on_exit, ":debug-on-exit");
+ defsubr (&Smapbacktrace);
+ defsubr (&Sbacktrace_frame_internal);
defsubr (&Sbacktrace_eval);
defsubr (&Sbacktrace__locals);
defsubr (&Sspecial_variable_p);