Commands are entered by typing the corresponding key (without newline), the case of the letters is significant. The action of some of them is immediate, others require additional parameters to be typed afterwards. Since the ECLiPSe debugger has the possibility to display not only the goal that is currently being executed (the current goal or procedure), but also its ancestors, some of the commands may work on the displayed procedure whatever it is, and others on the current one.
When a counter is used and is valid for the command, the command is repeated, decrementing the counter until zero. When repeating the command, the command and the remaining counter value is printed after the debugger prompt instead of waiting for user input.
Some commands prompt for a parameter, e.g. the j (jump) command asks for the number of the level to which to jump. Usually the parameter has a sensible default value (which is printed in square backets). If just a newline is typed, then the default value is taken. If a valid parameter value is typed, followed by newline, this value is taken. If an illegal letter is typed, the command is aborted.
[eclipse 3]: p. (1) 1 CALL p %> skip (1) 1 FAIL p %> query culprit failure culprit was (3) - rerun and type q to jump there %> nodebug? [y] No (0.00s cpu) [eclipse 4]: p. (1) 1 CALL p %> query culprit failure culprit was (3) - jump to invoc: [3]? (3) 3 CALL r(1) %> creep (3) 3 FAIL r(...) %> creep (2) 2 FAIL q %> creep (1) 1 FAIL p %> creep No (0.01s cpu)
[eclipse 4]: [X, Y] :: 1..9, X #>= Y, Y#>1. (1) 1 CALL [X, Y] :: 1..9 %> var/term spy? [y] Var/term spy set up with invocation number (2) %> jump to invoc: [1]? 2 (2) 3 MODIFY [X{[1..9]}, Y{[2..9]}] :: 1..9 %> jump to invoc: [2]? (2) 4 MODIFY [X{[2..9]}, Y{[2..9]}] :: 1..9 %> jump to invoc: [2]?Note that these monitors can also be set up from within the program code using one of the built-ins spy_var/1 or spy_term/2.
~
exit).
Execution then continues until the specified port appears or,
in the negated case, until a port other than the specified one appears.
The default is the negation of the current port, which is useful
when exiting from a deep recursion (a long sequence of EXIT or FAIL ports).
[eclipse 5]: [X, Y] :: 1..9, X #>= Y, Y #>= X. (1) 1 CALL [X, Y] :: 1..9 %> creep (1) 1 EXIT [X{[1..9]}, Y{[1..9]}] :: 1..9 %> creep (2) 1 CALL X{[1..9]} - Y{[1..9]}#>=0 %> creep (3) 2 DELAY X{[1..9]} - Y{[1..9]}#>=0 %> creep (2) 1 EXIT X{[1..9]} - Y{[1..9]}#>=0 %> creep (4) 1 CALL Y{[1..9]} - X{[1..9]}#>=0 %> creep (5) 2 DELAY Y{[1..9]} - X{[1..9]}#>=0 %> delayed goals with prio: [all]? ------- delayed goals ------- (3) <2> X{[1..9]} - Y{[1..9]}#>=0 (5) <2> Y{[1..9]} - X{[1..9]}#>=0 ------------ end ------------ (5) 2 DELAY Y{[1..9]} - X{[1..9]}#>=0 %>
[eclipse 13]: [X,Y,Z]::1..9, X#>Z, Y#>Z, Z#>1. (1) 1 CALL [X, Y, Z] :: 1..9 %> creep (1) 1 EXIT [X{[1..9]}, Y{[1..9]}, Z{[1..9]}] :: 1..9 %> creep (2) 1 CALL X{[1..9]} - Z{[1..9]}+-1#>=0 %> creep (3) 2 DELAY X{[2..9]} - Z{[1..8]}#>=1 %> creep (2) 1 EXIT X{[2..9]} - Z{[1..8]}+-1#>=0 %> creep (4) 1 CALL Y{[1..9]} - Z{[1..8]}+-1#>=0 %> creep (5) 2 DELAY Y{[2..9]} - Z{[1..8]}#>=1 %> creep (4) 1 EXIT Y{[2..9]} - Z{[1..8]}+-1#>=0 %> creep (6) 1 CALL 0 + Z{[1..8]}+-2#>=0 %> creep (3) 2 RESUME X{[2..9]} - Z{[2..8]}#>=1 %> scheduled goals with prio: [all]? ------ scheduled goals ------ (5) <2> Y{[2..9]} - Z{[2..8]}#>=1 ------------ end ------------ (3) 2 RESUME X{[2..9]} - Z{[2..8]}#>=1 %>
While the debugger waits for commands, program execution is always stopped at some port of some predicate invocation box, or goal. Apart from this current goal, two types of other goals are also active. These are the ancestors of the current goal (the enclosing, not yet exited boxes in the box model) and the delayed goals. The debugger allows to navigate among these goals and inspect them.
This family of commands allow the subterms in the goal displayed at the port to be inspected14.2. The ability to inspect subterms is designed to help overcome two problems when examining a large goal with the normal display of the goal at a debug port:
With inspect subterm commands, the user is able to issue commands to navigate through the subterms of the current goal and examine them. A current subterm of the goal is maintained, and this is printed after each inspect subterm command, instead of the entire goal. Initially, the current subterm is set to the goal, but this can then be moved to the subterms of the goal with navigation commands.
Once inspect subterm is initiated by an inspect subterm command, the debugger enters into the inspect subterm mode. This is indicated in the trace line by 'INSPECT' instead of the name of the port, and in addition, the goal is not shown on the trace line:
INSPECT (length/2) %>
Instead of showing the goal, a summary of the current subterm - generally its functor and arity if the subterm is a structure - is shown in brackets.
The most basic command of inspect subterm is to move the current subterm to
an argument of the existing current subterm. This is done by typing a
number followed by carriage return, or by typing #
, which causes the
debugger to prompt for a number. In both cases, the number specifies the
argument number to move down to.
In the following example, the #
style of the command is used to move
to the first argument, and the number style of the command to move to the
third argument:
(1) 1 CALL foo(a, g(b, [1, 2]), X) %> inspect arg #: 1<NL> a INSPECT (atom) %>
(1) 1 CALL foo(a, g(b, [1, 2]), X) %> 3<NL> X INSPECT (var) %>
The new current subterm is printed, followed by the INSPECT trace line. Notice that the summary shows the type of the current subterm, instead of Name/Arity, since in both cases the subterms are not structures.
If the current subterm itself is a compound term, then it is possible to recursively navigate into the subterm:
(1) 1 CALL foo(a, g(b, [1, 2]), X) %> 2<NL> g(b, [1, 2]) INSPECT (g/2) %> 2<NL> [1, 2] INSPECT (list 1-head 2-tail) %> 2<NL> [2] INSPECT (list 1-head 2-tail) %>
Notice that lists are treated as a structure with arity 2, although the
functor (./2
) is not printed.
In addition to compound terms, it is also possible to navigate into the attributes of attributed variables:
[eclipse 21]: suspend(foo(X), 3, X->inst), foo(X).<NL> (1) 1 DELAY foo(X) %> <NL> creep (2) 1 CALL foo(X) %> 1<NL> X INSPECT (attributes 1-suspend 2-fd ) %>1<NL> suspend(['SUSP-1-susp'|_218] - _218, [], []) INSPECT (struct suspend/3) %>
The variable X is an attributed variable in this case, and when it is the
current subterm, this is indicated in the trace line. The debugger also
shows the user the currently available attributes, and the user can then
select one to navigate into (fd
is available in
this case because the finite domain library was loaded earlier in the
session. Otherwise, it would not be available as a choice here).
Note that the suspend/3
summary contains a struct
before
it. This is because the suspend/3
is a predefined structure with
field names (see section ). It is possible to view the
field names of such structures using the
.
command in inspect mode.
If the number specified is larger than the number of the arguments of the current subterm, then an error is reported and no movement is made:
foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %> 4<NL> Out of range..... foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %>
[nuparrow key ] Move current subterm up by N levels
[nA ] Move current subterm up by N levels
In addition to moving the current subterm down, it can also be moved up
from its current position. This is done by typing the uparrow key. This key
is mapped to A
by the debugger, so one can also type
A
. Typing A
may be necessary for some configurations
(combination of keyboards and operating systems) because the uparrow key is
not correctly mapped to A
.
An optional argument can preceded the uparrow keystroke, which indicates the number of levels to move up. The default is 1:
(1) 1 CALL foo(a, g(b, [1, 2]), 3) %> 2<NL> g(b, [1, 2]) INSPECT (g/2) %> 1<NL> b INSPECT (atom) %> up subterm g(b, [1, 2]) INSPECT (g/2) %> 1up subterm foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %>
The debugger prints up subterm
when the uparrow key is typed. The
current subterm moves back up the structure to its parent for each level it
moves up, and the above move can be done directly by specifying 2 as the
levels to move up:
b INSPECT (atom) %> 2up subterm foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %>
If the number of levels specified is more than the number of levels that can be traversed up, the current subterm stops at the toplevel:
(1) 1 CALL foo(a, g(b, [1, 2]), 3) %> 2<NL> g(b, [1, 2]) INSPECT (g/2) %> 2<NL> [1, 2] INSPECT (list 1-head 2-tail) %> 5up subterm foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %>
[0 ] Move current subterm to toplevel
It is possible to quickly move back to the top of a goal that is being inspected by specifying 0 (zero) as the command:
(1) 1 CALL foo(a, g(b, [1, 2]), 3) %> 2<NL> g(b, [1, 2]) INSPECT (g/2) %> 2<NL> [1, 2] INSPECT (list 1-head 2-tail) %> 2<NL> [2] INSPECT (list 1-head 2-tail) %> 2<NL> [] INSPECT (atom) %> 0<NL> foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %>
Moving to the top can also be done by the #
command, and not giving
any argument (or 0
) when prompted for the argument.
[nleftarrow key ] Move current subterm left by N positions
[nD ] Move current subterm left by N positions
The leftarrow key (or the equivalent D
) moves the current subterm to
a sibling subterm (i.e. fellow argument of the parent structure) that is to
the left of it. Consider the structure foo(a, g(b, [1, 2]), 3)
, then
for the second argument, g(b, [1, 2])
, a
is its (only) left
sibling, and 3
its (only) right sibling. For the third argument,
3
, both a
(distance of 2) and
g(b, [1, 2])
(distance of 1) are its left siblings. The optional
numeric argument for the command specifies the distance to the left that
the current subterm should be moved. It defaults to 1.
foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %> 3<NL> 3 INSPECT (integer) %> 2left subterm a INSPECT (atom) %>
If the leftward movement specified would move the argument position before the first argument of the parent term, then the movement will stop at the first argument:
foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %> 3<NL> 3 INSPECT (integer) %> 5left subterm a INSPECT (atom) %>
In the above example, the current subterm was at the third argument, thus trying to move left by 5 argument positions is not possible, and the current subterm stopped at leftmost position - the first argument.
[nrightarrow key ] Move current subterm right by N positions
[nC ] Move current subterm right by N positions
The rightarrow key (or the equivalent C
) moves the current subterm
to a sibling subterm (i.e. fellow argument of the parent structure) that is
to the right of it. Consider the structure foo(a, g(b, [1, 2]), 3)
,
then for the first argument, a
, g(b, [1, 2])
is a right
sibling with distance of 1, and 3
is a right sibling with distance
of 2. The optional numeric argument for the command specifies the distance
to the left that the current subterm should be moved. It defaults to 1.
foo(a, g(b, [1, 2]), 3) INSPECT (integer) %> 2left subterm a INSPECT (atom) %>
If the rightward movement specified would move the argument position beyond the last argument of the parent term, then the movement will stop at the last argument:
foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %> 3<NL> 3 INSPECT (integer) %> right subterm 3 INSPECT (integer) %>
In the above example, the current subterm was at the third (and last) argument, thus trying to move to the right (by the default 1 position in this case) is not possible, and the current subterm remains at the third argument.
[ndownarrow key ] Move current subterm down by N levels
[nB ] Move current subterm down by N levels
The down-arrow key moves the current subterm down from its current position. This command is only valid if the current subterm is a compound term and so has subterms itself. A structure has in general more than one argument, so there is a choice of which argument position to move down to. This argument is not directly specified by the user as part of the command, but is implicitly specified: the argument position selected is the argument position of the current subterm within its parent:
foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %> 2<NL> g(b, [1, 2]) INSPECT (list 1-head 2-tail) %> 3down subterm 2 for 3 levels [] INSPECT (atom) %>
In the above example, the user moves down into the second argument, and then use the down-arrow key to move down into the second argument for 2 levels - the numeric argument typed before the arrow key specified the number of levels that the current subterm was moved down by. The command moves into the second argument because it was at the second argument position when the command was issue.
However, there is not always an argument position for the current sub-term. For example, when the current sub-term is at the toplevel of the goal or if it is at an attribute. In these cases, the default for the argument position to move down into is the first argument:
INSPECT (atom) %> 0<NL> foo(a, g(b, [1, 2]), 3) INSPECT (foo/3) %> down subterm 1 for 1 levels a INSPECT (atom) %>
In the above example, the down-arrow key is typed at the top-level, and thus the argument position chosen for moving down is first argument, with the default numeric argument for the
If the argument position to move into is beyond the range of the current subterm's number of arguments, then no move is performed:
(1) 1 CALL foo(a, b, c(d, e)) %> 3<NL> c(d, e) INSPECT (c/2) %> Out of range after traversing down arg... c(d, e) INSPECT (c/2) %>In this case, the down-arrow key was typed in the second trace line, which had the current subterm at the third argument of its parent term, and thus the command tries to move the new current subterm to the third argument of the current sub-term, but the structure does not have a third argument and so no move was made. In the case of moving down multiple levels, then the movement will stop as soon as the argument position to move down to goes out of range.
Moving down is particularly useful for traversing lists. As discussed, lists are really structures with arity two, so the #N command would not move to the Nth element of the list. With the down-arrow command , it is possible to move into the Nth position in one command:
[eclipse 30]: foo([1,2,3,4,5,6,7,8,9]). (1) 1 CALL foo([1, 2, 3, ...]) %> 1<NL> [1, 2, 3, 4, ...] INSPECT (list 1-head 2-tail) %> 2<NL> [2, 3, 4, 5, ...] INSPECT (list 1-head 2-tail) %> 6down subterm 2 for 6 levels [8, 9] INSPECT (list 1-head 2-tail) %>
In order to move down a list, we repeatedly move into the tail of the list - the second argument position. In order to do this with the down-arrow command, we need to be at the second argument position first, and this is done in the second trace line. Once this is done, then it is possible to move arbitrarily far down the list in one go, as is shown in the example.
[. ] Print structure definition
In ECLiPSe, it is possible to define field names for structures (see
section 5.1). If the inspector encounters such structures,
then the user can get the debugger to print out the field names. Note that
this functionality only applies within the inspect subterm mode, as the
debugger command `.
' normally prints the source for the predicate.
The fact that a structure has defined field names are indicated by a
``struct'' in the summary:
:- local struct(capital(city,country)). ..... (1) 1 CALL f(capital(london, C)) %> 1<NL> capital(london, C) INSPECT (struct capital/2) %> structure definition: 1=city 2=country %>
In this example, a structure definition was made for captial/2
. When
this structure is the current subterm in the inspect mode, the
struct
in the summary for the structure indicates that it has
a structure definition. For such structures, the field names are printed by
the structure definition command.
If the command is issued for a term that does not have a structure definition, an error would be reported:
INSPECT (f/1) %> structure definition: No struct definition for term f/1@eclipse. %>
As the user navigates into a term, then at each level, a particular
argument position (or attribute, in the case of attributed variables) is
selected at each level. The user can view the position the current subterm
is at by the p
command. For example,
(1) 1 CALL foo(a, g(b, [1, 2]), 3) %> 2<NL> g(b, [1, 2]) INSPECT (g/2) %> 2<NL> [1, 2] INSPECT (list 1-head 2-tail) %> 1<NL> 1 INSPECT (integer) %> p Subterm path: 2, 2, 1 %>
The subterm path shows the argument positions taken at each level of the toplevel term to reach the current subterm, starting from the top.
Extra information (in addition to the numeric argument position) will be printed if the subterm at a particular level is either a structure with field names or an attributed variable. For example:
:- local struct(capital(city,country)). ..... [eclipse 8]: suspend(capital(london, C), 3, C -> inst), f(capital(london, C)). .... (2) 1 CALL f(capital(london, C)) %> 1<NL> capital(london, C) INSPECT (struct capital/2) %> 2<NL> C INSPECT (attributes 1-suspend ) %> 1<NL> suspend(['SUSP-1-susp'|_244] - _244, [], []) INSPECT (struct suspend/3) %> 1<NL> ['SUSP-1-susp'|_244] - _244 INSPECT (-/2) %> Subterm path: 1, country of capital (2), attr: suspend, inst of suspend (1) %>
In this example, except for the toplevel argument, all the other positions are
either have field names or are attributes. This is reflected in the path,
for example, country of capital (2) shows that the field name for
the selected argument position (2, shown in brackets) is country
,
and the structure name is capital
. For the `position' of the
selected attribute (suspend
) of the attributed variable C
,
the path position is shown as attr: suspend.
The debugger commands that affect the print formats in the debugger also affects the printed current subterm. Thus, both the print depth and output mode of the printed subterm can be changed.
The changing of the output modes can have a significant impact on the inspect mode. This is because for terms which are transformed by write macros before they are printed (see chapter 12), different terms can be printed depending on the settings of the output modes. In particular, output transformation is used to hide many of the implementation related extra fields and even term names of many ECLiPSe data structures (such as those used in the finite domain library). For the purposes of inspect subterms, the term that is inspected is always the printed form of the term, and thus changing the output mode can change the term that is being inspected.
Consider the example of looking at the attribute of a finite domain variable:
A{[4..10000000]} INSPECT (attributes 1-suspend 2-fd ) %> 2<NL> [4..10000000] INSPECT (list 1-head 2-tail) %> 1<NL> 4..10000000 INSPECT (../2) %> 2up subterm A{[4..10000000]} INSPECT (attributes 1-suspend 2-fd ) %> <o> current output mode is "QPm", toggle char: T new output mode is "TQPm". A{[4..10000000]} INSPECT (attributes 1-suspend 2-fd ) %> 2<NL> fd(dom([4..10000000], 9999997), [], [], []) INSPECT (struct fd/4) %> 1<NL> dom([4..10000000], 9999997) INSPECT (dom/2) %>
After selecting the output mode T
, which turns off any output
macros, the internal form of the attribute is shown. This allows previously
hidden fields of the attribute to be examined by the subterm navigation.
Note that if the current subterm is inside a structure which will be
changed by a changed output mode (such as inside the fd attribute), and the
output mode is changed, then until the current subterm is moved out of the
structure, the existing subterm path is still applicable.
Also, after a change in output modes, the current subterm will still be examining the structure that it obtained from the parent subterm. Consider the finite domain variable example again:
4..10000000 INSPECT (../2) %> up subterm [4..10000000] ***** printed structure 1 INSPECT (list 1-head 2-tail) %> <o> current output mode is "QPm", toggle char: T new output mode is "TQPm". [4..10000000] INSPECT (list 1-head 2-tail) %> up subterm A{[4..10000000]} INSPECT (attributes 1-suspend 2-fd ) %> 2 fd(dom([4..10000000], 9999997), [], [], []) INSPECT (struct fd/4) %> <o> current output mode is "QPmT", toggle char: T new output mode is "QPm". fd(4..10000000, [], [], []) ***** printed structure 2 INSPECT (struct fd/4) %>
Printed structures 1 and 2 in the above example are at the same position
(toplevel of the finite domain structure), and printed with the same output
mode (QPm
), but are different because the structure obtained from
the parent subterm is different - in printed structure 2, the output mode
was not changed until after the fd/4
structure was the current
subterm.
...
.
Note that the debugger has a private print_depth setting with
default 5, which is different from the global setting obtained from
get_flag/2.
(1) 1 CALL true %> show module (1) 1 CALL eclipse : true %>
(1) 1 CALL X is length([1, 2, ...]) %> current output mode is "QPm", toggle char: V new output mode is "VQPm". (1) 1 CALL X_72 is length([1, 2, ...]) %> current output mode is "QVPm", toggle char: O new output mode is "OQVPm". (1) 1 CALL is(X_72, length([1, 2, ...])) %> current output mode is "OQVPm", toggle char: . new output mode is ".OQVPm". (1) 1 CALL is(X_72, length(.(1, .(2, .(...))))) %>
Note that the debugger does not check for spy points that occur inside skipped procedures or during the execution of any other skip command than the leap command l.
^
D, or end_of_file
the execution returns to the debugger and the last trace line is redisplayed.