[m-rev.] for review: conditional breakpoints

Zoltan Somogyi zs at cs.mu.OZ.AU
Mon Jan 31 12:34:00 AEDT 2005


This is for both branches.

Zoltan.

Implement a new mdb command, "condition", which associates a condition with
an existing breakpoint. The condition is a match between a variable live at
the breakpoint, or a part thereof, and a term provided as part of the condition
command. If execution arrives at the breakpoint but the match doesn't have the
required outcome, execution will continue without stopping.

NEWS:
	Mention the new capability.

doc/user_guide.texi:
	Document the new capability.

runtime/mercury_trace_term.[ch]:
	This new module has facilities for converting strings to a structured
	representation of terms. The debugger uses this representation for the
	term being matched.

runtime/Mmakefile:
	Add the new module to the list of modules in the runtime library.

browser/cterm.m:
	This new module tests whether a value in the program being debugged
	matches a term represented by the data structure defiend in
	mercury_trace_term.

browser/mdb.m:
	Include the new module in the browser library.

trace/mercury_trace_spy.[ch]:
	Change the code that checks for breakpoints to check breakpoints'
	conditions.

	Fix an old bug: set the number of the most recent breakpoint
	even when reusing an existing slot.

trace/mercury_trace_vars.c:
	Change the code that checks for breakpoints to also evaluate the
	condition, if any.

	Provide the facilities required to implement conditions. Besides
	exporting some previously private functions, this involved breaking up
	two existing functions into two pieces each, because condition checking
	wanted to reuse only parts of them.

	Modify the implementation of the functions manipulating breakpoints
	to handle the new parts of spy point structures.

	Modify the way we delete spy point structures to make doubly sure
	that we don't free memory twice; it is now MR_delete_spy_point that
	sets te spy_exists field to FALSE, after checking it.

	Give more meaningful names to some variables.

trace/mercury_trace_internal.[ch]:
	Implement the condition command.

	Conform to the changes in mercury_trace_vars.c

	When the condition of a breakpoint cannot be evaluated, print an error
	message.

	Extend the command parser to support double quotes, since this is now
	needed to allow strings in terms in the condition command.

	Flush any error messages resulting from an mdb command immediately
	after the command. This was useful in debugging the change.

tests/debugger/cond.{m,inp,exp*}:
	Add this new test case to test the new capability.

tests/debugger/Mmakefile:
	Include the new test case in the list of test cases.

tests/debugger/completion.exp:
tests/debugger/mdb_command_test.inp:
	Update to reflect the new command.

tests/debugger/cmd_quote.exp:
	Update the error message.

cvs diff: Diffing .
Index: NEWS
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/NEWS,v
retrieving revision 1.370
diff -u -b -r1.370 NEWS
--- NEWS	27 Jan 2005 06:17:31 -0000	1.370
+++ NEWS	31 Jan 2005 01:12:48 -0000
@@ -54,10 +54,12 @@
 * Shared libraries now work on Mac OS X.
 
 Changes to the Mercury debugger:
-* Users can now limit the output from stack traces.
-* Users can now put breakpoints on unify and compare predicates.
 * Users can now arrange to have the goal and/or some variables printed
   every time execution arrives at a breakpoint.
+* Users can now arrange to associate a condition with a breakpoint.
+  Execution won't stop at the breakpoint if the condition is false.
+* Users can now limit the output from stack traces.
+* Users can now put breakpoints on unify and compare predicates.
 * Users can now save runtime values to files.
 * Users can now tell the declarative debugger to trust entire modules or 
   individual predicates or functions.
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/cterm.m
===================================================================
RCS file: browser/cterm.m
diff -N browser/cterm.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ browser/cterm.m	30 Jan 2005 17:32:52 -0000
@@ -0,0 +1,138 @@
+%---------------------------------------------------------------------------%
+% 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.
+%---------------------------------------------------------------------------%
+
+:- module mdb.cterm.
+
+:- interface.
+
+:- import_module bool.
+
+:- type cterm.
+:- type cargs.
+
+	% Succeed if and only if the given term matches the given cterm.
+	%
+:- pred match_with_cterm(T::in, cterm::in, bool::out) is cc_multi.
+
+	% Implement deconstruct for cterms.
+	%
+:- pred cterm_deconstruct(cterm::in, string::out, cargs::out) is det.
+
+	% Decompose a list of arguments into the first element and the rest.
+	% Fail if the list is empty.
+	%
+:- pred cterm_head_tail(cargs::in, cterm::out, cargs::out) is semidet.
+
+:- implementation.
+
+:- import_module list.
+:- import_module deconstruct.
+:- import_module std_util.
+
+:- pragma foreign_decl(c, "
+#include ""mercury_trace_term.h""
+").
+
+:- pragma foreign_type(c, cterm, "MR_CTerm", [can_pass_as_mercury_type]).
+:- pragma foreign_type(c, cargs, "MR_CArgs", [can_pass_as_mercury_type]).
+
+:- pragma export(match_with_cterm(in, in, out), "ML_BROWSE_match_with_cterm").
+
+% Uncomment these and the unsafe_perform_ios below to debug match_with_cterm
+% and its callers in the trace directory.
+% :- import_module io, unsafe.
+% :- pragma promise_pure(match_with_cterm/3).
+
+match_with_cterm(Term, CTerm, Match) :-
+	deconstruct(Term, include_details_cc, TermFunctor, _, TermArgs),
+	cterm_deconstruct(CTerm, CTermFunctor, CTermArgs),
+	% impure unsafe_perform_io(io__write_string("comparing <")),
+	% impure unsafe_perform_io(io__write_string(TermFunctor)),
+	% impure unsafe_perform_io(io__write_string("> to <")),
+	% impure unsafe_perform_io(io__write_string(CTermFunctor)),
+	% impure unsafe_perform_io(io__write_string(">\n")),
+	( TermFunctor = CTermFunctor ->
+		match_with_cterms(TermArgs, CTermArgs, Match)
+	; CTermFunctor = "_" ->
+		Match = yes
+	;
+		Match = no
+	).
+
+:- pred match_with_cterms(list(univ)::in, cargs::in, bool::out) is cc_multi.
+
+match_with_cterms(UnivArgs, CArgs, Match) :-
+	( cterm_head_tail(CArgs, CHead, CTail) ->
+		( UnivArgs = [UnivHead | UnivTail] ->
+			Head = univ_value(UnivHead),
+			match_with_cterm(Head, CHead, MatchHead),
+			(
+				MatchHead = no,
+				Match = no
+			;
+				MatchHead = yes,
+				match_with_cterms(UnivTail, CTail, Match)
+			)
+		;
+			Match = no
+		)
+	;
+		( UnivArgs = [] ->
+			Match = yes
+		;
+			Match = no
+		)
+	).
+
+:- pragma foreign_proc(c, 
+	cterm_deconstruct(Term::in, Functor::out, Args::out),
+	[will_not_call_mercury, promise_pure],
+"
+	if (Term == NULL) {
+		MR_fatal_error(""cterm_deconstruct: NULL term"");
+	}
+
+	Functor = Term->term_functor;
+	Args = Term->term_args;
+").
+
+:- pragma foreign_proc(c, 
+	cterm_head_tail(Args::in, Head::out, Tail::out),
+	[will_not_call_mercury, promise_pure],
+"
+	if (Args == NULL) {
+		SUCCESS_INDICATOR = MR_FALSE;
+	} else {
+		Head = Args->args_head;
+		Tail = Args->args_tail;
+		SUCCESS_INDICATOR = MR_TRUE;
+	}
+").
+
+:- pragma foreign_proc(c, 
+	cterm_deconstruct(Term::in, Functor::out, Args::out),
+	[will_not_call_mercury, promise_pure],
+"
+	if (Term == NULL) {
+		MR_fatal_error(""cterm_deconstruct: NULL term"");
+	}
+
+	Functor = Term->term_functor;
+	Args = Term->term_args;
+").
+
+:- pragma foreign_proc(c, 
+	cterm_head_tail(Args::in, Head::out, Tail::out),
+	[will_not_call_mercury, promise_pure],
+"
+	if (Args == NULL) {
+		SUCCESS_INDICATOR = MR_FALSE;
+	} else {
+		Head = Args->args_head;
+		Tail = Args->args_tail;
+		SUCCESS_INDICATOR = MR_TRUE;
+	}
+").
Index: browser/mdb.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/mdb.m,v
retrieving revision 1.17
diff -u -b -r1.17 mdb.m
--- browser/mdb.m	24 Jan 2005 07:41:04 -0000	1.17
+++ browser/mdb.m	29 Jan 2005 10:34:14 -0000
@@ -18,6 +18,7 @@
 :- include_module browser_info.
 :- include_module browser_term.
 :- include_module collect_lib.
+:- include_module cterm.
 :- include_module debugger_interface.
 :- include_module declarative_debugger.
 :- include_module declarative_execution.
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/user_guide.texi
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.414
diff -u -b -r1.414 user_guide.texi
--- doc/user_guide.texi	28 Jan 2005 02:59:10 -0000	1.414
+++ doc/user_guide.texi	31 Jan 2005 01:15:10 -0000
@@ -3022,8 +3022,43 @@
 @item break info
 Lists the details, status and print lists of all break points.
 @sp 1
- at item ignore [-E at var{ignore-count}] [-I at var{ignore-count}] @var{num}
+ at item condition [-n at var{break-num}] [-p] [-v] @var{varname}[@var{pathspec}] @var{op} @var{term}
+ at kindex condition (mdb command)
+Attaches a condition to the most recent breakpoint,
+or, if the @samp{n} or @samp{break-num} is given;
+execution won't stop at the breakpoint if the condition is false.
+ at sp 1
+The condition is a match between a variable live at the breakpoint,
+or a part thereof, and @var{term}.
+It is ok for @var{term} to contain spaces.
+The term from the program to be matched
+is specified by @var{varname};
+if it is followed by @var{pathspec} (without a space),
+it specifies that the match is to be
+against the specified part of @var{varname}.
+ at sp 1
+There are two values allowed for @var{op}.
+If @var{op} is @samp{=}, the condition is true
+if the term specified by @var{printspec} matches @var{term}.
+If @var{op} is @samp{!=}, the condition is true
+if the term specified by @var{printspec} doesn't match @var{term}.
+ at var{term} may contain integers and strings,
+but floats and characters aren't supported (yet),
+and neither is any special syntax for lists, operators, etc.
+ at var{term} also may not contain variables, with one exception:
+any occurrence of @samp{_} in @var{term} matches any term.
+ at sp 1
+If execution reaches a breakpoint and the condition cannot be evaluated,
+execution will normally stop at that breakpoint with a message to that effect.
+If the @samp{-p} or @samp{--dont-require-path} option is given,
+execution won't stop at breakpoints at which
+the specified part of the specified variable doesn't exist.
+If the @samp{-v} or @samp{--dont-require-var} option is given,
+execution won't stop at breakpoints at which
+the specified variable itself doesn't exist.
 @sp 1
+ at item ignore [-E at var{ignore-count}] [-I at var{ignore-count}] @var{num}
+ at kindex ignore (mdb command)
 The options @samp{-E at var{ignore-count}}
 and @samp{--ignore-entry @var{ignore-count}}
 tell the debugger to ignore the breakpoint
@@ -3040,7 +3075,6 @@
 Reports an error if there is no break point with the specified number.
 @sp 1
 @item ignore [-E at var{ignore-count}] [-I at var{ignore-count}]
- at sp 1
 The options @samp{-E at var{ignore-count}}
 and @samp{--ignore-entry @var{ignore-count}}
 tell the debugger to ignore the breakpoint
@@ -3057,7 +3091,7 @@
 Reports an error if the most recently added breakpoint has since been deleted.
 @sp 1
 @item break_print [-fpv] [-e] [-n] @var{num} @var{print-spec}*
- at sp 1
+ at kindex break_print (mdb command)
 Adds the specified print list elements (there may be more than one)
 to the print list of the breakpoint numbered @var{num}.
 @sp 1
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
Index: runtime/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/Mmakefile,v
retrieving revision 1.117
diff -u -b -r1.117 Mmakefile
--- runtime/Mmakefile	28 Jan 2005 07:11:55 -0000	1.117
+++ runtime/Mmakefile	29 Jan 2005 10:20:32 -0000
@@ -91,6 +91,7 @@
 			mercury_thread.h	\
 			mercury_timing.h	\
 			mercury_trace_base.h	\
+			mercury_trace_term.h	\
 			mercury_trail.h		\
 			mercury_typeclass_info.h	\
 			mercury_type_desc.h	\
@@ -182,6 +183,7 @@
 			mercury_thread.c	\
 			mercury_timing.c	\
 			mercury_trace_base.c	\
+			mercury_trace_term.c	\
 			mercury_trail.c 	\
 			mercury_type_desc.c	\
 			mercury_type_info.c	\
Index: runtime/mercury_trace_term.c
===================================================================
RCS file: runtime/mercury_trace_term.c
diff -N runtime/mercury_trace_term.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ runtime/mercury_trace_term.c	30 Jan 2005 15:47:29 -0000
@@ -0,0 +1,175 @@
+/*
+** 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 file contains code to manage terms, for conditional breakpoints.
+**
+** Author: Zoltan Somogyi.
+*/
+
+#include "mercury_imp.h"
+#include "mercury_trace_term.h"
+#include <stdlib.h>
+
+static  MR_CArgs    MR_create_cargs(char *str, char **rest);
+static  void        MR_delete_cargs(MR_CArgs args);
+
+/**************************************************************************/
+
+MR_CTerm
+MR_create_cterm(char *str, char **rest)
+{
+    MR_CTerm    term;
+    MR_CArgs    args;
+    int         i;
+
+    /*
+    ** We don't have to worry about skipping white space, because there
+    ** won't be any, except inside strings.
+    */
+
+    if (str[0] == '"') {
+        i = 1;
+        while (str[i] != '\0' && str[i] != '"') {
+            i++;
+        }
+
+        if (str[i] == '"') {
+            term = MR_malloc(sizeof(struct MR_CTerm_Struct));
+            term->term_functor = &str[0];
+            term->term_args = NULL;
+            *rest = &str[i + 1];
+            return term;
+        }
+
+        return NULL;
+    }
+
+    if (! MR_isalnumunder(str[0]) || MR_isupper(str[0])) {
+        return NULL;
+    }
+
+    i = 0;
+    while (MR_isalnumunder(str[i])) {
+        i++;
+    }
+
+    term = MR_malloc(sizeof(struct MR_CTerm_Struct));
+
+    if ((str[i] == '\0') || str[i] == ',' || str[i] == ')') {
+        term->term_functor = str;
+        term->term_args = NULL;
+        *rest = &str[i];
+        return term;
+    } else if (str[i] == '(') {
+        str[i] = '\0';
+        term->term_functor = str;
+        args = MR_create_cargs(&str[i + 1], rest);
+        if (args == NULL) {
+            MR_free(term);
+            return NULL;
+        }
+
+        term->term_args = args;
+        return term;
+    }
+
+    MR_free(term);
+    return NULL;
+}
+
+static MR_CArgs
+MR_create_cargs(char *str, char **rest)
+{
+    char            *more;
+    MR_CTerm        term;
+    MR_CArgs        args;
+    MR_CArgs        tail;
+    int             i;
+
+    term = MR_create_cterm(str, &more);
+    if (term == NULL) {
+        return NULL;
+    }
+
+    args = MR_malloc(sizeof(struct MR_CArgs_Struct));
+    args->args_head = term;
+
+    if (more[0] == ')') {
+        more[0] = '\0'; /* to terminate the just previous functor, if any */
+        args->args_tail = NULL;
+        *rest = &more[1];
+        return args;
+    } else if (more[0] == ',') {
+        more[0] = '\0'; /* to terminate the just previous functor, if any */
+        i = 1;
+        while (more[i] != '\0' && MR_isspace(more[i])) {
+            i++;
+        }
+
+        if (more[i] == '\0') {
+            MR_free(args);
+            return NULL;
+        }
+
+        tail = MR_create_cargs(more + i, rest);
+        if (tail == NULL) {
+            MR_free(args);
+            return NULL;
+        }
+
+        args->args_tail = tail;
+        return args;
+    }
+
+    MR_free(args);
+    return NULL;
+}
+
+void
+MR_print_cterm(FILE *fp, MR_CTerm term)
+{
+    MR_CArgs    args;
+    int         i;
+
+    fprintf(fp, "%s", term->term_functor);
+    if (term->term_args != NULL) {
+        fprintf(fp, "(");
+        i = 0;
+        args = term->term_args;
+        while (args != NULL) {
+            if (i > 0) {
+                fprintf(fp, ", ");
+            }
+            MR_print_cterm(fp, args->args_head);
+            args = args->args_tail;
+            i++;
+        }
+        fprintf(fp, ")");
+    }
+}
+
+void
+MR_delete_cterm(MR_CTerm term)
+{
+    if (term != NULL) {
+        MR_delete_cargs(term->term_args);
+        MR_free(term);
+    }
+}
+
+static void
+MR_delete_cargs(MR_CArgs args)
+{
+    if (args != NULL) {
+        MR_delete_cargs(args->args_tail);
+        MR_delete_cterm(args->args_head);
+        MR_free(args);
+    }
+}
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 tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
Index: tests/debugger/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/Mmakefile,v
retrieving revision 1.108
diff -u -b -r1.108 Mmakefile
--- tests/debugger/Mmakefile	9 Dec 2004 01:03:19 -0000	1.108
+++ tests/debugger/Mmakefile	30 Jan 2005 10:55:41 -0000
@@ -20,6 +20,7 @@
 	browse_pretty			\
 	class_decl			\
 	cmd_quote			\
+	cond				\
 	debugger_regs			\
 	exception_cmd			\
 	exception_value			\
@@ -245,6 +246,9 @@
 cmd_quote.out: cmd_quote cmd_quote.inp
 	$(MDB) ./cmd_quote < cmd_quote.inp 2>&1 | \
 		sed 's/io.m:[0-9]*/io.m:NNNN/g' > cmd_quote.out 2>&1
+
+cond.out: cond cond.inp
+	$(MDB) ./cond < cond.inp 2>&1 > cond.out 2>&1
 
 # Set up readline to make it easier to use completion non-interactively.
 completion.out: completion completion.inp
Index: tests/debugger/cmd_quote.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/cmd_quote.exp,v
retrieving revision 1.3
diff -u -b -r1.3 cmd_quote.exp
--- tests/debugger/cmd_quote.exp	26 Jan 2004 21:17:35 -0000	1.3
+++ tests/debugger/cmd_quote.exp	30 Jan 2005 19:36:57 -0000
@@ -39,5 +39,5 @@
 mdb> '\ \\\''
 Unknown command ` \''. Give the command `help' for help.
 mdb> '
-> unmatched quote.
+> unmatched single quote.
 mdb> mdb: are you sure you want to quit? 
Index: tests/debugger/completion.exp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/completion.exp,v
retrieving revision 1.25
diff -u -b -r1.25 completion.exp
--- tests/debugger/completion.exp	27 Jan 2005 06:17:37 -0000	1.25
+++ tests/debugger/completion.exp	30 Jan 2005 19:39:28 -0000
@@ -3,21 +3,22 @@
 Command echo enabled.
 mdb> register --quiet
 mdb> 
-?                    excp                 r
-P                    f                    register
-alias                finish               retry
-all_class_decls      flag                 return
-all_procedures       forward              s
-all_regs             g                    save
-all_type_ctors       gen_stack            save_to_file
-b                    goal_paths           scope
-break                goto                 scroll
-break_print          h                    set
-browse               help                 source
-c                    histogram_all        stack
-cc_query             histogram_exp        stack_default_limit
-class_decl           ignore               stack_regs
-clear_histogram      io_query             step
+?                    exception            quit
+P                    excp                 r
+alias                f                    register
+all_class_decls      finish               retry
+all_procedures       flag                 return
+all_regs             forward              s
+all_type_ctors       g                    save
+b                    gen_stack            save_to_file
+break                goal_paths           scope
+break_print          goto                 scroll
+browse               h                    set
+c                    help                 source
+cc_query             histogram_all        stack
+class_decl           histogram_exp        stack_default_limit
+clear_histogram      ignore               stack_regs
+condition            io_query             step
 consumer             label_stats          subgoal
 context              level                table
 continue             maxdepth             table_io
@@ -35,7 +36,6 @@
 e                    proc_stats           vars
 echo                 procedures           view
 enable               query                
-exception            quit                 
 h              help           histogram_all  histogram_exp  
 var_details     var_name_stats  vars            view
 var_details     var_name_stats  vars            
Index: tests/debugger/cond.exp
===================================================================
RCS file: tests/debugger/cond.exp
diff -N tests/debugger/cond.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/cond.exp	30 Jan 2005 19:37:03 -0000
@@ -0,0 +1,89 @@
+       1:      1  1 CALL pred cond.main/2-0 (det) cond.m:13
+mdb> echo on
+Command echo enabled.
+mdb> context none
+Contexts will not be printed.
+mdb> break p
+Registering debuggable procedures... done.
+There is one debuggable module, with 5 procedures.
+ 0: + stop  interface pred cond.p/2-0 (det)
+mdb> condition X = yes(_)
+ 0: + stop  interface pred cond.p/2-0 (det)
+            X = yes(_)
+mdb> continue
+       6:      4  3 CALL pred cond.p/2-0 (det)
+mdb> print
+p(yes(2), _)
+mdb> delete *
+ 0: E stop  interface pred cond.p/2-0 (det)
+            X = yes(_)
+mdb> finish 1
+[no, yes(3), yes(4)]
+      12:      2  2 EXIT pred cond.test_maybe/2-0 (det)
+mdb> break p
+ 0: + stop  interface pred cond.p/2-0 (det)
+mdb> condition X = yes(3)
+ 0: + stop  interface pred cond.p/2-0 (det)
+            X = yes(3)
+mdb> continue
+      20:      9  3 CALL pred cond.p/2-0 (det)
+mdb> print
+p(yes(3), _)
+mdb> delete *
+ 0: E stop  interface pred cond.p/2-0 (det)
+            X = yes(3)
+mdb> finish 1
+[no, yes(3), yes(4)]
+      23:      6  2 EXIT pred cond.test_maybe/2-0 (det)
+mdb> break p
+ 0: + stop  interface pred cond.p/2-0 (det)
+mdb> condition -v Y = yes( 3)
+ 0: + stop  interface pred cond.p/2-0 (det)
+            -v -p Y = yes(3)
+mdb> continue
+      30:     12  3 EXIT pred cond.p/2-0 (det)
+mdb> print
+p(yes(2), yes(3))
+mdb> delete *
+ 0: E stop  interface pred cond.p/2-0 (det)
+            -v -p Y = yes(3)
+mdb> finish 1
+[no, yes(3), yes(4)]
+      34:     10  2 EXIT pred cond.test_maybe/2-0 (det)
+mdb> break p
+ 0: + stop  interface pred cond.p/2-0 (det)
+mdb> condition -v Y^1 != 3
+ 0: + stop  interface pred cond.p/2-0 (det)
+            -v -p Y ^1 != 3
+mdb> continue
+      44:     17  3 EXIT pred cond.p/2-0 (det)
+mdb> print
+p(yes(3), yes(4))
+mdb> delete *
+ 0: E stop  interface pred cond.p/2-0 (det)
+            -v -p Y ^1 != 3
+mdb> finish 1
+[no, yes(3), yes(4)]
+      45:     14  2 EXIT pred cond.test_maybe/2-0 (det)
+mdb> break q
+ 0: + stop  interface pred cond.q/2-0 (det)
+mdb> condition -v Y != "abc "
+ 0: + stop  interface pred cond.q/2-0 (det)
+            -v -p Y != "abc "
+mdb> continue
+      50:     19  3 EXIT pred cond.q/2-0 (det)
+mdb> print
+q("abc", "xabcx")
+mdb> continue
+xabcx
+      56:     20  3 EXIT pred cond.q/2-0 (det)
+mdb> print
+q("def", "ydefy")
+mdb> delete *
+ 0: E stop  interface pred cond.q/2-0 (det)
+            -v -p Y != "abc "
+mdb> finish 1
+ydefy
+else
+      63:     18  2 EXIT pred cond.test_string/2-0 (det)
+mdb> continue
Index: tests/debugger/cond.inp
===================================================================
RCS file: tests/debugger/cond.inp
diff -N tests/debugger/cond.inp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/cond.inp	30 Jan 2005 17:32:05 -0000
@@ -0,0 +1,35 @@
+echo on
+context none
+break p
+condition X = yes(_)
+continue
+print
+delete *
+finish 1
+break p
+condition X = yes(3)
+continue
+print
+delete *
+finish 1
+break p
+condition -v Y = yes( 3)
+continue
+print
+delete *
+finish 1
+break p
+condition -v Y^1 != 3
+continue
+print
+delete *
+finish 1
+break q
+condition -v Y != "abc "
+continue
+print
+continue
+print
+delete *
+finish 1
+continue
Index: tests/debugger/cond.m
===================================================================
RCS file: tests/debugger/cond.m
diff -N tests/debugger/cond.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/cond.m	30 Jan 2005 14:59:40 -0000
@@ -0,0 +1,62 @@
+:- module cond.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module list, int, std_util.
+
+main(!IO) :-
+	test_maybe(!IO),
+	test_maybe(!IO),
+	test_maybe(!IO),
+	test_maybe(!IO),
+	test_string(!IO).
+
+:- pred test_maybe(io::di, io::uo) is det.
+
+test_maybe(!IO) :-
+	p(no, A),
+	p(yes(2), B),
+	p(yes(3), C),
+	io__write([A, B, C], !IO),
+	io__nl(!IO).
+
+:- pred test_string(io::di, io::uo) is det.
+
+test_string(!IO) :-
+	q("abc", A),
+	io__write_string(A, !IO),
+	io__nl(!IO),
+	q("def", B),
+	io__write_string(B, !IO),
+	io__nl(!IO),
+	q("ghi", C),
+	io__write_string(C, !IO),
+	io__nl(!IO).
+
+:- pred p(maybe(int)::in, maybe(int)::out) is det.
+
+p(X, Y) :-
+	(
+		X = no,
+		Y = no
+	;
+		X = yes(Z),
+		Y = yes(Z + 1)
+	).
+
+:- pred q(string::in, string::out) is det.
+
+q(X, Y) :-
+	( X = "abc" ->
+		Y = "xabcx"
+	; X = "def" ->
+		Y = "ydefy"
+	;
+		Y = "else"
+	).
Index: tests/debugger/mdb_command_test.inp
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/debugger/mdb_command_test.inp,v
retrieving revision 1.38
diff -u -b -r1.38 mdb_command_test.inp
--- tests/debugger/mdb_command_test.inp	28 Jan 2005 01:13:32 -0000	1.38
+++ tests/debugger/mdb_command_test.inp	30 Jan 2005 19:35:53 -0000
@@ -24,6 +24,7 @@
 view                 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
 ignore               xyzzy xyzzy xyzzy xyzzy xyzzy
 break_print          xyzzy xyzzy xyzzy xyzzy xyzzy
 disable              xyzzy xyzzy xyzzy xyzzy xyzzy
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/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.190
diff -u -b -r1.190 mercury_trace_internal.c
--- trace/mercury_trace_internal.c	28 Jan 2005 02:47:43 -0000	1.190
+++ trace/mercury_trace_internal.c	30 Jan 2005 18:13:48 -0000
@@ -74,8 +74,9 @@
 #endif
 
 /* Special characters used in mdb commands. */
-#define MR_MDB_QUOTE_CHAR   '\''
-#define MR_MDB_ESCAPE_CHAR  '\\'
+#define DOUBLE_QUOTE_CHAR    '"'
+#define SINGLE_QUOTE_CHAR    '\''
+#define ESCAPE_CHAR          '\\'
 
 /* The initial size of arrays of words. */
 #define MR_INIT_WORD_COUNT  20
@@ -433,6 +434,7 @@
 static  MR_TraceCmdFunc MR_trace_cmd_view;
 static  MR_TraceCmdFunc MR_trace_cmd_save_to_file;
 static  MR_TraceCmdFunc MR_trace_cmd_break;
+static  MR_TraceCmdFunc MR_trace_cmd_condition;
 static  MR_TraceCmdFunc MR_trace_cmd_ignore;
 static  MR_TraceCmdFunc MR_trace_cmd_break_print;
 static  MR_TraceCmdFunc MR_trace_cmd_enable;
@@ -528,6 +530,10 @@
                         MR_Spy_Print_List *print_list,
                         char ***words, int *word_count,
                         const char *cat, const char *item);
+static  MR_bool     MR_trace_options_condition(int *break_num,
+                        MR_bool *require_var, MR_bool *require_path,
+                        char ***words, int *word_count, const char *cat,
+                        const char *item);
 static  MR_bool     MR_trace_options_ignore_count(
                         MR_Spy_Ignore_When *ignore_when,
                         int *ignore_count, char ***words, int *word_count,
@@ -693,7 +699,8 @@
                         MR_bool ignore_errors);
 static  void        MR_trace_source_from_open_file(FILE *fp);
 static  char        *MR_trace_getline_queue(void);
-static  MR_bool     MR_trace_continue_line(char *ptr, MR_bool *quoted);
+static  MR_bool     MR_trace_continue_line(char *ptr, MR_bool *single_quoted,
+                        MR_bool *double_quoted);
 static  MR_Code     *MR_trace_event_internal_report(MR_Trace_Cmd_Info *cmd,
                         MR_Spy_Print_List print_list,
                         MR_Event_Info *event_info);
@@ -744,6 +751,12 @@
 
     MR_trace_internal_ensure_init();
 
+    if (MR_spy_point_cond_problem != NULL) {
+        fprintf(MR_mdb_err, "mdb: couldn't evaluate break point condition.\n");
+        fprintf(MR_mdb_err, "%s\n", MR_spy_point_cond_problem);
+        MR_spy_point_cond_problem = NULL;
+    }
+
     MR_trace_event_print_internal_report(event_info);
     MR_trace_maybe_sync_source_window(event_info, MR_FALSE);
 
@@ -772,6 +785,7 @@
         line = MR_trace_get_command("mdb> ", MR_mdb_in, MR_mdb_out);
         res = MR_trace_debug_cmd(line, cmd, event_info, &event_details,
             &jumpaddr);
+        fflush(MR_mdb_err);
     } while (res == KEEP_INTERACTING);
 
     cmd->MR_trace_must_check = (! cmd->MR_trace_strict) ||
@@ -2638,6 +2652,119 @@
 }
 
 static MR_Next
+MR_trace_cmd_condition(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
+    MR_Event_Info *event_info, MR_Event_Details *event_details,
+    MR_Code **jumpaddr)
+{
+    int             break_num;
+    MR_bool         require_var;
+    MR_bool         require_path;
+    int             i;
+    const char      *problem;
+    MR_CTerm        term;
+    MR_Spy_Test     test;
+    char            *what_str;
+    char            *term_str;
+    int             len;
+    char            *rest;
+    MR_Spy_Cond     *cond;
+    MR_Var_Spec     var_spec;
+    char            *path;
+
+    break_num = MR_most_recent_spy_point;
+    require_var = MR_TRUE;
+    require_path = MR_TRUE;
+    if (! MR_trace_options_condition(&break_num, &require_var, &require_path,
+        &words, &word_count, "breakpoint", "condition"))
+    {
+        /* the usage message has already been printed */
+        return KEEP_INTERACTING;
+    } else if (word_count < 4) {
+        MR_trace_usage("breakpoint", "condition");
+        return KEEP_INTERACTING;
+    }
+
+    if (break_num < 0) {
+        fprintf(MR_mdb_err, "There is no breakpoint.\n");
+        return KEEP_INTERACTING;
+    }
+
+    if (! (0 <= break_num && break_num < MR_spy_point_next)) {
+        fprintf(MR_mdb_err, "There is no breakpoint %d.\n", break_num);
+        return KEEP_INTERACTING;
+    }
+
+    if (! MR_spy_points[break_num]->spy_exists) {
+        fprintf(MR_mdb_err, "Breakpoint %d has been deleted.\n", break_num);
+        return KEEP_INTERACTING;
+    }
+
+    cond = MR_malloc(sizeof(MR_Spy_Cond));
+
+    what_str = MR_malloc(strlen(words[1]) + 1);
+    strcpy(what_str, words[1]);
+
+    problem = MR_trace_parse_var_path(what_str, &var_spec, &path);
+    if (problem != NULL) {
+        fprintf(MR_mdb_err, "mdb: %s: %s.\n", what_str, problem);
+        return KEEP_INTERACTING;
+    }
+
+    if (MR_streq(words[2], "=") || MR_streq(words[2], "==")) {
+        test = MR_SPY_TEST_EQUAL;
+    } else if (MR_streq(words[2], "!=")) {
+        test = MR_SPY_TEST_NOT_EQUAL;
+    } else {
+        fprintf(MR_mdb_err, "invalid condition: should be = or !=\n");
+        return KEEP_INTERACTING;
+    }
+
+    len = 0;
+    for (i = 3; i < word_count; i++) {
+        len += strlen(words[i]);
+    }
+
+    term_str = MR_malloc(len + 1);
+    len = 0;
+    for (i = 3; i < word_count; i++) {
+        strcpy(term_str + len, words[i]);
+        len += strlen(words[i]);
+    }
+
+    term = MR_create_cterm(term_str, &rest);
+    if (term == NULL) {
+        fprintf(MR_mdb_out, "syntax error in term\n");
+        return KEEP_INTERACTING;
+    }
+
+    if (*rest != '\0') {
+        fprintf(MR_mdb_out, "syntax error after term\n");
+        return KEEP_INTERACTING;
+    }
+
+    if (MR_spy_points[break_num]->spy_cond != NULL) {
+        MR_delete_cterm(MR_spy_points[break_num]->spy_cond->cond_term);
+        MR_free(MR_spy_points[break_num]->spy_cond->cond_what_string);
+        MR_free(MR_spy_points[break_num]->spy_cond->cond_term_string);
+        MR_free(MR_spy_points[break_num]->spy_cond);
+    }
+
+    cond->cond_var_spec = var_spec;
+    cond->cond_path = path;
+    cond->cond_test = test;
+    cond->cond_term = term;
+    cond->cond_term_string = term_str;
+    cond->cond_what_string = what_str;
+    cond->cond_require_var = require_var;
+    cond->cond_require_path = require_path;
+
+    MR_spy_points[break_num]->spy_cond = cond;
+
+    MR_print_spy_point(MR_mdb_out, break_num, MR_TRUE);
+    return KEEP_INTERACTING;
+}
+
+static MR_Next
 MR_trace_cmd_ignore(char **words, int word_count, MR_Trace_Cmd_Info *cmd,
     MR_Event_Info *event_info, MR_Event_Details *event_details,
     MR_Code **jumpaddr)
@@ -2894,6 +3021,7 @@
         if (0 <= n && n < MR_spy_point_next && MR_spy_points[n]->spy_exists) {
             MR_spy_points[n]->spy_exists = MR_FALSE;
             MR_print_spy_point(MR_mdb_out, n, MR_FALSE);
+            MR_spy_points[n]->spy_exists = MR_TRUE;
             MR_delete_spy_point(n);
         } else {
             fflush(MR_mdb_out);
@@ -2908,6 +3036,7 @@
             if (MR_spy_points[i]->spy_exists) {
                 MR_spy_points[i]->spy_exists = MR_FALSE;
                 MR_print_spy_point(MR_mdb_out, i, MR_FALSE);
+                MR_spy_points[i]->spy_exists = MR_TRUE;
                 MR_delete_spy_point(i);
                 count++;
             }
@@ -2925,8 +3054,9 @@
             int slot;
 
             slot = MR_most_recent_spy_point;
-            MR_spy_points[slot]-> spy_exists = MR_FALSE;
+            MR_spy_points[slot]->spy_exists = MR_FALSE;
             MR_print_spy_point(MR_mdb_out, slot, MR_FALSE);
+            MR_spy_points[slot]->spy_exists = MR_TRUE;
             MR_delete_spy_point(slot);
         } else {
             fflush(MR_mdb_out);
@@ -6085,6 +6215,61 @@
     return MR_TRUE;
 }
 
+static struct MR_option MR_trace_condition_opts[] =
+{
+    { "break-num",          MR_required_argument,   NULL,   'n' },
+    { "dont-require-var",   MR_no_argument,         NULL,   'v' },
+    { "dont-require-path",  MR_no_argument,         NULL,   'p' },
+    { NULL,                 MR_no_argument,         NULL,   0 }
+};
+
+static MR_bool
+MR_trace_options_condition(int *break_num, MR_bool *require_var,
+    MR_bool *require_path, char ***words, int *word_count,
+    const char *cat, const char *item)
+{
+    int c;
+    int n;
+
+    MR_optind = 0;
+    while ((c = MR_getopt_long(*word_count, *words, "n:vp",
+        MR_trace_condition_opts, NULL)) != EOF)
+    {
+        switch (c) {
+
+            case 'n':
+                if (! MR_trace_is_natural_number(MR_optarg, &n)) {
+                    MR_trace_usage(cat, item);
+                    return MR_FALSE;
+                }
+                *break_num = n;
+                break;
+
+            case 'p':
+                *require_path = MR_FALSE;
+                break;
+
+            case 'v':
+                /*
+                ** If a variable is missing, then the path inside
+                ** is missing as well.
+                */
+
+                *require_path = MR_FALSE;
+                *require_var = 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_ignore_count_opts[] =
 {
     { "ignore-entry",       MR_required_argument,   NULL,   'E' },
@@ -7015,20 +7200,28 @@
 MR_trace_break_off_one_word(char *line, int char_pos, int *new_char_pos_ptr)
 {
     int         lag = 0;
-    MR_bool     quoted = MR_FALSE;
+    MR_bool     single_quoted = MR_FALSE;
+    MR_bool     double_quoted = MR_FALSE;
     MR_bool     another = MR_FALSE;
 
     while (line[char_pos] != '\0') {
-        if (! quoted && MR_isspace(line[char_pos])) {
+        if (! single_quoted && ! double_quoted && MR_isspace(line[char_pos])) {
             another = MR_TRUE;
             break;
         }
-        if (line[char_pos] == MR_MDB_QUOTE_CHAR) {
+
+        if (! double_quoted && line[char_pos] == SINGLE_QUOTE_CHAR) {
             lag++;
             char_pos++;
-            quoted = !quoted;
+            single_quoted = ! single_quoted;
+        } else if (! single_quoted && line[char_pos] == DOUBLE_QUOTE_CHAR) {
+            if (lag != 0) {
+                line[char_pos - lag] = line[char_pos];
+            }
+            char_pos++;
+            double_quoted = ! double_quoted;
         } else {
-            if (line[char_pos] == MR_MDB_ESCAPE_CHAR) {
+            if (line[char_pos] == ESCAPE_CHAR) {
                 lag++;
                 char_pos++;
                 if (line[char_pos] == '\0') {
@@ -7036,15 +7229,19 @@
                 }
             }
 
-            if (lag) {
+            if (lag != 0) {
                 line[char_pos - lag] = line[char_pos];
             }
             char_pos++;
         }
     }
 
-    if (quoted) {
-        return "unmatched quote";
+    if (single_quoted) {
+        return "unmatched single quote";
+    }
+
+    if (double_quoted) {
+        return "unmatched double quote";
     }
 
     line[char_pos - lag] = '\0';
@@ -7140,7 +7337,8 @@
     char        *ptr;
     char        *cmd_chars;
     int         cmd_char_max;
-    MR_bool     quoted;
+    MR_bool     single_quoted;
+    MR_bool     double_quoted;
     int         len, extra_len;
 
     line = MR_trace_getline(prompt, mdb_in, mdb_out);
@@ -7159,8 +7357,9 @@
     ptr = line;
     cmd_chars = line;
     cmd_char_max = len + 1;
-    quoted = MR_FALSE;
-    while (MR_trace_continue_line(ptr, &quoted)) {
+    single_quoted = MR_FALSE;
+    double_quoted = MR_FALSE;
+    while (MR_trace_continue_line(ptr, &single_quoted, &double_quoted)) {
         /*
         ** We were inside quotes when the end of the line was
         ** reached, or the newline was escaped, so input continues
@@ -7295,7 +7494,8 @@
 */
 
 static MR_bool
-MR_trace_continue_line(char *ptr, MR_bool *quoted)
+MR_trace_continue_line(char *ptr, MR_bool *single_quoted,
+    MR_bool *double_quoted)
 {
     MR_bool     escaped = MR_FALSE;
 
@@ -7303,11 +7503,13 @@
         if (escaped) {
             /* do nothing special */
             escaped = MR_FALSE;
-        } else if (*ptr == MR_MDB_ESCAPE_CHAR) {
+        } else if (*ptr == ESCAPE_CHAR) {
             escaped = MR_TRUE;
-        } else if (*ptr == MR_MDB_QUOTE_CHAR) {
-            *quoted = !(*quoted);
-        } else if (!(*quoted) && *ptr == ';') {
+        } else if (! (*double_quoted) && *ptr == SINGLE_QUOTE_CHAR) {
+            *single_quoted = ! (*single_quoted);
+        } else if (! (*single_quoted) && *ptr == DOUBLE_QUOTE_CHAR) {
+            *double_quoted = ! (*double_quoted);
+        } else if (! (*single_quoted) && ! (*double_quoted) && *ptr == ';') {
             /*
             ** The line contains at least two commands.
             ** Return only the first command now; put the
@@ -7328,7 +7530,7 @@
         *(ptr - 1) = ' ';
     }
 
-    return (*quoted || escaped);
+    return (*single_quoted || *double_quoted || escaped);
 }
 
 static MR_Code *
@@ -7591,6 +7793,8 @@
 
     { "breakpoint", "break", MR_trace_cmd_break,
         MR_trace_break_cmd_args, MR_trace_breakpoint_completer },
+    { "breakpoint", "condition", MR_trace_cmd_condition,
+        NULL, MR_trace_null_completer },
     { "breakpoint", "ignore", MR_trace_cmd_ignore,
         MR_trace_ignore_cmd_args, MR_trace_null_completer },
     { "breakpoint", "break_print", MR_trace_cmd_break_print,
Index: trace/mercury_trace_spy.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_spy.c,v
retrieving revision 1.23
diff -u -b -r1.23 mercury_trace_spy.c
--- trace/mercury_trace_spy.c	28 Jan 2005 02:46:44 -0000	1.23
+++ trace/mercury_trace_spy.c	30 Jan 2005 17:33:23 -0000
@@ -16,11 +16,16 @@
 
 #include "mercury_imp.h"
 #include "mercury_array_macros.h"
+#include "mercury_layout_util.h"
 #include "mercury_trace_base.h"
 
 #include "mercury_trace.h"
 #include "mercury_trace_spy.h"
 #include "mercury_trace_tables.h"
+#include "mercury_trace_util.h"
+#include "mercury_trace_vars.h"
+
+#include "mdb.cterm.mh"
 
 #include <stdlib.h>
 
@@ -102,6 +107,8 @@
 static  int         MR_search_spy_table_for_proc(const MR_Proc_Layout *entry);
 static  int         MR_search_spy_table_for_label(
                         const MR_Label_Layout *label);
+static  MR_bool     MR_spy_cond_is_true(MR_Spy_Point *point,
+                        const MR_Label_Layout *label);
 static  void        MR_add_line_spy_point_callback(
                         const MR_Label_Layout *label, int spy_point_num);
 static  int         MR_compare_spied_labels(const void *, const void *);
@@ -202,11 +209,13 @@
                 MR_fatal_error("non-lineno spy point in spied labels array");
             }
 
+            if (MR_spy_cond_is_true(point, layout)) {
             MR_update_enabled_action(point, port, &action, &enabled);
             if (*print_list == NULL) {
                 *print_list = point->spy_print_list;
             }
         }
+        }
 
         if (MR_port_is_interface(port)) {
             MR_restore_transient_registers();
@@ -223,6 +232,7 @@
                         "spied labels array");
                 }
 
+                if (MR_spy_cond_is_true(point, layout)) {
                 MR_update_enabled_action(point, port, &action, &enabled);
                 if (*print_list == NULL) {
                     *print_list = point->spy_print_list;
@@ -230,6 +240,7 @@
             }
         }
     }
+    }
 
     slot = MR_search_spy_table_for_proc(layout->MR_sll_entry);
     if (slot >= 0) {
@@ -239,19 +250,24 @@
             switch (point->spy_when) {
 
                 case MR_SPY_ALL:
-                    MR_update_enabled_action(point, port, &action, &enabled);
+                    if (MR_spy_cond_is_true(point, layout)) {
+                        MR_update_enabled_action(point, port, &action,
+                            &enabled);
                     if (*print_list == NULL) {
                         *print_list = point->spy_print_list;
                     }
+                    }
                 break;
 
                 case MR_SPY_ENTRY:
                     if (MR_port_is_entry(port)) {
+                        if (MR_spy_cond_is_true(point, layout)) {
                         MR_update_enabled_action(point, port, &action,
                             &enabled);
                         if (*print_list == NULL) {
                             *print_list = point->spy_print_list;
                         }
+                        }
                     } else {
                         continue;
                     }
@@ -260,11 +276,13 @@
 
                 case MR_SPY_INTERFACE:
                     if (MR_port_is_interface(port)) {
+                        if (MR_spy_cond_is_true(point, layout)) {
                         MR_update_enabled_action(point, port, &action,
                             &enabled);
                         if (*print_list == NULL) {
                             *print_list = point->spy_print_list;
                         }
+                        }
                     } else {
                         continue;
                     }
@@ -273,11 +291,13 @@
 
                 case MR_SPY_SPECIFIC:
                     if (layout == point->spy_label) {
+                        if (MR_spy_cond_is_true(point, layout)) {
                         MR_update_enabled_action(point, port, &action,
                             &enabled);
                         if (*print_list == NULL) {
                             *print_list = point->spy_print_list;
                         }
+                        }
                     } else {
                         continue;
                     }
@@ -338,6 +358,129 @@
     }
 }
 
+const char  *MR_spy_point_cond_problem = NULL;
+
+static MR_bool
+MR_spy_cond_is_true(MR_Spy_Point *point, const MR_Label_Layout *label_layout)
+{
+    int             max_mr_num;
+    MR_Word         saved_regs[MR_MAX_FAKE_REG];
+    MR_Var_Spec     var_spec;
+    char            *path;
+    const char      *problem;
+    char            *bad_path;
+    MR_TypeInfo     type_info;
+    MR_Word         value;
+    MR_Word         *value_ptr;
+    MR_TypeInfo     sub_type_info;
+    MR_Word         *sub_value_ptr;
+    MR_Word         match;
+    MR_bool         saved_trace_func_enabled;
+    MR_bool         retval;
+    MR_Spy_Cond     *cond;
+
+    if (point->spy_cond == NULL) {
+        return MR_TRUE;
+    }
+
+    MR_restore_transient_registers();
+
+    cond = point->spy_cond;
+
+    /*
+    ** From this point, returning should be done by setting both
+    ** MR_spy_point_cond_problem and retval, and goto end.
+    */
+
+    MR_spy_point_cond_problem = "internal error in MR_spy_cond_is_true";
+    retval = MR_TRUE;
+
+    MR_compute_max_mr_num(max_mr_num, label_layout);
+    /* This also saves the regs in MR_fake_regs. */
+    MR_copy_regs_to_saved_regs(max_mr_num, saved_regs);
+    MR_trace_init_point_vars(label_layout, saved_regs,
+        (MR_Trace_Port) label_layout->MR_sll_port, MR_FALSE);
+
+    problem = MR_lookup_unambiguous_var_spec(cond->cond_var_spec,
+        &type_info, &value);
+    if (problem != NULL) {
+        if (cond->cond_require_var) {
+            MR_spy_point_cond_problem = problem;
+            retval = MR_TRUE;
+        } else {
+            MR_spy_point_cond_problem = NULL;
+            retval = MR_FALSE;
+        }
+
+        goto end;
+    }
+
+    value_ptr = &value;
+    bad_path = MR_select_specified_subterm(cond->cond_path,
+        type_info, value_ptr, &sub_type_info, &sub_value_ptr);
+
+    if (bad_path != NULL) {
+        if (cond->cond_require_var) {
+            MR_spy_point_cond_problem = MR_trace_bad_path(bad_path);
+            retval = MR_TRUE;
+        } else {
+            MR_spy_point_cond_problem = NULL;
+            retval = MR_FALSE;
+        }
+        goto end;
+    }
+
+#ifdef MR_DEBUG_SPY_COND
+    MR_print_cterm(stdout, cond->cond_term);
+    fprintf(stdout, ": ");
+#endif
+
+    saved_trace_func_enabled = MR_trace_func_enabled;
+    MR_trace_func_enabled = MR_FALSE;
+    MR_TRACE_CALL_MERCURY(
+        ML_BROWSE_match_with_cterm((MR_Word) sub_type_info, *sub_value_ptr,
+            cond->cond_term, &match);
+    );
+    MR_trace_func_enabled = saved_trace_func_enabled;
+
+#ifdef MR_DEBUG_SPY_COND
+    fprintf(stdout, "%d\n", match);
+#endif
+
+    switch (cond->cond_test) {
+        case MR_SPY_TEST_EQUAL:
+            MR_spy_point_cond_problem = NULL;
+            if (match != 0) {
+                retval = MR_TRUE;
+                goto end;
+            } else {
+                retval = MR_FALSE;
+                goto end;
+            }
+            break;
+
+        case MR_SPY_TEST_NOT_EQUAL:
+            MR_spy_point_cond_problem = NULL;
+            if (match != 0) {
+                retval = MR_FALSE;
+                goto end;
+            } else {
+                retval = MR_TRUE;
+                goto end;
+            }
+            break;
+
+        default:
+            MR_fatal_error("MR_spy_cond_is_true: invalid spy_cond_test");
+            break;
+    }
+
+end:
+    MR_copy_saved_regs_to_regs(max_mr_num, saved_regs);
+    MR_save_transient_registers();
+    return retval;
+}
+
 static const char *incompatible =
     "Ignore count is not compatible with break point specification";
 
@@ -373,6 +516,7 @@
     point->spy_action  = action;
     point->spy_ignore_when  = ignore_when;
     point->spy_ignore_count = ignore_count;
+    point->spy_cond    = NULL;
     point->spy_print_list   = print_list;
     point->spy_proc    = entry;
     point->spy_label   = label;
@@ -381,6 +525,7 @@
 
     for (i = 0; i < MR_spy_point_next; i++) {
         if (! MR_spy_points[i]->spy_exists) {
+            MR_most_recent_spy_point = i;
             MR_spy_points[i] = point;
             return i;
         }
@@ -462,6 +607,7 @@
     point->spy_action     = action;
     point->spy_ignore_when  = ignore_when;
     point->spy_ignore_count = ignore_count;
+    point->spy_cond       = NULL;
     point->spy_print_list = print_list;
     point->spy_filename   = filename;
     point->spy_linenumber = linenumber;
@@ -604,7 +750,25 @@
         MR_most_recent_spy_point = -1;
     }
 
+    if (! MR_spy_points[point_table_slot]->spy_exists) {
+        return;
+    }
+
+    MR_spy_points[point_table_slot]->spy_exists = MR_FALSE;
+
     MR_delete_spy_print_list(point->spy_print_list);
+    /* in case it gets deleted again */
+    point->spy_print_list = NULL;
+
+    if (point->spy_cond != NULL) {
+        MR_delete_cterm(point->spy_cond->cond_term);
+        MR_free(point->spy_cond->cond_what_string);
+        MR_free(point->spy_cond->cond_term_string);
+        MR_free(point->spy_cond);
+
+        /* in case it gets deleted again */
+        point->spy_cond = NULL;
+    }
 
     if (point->spy_when == MR_SPY_LINENO) {
         /* Release the storage acquired by MR_copy_string. */
@@ -656,6 +820,7 @@
 MR_print_spy_point(FILE *fp, int spy_point_num, MR_bool verbose)
 {
     MR_Spy_Point    *point;
+    MR_Spy_Cond     *cond;
 
     point = MR_spy_points[spy_point_num];
     fprintf(fp, "%2d: %1s %-5s %9s ",
@@ -679,6 +844,55 @@
         fprintf(fp, "\n%12s(ignore next %s event)\n",
             "", MR_ignore_when_to_string(point->spy_ignore_when));
     } else {
+        fprintf(fp, "\n");
+    }
+
+    if (point->spy_cond != NULL) {
+        cond = point->spy_cond;
+
+        fprintf(fp, "%12s", "");
+
+        if (! cond->cond_require_var) {
+            fprintf(fp, "-v ");
+        }
+
+        if (! cond->cond_require_path) {
+            fprintf(fp, "-p ");
+        }
+
+        switch (cond->cond_var_spec.MR_var_spec_kind) {
+            case MR_VAR_SPEC_NUMBER:
+                fprintf(fp, "%d", cond->cond_var_spec.MR_var_spec_number);
+                break;
+
+            case MR_VAR_SPEC_NAME:
+                fprintf(fp, "%s", cond->cond_var_spec.MR_var_spec_name);
+                break;
+
+            default:
+                MR_fatal_error("MR_print_spy_point: invalid cond_what");
+                break;
+        }
+
+        if (cond->cond_path != NULL) {
+            fprintf(fp, " ^%s", cond->cond_path);
+        }
+
+        switch (cond->cond_test) {
+            case MR_SPY_TEST_EQUAL:
+                fprintf(fp, " = ");
+                break;
+
+            case MR_SPY_TEST_NOT_EQUAL:
+                fprintf(fp, " != ");
+                break;
+
+            default:
+                MR_fatal_error("MR_print_spy_point: invalid cond_test");
+                break;
+        }
+
+        MR_print_cterm(fp, cond->cond_term);
         fprintf(fp, "\n");
     }
 
Index: trace/mercury_trace_spy.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_spy.h,v
retrieving revision 1.10
diff -u -b -r1.10 mercury_trace_spy.h
--- trace/mercury_trace_spy.h	27 Jan 2005 06:17:41 -0000	1.10
+++ trace/mercury_trace_spy.h	30 Jan 2005 16:25:20 -0000
@@ -15,8 +15,10 @@
 #define	MERCURY_TRACE_SPY_H
 
 #include "mercury_stack_layout.h"	/* for MR_Proc_Layout etc */
+#include "mercury_trace_term.h"		/* for MR_CTerm */
 #include "mercury_trace_base.h"		/* for MR_Trace_Port etc  */
 #include "mercury_trace_browse.h"	/* for MR_Browse_Format */
+#include "mercury_trace_vars.h"		/* for MR_Var_Spec */
 
 typedef enum {
 	MR_SPY_PRINT, MR_SPY_STOP
@@ -46,6 +48,10 @@
 typedef	struct MR_Spy_Print_List_Struct	*MR_Spy_Print_List;
 
 typedef enum {
+	MR_SPY_TEST_EQUAL, MR_SPY_TEST_NOT_EQUAL
+} MR_Spy_Test;
+
+typedef enum {
 	MR_SPY_PRINT_GOAL,
 	MR_SPY_PRINT_ALL,
 	MR_SPY_PRINT_ONE,
@@ -65,6 +71,17 @@
 
 typedef struct MR_Spy_Point_Struct MR_Spy_Point;
 
+typedef struct {
+	MR_Var_Spec		cond_var_spec;
+	char			*cond_path;
+	MR_Spy_Test		cond_test;
+	MR_CTerm		cond_term;
+	MR_bool			cond_require_var;
+	MR_bool			cond_require_path;
+	char			*cond_what_string;
+	char			*cond_term_string;
+} MR_Spy_Cond;
+
 struct MR_Spy_Point_Struct {
 	MR_bool			spy_exists;	/* MR_FALSE if deleted */
 	MR_bool			spy_enabled;
@@ -72,6 +89,7 @@
 	MR_Spy_Action		spy_action;
 	MR_Spy_Ignore_When	spy_ignore_when;
 	int			spy_ignore_count;
+	MR_Spy_Cond		*spy_cond;
 	MR_Spy_Print_List	spy_print_list;
 	const MR_Proc_Layout	*spy_proc;      /* if not LINENO */
 	const MR_Label_Layout	*spy_label;	/* if SPECIFIC */
@@ -90,6 +108,8 @@
 extern	int		MR_spy_point_max;
 
 extern	int		MR_most_recent_spy_point;
+
+extern	const char	*MR_spy_point_cond_problem;
 
 /*
 ** Check whether the event described by the given label layout and port
Index: trace/mercury_trace_vars.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_vars.c,v
retrieving revision 1.60
diff -u -b -r1.60 mercury_trace_vars.c
--- trace/mercury_trace_vars.c	28 Jan 2005 02:47:44 -0000	1.60
+++ trace/mercury_trace_vars.c	30 Jan 2005 06:47:43 -0000
@@ -138,7 +138,6 @@
                             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  const char *    MR_trace_bad_path(const char *path);
 static  int             MR_trace_print_var_name(FILE *out,
                             MR_Var_Details *var);
 static  const char *    MR_trace_valid_var_number(int var_number);
@@ -935,21 +934,17 @@
 }
 
 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)
+MR_trace_parse_var_path(char *word_spec, MR_Var_Spec *var_spec, char **path)
 {
-    MR_Var_Spec var_spec;
-    char        *path;
     char        *s;
-    int         n;
+    char    *start;
 
     s = strpbrk(word_spec, "^/");
 
     if (s == NULL) {
-        path = NULL;
+        *path = NULL;
     } else {
-        path = s;
+        start = s;
 
         do {
             if (*s == '^' || *s == '/') {
@@ -973,11 +968,27 @@
             }
         } while (*s != '\0');
 
-        *path = '\0';
-        path++;
+        *start = '\0';
+        *path = start+1;
     }
 
-    MR_convert_arg_to_var_spec(word_spec, &var_spec);
+    MR_convert_arg_to_var_spec(word_spec, var_spec);
+    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)
+{
+    MR_Var_Spec var_spec;
+    char        *path;
+    const char  *problem;
+
+    problem = MR_trace_parse_var_path(word_spec, &var_spec, &path);
+    if (problem != NULL) {
+        return problem;
+    }
 
     return MR_trace_browse_one_path(out, print_var_name, var_spec, path,
         browser, caller, format, must_be_unique);
@@ -992,25 +1003,47 @@
         browser, caller, format, must_be_unique);
 }
 
+const char *
+MR_lookup_unambiguous_var_spec(MR_Var_Spec var_spec,
+    MR_TypeInfo *type_info, MR_Word *value)
+{
+    int         var_num;
+    MR_bool     is_ambiguous;
+    const char  *problem;
+
+    problem = MR_lookup_var_spec(var_spec, &var_num, &is_ambiguous);
+    if (problem != NULL) {
+        return problem;
+    }
+
+    if (is_ambiguous) {
+        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;
+}
+
 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)
 {
-    int         i;
+    int         var_num;
     MR_bool     is_ambiguous;
     const char  *problem;
     char        *bad_path;
 
-    problem = MR_lookup_var_spec(var_spec, &i, &is_ambiguous);
+    problem = MR_lookup_var_spec(var_spec, &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[i], path, browser, caller, format);
+            &MR_point.MR_point_vars[var_num], path, browser, caller, format);
         if (bad_path != NULL) {
             return MR_trace_bad_path(bad_path);
         }
@@ -1024,16 +1057,17 @@
         success_count = 0;
         do {
             bad_path = MR_trace_browse_var(out, print_var_name,
-                &MR_point.MR_point_vars[i], path, browser, caller, format);
+                &MR_point.MR_point_vars[var_num], path, browser, caller,
+                format);
 
             if (bad_path == NULL) {
                 success_count++;
             }
 
-            i++;
-        } while (i < MR_point.MR_point_var_count &&
+            var_num++;
+        } while (var_num < MR_point.MR_point_var_count &&
             MR_streq(var_spec.MR_var_spec_name,
-            MR_point.MR_point_vars[i].MR_var_fullname));
+            MR_point.MR_point_vars[var_num].MR_var_fullname));
 
         if (success_count == 0) {
             return "the selected path does not exist "
@@ -1053,13 +1087,13 @@
 
 #else
 
-    int         i;
+    int         var_num;
     MR_bool     is_ambiguous;
     const char  *problem;
     MR_Var_Spec var_spec;
 
     MR_convert_arg_to_var_spec(word_spec, &var_spec);
-    problem = MR_lookup_var_spec(var_spec, &i, &is_ambiguous);
+    problem = MR_lookup_var_spec(var_spec, &var_num, &is_ambiguous);
     if (problem != NULL) {
         return problem;
     }
@@ -1067,18 +1101,18 @@
     if (is_ambiguous) {
         do {
             fprintf(out, "%20s: %6u\n",
-                MR_point.MR_point_vars[i].MR_var_fullname,
-                MR_term_size(MR_point.MR_point_vars[i].MR_var_type,
-                    MR_point.MR_point_vars[i].MR_var_value));
-            i++;
-        } while (i < MR_point.MR_point_var_count &&
+                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));
+            var_num++;
+        } while (var_num < MR_point.MR_point_var_count &&
             MR_streq(var_spec.MR_var_spec_name,
-            MR_point.MR_point_vars[i].MR_var_fullname));
+            MR_point.MR_point_vars[var_num].MR_var_fullname));
     } else {
         fprintf(out, "%20s: %6u\n",
-            MR_point.MR_point_vars[i].MR_var_fullname,
-            MR_term_size(MR_point.MR_point_vars[i].MR_var_type,
-                MR_point.MR_point_vars[i].MR_var_value));
+            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));
     }
 
     return NULL;
@@ -1092,18 +1126,18 @@
 #ifndef MR_RECORD_TERM_SIZES
     return "term sizes not available in this grade";
 #else
-    int         i;
+    int         var_num;
     const char  *problem;
 
     if (MR_point.MR_point_problem != NULL) {
         return MR_point.MR_point_problem;
     }
 
-    for (i = 0; i < MR_point.MR_point_var_count; i++) {
+    for (var_num = 0; var_num < MR_point.MR_point_var_count; var_num++) {
         fprintf(out, "%-20s %6u\n",
-            MR_point.MR_point_vars[i].MR_var_fullname,
-            MR_term_size(MR_point.MR_point_vars[i].MR_var_type,
-                MR_point.MR_point_vars[i].MR_var_value));
+            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));
     }
 
     return NULL;
@@ -1114,7 +1148,7 @@
 #define BAD_PATH_MSG_PREFIX     "the path "
 #define BAD_PATH_MSG_SUFFIX     " does not exist"
 
-static const char *
+const char *
 MR_trace_bad_path(const char *path)
 {
     static  char    buffer[BAD_PATH_BUFFER_SIZE];
@@ -1133,7 +1167,7 @@
 const char *
 MR_trace_browse_all(FILE *out, MR_Browser browser, MR_Browse_Format format)
 {
-    int i;
+    int var_num;
 
     if (MR_point.MR_point_problem != NULL) {
         return MR_point.MR_point_problem;
@@ -1143,9 +1177,10 @@
         fprintf(out, "mdb: there are no live variables.\n");
     }
 
-    for (i = 0; i < MR_point.MR_point_var_count; i++) {
-        (void) MR_trace_browse_var(out, MR_TRUE, &MR_point.MR_point_vars[i],
-            NULL, browser, MR_BROWSE_CALLER_PRINT_ALL, format);
+    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);
     }
 
     return NULL;
@@ -1167,24 +1202,22 @@
     return MR_trace_browse_all(out, MR_trace_print, MR_BROWSE_DEFAULT_FORMAT);
 }
 
-static char *
-MR_trace_browse_var(FILE *out, MR_bool print_var_name, MR_Var_Details *var,
-    char *path, MR_Browser browser, MR_Browse_Caller_Type caller,
-    MR_Browse_Format format)
+char *
+MR_select_specified_subterm(char *path, MR_TypeInfo type_info, MR_Word *value,
+    MR_TypeInfo *sub_type_info, MR_Word **sub_value)
 {
-    MR_TypeInfo typeinfo;
-    MR_TypeInfo new_typeinfo;
-    MR_Word     *value;
+    MR_TypeInfo new_type_info;
     MR_Word     *new_value;
     char        *old_path;
     int         arg_num;
     int         len;
-    MR_bool     saved_io_tabling_enabled;
 
-    typeinfo = var->MR_var_type;
-    value = &var->MR_var_value;
+    if (path == NULL) {
+        *sub_value = value;
+        *sub_type_info = type_info;
+        return NULL;
+    }
 
-    if (path != NULL) {
         while (*path != '\0') {
             old_path = path;
 
@@ -1210,7 +1243,7 @@
                 saved_char = *path;
                 *path = '\0';
 
-                if (! MR_named_arg_num(typeinfo, value, old_path, &arg_num))
+            if (! MR_named_arg_num(type_info, value, old_path, &arg_num))
                 {
                     *path = saved_char;
                     return old_path;
@@ -1224,15 +1257,37 @@
                 path++; /* step over / or ^ */
             }
 
-            if (MR_arg(typeinfo, value, arg_num, &new_typeinfo,
-                &new_value, MR_NONCANON_CC))
+        if (MR_arg(type_info, value, arg_num, &new_type_info, &new_value,
+            MR_NONCANON_CC))
             {
-                typeinfo = new_typeinfo;
+            type_info = new_type_info;
                 value = new_value;
             } else {
                 return old_path;
             }
         }
+
+    *sub_value = value;
+    *sub_type_info = type_info;
+    return NULL;
+}
+
+static char *
+MR_trace_browse_var(FILE *out, MR_bool print_var_name, MR_Var_Details *var,
+    char *path, MR_Browser browser, MR_Browse_Caller_Type caller,
+    MR_Browse_Format format)
+{
+    MR_TypeInfo type_info;
+    MR_Word     *value;
+    int         len;
+    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);
+
+    if (bad_path != NULL) {
+        return bad_path;
     }
 
     if (print_var_name) {
@@ -1262,7 +1317,7 @@
 
     saved_io_tabling_enabled = MR_io_tabling_enabled;
     MR_io_tabling_enabled = MR_FALSE;
-    (*browser)((MR_Word) typeinfo, *value, caller, format);
+    (*browser)((MR_Word) type_info, *value, caller, format);
     MR_io_tabling_enabled = saved_io_tabling_enabled;
     return NULL;
 }
Index: trace/mercury_trace_vars.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_vars.h,v
retrieving revision 1.26
diff -u -b -r1.26 mercury_trace_vars.h
--- trace/mercury_trace_vars.h	19 Jul 2004 03:37:55 -0000	1.26
+++ trace/mercury_trace_vars.h	30 Jan 2005 06:14:36 -0000
@@ -30,9 +30,10 @@
 ** in the third set.
 **
 ** The functions MR_trace_var_count, MR_trace_list_vars,
-** MR_trace_return_var_info, MR_trace_headvar_num, MR_trace_parse_browse_one,
-** MR_trace_browse_one and MR_trace_browse_all all work in the context
-** established by MR_trace_init_point_vars and possibly MR_trace_set_level.
+** MR_trace_return_var_info, MR_trace_headvar_num, MR_trace_parse_var_path,
+** MR_trace_parse_browse_one, MR_trace_browse_one and MR_trace_browse_all
+** all work in the context established by MR_trace_init_point_vars and
+** possibly MR_trace_set_level.
 **
 ** This context may say that there is no information available about
 ** the variables live at the current location (this is possible if the
@@ -181,8 +182,19 @@
 				MR_Browse_Format format);
 
 /*
+** Parse the given word into a variable specification and the specification
+** of a path within that 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 is specified by zero or more suffixes of the form
+** ^argnum or /argnum.
+*/
+
+extern	const char	*MR_trace_parse_var_path(char *word_spec,
+				MR_Var_Spec *var_spec, char **path);
+
+/*
 ** Print the (names and) values of (the specified parts of) the specified
-** variables. (The variable is specified by either its name or its sequence
+** 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
 ** is specified by zero or more suffixes of the form ^argnum or /argnum.
 **
@@ -230,6 +242,7 @@
 extern	const char 	*MR_trace_browse_all(FILE *out, MR_Browser browser,
 				MR_Browse_Format format);
 
+
 /*
 ** Sets the current set of variables to be ones live at the program point
 ** referred to by level_layout, base_sp and base_curfr arguments, and then
@@ -242,6 +255,33 @@
 				const MR_Label_Layout *level_layout,
 				MR_Word *base_sp, MR_Word *base_curfr,
 				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.
+*/
+
+extern	const char	*MR_lookup_unambiguous_var_spec(MR_Var_Spec var_spec,
+				MR_TypeInfo *type_info, MR_Word *value);
+
+/*
+** *value and type_info describe a term, and path specifies a subterm of that
+** term. If the path is valid, return NULL and put the specified subterm in
+** *sub_value and **sub_type_info. If it is not valid, return the invalid part
+** of the path specification. This can be turned into an error message with
+** MR_trace_bad_path.
+*/
+
+extern	char		*MR_select_specified_subterm(char *path,
+				MR_TypeInfo type_info, MR_Word *value,
+				MR_TypeInfo *sub_type_info,
+				MR_Word **sub_value);
+
+/*
+** Given an invalid path specification, return an error message for that error.
+*/
+
+extern	const char	*MR_trace_bad_path(const char *path); 
 
 /*
 ** Print the size of the specified variable(s) to the specified file.
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