/* Evaluator for GNU Emacs Lisp interpreter.
- Copyright (C) 1985, 86, 87, 93, 94, 95, 99, 2000
+ Copyright (C) 1985, 86, 87, 93, 94, 95, 99, 2000, 2001
Free Software Foundation, Inc.
This file is part of GNU Emacs.
/* Putting it in lisp.h makes cc bomb out! */
struct backtrace
- {
- struct backtrace *next;
- Lisp_Object *function;
- Lisp_Object *args; /* Points to vector of args. */
- int nargs; /* Length of vector.
+{
+ struct backtrace *next;
+ Lisp_Object *function;
+ Lisp_Object *args; /* Points to vector of args. */
+ int nargs; /* Length of vector.
If nargs is UNEVALLED, args points to slot holding
list of unevalled args */
- char evalargs;
- /* Nonzero means call value of debugger when done with this operation. */
- char debug_on_exit;
- };
+ char evalargs;
+ /* Nonzero means call value of debugger when done with this operation. */
+ char debug_on_exit;
+};
struct backtrace *backtrace_list;
All the other members are concerned with restoring the interpreter
state. */
+
struct catchtag
- {
- Lisp_Object tag;
- Lisp_Object val;
- struct catchtag *next;
- struct gcpro *gcpro;
- jmp_buf jmp;
- struct backtrace *backlist;
- struct handler *handlerlist;
- int lisp_eval_depth;
- int pdlcount;
- int poll_suppress_count;
- struct byte_stack *byte_stack;
- };
+{
+ Lisp_Object tag;
+ Lisp_Object val;
+ struct catchtag *next;
+ struct gcpro *gcpro;
+ jmp_buf jmp;
+ struct backtrace *backlist;
+ struct handler *handlerlist;
+ int lisp_eval_depth;
+ int pdlcount;
+ int poll_suppress_count;
+ struct byte_stack *byte_stack;
+};
struct catchtag *catchlist;
/* This holds either the symbol `run-hooks' or nil.
It is nil at an early stage of startup, and when Emacs
is shutting down. */
+
Lisp_Object Vrun_hooks;
/* Non-nil means record all fset's and provide's, to be undone
Lisp_Object Vautoload_queue;
/* Current number of specbindings allocated in specpdl. */
+
int specpdl_size;
/* Pointer to beginning of specpdl. */
+
struct specbinding *specpdl;
/* Pointer to first unused element in specpdl. */
+
struct specbinding *specpdl_ptr;
/* Maximum size allowed for specpdl allocation */
+
int max_specpdl_size;
/* Depth in Lisp evaluations and function calls. */
+
int lisp_eval_depth;
/* Maximum allowed depth in Lisp evaluations and function calls. */
+
int max_lisp_eval_depth;
/* Nonzero means enter debugger before next function call */
+
int debug_on_next_call;
/* Non-zero means debuffer may continue. This is zero when the
/* List of conditions (non-nil atom means all) which cause a backtrace
if an error is handled by the command loop's error handler. */
+
Lisp_Object Vstack_trace_on_error;
/* List of conditions (non-nil atom means all) which enter the debugger
if an error is handled by the command loop's error handler. */
+
Lisp_Object Vdebug_on_error;
/* List of conditions and regexps specifying error messages which
do not enter the debugger even if Vdebug_on_errors says they should. */
+
Lisp_Object Vdebug_ignored_errors;
/* Non-nil means call the debugger even if the error will be handled. */
+
Lisp_Object Vdebug_on_signal;
/* Hook for edebug to use. */
+
Lisp_Object Vsignal_hook_function;
/* Nonzero means enter debugger if a quit signal
is handled by the command loop's error handler. */
+
int debug_on_quit;
/* The value of num_nonmacro_input_events as of the last time we
know that the debugger itself has an error, and we should just
signal the error instead of entering an infinite loop of debugger
invocations. */
+
int when_entered_debugger;
Lisp_Object Vdebugger;
+/* The function from which the last `signal' was called. Set in
+ Fsignal. */
+
+Lisp_Object Vsignaling_function;
+
+/* Set to non-zero while processing X events. Checked in Feval to
+ make sure the Lisp interpreter isn't called from a signal handler,
+ which is unsafe because the interpreter isn't reentrant. */
+
+int handling_signal;
+
void specbind (), record_unwind_protect ();
Lisp_Object run_hook_with_args ();
if (specpdl_size + 40 > max_specpdl_size)
max_specpdl_size = specpdl_size + 40;
+#ifdef HAVE_X_WINDOWS
+ if (display_hourglass_p)
+ cancel_hourglass ();
+#endif
+
debug_on_next_call = 0;
when_entered_debugger = num_nonmacro_input_events;
return Fcar (args);
}
+
DEFUN ("interactive-p", Finteractive_p, Sinteractive_p, 0, 0, 0,
"Return t if function in which this appears was called interactively.\n\
This means that the function was called with call-interactively (which\n\
and input is currently coming from the keyboard (not in keyboard macro).")
()
{
- register struct backtrace *btp;
- register Lisp_Object fun;
+ return interactive_p (1) ? Qt : Qnil;
+}
+
+
+/* Return 1 if function in which this appears was called
+ interactively. This means that the function was called with
+ call-interactively (which includes being called as the binding of
+ a key) and input is currently coming from the keyboard (not in
+ keyboard macro).
+
+ EXCLUDE_SUBRS_P non-zero means always return 0 if the function
+ called is a built-in. */
+
+int
+interactive_p (exclude_subrs_p)
+ int exclude_subrs_p;
+{
+ struct backtrace *btp;
+ Lisp_Object fun;
if (!INTERACTIVE)
- return Qnil;
+ return 0;
btp = backtrace_list;
/* If this isn't a byte-compiled function, there may be a frame at
- the top for Finteractive_p itself. If so, skip it. */
+ the top for Finteractive_p. If so, skip it. */
fun = Findirect_function (*btp->function);
if (SUBRP (fun) && XSUBR (fun) == &Sinteractive_p)
btp = btp->next;
Fbytecode at the top. If this frame is for a built-in function
(such as load or eval-region) return nil. */
fun = Findirect_function (*btp->function);
- if (SUBRP (fun))
- return Qnil;
+ if (exclude_subrs_p && SUBRP (fun))
+ return 0;
+
/* btp points to the frame of a Lisp function that called interactive-p.
Return t if that function was called interactively. */
if (btp && btp->next && EQ (*btp->next->function, Qcall_interactively))
- return Qt;
- return Qnil;
+ return 1;
+ return 0;
}
+
DEFUN ("defun", Fdefun, Sdefun, 2, UNEVALLED, 0,
"Define NAME as a function.\n\
The definition is (lambda ARGLIST [DOCSTRING] BODY...).\n\
buffer-local values are not affected.\n\
INITVALUE and DOCSTRING are optional.\n\
If DOCSTRING starts with *, this variable is identified as a user option.\n\
- This means that M-x set-variable and M-x edit-options recognize it.\n\
+ This means that M-x set-variable recognizes it.\n\
+ See also `user-variable-p'.\n\
If INITVALUE is missing, SYMBOL's value is not set.")
(args)
Lisp_Object args;
If FORM is not a macro call, it is returned unchanged.\n\
Otherwise, the macro is expanded and the expansion is considered\n\
in place of FORM. When a non-macro-call results, it is returned.\n\n\
-The second optional arg ENVIRONMENT species an environment of macro\n\
+The second optional arg ENVIRONMENT specifies an environment of macro\n\
definitions to shadow the loaded ones for use in file byte-compilation.")
(form, environment)
Lisp_Object form;
Lisp_Object val;
struct catchtag c;
struct handler h;
- register Lisp_Object var, bodyform, handlers;
+ register Lisp_Object bodyform, handlers;
+ volatile Lisp_Object var;
var = Fcar (args);
bodyform = Fcar (Fcdr (args));
struct catchtag c;
struct handler h;
+#if 0 /* Can't do this check anymore because realize_basic_faces has
+ to BLOCK_INPUT, and can call Lisp. What's really needed is a
+ flag indicating that we're currently handling a signal. */
/* Since Fsignal resets this to 0, it had better be 0 now
or else we have a potential bug. */
if (interrupt_input_blocked != 0)
abort ();
+#endif
c.tag = Qnil;
c.val = Qnil;
handlerlist = h.next;
return val;
}
+
+
+/* Like internal_condition_case but call HFUN with NARGS as first,
+ and ARGS as second argument. */
+
+Lisp_Object
+internal_condition_case_2 (bfun, nargs, args, handlers, hfun)
+ Lisp_Object (*bfun) ();
+ int nargs;
+ Lisp_Object *args;
+ Lisp_Object handlers;
+ Lisp_Object (*hfun) ();
+{
+ Lisp_Object val;
+ struct catchtag c;
+ struct handler h;
+
+ c.tag = Qnil;
+ c.val = Qnil;
+ c.backlist = backtrace_list;
+ c.handlerlist = handlerlist;
+ c.lisp_eval_depth = lisp_eval_depth;
+ c.pdlcount = specpdl_ptr - specpdl;
+ c.poll_suppress_count = poll_suppress_count;
+ c.gcpro = gcprolist;
+ c.byte_stack = byte_stack_list;
+ if (_setjmp (c.jmp))
+ {
+ return (*hfun) (c.val);
+ }
+ c.next = catchlist;
+ catchlist = &c;
+ h.handler = handlers;
+ h.var = Qnil;
+ h.next = handlerlist;
+ h.tag = &c;
+ handlerlist = &h;
+
+ val = (*bfun) (nargs, args);
+ catchlist = c.next;
+ handlerlist = h.next;
+ return val;
+}
+
\f
static Lisp_Object find_handler_clause ();
Lisp_Object debugger_value;
Lisp_Object string;
Lisp_Object real_error_symbol;
- extern int display_busy_cursor_p;
+ extern int display_hourglass_p;
+ struct backtrace *bp;
- immediate_quit = 0;
+ immediate_quit = handling_signal = 0;
if (gc_in_progress || waiting_for_input)
abort ();
real_error_symbol = error_symbol;
#ifdef HAVE_X_WINDOWS
- if (display_busy_cursor_p)
- Fx_hide_busy_cursor (Qt);
+ if (display_hourglass_p)
+ cancel_hourglass ();
#endif
/* This hook is used by edebug. */
conditions = Fget (real_error_symbol, Qerror_conditions);
+ /* Remember from where signal was called. Skip over the frame for
+ `signal' itself. If a frame for `error' follows, skip that,
+ too. */
+ Vsignaling_function = Qnil;
+ if (backtrace_list)
+ {
+ bp = backtrace_list->next;
+ if (bp && bp->function && EQ (*bp->function, Qerror))
+ bp = bp->next;
+ if (bp && bp->function)
+ Vsignaling_function = *bp->function;
+ }
+
for (; handlerlist; handlerlist = handlerlist->next)
{
register Lisp_Object clause;
+
+ if (lisp_eval_depth + 20 > max_lisp_eval_depth)
+ max_lisp_eval_depth = lisp_eval_depth + 20;
+
+ if (specpdl_size + 40 > max_specpdl_size)
+ max_specpdl_size = specpdl_size + 40;
+
clause = find_handler_clause (handlerlist->handler, conditions,
error_symbol, data, &debugger_value);
int first_string = 1;
Lisp_Object error_message;
- for (tail = Vdebug_ignored_errors; CONSP (tail);
- tail = XCDR (tail))
+ error_message = Qnil;
+ for (tail = Vdebug_ignored_errors; CONSP (tail); tail = XCDR (tail))
{
if (STRINGP (XCAR (tail)))
{
error_message = Ferror_message_string (data);
first_string = 0;
}
+
if (fast_string_match (XCAR (tail), error_message) >= 0)
return 1;
}
{
Lisp_Object contail;
- for (contail = conditions; CONSP (contail);
- contail = XCDR (contail))
+ for (contail = conditions; CONSP (contail); contail = XCDR (contail))
if (EQ (XCAR (tail), XCAR (contail)))
return 1;
}
if (wants_debugger (Vstack_trace_on_error, conditions))
{
-#ifdef __STDC__
+#ifdef PROTOTYPES
internal_with_output_to_temp_buffer ("*Backtrace*",
(Lisp_Object (*) (Lisp_Object)) Fbacktrace,
Qnil);
string = build_string (buffer);
if (allocated)
- free (buffer);
+ xfree (buffer);
Fsignal (Qerror, Fcons (string, Qnil));
+ abort ();
}
\f
DEFUN ("commandp", Fcommandp, Scommandp, 1, 1, 0,
&& EQ (XCAR (XSYMBOL (function)->function), Qautoload)))
return Qnil;
+ if (NILP (Vpurify_flag))
+ /* Only add entries after dumping, because the ones before are
+ not useful and else we get loads of them from the loaddefs.el. */
+ LOADHIST_ATTACH (Fcons (Qautoload, function));
+
#ifdef NO_ARG_ARRAY
args[0] = file;
args[1] = docstring;
XSYMBOL (funname)->name->data);
UNGCPRO;
}
+
\f
DEFUN ("eval", Feval, Seval, 1, 1, 0,
"Evaluate FORM and return its value.")
struct backtrace backtrace;
struct gcpro gcpro1, gcpro2, gcpro3;
- /* Since Fsignal resets this to 0, it had better be 0 now
- or else we have a potential bug. */
- if (interrupt_input_blocked != 0)
+ if (handling_signal)
abort ();
if (SYMBOLP (form))
enum run_hooks_condition {to_completion, until_success, until_failure};
-DEFUN ("run-hooks", Frun_hooks, Srun_hooks, 1, MANY, 0,
+DEFUN ("run-hooks", Frun_hooks, Srun_hooks, 0, MANY, 0,
"Run each hook in HOOKS. Major mode functions use this.\n\
Each argument should be a symbol, a hook variable.\n\
These symbols are processed in the order specified.\n\
int nargs;
register Lisp_Object *arg_vector;
{
- Lisp_Object val, tem;
- register Lisp_Object syms_left;
- Lisp_Object numargs;
- register Lisp_Object next;
+ Lisp_Object val, syms_left, next;
int count = specpdl_ptr - specpdl;
- register int i;
- int optional = 0, rest = 0;
-
- specbind (Qmocklisp_arguments, Qt); /* t means NOT mocklisp! */
+ int i, optional, rest;
- XSETFASTINT (numargs, nargs);
+ if (NILP (Vmocklisp_arguments))
+ specbind (Qmocklisp_arguments, Qt); /* t means NOT mocklisp! */
if (CONSP (fun))
- syms_left = Fcar (Fcdr (fun));
+ {
+ syms_left = XCDR (fun);
+ if (CONSP (syms_left))
+ syms_left = XCAR (syms_left);
+ else
+ return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
+ }
else if (COMPILEDP (fun))
syms_left = XVECTOR (fun)->contents[COMPILED_ARGLIST];
- else abort ();
+ else
+ abort ();
- i = 0;
- for (; !NILP (syms_left); syms_left = Fcdr (syms_left))
+ i = optional = rest = 0;
+ for (; CONSP (syms_left); syms_left = XCDR (syms_left))
{
QUIT;
- next = Fcar (syms_left);
+
+ next = XCAR (syms_left);
while (!SYMBOLP (next))
next = Fsignal (Qinvalid_function, Fcons (fun, Qnil));
+
if (EQ (next, Qand_rest))
rest = 1;
else if (EQ (next, Qand_optional))
i = nargs;
}
else if (i < nargs)
- {
- tem = arg_vector[i++];
- specbind (next, tem);
- }
+ specbind (next, arg_vector[i++]);
else if (!optional)
- return Fsignal (Qwrong_number_of_arguments, Fcons (fun, Fcons (numargs, Qnil)));
+ return Fsignal (Qwrong_number_of_arguments,
+ Fcons (fun, Fcons (make_number (nargs), Qnil)));
else
specbind (next, Qnil);
}
- if (i < nargs)
- return Fsignal (Qwrong_number_of_arguments, Fcons (fun, Fcons (numargs, Qnil)));
+ if (!NILP (syms_left))
+ return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
+ else if (i < nargs)
+ return Fsignal (Qwrong_number_of_arguments,
+ Fcons (fun, Fcons (make_number (nargs), Qnil)));
if (CONSP (fun))
- val = Fprogn (Fcdr (Fcdr (fun)));
+ val = Fprogn (XCDR (XCDR (fun)));
else
{
/* If we have not actually read the bytecode string
XVECTOR (fun)->contents[COMPILED_CONSTANTS],
XVECTOR (fun)->contents[COMPILED_STACK_DEPTH]);
}
+
return unbind_to (count, val);
}
Lisp_Object ovalue;
CHECK_SYMBOL (symbol, 0);
-
- ovalue = find_symbol_value (symbol);
-
if (specpdl_ptr == specpdl + specpdl_size)
grow_specpdl ();
- specpdl_ptr->func = 0;
- specpdl_ptr->old_value = ovalue;
-
- if (BUFFER_LOCAL_VALUEP (XSYMBOL (symbol)->value)
- || SOME_BUFFER_LOCAL_VALUEP (XSYMBOL (symbol)->value)
- || BUFFER_OBJFWDP (XSYMBOL (symbol)->value))
- {
- Lisp_Object buffer;
- /* For a local variable, record both the symbol and which
- buffer's value we are saving. */
- buffer = Fcurrent_buffer ();
- /* If the variable is not local in this buffer,
- we are saving the global value, so restore that. */
- if (NILP (Flocal_variable_p (symbol, buffer)))
- buffer = Qnil;
- specpdl_ptr->symbol = Fcons (symbol, buffer);
+
+ /* The most common case is that a non-constant symbol with a trivial
+ value. Make that as fast as we can. */
+ if (!MISCP (XSYMBOL (symbol)->value)
+ && !EQ (symbol, Qnil)
+ && !EQ (symbol, Qt)
+ && !(XSYMBOL (symbol)->name->data[0] == ':'
+ && EQ (XSYMBOL (symbol)->obarray, initial_obarray)
+ && !EQ (value, symbol)))
+ {
+ specpdl_ptr->symbol = symbol;
+ specpdl_ptr->old_value = XSYMBOL (symbol)->value;
+ specpdl_ptr->func = NULL;
+ ++specpdl_ptr;
+ XSYMBOL (symbol)->value = value;
}
else
- specpdl_ptr->symbol = symbol;
+ {
+ ovalue = find_symbol_value (symbol);
+ specpdl_ptr->func = 0;
+ specpdl_ptr->old_value = ovalue;
- specpdl_ptr++;
- if (BUFFER_OBJFWDP (ovalue) || KBOARD_OBJFWDP (ovalue))
- store_symval_forwarding (symbol, ovalue, value);
- else
- set_internal (symbol, value, 0, 1);
+ if (BUFFER_LOCAL_VALUEP (XSYMBOL (symbol)->value)
+ || SOME_BUFFER_LOCAL_VALUEP (XSYMBOL (symbol)->value)
+ || BUFFER_OBJFWDP (XSYMBOL (symbol)->value))
+ {
+ Lisp_Object current_buffer, binding_buffer;
+
+ /* For a local variable, record both the symbol and which
+ buffer's value we are saving. */
+ current_buffer = Fcurrent_buffer ();
+ binding_buffer = current_buffer;
+
+ /* If the variable is not local in this buffer,
+ we are saving the global value, so restore that. */
+ if (NILP (Flocal_variable_p (symbol, binding_buffer)))
+ binding_buffer = Qnil;
+ specpdl_ptr->symbol
+ = Fcons (symbol, Fcons (binding_buffer, current_buffer));
+
+ /* If SYMBOL is a per-buffer variable which doesn't have a
+ buffer-local value here, make the `let' change the global
+ value by changing the value of SYMBOL in all buffers not
+ having their own value. This is consistent with what
+ happens with other buffer-local variables. */
+ if (NILP (binding_buffer)
+ && BUFFER_OBJFWDP (XSYMBOL (symbol)->value))
+ {
+ ++specpdl_ptr;
+ Fset_default (symbol, value);
+ return;
+ }
+ }
+ else
+ specpdl_ptr->symbol = symbol;
+
+ specpdl_ptr++;
+ if (BUFFER_OBJFWDP (ovalue) || KBOARD_OBJFWDP (ovalue))
+ store_symval_forwarding (symbol, ovalue, value);
+ else
+ set_internal (symbol, value, 0, 1);
+ }
}
void
struct gcpro gcpro1;
GCPRO1 (value);
-
Vquit_flag = Qnil;
while (specpdl_ptr != specpdl + count)
{
--specpdl_ptr;
+
if (specpdl_ptr->func != 0)
(*specpdl_ptr->func) (specpdl_ptr->old_value);
/* Note that a "binding" of nil is really an unwind protect,
so in that case the "old value" is a list of forms to evaluate. */
else if (NILP (specpdl_ptr->symbol))
Fprogn (specpdl_ptr->old_value);
+ /* If the symbol is a list, it is really
+ (SYMBOL BINDING_BUFFER . CURRENT_BUFFER)
+ and it indicates we bound a variable that has
+ buffer-local bindings. */
else if (CONSP (specpdl_ptr->symbol))
{
Lisp_Object symbol, buffer;
symbol = XCAR (specpdl_ptr->symbol);
- buffer = XCDR (specpdl_ptr->symbol);
+ buffer = XCAR (XCDR (specpdl_ptr->symbol));
/* Handle restoring a default value. */
if (NILP (buffer))
set_internal (symbol, specpdl_ptr->old_value, XBUFFER (buffer), 1);
}
else
- set_internal (specpdl_ptr->symbol, specpdl_ptr->old_value, 0, 1);
+ {
+ /* 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. */
+ if (!MISCP (XSYMBOL (specpdl_ptr->symbol)->value))
+ XSYMBOL (specpdl_ptr->symbol)->value = specpdl_ptr->old_value;
+ else
+ set_internal (specpdl_ptr->symbol, specpdl_ptr->old_value, 0, 1);
+ }
}
- if (NILP (Vquit_flag) && quitf) Vquit_flag = Qt;
+
+ if (NILP (Vquit_flag) && quitf)
+ Vquit_flag = Qt;
UNGCPRO;
-
return value;
}
\f
return Qnil;
}
-DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 1, "",
+DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 1, NULL,
"Return the function and arguments NFRAMES up from current execution point.\n\
If that frame has not evaluated the arguments yet (or is a special form),\n\
the value is (nil FUNCTION ARG-FORMS...).\n\
return Fcons (Qt, Fcons (*backlist->function, tem));
}
}
+
\f
void
syms_of_eval ()
DEFVAR_LISP ("debug-on-error", &Vdebug_on_error,
"*Non-nil means enter debugger if an error is signaled.\n\
-Does not apply to errors handled by `condition-case'.\n\
+Does not apply to errors handled by `condition-case' or those\n\
+matched by `debug-ignored-errors'.\n\
If the value is a list, an error only means to enter the debugger\n\
if one of its condition symbols appears in the list.\n\
See also variable `debug-on-quit'.");
staticpro (&Vautoload_queue);
Vautoload_queue = Qnil;
+ staticpro (&Vsignaling_function);
+ Vsignaling_function = Qnil;
defsubr (&Sor);
defsubr (&Sand);