aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorClément Pit--Claudel2016-12-05 00:52:14 -0500
committerClément Pit--Claudel2016-12-12 17:41:27 -0500
commit27cada035a79b633e856a437dd0e037acc1d61c6 (patch)
treeb02c80fe4e7b4ce9fe54912118e4fa5e723723c5 /src
parenta41ded87b318ce3cbeb0ba3624bcb83ae3b8a437 (diff)
downloademacs-27cada035a79b633e856a437dd0e037acc1d61c6.tar.gz
emacs-27cada035a79b633e856a437dd0e037acc1d61c6.zip
Move backtrace to ELisp using a new mapbacktrace primitive
* src/eval.c (get_backtrace_starting_at, backtrace_frame_apply) (Fmapbacktrace, Fbacktrace_frame_internal): New functions. (get_backtrace_frame, Fbacktrace_debug): Use `get_backtrace_starting_at'. * lisp/subr.el (backtrace--print-frame): New function. (backtrace): Reimplement using `backtrace--print-frame' and `mapbacktrace'. (backtrace-frame): Reimplement using `backtrace-frame--internal'. * lisp/emacs-lisp/debug.el (debugger-setup-buffer): Pass a base to `mapbacktrace' instead of searching for "(debug" in the output of `backtrace'. * test/lisp/subr-tests.el (subr-test-backtrace-simple-tests) (subr-test-backtrace-integration-test): New tests. * doc/lispref/debugging.texi (Internals of Debugger): Document `mapbacktrace' and missing argument BASE of `backtrace-frame'.
Diffstat (limited to 'src')
-rw-r--r--src/eval.c157
1 files changed, 69 insertions, 88 deletions
diff --git a/src/eval.c b/src/eval.c
index f1e0ae7d586..7852ef700ba 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3541,87 +3541,29 @@ context where binding is lexical by default. */)
3541} 3541}
3542 3542
3543 3543
3544DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 2, 0, 3544static union specbinding *
3545 doc: /* Set the debug-on-exit flag of eval frame LEVEL levels down to FLAG. 3545get_backtrace_starting_at (Lisp_Object base)
3546The debugger is entered when that frame exits, if the flag is non-nil. */)
3547 (Lisp_Object level, Lisp_Object flag)
3548{
3549 union specbinding *pdl = backtrace_top ();
3550 register EMACS_INT i;
3551
3552 CHECK_NUMBER (level);
3553
3554 for (i = 0; backtrace_p (pdl) && i < XINT (level); i++)
3555 pdl = backtrace_next (pdl);
3556
3557 if (backtrace_p (pdl))
3558 set_backtrace_debug_on_exit (pdl, !NILP (flag));
3559
3560 return flag;
3561}
3562
3563DEFUN ("backtrace", Fbacktrace, Sbacktrace, 0, 0, "",
3564 doc: /* Print a trace of Lisp function calls currently active.
3565Output stream used is value of `standard-output'. */)
3566 (void)
3567{ 3546{
3568 union specbinding *pdl = backtrace_top (); 3547 union specbinding *pdl = backtrace_top ();
3569 Lisp_Object tem;
3570 Lisp_Object old_print_level = Vprint_level;
3571 3548
3572 if (NILP (Vprint_level)) 3549 if (!NILP (base))
3573 XSETFASTINT (Vprint_level, 8); 3550 { /* Skip up to `base'. */
3574 3551 base = Findirect_function (base, Qt);
3575 while (backtrace_p (pdl)) 3552 while (backtrace_p (pdl)
3576 { 3553 && !EQ (base, Findirect_function (backtrace_function (pdl), Qt)))
3577 write_string (backtrace_debug_on_exit (pdl) ? "* " : " "); 3554 pdl = backtrace_next (pdl);
3578 if (backtrace_nargs (pdl) == UNEVALLED)
3579 {
3580 Fprin1 (Fcons (backtrace_function (pdl), *backtrace_args (pdl)),
3581 Qnil);
3582 write_string ("\n");
3583 }
3584 else
3585 {
3586 tem = backtrace_function (pdl);
3587 if (debugger_stack_frame_as_list)
3588 write_string ("(");
3589 Fprin1 (tem, Qnil); /* This can QUIT. */
3590 if (!debugger_stack_frame_as_list)
3591 write_string ("(");
3592 {
3593 ptrdiff_t i;
3594 for (i = 0; i < backtrace_nargs (pdl); i++)
3595 {
3596 if (i || debugger_stack_frame_as_list)
3597 write_string(" ");
3598 Fprin1 (backtrace_args (pdl)[i], Qnil);
3599 }
3600 }
3601 write_string (")\n");
3602 }
3603 pdl = backtrace_next (pdl);
3604 } 3555 }
3605 3556
3606 Vprint_level = old_print_level; 3557 return pdl;
3607 return Qnil;
3608} 3558}
3609 3559
3610static union specbinding * 3560static union specbinding *
3611get_backtrace_frame (Lisp_Object nframes, Lisp_Object base) 3561get_backtrace_frame (Lisp_Object nframes, Lisp_Object base)
3612{ 3562{
3613 union specbinding *pdl = backtrace_top ();
3614 register EMACS_INT i; 3563 register EMACS_INT i;
3615 3564
3616 CHECK_NATNUM (nframes); 3565 CHECK_NATNUM (nframes);
3617 3566 union specbinding *pdl = get_backtrace_starting_at (base);
3618 if (!NILP (base))
3619 { /* Skip up to `base'. */
3620 base = Findirect_function (base, Qt);
3621 while (backtrace_p (pdl)
3622 && !EQ (base, Findirect_function (backtrace_function (pdl), Qt)))
3623 pdl = backtrace_next (pdl);
3624 }
3625 3567
3626 /* Find the frame requested. */ 3568 /* Find the frame requested. */
3627 for (i = XFASTINT (nframes); i > 0 && backtrace_p (pdl); i--) 3569 for (i = XFASTINT (nframes); i > 0 && backtrace_p (pdl); i--)
@@ -3630,33 +3572,71 @@ get_backtrace_frame (Lisp_Object nframes, Lisp_Object base)
3630 return pdl; 3572 return pdl;
3631} 3573}
3632 3574
3633DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 2, NULL, 3575static Lisp_Object
3634 doc: /* Return the function and arguments NFRAMES up from current execution point. 3576backtrace_frame_apply (Lisp_Object function, union specbinding *pdl)
3635If that frame has not evaluated the arguments yet (or is a special form),
3636the value is (nil FUNCTION ARG-FORMS...).
3637If that frame has evaluated its arguments and called its function already,
3638the value is (t FUNCTION ARG-VALUES...).
3639A &rest arg is represented as the tail of the list ARG-VALUES.
3640FUNCTION is whatever was supplied as car of evaluated list,
3641or a lambda expression for macro calls.
3642If NFRAMES is more than the number of frames, the value is nil.
3643If BASE is non-nil, it should be a function and NFRAMES counts from its
3644nearest activation frame. */)
3645 (Lisp_Object nframes, Lisp_Object base)
3646{ 3577{
3647 union specbinding *pdl = get_backtrace_frame (nframes, base);
3648
3649 if (!backtrace_p (pdl)) 3578 if (!backtrace_p (pdl))
3650 return Qnil; 3579 return Qnil;
3580
3581 Lisp_Object flags = Qnil;
3582 if (backtrace_debug_on_exit (pdl))
3583 flags = Fcons (QCdebug_on_exit, Fcons (Qt, Qnil));
3584
3651 if (backtrace_nargs (pdl) == UNEVALLED) 3585 if (backtrace_nargs (pdl) == UNEVALLED)
3652 return Fcons (Qnil, 3586 return call4 (function, Qnil, backtrace_function (pdl), *backtrace_args (pdl), flags);
3653 Fcons (backtrace_function (pdl), *backtrace_args (pdl)));
3654 else 3587 else
3655 { 3588 {
3656 Lisp_Object tem = Flist (backtrace_nargs (pdl), backtrace_args (pdl)); 3589 Lisp_Object tem = Flist (backtrace_nargs (pdl), backtrace_args (pdl));
3590 return call4 (function, Qt, backtrace_function (pdl), tem, flags);
3591 }
3592}
3657 3593
3658 return Fcons (Qt, Fcons (backtrace_function (pdl), tem)); 3594DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 2, 0,
3595 doc: /* Set the debug-on-exit flag of eval frame LEVEL levels down to FLAG.
3596The debugger is entered when that frame exits, if the flag is non-nil. */)
3597 (Lisp_Object level, Lisp_Object flag)
3598{
3599 CHECK_NUMBER (level);
3600 union specbinding *pdl = get_backtrace_frame(level, Qnil);
3601
3602 if (backtrace_p (pdl))
3603 set_backtrace_debug_on_exit (pdl, !NILP (flag));
3604
3605 return flag;
3606}
3607
3608DEFUN ("mapbacktrace", Fmapbacktrace, Smapbacktrace, 1, 2, 0,
3609 doc: /* Call FUNCTION for each frame in backtrace.
3610If BASE is non-nil, it should be a function and iteration will start
3611from its nearest activation frame.
3612FUNCTION is called with 4 arguments: EVALD, FUNC, ARGS, and FLAGS. If
3613a frame has not evaluated its arguments yet or is a special form,
3614EVALD is nil and ARGS is a list of forms. If a frame has evaluated
3615its arguments and called its function already, EVALD is t and ARGS is
3616a list of values.
3617FLAGS is a plist of properties of the current frame: currently, the
3618only supported property is :debug-on-exit. `mapbacktrace' always
3619returns nil. */)
3620 (Lisp_Object function, Lisp_Object base)
3621{
3622 union specbinding *pdl = get_backtrace_starting_at (base);
3623
3624 while (backtrace_p (pdl))
3625 {
3626 backtrace_frame_apply (function, pdl);
3627 pdl = backtrace_next (pdl);
3659 } 3628 }
3629
3630 return Qnil;
3631}
3632
3633DEFUN ("backtrace-frame--internal", Fbacktrace_frame_internal,
3634 Sbacktrace_frame_internal, 3, 3, NULL,
3635 doc: /* Call FUNCTION on stack frame NFRAMES away from BASE.
3636Return the result of FUNCTION, or nil if no matching frame could be found. */)
3637 (Lisp_Object function, Lisp_Object nframes, Lisp_Object base)
3638{
3639 return backtrace_frame_apply (function, get_backtrace_frame (nframes, base));
3660} 3640}
3661 3641
3662/* For backtrace-eval, we want to temporarily unwind the last few elements of 3642/* For backtrace-eval, we want to temporarily unwind the last few elements of
@@ -4114,8 +4094,9 @@ alist of active lexical bindings. */);
4114 defsubr (&Srun_hook_wrapped); 4094 defsubr (&Srun_hook_wrapped);
4115 defsubr (&Sfetch_bytecode); 4095 defsubr (&Sfetch_bytecode);
4116 defsubr (&Sbacktrace_debug); 4096 defsubr (&Sbacktrace_debug);
4117 defsubr (&Sbacktrace); 4097 DEFSYM (QCdebug_on_exit, ":debug-on-exit");
4118 defsubr (&Sbacktrace_frame); 4098 defsubr (&Smapbacktrace);
4099 defsubr (&Sbacktrace_frame_internal);
4119 defsubr (&Sbacktrace_eval); 4100 defsubr (&Sbacktrace_eval);
4120 defsubr (&Sbacktrace__locals); 4101 defsubr (&Sbacktrace__locals);
4121 defsubr (&Sspecial_variable_p); 4102 defsubr (&Sspecial_variable_p);