* doc/ref/api-debug.texi: Document the peek and pk procedures. --- doc/ref/api-debug.texi | 187 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 8 deletions(-)
diff --git a/doc/ref/api-debug.texi b/doc/ref/api-debug.texi index faa0c40bd..486473cdb 100644 --- a/doc/ref/api-debug.texi +++ b/doc/ref/api-debug.texi @@ -1,27 +1,198 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2007, 2010, 2011, 2012, 2013, 2014, 2018, 2021 +@c Copyright (C) 1996-1997, 2000-2004, 2007, 2010-2014, 2018, 2021, 2024 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @node Debugging @section Debugging Infrastructure -@cindex Debugging -In order to understand Guile's debugging facilities, you first need to -understand a little about how Guile represents the Scheme control stack. -With that in place we explain the low level trap calls that the virtual -machine can be configured to make, and the trap and breakpoint -infrastructure that builds on top of those calls. +@cindex debugging +Guile provides facilities for simple print-based debugging as well as +more advanced debugging features. In order to understand Guile's +advanced debugging facilities, one first must understand a little about +how Guile represents the Scheme control stack. With that in place, we +can explain the low level trap calls that the virtual machine can be +configured to make, and the trap and breakpoint infrastructure that +builds on top of those calls. @menu +* Simple Debugging:: Print-based debugging. * Evaluation Model:: Evaluation and the Scheme stack. * Source Properties:: From expressions to source locations. -* Programmatic Error Handling:: Debugging when an error occurs. +* Programmatic Error Handling:: Debugging when an error occurs. * Traps:: Breakpoints, tracepoints, oh my! * GDB Support:: C-level debugging with GDB. @end menu + +@node Simple Debugging +@subsection Simple Debugging + +Guile offers powerful tools for introspection and debugging at the REPL, +covered in the rest of this section and elsewhere in this manual +(@pxref{Interactive Debugging}). Here we deal with a more primitive +approach, commonly called ``print debugging.'' Let's be honest: for most +of us, this is our first line of debugging. And Guile doesn't judge us +for it! Instead, Guile provides a powerful and convenient tool to +facilitate print debugging: the @code{peek} procedure, more commonly +known as @code{pk} (pronounced by naming the letters). + +@deffn {Scheme Procedure} peek stuff @dots{} +@deffnx {Scheme Procedure} pk stuff @dots{} +Print @var{stuff} to the current output port using @code{write}. Return +the last argument. +@end deffn + +@code{pk} allows us to look at the state of our code as it runs without +having to step through it or break the normal code flow. Let's take a +look at how one might use it. Let's say we have a procedure to make a +smore, perhaps as part of a mod for a cozy space exploration game. + +@lisp +(define (make-smore marshmallow graham-crackers chocolate fire) + "Toast @var{mashmallow} over @var{fire} then sandwich it and +@var{chocolate} between @var{graham-crackers}." + (let ((toasted-marshmallow + (toast marshmallow fire))) + (unless (or (burned? toasted-marshmallow) + (undercooked? toasted-marshmallow)) + (cons (car graham-crackers) + (cons toasted-marshmallow + (cons chocolate + (cons (cdr graham-crackers) '()))))))) +@end lisp + +We've run this procedure a few times, and it isn't doing what we expect. +Instead of getting a tasty smore, we get nothing. Let's use @code{pk} to +find out what's going on. + +@lisp +(pk (make-smore (grab-one marshmallow-bag) + (cons graham-cracker graham-cracker) + campfire)) + +;;; (#<unspecified>) +@end lisp + +@code{#<unspecified>} is a value in Guile which indicates that no Scheme +standard specifies a return value for whatever is returning it. In this +case, it probably means that our @code{unless} check is not proving +true, so the procedure returns nothing. Let's add a @code{pk} around the +call to @code{toast} and see what happens. + +@lisp +(define (make-smore marshmallow graham-crackers chocolate fire) + "Toast @var{mashmallow} over @var{fire} then sandwich it and +@var{chocolate} between @var{graham-crackers}." + (let ((toasted-marshmallow + ;; Let's see what state the toasted-marshmallow is in + (pk 'toasted-marshmallow (toast marshmallow fire)))) + (unless (or (burned? toasted-marshmallow) + (undercooked? toasted-marshmallow)) + (cons (car graham-crackers) + (cons toasted-marshmallow + (cons chocolate + (cons (cdr graham-crackers) '()))))))) + +(make-smore (grab-one marshmallow-bag) + (cons graham-cracker graham-cracker) + campfire) + +;;; (toasted-marshmallow #<<marshmallow> state: raw>) +@end lisp + +Our marshmallow isn't getting cooked at all! Let's see if we can find +out why. We'll check on the state of @var{fire} since we know that +@code{toast} just operates on the state of the fire and of the +marshmallow. @code{toasted-marshmallow} matches the state we expect for +a fresh marshmallow, so the problem is probably with the fire. + +@lisp +(define (make-smore marshmallow graham-crackers chocolate fire) + "Toast @var{mashmallow} over @var{fire} then sandwich it and +@var{chocolate} between @var{graham-crackers}." + (let ((toasted-marshmallow + ;; Now we'll check on the fire, too + (pk 'toasted-marshmallow (toast marshmallow (pk 'fire fire))))) + (unless (or (burned? toasted-marshmallow) + (undercooked? toasted-marshmallow)) + (cons (car graham-crackers) + (cons toasted-marshmallow + (cons chocolate + (cons (cdr graham-crackers) '()))))))) + +(make-smore (grab-one marshmallow-bag) + (cons graham-cracker graham-cracker) + campfire) + +;;; (fire #<<fire> state: unlit>) + +;;; (toasted-marshmallow #<<marshmallow> state: raw>) +@end lisp + +Oh, well that makes sense! A fire can't cook a marshmallow if it isn't +lit! + +Notice that the result of evaluating the @code{pk} around @code{fire} is +printed before the one around @code{toast}. This is just the result of +the normal process of evaluating s-expressions from the inside out. We +highlight it because it can be confusing at first, especially with more +@code{pk}s in more complex code. + +Let's add a guard to light the fire and run our procedure again. + +@lisp +(define (make-smore marshmallow graham-crackers chocolate fire) + "Toast @var{mashmallow} over @var{fire} then sandwich it and +@var{chocolate} between @var{graham-crackers}." + (let ((toasted-marshmallow + (toast marshmallow fire))) + (unless (lit? fire) + (light fire)) + (unless (or (burned? toasted-marshmallow) + (undercooked? toasted-marshmallow)) + (cons (car graham-crackers) + (cons toasted-marshmallow + (cons chocolate + (cons (cdr graham-crackers) '()))))))) + +(make-smore (grab-one marshmallow-bag) + (cons graham-cracker graham-cracker) + campfire) +@result{} (#<<graham-cracker>> #<<marshmallow> state: cooked> #<<chocolate>> #<<graham-cracker>>) +@end lisp + +Yay! Now it works, and we have a tasty smore! + +As we demonstrated, you can pass in any number of arguments and the +result of evaluating the last argument is the value returned from +@code{pk}. This is handy to, as we showed, wrap code in-line without +needing to add extra steps along the way while still providing +informative labels about what, exactly, is getting printed. We could as +easily have put @code{pk}s completely on their own, rather than wrapping +other code. This is commonly used to, for example, test if a given +procedure or part of a procedure is entered. Earlier, we could have put +a @code{pk} in the body of the @code{unless} clause to let us know if we +entered it, such as: + +@lisp +(define (make-smore ...) + ... + (unless ... + (pk 'inside-unless) + ...)) +@end lisp + +As a final note, labels don't have to be symbols. @code{pk} will happily +print any object we pass it. We could have used strings or anything else +we wanted alongside the code we were interested in. + +Hopefully this silly little example has shown the utility of @code{pk}. +Now that it's in your toolbox, go forth, newly empowered, and happy +hacking! + + @node Evaluation Model @subsection Evaluation and the Scheme Stack -- 2.45.1