diff options
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 97 |
1 files changed, 62 insertions, 35 deletions
diff --git a/src/eval.c b/src/eval.c index 48104bd0f45..94ad0607732 100644 --- a/src/eval.c +++ b/src/eval.c @@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "dispextern.h" #include "buffer.h" #include "pdumper.h" +#include "atimer.h" /* CACHEABLE is ordinarily nothing, except it is 'volatile' if necessary to cajole GCC into not warning incorrectly that a @@ -364,9 +365,6 @@ do_debug_on_call (Lisp_Object code, ptrdiff_t count) call_debugger (list1 (code)); } -/* NOTE!!! Every function that can call EVAL must protect its args - and temporaries from garbage collection while it needs them. - The definition of `For' shows what you have to do. */ DEFUN ("or", For, Sor, 0, UNEVALLED, 0, doc: /* Eval args until one of them yields non-nil, then return that value. @@ -1081,6 +1079,47 @@ usage: (while TEST BODY...) */) return Qnil; } +static void +with_delayed_message_display (struct atimer *timer) +{ + message3 (build_string (timer->client_data)); +} + +static void +with_delayed_message_cancel (void *timer) +{ + xfree (((struct atimer *) timer)->client_data); + cancel_atimer (timer); +} + +DEFUN ("funcall-with-delayed-message", + Ffuncall_with_delayed_message, Sfuncall_with_delayed_message, + 3, 3, 0, + doc: /* Like `funcall', but display MESSAGE if FUNCTION takes longer than TIMEOUT. +TIMEOUT is a number of seconds, and can be an integer or a floating +point number. + +If FUNCTION takes less time to execute than TIMEOUT seconds, MESSAGE +is not displayed. */) + (Lisp_Object timeout, Lisp_Object message, Lisp_Object function) +{ + ptrdiff_t count = SPECPDL_INDEX (); + + CHECK_NUMBER (timeout); + CHECK_STRING (message); + + /* Set up the atimer. */ + struct timespec interval = dtotimespec (XFLOATINT (timeout)); + struct atimer *timer = start_atimer (ATIMER_RELATIVE, interval, + with_delayed_message_display, + xstrdup (SSDATA (message))); + record_unwind_protect_ptr (with_delayed_message_cancel, timer); + + Lisp_Object result = CALLN (Ffuncall, function); + + return unbind_to (count, result); +} + DEFUN ("macroexpand", Fmacroexpand, Smacroexpand, 1, 2, 0, doc: /* Return result of expanding macros at top level of FORM. If FORM is not a macro call, it is returned unchanged. @@ -1174,14 +1213,6 @@ usage: (catch TAG BODY...) */) FUNC should return a Lisp_Object. This is how catches are done from within C code. */ -/* MINIBUFFER_QUIT_LEVEL is to handle quitting from nested minibuffers by - throwing t to tag `exit'. - 0 means there is no (throw 'exit t) in progress, or it wasn't from - a minibuffer which isn't the most nested; - N > 0 means the `throw' was done from the minibuffer at level N which - wasn't the most nested. */ -EMACS_INT minibuffer_quit_level = 0; - Lisp_Object internal_catch (Lisp_Object tag, Lisp_Object (*func) (Lisp_Object), Lisp_Object arg) @@ -1189,9 +1220,6 @@ internal_catch (Lisp_Object tag, /* This structure is made part of the chain `catchlist'. */ struct handler *c = push_handler (tag, CATCHER); - if (EQ (tag, Qexit)) - minibuffer_quit_level = 0; - /* Call FUNC. */ if (! sys_setjmp (c->jmp)) { @@ -1205,17 +1233,6 @@ internal_catch (Lisp_Object tag, Lisp_Object val = handlerlist->val; clobbered_eassert (handlerlist == c); handlerlist = handlerlist->next; - if (EQ (tag, Qexit) && EQ (val, Qt) && minibuffer_quit_level > 0) - /* If we've thrown t to tag `exit' from within a minibuffer, we - exit all minibuffers more deeply nested than the current - one. */ - { - if (minibuf_level > minibuffer_quit_level - && !NILP (Fminibuffer_innermost_command_loop_p (Qnil))) - Fthrow (Qexit, Qt); - else - minibuffer_quit_level = 0; - } return val; } } @@ -3270,6 +3287,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, emacs_abort (); i = optional = rest = 0; + bool previous_rest = false; for (; CONSP (syms_left); syms_left = XCDR (syms_left)) { maybe_quit (); @@ -3280,13 +3298,14 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, if (EQ (next, Qand_rest)) { - if (rest) + if (rest || previous_rest) xsignal1 (Qinvalid_function, fun); rest = 1; + previous_rest = true; } else if (EQ (next, Qand_optional)) { - if (optional || rest) + if (optional || rest || previous_rest) xsignal1 (Qinvalid_function, fun); optional = 1; } @@ -3312,10 +3331,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, else /* Dynamically bind NEXT. */ specbind (next, arg); + previous_rest = false; } } - if (!NILP (syms_left)) + if (!NILP (syms_left) || previous_rest) xsignal1 (Qinvalid_function, fun); else if (i < nargs) xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (nargs)); @@ -4333,13 +4353,19 @@ syms_of_eval (void) { DEFVAR_INT ("max-specpdl-size", max_specpdl_size, doc: /* Limit on number of Lisp variable bindings and `unwind-protect's. -If Lisp code tries to increase the total number past this amount, -an error is signaled. -You can safely use a value considerably larger than the default value, -if that proves inconveniently small. However, if you increase it too far, -Emacs could run out of memory trying to make the stack bigger. -Note that this limit may be silently increased by the debugger -if `debug-on-error' or `debug-on-quit' is set. */); + +If Lisp code tries to use more bindings than this amount, an error is +signaled. + +You can safely increase this variable substantially if the default +value proves inconveniently small. However, if you increase it too +much, Emacs could run out of memory trying to make the stack bigger. +Note that this limit may be silently increased by the debugger if +`debug-on-error' or `debug-on-quit' is set. + +\"spec\" is short for \"special variables\", i.e., dynamically bound +variables. \"PDL\" is short for \"push-down list\", which is an old +term for \"stack\". */); DEFVAR_INT ("max-lisp-eval-depth", max_lisp_eval_depth, doc: /* Limit on depth in `eval', `apply' and `funcall' before error. @@ -4527,6 +4553,7 @@ alist of active lexical bindings. */); defsubr (&Slet); defsubr (&SletX); defsubr (&Swhile); + defsubr (&Sfuncall_with_delayed_message); defsubr (&Smacroexpand); defsubr (&Scatch); defsubr (&Sthrow); |