aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval.c97
-rw-r--r--src/lisp.h41
2 files changed, 121 insertions, 17 deletions
diff --git a/src/eval.c b/src/eval.c
index 7f67b5a9db8..595267f7686 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1198,6 +1198,12 @@ usage: (catch TAG BODY...) */)
1198 1198
1199#define clobbered_eassert(E) verify (sizeof (E) != 0) 1199#define clobbered_eassert(E) verify (sizeof (E) != 0)
1200 1200
1201static void
1202pop_handler (void)
1203{
1204 handlerlist = handlerlist->next;
1205}
1206
1201/* Set up a catch, then call C function FUNC on argument ARG. 1207/* Set up a catch, then call C function FUNC on argument ARG.
1202 FUNC should return a Lisp_Object. 1208 FUNC should return a Lisp_Object.
1203 This is how catches are done from within C code. */ 1209 This is how catches are done from within C code. */
@@ -1361,6 +1367,43 @@ usage: (condition-case VAR BODYFORM &rest HANDLERS) */)
1361 return internal_lisp_condition_case (var, bodyform, handlers); 1367 return internal_lisp_condition_case (var, bodyform, handlers);
1362} 1368}
1363 1369
1370DEFUN ("handler-bind-1", Fhandler_bind_1, Shandler_bind_1, 1, MANY, 0,
1371 doc: /* Setup error handlers around execution of BODYFUN.
1372BODYFUN be a function and it is called with no arguments.
1373CONDITIONS should be a list of condition names (symbols).
1374When an error is signaled during executon of BODYFUN, if that
1375error matches one of CONDITIONS, then the associated HANDLER is
1376called with the error as argument.
1377HANDLER should either transfer the control via a non-local exit,
1378or return normally.
1379If it returns normally, the search for an error handler continues
1380from where it left off.
1381
1382usage: (handler-bind BODYFUN [CONDITIONS HANDLER]...) */)
1383 (ptrdiff_t nargs, Lisp_Object *args)
1384{
1385 eassert (nargs >= 1);
1386 Lisp_Object bodyfun = args[0];
1387 int count = 0;
1388 if (nargs % 2 == 0)
1389 error ("Trailing CONDITIONS withount HANDLER in `handler-bind`");
1390 for (ptrdiff_t i = nargs - 2; i > 0; i -= 2)
1391 {
1392 Lisp_Object conditions = args[i], handler = args[i + 1];
1393 if (NILP (conditions))
1394 continue;
1395 else if (!CONSP (conditions))
1396 conditions = Fcons (conditions, Qnil);
1397 struct handler *c = push_handler (conditions, HANDLER_BIND);
1398 c->val = handler;
1399 c->bytecode_dest = count++;
1400 }
1401 Lisp_Object ret = call0 (bodyfun);
1402 for (; count > 0; count--)
1403 pop_handler ();
1404 return ret;
1405}
1406
1364/* Like Fcondition_case, but the args are separate 1407/* Like Fcondition_case, but the args are separate
1365 rather than passed in a list. Used by Fbyte_code. */ 1408 rather than passed in a list. Used by Fbyte_code. */
1366 1409
@@ -1737,6 +1780,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1737 = (NILP (error_symbol) ? Fcar (data) : error_symbol); 1780 = (NILP (error_symbol) ? Fcar (data) : error_symbol);
1738 Lisp_Object clause = Qnil; 1781 Lisp_Object clause = Qnil;
1739 struct handler *h; 1782 struct handler *h;
1783 int skip;
1740 1784
1741 if (gc_in_progress || waiting_for_input) 1785 if (gc_in_progress || waiting_for_input)
1742 emacs_abort (); 1786 emacs_abort ();
@@ -1759,6 +1803,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1759 /* Edebug takes care of restoring these variables when it exits. */ 1803 /* Edebug takes care of restoring these variables when it exits. */
1760 max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 20); 1804 max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 20);
1761 1805
1806 /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete? */
1762 call2 (Vsignal_hook_function, error_symbol, data); 1807 call2 (Vsignal_hook_function, error_symbol, data);
1763 } 1808 }
1764 1809
@@ -1778,16 +1823,42 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1778 Vsignaling_function = backtrace_function (pdl); 1823 Vsignaling_function = backtrace_function (pdl);
1779 } 1824 }
1780 1825
1781 for (h = handlerlist; h; h = h->next) 1826 for (skip = 0, h = handlerlist; h; skip++, h = h->next)
1782 { 1827 {
1783 if (h->type == CATCHER_ALL) 1828 switch (h->type)
1784 { 1829 {
1830 case CATCHER_ALL:
1785 clause = Qt; 1831 clause = Qt;
1786 break; 1832 break;
1787 } 1833 case CATCHER:
1788 if (h->type != CONDITION_CASE) 1834 continue;
1789 continue; 1835 case CONDITION_CASE:
1790 clause = find_handler_clause (h->tag_or_ch, conditions); 1836 clause = find_handler_clause (h->tag_or_ch, conditions);
1837 break;
1838 case HANDLER_BIND:
1839 {
1840 if (!NILP (find_handler_clause (h->tag_or_ch, conditions)))
1841 {
1842 Lisp_Object error_data
1843 = (NILP (error_symbol)
1844 ? data : Fcons (error_symbol, data));
1845 push_handler (make_fixnum (skip + h->bytecode_dest),
1846 SKIP_CONDITIONS);
1847 call1 (h->val, error_data);
1848 pop_handler ();
1849 }
1850 continue;
1851 }
1852 case SKIP_CONDITIONS:
1853 {
1854 int toskip = XFIXNUM (h->tag_or_ch);
1855 while (toskip-- >= 0)
1856 h = h->next;
1857 continue;
1858 }
1859 default:
1860 abort ();
1861 }
1791 if (!NILP (clause)) 1862 if (!NILP (clause))
1792 break; 1863 break;
1793 } 1864 }
@@ -1804,7 +1875,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1804 || (CONSP (clause) && !NILP (Fmemq (Qdebug, clause))) 1875 || (CONSP (clause) && !NILP (Fmemq (Qdebug, clause)))
1805 /* Special handler that means "print a message and run debugger 1876 /* Special handler that means "print a message and run debugger
1806 if requested". */ 1877 if requested". */
1807 || EQ (h->tag_or_ch, Qerror))) 1878 || EQ (clause, Qerror)))
1808 { 1879 {
1809 debugger_called 1880 debugger_called
1810 = maybe_call_debugger (conditions, error_symbol, data); 1881 = maybe_call_debugger (conditions, error_symbol, data);
@@ -1818,8 +1889,9 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1818 with debugging. Make sure to use `debug-early' unconditionally 1889 with debugging. Make sure to use `debug-early' unconditionally
1819 to not interfere with ERT or other packages that install custom 1890 to not interfere with ERT or other packages that install custom
1820 debuggers. */ 1891 debuggers. */
1892 /* FIXME: This could be turned into a `handler-bind` at toplevel? */
1821 if (!debugger_called && !NILP (error_symbol) 1893 if (!debugger_called && !NILP (error_symbol)
1822 && (NILP (clause) || EQ (h->tag_or_ch, Qerror)) 1894 && (NILP (clause) || EQ (clause, Qerror))
1823 && noninteractive && backtrace_on_error_noninteractive 1895 && noninteractive && backtrace_on_error_noninteractive
1824 && NILP (Vinhibit_debugger) 1896 && NILP (Vinhibit_debugger)
1825 && !NILP (Ffboundp (Qdebug_early))) 1897 && !NILP (Ffboundp (Qdebug_early)))
@@ -1833,6 +1905,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1833 1905
1834 /* If an error is signaled during a Lisp hook in redisplay, write a 1906 /* If an error is signaled during a Lisp hook in redisplay, write a
1835 backtrace into the buffer *Redisplay-trace*. */ 1907 backtrace into the buffer *Redisplay-trace*. */
1908 /* FIXME: Turn this into a `handler-bind` installed during redisplay? */
1836 if (!debugger_called && !NILP (error_symbol) 1909 if (!debugger_called && !NILP (error_symbol)
1837 && backtrace_on_redisplay_error 1910 && backtrace_on_redisplay_error
1838 && (NILP (clause) || h == redisplay_deep_handler) 1911 && (NILP (clause) || h == redisplay_deep_handler)
@@ -2058,13 +2131,10 @@ find_handler_clause (Lisp_Object handlers, Lisp_Object conditions)
2058 register Lisp_Object h; 2131 register Lisp_Object h;
2059 2132
2060 /* t is used by handlers for all conditions, set up by C code. */ 2133 /* t is used by handlers for all conditions, set up by C code. */
2061 if (EQ (handlers, Qt))
2062 return Qt;
2063
2064 /* error is used similarly, but means print an error message 2134 /* error is used similarly, but means print an error message
2065 and run the debugger if that is enabled. */ 2135 and run the debugger if that is enabled. */
2066 if (EQ (handlers, Qerror)) 2136 if (!CONSP (handlers))
2067 return Qt; 2137 return handlers;
2068 2138
2069 for (h = handlers; CONSP (h); h = XCDR (h)) 2139 for (h = handlers; CONSP (h); h = XCDR (h))
2070 { 2140 {
@@ -4494,6 +4564,7 @@ alist of active lexical bindings. */);
4494 defsubr (&Sthrow); 4564 defsubr (&Sthrow);
4495 defsubr (&Sunwind_protect); 4565 defsubr (&Sunwind_protect);
4496 defsubr (&Scondition_case); 4566 defsubr (&Scondition_case);
4567 defsubr (&Shandler_bind_1);
4497 DEFSYM (QCsuccess, ":success"); 4568 DEFSYM (QCsuccess, ":success");
4498 defsubr (&Ssignal); 4569 defsubr (&Ssignal);
4499 defsubr (&Scommandp); 4570 defsubr (&Scommandp);
diff --git a/src/lisp.h b/src/lisp.h
index 10018e4dde7..2b30326abfc 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3543,7 +3543,8 @@ record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs)
3543} 3543}
3544 3544
3545/* This structure helps implement the `catch/throw' and `condition-case/signal' 3545/* This structure helps implement the `catch/throw' and `condition-case/signal'
3546 control structures. A struct handler contains all the information needed to 3546 control structures as well as 'handler-bind'.
3547 A struct handler contains all the information needed to
3547 restore the state of the interpreter after a non-local jump. 3548 restore the state of the interpreter after a non-local jump.
3548 3549
3549 Handler structures are chained together in a doubly linked list; the `next' 3550 Handler structures are chained together in a doubly linked list; the `next'
@@ -3564,9 +3565,41 @@ record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs)
3564 state. 3565 state.
3565 3566
3566 Members are volatile if their values need to survive _longjmp when 3567 Members are volatile if their values need to survive _longjmp when
3567 a 'struct handler' is a local variable. */ 3568 a 'struct handler' is a local variable.
3568 3569
3569enum handlertype { CATCHER, CONDITION_CASE, CATCHER_ALL }; 3570 When running the HANDLER of a 'handler-bind', we need to
3571 temporarily "mute" the CONDITION_CASEs and HANDLERs that are "below"
3572 the current handler, but without hiding any CATCHERs. We do that by
3573 installing a SKIP_CONDITIONS which tells the search to skip the
3574 N next conditions. */
3575
3576enum handlertype {
3577 CATCHER, /* Entry for 'catch'.
3578 'tag_or_ch' holds the catch's tag.
3579 'val' holds the retval during longjmp. */
3580 CONDITION_CASE, /* Entry for 'condition-case'.
3581 'tag_or_ch' holds the list of conditions.
3582 'val' holds the retval during longjmp. */
3583 CATCHER_ALL, /* Wildcard which catches all 'throw's.
3584 'tag_or_ch' is unused.
3585 'val' holds the retval during longjmp. */
3586 HANDLER_BIND, /* Entry for 'handler-bind'.
3587 'tag_or_ch' holds the list of conditions.
3588 'val' holds the handler function.
3589 The rest of the handler is unused,
3590 except for 'bytecode_dest' that holds
3591 the number of preceding HANDLER_BIND
3592 entries which belong to the same
3593 'handler-bind' (and hence need to
3594 be muted together). */
3595 SKIP_CONDITIONS /* Mask out the N preceding entries.
3596 Used while running the handler of
3597 a HANDLER_BIND to hides the condition
3598 handlers underneath (and including)
3599 the 'handler-bind'.
3600 'tag_or_ch' holds that number, the rest
3601 is unused. */
3602};
3570 3603
3571enum nonlocal_exit 3604enum nonlocal_exit
3572{ 3605{