aboutsummaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorStefan Monnier2023-12-27 15:06:32 -0500
committerStefan Monnier2024-01-04 16:37:01 -0500
commit2ef6e40da88d5b4f070e339a2210f5751ab6a7cb (patch)
treec5669492d32dba2bffe119cc0c2c72b327d994ee /src/eval.c
parent02edbc88a1210b8d5a3e62ca4f03ffd17b23cbf7 (diff)
downloademacs-2ef6e40da88d5b4f070e339a2210f5751ab6a7cb.tar.gz
emacs-2ef6e40da88d5b4f070e339a2210f5751ab6a7cb.zip
(signal_or_quit): Preserve error object identity
Make sure we build the (ERROR-SYMBOL . ERROR-DATA) object only once when signaling an error, so that its `eq` identity can be used. It also gets us a tiny bit closer to having real "error objects" like in most other current programming languages. * src/eval.c (maybe_call_debugger): Change arglist to receive the error object instead of receiving the signal and the data separately. (signal_or_quit): Build the error object right at the beginning so it stays `eq` to itself. Rename the `keyboard_quit` arg to `continuable` so say what it does rather than what it's used for. (signal_quit_p): Change arg to be the error object rather than just the error-symbol. * src/keyboard.c (cmd_error_internal, menu_item_eval_property_1): Adjust calls to `signal_quit_p` accordingly. * test/src/eval-tests.el (eval-tests--error-id): New test.
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c66
1 files changed, 30 insertions, 36 deletions
diff --git a/src/eval.c b/src/eval.c
index b982c124184..1dd797063eb 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1706,8 +1706,7 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
1706 1706
1707static Lisp_Object signal_or_quit (Lisp_Object, Lisp_Object, bool); 1707static Lisp_Object signal_or_quit (Lisp_Object, Lisp_Object, bool);
1708static Lisp_Object find_handler_clause (Lisp_Object, Lisp_Object); 1708static Lisp_Object find_handler_clause (Lisp_Object, Lisp_Object);
1709static bool maybe_call_debugger (Lisp_Object conditions, Lisp_Object sig, 1709static bool maybe_call_debugger (Lisp_Object conditions, Lisp_Object error);
1710 Lisp_Object data);
1711 1710
1712static void 1711static void
1713process_quit_flag (void) 1712process_quit_flag (void)
@@ -1773,20 +1772,25 @@ quit (void)
1773bool backtrace_yet = false; 1772bool backtrace_yet = false;
1774 1773
1775/* Signal an error, or quit. ERROR_SYMBOL and DATA are as with Fsignal. 1774/* Signal an error, or quit. ERROR_SYMBOL and DATA are as with Fsignal.
1776 If KEYBOARD_QUIT, this is a quit; ERROR_SYMBOL should be 1775 If CONTINUABLE, the caller allows this function to return
1777 Qquit and DATA should be Qnil, and this function may return. 1776 (presumably after calling the debugger);
1778 Otherwise this function is like Fsignal and does not return. */ 1777 Otherwise this function is like Fsignal and does not return. */
1779 1778
1780static Lisp_Object 1779static Lisp_Object
1781signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit) 1780signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool continuable)
1782{ 1781{
1783 /* When memory is full, ERROR-SYMBOL is nil, 1782 /* When memory is full, ERROR-SYMBOL is nil,
1784 and DATA is (REAL-ERROR-SYMBOL . REAL-DATA). 1783 and DATA is (REAL-ERROR-SYMBOL . REAL-DATA).
1785 That is a special case--don't do this in other situations. */ 1784 That is a special case--don't do this in other situations. */
1785 bool oom = NILP (error_symbol);
1786 Lisp_Object error /* The error object. */
1787 = oom ? data
1788 : (!SYMBOLP (error_symbol) && NILP (data)) ? error_symbol
1789 : Fcons (error_symbol, data);
1786 Lisp_Object conditions; 1790 Lisp_Object conditions;
1787 Lisp_Object string; 1791 Lisp_Object string;
1788 Lisp_Object real_error_symbol 1792 Lisp_Object real_error_symbol
1789 = (NILP (error_symbol) ? Fcar (data) : error_symbol); 1793 = CONSP (error) ? XCAR (error) : error_symbol;
1790 Lisp_Object clause = Qnil; 1794 Lisp_Object clause = Qnil;
1791 struct handler *h; 1795 struct handler *h;
1792 int skip; 1796 int skip;
@@ -1804,11 +1808,13 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1804 1808
1805 /* This hook is used by edebug. */ 1809 /* This hook is used by edebug. */
1806 if (! NILP (Vsignal_hook_function) 1810 if (! NILP (Vsignal_hook_function)
1807 && ! NILP (error_symbol)) 1811 && !oom)
1808 { 1812 {
1809 specpdl_ref count = SPECPDL_INDEX (); 1813 specpdl_ref count = SPECPDL_INDEX ();
1810 max_ensure_room (20); 1814 max_ensure_room (20);
1811 /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete? */ 1815 /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete? */
1816 /* FIXME: Here we still "split" the error object
1817 into its error-symbol and its error-data? */
1812 call2 (Vsignal_hook_function, error_symbol, data); 1818 call2 (Vsignal_hook_function, error_symbol, data);
1813 unbind_to (count, Qnil); 1819 unbind_to (count, Qnil);
1814 } 1820 }
@@ -1820,7 +1826,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1820 too. Don't do this when ERROR_SYMBOL is nil, because that 1826 too. Don't do this when ERROR_SYMBOL is nil, because that
1821 is a memory-full error. */ 1827 is a memory-full error. */
1822 Vsignaling_function = Qnil; 1828 Vsignaling_function = Qnil;
1823 if (!NILP (error_symbol)) 1829 if (!oom)
1824 { 1830 {
1825 union specbinding *pdl = backtrace_next (backtrace_top ()); 1831 union specbinding *pdl = backtrace_next (backtrace_top ());
1826 if (backtrace_p (pdl) && EQ (backtrace_function (pdl), Qerror)) 1832 if (backtrace_p (pdl) && EQ (backtrace_function (pdl), Qerror))
@@ -1845,14 +1851,11 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1845 { 1851 {
1846 if (!NILP (find_handler_clause (h->tag_or_ch, conditions))) 1852 if (!NILP (find_handler_clause (h->tag_or_ch, conditions)))
1847 { 1853 {
1848 Lisp_Object error_data
1849 = (NILP (error_symbol)
1850 ? data : Fcons (error_symbol, data));
1851 specpdl_ref count = SPECPDL_INDEX (); 1854 specpdl_ref count = SPECPDL_INDEX ();
1852 max_ensure_room (20); 1855 max_ensure_room (20);
1853 push_handler (make_fixnum (skip + h->bytecode_dest), 1856 push_handler (make_fixnum (skip + h->bytecode_dest),
1854 SKIP_CONDITIONS); 1857 SKIP_CONDITIONS);
1855 call1 (h->val, error_data); 1858 call1 (h->val, error);
1856 unbind_to (count, Qnil); 1859 unbind_to (count, Qnil);
1857 pop_handler (); 1860 pop_handler ();
1858 } 1861 }
@@ -1875,7 +1878,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1875 bool debugger_called = false; 1878 bool debugger_called = false;
1876 if (/* Don't run the debugger for a memory-full error. 1879 if (/* Don't run the debugger for a memory-full error.
1877 (There is no room in memory to do that!) */ 1880 (There is no room in memory to do that!) */
1878 !NILP (error_symbol) 1881 !oom
1879 && (!NILP (Vdebug_on_signal) 1882 && (!NILP (Vdebug_on_signal)
1880 /* If no handler is present now, try to run the debugger. */ 1883 /* If no handler is present now, try to run the debugger. */
1881 || NILP (clause) 1884 || NILP (clause)
@@ -1887,17 +1890,17 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1887 || EQ (clause, Qerror))) 1890 || EQ (clause, Qerror)))
1888 { 1891 {
1889 debugger_called 1892 debugger_called
1890 = maybe_call_debugger (conditions, error_symbol, data); 1893 = maybe_call_debugger (conditions, error);
1891 /* We can't return values to code which signaled an error, but we 1894 /* We can't return values to code which signaled an error, but we
1892 can continue code which has signaled a quit. */ 1895 can continue code which has signaled a quit. */
1893 if (keyboard_quit && debugger_called && EQ (real_error_symbol, Qquit)) 1896 if (continuable && debugger_called)
1894 return Qnil; 1897 return Qnil;
1895 } 1898 }
1896 1899
1897 /* If an error is signaled during a Lisp hook in redisplay, write a 1900 /* If an error is signaled during a Lisp hook in redisplay, write a
1898 backtrace into the buffer *Redisplay-trace*. */ 1901 backtrace into the buffer *Redisplay-trace*. */
1899 /* FIXME: Turn this into a `handler-bind` installed during redisplay? */ 1902 /* FIXME: Turn this into a `handler-bind` installed during redisplay? */
1900 if (!debugger_called && !NILP (error_symbol) 1903 if (!debugger_called && !oom
1901 && backtrace_on_redisplay_error 1904 && backtrace_on_redisplay_error
1902 && (NILP (clause) || h == redisplay_deep_handler) 1905 && (NILP (clause) || h == redisplay_deep_handler)
1903 && NILP (Vinhibit_debugger) 1906 && NILP (Vinhibit_debugger)
@@ -1918,7 +1921,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1918 backtrace_yet = true; 1921 backtrace_yet = true;
1919 specbind (Qstandard_output, redisplay_trace_buffer); 1922 specbind (Qstandard_output, redisplay_trace_buffer);
1920 specbind (Qdebugger, Qdebug_early); 1923 specbind (Qdebugger, Qdebug_early);
1921 call_debugger (list2 (Qerror, Fcons (error_symbol, data))); 1924 call_debugger (list2 (Qerror, error));
1922 unbind_to (count, Qnil); 1925 unbind_to (count, Qnil);
1923 delayed_warning = make_string 1926 delayed_warning = make_string
1924 ("Error in a redisplay Lisp hook. See buffer *Redisplay-trace*", 61); 1927 ("Error in a redisplay Lisp hook. See buffer *Redisplay-trace*", 61);
@@ -1929,10 +1932,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1929 1932
1930 if (!NILP (clause)) 1933 if (!NILP (clause))
1931 { 1934 {
1932 Lisp_Object unwind_data 1935 unwind_to_catch (h, NONLOCAL_EXIT_SIGNAL, error);
1933 = (NILP (error_symbol) ? data : Fcons (error_symbol, data));
1934
1935 unwind_to_catch (h, NONLOCAL_EXIT_SIGNAL, unwind_data);
1936 } 1936 }
1937 else 1937 else
1938 { 1938 {
@@ -1943,10 +1943,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1943 Fthrow (Qtop_level, Qt); 1943 Fthrow (Qtop_level, Qt);
1944 } 1944 }
1945 1945
1946 if (! NILP (error_symbol)) 1946 string = Ferror_message_string (error);
1947 data = Fcons (error_symbol, data);
1948
1949 string = Ferror_message_string (data);
1950 fatal ("%s", SDATA (string)); 1947 fatal ("%s", SDATA (string));
1951} 1948}
1952 1949
@@ -2071,14 +2068,15 @@ skip_debugger (Lisp_Object conditions, Lisp_Object data)
2071 return 0; 2068 return 0;
2072} 2069}
2073 2070
2074/* Say whether SIGNAL is a `quit' symbol (or inherits from it). */ 2071/* Say whether SIGNAL is a `quit' error (or inherits from it). */
2075bool 2072bool
2076signal_quit_p (Lisp_Object signal) 2073signal_quit_p (Lisp_Object error)
2077{ 2074{
2075 Lisp_Object signal = CONSP (error) ? XCAR (error) : Qnil;
2078 Lisp_Object list; 2076 Lisp_Object list;
2079 2077
2080 return EQ (signal, Qquit) 2078 return EQ (signal, Qquit)
2081 || (!NILP (Fsymbolp (signal)) 2079 || (SYMBOLP (signal)
2082 && CONSP (list = Fget (signal, Qerror_conditions)) 2080 && CONSP (list = Fget (signal, Qerror_conditions))
2083 && !NILP (Fmemq (Qquit, list))); 2081 && !NILP (Fmemq (Qquit, list)));
2084} 2082}
@@ -2089,27 +2087,23 @@ signal_quit_p (Lisp_Object signal)
2089 = SIG is nil, and DATA is (SYMBOL . REST-OF-DATA). 2087 = SIG is nil, and DATA is (SYMBOL . REST-OF-DATA).
2090 This is for memory-full errors only. */ 2088 This is for memory-full errors only. */
2091static bool 2089static bool
2092maybe_call_debugger (Lisp_Object conditions, Lisp_Object sig, Lisp_Object data) 2090maybe_call_debugger (Lisp_Object conditions, Lisp_Object error)
2093{ 2091{
2094 Lisp_Object combined_data;
2095
2096 combined_data = Fcons (sig, data);
2097
2098 if ( 2092 if (
2099 /* Don't try to run the debugger with interrupts blocked. 2093 /* Don't try to run the debugger with interrupts blocked.
2100 The editing loop would return anyway. */ 2094 The editing loop would return anyway. */
2101 ! input_blocked_p () 2095 ! input_blocked_p ()
2102 && NILP (Vinhibit_debugger) 2096 && NILP (Vinhibit_debugger)
2103 /* Does user want to enter debugger for this kind of error? */ 2097 /* Does user want to enter debugger for this kind of error? */
2104 && (signal_quit_p (sig) 2098 && (signal_quit_p (error)
2105 ? debug_on_quit 2099 ? debug_on_quit
2106 : wants_debugger (Vdebug_on_error, conditions)) 2100 : wants_debugger (Vdebug_on_error, conditions))
2107 && ! skip_debugger (conditions, combined_data) 2101 && ! skip_debugger (conditions, error)
2108 /* See commentary on definition of 2102 /* See commentary on definition of
2109 `internal-when-entered-debugger'. */ 2103 `internal-when-entered-debugger'. */
2110 && when_entered_debugger < num_nonmacro_input_events) 2104 && when_entered_debugger < num_nonmacro_input_events)
2111 { 2105 {
2112 call_debugger (list2 (Qerror, combined_data)); 2106 call_debugger (list2 (Qerror, error));
2113 return 1; 2107 return 1;
2114 } 2108 }
2115 2109