diff options
Diffstat (limited to 'doc/ref/scheme-using.texi')
-rw-r--r-- | doc/ref/scheme-using.texi | 399 |
1 files changed, 248 insertions, 151 deletions
diff --git a/doc/ref/scheme-using.texi b/doc/ref/scheme-using.texi index c19823683..93d0949f8 100644 --- a/doc/ref/scheme-using.texi +++ b/doc/ref/scheme-using.texi @@ -449,11 +449,9 @@ section. * GDS Introduction:: * GDS Architecture:: * GDS Getting Started:: +* Working with GDS in Scheme Buffers:: * Displaying the Scheme Stack:: * Continuing Execution:: -* Evaluating Scheme Code:: -* Setting and Managing Breakpoints:: -* Access to Guile Help and Completion:: * Associating Buffers with Clients:: * An Example GDS Session:: @end menu @@ -501,7 +499,6 @@ existing ones @item continue execution, either normally or step by step. @end itemize -@end enumerate The presentation makes it very easy to move up and down the stack, showing whenever possible the source code for each frame in another @@ -509,11 +506,12 @@ Emacs buffer. It also provides convenient keystrokes for telling Guile what to do next; for example, you can select a stack frame and tell Guile to run until that frame completes, at which point GDS will display the frame's return value. +@end enumerate -Combinations of the above work well too. You can evaluate a fragment of -code (in a Scheme buffer) that contains a breakpoint, then use the -debugging interface to step through the code at the breakpoint. You can -also run a program until it hits a breakpoint, then examine, modify and +Combinations of these well too. You can evaluate a fragment of code (in +a Scheme buffer) that contains a breakpoint, then use the debugging +interface to step through the code at the breakpoint. You can also run +a program until it hits a breakpoint, then examine, modify and reevaluate some of the relevant code, and then tell the program to continue running. @@ -642,7 +640,6 @@ files or modules by sending it @code{load} or @code{use-modules} expressions. You can set breakpoints and evaluate code which hits those breakpoints, and GDS will pop up the stack at the breakpoint so you can explore your code by single-stepping and evaluating test expressions. - For a hands-on, tutorial introduction to using GDS in this way, use Emacs to open the file @file{gds-tutorial.txt} (which should have been installed as part of Guile, perhaps under @file{/usr/share/doc/guile}), @@ -655,21 +652,33 @@ following subsections describe the various ways of doing this. @subsubsection Setting Specific Breakpoints +The first option is to use @code{break-in} or @code{break-at} to set +specific breakpoints in the application's code. This requires code like +the following. + @lisp (use-modules (ice-9 debugging breakpoints) (ice-9 gds-client)) (break-in 'fact2 "ice-9/debugging/example-fns" #:behaviour gds-debug-trap) +(break-in 'facti "ice-9/debugging/example-fns" + #:behaviour gds-debug-trap) @end lisp -In this example, the program chooses to define its breakpoint explicitly -in its code, rather than downloading definitions from GDS, but it still -uses GDS to control what happens when the breakpoint is hit, by -specifying @code{gds-debug-trap} as the breakpoint behaviour. +@noindent +The @code{#:behaviour gds-debug-trap} clauses mean to use GDS to display +the stack when one of these breakpoints is hit. For more on +breakpoints, @code{break-in} and @code{break-at}, see @ref{Intro to +Breakpoints}. @subsubsection Setting GDS-managed Breakpoints +Instead of listing specific breakpoints in application code, you can use +GDS to manage the set of breakpoints that you want from Emacs, and tell +the application to download the breakpoints that it should set from +GDS. The code for this is: + @lisp (use-modules (ice-9 gds-client)) (set-gds-breakpoints) @@ -680,11 +689,52 @@ a set of breakpoint definitions. The program sets those breakpoints in its code, then continues running. When the program later hits one of the breakpoints, it will use GDS to -display the stack and wait for instruction on what to do next, as -described above. +display the stack and wait for instruction on what to do next. @subsubsection Invoking GDS when an Exception Occurs +Another option is to use GDS to catch and display any exceptions that +are thrown by the application's code. If you already have a +@code{lazy-catch} or @code{with-throw-handler} around the area of code +that you want to monitor, you just need to add the following to the +handler code: + +@lisp +(gds-debug-trap (throw->trap-context key args)) +@end lisp + +@noindent +where @code{key} and @code{args} are the first and rest arguments that +Guile passes to the handler. (In other words, they assume the handler +signature @code{(lambda (key . args) @dots{})}.) With Guile 1.8 or +later, you can also do this with a @code{catch}, by adding this same +code to the catch's pre-unwind handler. + +If you don't already have any of these, insert a whole +@code{with-throw-handler} expression (or @code{lazy-catch} if your Guile +is pre-1.8) around the code of interest like this: + +@lisp +(with-throw-handler #t + (lambda () + ;; Protected code here. + ) + (lambda (key . args) + (gds-debug-trap (throw->trap-context key args)))) +@end lisp + +In all cases you will need to use the @code{(ice-9 gds-client)} and +@code{(ice-9 debugging traps)} modules. + +Two special cases of this are the lazy-catch that the Guile REPL code +uses to catch exceptions in user code, and the lazy-catch inside the +@code{stack-catch} utility procedure that is provided by the +@code{(ice-9 stack-catch)} module. Both of these use a handler called +@code{lazy-handler-dispatch} (defined in @file{boot-9.scm}), which you +can hook into such that it calls GDS to display the stack when an +exception occurs. To do this, use the @code{on-lazy-handler-dispatch} +procedure as follows. + @lisp (use-modules (ice-9 gds-client) (ice-9 debugging traps)) @@ -692,18 +742,10 @@ described above. (on-lazy-handler-dispatch gds-debug-trap) @end lisp -This means that the program will use GDS to display the stack whenever -it hits an exception that is protected by a @code{lazy-catch} using -Guile's standard @code{lazy-catch-handler} (defined in -@file{boot-9.scm}). - -@code{lazy-catch-handler} is used by the @code{stack-catch} procedure, -provided by the @code{(ice-9 stack-catch)} module, so this will include -exceptions within a @code{stack-catch}. @code{lazy-catch-handler} is -also used by the standard Guile REPL, when you run Guile interactively, -so you can add the above lines to your @file{.guile} file if you want to -use GDS whenever something that you type into the REPL throws an -exception. +@noindent +After this the program will use GDS to display the stack whenever it +hits an exception that is protected by a @code{lazy-catch} using +@code{lazy-handler-dispatch}. @subsubsection Accepting GDS Instructions at Any Time @@ -745,14 +787,11 @@ This approach is not yet implemented, though. @subsubsection Utility Guile Implementation -We bring this subsection full circle by noting that the ``utility'' Guile -client, which GDS starts automatically when you use GDS as described -under approach 1 above, is really just a special case of ``a Guile -program or script which is started independently'' (approach 2), and -provides the services that the GDS front end needs by a simple -combination of some of the code fragments just described. +We conclude this subsection with an aside, by noting that the +``utility'' Guile client described above is nothing more than a +combination of the previous options. -To be precise, the code for the utility Guile client is essentially +To be precise, the code for the utility Guile client is essentially just this: @lisp @@ -765,12 +804,11 @@ this: @code{set-gds-breakpoints} works as already described. The @code{named-module-use!} line ensures that the client can process -@code{help} and @code{apropos} expressions, which is what the front end -sends to implement lookups in Guile's online help. The @code{#f} -parameter to @code{gds-accept-input} means that the @code{continue} -instruction will not cause the instruction loop to exit, which makes -sense here because the utility client has nothing to do except to -process GDS instructions. +@code{help} and @code{apropos} expressions, to implement lookups in +Guile's online help. The @code{#f} parameter to @code{gds-accept-input} +means that the @code{continue} instruction will not cause the +instruction loop to exit, which makes sense here because the utility +client has nothing to do except to process GDS instructions. (The utility client does not use @code{on-lazy-handler-dispatch}, because it has its own mechanism for catching and reporting exceptions @@ -780,6 +818,176 @@ stack, so the end result is very similar to what @code{on-lazy-handler-dispatch} provides.) +@node Working with GDS in Scheme Buffers +@subsection Working with GDS in Scheme Buffers + +The following subsections describe the facilities and key sequences that +GDS provides for working on code in @code{scheme-mode} buffers. + +@menu +* Access to Guile Help and Completion:: +* Setting and Managing Breakpoints:: +* Listing and Deleting Breakpoints:: +* Moving and Losing Breakpoints:: +* Evaluating Scheme Code:: +@end menu + + +@node Access to Guile Help and Completion +@subsubsection Access to Guile Help and Completion + +The following keystrokes provide fast and convenient access to Guile's +built in help, and to completion with respect to the set of defined and +accessible symbols. + +@table @kbd +@item C-h g +@findex gds-help-symbol +Get Guile help for a particular symbol, with the same results as if +you had typed @code{(help SYMBOL)} into the Guile REPL +(@code{gds-help-symbol}). The symbol to query defaults to the word at +or before the cursor but can also be entered or edited in the +minibuffer. The available help is popped up in a temporary Emacs +window. + +@item C-h C-g +@findex gds-apropos +List all accessible Guile symbols matching a given regular expression, +with the same results as if you had typed @code{(apropos REGEXP)} into +the Guile REPL (@code{gds-apropos}). The regexp to query defaults to +the word at or before the cursor but can also be entered or edited in +the minibuffer. The list of matching symbols is popped up in a +temporary Emacs window. + +@item M-@key{TAB} +@findex gds-complete-symbol +Try to complete the symbol at the cursor by matching it against the +set of all defined and accessible bindings in the associated Guile +process (@code{gds-complete-symbol}). If there are any extra +characters that can be definitively added to the symbol at point, they +are inserted. Otherwise, if there are any completions available, they +are popped up in a temporary Emacs window, where one of them can be +selected using either @kbd{@key{RET}} or the mouse. +@end table + + +@node Setting and Managing Breakpoints +@subsubsection Setting and Managing Breakpoints + +You can create a breakpoint in GDS by typing @kbd{C-x @key{SPC}} in a +Scheme mode buffer. To create a breakpoint on calls to a procedure --- +i.e. the equivalent of calling @code{break-in} --- place the cursor +anywhere within the procedure's definition, make sure that the region is +unset, and type @kbd{C-x @key{SPC}}. To create breakpoints on a +particular expression, or on the series of expressions in a particular +region --- i.e. as with @code{break-at} --- select a region containing +the open parentheses of the expressions where you want breakpoints, and +type @kbd{C-x @key{SPC}}. In other words, GDS assumes that you want a +@code{break-at} breakpoint if there is an active region, and a +@code{break-in} breakpoint otherwise. + +There are three supported breakpoint behaviours, known as @code{debug}, +@code{trace} and @code{trace-subtree}. @code{debug} means that GDS will +display the stack and wait for instruction when the breakpoint is hit. +@code{trace} means that a line will be written to the trace output +buffer (@code{*GDS Trace*}) when the breakpoint is hit, and when the +relevant expression or procedure call returns. @code{trace-subtree} +means that a line is written to the trace output buffer for every +evaluation step between when the breakpoint is hit and when the +expression or procedure returns. + +@kbd{C-x @key{SPC}} creates a breakpoint with behaviour according to the +@code{gds-default-breakpoint-type} variable, which by default is +@code{debug}; you can customize this if you prefer a different default. +You can also create a breakpoint with behaviour other than the current +default by using the alternative key sequences @kbd{C-c C-b d} (for +@code{debug}), @kbd{C-c C-b t} (for @code{trace}) and @kbd{C-c C-b T} +(for @code{trace-subtree}). + +GDS keeps all the breakpoints that you create in a single list, and +tries to set them in every Guile program that connects to GDS and calls +@code{set-gds-breakpoints}. That may sound surprising, because you are +probably thinking of one particular program when you create a +breakpoint; but GDS assumes that you would want the breakpoint to continue +taking effect if you stop and restart that program, and this is +currently achieved by giving all breakpoints to every program that asks +for them. In practice it doesn't matter if a program gets a breakpoint +definition --- such as ``break in procedure @code{foo}'' --- that it +can't actually map to any of its code. + +If there are already Guile programs connected to GDS when you create a +new breakpoint, GDS also tries to set the new breakpoint in each of +those programs at the earliest opportunity, which is usually when they +decide to stop and talk to GDS for some other reason. + + +@node Listing and Deleting Breakpoints +@subsubsection Listing and Deleting Breakpoints + +To see a list of all breakpoints, type @kbd{C-c C-b ?} (or @kbd{M-x +gds-describe-breakpoints}). GDS will then pop up a buffer that +describes each breakpoint and reports whether it is actually set in each +of the Guile programs connected to GDS. + +To delete a breakpoint, type @kbd{C-c C-b @key{backspace}}. If the +region is active when you do this, GDS will delete all of the +breakpoints in the region. If the region is not active, GDS tries to +delete a ``break-in'' breakpoint for the procedure whose definition +contains point (the Emacs cursor). In either case, deletion means that +the breakpoint is removed both from GDS's global list and from all of +the connected Guile programs that had previously managed to set it. + + +@node Moving and Losing Breakpoints +@subsubsection Moving and Losing Breakpoints + +Imagine that you set a breakpoint at line 80 of a Scheme code file, and +execute some code that hits this breakpoint; then you add some new code +at line 40, or delete some code that is no longer needed, and save the +file. Now the breakpoint will have moved up or down from line 80, and +any attached Guile program needs to be told about the new line number. +Otherwise, when a program loads this file again, it will try incorrectly +to set a breakpoint on whatever code is now at line 80, and will +@emph{not} set a breakpoint on the code where you want it. + +For this reason, GDS checks all breakpoint positions whenever you save a +Scheme file, and sends the new position to connected Guile programs for +any breakpoints that have moved. @dots{} [to be continued] + + +@node Evaluating Scheme Code +@subsubsection Evaluating Scheme Code + +The following keystrokes and commands provide various ways of sending +code to a Guile client process for evaluation. + +@table @kbd +@item M-C-x +@findex gds-eval-defun +Evaluate the ``top level defun'' that the cursor is in, in other words +the smallest balanced expression which includes the cursor and whose +opening parenthesis is in column 0 (@code{gds-eval-defun}). + +@item C-x C-e +@findex gds-eval-last-sexp +Evaluate the expression that ends just before the cursor +(@code{gds-eval-last-sexp}). This is designed so that it is easy to +evaluate an expression that you have just finished typing. + +@item C-c C-e +@findex gds-eval-expression +Read a Scheme expression using the minibuffer, and evaluate that +expression (@code{gds-eval-expression}). + +@item C-c C-r +@findex gds-eval-region +Evaluate the Scheme code in the marked region of the current buffer +(@code{gds-eval-region}). Note that GDS does not check whether the +region contains a balanced expression, or try to expand the region so +that it does; it uses the region exactly as it is. +@end table + + @node Displaying the Scheme Stack @subsection Displaying the Scheme Stack @@ -902,117 +1110,6 @@ remains in place and so will still fire at the appropriate point. @end table -@node Evaluating Scheme Code -@subsection Evaluating Scheme Code - -The following keystrokes and commands provide various ways of sending -code to a Guile client process for evaluation. - -@table @kbd -@item M-C-x -@findex gds-eval-defun -Evaluate the ``top level defun'' that the cursor is in, in other words -the smallest balanced expression which includes the cursor and whose -opening parenthesis is in column 0 (@code{gds-eval-defun}). - -@item C-x C-e -@findex gds-eval-last-sexp -Evaluate the expression that ends just before the cursor -(@code{gds-eval-last-sexp}). This is designed so that it is easy to -evaluate an expression that you have just finished typing. - -@item C-c C-e -@findex gds-eval-expression -Read a Scheme expression using the minibuffer, and evaluate that -expression (@code{gds-eval-expression}). - -@item C-c C-r -@findex gds-eval-region -Evaluate the Scheme code in the marked region of the current buffer -(@code{gds-eval-region}). Note that GDS does not check whether the -region contains a balanced expression, or try to expand the region so -that it does; it uses the region exactly as it is. -@end table - - -@node Setting and Managing Breakpoints -@subsection Setting and Managing Breakpoints - -You can create a breakpoint in GDS by typing @kbd{C-x @key{SPC}} in a -Scheme mode buffer. To create a breakpoint on calls to a procedure ---- i.e. the equivalent of calling @code{break-in} --- place the -cursor on the procedure's name and type @kbd{C-x @key{SPC}}. To -create breakpoints on a particular expression, or on the series of -expressions in a particular region --- i.e. as with @code{break-at} ---- select the expression or region in the usual way and type @kbd{C-x -@key{SPC}}. In general, GDS assumes that you want a @code{break-at} -breakpoint if there is an active region, and a @code{break-in} -breakpoint otherwise. - -When you create a breakpoint like this, two things happen. Firstly, -if the current buffer is associated with a Guile client program, the -new breakpoint definition is immediately sent to that client (or, if -the client cannot accept input immediately, it is held in readiness to -pass to the client at the next possible opportunity). This allows the -new breakpoint to take effect as soon as possible in the relevant -client program. - -Secondly, it is added to GDS's @emph{global} list of all breakpoints. -This list holds the breakpoint information that will be given to any -client program that asks for it by calling @code{set-gds-breakpoints}. -The fact that this list is global, rather than client-specific, means -that the breakpoints you have set will automatically be recreated if -the program you are debugging has to be stopped and restarted --- -which in my experience happens often.@footnote{An important point here -is that there is nothing that unambiguously relates two subsequent -runs of the same client program, which might allow GDS to pass on -breakpoint settings more precisely.} - -(The only possible downside of this last point is that if you are -debugging two programs in parallel, which have some code in common, -you might not want a common code breakpoint in one program to be set -in the other program as well. But this feels like a small concern in -comparison to the benefit of breakpoints persisting as just described.) - - -@node Access to Guile Help and Completion -@subsection Access to Guile Help and Completion - -The following keystrokes provide fast and convenient access to Guile's -built in help, and to completion with respect to the set of defined and -accessible symbols. - -@table @kbd -@item C-h g -@findex gds-help-symbol -Get Guile help for a particular symbol, with the same results as if -you had typed @code{(help SYMBOL)} into the Guile REPL -(@code{gds-help-symbol}). The symbol to query defaults to the word at -or before the cursor but can also be entered or edited in the -minibuffer. The available help is popped up in a temporary Emacs -window. - -@item C-h C-g -@findex gds-apropos -List all accessible Guile symbols matching a given regular expression, -with the same results as if you had typed @code{(apropos REGEXP)} into -the Guile REPL (@code{gds-apropos}). The regexp to query defaults to -the word at or before the cursor but can also be entered or edited in -the minibuffer. The list of matching symbols is popped up in a -temporary Emacs window. - -@item M-@key{TAB} -@findex gds-complete-symbol -Try to complete the symbol at the cursor by matching it against the -set of all defined and accessible bindings in the associated Guile -process (@code{gds-complete-symbol}). If there are any extra -characters that can be definitively added to the symbol at point, they -are inserted. Otherwise, if there are any completions available, they -are popped up in a temporary Emacs window, where one of them can be -selected using either @kbd{@key{RET}} or the mouse. -@end table - - @node Associating Buffers with Clients @subsection Associating Buffers with Clients |