[m-rev.] for review: new mdb commands "hold" and "diff"

Zoltan Somogyi zs at cs.mu.OZ.AU
Mon Jul 11 13:23:04 AEST 2005


For review by anyone. The diff to the expected output files for debug grades
aren't final yet.

Zoltan.

Add two new capabilities to the debugger.

The first capability is the idea of "held variables", variables that the
debugger holds onto even when execution has left the event they came from.
You can hold onto a variable via the mdb command "hold varname heldvarname".
You can suffix the name of the existing variable with a term path, in which
case the new held variable will refer only to the specified part of the term.
Later mdb commands can refer to the held variable by prefixing its name with
a dollar sign. For example, after "hold HeadVar__1^2 x", "$x" will refer to
the term that was the second argument of HeadVar__1 at the program point
at which the "hold" command was executed.

The second capability is the ability to compute the diff of two terms and
express those diffs as the term paths of the function symbols at which the two
terms differ, instead of the line numbers you get by using save_to_file and the
usual Unix diff command. The mdb command is "diff var1 var2". We limit the
number of term paths of difference sites that we display at any one time;
the mdb diff command has options to control this.

doc/user_guide.texi:
	Document the new mdb commands "hold" and "diff", the new mdb command
	"held_vars" which simply lists the names of all the held variables
	(just as "vars" lists the names of all the nonheld variables currently
	accessible), and the concept of held variables.

doc/mdb_categories:
	Update this file for the new mdb commands and concepts.

browser/browse_diff.m:
	This new module implements the diff operation on terms.

browser/mdb.m:
	Add the new module to the list of submodules of the mdb package.

browser/*.m:
	Minor cleanups, such as importing only one module per line; there
	are no algorithmic changes.o

trace/mercury_trace_hold_vars.[ch]:
	This new module implements the database of held variables.

trace/Mmakefile:
	Mention the new module.

trace/mercury_trace_internal.c:
	Implement the three new mdb commands.

trace/mercury_trace_vars.[ch]:
	Modify the functions that recognize variable specifications or
	process them to work with held variables as well as variables from
	the current environment. This required some reorganization of the
	internals of this module.

	Provide some a utility function, MR_trace_parse_lookup_var_path,
	for converting a string representing the specification of a term
	(a variable and possibly some path within it) to the type and value
	of that term. Make the utility function this is based upon,
	MR_lookup_unambiguous_var_spec, replace the previous but less capable
	MR_convert_var_spec_to_type_value.

trace/mercury_trace_spy.c:
	Conform to the change in mercury_trace_vars.c.

trace/mercury_trace_util.c:
	Make a utility function more robust.

trace/mercury_trace_alias.c:
	Minor cleanups.

tests/debugger/queens.{inp,exp*}:
	Update this test case to test the debugger's new capabilities.

tests/debugger/completion.{inp,exp*}:
	Update this test case to expect the new mdb commands, and avoid the 
	ambiguity between "help" and "held_vars".

cvs diff: Diffing .
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing browser
Index: browser/browse.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/browse.m,v
retrieving revision 1.51
diff -u -b -r1.51 browse.m
--- browser/browse.m	22 Feb 2005 22:27:48 -0000	1.51
+++ browser/browse.m	10 Jul 2005 02:11:12 -0000
@@ -23,7 +23,9 @@
 :- import_module mdb.browser_info.
 :- import_module mdb.browser_term.
 
-:- import_module io, std_util, list.
+:- import_module io.
+:- import_module list.
+:- import_module std_util.
 
 	% The interactive term browser.  The caller type will be `browse', and
 	% the default format for the `browse' caller type will be used.  Since
@@ -149,8 +151,18 @@
 :- import_module mdb__frame.
 :- import_module mdb__sized_pretty.
 
-:- import_module bool, string, int, char, map, std_util, term_to_xml.
-:- import_module parser, require, pprint, getopt, deconstruct.
+:- import_module bool.
+:- import_module char.
+:- import_module deconstruct.
+:- import_module getopt.
+:- import_module int.
+:- import_module map.
+:- import_module parser.
+:- import_module pprint.
+:- import_module require.
+:- import_module std_util.
+:- import_module string.
+:- import_module term_to_xml.
 
 %---------------------------------------------------------------------------%
 %
Index: browser/browse_test.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/browse_test.m,v
retrieving revision 1.5
diff -u -b -r1.5 browse_test.m
--- browser/browse_test.m	24 Jan 2005 07:41:02 -0000	1.5
+++ browser/browse_test.m	10 Jul 2005 02:10:16 -0000
@@ -23,7 +23,12 @@
 :- import_module mdb__browse.
 :- import_module mdb__browser_info.
 
-:- import_module list, string, int, std_util, tree234, assoc_list.
+:- import_module assoc_list.
+:- import_module int.
+:- import_module list.
+:- import_module std_util.
+:- import_module string.
+:- import_module tree234.
 
 main -->
 	{ Filename = "/etc/fstab" },
Index: browser/browser_info.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/browser_info.m,v
retrieving revision 1.19
diff -u -b -r1.19 browser_info.m
--- browser/browser_info.m	22 Feb 2005 22:27:48 -0000	1.19
+++ browser/browser_info.m	10 Jul 2005 02:11:00 -0000
@@ -18,7 +18,11 @@
 :- import_module mdb.parse.
 :- import_module mdbcomp.program_representation.
 
-:- import_module bool, list, std_util, io, getopt.
+:- import_module bool.
+:- import_module getopt.
+:- import_module io.
+:- import_module list.
+:- import_module std_util.
 
 	% The non-persistent browser information.  A new one of these is
 	% created every time the browser is called, based on the contents
@@ -224,7 +228,10 @@
 %---------------------------------------------------------------------------%
 
 :- implementation.
-:- import_module deconstruct, require, io.
+
+:- import_module deconstruct.
+:- import_module io.
+:- import_module require.
 
 :- pragma export(browser_info__init_persistent_state(out),
 		"ML_BROWSE_init_persistent_state").
Index: browser/browser_term.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/browser_term.m,v
retrieving revision 1.2
diff -u -b -r1.2 browser_term.m
--- browser/browser_term.m	24 Jan 2005 07:41:03 -0000	1.2
+++ browser/browser_term.m	10 Jul 2005 02:11:42 -0000
@@ -11,7 +11,9 @@
 
 :- interface.
 
-:- import_module bool, std_util, list.
+:- import_module bool.
+:- import_module list.
+:- import_module std_util.
 
 :- type browser_term
 	--->	plain_term(
Index: browser/collect_lib.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/collect_lib.m,v
retrieving revision 1.10
diff -u -b -r1.10 collect_lib.m
--- browser/collect_lib.m	24 Jan 2005 07:41:03 -0000	1.10
+++ browser/collect_lib.m	10 Jul 2005 02:12:09 -0000
@@ -60,10 +60,17 @@
 :- pred dummy_pred_to_avoid_warning_about_nothing_exported is det.
 
 %------------------------------------------------------------------------------%
+
 :- implementation.
-:- import_module int, list, std_util, io, char.
+
 :- import_module mdb__dl.
 
+:- import_module char.
+:- import_module int.
+:- import_module io.
+:- import_module list.
+:- import_module std_util.
+
 dummy_pred_to_avoid_warning_about_nothing_exported.
 
 :- pragma export(link_collect(in, out, out, out, out, out, out, out, di, uo),
Index: browser/cterm.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/cterm.m,v
retrieving revision 1.1
diff -u -b -r1.1 cterm.m
--- browser/cterm.m	1 Feb 2005 03:24:21 -0000	1.1
+++ browser/cterm.m	10 Jul 2005 02:12:25 -0000
@@ -34,8 +34,8 @@
 
 :- implementation.
 
-:- import_module list.
 :- import_module deconstruct.
+:- import_module list.
 :- import_module std_util.
 
 :- pragma foreign_decl(c, "
Index: browser/debugger_interface.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/debugger_interface.m,v
retrieving revision 1.22
diff -u -b -r1.22 debugger_interface.m
--- browser/debugger_interface.m	24 Jan 2005 07:41:03 -0000	1.22
+++ browser/debugger_interface.m	10 Jul 2005 02:13:41 -0000
@@ -35,8 +35,11 @@
 :- import_module mdb.util.
 :- import_module mdbcomp.prim_data.
 
-:- import_module list, bool, std_util.
-:- import_module io, require.
+:- import_module bool.
+:- import_module io.
+:- import_module list.
+:- import_module require.
+:- import_module std_util.
 
 dummy_pred_to_avoid_warning_about_nothing_exported.
 
@@ -48,7 +51,6 @@
 	% encoded as specified in ../runtime/mercury_stack_layout.h
 	% and ../compiler/stack_layout.m.
 
-
 % Depending whether the Opium side is requesting for a user defined procedure
 % or a compiler generated one, the event has not exactly the same structure.
 % The differences between the two types of event are gathered in a forward_move
@@ -163,7 +165,6 @@
 :- type call_number == int.
 :- type depth_number == int.
 
-
 % `match' is called "get status" in the Opium documentation.
 % This type defines a unary predicate which determines whether
 % or not a particular value will be selected.
@@ -175,7 +176,6 @@
 	;	interval(T,T)	% interval(Low, High): Low =< X, X =< High
 	.
 
-
 % The debugger_response type is used for response sent
 % to the debugger process from the Mercury program being debugged.
 :- type debugger_response
@@ -239,7 +239,8 @@
 	% The protocol between the debugger and the debuggee is described is
 	% trace/mercury_trace_external.c.
 	;	level(int)				% stack level
-	;	proc(string, string, string, int, int)	% compiler generated proc
+	;	proc(string, string, string, int, int)	% compiler generated
+							% proc
 	;	proc(string, string, int, int)		% user generated proc
 	;	def_module(string)
 	;	detail(int, int, int)
@@ -272,7 +273,6 @@
 	;	collect_arg_off_ok
 	.
 
-
 %-----------------------------------------------------------------------------%
 %	send to the debugger (e.g. Opium) the wanted features.
 
@@ -291,7 +291,6 @@
 :- mode output_current_slots_user(in, in, in, in, in, in, in, in, in, in, 
 	in, in, in, in, di, uo) is det.
 
-
 output_current_slots_user(EventNumber, CallNumber, DepthNumber, Port, 
 	PredOrFunc, DeclModuleName, DefModuleName, PredName, Arity, ModeNum, 
 	Determinism, Path, LineNo, OutputStream) -->
@@ -318,7 +317,6 @@
 :- mode output_current_slots_comp(in, in, in, in, in, in, in, in, in, in, 
 	in, in, in, in, di, uo) is det.
 
-
 output_current_slots_comp(EventNumber, CallNumber, DepthNumber, Port, 
 	NameType, ModuleType, DefModuleName, PredName, Arity, 
 	ModeNum, Determinism, Path, LineNo, OutputStream) -->
@@ -341,7 +339,6 @@
 	io__output_stream, io__state, io__state).
 :- mode output_current_vars(in, in, in, di, uo) is det.
 
-
 output_current_vars(VarList, StringList, OutputStream) -->
 		
 	{ CurrentTraceInfo = current_vars(VarList, StringList) },
@@ -358,7 +355,6 @@
 :- pred output_current_nth_var(univ, io__output_stream, io__state, io__state).
 :- mode output_current_nth_var(in, in, di, uo) is det.
 
-
 output_current_nth_var(Var, OutputStream) -->
 		
 	{ CurrentTraceInfo = current_nth_var(Var) },
@@ -366,7 +362,6 @@
 	io__print(OutputStream, ".\n"),
 	io__flush_output(OutputStream).
 
-
 :- pragma export(output_current_live_var_names(in, in, in, di, uo), 
 	"ML_DI_output_current_live_var_names").
 			
@@ -374,7 +369,6 @@
 	io__output_stream, io__state, io__state).
 :- mode output_current_live_var_names(in, in, in, di, uo) is det.
 
-
 output_current_live_var_names(LiveVarNameList, LiveVarTypeList, 
 	OutputStream) -->
 		
@@ -452,7 +446,6 @@
 		error("found_match: forward_move expected")
 	).
 
-
 % match(MatchPattern, Value) is true iff Value matches the specified pattern.
 :- pred match(match(T), T).
 :- mode match(in, in) is semidet.
@@ -468,7 +461,6 @@
 	compare(GE, X, Low), 
 	(GE = (>) ; GE = (=)).
 
-
 :- pragma export(found_match_comp(in, in, in, in, in, in, in, in, in, in, in,
 			in, in, in), "ML_DI_found_match_comp").
 			
@@ -518,7 +510,6 @@
 		error("found_match: forward_move expected")
 	).
 
-
 %-----------------------------------------------------------------------------%
 
 :- pred read_request_from_socket(io__input_stream, debugger_request, int,
@@ -550,7 +541,6 @@
 	io__print(StdErr, ".\n").
 	***********/
 
-
 %-----------------------------------------------------------------------------%
 
 :- pred get_list_modules_to_import(debugger_request, int, imports).
@@ -667,6 +657,5 @@
 classify_request(current_grade,20).
 classify_request(collect_arg_on,21).
 classify_request(collect_arg_off,22).
-
 
 %-----------------------------------------------------------------------------%
Index: browser/declarative_analyser.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/declarative_analyser.m,v
retrieving revision 1.26
diff -u -b -r1.26 declarative_analyser.m
--- browser/declarative_analyser.m	19 Jun 2005 02:14:16 -0000	1.26
+++ browser/declarative_analyser.m	10 Jul 2005 02:14:26 -0000
@@ -3,6 +3,7 @@
 % This file may only be copied under the terms of the GNU Library General
 % Public License - see the file COPYING.LIB in the Mercury distribution.
 %-----------------------------------------------------------------------------%
+%
 % File: declarative_analyser.m
 % Authors: Mark Brown, Ian MacLarty
 %
@@ -12,7 +13,6 @@
 % EDT, storing information relevant to the bug search.  Throughout this module
 % the type variables T and S refer to the types of nodes in the EDT and the
 % store of EDT nodes respectively.
-%
 
 :- module mdb.declarative_analyser.
 
@@ -22,7 +22,8 @@
 :- import_module mdb.declarative_edt.
 :- import_module mdb.declarative_oracle.
 
-:- import_module std_util, io.
+:- import_module io.
+:- import_module std_util.
 
 :- type analyser_response(T)
 
@@ -127,8 +128,16 @@
 :- import_module mdbcomp.prim_data.
 :- import_module mdbcomp.program_representation.
 
-:- import_module bool, exception, counter, array, list, float.
-:- import_module math, string, map, int. 
+:- import_module array.
+:- import_module bool.
+:- import_module counter.
+:- import_module exception.
+:- import_module float.
+:- import_module int. 
+:- import_module list.
+:- import_module map.
+:- import_module math.
+:- import_module string.
 
 	% Describes what search strategy is being used by the analyser and the
 	% state of the search.
Index: browser/declarative_debugger.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/declarative_debugger.m,v
retrieving revision 1.59
diff -u -b -r1.59 declarative_debugger.m
--- browser/declarative_debugger.m	19 Jun 2005 02:14:16 -0000	1.59
+++ browser/declarative_debugger.m	10 Jul 2005 09:25:23 -0000
@@ -3,6 +3,7 @@
 % This file may only be copied under the terms of the GNU Library General
 % Public License - see the file COPYING.LIB in the Mercury distribution.
 %-----------------------------------------------------------------------------%
+%
 % File: declarative_debugger.m
 % Author: Mark Brown
 %
@@ -66,7 +67,10 @@
 :- import_module mdb.term_rep.
 :- import_module mdbcomp.program_representation.
 
-:- import_module io, list, std_util, string.
+:- import_module io.
+:- import_module list.
+:- import_module std_util.
+:- import_module string.
 
 	% This type represents the possible truth values for nodes
 	% in the EDT.
Index: browser/declarative_edt.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/declarative_edt.m,v
retrieving revision 1.11
diff -u -b -r1.11 declarative_edt.m
--- browser/declarative_edt.m	19 Jun 2005 02:14:16 -0000	1.11
+++ browser/declarative_edt.m	10 Jul 2005 02:15:23 -0000
@@ -63,7 +63,9 @@
 :- import_module mdbcomp.prim_data.
 :- import_module mdbcomp.program_representation.
 
-:- import_module bool, list, std_util.
+:- import_module bool.
+:- import_module list.
+:- import_module std_util.
 
 	% This typeclass defines how EDTs may be accessed by this module.
 	% An EDT is a tree of nodes, each of which contains a question
@@ -512,8 +514,14 @@
 
 :- implementation.
 
-:- import_module exception, map, int, counter, std_util, string, bimap.
+:- import_module bimap.
+:- import_module counter.
+:- import_module exception.
 :- import_module float.
+:- import_module int.
+:- import_module map.
+:- import_module std_util.
+:- import_module string.
 
 	% A suspect is an edt node with some additional information relevant
 	% to the bug search.
Index: browser/declarative_test.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/declarative_test.m,v
retrieving revision 1.6
diff -u -b -r1.6 declarative_test.m
--- browser/declarative_test.m	28 Jan 2005 00:56:06 -0000	1.6
+++ browser/declarative_test.m	10 Jul 2005 02:15:57 -0000
@@ -23,7 +23,10 @@
 :- import_module mdb.declarative_debugger.
 :- import_module mdb.declarative_execution.
 
-:- import_module list, std_util, map, require.
+:- import_module list.
+:- import_module map.
+:- import_module require.
+:- import_module std_util.
 
 main(!IO) :-
 	process_arguments(MaybeFile, !IO),
Index: browser/declarative_tree.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/declarative_tree.m,v
retrieving revision 1.29
diff -u -b -r1.29 declarative_tree.m
--- browser/declarative_tree.m	8 Jul 2005 16:45:19 -0000	1.29
+++ browser/declarative_tree.m	11 Jul 2005 02:58:07 -0000
@@ -53,8 +53,15 @@
 :- import_module mdbcomp.prim_data.
 :- import_module mdbcomp.program_representation.
 
-:- import_module assoc_list, bool, exception, int, list, map, std_util, string.
+:- import_module assoc_list.
+:- import_module bool.
+:- import_module exception.
+:- import_module int.
 :- import_module io.
+:- import_module list.
+:- import_module map.
+:- import_module std_util.
+:- import_module string.
 
 :- instance mercury_edt(wrap(S), edt_node(R)) <= annotated_trace(S, R)
 	where [
Index: browser/diff.m
===================================================================
RCS file: browser/diff.m
diff -N browser/diff.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/diff.m	11 Jul 2005 03:09:29 -0000
@@ -0,0 +1,129 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+% Copyright (C) 2005 The University of Melbourne.
+% This file may only be copied under the terms of the GNU Library General
+% Public License - see the file COPYING.LIB in the Mercury distribution.
+%---------------------------------------------------------------------------%
+
+% This module computes diffs between terms.
+
+:- module mdb.diff.
+
+:- interface.
+
+:- import_module int.
+:- import_module io.
+:- import_module std_util.
+
+:- pred report_diffs(int::in, int::in, univ::in, univ::in, io::di, io::uo)
+    is cc_multi.
+
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module mdbcomp.program_representation.
+
+:- import_module deconstruct.
+:- import_module list.
+:- import_module require.
+:- import_module string.
+:- import_module type_desc.
+
+:- pragma export(report_diffs(in, in, in, in, di, uo), "ML_report_diffs").
+
+report_diffs(Drop, Max, Univ1, Univ2, !IO) :-
+    (
+        Type1 = univ_type(Univ1),
+        Type2 = univ_type(Univ2),
+        Type1 = Type2
+    ->
+        compute_diffs(Univ1, Univ2, [], [], RevDiffs),
+        list__reverse(RevDiffs, AllDiffs),
+        list__length(AllDiffs, NumAllDiffs),
+        (
+            list__drop(Drop, AllDiffs, Diffs),
+            Diffs = [_ | _]
+        ->
+            FirstShown = Drop + 1,
+            LastShown = min(Drop + Max, NumAllDiffs),
+            ( FirstShown = LastShown ->
+                io__format("There are %d diffs, showing diff %d:\n",
+                    [i(NumAllDiffs), i(FirstShown)], !IO)
+            ;
+                io__format("There are %d diffs, showing diffs %d-%d:\n",
+                    [i(NumAllDiffs), i(FirstShown), i(LastShown)], !IO)
+            ),
+            list__take_upto(Max, Diffs, ShowDiffs),
+            list__foldl2(show_diff, ShowDiffs, Drop, _, !IO)
+        ;
+            ( NumAllDiffs = 0 ->
+                io__write_string("There are no diffs.\n", !IO)
+            ; NumAllDiffs = 1 ->
+                io__write_string("There is only one diff.\n", !IO)
+            ;
+                io__format("There are only %d diffs.\n", [i(NumAllDiffs)], !IO)
+            )
+        )
+    ;
+        io__write_string("The two values are of different types.\n", !IO)
+    ).
+
+:- type term_path_diff
+    --->    term_path_diff(term_path, univ, univ).
+
+:- pred compute_diffs(univ::in, univ::in, term_path::in,
+    list(term_path_diff)::in, list(term_path_diff)::out) is cc_multi.
+
+compute_diffs(Univ1, Univ2, !.RevPath, !RevDiffs) :-
+    deconstruct(univ_value(Univ1), include_details_cc, Functor1, _, Args1),
+    deconstruct(univ_value(Univ2), include_details_cc, Functor2, _, Args2),
+    ( Functor1 = Functor2 ->
+        compute_arg_diffs(Args1, Args2, !.RevPath, 1, !RevDiffs)
+    ;
+        list__reverse(!.RevPath, Path),
+        !:RevDiffs = [term_path_diff(Path, Univ1, Univ2) | !.RevDiffs]
+    ).
+
+:- pred compute_arg_diffs(list(univ)::in, list(univ)::in, term_path::in,
+    int::in, list(term_path_diff)::in, list(term_path_diff)::out) is cc_multi.
+
+compute_arg_diffs([], [], _, _, !RevDiffs).
+compute_arg_diffs([], [_ | _], _, _, !RevDiffs) :-
+    error("compute_arg_diffs: argument list mismatch").
+compute_arg_diffs([_ | _], [], _, _, !RevDiffs) :-
+    error("compute_arg_diffs: argument list mismatch").
+compute_arg_diffs([Arg1 | Args1], [Arg2 | Args2], !.RevPath, ArgNum,
+        !RevDiffs) :-
+    compute_diffs(Arg1, Arg2, [ArgNum | !.RevPath], !RevDiffs),
+    compute_arg_diffs(Args1, Args2, !.RevPath, ArgNum + 1, !RevDiffs).
+
+:- pred show_diff(term_path_diff::in, int::in, int::out, io::di, io::uo)
+    is cc_multi.
+
+show_diff(Diff, !DiffNum, !IO) :-
+    !:DiffNum = !.DiffNum + 1,
+    io__format("%d: ", [i(!.DiffNum)], !IO),
+    Diff = term_path_diff(Path, Univ1, Univ2),
+    (
+        Path = [],
+        io__write_string("mismatch at root", !IO)
+    ;
+        Path = [Posn | Posns],
+        io__write_int(Posn, !IO),
+        show_path_rest(Posns, !IO)
+    ),
+    io__write_string(": ", !IO),
+    functor(univ_value(Univ1), include_details_cc, Functor1, Arity1),
+    functor(univ_value(Univ2), include_details_cc, Functor2, Arity2),
+    io__format("%s/%d vs %s/%d\n",
+        [s(Functor1), i(Arity1), s(Functor2), i(Arity2)], !IO).
+
+:- pred show_path_rest(list(int)::in, io::di, io::uo) is det.
+
+show_path_rest([], !IO).
+show_path_rest([Posn | Posns], !IO) :-
+    io__write_string("/", !IO),
+    io__write_int(Posn, !IO),
+    show_path_rest(Posns, !IO).
Index: browser/dl.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/dl.m,v
retrieving revision 1.24
diff -u -b -r1.24 dl.m
--- browser/dl.m	24 Jan 2005 07:41:04 -0000	1.24
+++ browser/dl.m	10 Jul 2005 02:16:49 -0000
@@ -82,7 +82,11 @@
 
 :- implementation.
 
-:- import_module std_util, require, string, list, int.
+:- import_module int.
+:- import_module list.
+:- import_module require.
+:- import_module std_util.
+:- import_module string.
 
 :- pragma foreign_decl("C", "
 	#include <stdio.h>
Index: browser/frame.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/frame.m,v
retrieving revision 1.7
diff -u -b -r1.7 frame.m
--- browser/frame.m	24 Jan 2005 07:41:04 -0000	1.7
+++ browser/frame.m	10 Jul 2005 02:17:06 -0000
@@ -19,7 +19,8 @@
 
 :- interface.
 
-:- import_module list, std_util.
+:- import_module list.
+:- import_module std_util.
 
 	% XXX: Make frame type abstract instead?
 % :- type frame.
@@ -57,7 +58,12 @@
 :- implementation.
 
 :- import_module mdb.util.
-:- import_module string, list, int, io, require.
+
+:- import_module int.
+:- import_module io.
+:- import_module list.
+:- import_module require.
+:- import_module string.
 
 frame__from_string(Str, [Str]).
 
Index: browser/help.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/help.m,v
retrieving revision 1.6
diff -u -b -r1.6 help.m
--- browser/help.m	24 Jan 2005 07:41:04 -0000	1.6
+++ browser/help.m	10 Jul 2005 02:17:28 -0000
@@ -23,7 +23,9 @@
 
 :- interface.
 
-:- import_module list, io, std_util.
+:- import_module io.
+:- import_module list.
+:- import_module std_util.
 
 :- type help__system.
 
@@ -70,7 +72,9 @@
 
 :- implementation.
 
-:- import_module int, string, require.
+:- import_module int.
+:- import_module require.
+:- import_module string.
 
 :- type help__system	==	list(help__entry).
 
Index: browser/interactive_query.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/interactive_query.m,v
retrieving revision 1.24
diff -u -b -r1.24 interactive_query.m
--- browser/interactive_query.m	24 Jan 2005 07:41:04 -0000	1.24
+++ browser/interactive_query.m	10 Jul 2005 02:17:59 -0000
@@ -19,7 +19,8 @@
 
 :- interface.
 
-:- import_module io, list.
+:- import_module io.
+:- import_module list.
 
 :- pred query(query_type::in, imports::in, options::in,
 	io__input_stream::in, io__output_stream::in, io::di, io::uo) is det.
@@ -39,7 +40,13 @@
 :- import_module mdb.name_mangle.
 :- import_module mdb.util.
 
-:- import_module std_util, bool, string, term, varset, term_io, parser.
+:- import_module bool.
+:- import_module parser.
+:- import_module std_util.
+:- import_module string.
+:- import_module term.
+:- import_module term_io.
+:- import_module varset.
 
 :- pragma export(query(in, in, in, in, in, di, uo), "ML_query").
 
@@ -65,7 +72,6 @@
 			ReadTerm, !IO)
 	).
 
-
 :- pred query_2(query_type::in, imports::in, options::in,
 	io__input_stream::in, io__output_stream::in,
 	read_term(generic)::in, io::di, io::uo) is det.
@@ -119,7 +125,6 @@
 		)
 	).
 
-
 	% interactive_query_response is type of the terms sent to the socket
 	% during an interactive query session under the control of the
 	% external debugger.
Index: browser/mdb.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/mdb.m,v
retrieving revision 1.20
diff -u -b -r1.20 mdb.m
--- browser/mdb.m	29 Apr 2005 01:03:07 -0000	1.20
+++ browser/mdb.m	11 Jul 2005 02:54:33 -0000
@@ -22,6 +22,7 @@
 :- include_module debugger_interface.
 :- include_module declarative_debugger.
 :- include_module declarative_execution.
+:- include_module diff.
 :- include_module help.
 :- include_module interactive_query.
 :- include_module io_action.
Index: browser/name_mangle.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/name_mangle.m,v
retrieving revision 1.9
diff -u -b -r1.9 name_mangle.m
--- browser/name_mangle.m	24 Jan 2005 07:41:04 -0000	1.9
+++ browser/name_mangle.m	10 Jul 2005 02:19:22 -0000
@@ -59,7 +59,10 @@
 
 :- implementation.
 
-:- import_module string, char, int, list.
+:- import_module char.
+:- import_module int.
+:- import_module list.
+:- import_module string.
 
 % XXX most of the code below is very similar to the code in
 % compiler/llds_out.m.  Any changes there may require changes here
@@ -151,14 +154,13 @@
 sym_name_mangle(qualified(ModuleName, PlainName), MangledName) :-
 	sym_name_mangle(ModuleName, MangledModuleName),
 	name_mangle(PlainName, MangledPlainName),
-	qualify_name(MangledModuleName, MangledPlainName,
-			MangledName).
+	qualify_name(MangledModuleName, MangledPlainName, MangledName).
 	
 	% Convert a Mercury predicate name into something that can form
 	% part of a C identifier.  This predicate is necessary because
 	% quoted names such as 'name with embedded spaces' are valid
 	% predicate names in Mercury.
-
+	%
 :- pred name_mangle(string::in, string::out) is det.
 
 name_mangle(Name, MangledName) :-
@@ -203,7 +205,7 @@
 	% to avoid introducing name clashes.
 	% If the functor name is not found in the table, then
 	% we use a fall-back method which produces ugly names.
-
+	%
 :- pred name_conversion_table(string::in, string::out) is semidet.
 
 name_conversion_table("\\=", "f_not_equal").
@@ -229,7 +231,7 @@
 	% constructs everything except the initial "f".
 	%
 	% For example, given the input "\n\t" we return "_10_8".
-
+	%
 :- pred convert_to_valid_c_identifier_2(string::in, string::out) is det.
 
 convert_to_valid_c_identifier_2(String, Name) :-	
Index: browser/parse.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/parse.m,v
retrieving revision 1.24
diff -u -b -r1.24 parse.m
--- browser/parse.m	24 Jan 2005 07:41:04 -0000	1.24
+++ browser/parse.m	10 Jul 2005 02:20:01 -0000
@@ -107,7 +107,11 @@
 
 :- import_module mdb.browser_info.
 
-:- import_module io, string, list, std_util, getopt.
+:- import_module getopt.
+:- import_module io.
+:- import_module list.
+:- import_module std_util.
+:- import_module string.
 
 :- type command
 	--->	print(
@@ -169,7 +173,10 @@
 
 :- import_module mdb.util.
 
-:- import_module bool, list, char, int.
+:- import_module bool.
+:- import_module char.
+:- import_module int.
+:- import_module list.
 
 :- type token
 	--->	(.)
Index: browser/sized_pretty.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/sized_pretty.m,v
retrieving revision 1.11
diff -u -b -r1.11 sized_pretty.m
--- browser/sized_pretty.m	24 Jan 2005 07:41:04 -0000	1.11
+++ browser/sized_pretty.m	10 Jul 2005 09:27:39 -0000
@@ -1,14 +1,14 @@
 %---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
 % Copyright (C) 2001-2005 The University of Melbourne.
 % This file may only be copied under the terms of the GNU Library General
 % Public License - see the file COPYING.LIB in the Mercury distribution.
 %---------------------------------------------------------------------------%
 
-% sized_pretty-	When printing a term during debugging this module allows
-%		the user to put a limit on the size of the term displayed.
-%               This limit is specified by setting the number of lines you
-%               want and the width of these lines.
-%
+% When printing a term during debugging this module allows the user to put
+% a limit on the size of the term displayed. This limit is specified by
+% setting the number of lines you want and the width of these lines.
 %
 % author: sthur
 %
@@ -16,11 +16,10 @@
 % ---------------------------
 %
 % Call univ_to_string_line with the follwing variables:
-% 	univ_to_string_line(Univ, LineWidth, Lines, String)
-%		where Univ 	: is the Term (in univ type) you want to convert
+% univ_to_string_line(Univ, LineWidth, Lines, String) where
+% Univ      : is the Term (in univ type) you want to convert
 %		      LineWidth : is the length of the lines
-%		      Lines 	: is the number of lines you want the term to be
-%		            	  printed on
+% Lines     : is the number of lines you want the term to be printed on
 %		      String	: output string
 %
 % EXAMPLES
@@ -47,7 +46,8 @@
 %                       ),
 %		     "Level 2",
 %		     small
-%                    )).
+%                )
+%             ).
 %
 %---------------------------------------------------------------------------%
 % Width = 18, Line(s) = 16
@@ -164,17 +164,21 @@
 :- import_module mdb.browser_info.
 :- import_module mdb.browser_term.
 
-:- import_module std_util, int, string.
+:- import_module int.
+:- import_module std_util.
+:- import_module string.
 
 	% sized_pretty__univ_to_string_line(Univ, LineWidth, Lines, String)
 	% Converts the term in Univ to a string that fits into Lines lines
 	% of width LineWidth. It may throw an exception or cause a runtime
 	% abort if the term in question has no canonical representation.
+    %
 :- pred sized_pretty__univ_to_string_line(browser_db::in, univ::in,
 	int::in, int::in, string::out) is cc_multi.
 
 	% The same as sized_pretty__univ_to_string_line, except works on
 	% browser_terms.
+    %
 :- pred sized_pretty__browser_term_to_string_line(browser_db::in,
 	browser_term::in, int::in, int::in, string::out) is cc_multi.
 
@@ -182,7 +186,11 @@
 
 :- implementation.
 
-:- import_module list, require, assoc_list, pprint, bool.
+:- import_module assoc_list.
+:- import_module bool.
+:- import_module list.
+:- import_module pprint.
+:- import_module require.
 
 :- type no_measure_params --->	no_measure_params.
 :- type measure_params
@@ -210,8 +218,7 @@
 	;	at_least(
 			browser_term,		% univ(Term)
 			T,			% size of the term up to the
-						% point where it is
-						% deconstructed
+                                        % point where it is deconstructed
 			maybe_deconstructed(T)
 		).
 
@@ -263,7 +270,7 @@
 	% Head Term is going to be printed on a single line then it should be
 	% given a limit of character_count(LineWidth - 1) instead of
 	% character_count(LineWidth - 3).
-
+    %
 sized_pretty__univ_to_string_line(BrowserDb, Univ, LineWidth, Lines, String) :-
 	sized_pretty__browser_term_to_string_line(BrowserDb, plain_term(Univ),
 		LineWidth, Lines, String).
@@ -271,8 +278,8 @@
 sized_pretty__browser_term_to_string_line(BrowserDb, BrowserTerm,
 		LineWidth, Lines, String) :-
 	Params = measure_params(LineWidth),
-	functor_browser_term_cc(BrowserDb, BrowserTerm,
-		_Functor, Arity, MaybeReturn),
+    functor_browser_term_cc(BrowserDb, BrowserTerm, _Functor, Arity,
+        MaybeReturn),
 	(
 		Arity \= 0,
 		Lines \= 0,
@@ -288,13 +295,12 @@
 		MaybeReturn = yes,
 		BrowserTerm = synthetic_term(_, _, yes(ReturnValue))
 	->
-		annotate_with_size(BrowserDb, plain_term(ReturnValue),
-			Params, Limit, AnnotReturn),
+        annotate_with_size(BrowserDb, plain_term(ReturnValue), Params, Limit,
+            AnnotReturn),
 		Doc = group(
 			to_doc_sized(AnnotTerm)
 			`<>` line
-			`<>` nest(2, text(" = ")
-				`<>` to_doc_sized(AnnotReturn))
+            `<>` nest(2, text(" = ") `<>` to_doc_sized(AnnotReturn))
 		)
 	;
 		Doc = to_doc_sized(AnnotTerm)
@@ -309,6 +315,7 @@
 	% further.
 	% In the Second pass the space is evenly distributed between
 	% the terms and therefore the subterms are deconstructed evenly.
+    %
 :- pred annotate_with_size(browser_db::in, browser_term::in, MeasureParams::in,
 	T::in, size_annotated_term(T)::out) is cc_multi
 	<= measure_with_params(T, MeasureParams).
@@ -329,25 +336,25 @@
 		MaxFunctors, MaybeFunctorArityArgs, _MaybeReturn),
 	(
 		MaybeFunctorArityArgs = yes({Functor, Arity, Args}),
-		measured_split(BrowserDb, BrowserTerm, Params, Limit,
-			Arity, yes, FunctorSize, MaybeInitArgLimit,
-			NewLimit, NewParams),
-		( (Arity \= 0, MaybeInitArgLimit = no) ->
+        measured_split(BrowserDb, BrowserTerm, Params, Limit, Arity, yes,
+            FunctorSize, MaybeInitArgLimit, NewLimit, NewParams),
+        (
+            Arity \= 0,
+            MaybeInitArgLimit = no
+        ->
 			Exact0 = no
 		;
 			Exact0 = yes
 		),
-		annotate_args_with_size(BrowserDb, Args, MaybeInitArgLimit,
-			NewParams, NewLimit, FunctorSize, SoFar, Exact0, Exact,
-			MaybeArgSizes),
+        annotate_args_with_size(BrowserDb, Args, MaybeInitArgLimit, NewParams,
+            NewLimit, FunctorSize, SoFar, Exact0, Exact, MaybeArgSizes),
 		(
 			Exact = no,
 			Size = at_least(BrowserTerm, SoFar,
 				deconstructed(Functor, Arity, MaybeArgSizes))
 		;
 			Exact = yes,
-			Size = exact(BrowserTerm, SoFar, Functor, Arity,
-				MaybeArgSizes)
+            Size = exact(BrowserTerm, SoFar, Functor, Arity, MaybeArgSizes)
 		)
 	;
 		MaybeFunctorArityArgs = no,
@@ -356,11 +363,12 @@
 
 %---------------------------------------------------------------------------%
 
-	% annotating the arguments.
+    % Annotating the arguments.
+    %
 :- pred annotate_args_with_size(browser_db::in, list(univ)::in, maybe(T)::in,
 	MeasureParams::in, T::in, T::in, T::out, bool::in, bool::out,
-	size_annotated_args(T)::out) is cc_multi <= measure_with_params(T,
-	MeasureParams).
+    size_annotated_args(T)::out) is cc_multi
+    <= measure_with_params(T, MeasureParams).
 
 annotate_args_with_size(_, [], _, _, _, SoFar, SoFar, Exact, Exact, []).
 annotate_args_with_size(BrowserDb, [Arg | Args], MaybeInitArgLimit, Params,
@@ -374,8 +382,7 @@
 			AppliedArgLimit = max_measure(InitArgLimit,
 				subtract_measures(Limit, SoFar0, Params))
 		),
-		first_pass(BrowserDb, plain_term(Arg), Params,
-			AppliedArgLimit, Size),
+        first_pass(BrowserDb, plain_term(Arg), Params, AppliedArgLimit, Size),
 		MaybeArgSize = yes(InitArgLimit - Size),
 		extract_size_from_annotation(Size) = ArgSize,
 		SoFar1 = add_measures(SoFar0, ArgSize, Params),
@@ -425,14 +432,14 @@
 	% the other terms which could take up more than their share.
 	% If a term can be fully printed within the given space,
 	% ("exact" type) then the Term is not altered.
+    %
 :- pred second_pass(browser_db::in, size_annotated_term(T)::in,
 	MeasureParams::in, T::in, size_annotated_term(T)::out) is cc_multi
 	<= measure_with_params(T, MeasureParams).
 
 second_pass(BrowserDb, OldSizeTerm, Params, Limit, NewSizeTerm) :-
 	(
-    		OldSizeTerm = exact(_BrowserTerm, _Size, _,
-			_Arity, _MaybeArgs),
+        OldSizeTerm = exact(_BrowserTerm, _Size, _, _Arity, _MaybeArgs),
 		NewSizeTerm = OldSizeTerm
 	;
     		OldSizeTerm = at_least(_BrowserTerm, _Size, not_deconstructed),
@@ -442,39 +449,34 @@
 			deconstructed(Functor, Arity,MaybeArgs)),
 		measured_split(BrowserDb, BrowserTerm, Params, Limit, Arity,
 			yes, FSize, MaybeInitLimit, NewLimit, NewParams),
-		( MaybeInitLimit = yes(InitLimit) ->
-	    		check_args(NewParams, MaybeArgs, InitLimit, Passed,
-				FSize, Used),
+        (
+            MaybeInitLimit = yes(InitLimit),
+            check_args(NewParams, MaybeArgs, InitLimit, Passed, FSize, Used),
 			LeftOver = add_measures(subtract_measures(NewLimit,
 			  	Used, Params), FSize, Params),
-	    		measured_split(BrowserDb, BrowserTerm, Params,
-				LeftOver, Arity - Passed, no, _,
-				MaybeSplitLimit, _, _),
-	    		( MaybeSplitLimit = yes(SplitLimit) ->
+            measured_split(BrowserDb, BrowserTerm, Params, LeftOver,
+                Arity - Passed, no, _, MaybeSplitLimit, _, _),
+            (
+                MaybeSplitLimit = yes(SplitLimit),
 	        		process_args(BrowserDb, NewParams, MaybeArgs,
-					InitLimit, SplitLimit,
-					NewArgs, NewSize0),
-				NewSize = add_measures(FSize, NewSize0,
-					NewParams),
+                    InitLimit, SplitLimit, NewArgs, NewSize0),
+                NewSize = add_measures(FSize, NewSize0, NewParams),
 				Result0 = list__map(check_if_exact, NewArgs),
     				list__remove_adjacent_dups(Result0, Result),
 				( Result = [yes] ->
-					NewSizeTerm = exact(BrowserTerm,
-						NewSize, Functor, Arity,
+                    NewSizeTerm = exact(BrowserTerm, NewSize, Functor, Arity,
 						NewArgs)
 	        		;
-					NewSizeTerm = at_least(BrowserTerm,
-						NewSize,
-						deconstructed(Functor, Arity,
-							NewArgs))
+                    NewSizeTerm = at_least(BrowserTerm, NewSize,
+                    deconstructed(Functor, Arity, NewArgs))
 				)
 	    		;
-	        		NewSizeTerm = at_least(BrowserTerm, FSize,
-					not_deconstructed)
+                MaybeSplitLimit = no,
+                NewSizeTerm = at_least(BrowserTerm, FSize, not_deconstructed)
 	    		)
 		;
-			NewSizeTerm = at_least(BrowserTerm, FSize,
-				not_deconstructed)
+            MaybeInitLimit = no,
+            NewSizeTerm = at_least(BrowserTerm, FSize, not_deconstructed)
 		)
 	).
 
@@ -485,40 +487,41 @@
 	% "Used". Where "Passed" represents the number of terms that
 	% obey the Limit and are fully represented("exact") and "Used"
 	% represents the space that these terms take up.
+    %
 :- pred check_args(MeasureParams::in, size_annotated_args(T)::in, T::in,
 	int::out, T::in, T::out) is det
 	<= measure_with_params(T, MeasureParams).
 
-check_args(_, [], _, 0, Used0, Used0).
-check_args(Params, [HeadArg | Rest], ArgLimit, Passed, Used0, Used) :-
-	( HeadArg = yes(X) ->
+check_args(_, [], _, 0, !Used).
+check_args(Params, [HeadArg | Rest], ArgLimit, Passed, !Used) :-
+    (
+        HeadArg = yes(X),
 		X = _ - STerm,
 		Size = extract_size_from_annotation(STerm),
 		( STerm = exact(_, _, _, _, _) ->
 	    		( compare_measures(ArgLimit, Size) = (<) ->
-	    			check_args(Params, Rest, ArgLimit, Passed,
-					Used0, Used)
+                check_args(Params, Rest, ArgLimit, Passed, !Used)
 	    		;
 	    			Passed = 1 + PassedRest,
-				UsedSofar = add_measures(Used0, Size, Params),
-	    			check_args(Params, Rest, ArgLimit, PassedRest,
-					UsedSofar, Used)
+                !:Used = add_measures(!.Used, Size, Params),
+                check_args(Params, Rest, ArgLimit, PassedRest, !Used)
 	    		)
 		;
-	    		check_args(Params, Rest, ArgLimit, Passed, Used0, Used)
+            check_args(Params, Rest, ArgLimit, Passed, !Used)
 		)
     	;
-		check_args(Params, Rest, ArgLimit, Passed, Used0, Used)
+        HeadArg = no,
+        check_args(Params, Rest, ArgLimit, Passed, !Used)
 	).
 
 %---------------------------------------------------------------------------%
 
-	% This predicate accepts a list of size annotated terms(paired
-	% with a flag) and returns a list of the same type. This new
-	% list would consist of the same number of terms as the other
-	% but the terms which do not obey the limit or not fully
-	% represented would be annoted again with a new limit
+    % This predicate accepts a list of size annotated terms(paired with a flag)
+    % and returns a list of the same type. This new list would consist of the
+    % same number of terms as the other but the terms which do not obey the
+    % limit or not fully represented would be annoted again with a new limit
 	% (SplitLimit). The rest of the terms are left alone.
+    %
 :- pred process_args(browser_db::in, MeasureParams::in,
 	size_annotated_args(T)::in, T::in, T::in, size_annotated_args(T)::out,
 	T::out) is cc_multi <= measure_with_params(T, MeasureParams).
@@ -526,7 +529,8 @@
 process_args(_, _, [], _, _, [], zero_measure).
 process_args(BrowserDb, Params, [HeadArg | Rest], ArgLimit, SplitLimit,
 		[NewHeadArg | NewRest], SizeOut) :-
-    	( HeadArg = yes(X) ->
+    (
+        HeadArg = yes(X),
 		X = _ - STerm,
 		Size = extract_size_from_annotation(STerm),
         	BrowserTerm = extract_browser_term_from_annotation(STerm),
@@ -541,20 +545,23 @@
 			NewHeadArg = HeadArg
 		;
 			NewHeadArg = yes(pair(SplitLimit, NewSTerm)),
-			annotate_with_size(BrowserDb, BrowserTerm, Params,
-				SplitLimit, NewSTerm)
+            annotate_with_size(BrowserDb, BrowserTerm, Params, SplitLimit,
+                NewSTerm)
 		)
     	;
+        HeadArg = no,
 		NewHeadArg = no
     	),
-    	( NewHeadArg = yes(_ - Term) ->
+    (
+        NewHeadArg = yes(_ - Term),
 		NewSize = extract_size_from_annotation(Term),
 		SizeOut = add_measures(NewSize, RestSize, Params)
     	;
+        NewHeadArg = no,
 		SizeOut = RestSize
     	),
-    	process_args(BrowserDb, Params, Rest, ArgLimit, SplitLimit,
-		NewRest, RestSize).
+    process_args(BrowserDb, Params, Rest, ArgLimit, SplitLimit, NewRest,
+        RestSize).
 
 %---------------------------------------------------------------------------%
 
@@ -575,6 +582,7 @@
 
 	% A function to convert a size annotated term to a 'doc' type,
 	% a type defined in pprint.m.
+    %
 :- func to_doc_sized(size_annotated_term(T)) = doc.
 
 to_doc_sized(at_least(BrowserTerm, _, not_deconstructed)) = Doc :-
@@ -605,6 +613,7 @@
 
 	% Assumes that every argument must be on a different line
 	% or all of them should be on the same line.
+    %
 :- func to_doc_sized_2(string, int, size_annotated_args(T)) = doc.
 
 to_doc_sized_2(Functor, _Arity, []) = text(Functor).
@@ -613,8 +622,9 @@
     	Args = list__map(handle_arg, [HeadArg|Tail]),
     	list__remove_adjacent_dups(Args, NewArgs),
     	( NewArgs \= [nil] ->
-        	Doc = text(Functor) `<>` parentheses(group(nest(2, line `<>`
-			separated(id,comma_space_line, Args))))
+        Doc = text(Functor) `<>`
+            parentheses(group(nest(2,
+                line `<>` separated(id, comma_space_line, Args))))
     	;
         	Doc = text(Functor) `<>` text("/") `<>` poly(i(Arity))
     	).
@@ -637,7 +647,8 @@
 :- func add_functor_count(functor_count, functor_count,
 	no_measure_params) = functor_count.
 
-add_functor_count(functor_count(A), functor_count(B), _) = functor_count(A + B).
+add_functor_count(functor_count(A), functor_count(B), _) =
+    functor_count(A + B).
 
 :- func subtract_functor_count(functor_count, functor_count,
 	no_measure_params) = functor_count.
@@ -649,7 +660,8 @@
 
 maximum_functor_count(functor_count(N), _) = N.
 
-:- func compare_functor_count(functor_count, functor_count) = comparison_result.
+:- func compare_functor_count(functor_count, functor_count)
+    = comparison_result.
 
 compare_functor_count(functor_count(A), functor_count(B)) = R :-
 	compare(R, A, B).
@@ -669,8 +681,7 @@
 	no_measure_params::out) is cc_multi.
 
 functor_count_split(_, _, Params, functor_count(Limit), Arity, _,
-		functor_count(1), MaybeArgLimit, functor_count(Limit),
-		Params) :-
+        functor_count(1), MaybeArgLimit, functor_count(Limit), Params) :-
 	( Arity = 0 ->
 		% This artificial detism cast shuts up a warning about
 		% the true detism of functor_count_split being det.
@@ -742,13 +753,15 @@
 	no_measure_params::out) is cc_multi.
 
 char_count_split(BrowserDb, BrowserTerm, Params, char_count(Limit), Arity,
-		Check, char_count(FunctorSize), MaybeArgLimit,
-		char_count(Limit), Params) :-
+        Check, char_count(FunctorSize), MaybeArgLimit, char_count(Limit),
+        Params) :-
 	deconstruct_browser_term_cc(BrowserDb, BrowserTerm, Functor, _, Args,
 		MaybeReturn),
-	( Check = yes ->
+    (
+        Check = yes,
 		get_arg_length(Args, TotalLength, _)
 	;
+        Check = no,
 		TotalLength = 0
 	),
 	(
@@ -833,6 +846,7 @@
 	% which case is likely to happen in this code using the information
 	% it has. Therefore size_count_split determines which case is true
 	% (and changes the limit accordingly).
+    %
 :- func subtract_size_count(size_count, size_count,measure_params) = size_count.
 
 subtract_size_count(character_count(A), character_count(B), _) = Result :-
@@ -908,6 +922,7 @@
 
 	% We assume that all arguments have to be on separate lines, or
 	% the whole term should be printed on a single line.
+    %
 :- pred size_count_split(browser_db::in, browser_term::in, measure_params::in,
 	size_count::in, int::in, bool::in, size_count::out,
 	maybe(size_count)::out, size_count::out, measure_params::out)
@@ -917,13 +932,12 @@
 		FunctorSize, MaybeArgLimit, NewLimit, NewParams) :-
 	% LineWidth is length of the line in which the functor is printed.
 	Params = measure_params(LineWidth),
-	deconstruct_browser_term_cc(BrowserDb, BrowserTerm,
-		Functor, ActualArity, Args, MaybeReturn),
+    deconstruct_browser_term_cc(BrowserDb, BrowserTerm, Functor, ActualArity,
+        Args, MaybeReturn),
 	FSize = string__length(Functor) + 2 * (ActualArity),
 	( Check = yes ->
 		get_arg_length(Args, TotalLength, MaxArgLength),
-		int__max(MaxArgLength, (string__length(Functor) + 1),
-			MaxLength)
+        int__max(MaxArgLength, (string__length(Functor) + 1), MaxLength)
 	;
 		TotalLength = 0,
 		MaxLength = 0
@@ -958,8 +972,7 @@
 			LineWidth - 3 >= (FSize + TotalLength)
 		->
 			% "Arity - 1" is for rounding up.
-			Char = (LineWidth - 3 - FSize + Arity - 1)
-				// Arity ,
+            Char = (LineWidth - 3 - FSize + Arity - 1) // Arity,
 			MaybeArgLimit = yes(character_count(Char)),
 			FunctorSize = character_count(FSize),
 			NewLimit = character_count(LineWidth - 3),
@@ -968,8 +981,7 @@
 			Limit = character_count(CharLimit),
 			CharLimit >= (FSize + TotalLength)
 		->
-			Char = (CharLimit - FSize + Arity - 1)
-				// Arity,
+            Char = (CharLimit - FSize + Arity - 1) // Arity,
 			MaybeArgLimit = yes(character_count(Char)),
 			FunctorSize = character_count(FSize),
 			NewLimit = Limit,
@@ -1015,14 +1027,17 @@
 	% This predicate determines how many characters it will take
 	% to print the functors of the arguments. Also determines the
 	% length of biggest functor.
+    %
 :- pred get_arg_length(list(univ)::in, int::out, int::out) is det.
 
 get_arg_length([], 0, 0).
 get_arg_length([HeadUniv | Rest], TotalLength, MaxLength) :-
 	functor(univ_value(HeadUniv), Functor, Arity),
-	( Rest = [] ->
+    (
+        Rest = [],
 		Correction = 2
 	;
+        Rest = [_ | _],
 		Correction = 3
 	),
 	( Arity = 0 ->
Index: browser/term_rep.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/term_rep.m,v
retrieving revision 1.3
diff -u -b -r1.3 term_rep.m
--- browser/term_rep.m	24 Jan 2005 07:41:04 -0000	1.3
+++ browser/term_rep.m	10 Jul 2005 02:24:03 -0000
@@ -3,6 +3,7 @@
 % This file may only be copied under the terms of the GNU Library General
 % Public License - see the file COPYING.LIB in the Mercury distribution.
 %-----------------------------------------------------------------------------%
+%
 % File: term_rep.m
 % Author: Ian MacLarty
 %
@@ -13,7 +14,6 @@
 %
 % This is useful when we only want to consider the representation of a term
 % and don't care about it's actual value.
-%
 
 :- module mdb.term_rep.
 
Index: browser/util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/util.m,v
retrieving revision 1.28
diff -u -b -r1.28 util.m
--- browser/util.m	20 May 2005 06:15:06 -0000	1.28
+++ browser/util.m	10 Jul 2005 02:24:23 -0000
@@ -10,7 +10,10 @@
 
 :- import_module mdbcomp.prim_data.
 
-:- import_module list, string, io, bool.
+:- import_module bool.
+:- import_module io.
+:- import_module list.
+:- import_module string.
 
 :- func util__is_predicate(pred_or_func) = bool.
 :- func util__is_function(pred_or_func) = bool.
@@ -55,7 +58,8 @@
 
 :- implementation.
 
-:- import_module int, require.
+:- import_module int.
+:- import_module require.
 
 util__is_predicate(predicate) = yes.
 util__is_predicate(function) = no.
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
Index: doc/mdb_categories
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/mdb_categories,v
retrieving revision 1.26
diff -u -b -r1.26 mdb_categories
--- doc/mdb_categories	2 May 2005 04:21:14 -0000	1.26
+++ doc/mdb_categories	10 Jul 2005 12:26:18 -0000
@@ -2,7 +2,7 @@
 concepts   - The concepts on which the Mercury debugger is based.
              The concepts for which documentation is available are
              `break_points', `strict_commands', `print_level',
-             `default_print_level', `current_environment',
+             `default_print_level', `current_environment', `held_variables'
              `procedure_specification' and `decl_debug'.
 
 end
@@ -25,9 +25,9 @@
 end
 document_category 400 browsing
 browsing   - Commands that let users explore the state of the computation.
-             The browsing commands are `vars', `print', `browse',
-             `stack', `up', `down', `level', `current', `view' and
-             `save_to_file'.
+             The browsing commands are `vars', `held_vars', `print', `browse',
+             `stack', `up', `down', `level', `current', `view', `hold',
+	     `diff' and `save_to_file'.
 
 end
 document_category 500 breakpoint
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.441
diff -u -b -r1.441 user_guide.texi
--- doc/user_guide.texi	8 Jul 2005 04:22:13 -0000	1.441
+++ doc/user_guide.texi	10 Jul 2005 12:20:08 -0000
@@ -2016,6 +2016,18 @@
 The exception is the subterm specification "^..",
 which goes one level up, to the parent of the current directory.
 @sp 1
+ at item held variables
+ at cindex held variables (in mdb)
+Normally, the only variables from the program accessible in the debugger
+are the variables in the current environment at the current program point.
+However, the user can @emph{hold} variables,
+causing their values -or selected parts of their values-
+to stay available for the rest of the debugger session.
+All the commands that accept variable names
+also accept the names of held variables;
+users can ask for a held variable
+by prefixing the name of the held variable with a dollar sign.
+ at sp 1
 @item procedure specification
 @cindex procedure specification (in mdb)
 @cindex debugger procedure specification
@@ -2516,6 +2528,9 @@
 @kindex vars (mdb command)
 Prints the names of all the known variables in the current environment,
 together with an ordinal number for each variable.
+ at item held_vars
+ at kindex held_vars (mdb command)
+Prints the names of all the held variables.
 @sp 1
 @item print [-fpv] @var{name}[@var{termpath}]
 @itemx print [-fpv] @var{num}[@var{termpath}]
@@ -2782,11 +2797,32 @@
 The option @samp{-t} (or @samp{--timeout}) specifies
 the maximum number of seconds to wait for the server to start.
 @sp 1
+ZZZ
+ at item hold @var{name}[@var{termpath}] [@var{heldname}]
+ at kindex hold (mdb command)
+Holds on to the variable @var{name} of the current event,
+or the part of the specified by @var{termpath},
+even after execution leaves the current event.
+The held value will stay accessible via the name @var{$heldname}.
+If @var{heldname} is not specified, it defaults to @var{name}.
+ at sp 1
+ at item diff [-s @var{start}] [-m @var{max}] @var{name1}[@var{termpath1}] @var{name2}[@var{termpath2}]
+ at kindex diff (mdb command)
+Prints a list of some of the term paths
+at which the (specified parts of) the specified terms differ.
+Normally this command prints the term paths of the first 20 differences.
+ at sp 1
+The option @samp{-s} (or @samp{--start}), if present,
+specifies how many of the initial differences to skip.
+ at sp 1
+The option @samp{-m} (or @samp{--max}), if present,
+specifies how many differences to print.
+ at sp 1
 @item save_to_file [-x] goal @var{filename}
 @kindex save_to_file (mdb command)
 Writes the goal of the current call in its present state of instantiation
-to the specified file.  The option @samp{-x} (or @samp{--xml}) causes the
-output to be in XML.
+to the specified file.
+The option @samp{-x} (or @samp{--xml}) causes the output to be in XML.
 @sp 1
 @item save_to_file [-x] exception @var{filename}
 Writes the value of the exception at an EXCP port
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
cvs diff: Diffing mdbcomp
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
Index: tests/debugger/completion.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/completion.exp,v
retrieving revision 1.27
diff -u -b -r1.27 completion.exp
--- tests/debugger/completion.exp	10 Feb 2005 04:10:31 -0000	1.27
+++ tests/debugger/completion.exp	10 Jul 2005 14:51:59 -0000
@@ -3,40 +3,42 @@
 Command echo enabled.
 mdb> register --quiet
 mdb> 
-?                    enable               query
-P                    exception            quit
-alias                excp                 r
-all_class_decls      f                    register
-all_procedures       finish               retry
-all_regs             flag                 return
-all_type_ctors       forward              s
-b                    g                    save
-break                gen_stack            save_to_file
-break_print          goal_paths           scope
-browse               goto                 scroll
-c                    h                    set
-cc_query             help                 source
-class_decl           histogram_all        stack
-clear_histogram      histogram_exp        stack_default_limit
-condition            ignore               stack_regs
-consumer             io_query             step
-context              label_stats          subgoal
-continue             level                table
-current              maxdepth             table_io
-cut_stack            mindepth             term_size
-d                    mm_stacks            trust
-dd                   mmc_options          trusted
-dd_dd                modules              type_ctor
-debug_vars           next                 unalias
-delete               nondet_stack         unhide_events
-dice                 p                    untrust
-disable              pneg_stack           up
-document             print                v
-document_category    print_optionals      var_details
-down                 printlevel           var_name_stats
-e                    proc_stats           vars
-echo                 procedures           view
-h              help           histogram_all  histogram_exp  
+?                    enable               procedures
+P                    exception            query
+alias                excp                 quit
+all_class_decls      f                    r
+all_procedures       finish               register
+all_regs             flag                 retry
+all_type_ctors       forward              return
+b                    g                    s
+break                gen_stack            save
+break_print          goal_paths           save_to_file
+browse               goto                 scope
+c                    h                    scroll
+cc_query             held_vars            set
+class_decl           help                 source
+clear_histogram      histogram_all        stack
+condition            histogram_exp        stack_default_limit
+consumer             hold                 stack_regs
+context              ignore               step
+continue             io_query             subgoal
+current              label_stats          table
+cut_stack            level                table_io
+d                    maxdepth             term_size
+dd                   mindepth             trust
+dd_dd                mm_stacks            trusted
+debug_vars           mmc_options          type_ctor
+delete               modules              unalias
+dice                 next                 unhide_events
+diff                 nondet_stack         untrust
+disable              p                    up
+document             pneg_stack           v
+document_category    print                var_details
+down                 print_optionals      var_name_stats
+e                    printlevel           vars
+echo                 proc_stats           view
+h              help           histogram_exp  
+held_vars      histogram_all  hold           
 var_details     var_name_stats  vars            view
 var_details     var_name_stats  vars            
  help vars 
@@ -87,10 +89,10 @@
 b completion.sub2.sub3.zabc3 
  3: + stop  interface func completion.sub2.sub3.zabc3/0-0 (det)
 mdb> 
-2d                  2delete             2document_category
-2dd                 2dice               2down
-2dd_dd              2disable            
-2debug_vars         2document           
+2d                  2delete             2document
+2dd                 2dice               2document_category
+2dd_dd              2diff               2down
+2debug_vars         2disable            
 2debug_vars  2delete      
 2delete 
  2: E stop  interface func completion.sub1.z1/0-0 (det)
Index: tests/debugger/completion.inp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/completion.inp,v
retrieving revision 1.9
diff -u -b -r1.9 completion.inp
--- tests/debugger/completion.inp	20 Sep 2004 04:50:24 -0000	1.9
+++ tests/debugger/completion.inp	10 Jul 2005 14:32:14 -0000
@@ -1,6 +1,6 @@
 echo on
 register --quiet
-@ h at e@v at a@s@
+@ h at elp@v at a@s@
 p --f@@D@
 sta@ @
 proc at e@complet at .@1
Index: tests/debugger/mdb_command_test.inp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/mdb_command_test.inp,v
retrieving revision 1.41
diff -u -b -r1.41 mdb_command_test.inp
--- tests/debugger/mdb_command_test.inp	2 May 2005 04:21:15 -0000	1.41
+++ tests/debugger/mdb_command_test.inp	10 Jul 2005 20:58:34 -0000
@@ -25,6 +25,7 @@
 continue             xyzzy xyzzy xyzzy xyzzy xyzzy
 retry                xyzzy xyzzy xyzzy xyzzy xyzzy
 vars                 xyzzy xyzzy xyzzy xyzzy xyzzy
+held_vars            xyzzy xyzzy xyzzy xyzzy xyzzy
 print                xyzzy xyzzy xyzzy xyzzy xyzzy
 browse               xyzzy xyzzy xyzzy xyzzy xyzzy
 stack                xyzzy xyzzy xyzzy xyzzy xyzzy
@@ -33,6 +34,8 @@
 level                xyzzy xyzzy xyzzy xyzzy xyzzy
 current              xyzzy xyzzy xyzzy xyzzy xyzzy
 view                 xyzzy xyzzy xyzzy xyzzy xyzzy
+hold                 xyzzy xyzzy xyzzy xyzzy xyzzy
+diff                 xyzzy xyzzy xyzzy xyzzy xyzzy
 save_to_file         xyzzy xyzzy xyzzy xyzzy xyzzy
 break                xyzzy xyzzy xyzzy xyzzy xyzzy
 condition            xyzzy xyzzy xyzzy xyzzy xyzzy
Index: tests/debugger/queens.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/queens.exp,v
retrieving revision 1.30
diff -u -b -r1.30 queens.exp
--- tests/debugger/queens.exp	17 Jan 2005 05:58:08 -0000	1.30
+++ tests/debugger/queens.exp	11 Jul 2005 03:17:38 -0000
@@ -91,6 +91,43 @@
        HeadVar__2             	[1, 2, 3, 4, 5]
 mdb> print HeadVar__3
        HeadVar__3             	[2, 3, 4, 5]
+mdb> hold HeadVar__2^1 x
+mdb> hold HeadVar__2^2 y
+mdb> hold HeadVar__2 y
+mdb: there is already a held variable $y
+mdb> hold HeadVar__2 z
+mdb> held_vars
+$x
+$y
+$z
+mdb> print $x
+       x                      	1
+mdb> print $y
+       y                      	[2, 3, 4, 5]
+mdb> print $z
+       z                      	[1, 2, 3, 4, 5]
+mdb> diff $x $y
+The two values are of different types.
+mdb> diff $y $z
+There are 5 diffs, showing diffs 1-5:
+1: 1: 2/0 vs 1/0
+2: 2/1: 3/0 vs 2/0
+3: 2/2/1: 4/0 vs 3/0
+4: 2/2/2/1: 5/0 vs 4/0
+5: 2/2/2/2: []/0 vs [|]/2
+mdb> diff -m 2 $y $z
+There are 5 diffs, showing diffs 1-2:
+1: 1: 2/0 vs 1/0
+2: 2/1: 3/0 vs 2/0
+mdb> diff -s 2 -m 2 $y $z
+There are 5 diffs, showing diffs 3-4:
+3: 2/2/1: 4/0 vs 3/0
+4: 2/2/2/1: 5/0 vs 4/0
+mdb> diff -s 4 -m 2 $y $z
+There are 5 diffs, showing diff 5:
+5: 2/2/2/2: []/0 vs [|]/2
+mdb> diff $y $z^2
+There are no diffs.
 mdb> 
      E10:     C6 CALL queens.m:36 (from queens.m:40)
                          pred queens.qperm/2-0 (nondet)
Index: tests/debugger/queens.exp2
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/queens.exp2,v
retrieving revision 1.11
diff -u -b -r1.11 queens.exp2
--- tests/debugger/queens.exp2	17 Jan 2005 05:58:08 -0000	1.11
+++ tests/debugger/queens.exp2	10 Jul 2005 21:03:22 -0000
@@ -91,6 +91,43 @@
        HeadVar__2             	[1, 2, 3, 4, 5]
 mdb> print HeadVar__3
        HeadVar__3             	[2, 3, 4, 5]
+mdb> hold HeadVar__2^1 x
+mdb> hold HeadVar__2^2 y
+mdb> hold HeadVar__2 y
+mdb: there is already a held variable $y
+mdb> hold HeadVar__2 z
+mdb> held_vars
+$x
+$y
+$z
+mdb> print $x
+       x                      	1
+mdb> print $y
+       y                      	[2, 3, 4, 5]
+mdb> print $z
+       z                      	[1, 2, 3, 4, 5]
+mdb> diff $x $y
+The two values are of different types.
+mdb> diff $y $z
+There are 5 diffs, showing diffs 1-5:
+1: 1
+2: 2/1
+3: 2/2/1
+4: 2/2/2/1
+5: 2/2/2/2
+mdb> diff -m 2 $y $z
+There are 5 diffs, showing diffs 1-2:
+1: 1
+2: 2/1
+mdb> diff -s 2 -m 2 $y $z
+There are 5 diffs, showing diffs 3-4:
+3: 2/2/1
+4: 2/2/2/1
+mdb> diff -s 4 -m 2 $y $z
+There are 5 diffs, showing diff 5:
+5: 2/2/2/2
+mdb> diff $y $z^2
+There are no diffs.
 mdb> 
      E10:     C6 CALL queens.m:36 (from queens.m:40)
                          pred queens.qperm/2-0 (nondet)
Index: tests/debugger/queens.inp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/queens.inp,v
retrieving revision 1.14
diff -u -b -r1.14 queens.inp
--- tests/debugger/queens.inp	20 Jun 2003 12:33:55 -0000	1.14
+++ tests/debugger/queens.inp	10 Jul 2005 12:31:33 -0000
@@ -38,6 +38,20 @@
 print HeadVar__1
 print HeadVar__2
 print HeadVar__3
+hold HeadVar__2^1 x
+hold HeadVar__2^2 y
+hold HeadVar__2 y
+hold HeadVar__2 z
+held_vars
+print $x
+print $y
+print $z
+diff $x $y
+diff $y $z
+diff -m 2 $y $z
+diff -s 2 -m 2 $y $z
+diff -s 4 -m 2 $y $z
+diff $y $z^2
 
 print *
 
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
Index: trace/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/Mmakefile,v
retrieving revision 1.43
diff -u -b -r1.43 Mmakefile
--- trace/Mmakefile	20 May 2005 06:15:28 -0000	1.43
+++ trace/Mmakefile	9 Jul 2005 00:15:39 -0000
@@ -11,13 +11,14 @@
 
 # keep this list in alphabetical order, please
 HDRS		=	\
-			mercury_trace.h			\
 			mercury_trace_alias.h		\
 			mercury_trace_browse.h		\
 			mercury_trace_completion.h	\
 			mercury_trace_declarative.h	\
 			mercury_trace_external.h 	\
+			mercury_trace.h			\
 			mercury_trace_help.h		\
+			mercury_trace_hold_vars.h	\
 			mercury_trace_internal.h	\
 			mercury_trace_readline.h	\
 			mercury_trace_source.h		\
@@ -28,13 +29,14 @@
 
 # keep this list in alphabetical order, please
 CFILES		= 	\
-			mercury_trace.c			\
 			mercury_trace_alias.c		\
 			mercury_trace_browse.c		\
+			mercury_trace.c			\
 			mercury_trace_completion.c	\
 			mercury_trace_declarative.c	\
 			mercury_trace_external.c 	\
 			mercury_trace_help.c		\
+			mercury_trace_hold_vars.c	\
 			mercury_trace_internal.c	\
 			mercury_trace_readline.c	\
 			mercury_trace_source.c		\
Index: trace/mercury_trace_alias.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_alias.c,v
retrieving revision 1.7
diff -u -b -r1.7 mercury_trace_alias.c
--- trace/mercury_trace_alias.c	10 Jan 2003 05:17:33 -0000	1.7
+++ trace/mercury_trace_alias.c	9 Jul 2005 00:09:31 -0000
@@ -52,8 +52,7 @@
 			INIT_ALIAS_COUNT);
 		MR_prepare_insert_into_sorted(MR_alias_records,
 			MR_alias_record_next, slot,
-			strcmp(MR_alias_records[slot].MR_alias_name,
-				name));
+			strcmp(MR_alias_records[slot].MR_alias_name, name));
 	}
 
 	MR_alias_records[slot].MR_alias_name = MR_copy_string(name);
@@ -182,4 +181,3 @@
 {
 	return (MR_strdiff(word, "EMPTY") && MR_strdiff(word, "NUMBER"));
 }
-
Index: trace/mercury_trace_hold_vars.c
===================================================================
RCS file: trace/mercury_trace_hold_vars.c
diff -N trace/mercury_trace_hold_vars.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ trace/mercury_trace_hold_vars.c	10 Jul 2005 12:25:12 -0000
@@ -0,0 +1,82 @@
+/*
+** vim: ts=4 sw=4 expandtab
+*/
+/*
+** Copyright (C) 2005 The University of Melbourne.
+** This file may only be copied under the terms of the GNU Library General
+** Public License - see the file COPYING.LIB in the Mercury distribution.
+*/
+
+#include "mercury_imp.h"
+#include "mercury_array_macros.h"       /* MR_bsearch etc */
+#include "mercury_trace_base.h"         /* MR_TRACE_CALL_MERCURY */
+#include "type_desc.mh"                 /* ML_get_type_info_for_type_info */
+#include "mercury_trace_hold_vars.h"
+
+typedef struct {
+    const char  *MR_held_name;
+    MR_TypeInfo MR_held_type;
+    MR_Word     MR_held_value;
+} MR_Held_Var;
+
+/* The initial size of the held vars table. */
+#define MR_INIT_HELD_VARS   10
+
+static MR_Held_Var  *MR_held_vars;
+static int          MR_held_var_max = 0;
+static int          MR_held_var_next = 0;
+
+MR_bool
+MR_add_hold_var(const char *name, const MR_TypeInfo typeinfo, MR_Word value)
+{
+    MR_TypeInfo old_type;
+    MR_Word     old_value;
+    int         slot;
+    MR_Word     typeinfo_type_word;
+
+    if (MR_lookup_hold_var(name, &old_type, &old_value)) {
+        return MR_FALSE;
+    }
+
+    MR_TRACE_CALL_MERCURY(
+        typeinfo_type_word = ML_get_type_info_for_type_info();
+    );
+
+    MR_ensure_room_for_next(MR_held_var, MR_Held_Var, MR_INIT_HELD_VARS);
+    MR_prepare_insert_into_sorted(MR_held_vars, MR_held_var_next, slot,
+        strcmp(MR_held_vars[slot].MR_held_name, name));
+    MR_held_vars[slot].MR_held_name = strdup(name);
+    MR_held_vars[slot].MR_held_type = (MR_TypeInfo) MR_make_permanent(typeinfo,
+        typeinfo_type_word);
+    MR_held_vars[slot].MR_held_value = MR_make_permanent(value, typeinfo);
+
+    return MR_TRUE;
+}
+
+MR_bool
+MR_lookup_hold_var(const char *name, MR_TypeInfo *typeinfo,
+    MR_Word *value)
+{
+    MR_bool found;
+    int     slot;
+
+    MR_bsearch(MR_held_var_next, slot, found,
+        strcmp(MR_held_vars[slot].MR_held_name, name));
+    if (found) {
+        *typeinfo = MR_held_vars[slot].MR_held_type;
+        *value = MR_held_vars[slot].MR_held_value;
+        return MR_TRUE;
+    } else {
+        return MR_FALSE;
+    }
+}
+
+void
+MR_trace_list_held_vars(FILE *fp)
+{
+    int i;
+
+    for (i = 0; i < MR_held_var_next; i++) {
+        fprintf(fp, "$%s\n", MR_held_vars[i].MR_held_name);
+    }
+}
Index: trace/mercury_trace_hold_vars.h
===================================================================
RCS file: trace/mercury_trace_hold_vars.h
diff -N trace/mercury_trace_hold_vars.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ trace/mercury_trace_hold_vars.h	11 Jul 2005 03:11:14 -0000
@@ -0,0 +1,47 @@
+/*
+** vim: ts=4 sw=4 expandtab
+*/
+/*
+** Copyright (C) 2005 The University of Melbourne.
+** This file may only be copied under the terms of the GNU Library General
+** Public License - see the file COPYING.LIB in the Mercury distribution.
+*/
+
+/*
+** This module looks after the debugger's information about the variables
+** that have been held the user. Held variables start out as variables
+** live at a trace event, and then the act of holding onto them extends their
+** lifetimes to the end of the debugger session.
+*/
+
+#ifndef MERCURY_TRACE_HOLD_VARS_H
+#define MERCURY_TRACE_HOLD_VARS_H
+
+#include <stdio.h>              /* for FILE         */
+#include "mercury_std.h"        /* for MR_bool      */
+#include "mercury_types.h"      /* for MR_Word etc  */
+
+/*
+** Add a new variable with the given name, type and value to the set
+** of held variables. Returns true if successful; returning false indicates
+** that a held variable with that name already exists.
+*/
+
+extern  MR_bool     MR_add_hold_var(const char *name,
+                        const MR_TypeInfo typeinfo, MR_Word value);
+
+/*
+** Search for a held variable with the given name. If successful, return true
+** and fill in *typeinfo and *name, otherwise return false.
+*/
+
+extern  MR_bool     MR_lookup_hold_var(const char *name,
+                        MR_TypeInfo *typeinfo, MR_Word *value);
+
+/*
+** Print a list of the extant held variables to the specified file.
+*/
+
+extern  void        MR_trace_list_held_vars(FILE *fp);
+
+#endif  /* MERCURY_TRACE_HOLD_VARS_H */
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.206
diff -u -b -r1.206 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	7 Jun 2005 03:00:10 -0000	1.206
+++ trace/mercury_trace_internal.c	11 Jul 2005 02:54:57 -0000
@@ -31,10 +31,12 @@
 #include "mercury_trace_tables.h"
 #include "mercury_trace_util.h"
 #include "mercury_trace_vars.h"
+#include "mercury_trace_hold_vars.h"
 #include "mercury_trace_readline.h"
 #include "mercury_trace_source.h"
 
 #include "mdb.browse.mh"
+#include "mdb.diff.mh"
 #include "mdb.browser_info.mh"
 #include "mdb.declarative_execution.mh"
 #include "mdbcomp.program_representation.mh"
@@ -452,12 +454,15 @@
 static  MR_TraceCmdFunc MR_trace_cmd_up;
 static  MR_TraceCmdFunc MR_trace_cmd_down;
 static  MR_TraceCmdFunc MR_trace_cmd_vars;
+static  MR_TraceCmdFunc MR_trace_cmd_held_vars;
 static  MR_TraceCmdFunc MR_trace_cmd_print;
 static  MR_TraceCmdFunc MR_trace_cmd_browse;
 static  MR_TraceCmdFunc MR_trace_cmd_stack;
 static  MR_TraceCmdFunc MR_trace_cmd_current;
 static  MR_TraceCmdFunc MR_trace_cmd_set;
 static  MR_TraceCmdFunc MR_trace_cmd_view;
+static  MR_TraceCmdFunc MR_trace_cmd_hold;
+static  MR_TraceCmdFunc MR_trace_cmd_diff;
 static  MR_TraceCmdFunc MR_trace_cmd_save_to_file;
 static  MR_TraceCmdFunc MR_trace_cmd_break;
 static  MR_TraceCmdFunc MR_trace_cmd_condition;
@@ -610,6 +615,9 @@
 static  MR_bool     MR_trace_options_all_procedures(MR_bool *separate,
                         MR_bool *uci, char **module, char ***words,
                         int *word_count, const char *cat, const char *item);
+static  MR_bool     MR_trace_options_diff(int *start, int *max,
+                        char ***words, int *word_count, const char *cat,
+                        const char *item);
 static  MR_bool     MR_trace_options_save_to_file(MR_bool *xml,
                         char ***words, int *word_count, const char *cat,
                         const char *item);
@@ -2123,6 +2131,20 @@
 }
 
 static MR_Next
+MR_trace_cmd_held_vars(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+    MR_Event_Info *event_info, MR_Event_Details *event_details,
+    MR_Code **jumpaddr)
+{
+    if (word_count == 1) {
+        MR_trace_list_held_vars(MR_mdb_out);
+    } else {
+        MR_trace_usage("browsing", "held_vars");
+    }
+
+    return KEEP_INTERACTING;
+}
+
+static MR_Next
 MR_trace_cmd_print(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
     MR_Event_Info *event_info, MR_Event_Details *event_details,
     MR_Code **jumpaddr)
@@ -2424,6 +2446,119 @@
 }
 
 static MR_Next
+MR_trace_cmd_hold(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+    MR_Event_Info *event_info, MR_Event_Details *event_details,
+    MR_Code **jumpaddr)
+{
+    char        *event_var_name;
+    char        *held_var_name;
+    MR_TypeInfo type_info;
+    MR_Word     value;
+    const char  *ignored_name;
+    const char  *problem;
+    MR_bool     bad_subterm;
+
+    if (word_count == 2) {
+        event_var_name = words[1];
+        held_var_name = words[1];
+    } else if (word_count == 3) {
+        event_var_name = words[1];
+        held_var_name = words[2];
+    } else {
+        MR_trace_usage("browsing", "hold");
+        return KEEP_INTERACTING;
+    }
+
+    if (strpbrk(held_var_name, "^/") != NULL) {
+        /* Don't allow path separators in variable names. */
+        MR_trace_usage("browsing", "hold");
+        return KEEP_INTERACTING;
+    }
+
+    if (held_var_name[0] == '$') {
+        /* Ignore any unneeded initial $ signs. */
+        held_var_name = &held_var_name[1];
+    }
+
+    problem = MR_trace_parse_lookup_var_path(event_var_name, &type_info,
+        &value, &bad_subterm);
+    if (problem != NULL) {
+        fflush(MR_mdb_out);
+        fprintf(MR_mdb_err, "mdb: %s%s.\n",
+            (bad_subterm? "there is no path " : ""), problem);
+        return KEEP_INTERACTING;
+    }
+
+    if (! MR_add_hold_var(held_var_name, type_info, value)) {
+        fflush(MR_mdb_out);
+        fprintf(MR_mdb_err, "mdb: there is already a held variable $%s\n",
+            held_var_name);
+    }
+
+    return KEEP_INTERACTING;
+}
+
+static MR_Next
+MR_trace_cmd_diff(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+    MR_Event_Info *event_info, MR_Event_Details *event_details,
+    MR_Code **jumpaddr)
+{
+    int         start;
+    int         max;
+    char        *name1;
+    char        *name2;
+    MR_TypeInfo type_info1;
+    MR_TypeInfo type_info2;
+    MR_Word     value1;
+    MR_Word     value2;
+    MR_Word     univ1;
+    MR_Word     univ2;
+    const char  *problem1;
+    const char  *problem2;
+    MR_bool     bad_subterm1;
+    MR_bool     bad_subterm2;
+
+    start = 0;
+    max = 20;
+    if (! MR_trace_options_diff(&start, &max, &words, &word_count,
+        "browsing", "diff"))
+    {
+        /* the usage message has already been printed */
+        return KEEP_INTERACTING;
+    } else if (word_count != 3) {
+        MR_trace_usage("browsing", "diff");
+        return KEEP_INTERACTING;
+    }
+
+    name1 = words[1];
+    name2 = words[2];
+    problem1 = MR_trace_parse_lookup_var_path(name1, &type_info1, &value1,
+        &bad_subterm1);
+    problem2 = MR_trace_parse_lookup_var_path(name2, &type_info2, &value2,
+        &bad_subterm2);
+    if (problem1 != NULL) {
+        fflush(MR_mdb_out);
+        fprintf(MR_mdb_err, "mdb: %s%s.\n",
+            (bad_subterm1? "arg1: there is no path " : ""), problem1);
+        return KEEP_INTERACTING;
+    }
+    if (problem2 != NULL) {
+        fflush(MR_mdb_out);
+        fprintf(MR_mdb_err, "mdb: %s%s.\n",
+            (bad_subterm2? "arg2: there is no path " : ""), problem2);
+        return KEEP_INTERACTING;
+    }
+
+    MR_TRACE_CALL_MERCURY(
+        MR_new_univ_on_hp(univ1, type_info1, value1);
+        MR_new_univ_on_hp(univ2, type_info2, value2);
+        ML_report_diffs(start, max, univ1, univ2);
+    );
+
+    return KEEP_INTERACTING;
+}
+
+static MR_Next
 MR_trace_cmd_save_to_file(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
     MR_Event_Info *event_info, MR_Event_Details *event_details,
     MR_Code **jumpaddr)
@@ -2479,10 +2614,11 @@
             MR_Var_Spec var_spec;
             MR_TypeInfo type_info;
             MR_Word     value;
+            const char  *name;
 
             MR_convert_arg_to_var_spec(words[1], &var_spec);
-            problem = MR_convert_var_spec_to_type_value(var_spec,
-                &type_info, &value);
+            problem = MR_lookup_unambiguous_var_spec(var_spec,
+                &type_info, &value, &name);
             if (problem == NULL) {
                 browser_term = MR_type_value_to_browser_term(type_info, value);
             }
@@ -7256,6 +7392,50 @@
     return MR_TRUE;
 }
 
+static struct MR_option MR_trace_diff_opts[] =
+{
+    { "start",      MR_required_argument,   NULL,   's' },
+    { "max",        MR_required_argument,   NULL,   'm' },
+    { NULL,         MR_no_argument,         NULL,   0 }
+};
+
+static MR_bool
+MR_trace_options_diff(int *start, int *max,
+    char ***words, int *word_count, const char *cat, const char *item)
+{
+    int c;
+
+    MR_optind = 0;
+    while ((c = MR_getopt_long(*word_count, *words, "m:s:", MR_trace_diff_opts,
+        NULL)) != EOF)
+    {
+        switch (c) {
+
+            case 'm':
+                if (! MR_trace_is_natural_number(MR_optarg, max)) {
+                    MR_trace_usage(cat, item);
+                    return MR_FALSE;
+                }
+                break;
+
+            case 's':
+                if (! MR_trace_is_natural_number(MR_optarg, start)) {
+                    MR_trace_usage(cat, item);
+                    return MR_FALSE;
+                }
+                break;
+
+            default:
+                MR_trace_usage(cat, item);
+                return MR_FALSE;
+        }
+    }
+
+    *words = *words + MR_optind - 1;
+    *word_count = *word_count - MR_optind + 1;
+    return MR_TRUE;
+}
+
 static struct MR_option MR_trace_save_to_file_opts[] =
 {
     { "xml",        MR_no_argument,     NULL,   'x' },
@@ -8099,6 +8279,8 @@
         MR_trace_stack_cmd_args, MR_trace_null_completer },
     { "browsing", "vars", MR_trace_cmd_vars,
         NULL, MR_trace_null_completer },
+    { "browsing", "held_vars", MR_trace_cmd_held_vars,
+        NULL, MR_trace_null_completer },
     { "browsing", "print", MR_trace_cmd_print,
         MR_trace_print_cmd_args, MR_trace_var_completer },
     { "browsing", "browse", MR_trace_cmd_browse,
@@ -8109,6 +8291,10 @@
         NULL, MR_trace_null_completer },
     { "browsing", "view", MR_trace_cmd_view,
         MR_trace_view_cmd_args, MR_trace_null_completer },
+    { "browsing", "hold", MR_trace_cmd_hold,
+        NULL, MR_trace_var_completer },
+    { "browsing", "diff", MR_trace_cmd_diff,
+        NULL, MR_trace_var_completer },
     { "browsing", "save_to_file", MR_trace_cmd_save_to_file,
         NULL, MR_trace_var_completer },
 
Index: trace/mercury_trace_spy.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_spy.c,v
retrieving revision 1.24
diff -u -b -r1.24 mercury_trace_spy.c
--- trace/mercury_trace_spy.c	1 Feb 2005 03:24:32 -0000	1.24
+++ trace/mercury_trace_spy.c	10 Jul 2005 00:42:27 -0000
@@ -372,6 +372,7 @@
     char            *bad_path;
     MR_TypeInfo     type_info;
     MR_Word         value;
+    const char      *name;
     MR_Word         *value_ptr;
     MR_TypeInfo     sub_type_info;
     MR_Word         *sub_value_ptr;
@@ -404,7 +405,7 @@
         (MR_Trace_Port) label_layout->MR_sll_port, MR_FALSE);
 
     problem = MR_lookup_unambiguous_var_spec(cond->cond_var_spec,
-        &type_info, &value);
+        &type_info, &value, &name);
     if (problem != NULL) {
         if (cond->cond_require_var) {
             MR_spy_point_cond_problem = problem;
Index: trace/mercury_trace_util.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_util.c,v
retrieving revision 1.14
diff -u -b -r1.14 mercury_trace_util.c
--- trace/mercury_trace_util.c	28 Jan 2005 02:47:44 -0000	1.14
+++ trace/mercury_trace_util.c	10 Jul 2005 11:58:40 -0000
@@ -31,7 +31,7 @@
 MR_bool
 MR_trace_is_natural_number(const char *word, int *value)
 {
-    if (MR_isdigit(*word)) {
+    if (word != NULL && MR_isdigit(*word)) {
         *value = *word - '0';
         word++;
         while (MR_isdigit(*word)) {
Index: trace/mercury_trace_vars.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_vars.c,v
retrieving revision 1.62
diff -u -b -r1.62 mercury_trace_vars.c
--- trace/mercury_trace_vars.c	6 Apr 2005 01:11:33 -0000	1.62
+++ trace/mercury_trace_vars.c	10 Jul 2005 11:49:16 -0000
@@ -24,6 +24,7 @@
 #include "mercury_stack_layout.h"
 #include "mercury_trace_util.h"
 #include "mercury_trace_vars.h"
+#include "mercury_trace_hold_vars.h"
 
 #include "mdb.browse.mh"
 
@@ -54,6 +55,10 @@
 ** does not uniquely identify it among all the variables live at the
 ** current point. What *is* guaranteed to uniquely identify a variable
 ** is its HLDS number, which will be in the hlds_number field.
+** (Note that the HLDS numbers identifying variables to the debugger
+** are not the same as the numbers identifying those variables in the compiler;
+** variable numbers occurring in the RTTI are renumbered to be a dense set,
+** whereas the original variable numbers are not guaranteed to be dense.)
 **
 ** The last two fields contain the value of the variable and the typeinfo
 ** describing the type of this value.
@@ -125,22 +130,26 @@
                             const void *arg2);
 static  int             MR_compare_slots_on_headvar_num(const void *p1,
                             const void *p2);
-static  const char *    MR_trace_browse_one_path(FILE *out,
+static  const char      *MR_trace_browse_one_path(FILE *out,
                             MR_bool print_var_name, MR_Var_Spec var_spec,
                             char *path, MR_Browser browser,
                             MR_Browse_Caller_Type caller,
                             MR_Browse_Format format, MR_bool must_be_unique);
-static  char *          MR_trace_browse_var(FILE *out, MR_bool print_var_name,
-                            MR_Var_Details *var, char *path,
+static  char            *MR_trace_browse_var(FILE *out, MR_bool print_var_name,
+                            MR_TypeInfo type_info, MR_Word value,
+                            const char *name, char *path,
                             MR_Browser browser, MR_Browse_Caller_Type caller,
                             MR_Browse_Format format);
-static  const char *    MR_lookup_var_spec(MR_Var_Spec var_spec,
-                            int *var_index_ptr, MR_bool *is_ambiguous_ptr);
-static  char *          MR_trace_var_completer_next(const char *word,
+static  const char      *MR_lookup_var_spec(MR_Var_Spec var_spec,
+                            MR_TypeInfo *type_info_ptr, MR_Word *value_ptr,
+                            const char **name_ptr, int *var_index_ptr,
+                            MR_bool *is_ambiguous_ptr);
+static  char            *MR_trace_var_completer_next(const char *word,
                             size_t word_len, MR_Completer_Data *data);
 static  int             MR_trace_print_var_name(FILE *out,
                             MR_Var_Details *var);
-static  const char *    MR_trace_valid_var_number(int var_number);
+static  const char      *MR_trace_printed_var_name(MR_Var_Details *var);
+static  const char      *MR_trace_valid_var_number(int var_number);
 
 #define MR_INIT_VAR_DETAIL_COUNT        20
 #define MR_TRACE_PADDED_VAR_NAME_LENGTH 23
@@ -787,6 +796,10 @@
         var_spec->MR_var_spec_kind = MR_VAR_SPEC_NUMBER;
         var_spec->MR_var_spec_number = n;
         var_spec->MR_var_spec_name = NULL; /* unused */
+    } else if (word_spec[0] == '$') {
+        var_spec->MR_var_spec_kind = MR_VAR_SPEC_HELD_NAME;
+        var_spec->MR_var_spec_name = word_spec + 1;
+        var_spec->MR_var_spec_number = -1; /* unused */
     } else {
         var_spec->MR_var_spec_kind = MR_VAR_SPEC_NAME;
         var_spec->MR_var_spec_name = word_spec;
@@ -977,6 +990,45 @@
 }
 
 const char *
+MR_trace_parse_lookup_var_path(char *word_spec, MR_TypeInfo *type_info_ptr,
+    MR_Word *value_ptr, MR_bool *bad_subterm_ptr)
+{
+    MR_Var_Spec var_spec;
+    MR_TypeInfo var_type_info;
+    MR_Word     var_value;
+    MR_TypeInfo sub_type_info;
+    MR_Word     *sub_value_ptr;
+    char        *path;
+    const char  *problem;
+    const char  *bad_path;
+    const char  *ignored_name;
+
+    *bad_subterm_ptr = MR_FALSE;
+
+    problem = MR_trace_parse_var_path(word_spec, &var_spec, &path);
+    if (problem != NULL) {
+        return problem;
+    }
+
+    problem = MR_lookup_unambiguous_var_spec(var_spec, &var_type_info,
+        &var_value, &ignored_name);
+    if (problem != NULL) {
+        return problem;
+    }
+
+    bad_path = MR_select_specified_subterm(path, var_type_info, &var_value,
+        &sub_type_info, &sub_value_ptr);
+    if (bad_path != NULL) {
+        *bad_subterm_ptr = MR_TRUE;
+        return bad_path;
+    }
+
+    *type_info_ptr = sub_type_info;
+    *value_ptr = *sub_value_ptr;
+    return NULL;
+}
+
+const char *
 MR_trace_parse_browse_one(FILE *out, MR_bool print_var_name, char *word_spec,
     MR_Browser browser, MR_Browse_Caller_Type caller, MR_Browse_Format format,
     MR_bool must_be_unique)
@@ -1005,13 +1057,14 @@
 
 const char *
 MR_lookup_unambiguous_var_spec(MR_Var_Spec var_spec,
-    MR_TypeInfo *type_info, MR_Word *value)
+    MR_TypeInfo *type_info_ptr, MR_Word *value_ptr, const char **name_ptr)
 {
     int         var_num;
     MR_bool     is_ambiguous;
     const char  *problem;
 
-    problem = MR_lookup_var_spec(var_spec, &var_num, &is_ambiguous);
+    problem = MR_lookup_var_spec(var_spec, type_info_ptr, value_ptr, name_ptr,
+        &var_num, &is_ambiguous);
     if (problem != NULL) {
         return problem;
     }
@@ -1020,8 +1073,6 @@
         return "variable name is not unique";
     }
 
-    *type_info = MR_point.MR_point_vars[var_num].MR_var_type;
-    *value = MR_point.MR_point_vars[var_num].MR_var_value;
     return NULL;
 }
 
@@ -1035,15 +1086,19 @@
     MR_bool     is_ambiguous;
     const char  *problem;
     char        *bad_path;
+    MR_TypeInfo type_info;
+    MR_Word     value;
+    const char  *name;
 
-    problem = MR_lookup_var_spec(var_spec, &var_num, &is_ambiguous);
+    problem = MR_lookup_var_spec(var_spec, &type_info, &value, &name, &var_num,
+        &is_ambiguous);
     if (problem != NULL) {
         return problem;
     }
 
     if (! is_ambiguous) {
-        bad_path = MR_trace_browse_var(out, print_var_name,
-            &MR_point.MR_point_vars[var_num], path, browser, caller, format);
+        bad_path = MR_trace_browse_var(out, print_var_name, type_info, value,
+            name, path, browser, caller, format);
         if (bad_path != NULL) {
             return MR_trace_bad_path(bad_path);
         }
@@ -1057,8 +1112,7 @@
         success_count = 0;
         do {
             bad_path = MR_trace_browse_var(out, print_var_name,
-                &MR_point.MR_point_vars[var_num], path, browser, caller,
-                format);
+                type_info, value, name, path, browser, caller, format);
 
             if (bad_path == NULL) {
                 success_count++;
@@ -1091,14 +1145,22 @@
     MR_bool     is_ambiguous;
     const char  *problem;
     MR_Var_Spec var_spec;
+    MR_TypeInfo type_info;
+    MR_Word     value;
+    const char  *name;
 
     MR_convert_arg_to_var_spec(word_spec, &var_spec);
-    problem = MR_lookup_var_spec(var_spec, &var_num, &is_ambiguous);
+    problem = MR_lookup_var_spec(var_spec, &type_info, &value, &name, &var_num,
+        &is_ambiguous);
     if (problem != NULL) {
         return problem;
     }
 
     if (is_ambiguous) {
+        if (var_num < 0) {
+            MR_fatal_error("MR_trace_print_size_one: ambiguous, no var num");
+        }
+
         do {
             fprintf(out, "%20s: %6u\n",
                 MR_point.MR_point_vars[var_num].MR_var_fullname,
@@ -1109,10 +1171,7 @@
             MR_streq(var_spec.MR_var_spec_name,
             MR_point.MR_point_vars[var_num].MR_var_fullname));
     } else {
-        fprintf(out, "%20s: %6u\n",
-            MR_point.MR_point_vars[var_num].MR_var_fullname,
-            MR_term_size(MR_point.MR_point_vars[var_num].MR_var_type,
-                MR_point.MR_point_vars[var_num].MR_var_value));
+        fprintf(out, "%20s: %6u\n", name, type_info, value);
     }
 
     return NULL;
@@ -1179,8 +1238,10 @@
 
     for (var_num = 0; var_num < MR_point.MR_point_var_count; var_num++) {
         (void) MR_trace_browse_var(out, MR_TRUE,
-            &MR_point.MR_point_vars[var_num], NULL, browser,
-            MR_BROWSE_CALLER_PRINT_ALL, format);
+            MR_point.MR_point_vars[var_num].MR_var_type,
+            MR_point.MR_point_vars[var_num].MR_var_value,
+            MR_trace_printed_var_name(&MR_point.MR_point_vars[var_num]),
+            NULL, browser, MR_BROWSE_CALLER_PRINT_ALL, format);
     }
 
     return NULL;
@@ -1273,7 +1334,8 @@
 }
 
 static char *
-MR_trace_browse_var(FILE *out, MR_bool print_var_name, MR_Var_Details *var,
+MR_trace_browse_var(FILE *out, MR_bool print_var_name,
+    MR_TypeInfo var_type_info, MR_Word var_value, const char *name,
     char *path, MR_Browser browser, MR_Browse_Caller_Type caller,
     MR_Browse_Format format)
 {
@@ -1283,8 +1345,8 @@
     MR_bool     saved_io_tabling_enabled;
     char        *bad_path;
 
-    bad_path = MR_select_specified_subterm(path, var->MR_var_type,
-        &var->MR_var_value, &type_info, &value);
+    bad_path = MR_select_specified_subterm(path, var_type_info, &var_value,
+        &type_info, &value);
 
     if (bad_path != NULL) {
         return bad_path;
@@ -1301,7 +1363,8 @@
         */
 
         fprintf(out, "%7s", "");
-        len = MR_trace_print_var_name(out, var);
+        fprintf(out, "%s", name);
+        len = strlen(name);
         while (len < MR_TRACE_PADDED_VAR_NAME_LENGTH) {
             fputc(' ', out);
             len++;
@@ -1338,10 +1401,11 @@
 */
 
 static const char *
-MR_lookup_var_spec(MR_Var_Spec var_spec, int *var_index_ptr,
+MR_lookup_var_spec(MR_Var_Spec var_spec, MR_TypeInfo *type_info_ptr,
+    MR_Word *value_ptr, const char **name_ptr, int *var_index_ptr,
     MR_bool *is_ambiguous_ptr)
 {
-    int         i;
+    int         vn;
     MR_bool     found;
     const char  *problem;
 
@@ -1349,20 +1413,26 @@
         return MR_point.MR_point_problem;
     }
 
-    if (var_spec.MR_var_spec_kind == MR_VAR_SPEC_NUMBER) {
+    switch (var_spec.MR_var_spec_kind) {
+        case MR_VAR_SPEC_NUMBER:
         problem = MR_trace_valid_var_number(var_spec.MR_var_spec_number);
         if (problem != NULL) {
             return problem;
         }
 
-        *var_index_ptr = var_spec.MR_var_spec_number - 1;
+            vn = var_spec.MR_var_spec_number - 1;
+            *var_index_ptr = vn;
+            *type_info_ptr = MR_point.MR_point_vars[vn].MR_var_type;
+            *value_ptr = MR_point.MR_point_vars[vn].MR_var_value;
+            *name_ptr = MR_trace_printed_var_name(&MR_point.MR_point_vars[vn]);
         *is_ambiguous_ptr = MR_FALSE;
         return NULL;
-    } else if (var_spec.MR_var_spec_kind == MR_VAR_SPEC_NAME) {
+
+        case MR_VAR_SPEC_NAME:
         found = MR_FALSE;
-        for (i = 0; i < MR_point.MR_point_var_count; i++) {
+            for (vn = 0; vn < MR_point.MR_point_var_count; vn++) {
             if (MR_streq(var_spec.MR_var_spec_name,
-                MR_point.MR_point_vars[i].MR_var_fullname))
+                    MR_point.MR_point_vars[vn].MR_var_fullname))
             {
                 found = MR_TRUE;
                 break;
@@ -1373,40 +1443,34 @@
             return "there is no such variable";
         }
 
-        *var_index_ptr = i;
-        if (MR_point.MR_point_vars[i].MR_var_is_ambiguous) {
+            *var_index_ptr = vn;
+            *type_info_ptr = MR_point.MR_point_vars[vn].MR_var_type;
+            *value_ptr = MR_point.MR_point_vars[vn].MR_var_value;
+            *name_ptr = MR_trace_printed_var_name(&MR_point.MR_point_vars[vn]);
+            if (MR_point.MR_point_vars[vn].MR_var_is_ambiguous) {
             *is_ambiguous_ptr = MR_TRUE;
         } else {
             *is_ambiguous_ptr = MR_FALSE;
         }
 
         return NULL;
-    } else {
-        MR_fatal_error("internal error: bad var_spec kind");
-        return NULL;
-    }
-}
 
-const char *
-MR_convert_var_spec_to_type_value(MR_Var_Spec var_spec,
-    MR_TypeInfo *type_info_ptr, MR_Word *value_ptr)
-{
-    int         i;
-    MR_bool     is_ambiguous;
-    const char  *problem;
-
-    problem = MR_lookup_var_spec(var_spec, &i, &is_ambiguous);
-    if (problem != NULL) {
-        return problem;
+        case MR_VAR_SPEC_HELD_NAME:
+            *var_index_ptr = -1;
+            if (! MR_lookup_hold_var(var_spec.MR_var_spec_name,
+                type_info_ptr, value_ptr))
+            {
+                return "no such held variable";
     }
 
-    if (! is_ambiguous) {
-        *type_info_ptr = MR_point.MR_point_vars[i].MR_var_type;
-        *value_ptr = MR_point.MR_point_vars[i].MR_var_value;
+            *name_ptr = var_spec.MR_var_spec_name;
+            *var_index_ptr = -1;
+            *is_ambiguous_ptr = MR_FALSE;
         return NULL;
-    } else {
-        return "variable name is not unique";
     }
+
+    MR_fatal_error("MR_lookup_var_spec: internal error: bad var_spec kind");
+    return NULL;
 }
 
 MR_ConstString
@@ -1491,6 +1555,61 @@
     return len;
 }
 
+/* this should be plenty big enough */
+#define  MR_TRACE_VAR_NAME_BUF_SIZE 256
+static  char    MR_var_name_buf[MR_TRACE_VAR_NAME_BUF_SIZE];
+
+static const char *
+MR_trace_printed_var_name(MR_Var_Details *var)
+{
+    /*
+    ** If the variable starts with "HeadVar__" then the
+    ** argument number is part of the name.
+    */
+    if (var->MR_var_is_headvar &&
+        ! MR_streq(var->MR_var_basename, "HeadVar__"))
+    {
+        if (var->MR_var_is_ambiguous) {
+#ifdef  MR_HAVE_SNPRINTF
+            snprintf(MR_var_name_buf, MR_TRACE_VAR_NAME_BUF_SIZE,
+                "%s(%d) (arg %d)", var->MR_var_fullname,
+                var->MR_var_hlds_number, var->MR_var_is_headvar);
+#else
+            sprintf(MR_var_name_buf, "%s(%d) (arg %d)",
+                var->MR_var_fullname,
+                var->MR_var_hlds_number, var->MR_var_is_headvar);
+#endif
+        } else {
+#ifdef  MR_HAVE_SNPRINTF
+            snprintf(MR_var_name_buf, MR_TRACE_VAR_NAME_BUF_SIZE,
+                "%s (arg %d)", var->MR_var_fullname, var->MR_var_is_headvar);
+#else
+            sprintf(MR_var_name_buf, "%s (arg %d)",
+                var->MR_var_fullname, var->MR_var_is_headvar);
+#endif
+        }
+    } else {
+        if (var->MR_var_is_ambiguous) {
+#ifdef  MR_HAVE_SNPRINTF
+            snprintf(MR_var_name_buf, MR_TRACE_VAR_NAME_BUF_SIZE,
+                "%s(%d)", var->MR_var_fullname, var->MR_var_hlds_number);
+#else
+            sprintf(MR_var_name_buf, "%s(%d)",
+                var->MR_var_fullname, var->MR_var_hlds_number);
+#endif
+        } else {
+#ifdef  MR_HAVE_SNPRINTF
+            snprintf(MR_var_name_buf, MR_TRACE_VAR_NAME_BUF_SIZE, "%s",
+                var->MR_var_fullname);
+#else
+            sprintf(MR_var_name_buf, "%s", var->MR_var_fullname);
+#endif
+        }
+    }
+
+    return MR_var_name_buf;
+}
+
 static  const char *
 MR_trace_valid_var_number(int var_number)
 {
@@ -1521,7 +1640,10 @@
         ** closely by a call or an exit, this should be sufficient to catch
         ** most misconstructed terms.
         */
-        (void) MR_trace_browse_var(stdout, MR_TRUE, &MR_point.MR_point_vars[i],
+        (void) MR_trace_browse_var(stdout, MR_TRUE,
+            MR_point.MR_point_vars[i].MR_var_type,
+            MR_point.MR_point_vars[i].MR_var_value,
+            MR_point.MR_point_vars[i].MR_var_fullname,
             (MR_String) (MR_Integer) "", MR_trace_print,
             MR_BROWSE_CALLER_PRINT, MR_BROWSE_DEFAULT_FORMAT);
 
Index: trace/mercury_trace_vars.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_vars.h,v
retrieving revision 1.27
diff -u -b -r1.27 mercury_trace_vars.h
--- trace/mercury_trace_vars.h	1 Feb 2005 03:24:32 -0000	1.27
+++ trace/mercury_trace_vars.h	10 Jul 2005 11:35:53 -0000
@@ -65,13 +65,15 @@
 
 typedef	enum {
 	MR_VAR_SPEC_NUMBER,
-	MR_VAR_SPEC_NAME
+	MR_VAR_SPEC_NAME,
+	MR_VAR_SPEC_HELD_NAME
 } MR_Var_Spec_Kind;
 
 typedef struct {
 	MR_Var_Spec_Kind	MR_var_spec_kind;
 	int			MR_var_spec_number; /* valid if NUMBER */
 	const char		*MR_var_spec_name;  /* valid if NAME   */
+						    /* or HELD_NAME    */
 } MR_Var_Spec;
 
 /*
@@ -193,6 +195,20 @@
 				MR_Var_Spec *var_spec, char **path);
 
 /*
+** Parse the given word into a variable specification and the specification
+** of a path within that variable, as with MR_trace_parse_var_path, then
+** look up and record the term at that path in *type_info and *value,
+** and return NULL. If there is a problem with changing to a specified subterm,
+** then return the term path of the problematic subterm and set *bad_subterm
+** to true. If there is some other problem, return a description of the problem
+** and set *bad_subterm to false.
+*/
+
+extern	const char	*MR_trace_parse_lookup_var_path(char *word_spec,
+				MR_TypeInfo *type_info, MR_Word *value,
+				MR_bool *bad_subterm);
+
+/*
 ** Print the (names and) values of (the specified parts of) the specified
 ** variable. (The variable is specified by either its name or its sequence
 ** number in the set of live variables at the current point; the desired part
@@ -257,12 +273,16 @@
 				int ancestor_level, MR_bool print_optionals);
 
 /*
-** If the given variable specification is unambiguous, then set *value to
-** the value of the specified variable, and set *type_info to its type.
+** If the given variable specification is unambiguous, then set set *type_info
+** to the type of the specified variable, set *value to its value, and set
+** *name to its name (the storage name points to will remain valid only until
+** the next call to MR_lookup_unambiguous_var_spec). Return a non-NULL error
+** message if this is not possible.
 */
 
 extern	const char	*MR_lookup_unambiguous_var_spec(MR_Var_Spec var_spec,
-				MR_TypeInfo *type_info, MR_Word *value);
+				MR_TypeInfo *type_info, MR_Word *value,
+				const char **name);
 
 /*
 ** *value and type_info describe a term, and path specifies a subterm of that
@@ -306,16 +326,6 @@
 				const char **functor_ptr,
 				MR_Word *arg_list_ptr, MR_bool *is_func_ptr);
 
-
-/*
-** Given a variable specification, return the type_info and the value of the
-** chosen variable. Return a non-NULL error message if this is not possible.
-*/
-
-extern	const char	*MR_convert_var_spec_to_type_value(
-				MR_Var_Spec var_spec,
-				MR_TypeInfo *type_info_ptr,
-				MR_Word *value_ptr);
 
 /*
 ** Return the name (if any) of the variable with the given HLDS variable number
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list