1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 11:50:28 +02:00
guile/doc/ref/scheme-using.texi
Neil Jerram ee6be719ce * scheme-using.texi (Error Handling, Interactive Debugger): Minor
editorial improvements.
(Leave Debugger): Removed.
(Display Backtrace): Minor updates.
(Frame Selection, Frame Information, Frame Evaluation) : Minor
editorial improvements.
(Stepping and Continuing): Merged from three previous nodes; plus
minor improvements.  Removed doc for `trace-finish', which no
longer exists.

* debugging/ice-9-debugger-extensions.scm (debugger:step):
Docstring improvements.
(debugger:next): Docstring improvements.
(debugger:continue): Docstring improvements.

* debugger/commands.scm (up, down): Docstring corrections.
(info-args, info-frame, position, evaluate): Docstring
improvements.
2006-09-25 21:05:46 +00:00

1264 lines
46 KiB
Text

@c -*-texinfo-*-
@c This is part of the GNU Guile Reference Manual.
@c Copyright (C) 2006
@c Free Software Foundation, Inc.
@c See the file guile.texi for copying conditions.
@node Using Guile Interactively
@section Using Guile Interactively
When you start up Guile by typing just @code{guile}, without a
@code{-c} argument or the name of a script to execute, you get an
interactive interpreter where you can enter Scheme expressions, and
Guile will evaluate them and print the results for you. Here are some
simple examples.
@lisp
guile> (+ 3 4 5)
12
guile> (display "Hello world!\n")
Hello world!
guile> (values 'a 'b)
a
b
@end lisp
@noindent
This mode of use is called a @dfn{REPL}, which is short for
``Read-Eval-Print Loop'', because the Guile interpreter first reads the
expression that you have typed, then evaluates it, and then prints the
result.
@menu
* Readline::
* Value Historyx::
* Error Handling::
* Interactive Debugger:: Using the interactive debugger.
@end menu
@node Readline
@subsection Readline
To make it easier for you to repeat and vary previously entered
expressions, or to edit the expression that you're typing in, Guile
can use the GNU Readline library. This is not enabled by default
because of licensing reasons, but all you need to activate Readline is
the following pair of lines.
@lisp
guile> (use-modules (ice-9 readline))
guile> (activate-readline)
@end lisp
It's a good idea to put these two lines (without the ``guile>''
prompts) in your @file{.guile} file. Guile reads this file when it
starts up interactively, so anything in this file has the same effect
as if you type it in by hand at the ``guile>'' prompt.
@node Value Historyx
@subsection Value History
Just as Readline helps you to reuse a previous input line, @dfn{value
history} allows you to use the @emph{result} of a previous evaluation
in a new expression. When value history is enabled, each evaluation
result is automatically assigned to the next in the sequence of
variables @code{$1}, @code{$2}, @dots{}, and you can then use these
variables in subsequent expressions.
@lisp
guile> (iota 10)
$1 = (0 1 2 3 4 5 6 7 8 9)
guile> (apply * (cdr $1))
$2 = 362880
guile> (sqrt $2)
$3 = 602.3952191045344
guile> (cons $2 $1)
$4 = (362880 0 1 2 3 4 5 6 7 8 9)
@end lisp
To enable value history, type @code{(use-modules (ice-9 history))} at
the Guile prompt, or add this to your @file{.guile} file. (It is not
enabled by default, to avoid the possibility of conflicting with some
other use you may have for the variables @code{$1}, @code{$2},
@dots{}, and also because it prevents the stored evaluation results
from being garbage collected, which some people may not want.)
@node Error Handling
@subsection Error Handling
When code being evaluated from the REPL hits an error, Guile remembers
the execution context where the error occurred and can give you three
levels of information about what the error was and exactly where it
occurred.
By default, Guile displays only the first level, which is the most
immediate information about where and why the error occurred, for
example:
@lisp
(make-string (* 4 (+ 3 #\s)) #\space)
@print{}
standard input:2:19: In procedure + in expression (+ 3 #\s):
standard input:2:19: Wrong type argument: #\s
ABORT: (wrong-type-arg)
Type "(backtrace)" to get more information
or "(debug)" to enter the debugger.
@end lisp
@noindent
However, as the message above says, you can obtain more information
about the context of the error by typing @code{(backtrace)} or
@code{(debug)}.
@code{(backtrace)} displays the Scheme call stack at the point where the
error occurred:
@lisp
(backtrace)
@print{}
Backtrace:
In standard input:
2: 0* [make-string ...
2: 1* [* 4 ...
2: 2* [+ 3 #\s]
Type "(debug-enable 'backtrace)" if you would like a backtrace
automatically if an error occurs in the future.
@end lisp
@noindent
In a more complex scenario than this one, this can be extremely useful
for understanding where and why the error occurred. You can make Guile
show the backtrace automatically by adding @code{(debug-enable
'backtrace)} to your @file{.guile}.
@code{(debug)} takes you into Guile's interactive debugger, which
provides commands that allow you to
@itemize @bullet
@item
display the Scheme call stack at the point where the error occurred
(the @code{backtrace} command --- see @ref{Display Backtrace})
@item
move up and down the call stack, to see in detail the expression being
evaluated, or the procedure being applied, in each @dfn{frame} (the
@code{up}, @code{down}, @code{frame}, @code{position}, @code{info args}
and @code{info frame} commands --- see @ref{Frame Selection} and
@ref{Frame Information})
@item
examine the values of variables and expressions in the context of each
frame (the @code{evaluate} command --- see @ref{Frame Evaluation}).
@end itemize
@noindent
The interactive debugger is documented further in the following section.
@node Interactive Debugger
@subsection Using the Interactive Debugger
Guile's interactive debugger is a command line application that accepts
commands from you for examining the stack and, if at a breakpoint, for
continuing program execution in various ways. Unlike in the normal
Guile REPL, commands are typed mostly without parentheses.
When you first enter the debugger, it introduces itself with a message
like this:
@lisp
This is the Guile debugger -- for help, type `help'.
There are 3 frames on the stack.
Frame 2 at standard input:36:19
[+ 3 #\s]
debug>
@end lisp
@noindent
``debug>'' is the debugger's prompt, and a reminder that you are not in
the normal Guile REPL. In case you find yourself in the debugger by
mistake, the @code{quit} command will return you to the REPL.
@deffn {Debugger Command} quit
Exit the debugger.
@end deffn
The other available commands are described in the following subsections.
@menu
* Display Backtrace:: backtrace.
* Frame Selection:: up, down, frame.
* Frame Information:: info args, info frame, position.
* Frame Evaluation:: evaluate.
* Stepping and Continuing:: step, next, (trace-)finish, continue.
@end menu
@node Display Backtrace
@subsubsection Display Backtrace
The @code{backtrace} command, which can also be invoked as @code{bt} or
@code{where}, displays the call stack (aka backtrace) at the point where
the debugger was entered:
@lisp
debug> bt
In standard input:
36: 0* [make-string ...
36: 1* [* 4 ...
36: 2* [+ 3 #\s]
@end lisp
@deffn {Debugger Command} backtrace [count]
@deffnx {Debugger Command} bt [count]
@deffnx {Debugger Command} where [count]
Print backtrace of all stack frames, or of the innermost @var{count}
frames. With a negative argument, print the outermost -@var{count}
frames. If the number of frames isn't explicitly given, the debug
option @code{depth} determines the maximum number of frames printed.
@end deffn
The format of the displayed backtrace is the same as for the
@code{display-backtrace} procedure (@pxref{Examining the Stack}).
@node Frame Selection
@subsubsection Frame Selection
A call stack consists of a sequence of stack @dfn{frames}, with each
frame describing one level of the nested evaluations and applications
that the program was executing when it hit a breakpoint or an error.
Frames are numbered such that frame 0 is the outermost --- i.e. the
operation on the call stack that began least recently --- and frame N-1
the innermost (where N is the total number of frames on the stack).
When you enter the debugger, the innermost frame is selected, which
means that the commands for getting information about the ``current''
frame, or for evaluating expressions in the context of the current
frame, will do so by default with respect to the innermost frame. To
select a different frame, so that these operations will apply to it
instead, use the @code{up}, @code{down} and @code{frame} commands like
this:
@lisp
debug> up
Frame 1 at standard input:36:14
[* 4 ...
debug> frame 0
Frame 0 at standard input:36:1
[make-string ...
debug> down
Frame 1 at standard input:36:14
[* 4 ...
@end lisp
@deffn {Debugger Command} up [n]
Move @var{n} frames up the stack. For positive @var{n}, this
advances toward the outermost frame, to lower frame numbers, to
frames that have existed longer. @var{n} defaults to one.
@end deffn
@deffn {Debugger Command} down [n]
Move @var{n} frames down the stack. For positive @var{n}, this
advances toward the innermost frame, to higher frame numbers, to frames
that were created more recently. @var{n} defaults to one.
@end deffn
@deffn {Debugger Command} frame [n]
Select and print a stack frame. With no argument, print the selected
stack frame. (See also ``info frame''.) An argument specifies the
frame to select; it must be a stack-frame number.
@end deffn
@node Frame Information
@subsubsection Frame Information
The following commands return detailed information about the currently
selected frame.
@deffn {Debugger Command} {info frame}
Display a verbose description of the selected frame. The information
that this command provides is equivalent to what can be deduced from the
one line summary for the frame that appears in a backtrace, but is
presented and explained more clearly.
@end deffn
@deffn {Debugger Command} {info args}
Display the argument variables of the current stack frame. Arguments
can also be seen in the backtrace, but are presented more clearly by
this command.
@end deffn
@deffn {Debugger Command} position
Display the name of the source file that the current expression comes
from, and the line and column number of the expression's opening
parenthesis within that file. This information is only available when
the @code{positions} read option is enabled (@pxref{Reader options}).
@end deffn
@node Frame Evaluation
@subsubsection Frame Evaluation
The @code{evaluate} command is most useful for querying the value of a
variable, either global or local, in the environment of the selected
stack frame, but it can be used more generally to evaluate any
expression.
@deffn {Debugger Command} evaluate expression
Evaluate an expression in the environment of the selected stack frame.
The expression must appear on the same line as the command, however it
may be continued over multiple lines.
@end deffn
@node Stepping and Continuing
@subsubsection Single Stepping and Continuing Execution
The commands in this subsection all apply only when the stack is
@dfn{continuable} --- in other words when it makes sense for the program
that the stack comes from to continue running. Usually this means that
the program stopped because of a trap or a breakpoint.
@deffn {Debugger Command} step [n]
Tell the debugged program to do @var{n} more steps from its current
position. One @dfn{step} means executing until the next frame entry or
exit of any kind. @var{n} defaults to 1.
@end deffn
@deffn {Debugger Command} next [n]
Tell the debugged program to do @var{n} more steps from its current
position, but only counting frame entries and exits where the
corresponding source code comes from the same file as the current stack
frame. (See @ref{Step Traps} for the details of how this works.) If
the current stack frame has no source code, the effect of this command
is the same as of @code{step}. @var{n} defaults to 1.
@end deffn
@deffn {Debugger Command} finish
Tell the program being debugged to continue running until the completion
of the current stack frame, and at that time to print the result and
reenter the command line debugger.
@end deffn
@deffn {Debugger Command} continue
Tell the program being debugged to continue running. (In fact this is
the same as the @code{quit} command, because it exits the debugger
command loop and so allows whatever code it was that invoked the
debugger to continue.)
@end deffn
@node Using Guile in Emacs
@section Using Guile in Emacs
There are quite a few options for working on Guile Scheme code in
Emacs. The simplest options are to use Emacs's standard
@code{scheme-mode} for editing code, and to run the interpreter when you
need it by typing ``guile'' at the prompt of a @code{*shell*} buffer,
but there are Emacs libraries available which add various bells and
whistles to this. The following diagram shows these libraries and how
they relate to each other, with the arrows indicating ``builds on'' or
``extends''. For example, the Quack library builds on cmuscheme, which
in turn builds on the standard scheme mode.
@example
scheme
^
|
.-----+-----.
| |
cmuscheme xscheme
^
|
.-----+-----.
| |
Quack GDS
@end example
@dfn{scheme}, written by Bill Rozas and Dave Love, is Emacs's standard
mode for Scheme code files. It provides Scheme-sensitive syntax
highlighting, parenthesis matching, indentation and so on.
@dfn{cmuscheme}, written by Olin Shivers, provides a comint-based Scheme
interaction buffer, so that you can run an interpreter more directly
than with the @code{*shell*} buffer approach by typing @kbd{@key{M-x}
run-scheme}. It also extends @code{scheme-mode} so that there are key
presses for sending selected bits of code from a Scheme buffer to this
interpreter. This means that when you are writing some code and want to
check what an expression evaluates to, you can easily select that code
and send it to the interpreter for evaluation, then switch to the
interpreter to see what the result is. cmuscheme is included in the
standard Emacs distribution.
@dfn{Quack}, written by Neil Van Dyke, adds a number of incremental
improvements to the scheme/cmuscheme combination: convenient menu
entries for looking up Scheme-related references (such as the SRFIs);
enhanced indentation rules that are customized for particular Scheme
interpreters, including Guile; an enhanced version of the
@code{run-scheme} command that knows the names of the common Scheme
interpreters and remembers which one you used last time; and so on.
Quack is available from @uref{http://www.neilvandyke.org/quack}.
@dfn{GDS}, written by Neil Jerram, also builds on the scheme/cmuscheme
combination, but with a fundamental change to the way that Scheme code
fragments are sent to the interpreter for evaluation. cmuscheme and
Quack send code fragments to the interpreter's standard input, on the
assumption that the interpreter is expecting to read Scheme expressions
there, and then monitor the interpreter's standard output to infer what
the result of the evaluation is. GDS doesn't use standard input and
output like this. Instead, it sets up a socket connection between the
Scheme interpreter and Emacs, and sends and receives messages using a
simple protocol through this socket. The messages include requests to
evaluate Scheme code, and responses conveying the results of an
evaluation, thus providing similar function to cmuscheme or Quack; they
also include requests for setting breakpoints, stack exploration and
debugging, which go beyond what cmuscheme or Quack can do. The price of
this extra power, however, is that GDS is Guile-specific. GDS requires
the Scheme interpreter, or any program that GDS is debugging, to run
some GDS-specific library code; currently this code is written as a
Guile module and uses a lot of debugging-related features that are
specific to Guile. GDS is now included in the Guile distribution; for
previous Guile releases (1.8.x and earlier) it can be obtained as part
of the @code{guile-debugging} package from
@uref{http://www.ossau.uklinux.net/guile}.
Finally, @dfn{xscheme} is similar to cmuscheme -- in that it starts up a
Scheme interaction process and sends commands to that process's standard
input -- and to GDS -- in that it has support beyond cmuscheme or Quack
for exploring the Scheme stack when an error has occurred -- but is
implemented specifically for MIT/GNU Scheme. Hence it isn't really
relevant to Guile work in Emacs, except as a reference for useful
features that could be implemented in one of the other libraries
mentioned here.
In summary, the ``best'' current choice for working on Guile code in
Emacs is either Quack or GDS, depending on which of these libraries'
features you find most important. For more information on Quack, please
see the website referenced above. GDS is documented further in the rest
of this section.
@menu
* GDS Introduction::
* GDS Getting Started::
* How To Use GDS::
* 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::
* GDS Architecture::
@end menu
@node GDS Introduction
@subsection GDS Introduction
GDS aims to allow you to work on Guile Scheme code in the same kind of
way that Emacs allows you to work on Emacs Lisp code: providing easy
access to help, evaluating arbitrary fragments of code, a nice debugging
interface, and so on. The thinking behind this environment is that you
will usually be doing one of two things.
@enumerate
@item
Writing or editing code. The code will be in a normal Emacs Scheme mode
buffer, and GDS extends Scheme mode to add keystrokes and menu items for
the things that are likely to be useful to you when working on code:
@itemize
@item
completing the identifier at point
@item
accessing Guile's built in help
@item
evaluating fragments of code to check what they do.
@end itemize
@item
Debugging a Guile Scheme program. When your program hits an error or a
breakpoint, GDS can show you the relevant code and the Scheme stack, and
make it easy to
@itemize
@item
look at the values of local variables
@item
see what is happening at all levels of the Scheme stack
@item
continue execution, either normally or step by step.
@end itemize
@end enumerate
Combinations of these 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 reevaluate some of the relevant code, and then tell the
program to continue running.
In other words, we could say that GDS provides a set of facilities which
aim to make the writing, debugging and maintenance of Scheme code in
Emacs as fluid and productive as possible. In a bit more detail, these
facilities are currently as follows.
@table @asis
@item Displaying the Scheme stack
When running Scheme code hits a trap or throws an exception, GDS can
display the stack at the point of the trap or exception. The
presentation makes it very easy to move up and down the stack, showing
whenever possible the source code for each frame in another Emacs
buffer, and allowing you to evaluate test expressions in the context of
the selected frame.
@item Continuing execution from a trap
When GDS is showing the stack for code that has hit a trap, it also
allows you to control how execution continues from that point. 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.
@item Evaluating Scheme code
GDS allows you to select a region of a Scheme buffer and send it to
Guile for evaluation, or to enter a Scheme expression to be evaluated in
the Emacs minibuffer. In both cases the evaluation results are popped
up in a temporary Emacs window.
@item Setting breakpoints in Scheme code
GDS makes it easy to set breakpoints in Scheme code from within Emacs.
Deep down this uses Guile's trap and breakpoint infrastructure described
elsewhere in this manual, but GDS makes the practicalities as simple as
typing @kbd{C-x @key{SPC}}. When a GDS breakpoint is hit, the stack at
that point is popped up in Emacs. GDS also remembers your breakpoints
between editing sessions, so you don't have to set them again when you
visit the relevant files.
@item Access to Guile's built in help system
GDS makes it easy to query Guile's ``help'' and ``apropos'' commands,
and pops up the results in a temporary Emacs window.
@item Symbol completion
GDS provides a keystroke which tries to complete a partially entered
symbol by asking Guile to match it against all the accessible bindings.
@end table
GDS can provide these facilities for any number of Guile Scheme programs
(which we often call ``clients'') at once, and these programs can be
started either completely independently of GDS, including outside Emacs,
or specifically @emph{by} GDS. The two common cases are:
@itemize
@item
a Guile application, such as @uref{http://www.gnucash.org, GnuCash},
which is started from your desktop, and which connects to GDS as a
result of some incantation added to its startup code
@item
a ``utility'' Guile process which is run by GDS to provide help,
completion and evaluation for Scheme code that you are working on in
Emacs.
@end itemize
@noindent
The user experience --- in other words the ways that the GDS front end
allows you to interact with the client --- is much the same in all
cases.
Communication between the Guile client program and GDS uses a TCP
socket, which means that it is orthogonal to any other interfaces that
the client program has. In particular GDS does not interfere with a
program's standard input and output.
@node GDS Getting Started
@subsection Getting Started with GDS
GDS's Scheme and Emacs Lisp files will have been installed in the
correct places system-wide when Guile as a whole was installed. To
enable the use of GDS in your own Emacs sessions, simply add
@lisp
(require 'gds)
@end lisp
@noindent
somewhere in your @file{.emacs} file.
For a hands-on, tutorial introduction to using GDS, you may then like to
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}), and then follow the steps in that file.
@node How To Use GDS
@subsection How To Use GDS
There are lots of ways to use GDS, but they boil down to two overall
approaches.
@enumerate
@item
When you are writing Scheme code in Emacs, you can use GDS while you are
writing to help with things like name completion, looking up help, and
evaluating fragments of code to check that they do what you expect.
The first time you do something that needs a running Guile process, GDS
will automatically create one as an Emacs subprocess. This Guile
program does nothing but wait for and act on instructions from GDS, and
we refer to it as a @dfn{utility} Guile client.
Over time this utility Guile will accumulate the code that you ask it to
evaluate, and you can also tell it to load complete 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.
@item
Alternatively, you can use GDS to explore and debug a Guile program or
script which is started independently of GDS. This could be a script
that you invoke from the command line, or a graphical Guile-using
application which is launched from your desktop's start menu.
In this case the program has to put something in its startup code to
cause it to connect to GDS at some point: either immediately during the
startup processing, or later when an error occurs or a trap is hit.
Several possibilities for this are described below.
Under certain conditions, then, the program will stop, pass its current
Scheme stack to GDS, and then wait for instruction before continuing
execution. At such points you can use GDS to explore the stack,
obviously, but also to set or delete other breakpoints, modify the
program's code (by editing and then reevaluating it from Emacs), and use
the help and completion facilities, before eventually telling the
program to single-step or to continue running normally.
@end enumerate
Here are some of the ways that a Guile program or script can arrange in
its startup code to use GDS.
@subsubsection Invoking GDS when an Exception Occurs
@lisp
(use-modules (ice-9 gds-client)
(ice-9 debugging traps))
(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.
@subsubsection Setting GDS-managed Breakpoints
@lisp
(use-modules (ice-9 gds-client))
(set-gds-breakpoints)
@end lisp
These lines tell the program to connect to GDS immediately and download
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.
@subsubsection Setting Specific Breakpoints
@lisp
(use-modules (ice-9 debugging breakpoints)
(ice-9 gds-client))
(break-in 'fact2 "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.
@subsubsection Accepting GDS Instructions at Any Time
In addition to setting breakpoints and/or an exception handler as
described above, a Guile program can in principle set itself up to
accept new instructions from GDS at any time, not just when it has
stopped at a breakpoint or exception. This would allow the GDS user to
set new breakpoints or to evaluate code in the context of the running
program, without having to wait for the program to stop first.
@lisp
(use-modules (ice-9 gds-client))
(gds-accept-input #t)
@end lisp
@code{gds-accept-input} causes the calling program to loop processing
instructions from GDS, until GDS sends the @code{continue} instruction.
This blocks the thread that calls it, however, so it will normally be
more practical for the program to set up a dedicated GDS thread and call
@code{gds-accept-input} from that thread.
For @code{select}-driven applications, an alternative approach would be
for the GDS client code to provide an API which allowed the application
to
@itemize
@item
discover the file descriptors (or Scheme ports) that are used for
receiving instruction from the GDS front end, so that it could include
these in its @code{select} call
@item
call the GDS instruction handler when @code{select} indicated data
available for reading on those descriptors/ports.
@end itemize
@noindent
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.
To be precise, the code for the utility Guile client is essentially
this:
@lisp
(use-modules (ice-9 gds-client))
(set-gds-breakpoints)
(named-module-use! '(guile-user) '(ice-9 session))
(gds-accept-input #f))
@end lisp
@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.
(The utility client does not use @code{on-lazy-handler-dispatch},
because it has its own mechanism for catching and reporting exceptions
in the code that it is asked to evaluate. This mechanism summarizes the
exception and gives the user a button they can click to see the full
stack, so the end result is very similar to what
@code{on-lazy-handler-dispatch} provides.)
@node Displaying the Scheme Stack
@subsection Displaying the Scheme Stack
When you specify @code{gds-debug-trap} as the behaviour for a trap or
a breakpoint and the Guile program concerned hits that trap or
breakpoint, GDS displays the stack and the relevant Scheme source code
in Emacs, allowing you to explore the state of the program and then
decide what to do next. The same applies if the program calls
@code{(on-lazy-handler-dispatch gds-debug-trap)} and then throws an
exception that passes through @code{lazy-handler-dispatch}, except
that in this case you can only explore; it isn't possible to continue
normal execution after an exception.
The following commands are available in the stack buffer for exploring
the state of the program.
@table @asis
@item @kbd{u}, @kbd{C-p}, @kbd{@key{up}}
@findex gds-up
Select the stack frame one up from the currently selected frame
(@code{gds-up}). GDS displays stack frames with the innermost at the
top, so moving ``up'' means selecting a more ``inner'' frame.
@item @kbd{d}, @kbd{C-n}, @kbd{@key{down}}
@findex gds-down
Select the stack frame one down from the currently selected frame
(@code{gds-down}). GDS displays stack frames with the innermost at the
top, so moving ``down'' means selecting a more ``outer'' frame.
@item @kbd{@key{RET}}
@findex gds-select-stack-frame
Select the stack frame at point (@code{gds-select-stack-frame}). This
is useful after clicking somewhere in the stack trace with the mouse.
@end table
Selecting a frame means that GDS will display the source code
corresponding to that frame in the adjacent window, and that
subsequent frame-sensitive commands, such as @code{gds-evaluate} (see
below) and @code{gds-step-over} (@pxref{Continuing Execution}), will
refer to that frame.
@table @kbd
@item e
@findex gds-evaluate
Evaluate a variable or expression in the local environment of the
selected stack frame (@code{gds-evaluate}). The result is displayed in
the echo area.
@item I
@findex gds-frame-info
Show summary information about the selected stack frame
(@code{gds-frame-info}). This includes what type of frame it is, the
associated expression, and the frame's source location, if any.
@item A
@findex gds-frame-args
For an application frame, display the frame's arguments
(@code{gds-frame-args}).
@item S
@findex gds-proc-source
For an application frame, show the Scheme source code of the procedure
being called (@code{gds-proc-source}). The source code (where
available) is displayed in the echo area.
@end table
@kbd{S} (@code{gds-proc-source}) is useful when the procedure being
called was created by an anonymous @code{(lambda @dots{})} expression.
Such procedures appear in the stack trace as @code{<procedure #f
(@dots{})>}, which doesn't give you much clue as to what will happen
next. @kbd{S} will show you the procedure's code, which is usually
enough for you to identify it.
@node Continuing Execution
@subsection Continuing Execution
If it makes sense to continue execution from the stack which is being
displayed, GDS provides the following further commands in the stack
buffer.
@table @asis
@item @kbd{g}, @kbd{c}, @kbd{q}
@findex gds-go
Tell the program to continue running (@code{gds-go}). It may of course
stop again if it hits another trap, or another occurrence of the same
trap.
The multiple keystrokes reflect that you can think of this as ``going'',
``continuing'' or ``quitting'' (in the sense of quitting the GDS
display).
@item @kbd{@key{SPC}}
@findex gds-step-file
Tell the program to do a single-step to the next entry or exit of a
frame whose code comes from the same source file as the selected stack
frame (@code{gds-step-file}).
In other words, you can hit @kbd{@key{SPC}} repeatedly to step through
the code in a given file, automatically stepping @emph{over} any
evaluations or procedure calls that use code from other files (or from
no file).
If the selected stack frame has no source, the effect of this command is
the same as that of @kbd{i}, described next.
@item @kbd{i}
@findex gds-step-into
Tell the debugged program to do a single-step to the next frame entry or
exit of any kind (@code{gds-step-into}). @kbd{i} therefore steps
through code at the most detailed level possible.
@item @kbd{o}
@findex gds-step-over
Tell the debugged program to continue running until the selected stack
frame completes, and then to display its result (@code{gds-step-over}).
Note that the program may stop before then if it hits another trap; in
this case the trap telling it to stop when the marked frame completes
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
The first time that you use one of GDS's evaluation, help or completion
commands from a given Scheme mode buffer, GDS will ask which Guile
client program you want to use for the operation, or if you want to
start up a new ``utility'' client. After that GDS considers the buffer
to be ``associated'' with the selected client, and so sends all further
requests to that client, but you can override this by explicitly
associating the buffer with a different client, or by removing the
default association.
@table @kbd
@item M-x gds-associate-buffer
Associate (or re-associate) the current buffer with a particular Guile
client program. The available clients are listed, and you can also
choose to start up a new ``utility'' client for this buffer to associate
with.
@item M-x gds-dissociate-buffer
Dissociate the current buffer from its client, if any. This means that
the next time you use an evaluation, help or completion command, GDS
will ask you again which client to send the request to.
@end table
When a buffer is associated with a client program, the buffer's modeline
shows whether the client is currently able to accept instruction from
GDS. This is done by adding one of the following suffixes to the
``Scheme'' major mode indicator:
@table @asis
@item :ready
The client program (or one of its threads, if multithreaded) is
currently ready to accept instruction from GDS. In other words, if you
send it a help or evaluation request, you should see the result pretty
much immediately.
@item :running
The client program is not currently able to accept instruction from
GDS. This means that it (or all of its threads, if multithreaded) is
busy, or waiting for input other than from GDS.
@item :debug
The client program (or one of its threads, if multithreaded) is stopped
in ``debugging mode'' with GDS displaying the stack for a trap or
exception. It is waiting for instruction from GDS on what to do next.
@end table
@node An Example GDS Session
@subsection An Example GDS Session
Create a file, @file{testgds.scm} say, for experimenting with GDS and
Scheme code, and type this into it:
@lisp
(use-modules (ice-9 debugging traps)
(ice-9 gds-client)
(ice-9 debugging example-fns))
(install-trap (make <procedure-trap>
#:behaviour gds-debug-trap
#:procedure fact1))
@end lisp
@noindent
Now select all of this code and type @kbd{C-c C-r} to send the selected
region to Guile for evaluation. GDS will ask you which Guile process to
use; unless you know that you already have another Guile application
running and connected to GDS, choose the ``Start a new Guile'' option,
which starts one of the ``utility'' processes described in @ref{How To
Use GDS}.
The results of the evaluation pop up in a window like this:
@lisp
(use-modules (ice-9 debugging traps)\n @dots{}
;;; Evaluating subexpression 1 in current module (guile-user)
@result{} no (or unspecified) value
;;; Evaluating subexpression 2 in current module (guile-user)
@result{} no (or unspecified) value
--:** *Guile Evaluation* (Scheme:ready)--All------------
@end lisp
@noindent
this tells you that the evaluation was successful but that the return
values were unspecified. Its effect was to load a module of example
functions and set a trap on one of these functions, @code{fact1}, that
calculates the factorial of its argument.
If you now call @code{fact1}, you can see the trap and GDS's stack
display in action. To do this add
@lisp
(fact1 4)
@end lisp
@noindent
to your @file{testgds.scm} buffer and type @kbd{C-x C-e} (which
evaluates the expression that the cursor is just after the end of). The
result is:
@lisp
(fact1 4)
;;; Evaluating in current module (guile-user)
@result{} 24
--:** *Guile Evaluation* (Scheme:ready)--All------------
@end lisp
@noindent
which is correct, but indicates that we forgot the step needed to enable
the trap mechanism. To do this, type @kbd{C-c C-e} and then enter
@lisp
(trap-enable 'traps)
@end lisp
@noindent
into the minibuffer. (You could equally have typed this into your test
file and evaluated it from there; we use @kbd{C-c C-e} here to
demonstrate the minibuffer option and because you typically wouldn't
want to leave this kind of global setting in the source code that you
are working on.)
If you now type @kbd{C-x C-e} to evaluate @code{(fact1 4)} again, a GDS
stack window like the following appears:
@lisp
Calling procedure:
=> s [fact1 4]
s [primitive-eval (fact1 4)]
--:** PID 28729 (Guile-Debug)--All------------
@end lisp
GDS's most compelling feature is its single-stepping. To get an
immediate feel for what this is like, make sure your Emacs is prepared
as described in @ref{GDS Getting Started}, then type the following code
into an interactive Guile session.
@lisp
(fact1 4)
@end lisp
@noindent
This will cause the GDS Guile-Debug window to pop up in Emacs, where
you can then press @kbd{i} once and @kbd{@key{SPC}} repeatedly to
single-step through the code from the point of the initial trap.
(@kbd{i} is needed as the first keystroke rather than @kbd{@key{SPC}},
because the aim here is to step through code in the @code{(ice-9
debugging example-fns)} module, whose source file is
@file{@dots{}/ice-9/debugging/example-fns.scm}, but the initial
@code{(fact1 4)} call comes from the Guile session, whose ``source
file'' Guile presents as @file{standard input}. If the user starts by
pressing @kbd{@key{SPC}} instead of @kbd{i}, the effect is that the
program runs until it hits the first recursive call @code{(fact1 (- n
1))}, where it stops because of the trap on @code{fact1} firing again.
At this point, the source file @emph{is}
@file{@dots{}/ice-9/debugging/example-fns.scm}, because the recursive
@code{(fact1 (- n 1))} call comes from code in that file, so further
pressing of @kbd{@key{SPC}} successfully single-steps through this
file.)
@node GDS Architecture
@subsection GDS Architecture
Ths following information may be of interest to readers who would like
to know how GDS works. Please note that understanding the details of
this subsection is completely optional so far as just using GDS is
concerned!
GDS consists of three components.
@itemize
@item
The GDS @dfn{interface} code is written in Emacs Lisp and runs inside
Emacs. This code, consisting of the installed files @file{gds.el} and
@file{gds-server.el}, is responsible for displaying information from
Guile in Emacs windows, and for responding to Emacs commands and
keystrokes by sending instructions back to the Guile program being
debugged.
@item
The GDS @dfn{server} code is written in Scheme and runs as an Emacs
inferior process. It acts as a multiplexer between the (possibly
multiple) Guile programs being debugged and the interface code running
in Emacs. The server code is the installed file
@file{gds-server.scm}.
@item
The GDS @dfn{client} code is written in Scheme (installed file
@file{gds-client.scm}), and is loaded as a module by each Guile
program that wants to use GDS for debugging. When a trap occurs whose
behaviour is @code{gds-debug-trap}, it feeds information about the
trap context through the server to Emacs, then waits for instruction
back from the Emacs interface on what to do next.
@end itemize
@noindent
Summarized in glorious ASCII art, this looks as follows.
@example
+------------+
| Program #1 |
| |
| +--------+ |
| | Client |-_
| +--------+ |-_ +---------------+
+------------+ -_TCP | Emacs |
-_ | |
-_+--------+ | +-----------+ |
_| Server |-----| Interface | |
+------------+ _- +--------+ | +-----------+ |
| Program #2 | _- +---------------+
| | _- TCP
| +--------+ _-
| | Client |-|
| +--------+ |
+------------+
@end example
@noindent
@cindex TCP, use of
The communication between the client and server components is over a
TCP connection, which has two implications. Firstly, that GDS is
independent of whatever other interfaces the programs being debugged
have, whether graphical or through standard input and output.
Secondly, that the server and Emacs interface can be on a different
computer from the programs being debugged (only theoretically, though,
because GDS doesn't yet provide an interface to connect to any server
other than the default, on localhost at TCP port 8333). The data
exchanged between client and server components, and between server and
interface components, is in the form of sexps that are organized so as
to be directly readable by both Scheme and Emacs Lisp.
@subsubsection Security Note
@cindex Security
GDS currently has no authentication between its client and server
components, so in an untrusted environment the use of TCP probably
raises important security issues. If you are thinking of using GDS in
such an environment, please consider any such issues carefully before
proceeding!
@c Local Variables:
@c TeX-master: "guile.texi"
@c End: