[m-rev.] for review: better error messages for overloaded types

Zoltan Somogyi zs at cs.mu.OZ.AU
Fri Aug 3 14:55:31 AEST 2001


For review by Fergus.

compiler/typecheck.m:
	When printing messages about errors involving overloaded types,
	print each type only once.

	When a variable has more than one type, print each type on a line of
	its own, to make the output easier to read. (Since type names currently
	have too many parentheses, further improvements are still possible.)

compiler/mercury_to_mercury.m:
	Provide a mechanism to turn a type into a string without printing it,
	so that it can be checked againt the representations of other types.

	This required changing many of the predicates in this module so that
	instead of doing I/O directly, they go through a typeclass interface
	which has two implementations: one does I/O while the other gathers
	output in a string.

	The performance impact of this change should be acceptable, since I/O
	is slow compared to computation anyway.

compiler/purity.m:
	Provide a predicate that returns a purity prefix as a string, to
	accompany another that prints it out.

compiler/check_typeclass.m:
compiler/prog_util.m:
	Minor changes to conform to the naming scheme now used in
	mercury_to_mercury.m, in particular to the fact the operations of the
	form x_to_string are now functions, not predicates.

	The functionality of prog_util should be unaffected. In check_typeclass
	we may now print more detailed error messages than before.

library/string.m:
	Declare the outputs append, append_list and join_list to be unique.
	Their implementations already return unique strings; declaring them to
	be unique help avoid redundant copying in mercury_to_mercury.m.

library/term_io.m:
	Add alternative versions of some output predicates that return their
	"output" in a string instead.

	Factor out some common code.

tests/invalid/overloading.{m,exp}:
	A test exercising the error message affected by the change.

tests/invalid/Mmakefile:
	Enable the new test.

Zoltan.

cvs diff: Diffing .
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
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/check_typeclass.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/check_typeclass.m,v
retrieving revision 1.43
diff -u -b -r1.43 check_typeclass.m
--- compiler/check_typeclass.m	2001/07/03 02:49:22	1.43
+++ compiler/check_typeclass.m	2001/08/02 13:33:09
@@ -543,8 +543,8 @@
 		prog_out__sym_name_to_string(ClassName, ClassNameString),
 		pred_or_func_to_string(PredOrFunc, PredOrFuncString),
 		string__int_to_string(Arity, ArityString),
-		mercury_type_list_to_string(InstanceVarSet, InstanceTypes,
-			InstanceTypesString),
+		InstanceTypesString = mercury_type_list_to_string(
+			InstanceVarSet, InstanceTypes),
 		string__append_list([
 			"In instance declaration for `",
 			ClassNameString, "(", InstanceTypesString, ")': ",
@@ -581,8 +581,8 @@
 		prog_out__sym_name_to_string(ClassName, ClassNameString),
 		pred_or_func_to_string(PredOrFunc, PredOrFuncString),
 		string__int_to_string(Arity, ArityString),
-		mercury_type_list_to_string(InstanceVarSet, InstanceTypes,
-			InstanceTypesString),
+		InstanceTypesString = mercury_type_list_to_string(
+			InstanceVarSet, InstanceTypes),
 		string__append_list([
 			"In instance declaration for `",
 			ClassNameString, "(", InstanceTypesString, ")': ",
@@ -881,8 +881,8 @@
 	;
 		ClassId = class_id(ClassName, _ClassArity),
 		prog_out__sym_name_to_string(ClassName, ClassNameString),
-		mercury_type_list_to_string(InstanceVarSet2, InstanceTypes,
-			InstanceTypesString),
+		InstanceTypesString = mercury_type_list_to_string(
+			InstanceVarSet2, InstanceTypes),
 		constraint_list_to_string(ClassVarSet, UnprovenConstraints, 
 			ConstraintsString),
 		string__append_list([
@@ -900,7 +900,7 @@
 
 constraint_list_to_string(_, [], "").
 constraint_list_to_string(VarSet, [C|Cs], String) :-
-	mercury_constraint_to_string(VarSet, C, String0),
+	String0 = mercury_constraint_to_string(VarSet, C),
 	constraint_list_to_string_2(VarSet, Cs, String1),
 	string__append_list(["`", String0, "'", String1], String).
 
@@ -909,7 +909,7 @@
 
 constraint_list_to_string_2(_VarSet, [], "").
 constraint_list_to_string_2(VarSet, [C|Cs], String) :-
-	mercury_constraint_to_string(VarSet, C, String0),
+	String0 = mercury_constraint_to_string(VarSet, C),
 	constraint_list_to_string_2(VarSet, Cs, String1),
 	string__append_list([", `", String0, "'", String1], String).
 
Index: compiler/mercury_to_mercury.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_to_mercury.m,v
retrieving revision 1.190
diff -u -b -r1.190 mercury_to_mercury.m
--- compiler/mercury_to_mercury.m	2001/07/31 16:26:02	1.190
+++ compiler/mercury_to_mercury.m	2001/08/03 04:43:52
@@ -8,6 +8,34 @@
 
 % This program converts the parse tree structure provided by prog_io
 % back into Mercury source text.
+%
+% Many (though not all) of the procedures in this module come in
+% groups of three, where the three follow the pattern:
+%
+%	:- pred mercury_output_xyz(..., io__state::di, io__state::uo) is det.
+%	:- func mercury_xyz_to_string(...) = string.
+%	:- pred mercury_format_xyz(..., U::di, U::uo) is det <= output(U).
+%
+% The first two simply forward all the work to the third. This is possible
+% because both io__state and string are members of the required typeclass,
+% which is defined at the end of this module.
+%
+% For the mercury_output_xyz versions, going through a typeclass interface is
+% (for now) a slight slowdown, but the time cost is still small compared to
+% the cost of I/O itself.
+%
+% For the mercury_xyz_to_string versions, the cost is acceptable because
+% (for now) we only create relatively small strings this way, e.g. strings that
+% go into error messages. The typeclass instance for strings has a quadratic
+% complexity in the number of strings being appended but a reasonably low
+% constant factor. If we ever want to use these functions to create long
+% strings (longer than a few lines), then we should use a typeclass
+% instance implementation that represents the entity being converted to string
+% as a list of strings that must be conceatenated together at the end using
+% string__append_list (probably after being un-reversed, so that you can
+% represent appending to the string by consing onto the front of the list).
+% The complexity of an implementation like that can be linear in the size
+% of the string being built, although it will have a higher constant factor.
 
 %-----------------------------------------------------------------------------%
 
@@ -47,6 +75,10 @@
 :- mode mercury_output_pred_type(in, in, in, in, in, in, in, in, in,
 		di, uo) is det.
 
+:- func mercury_pred_type_to_string(tvarset, existq_tvars, sym_name,
+	list(type), maybe(determinism), purity, class_constraints,
+	prog_context, bool) = string.
+
 	% Output a `:- func' declaration, making sure that the variable
 	% number appears in variable names if the boolean argument
 	% is set to `yes'.
@@ -57,31 +89,53 @@
 :- mode mercury_output_func_type(in, in, in, in, in, in, in, in, in, in,
 		di, uo) is det.
 
+:- func mercury_func_type_to_string(tvarset, existq_tvars, sym_name,
+	list(type), type, maybe(determinism), purity, class_constraints,
+	prog_context, bool) = string.
+
 :- pred mercury_output_pred_mode_decl(inst_varset, sym_name, list(mode),
 		maybe(determinism), prog_context, io__state, io__state).
 :- mode mercury_output_pred_mode_decl(in, in, in, in, in, di, uo) is det.
 
+:- func mercury_pred_mode_decl_to_string(inst_varset, sym_name, list(mode),
+	maybe(determinism), prog_context) = string.
+
 :- pred mercury_output_func_mode_decl(inst_varset, sym_name, list(mode), mode,
 		maybe(determinism), prog_context, io__state, io__state).
 :- mode mercury_output_func_mode_decl(in, in, in, in, in, in, di, uo) is det.
 
+:- func mercury_func_mode_decl_to_string(inst_varset, sym_name, list(mode),
+	mode, maybe(determinism), prog_context) = string.
+
 :- pred mercury_output_mode_subdecl(pred_or_func, inst_varset, sym_name,
 		list(mode), maybe(determinism), prog_context,
 		io__state, io__state).
 :- mode mercury_output_mode_subdecl(in, in, in, in, in, in, di, uo) is det.
 
+:- func mercury_mode_subdecl_to_string(pred_or_func, inst_varset, sym_name,
+	list(mode), maybe(determinism), prog_context) = string.
+
 :- pred mercury_output_pred_mode_subdecl(inst_varset, sym_name, list(mode),
 		maybe(determinism), prog_context, io__state, io__state).
 :- mode mercury_output_pred_mode_subdecl(in, in, in, in, in, di, uo) is det.
 
+:- func mercury_pred_mode_subdecl_to_string(inst_varset, sym_name, list(mode),
+	maybe(determinism), prog_context) = string.
+
 :- pred mercury_output_func_mode_subdecl(inst_varset, sym_name, list(mode),
 		mode, maybe(determinism), prog_context, io__state, io__state).
 :- mode mercury_output_func_mode_subdecl(in, in, in, in, in, in, di, uo) is det.
 
+:- func mercury_func_mode_subdecl_to_string(inst_varset, sym_name, list(mode),
+	mode, maybe(determinism), prog_context) = string.
+
 :- pred mercury_output_pragma_decl(sym_name, int, pred_or_func, string,
 		io__state, io__state).
 :- mode mercury_output_pragma_decl(in, in, in, in, di, uo) is det.
 
+:- func mercury_pragma_decl_to_string(sym_name, int, pred_or_func, string)
+	= string.
+
 :- pred mercury_output_pragma_foreign_code(
 		pragma_foreign_proc_attributes, sym_name,
 		pred_or_func, list(pragma_var), prog_varset,
@@ -89,6 +143,10 @@
 :- mode mercury_output_pragma_foreign_code(
 		in, in, in, in, in, in, di, uo) is det.
 
+:- func mercury_pragma_foreign_code_to_string(pragma_foreign_proc_attributes,
+	sym_name, pred_or_func, list(pragma_var), prog_varset,
+	pragma_foreign_code_impl) = string.
+
 :- inst type_spec == bound(type_spec(ground, ground, ground, ground,
 			ground, ground, ground, ground)).
 
@@ -106,9 +164,13 @@
 :- mode mercury_output_index_spec(in, di, uo) is det.
 
 	% Output the given foreign_decl declaration
-:- pred mercury_output_pragma_foreign_decl(foreign_language, string,				io__state, io__state).
+:- pred mercury_output_pragma_foreign_decl(foreign_language, string,
+		io__state, io__state).
 :- mode mercury_output_pragma_foreign_decl(in, in, di, uo) is det.
 
+:- func mercury_pragma_foreign_decl_to_string(foreign_language, string)
+	= string.
+
 :- pred mercury_output_ctor(constructor, tvarset, io__state, io__state).
 :- mode mercury_output_ctor(in, in, di, uo) is det.
 
@@ -123,9 +185,14 @@
 			io__state, io__state).
 :- mode mercury_output_structured_inst_list(in, in, in, di, uo) is det.
 
+:- func mercury_structured_inst_list_to_string(list(inst), int, inst_varset)
+	= string.
+
 :- pred mercury_output_inst_list(list(inst), inst_varset, io__state, io__state).
 :- mode mercury_output_inst_list(in, in, di, uo) is det.
 
+:- func mercury_inst_list_to_string(list(inst), inst_varset) = string.
+
 	% Output an inst in a format that makes it easy to read
 	% but may not be valid Mercury.
 
@@ -133,28 +200,44 @@
 		io__state, io__state).
 :- mode mercury_output_structured_inst(in, in, in, di, uo) is det.
 
+:- func mercury_structured_inst_to_string(inst, int, inst_varset) = string.
+
 :- pred mercury_output_inst(inst, inst_varset, io__state, io__state).
 :- mode mercury_output_inst(in, in, di, uo) is det.
 
+:- func mercury_inst_to_string(inst, inst_varset) = string.
+
 :- pred mercury_output_cons_id(cons_id, needs_brackets, io__state, io__state).
 :- mode mercury_output_cons_id(in, in, di, uo) is det.
 
+:- func mercury_cons_id_to_string(cons_id, needs_brackets) = string.
+
 :- pred mercury_output_mode(mode, inst_varset, io__state, io__state).
 :- mode mercury_output_mode(in, in, di, uo) is det.
 
+:- func mercury_mode_to_string(mode, inst_varset) = string.
+
 :- pred mercury_output_mode_list(list(mode), inst_varset, io__state, io__state).
 :- mode mercury_output_mode_list(in, in, di, uo) is det.
 
+:- func mercury_mode_list_to_string(list(mode), inst_varset) = string.
+
 :- pred mercury_output_uni_mode(uni_mode, inst_varset, io__state, io__state).
 :- mode mercury_output_uni_mode(in, in, di, uo) is det.
 
+:- func mercury_uni_mode_to_string(uni_mode, inst_varset) = string.
+
 :- pred mercury_output_uni_mode_list(list(uni_mode), inst_varset,
 					io__state, io__state).
 :- mode mercury_output_uni_mode_list(in, in, di, uo) is det.
 
+:- func mercury_uni_mode_list_to_string(list(uni_mode), inst_varset) = string.
+
 :- pred mercury_output_det(determinism, io__state, io__state).
 :- mode mercury_output_det(in, di, uo) is det.
 
+:- func mercury_det_to_string(determinism) = string.
+
 	% Output a comma-separated list of variables, making sure that
 	% the variable number appears in the variable name if the boolean
 	% argument is set to `yes'.
@@ -163,27 +246,36 @@
 		io__state, io__state).
 :- mode mercury_output_vars(in, in, in, di, uo) is det.
 
+:- func mercury_vars_to_string(list(var(T)), varset(T), bool) = string.
+
 	% Output a variable, making sure that the variable number appears
 	% in the variable name if the boolean argument is set to `yes'.
 
 :- pred mercury_output_var(var(T), varset(T), bool, io__state, io__state).
 :- mode mercury_output_var(in, in, in, di, uo) is det.
 
+:- func mercury_var_to_string(var(T), varset(T), bool) = string.
+
 	% Output a term, making sure that the variable number appears
 	% in variable names if the boolean argument is set to `yes'.
 
 :- pred mercury_output_term(term(T), varset(T), bool, io__state, io__state).
 :- mode mercury_output_term(in, in, in, di, uo) is det.
 
+:- func mercury_term_to_string(term(T), varset(T), bool) = string.
+
 :- pred mercury_output_term(term(T), varset(T), bool, needs_quotes,
 				io__state, io__state).
 :- mode mercury_output_term(in, in, in, in, di, uo) is det.
 
-:- pred mercury_type_to_string(tvarset, type, string).
-:- mode mercury_type_to_string(in, in, out) is det.
+:- func mercury_term_to_string(term(T), varset(T), bool, needs_quotes)
+	= string.
 
-:- pred mercury_type_list_to_string(tvarset, list(type), string).
-:- mode mercury_type_list_to_string(in, in, out) is det.
+	% XXX Even though types are defined to be terms, these two functions 
+	% format types not as mercury_term_to_string does but in a simplified
+	% manner.
+:- func mercury_type_to_string(tvarset, type) = string.
+:- func mercury_type_list_to_string(tvarset, list(type)) = string.
 
 :- pred mercury_output_newline(int, io__state, io__state).
 :- mode mercury_output_newline(in, di, uo) is det.
@@ -204,9 +296,7 @@
 		io__state, io__state).
 :- mode mercury_output_constraint(in, in, in, di, uo) is det.
 
-:- pred mercury_constraint_to_string(tvarset, class_constraint, 
-		string).
-:- mode mercury_constraint_to_string(in, in, out) is det.
+:- func mercury_constraint_to_string(tvarset, class_constraint) = string.
 
 	% Output an existential quantifier, making sure that the variable
 	% number appears in variable names if the boolean argument
@@ -215,6 +305,8 @@
 		io__state, io__state).
 :- mode mercury_output_quantifier(in, in, in, di, uo) is det.
 
+:- func mercury_quantifier_to_string(tvarset, bool, existq_tvars) = string.
+
 :- pred mercury_output_instance_methods(instance_methods, io__state,
 	io__state).
 :- mode mercury_output_instance_methods(in, di, uo) is det.
@@ -291,7 +383,7 @@
 mercury_output_item(mode_defn(VarSet, Name, Args, ModeDefn, _Cond),
 		Context) -->
 	maybe_output_line_number(Context),
-	mercury_output_mode_defn(VarSet, Name, Args, ModeDefn, Context).
+	mercury_format_mode_defn(VarSet, Name, Args, ModeDefn, Context).
 
 mercury_output_item(
 		pred_or_func(TypeVarSet, InstVarSet, ExistQVars,
@@ -301,7 +393,7 @@
 	maybe_output_line_number(Context),
 	(
 		{ PredOrFunc = predicate },
-		mercury_output_pred_decl(TypeVarSet, InstVarSet, ExistQVars,
+		mercury_format_pred_decl(TypeVarSet, InstVarSet, ExistQVars,
 			PredName, TypesAndModes, Det, Purity,
 			ClassContext, Context,
 			":- ", ".\n", ".\n")
@@ -309,7 +401,7 @@
 		{ PredOrFunc = function },
 		{ pred_args_to_func_args(TypesAndModes, FuncTypesAndModes,
 				RetTypeAndMode) },
-		mercury_output_func_decl(TypeVarSet, InstVarSet, ExistQVars,
+		mercury_format_func_decl(TypeVarSet, InstVarSet, ExistQVars,
 			PredName, FuncTypesAndModes, RetTypeAndMode,
 			Det, Purity, ClassContext, Context,
 			":- ", ".\n", ".\n")
@@ -369,11 +461,11 @@
 	;
 		{ Pragma = import(Pred, PredOrFunc, ModeList, Attributes,
 			C_Function) },
-		mercury_output_pragma_import(Pred, PredOrFunc, ModeList,
+		mercury_format_pragma_import(Pred, PredOrFunc, ModeList,
 			Attributes, C_Function)
 	;
 		{ Pragma = export(Pred, PredOrFunc, ModeList, C_Function) },
-		mercury_output_pragma_export(Pred, PredOrFunc, ModeList,
+		mercury_format_pragma_export(Pred, PredOrFunc, ModeList,
 			C_Function)
 	;
 		{ Pragma = obsolete(Pred, Arity) },
@@ -399,7 +491,7 @@
 			PredName, Arity, ModeNum, UnusedArgs)
 	;
 		{ Pragma = fact_table(Pred, Arity, FileName) },
-		mercury_output_pragma_fact_table(Pred, Arity, FileName)
+		mercury_format_pragma_fact_table(Pred, Arity, FileName)
 	;
 		{ Pragma = aditi(Pred, Arity) },
 		mercury_output_pragma_decl(Pred, Arity, predicate, "aditi")
@@ -409,7 +501,7 @@
 			predicate, "base_relation")
 	;
 		{ Pragma = aditi_index(Pred, Arity, Index) },
-		mercury_output_pragma_index(Pred, Arity, Index)
+		mercury_format_pragma_index(Pred, Arity, Index)
 	;
 		{ Pragma = aditi_memo(Pred, Arity) },
 		mercury_output_pragma_decl(Pred, Arity,
@@ -428,7 +520,7 @@
 			predicate, "context")
 	;
 		{ Pragma = owner(Pred, Arity, Owner) },
-		mercury_output_pragma_owner(Pred, Arity, Owner)
+		mercury_format_pragma_owner(Pred, Arity, Owner)
 	;
 		{ Pragma = naive(Pred, Arity) },
 		mercury_output_pragma_decl(Pred, Arity, predicate, "naive")
@@ -475,8 +567,8 @@
 	io__write_string(".\n").
 
 mercury_output_item(nothing(_), _) --> [].
-mercury_output_item(typeclass(Constraints, ClassName, Vars, Interface, 
-		VarSet), _) --> 
+mercury_output_item(typeclass(Constraints, ClassName, Vars, Interface, VarSet),
+		_) --> 
 	io__write_string(":- typeclass "),
 
 		% We put an extra set of brackets around the class name in
@@ -494,7 +586,7 @@
 	io__write_char(')'),
 
 	{ AppendVarnums = no },
-	mercury_output_class_constraint_list(Constraints, VarSet, "<=",
+	mercury_format_class_constraint_list(Constraints, VarSet, "<=",
 		AppendVarnums),
 
 	(
@@ -520,7 +612,7 @@
 	io__write_char(')'),
 	
 	{ AppendVarnums = no },
-	mercury_output_class_constraint_list(Constraints, VarSet, "<=",
+	mercury_format_class_constraint_list(Constraints, VarSet, "<=",
 		AppendVarnums),
 
 	(
@@ -552,14 +644,14 @@
 			Purity, ClassContext, Context) },
 		(
 			{ PredOrFunc = predicate },
-			mercury_output_pred_decl(TypeVarSet, InstVarSet,
+			mercury_format_pred_decl(TypeVarSet, InstVarSet,
 				ExistQVars, Name, TypesAndModes, Detism,
 				Purity, ClassContext, Context, "", ",\n\t", "")
 		;
 			{ PredOrFunc = function },
 			{ pred_args_to_func_args(TypesAndModes,
 				FuncTypesAndModes, RetTypeAndMode) },
-			mercury_output_func_decl(TypeVarSet, InstVarSet,
+			mercury_format_func_decl(TypeVarSet, InstVarSet,
 				ExistQVars, Name, FuncTypesAndModes,
 				RetTypeAndMode, Detism, Purity, ClassContext,
 				Context, "", ",\n\t", "")
@@ -569,12 +661,12 @@
 			Name, Modes, Detism, _Condition, Context) },
 		(
 			{ PredOrFunc = predicate },
-			mercury_output_pred_mode_decl_2(VarSet, Name, Modes,
+			mercury_format_pred_mode_decl_2(VarSet, Name, Modes,
 				Detism, Context, "", "")
 		;
 			{ PredOrFunc = function },
 			{ pred_args_to_func_args(Modes, FuncModes, RetMode) },
-			mercury_output_func_mode_decl_2(VarSet, Name,
+			mercury_format_func_mode_decl_2(VarSet, Name,
 				FuncModes, RetMode, Detism, Context, "", "")
 		)
 	).
@@ -706,550 +798,628 @@
 	io__write_string(") = "),
 	mercury_output_inst(Body, VarSet),
 	io__write_string(".\n").
+
+mercury_output_structured_inst_list(Insts, Indent, VarSet) -->
+	mercury_format_structured_inst_list(Insts, Indent, VarSet).
+
+mercury_structured_inst_list_to_string(Insts, Indent, VarSet) = String :-
+	mercury_format_structured_inst_list(Insts, Indent, VarSet, "", String).
+
+:- pred mercury_format_structured_inst_list(list(inst)::in, int::in,
+	inst_varset::in, U::di, U::uo) is det <= output(U).
+
+mercury_format_structured_inst_list([], _, _) --> [].
+mercury_format_structured_inst_list([Inst | Insts], Indent0, VarSet) -->
+	mercury_format_structured_inst(Inst, Indent0, VarSet),
+	mercury_format_structured_inst_list(Insts, Indent0, VarSet).
+
+mercury_output_inst_list(Insts, VarSet) -->
+	mercury_format_inst_list(Insts, VarSet).
 
-mercury_output_structured_inst_list([], _, _) --> [].
-mercury_output_structured_inst_list([Inst | Insts], Indent0, VarSet) -->
-	mercury_output_structured_inst(Inst, Indent0, VarSet),
-	mercury_output_structured_inst_list(Insts, Indent0, VarSet).
-
-mercury_output_inst_list([], _) --> [].
-mercury_output_inst_list([Inst | Insts], VarSet) -->
-	mercury_output_inst(Inst, VarSet),
+mercury_inst_list_to_string(Insts, VarSet) = String :-
+	mercury_format_inst_list(Insts, VarSet, "", String).
+
+:- pred mercury_format_inst_list(list(inst)::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_inst_list([], _) --> [].
+mercury_format_inst_list([Inst | Insts], VarSet) -->
+	mercury_format_inst(Inst, VarSet),
 	( { Insts = [] } ->
 		[]
 	;
-		io__write_string(", "),
-		mercury_output_inst_list(Insts, VarSet)
+		add_string(", "),
+		mercury_format_inst_list(Insts, VarSet)
 	).
 
-mercury_output_structured_inst(any(Uniq), Indent, _) -->
-	mercury_output_tabs(Indent),
-	mercury_output_any_uniqueness(Uniq),
-	io__write_string("\n").
-mercury_output_structured_inst(free, Indent, _) -->
-	mercury_output_tabs(Indent),
-	io__write_string("free\n").
-mercury_output_structured_inst(free(_T), Indent, _) -->
-	mercury_output_tabs(Indent),
-	io__write_string("free(with some type)\n").
-mercury_output_structured_inst(bound(Uniq, BoundInsts), Indent, VarSet) -->
-	mercury_output_tabs(Indent),
-	mercury_output_uniqueness(Uniq, "bound"),
-	io__write_string("(\n"),
-	mercury_output_structured_bound_insts(BoundInsts, Indent, VarSet),
-	mercury_output_tabs(Indent),
-	io__write_string(")\n").
-mercury_output_structured_inst(ground(Uniq, GroundInstInfo), Indent, VarSet)
+mercury_output_structured_inst(Inst, Indent, VarSet) -->
+	mercury_format_structured_inst(Inst, Indent, VarSet).
+
+mercury_structured_inst_to_string(Inst, Indent, VarSet) = String :-
+	mercury_format_structured_inst(Inst, Indent, VarSet, "", String).
+
+:- pred mercury_format_structured_inst((inst)::in, int::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_structured_inst(any(Uniq), Indent, _) -->
+	mercury_format_tabs(Indent),
+	mercury_format_any_uniqueness(Uniq),
+	add_string("\n").
+mercury_format_structured_inst(free, Indent, _) -->
+	mercury_format_tabs(Indent),
+	add_string("free\n").
+mercury_format_structured_inst(free(_T), Indent, _) -->
+	mercury_format_tabs(Indent),
+	add_string("free(with some type)\n").
+mercury_format_structured_inst(bound(Uniq, BoundInsts), Indent, VarSet) -->
+	mercury_format_tabs(Indent),
+	mercury_format_uniqueness(Uniq, "bound"),
+	add_string("(\n"),
+	mercury_format_structured_bound_insts(BoundInsts, Indent, VarSet),
+	mercury_format_tabs(Indent),
+	add_string(")\n").
+mercury_format_structured_inst(ground(Uniq, GroundInstInfo), Indent, VarSet)
 		-->
-	mercury_output_tabs(Indent),
+	mercury_format_tabs(Indent),
 	(	
 		{ GroundInstInfo = higher_order(pred_inst_info(PredOrFunc,
 				Modes, Det)) },
 		( { Uniq = shared } ->
 			[]
 		;
-			io__write_string("/* "),
-			mercury_output_uniqueness(Uniq, "ground"),
-			io__write_string(" */")
+			add_string("/* "),
+			mercury_format_uniqueness(Uniq, "ground"),
+			add_string(" */")
 		),
 		(
 			{ PredOrFunc = predicate },
 			( { Modes = [] } ->
-				io__write_string("(pred) is "),
-				mercury_output_det(Det),
-				io__write_string(")\n")
-			;
-				io__write_string("(pred("),
-				mercury_output_mode_list(Modes, VarSet),
-				io__write_string(") is "),
-				mercury_output_det(Det),
-				io__write_string(")\n")
+				add_string("(pred) is "),
+				mercury_format_det(Det),
+				add_string(")\n")
+			;
+				add_string("(pred("),
+				mercury_format_mode_list(Modes, VarSet),
+				add_string(") is "),
+				mercury_format_det(Det),
+				add_string(")\n")
 			)
 		;
 			{ PredOrFunc = function },
 			{ pred_args_to_func_args(Modes, ArgModes, RetMode) },
 			( { Modes = [] } ->
-				io__write_string("((func) = ")
+				add_string("((func) = ")
 			;
-				io__write_string("(func("),
-				mercury_output_mode_list(ArgModes, VarSet),
-				io__write_string(") = ")
-			),
-			mercury_output_mode(RetMode, VarSet),
-			io__write_string(" is "),
-			mercury_output_det(Det),
-			io__write_string(")\n")
+				add_string("(func("),
+				mercury_format_mode_list(ArgModes, VarSet),
+				add_string(") = ")
+			),
+			mercury_format_mode(RetMode, VarSet),
+			add_string(" is "),
+			mercury_format_det(Det),
+			add_string(")\n")
 		)
 	;
 		{ GroundInstInfo = constrained_inst_var(Var) },
-		mercury_output_tabs(Indent),
-		mercury_output_var(Var, VarSet, no),
-		io__write_string("\n")
+		mercury_format_tabs(Indent),
+		mercury_format_var(Var, VarSet, no),
+		add_string("\n")
 	;
 		{ GroundInstInfo = none},
-		mercury_output_uniqueness(Uniq, "ground"),
-		io__write_string("\n")
+		mercury_format_uniqueness(Uniq, "ground"),
+		add_string("\n")
 	).
-mercury_output_structured_inst(inst_var(Var), Indent, VarSet) -->
-	mercury_output_tabs(Indent),
-	mercury_output_var(Var, VarSet, no),
-	io__write_string("\n").
-mercury_output_structured_inst(abstract_inst(Name, Args), Indent, VarSet) -->
-	mercury_output_structured_inst_name(user_inst(Name, Args), Indent,
+mercury_format_structured_inst(inst_var(Var), Indent, VarSet) -->
+	mercury_format_tabs(Indent),
+	mercury_format_var(Var, VarSet, no),
+	add_string("\n").
+mercury_format_structured_inst(abstract_inst(Name, Args), Indent, VarSet) -->
+	mercury_format_structured_inst_name(user_inst(Name, Args), Indent,
 		VarSet).
-mercury_output_structured_inst(defined_inst(InstName), Indent, VarSet) -->
-	mercury_output_structured_inst_name(InstName, Indent, VarSet).
-mercury_output_structured_inst(not_reached, Indent, _) -->
-	mercury_output_tabs(Indent),
-	io__write_string("not_reached\n").
-
-mercury_output_inst(any(Uniq), _) -->
-	mercury_output_any_uniqueness(Uniq).
-mercury_output_inst(free, _) -->
-	io__write_string("free").
-mercury_output_inst(free(_T), _) -->
-	io__write_string("free(with some type)").
-mercury_output_inst(bound(Uniq, BoundInsts), VarSet) -->
-	mercury_output_uniqueness(Uniq, "bound"),
-	io__write_string("("),
-	mercury_output_bound_insts(BoundInsts, VarSet),
-	io__write_string(")").
-mercury_output_inst(ground(Uniq, GroundInstInfo), VarSet) -->
+mercury_format_structured_inst(defined_inst(InstName), Indent, VarSet) -->
+	mercury_format_structured_inst_name(InstName, Indent, VarSet).
+mercury_format_structured_inst(not_reached, Indent, _) -->
+	mercury_format_tabs(Indent),
+	add_string("not_reached\n").
+
+mercury_output_inst(Inst, VarSet) -->
+	mercury_format_inst(Inst, VarSet).
+
+mercury_inst_to_string(Inst, VarSet) = String :-
+	mercury_format_inst(Inst, VarSet, "", String).
+
+:- pred mercury_format_inst((inst)::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_inst(any(Uniq), _) -->
+	mercury_format_any_uniqueness(Uniq).
+mercury_format_inst(free, _) -->
+	add_string("free").
+mercury_format_inst(free(_T), _) -->
+	add_string("free(with some type)").
+mercury_format_inst(bound(Uniq, BoundInsts), VarSet) -->
+	mercury_format_uniqueness(Uniq, "bound"),
+	add_string("("),
+	mercury_format_bound_insts(BoundInsts, VarSet),
+	add_string(")").
+mercury_format_inst(ground(Uniq, GroundInstInfo), VarSet) -->
 	(	
 		{ GroundInstInfo = higher_order(pred_inst_info(PredOrFunc,
 				Modes, Det)) },
 		( { Uniq = shared } ->
 			[]
 		;
-			io__write_string("/* "),
-			mercury_output_uniqueness(Uniq, "ground"),
-			io__write_string(" */")
+			add_string("/* "),
+			mercury_format_uniqueness(Uniq, "ground"),
+			add_string(" */")
 		),
 		(
 			{ PredOrFunc = predicate },
 			( { Modes = [] } ->
-				io__write_string("((pred) is "),
-				mercury_output_det(Det),
-				io__write_string(")")
-			;
-				io__write_string("(pred("),
-				mercury_output_mode_list(Modes, VarSet),
-				io__write_string(") is "),
-				mercury_output_det(Det),
-				io__write_string(")")
+				add_string("((pred) is "),
+				mercury_format_det(Det),
+				add_string(")")
+			;
+				add_string("(pred("),
+				mercury_format_mode_list(Modes, VarSet),
+				add_string(") is "),
+				mercury_format_det(Det),
+				add_string(")")
 			)
 		;
 			{ PredOrFunc = function },
 			{ pred_args_to_func_args(Modes, ArgModes, RetMode) },
 			( { ArgModes = [] } ->
-				io__write_string("((func)")
+				add_string("((func)")
 			;
-				io__write_string("(func("),
-				mercury_output_mode_list(ArgModes, VarSet),
-				io__write_string(")")
-			),
-			io__write_string(" = "),
-			mercury_output_mode(RetMode, VarSet),
-			io__write_string(" is "),
-			mercury_output_det(Det),
-			io__write_string(")")
+				add_string("(func("),
+				mercury_format_mode_list(ArgModes, VarSet),
+				add_string(")")
+			),
+			add_string(" = "),
+			mercury_format_mode(RetMode, VarSet),
+			add_string(" is "),
+			mercury_format_det(Det),
+			add_string(")")
 		)
 	;
 		{ GroundInstInfo = constrained_inst_var(Var) },
-		mercury_output_var(Var, VarSet, no)
+		mercury_format_var(Var, VarSet, no)
 	;
 		{ GroundInstInfo = none },
-		mercury_output_uniqueness(Uniq, "ground")
+		mercury_format_uniqueness(Uniq, "ground")
 	).
-mercury_output_inst(inst_var(Var), VarSet) -->
-	mercury_output_var(Var, VarSet, no).
-mercury_output_inst(abstract_inst(Name, Args), VarSet) -->
-	mercury_output_inst_name(user_inst(Name, Args), VarSet).
-mercury_output_inst(defined_inst(InstName), VarSet) -->
-	mercury_output_inst_name(InstName, VarSet).
-mercury_output_inst(not_reached, _) -->
-	io__write_string("not_reached").
+mercury_format_inst(inst_var(Var), VarSet) -->
+	mercury_format_var(Var, VarSet, no).
+mercury_format_inst(abstract_inst(Name, Args), VarSet) -->
+	mercury_format_inst_name(user_inst(Name, Args), VarSet).
+mercury_format_inst(defined_inst(InstName), VarSet) -->
+	mercury_format_inst_name(InstName, VarSet).
+mercury_format_inst(not_reached, _) -->
+	add_string("not_reached").
 
-:- pred mercury_output_structured_inst_name(inst_name, int, inst_varset,
-	io__state, io__state).
-:- mode mercury_output_structured_inst_name(in, in, in, di, uo) is det.
+:- pred mercury_format_structured_inst_name(inst_name::in, int::in,
+	inst_varset::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_structured_inst_name(user_inst(Name, Args), Indent, VarSet) -->
+mercury_format_structured_inst_name(user_inst(Name, Args), Indent, VarSet) -->
 	( { Args = [] } ->
-		mercury_output_tabs(Indent),
-		mercury_output_bracketed_sym_name(Name)
+		mercury_format_tabs(Indent),
+		mercury_format_bracketed_sym_name(Name)
 	;
-		mercury_output_tabs(Indent),
-		mercury_output_sym_name(Name),
-		io__write_string("(\n"),
-		{ Indent1 is Indent + 1 },
-		mercury_output_structured_inst_list(Args, Indent1, VarSet),
-		mercury_output_tabs(Indent),
-		io__write_string(")\n")
+		mercury_format_tabs(Indent),
+		mercury_format_sym_name(Name),
+		add_string("(\n"),
+		{ Indent1 = Indent + 1 },
+		mercury_format_structured_inst_list(Args, Indent1, VarSet),
+		mercury_format_tabs(Indent),
+		add_string(")\n")
 	).
-mercury_output_structured_inst_name(merge_inst(InstA, InstB), Indent, VarSet)
+mercury_format_structured_inst_name(merge_inst(InstA, InstB), Indent, VarSet)
 		-->
-	mercury_output_tabs(Indent),
-	io__write_string("$merge_inst(\n"),
-	{ Indent1 is Indent + 1 },
-	mercury_output_structured_inst_list([InstA, InstB], Indent1, VarSet),
-	mercury_output_tabs(Indent),
-	io__write_string(")\n").
-mercury_output_structured_inst_name(shared_inst(InstName), Indent, VarSet) -->
-	mercury_output_tabs(Indent),
-	io__write_string("$shared_inst(\n"),
-	{ Indent1 is Indent + 1 },
-	mercury_output_structured_inst_name(InstName, Indent1, VarSet),
-	mercury_output_tabs(Indent),
-	io__write_string(")\n").
-mercury_output_structured_inst_name(mostly_uniq_inst(InstName), Indent, VarSet)
+	mercury_format_tabs(Indent),
+	add_string("$merge_inst(\n"),
+	{ Indent1 = Indent + 1 },
+	mercury_format_structured_inst_list([InstA, InstB], Indent1, VarSet),
+	mercury_format_tabs(Indent),
+	add_string(")\n").
+mercury_format_structured_inst_name(shared_inst(InstName), Indent, VarSet) -->
+	mercury_format_tabs(Indent),
+	add_string("$shared_inst(\n"),
+	{ Indent1 = Indent + 1 },
+	mercury_format_structured_inst_name(InstName, Indent1, VarSet),
+	mercury_format_tabs(Indent),
+	add_string(")\n").
+mercury_format_structured_inst_name(mostly_uniq_inst(InstName), Indent, VarSet)
 		-->
-	mercury_output_tabs(Indent),
-	io__write_string("$mostly_uniq_inst(\n"),
-	{ Indent1 is Indent + 1 },
-	mercury_output_structured_inst_name(InstName, Indent1, VarSet),
-	mercury_output_tabs(Indent),
-	io__write_string(")\n").
-mercury_output_structured_inst_name(unify_inst(Liveness, InstA, InstB, Real),
+	mercury_format_tabs(Indent),
+	add_string("$mostly_uniq_inst(\n"),
+	{ Indent1 = Indent + 1 },
+	mercury_format_structured_inst_name(InstName, Indent1, VarSet),
+	mercury_format_tabs(Indent),
+	add_string(")\n").
+mercury_format_structured_inst_name(unify_inst(Liveness, InstA, InstB, Real),
 		Indent, VarSet) -->
-	mercury_output_tabs(Indent),
-	io__write_string("$unify("),
+	mercury_format_tabs(Indent),
+	add_string("$unify("),
 	( { Liveness = live } ->
-		io__write_string("live, ")
+		add_string("live, ")
 	;
-		io__write_string("dead, ")
+		add_string("dead, ")
 	),
 	( { Real = real_unify } ->
-		io__write_string("real,\n")
+		add_string("real,\n")
 	;
-		io__write_string("fake,\n")
+		add_string("fake,\n")
 	),
-	{ Indent1 is Indent + 1 },
-	mercury_output_structured_inst_list([InstA, InstB], Indent1, VarSet),
-	mercury_output_tabs(Indent),
-	io__write_string(")\n").
-mercury_output_structured_inst_name(ground_inst(InstName, IsLive, Uniq, Real),
+	{ Indent1 = Indent + 1 },
+	mercury_format_structured_inst_list([InstA, InstB], Indent1, VarSet),
+	mercury_format_tabs(Indent),
+	add_string(")\n").
+mercury_format_structured_inst_name(ground_inst(InstName, IsLive, Uniq, Real),
 		Indent, VarSet) -->
-	mercury_output_tabs(Indent),
-	io__write_string("$ground("),
+	mercury_format_tabs(Indent),
+	add_string("$ground("),
 	( { IsLive = live } ->
-		io__write_string("live, ")
+		add_string("live, ")
 	;
-		io__write_string("dead, ")
+		add_string("dead, ")
 	),
 	( { Real = real_unify } ->
-		io__write_string("real, ")
+		add_string("real, ")
 	;
-		io__write_string("fake, ")
+		add_string("fake, ")
 	),
-	mercury_output_uniqueness(Uniq, "shared"),
-	io__write_string(",\n"),
-	{ Indent1 is Indent + 1 },
-	mercury_output_structured_inst_name(InstName, Indent1, VarSet),
-	mercury_output_tabs(Indent),
-	io__write_string(")\n").
-mercury_output_structured_inst_name(any_inst(InstName, IsLive, Uniq, Real),
+	mercury_format_uniqueness(Uniq, "shared"),
+	add_string(",\n"),
+	{ Indent1 = Indent + 1 },
+	mercury_format_structured_inst_name(InstName, Indent1, VarSet),
+	mercury_format_tabs(Indent),
+	add_string(")\n").
+mercury_format_structured_inst_name(any_inst(InstName, IsLive, Uniq, Real),
 		Indent, VarSet) -->
-	mercury_output_tabs(Indent),
-	io__write_string("$any("),
+	mercury_format_tabs(Indent),
+	add_string("$any("),
 	( { IsLive = live } ->
-		io__write_string("live, ")
+		add_string("live, ")
 	;
-		io__write_string("dead, ")
+		add_string("dead, ")
 	),
 	( { Real = real_unify } ->
-		io__write_string("real, ")
+		add_string("real, ")
 	;
-		io__write_string("fake, ")
+		add_string("fake, ")
 	),
-	mercury_output_uniqueness(Uniq, "shared"),
-	io__write_string(",\n"),
-	{ Indent1 is Indent + 1 },
-	mercury_output_structured_inst_name(InstName, Indent1, VarSet),
-	mercury_output_tabs(Indent),
-	io__write_string(")\n").
-mercury_output_structured_inst_name(typed_ground(Uniqueness, Type),
+	mercury_format_uniqueness(Uniq, "shared"),
+	add_string(",\n"),
+	{ Indent1 = Indent + 1 },
+	mercury_format_structured_inst_name(InstName, Indent1, VarSet),
+	mercury_format_tabs(Indent),
+	add_string(")\n").
+mercury_format_structured_inst_name(typed_ground(Uniqueness, Type),
 		Indent, _VarSet) -->
-	mercury_output_tabs(Indent),
-	io__write_string("$typed_ground("),
-	mercury_output_uniqueness(Uniqueness, "shared"),
-	io__write_string(", "),
+	mercury_format_tabs(Indent),
+	add_string("$typed_ground("),
+	mercury_format_uniqueness(Uniqueness, "shared"),
+	add_string(", "),
 	{ varset__init(TypeVarSet) },
-	mercury_output_term(Type, TypeVarSet, no),
-	io__write_string(")\n").
-mercury_output_structured_inst_name(typed_inst(Type, InstName),
+	mercury_format_term(Type, TypeVarSet, no),
+	add_string(")\n").
+mercury_format_structured_inst_name(typed_inst(Type, InstName),
 		Indent, VarSet) -->
-	mercury_output_tabs(Indent),
-	io__write_string("$typed_inst("),
+	mercury_format_tabs(Indent),
+	add_string("$typed_inst("),
 	{ varset__init(TypeVarSet) },
-	mercury_output_term(Type, TypeVarSet, no),
-	io__write_string(",\n"),
-	{ Indent1 is Indent + 1 },
-	mercury_output_structured_inst_name(InstName, Indent1, VarSet),
-	mercury_output_tabs(Indent),
-	io__write_string(")\n").
+	mercury_format_term(Type, TypeVarSet, no),
+	add_string(",\n"),
+	{ Indent1 = Indent + 1 },
+	mercury_format_structured_inst_name(InstName, Indent1, VarSet),
+	mercury_format_tabs(Indent),
+	add_string(")\n").
 
-:- pred mercury_output_inst_name(inst_name, inst_varset, io__state, io__state).
-:- mode mercury_output_inst_name(in, in, di, uo) is det.
+:- pred mercury_format_inst_name(inst_name::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_inst_name(user_inst(Name, Args), VarSet) -->
+mercury_format_inst_name(user_inst(Name, Args), VarSet) -->
 	( { Args = [] } ->
-		mercury_output_bracketed_sym_name(Name)
+		mercury_format_bracketed_sym_name(Name)
 	;
-		mercury_output_sym_name(Name),
-		io__write_string("("),
-		mercury_output_inst_list(Args, VarSet),
-		io__write_string(")")
-	).
-mercury_output_inst_name(merge_inst(InstA, InstB), VarSet) -->
-	io__write_string("$merge_inst("),
-	mercury_output_inst_list([InstA, InstB], VarSet),
-	io__write_string(")").
-mercury_output_inst_name(shared_inst(InstName), VarSet) -->
-	io__write_string("$shared_inst("),
-	mercury_output_inst_name(InstName, VarSet),
-	io__write_string(")").
-mercury_output_inst_name(mostly_uniq_inst(InstName), VarSet) -->
-	io__write_string("$mostly_uniq_inst("),
-	mercury_output_inst_name(InstName, VarSet),
-	io__write_string(")").
-mercury_output_inst_name(unify_inst(Liveness, InstA, InstB, Real), VarSet) -->
-	io__write_string("$unify("),
+		mercury_format_sym_name(Name),
+		add_string("("),
+		mercury_format_inst_list(Args, VarSet),
+		add_string(")")
+	).
+mercury_format_inst_name(merge_inst(InstA, InstB), VarSet) -->
+	add_string("$merge_inst("),
+	mercury_format_inst_list([InstA, InstB], VarSet),
+	add_string(")").
+mercury_format_inst_name(shared_inst(InstName), VarSet) -->
+	add_string("$shared_inst("),
+	mercury_format_inst_name(InstName, VarSet),
+	add_string(")").
+mercury_format_inst_name(mostly_uniq_inst(InstName), VarSet) -->
+	add_string("$mostly_uniq_inst("),
+	mercury_format_inst_name(InstName, VarSet),
+	add_string(")").
+mercury_format_inst_name(unify_inst(Liveness, InstA, InstB, Real), VarSet) -->
+	add_string("$unify("),
 	( { Liveness = live } ->
-		io__write_string("live, ")
+		add_string("live, ")
 	;
-		io__write_string("dead, ")
+		add_string("dead, ")
 	),
-	mercury_output_inst_list([InstA, InstB], VarSet),
+	mercury_format_inst_list([InstA, InstB], VarSet),
 	( { Real = real_unify } ->
-		io__write_string(", real")
+		add_string(", real")
 	;
-		io__write_string(", fake")
+		add_string(", fake")
 	),
-	io__write_string(")").
-mercury_output_inst_name(ground_inst(InstName, IsLive, Uniq, Real), VarSet) -->
-	io__write_string("$ground("),
-	mercury_output_inst_name(InstName, VarSet),
-	io__write_string(", "),
+	add_string(")").
+mercury_format_inst_name(ground_inst(InstName, IsLive, Uniq, Real), VarSet) -->
+	add_string("$ground("),
+	mercury_format_inst_name(InstName, VarSet),
+	add_string(", "),
 	( { IsLive = live } ->
-		io__write_string("live, ")
+		add_string("live, ")
 	;
-		io__write_string("dead, ")
+		add_string("dead, ")
 	),
-	mercury_output_uniqueness(Uniq, "shared"),
+	mercury_format_uniqueness(Uniq, "shared"),
 	( { Real = real_unify } ->
-		io__write_string(", real")
+		add_string(", real")
 	;
-		io__write_string(", fake")
+		add_string(", fake")
 	),
-	io__write_string(")").
-mercury_output_inst_name(any_inst(InstName, IsLive, Uniq, Real), VarSet) -->
-	io__write_string("$any("),
-	mercury_output_inst_name(InstName, VarSet),
-	io__write_string(", "),
+	add_string(")").
+mercury_format_inst_name(any_inst(InstName, IsLive, Uniq, Real), VarSet) -->
+	add_string("$any("),
+	mercury_format_inst_name(InstName, VarSet),
+	add_string(", "),
 	( { IsLive = live } ->
-		io__write_string("live, ")
+		add_string("live, ")
 	;
-		io__write_string("dead, ")
+		add_string("dead, ")
 	),
-	mercury_output_uniqueness(Uniq, "shared"),
+	mercury_format_uniqueness(Uniq, "shared"),
 	( { Real = real_unify } ->
-		io__write_string(", real")
+		add_string(", real")
 	;
-		io__write_string(", fake")
+		add_string(", fake")
 	),
-	io__write_string(")").
-mercury_output_inst_name(typed_ground(Uniqueness, Type), _VarSet) -->
-	io__write_string("$typed_ground("),
-	mercury_output_uniqueness(Uniqueness, "shared"),
-	io__write_string(", "),
+	add_string(")").
+mercury_format_inst_name(typed_ground(Uniqueness, Type), _VarSet) -->
+	add_string("$typed_ground("),
+	mercury_format_uniqueness(Uniqueness, "shared"),
+	add_string(", "),
 	{ varset__init(TypeVarSet) },
-	mercury_output_term(Type, TypeVarSet, no),
-	io__write_string(")").
-mercury_output_inst_name(typed_inst(Type, InstName), VarSet) -->
-	io__write_string("$typed_inst("),
+	mercury_format_term(Type, TypeVarSet, no),
+	add_string(")").
+mercury_format_inst_name(typed_inst(Type, InstName), VarSet) -->
+	add_string("$typed_inst("),
 	{ varset__init(TypeVarSet) },
-	mercury_output_term(Type, TypeVarSet, no),
-	io__write_string(", "),
-	mercury_output_inst_name(InstName, VarSet),
-	io__write_string(")").
-
-:- pred mercury_output_uniqueness(uniqueness, string, io__state, io__state).
-:- mode mercury_output_uniqueness(in, in, di, uo) is det.
+	mercury_format_term(Type, TypeVarSet, no),
+	add_string(", "),
+	mercury_format_inst_name(InstName, VarSet),
+	add_string(")").
+
+:- pred mercury_format_uniqueness(uniqueness::in, string::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_uniqueness(shared, SharedString) -->
+	add_string(SharedString).
+mercury_format_uniqueness(unique, _) -->
+	add_string("unique").
+mercury_format_uniqueness(mostly_unique, _) -->
+	add_string("mostly_unique").
+mercury_format_uniqueness(clobbered, _) -->
+	add_string("clobbered").
+mercury_format_uniqueness(mostly_clobbered, _) -->
+	add_string("mostly_clobbered").
+
+:- pred mercury_format_any_uniqueness(uniqueness::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_any_uniqueness(shared) -->
+	add_string("any").
+mercury_format_any_uniqueness(unique) -->
+	add_string("unique_any").
+mercury_format_any_uniqueness(mostly_unique) -->
+	add_string("mostly_unique_any").
+mercury_format_any_uniqueness(clobbered) -->
+	add_string("clobbered_any").
+mercury_format_any_uniqueness(mostly_clobbered) -->
+	add_string("mostly_clobbered_any").
 
-mercury_output_uniqueness(shared, SharedString) -->
-	io__write_string(SharedString).
-mercury_output_uniqueness(unique, _) -->
-	io__write_string("unique").
-mercury_output_uniqueness(mostly_unique, _) -->
-	io__write_string("mostly_unique").
-mercury_output_uniqueness(clobbered, _) -->
-	io__write_string("clobbered").
-mercury_output_uniqueness(mostly_clobbered, _) -->
-	io__write_string("mostly_clobbered").
-
-:- pred mercury_output_any_uniqueness(uniqueness, io__state, io__state).
-:- mode mercury_output_any_uniqueness(in, di, uo) is det.
-
-mercury_output_any_uniqueness(shared) -->
-	io__write_string("any").
-mercury_output_any_uniqueness(unique) -->
-	io__write_string("unique_any").
-mercury_output_any_uniqueness(mostly_unique) -->
-	io__write_string("mostly_unique_any").
-mercury_output_any_uniqueness(clobbered) -->
-	io__write_string("clobbered_any").
-mercury_output_any_uniqueness(mostly_clobbered) -->
-	io__write_string("mostly_clobbered_any").
-
-:- pred mercury_output_structured_bound_insts(list(bound_inst), int,
-		inst_varset, io__state, io__state).
-:- mode mercury_output_structured_bound_insts(in, in, in, di, uo) is det.
+:- pred mercury_format_structured_bound_insts(list(bound_inst)::in, int::in,
+	inst_varset::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_structured_bound_insts([], _, _) --> [].
-mercury_output_structured_bound_insts([functor(ConsId, Args) | BoundInsts],
+mercury_format_structured_bound_insts([], _, _) --> [].
+mercury_format_structured_bound_insts([functor(ConsId, Args) | BoundInsts],
 		Indent0, VarSet) -->
-	{ Indent1 is Indent0 + 1 },
-	{ Indent2 is Indent1 + 1 },
+	{ Indent1 = Indent0 + 1 },
+	{ Indent2 = Indent1 + 1 },
 	( { Args = [] } ->
-		mercury_output_tabs(Indent1),
-		mercury_output_cons_id(ConsId, needs_brackets),
-		io__write_string("\n")
-	;
-		mercury_output_tabs(Indent1),
-		mercury_output_cons_id(ConsId, does_not_need_brackets),
-		io__write_string("(\n"),
-		mercury_output_structured_inst_list(Args, Indent2, VarSet),
-		mercury_output_tabs(Indent1),
-		io__write_string(")\n")
+		mercury_format_tabs(Indent1),
+		mercury_format_cons_id(ConsId, needs_brackets),
+		add_string("\n")
+	;
+		mercury_format_tabs(Indent1),
+		mercury_format_cons_id(ConsId, does_not_need_brackets),
+		add_string("(\n"),
+		mercury_format_structured_inst_list(Args, Indent2, VarSet),
+		mercury_format_tabs(Indent1),
+		add_string(")\n")
 	),
 	( { BoundInsts = [] } ->
 		[]
 	;
-		mercury_output_tabs(Indent0),
-		io__write_string(";\n"),
-		mercury_output_structured_bound_insts(BoundInsts, Indent0,
+		mercury_format_tabs(Indent0),
+		add_string(";\n"),
+		mercury_format_structured_bound_insts(BoundInsts, Indent0,
 			VarSet)
 	).
 
-:- pred mercury_output_bound_insts(list(bound_inst), inst_varset, io__state,
-		io__state).
-:- mode mercury_output_bound_insts(in, in, di, uo) is det.
+:- pred mercury_format_bound_insts(list(bound_inst)::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_bound_insts([], _) --> [].
-mercury_output_bound_insts([functor(ConsId, Args) | BoundInsts], VarSet) -->
+mercury_format_bound_insts([], _) --> [].
+mercury_format_bound_insts([functor(ConsId, Args) | BoundInsts], VarSet) -->
 	( { Args = [] } ->
-		mercury_output_cons_id(ConsId, needs_brackets)
+		mercury_format_cons_id(ConsId, needs_brackets)
 	;
-		mercury_output_cons_id(ConsId, does_not_need_brackets),
-		io__write_string("("),
-		mercury_output_inst_list(Args, VarSet),
-		io__write_string(")")
+		mercury_format_cons_id(ConsId, does_not_need_brackets),
+		add_string("("),
+		mercury_format_inst_list(Args, VarSet),
+		add_string(")")
 	),
 	( { BoundInsts = [] } ->
 		[]
 	;
-		io__write_string(" ; "),
-		mercury_output_bound_insts(BoundInsts, VarSet)
+		add_string(" ; "),
+		mercury_format_bound_insts(BoundInsts, VarSet)
 	).
+
+mercury_output_cons_id(ConsId, NeedsBrackets) -->
+	mercury_format_cons_id(ConsId, NeedsBrackets).
+
+mercury_cons_id_to_string(ConsId, NeedsBrackets) = String :-
+	mercury_format_cons_id(ConsId, NeedsBrackets, "", String).
+
+:- pred mercury_format_cons_id(cons_id::in, needs_brackets::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_cons_id(cons(Name, _), NeedsBrackets) -->
+mercury_format_cons_id(cons(Name, _), NeedsBrackets) -->
 	( { NeedsBrackets = needs_brackets } ->
-		mercury_output_bracketed_sym_name(Name)
+		mercury_format_bracketed_sym_name(Name)
 	;
-		mercury_output_sym_name(Name)
+		mercury_format_sym_name(Name)
 	).
-mercury_output_cons_id(int_const(X), _) -->
-	io__write_int(X).
-mercury_output_cons_id(float_const(X), _) -->
-	io__write_float(X).
-mercury_output_cons_id(string_const(X), _) -->
-	term_io__quote_string(X).
-mercury_output_cons_id(pred_const(PredId, ProcId, EvalMethod), _) -->
+mercury_format_cons_id(int_const(X), _) -->
+	add_int(X).
+mercury_format_cons_id(float_const(X), _) -->
+	add_float(X).
+mercury_format_cons_id(string_const(X), _) -->
+	add_quoted_string(X).
+mercury_format_cons_id(pred_const(PredId, ProcId, EvalMethod), _) -->
 	% XXX Sufficient, but probably should print this out in
 	%     name/arity form.
 
 	{ pred_id_to_int(PredId, PredInt) },
 	{ proc_id_to_int(ProcId, ProcInt) },
-	io__write_string("<pred_const("),
-	io__write_int(PredInt),
-	io__write_string(", "),
-	io__write_int(ProcInt),
-	io__write_string(", "),
-	io__write(EvalMethod),
-	io__write_string(")>").
-mercury_output_cons_id(code_addr_const(PredId, ProcId), _) -->
+	add_string("<pred_const("),
+	add_int(PredInt),
+	add_string(", "),
+	add_int(ProcInt),
+	add_string(", "),
+	add_lambda_eval_method(EvalMethod),
+	add_string(")>").
+mercury_format_cons_id(code_addr_const(PredId, ProcId), _) -->
 	% XXX Sufficient, but probably should print this out in
 	%     name/arity form.
 
 	{ pred_id_to_int(PredId, PredInt) },
 	{ proc_id_to_int(ProcId, ProcInt) },
-	io__write_string("<code_addr_const("),
-	io__write_int(PredInt),
-	io__write_string(", "),
-	io__write_int(ProcInt),
-	io__write_string(")>").
-mercury_output_cons_id(type_ctor_info_const(Module, Type, Arity), _) -->
+	add_string("<code_addr_const("),
+	add_int(PredInt),
+	add_string(", "),
+	add_int(ProcInt),
+	add_string(")>").
+mercury_format_cons_id(type_ctor_info_const(Module, Type, Arity), _) -->
 	{ prog_out__sym_name_to_string(Module, ModuleString) },
 	{ string__int_to_string(Arity, ArityString) },
-	io__write_strings(["<type_ctor_info for ",
+	add_strings(["<type_ctor_info for ",
 		ModuleString, ":", Type, "/", ArityString, ">"]).
-mercury_output_cons_id(base_typeclass_info_const(Module, Class, InstanceNum,
+mercury_format_cons_id(base_typeclass_info_const(Module, Class, InstanceNum,
 		InstanceString), _) -->
 	{ prog_out__sym_name_to_string(Module, ModuleString) },
-	io__write_string("<base_typeclass_info for "),
-	io__write(Class),
+	add_string("<base_typeclass_info for "),
+	add_class_id(Class),
 	( { ModuleString \= "some bogus module name" } ->
-		io__write_strings([" from module ", ModuleString])
+		add_strings([" from module ", ModuleString])
 	;
 		[]
 	),
-	io__format(", instance number %d (%s)>",
+	add_format(", instance number %d (%s)>",
 		[i(InstanceNum), s(InstanceString)]).
-mercury_output_cons_id(tabling_pointer_const(_, _), _) -->
-	io__write_string("<tabling pointer>").
-mercury_output_cons_id(deep_profiling_proc_static(_), _) -->
-	io__write_string("<deep_profiling_proc_static>").
-
-:- pred mercury_output_mode_defn(inst_varset, sym_name, list(inst_var),
-		mode_defn, prog_context, io__state, io__state).
-:- mode mercury_output_mode_defn(in, in, in, in, in, di, uo) is det.
+mercury_format_cons_id(tabling_pointer_const(_, _), _) -->
+	add_string("<tabling pointer>").
+mercury_format_cons_id(deep_profiling_proc_static(_), _) -->
+	add_string("<deep_profiling_proc_static>").
+
+:- pred mercury_format_mode_defn(inst_varset::in, sym_name::in,
+	list(inst_var)::in, mode_defn::in, prog_context::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_mode_defn(VarSet, Name, Args, eqv_mode(Mode), Context) -->
-	io__write_string(":- mode ("),
+mercury_format_mode_defn(VarSet, Name, Args, eqv_mode(Mode), Context) -->
+	add_string(":- mode ("),
 	{ list__map(pred(V::in, variable(V)::out) is det, Args, ArgTerms) },
 	{ construct_qualified_term(Name, ArgTerms, Context, ModeTerm) },
-	mercury_output_term(ModeTerm, VarSet, no),
-	io__write_string(") :: "),
-	mercury_output_mode(Mode, VarSet),
-	io__write_string(".\n").
-
-mercury_output_mode_list([], _VarSet) --> [].
-mercury_output_mode_list([Mode | Modes], VarSet) -->
-	mercury_output_mode(Mode, VarSet),
+	mercury_format_term(ModeTerm, VarSet, no),
+	add_string(") :: "),
+	mercury_format_mode(Mode, VarSet),
+	add_string(".\n").
+
+mercury_output_mode_list(Modes, VarSet) -->
+	mercury_format_mode_list(Modes, VarSet).
+
+mercury_mode_list_to_string(Modes, VarSet) = String :-
+	mercury_format_mode_list(Modes, VarSet, "", String).
+
+:- pred mercury_format_mode_list(list(mode)::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_mode_list([], _VarSet) --> [].
+mercury_format_mode_list([Mode | Modes], VarSet) -->
+	mercury_format_mode(Mode, VarSet),
 	( { Modes = [] } ->
 		[]
 	;
-		io__write_string(", "),
-		mercury_output_mode_list(Modes, VarSet)
+		add_string(", "),
+		mercury_format_mode_list(Modes, VarSet)
 	).
+
+mercury_output_uni_mode_list(UniModes, VarSet) -->
+	mercury_format_uni_mode_list(UniModes, VarSet).
+
+mercury_uni_mode_list_to_string(UniModes, VarSet) = String :-
+	mercury_format_uni_mode_list(UniModes, VarSet, "", String).
 
-mercury_output_uni_mode_list([], _VarSet) --> [].
-mercury_output_uni_mode_list([Mode | Modes], VarSet) -->
-	mercury_output_uni_mode(Mode, VarSet),
+:- pred mercury_format_uni_mode_list(list(uni_mode)::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_uni_mode_list([], _VarSet) --> [].
+mercury_format_uni_mode_list([Mode | Modes], VarSet) -->
+	mercury_format_uni_mode(Mode, VarSet),
 	( { Modes = [] } ->
 		[]
 	;
-		io__write_string(", "),
-		mercury_output_uni_mode_list(Modes, VarSet)
+		add_string(", "),
+		mercury_format_uni_mode_list(Modes, VarSet)
 	).
 
-mercury_output_uni_mode((InstA1 - InstB1 -> InstA2 - InstB2), VarSet) -->
-	mercury_output_mode((InstA1 -> InstA2), VarSet),
-	io__write_string(" = "),
-	mercury_output_mode((InstB1 -> InstB2), VarSet).
+mercury_output_uni_mode(UniMode, VarSet) -->
+	mercury_format_uni_mode(UniMode, VarSet).
+
+mercury_uni_mode_to_string(UniMode, VarSet) = String :-
+	mercury_format_uni_mode(UniMode, VarSet, "", String).
+
+:- pred mercury_format_uni_mode(uni_mode::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_uni_mode((InstA1 - InstB1 -> InstA2 - InstB2), VarSet) -->
+	mercury_format_mode((InstA1 -> InstA2), VarSet),
+	add_string(" = "),
+	mercury_format_mode((InstB1 -> InstB2), VarSet).
+
+mercury_output_mode(Mode, VarSet) -->
+	mercury_format_mode(Mode, VarSet).
 
-mercury_output_mode((InstA -> InstB), VarSet) -->
+mercury_mode_to_string(Mode, VarSet) = String :-
+	mercury_format_mode(Mode, VarSet, "", String).
+
+:- pred mercury_format_mode((mode)::in, inst_varset::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_mode((InstA -> InstB), VarSet) -->
 	( 
 	    %
 	    % check for higher-order pred or func modes, and output them
@@ -1259,22 +1429,22 @@
 				_Modes, _Det))) },
 	    { InstB = InstA }
 	->
-	    mercury_output_inst(InstA, VarSet)
+		mercury_format_inst(InstA, VarSet)
 	;
-	    io__write_string("("),
-	    mercury_output_inst(InstA, VarSet),
-	    io__write_string(" -> "),
-	    mercury_output_inst(InstB, VarSet),
-	    io__write_string(")")
+		add_string("("),
+		mercury_format_inst(InstA, VarSet),
+		add_string(" -> "),
+		mercury_format_inst(InstB, VarSet),
+		add_string(")")
 	).
-mercury_output_mode(user_defined_mode(Name, Args), VarSet) -->
+mercury_format_mode(user_defined_mode(Name, Args), VarSet) -->
 	( { Args = [] } ->
-		mercury_output_bracketed_sym_name(Name)
+		mercury_format_bracketed_sym_name(Name)
 	;
-		mercury_output_sym_name(Name),
-		io__write_string("("),
-		mercury_output_inst_list(Args, VarSet),
-		io__write_string(")")
+		mercury_format_sym_name(Name),
+		add_string("("),
+		mercury_format_inst_list(Args, VarSet),
+		add_string(")")
 	).
 
 %-----------------------------------------------------------------------------%
@@ -1386,7 +1556,7 @@
 	),
 
 	{ AppendVarnums = no },
-	mercury_output_class_constraint_list(Constraints, VarSet, "=>",
+	mercury_format_class_constraint_list(Constraints, VarSet, "=>",
 		AppendVarnums),
 	(
 		{ ExistQVars = [] }
@@ -1421,14 +1591,12 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred mercury_output_pred_decl(tvarset, inst_varset, existq_tvars,
-		sym_name, list(type_and_mode),
-		maybe(determinism), purity, class_constraints,
-		prog_context, string, string, string, io__state, io__state).
-:- mode mercury_output_pred_decl(in, in, in, in, in, in, in, in, in, in, in, in,
-		di, uo) is det.
+:- pred mercury_format_pred_decl(tvarset::in, inst_varset::in, existq_tvars::in,
+	sym_name::in, list(type_and_mode)::in, maybe(determinism)::in,
+	purity::in, class_constraints::in, prog_context::in,
+	string::in, string::in, string::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_pred_decl(TypeVarSet, InstVarSet, ExistQVars, PredName,
+mercury_format_pred_decl(TypeVarSet, InstVarSet, ExistQVars, PredName,
 		TypesAndModes, MaybeDet, Purity, ClassContext, Context,
 		StartString, Separator, Terminator) -->
 	{ split_types_and_modes(TypesAndModes, Types, MaybeModes) },
@@ -1437,58 +1605,71 @@
 		{ Modes \= [] }
 	->
 		{ AppendVarnums = no },
-		mercury_output_pred_type_2(TypeVarSet, ExistQVars, PredName,
+		mercury_format_pred_type_2(TypeVarSet, ExistQVars, PredName,
 			Types, MaybeDet, Purity, ClassContext, Context,
 			AppendVarnums, StartString, Separator),
-		mercury_output_pred_mode_decl_2(InstVarSet, PredName, Modes,
+		mercury_format_pred_mode_decl_2(InstVarSet, PredName, Modes,
 				MaybeDet, Context, StartString, Terminator)
 	;
 		{ AppendVarnums = no },
-		mercury_output_pred_type_2(TypeVarSet, ExistQVars, PredName,
+		mercury_format_pred_type_2(TypeVarSet, ExistQVars, PredName,
 			Types, MaybeDet, Purity, ClassContext, Context,
 			AppendVarnums, StartString, Terminator)
 	).
 
 mercury_output_pred_type(VarSet, ExistQVars, PredName, Types, MaybeDet, Purity,
 		ClassContext, Context, AppendVarnums) -->
-	mercury_output_pred_type_2(VarSet, ExistQVars, PredName, Types,
+	mercury_format_pred_type(VarSet, ExistQVars, PredName, Types, MaybeDet,
+		Purity, ClassContext, Context, AppendVarnums).
+
+mercury_pred_type_to_string(VarSet, ExistQVars, PredName, Types, MaybeDet,
+		Purity, ClassContext, Context, AppendVarnums) = String :-
+	mercury_format_pred_type(VarSet, ExistQVars, PredName, Types, MaybeDet,
+		Purity, ClassContext, Context, AppendVarnums, "", String).
+
+:- pred mercury_format_pred_type(tvarset::in, existq_tvars::in, sym_name::in,
+	list(type)::in, maybe(determinism)::in, purity::in,
+	class_constraints::in, prog_context::in, bool::in, U::di, U::uo)
+	is det <= output(U).
+
+mercury_format_pred_type(VarSet, ExistQVars, PredName, Types, MaybeDet, Purity,
+		ClassContext, Context, AppendVarnums) -->
+	mercury_format_pred_type_2(VarSet, ExistQVars, PredName, Types,
 		MaybeDet, Purity, ClassContext, Context, AppendVarnums,
 		":- ", ".\n").
 
-
-:- pred mercury_output_pred_type_2(tvarset, existq_tvars, sym_name, list(type),
-		maybe(determinism), purity, class_constraints,
-		prog_context, bool, string, string, io__state, io__state).
-:- mode mercury_output_pred_type_2(in, in, in, in, in, in, in, in, in, in, in,
-		di, uo) is det.
+:- pred mercury_format_pred_type_2(tvarset::in, existq_tvars::in, sym_name::in,
+	list(type)::in, maybe(determinism)::in, purity::in,
+	class_constraints::in, prog_context::in, bool::in,
+	string::in, string::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_pred_type_2(VarSet, ExistQVars, PredName, Types, MaybeDet,
+mercury_format_pred_type_2(VarSet, ExistQVars, PredName, Types, MaybeDet,
 		Purity, ClassContext, _Context, AppendVarnums,
 		StartString, Separator) -->
-	io__write_string(StartString),
-	mercury_output_quantifier(VarSet, AppendVarnums, ExistQVars),
+	add_string(StartString),
+	mercury_format_quantifier(VarSet, AppendVarnums, ExistQVars),
 	( { ExistQVars = [], ClassContext = constraints(_, []) } -> 
 		[] 
 	; 
-		io__write_string("(")
+		add_string("(")
 	),
-	write_purity_prefix(Purity),
-	io__write_string("pred "),
+	add_purity_prefix(Purity),
+	add_string("pred "),
 	(
 		{ Types = [Type | Rest] }
 	->
-		mercury_output_sym_name(PredName),
-		io__write_string("("),
-		mercury_output_term(Type, VarSet, AppendVarnums),
-		mercury_output_remaining_terms(Rest, VarSet, AppendVarnums),
-		io__write_string(")"),
-		mercury_output_class_context(ClassContext, ExistQVars, VarSet,
+		mercury_format_sym_name(PredName),
+		add_string("("),
+		mercury_format_term(Type, VarSet, AppendVarnums),
+		mercury_format_remaining_terms(Rest, VarSet, AppendVarnums),
+		add_string(")"),
+		mercury_format_class_context(ClassContext, ExistQVars, VarSet,
 			AppendVarnums)
 	;
-		mercury_output_bracketed_sym_name(PredName),
-		mercury_output_class_context(ClassContext, ExistQVars, VarSet,
+		mercury_format_bracketed_sym_name(PredName),
+		mercury_format_class_context(ClassContext, ExistQVars, VarSet,
 			AppendVarnums),
-		mercury_output_det_annotation(MaybeDet)
+		mercury_format_det_annotation(MaybeDet)
 	),
 
 	% We need to handle is/2 specially, because it's used for
@@ -1508,23 +1689,21 @@
 		{ unqualify_name(PredName, "is") },
 		{ list__length(Types, 2) }
 	->
-		mercury_output_det_annotation(MaybeDet)
+		mercury_format_det_annotation(MaybeDet)
 	;
 		[]
 	),
-	io__write_string(Separator).
-
+	add_string(Separator).
 
 %-----------------------------------------------------------------------------%
 
-:- pred mercury_output_func_decl(tvarset, inst_varset, existq_tvars, sym_name,
-		list(type_and_mode), type_and_mode, maybe(determinism), 
-		purity, class_constraints, prog_context, string, string,
-		string, io__state, io__state).
-:- mode mercury_output_func_decl(in, in, in, in, in, in, in, in, in, in, in, in,
-		in, di, uo) is det.
+:- pred mercury_format_func_decl(tvarset::in, inst_varset::in,
+	existq_tvars::in, sym_name::in, list(type_and_mode)::in,
+	type_and_mode::in, maybe(determinism)::in, purity::in,
+	class_constraints::in, prog_context::in, string::in, string::in,
+	string::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_func_decl(TypeVarSet, InstVarSet, ExistQVars, FuncName,
+mercury_format_func_decl(TypeVarSet, InstVarSet, ExistQVars, FuncName,
 		TypesAndModes, RetTypeAndMode, MaybeDet, Purity, ClassContext,
 		Context, StartString, Separator, Terminator) -->
 	{ split_types_and_modes(TypesAndModes, Types, MaybeModes) },
@@ -1534,71 +1713,96 @@
 		{ MaybeRetMode = yes(RetMode) }
 	->
 		{ AppendVarnums = no },
-		mercury_output_func_type_2(TypeVarSet, ExistQVars, FuncName,
+		mercury_format_func_type_2(TypeVarSet, ExistQVars, FuncName,
 			Types, RetType, no, Purity, ClassContext,
 			Context, AppendVarnums, StartString, Separator),
-		mercury_output_func_mode_decl_2(InstVarSet, FuncName, Modes,
-				RetMode, MaybeDet, Context, 
-				StartString, Terminator)
+		mercury_format_func_mode_decl_2(InstVarSet, FuncName, Modes,
+			RetMode, MaybeDet, Context, StartString, Terminator)
 	;
 		{ AppendVarnums = no },
-		mercury_output_func_type_2(TypeVarSet, ExistQVars, FuncName,
+		mercury_format_func_type_2(TypeVarSet, ExistQVars, FuncName,
 			Types, RetType, MaybeDet, Purity, ClassContext,
 			Context, AppendVarnums, StartString, Terminator)
 	).
 
 mercury_output_func_type(VarSet, ExistQVars, FuncName, Types, RetType,
+		MaybeDet, Purity, ClassContext, Context, AppendVarnums) -->
+	mercury_format_func_type(VarSet, ExistQVars, FuncName, Types, RetType,
+		MaybeDet, Purity, ClassContext, Context, AppendVarnums).
+
+mercury_func_type_to_string(VarSet, ExistQVars, FuncName, Types, RetType,
+		MaybeDet, Purity, ClassContext, Context, AppendVarnums)
+		= String :-
+	mercury_format_func_type(VarSet, ExistQVars, FuncName, Types, RetType,
+		MaybeDet, Purity, ClassContext, Context, AppendVarnums,
+		"", String).
+
+:- pred mercury_format_func_type(tvarset::in, existq_tvars::in, sym_name::in,
+	list(type)::in, (type)::in, maybe(determinism)::in, purity::in,
+	class_constraints::in, prog_context::in, bool::in, U::di, U::uo)
+	is det <= output(U).
+
+mercury_format_func_type(VarSet, ExistQVars, FuncName, Types, RetType,
 		MaybeDet, Purity, ClassContext, Context, AppendVarnums) -->
-	mercury_output_func_type_2(VarSet, ExistQVars, FuncName, Types,
+	mercury_format_func_type_2(VarSet, ExistQVars, FuncName, Types,
 		RetType, MaybeDet, Purity, ClassContext, Context,
 		AppendVarnums, ":- ", ".\n").
 
-:- pred mercury_output_func_type_2(tvarset, existq_tvars, sym_name,
-		list(type), type, maybe(determinism), purity, class_constraints,
-		prog_context, bool, string, string, io__state, io__state).
-:- mode mercury_output_func_type_2(in, in, in, in, in, in, in, in, in, in, in, 
-		in, di, uo) is det.
+:- pred mercury_format_func_type_2(tvarset::in, existq_tvars::in, sym_name::in,
+	list(type)::in, (type)::in, maybe(determinism)::in,
+	purity::in, class_constraints::in, prog_context::in, bool::in,
+	string::in, string::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_func_type_2(VarSet, ExistQVars, FuncName, Types, RetType,
+mercury_format_func_type_2(VarSet, ExistQVars, FuncName, Types, RetType,
 		MaybeDet, Purity, ClassContext, _Context, AppendVarnums,
 		StartString, Separator) -->
-	io__write_string(StartString),
-	mercury_output_quantifier(VarSet, AppendVarnums, ExistQVars),
+	add_string(StartString),
+	mercury_format_quantifier(VarSet, AppendVarnums, ExistQVars),
 	( { ExistQVars = [], ClassContext = constraints(_, []) } -> 
 		[] 
 	; 
-		io__write_string("(")
+		add_string("(")
 	),
-	write_purity_prefix(Purity),
-	io__write_string("func "),
+	add_purity_prefix(Purity),
+	add_string("func "),
 	(
 		{ Types = [Type | Rest] }
 	->
-		mercury_output_sym_name(FuncName),
-		io__write_string("("),
-		mercury_output_term(Type, VarSet, AppendVarnums),
-		mercury_output_remaining_terms(Rest, VarSet, AppendVarnums),
-		io__write_string(")")
+		mercury_format_sym_name(FuncName),
+		add_string("("),
+		mercury_format_term(Type, VarSet, AppendVarnums),
+		mercury_format_remaining_terms(Rest, VarSet, AppendVarnums),
+		add_string(")")
 	;
-		mercury_output_bracketed_sym_name(FuncName)
+		mercury_format_bracketed_sym_name(FuncName)
 	),
-	io__write_string(" = "),
-	mercury_output_term(RetType, VarSet, AppendVarnums,
+	add_string(" = "),
+	mercury_format_term(RetType, VarSet, AppendVarnums,
 		next_to_graphic_token),
-	mercury_output_class_context(ClassContext, ExistQVars, VarSet,
+	mercury_format_class_context(ClassContext, ExistQVars, VarSet,
 		AppendVarnums),
-	mercury_output_det_annotation(MaybeDet),
-	io__write_string(Separator).
+	mercury_format_det_annotation(MaybeDet),
+	add_string(Separator).
 
 %-----------------------------------------------------------------------------%
 
 mercury_output_quantifier(VarSet, AppendVarNums, ExistQVars) -->
+	mercury_format_quantifier(VarSet, AppendVarNums, ExistQVars).
+
+mercury_quantifier_to_string(VarSet, AppendVarNums, ExistQVars) = String :-
+	mercury_format_quantifier(VarSet, AppendVarNums, ExistQVars,
+		"", String).
+
+:- pred mercury_format_quantifier(tvarset::in, bool::in, existq_tvars::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_quantifier(VarSet, AppendVarNums, ExistQVars) -->
 	( { ExistQVars = [] } ->
 		[]
 	;
-		io__write_string("some ["),
-		mercury_output_vars(ExistQVars, VarSet, AppendVarNums),
-		io__write_string("] ")
+		add_string("some ["),
+		mercury_format_vars(ExistQVars, VarSet, AppendVarNums),
+		add_string("] ")
 	).
 
 %-----------------------------------------------------------------------------%
@@ -1609,74 +1813,88 @@
 
 mercury_output_class_context(ClassContext, ExistQVars, VarSet,
 		AppendVarnums) -->
+	mercury_format_class_context(ClassContext, ExistQVars, VarSet,
+		AppendVarnums).
+
+:- pred mercury_format_class_context(class_constraints::in, existq_tvars::in,
+	tvarset::in, bool::in, U::di, U::uo) is det <= output(U).
+
+mercury_format_class_context(ClassContext, ExistQVars, VarSet,
+		AppendVarnums) -->
 	{ ClassContext = constraints(UnivCs, ExistCs) },
-	mercury_output_class_constraint_list(ExistCs, VarSet, "=>",
+	mercury_format_class_constraint_list(ExistCs, VarSet, "=>",
 		AppendVarnums),
 	( { ExistQVars = [], ExistCs = [] } -> 
 		[] 
 	; 
-		io__write_string(")")
+		add_string(")")
 	),
-	mercury_output_class_constraint_list(UnivCs, VarSet, "<=",
+	mercury_format_class_constraint_list(UnivCs, VarSet, "<=",
 		AppendVarnums).
 
-:- pred mercury_output_class_constraint_list(list(class_constraint), tvarset, 
-	string, bool, io__state, io__state).
-:- mode mercury_output_class_constraint_list(in, in, in, in, di, uo) is det.
+:- pred mercury_format_class_constraint_list(list(class_constraint)::in,
+	tvarset::in, string::in, bool::in, U::di, U::uo) is det <= output(U).
 	
-mercury_output_class_constraint_list(Constraints, VarSet, Operator,
+mercury_format_class_constraint_list(Constraints, VarSet, Operator,
 		AppendVarnums) -->
 	(
 		{ Constraints = [] }
 	;
 		{ Constraints = [_|_] },
-		io__write_strings([" ", Operator, " ("]),
-		io__write_list(Constraints, ", ",
-			mercury_output_constraint(VarSet, AppendVarnums)),
-		io__write_char(')')
+		add_strings([" ", Operator, " ("]),
+		add_list(Constraints, ", ",
+			mercury_format_constraint(VarSet, AppendVarnums)),
+		add_string(")")
 	).
 
-	% This code could be written in terms of mercury_constraint_to_string
-	% and io__write_string, but for efficiency's sake it's probably not
-	% worth doing as it would mean building an intermediate string every
-	% time you print a constraint. (eg. when generating interface files).
 mercury_output_constraint(VarSet, AppendVarnums, constraint(Name, Types)) -->
-	mercury_output_sym_name(Name),
-	io__write_char('('),
-	io__write_list(Types, ", ", output_type(VarSet, AppendVarnums)),
-	io__write_char(')').
+	mercury_format_constraint(VarSet, AppendVarnums,
+		constraint(Name, Types)).
 
-mercury_constraint_to_string(VarSet, constraint(Name, Types), String) :-
-	prog_out__sym_name_to_string(Name, NameString),
-	mercury_type_list_to_string(VarSet, Types, TypeString),
-	string__append_list([NameString, "(", TypeString, ")"], String).
-
-mercury_type_list_to_string(_, [], "").
-mercury_type_list_to_string(VarSet, [T|Ts], String) :-
-	mercury_type_to_string(VarSet, T, String0),
-	type_list_to_string_2(VarSet, Ts, String1),
+mercury_constraint_to_string(VarSet, constraint(Name, Types)) = String :-
+	mercury_format_constraint(VarSet, no, constraint(Name, Types),
+		"", String).
+
+:- pred mercury_format_constraint(tvarset::in, bool::in, class_constraint::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_constraint(VarSet, AppendVarnums, constraint(Name, Types)) -->
+	mercury_format_sym_name(Name),
+	add_string("("),
+	add_list(Types, ", ", format_type(VarSet, AppendVarnums)),
+	add_string(")").
+
+:- pred format_type(tvarset::in, bool::in, (type)::in, U::di, U::uo) is det
+	<= output(U).
+
+format_type(VarSet, AppendVarnums, Type) -->
+	mercury_format_term(Type, VarSet, AppendVarnums).
+
+mercury_type_list_to_string(_, []) = "".
+mercury_type_list_to_string(VarSet, [T | Ts]) = String :-
+	String0 = mercury_type_to_string(VarSet, T),
+	String1 = mercury_type_list_to_string_2(VarSet, Ts),
 	string__append(String0, String1, String).
 
-:- pred type_list_to_string_2(tvarset, list(type), string).
-:- mode type_list_to_string_2(in, in, out) is det.
+:- func mercury_type_list_to_string_2(tvarset, list(type)) = string.
 
-type_list_to_string_2(_, [], "").
-type_list_to_string_2(VarSet, [T|Ts], String) :-
-	mercury_type_to_string(VarSet, T, String0),
-	type_list_to_string_2(VarSet, Ts, String1),
+mercury_type_list_to_string_2(_, []) = "".
+mercury_type_list_to_string_2(VarSet, [T | Ts]) = String :-
+	String0 = mercury_type_to_string(VarSet, T),
+	String1 = mercury_type_list_to_string_2(VarSet, Ts),
 	string__append_list([", ", String0, String1], String).
 
 	% XXX this should probably be a little cleverer, like
 	% mercury_output_term. 
-mercury_type_to_string(VarSet, term__variable(Var), String) :-
+mercury_type_to_string(VarSet, term__variable(Var)) = String :-
 	varset__lookup_name(VarSet, Var, String).
-mercury_type_to_string(VarSet, term__functor(Functor, Args, _), String) :-
+mercury_type_to_string(VarSet, term__functor(Functor, Args, _)) = String :-
 	(
 		Functor = term__atom(":"),
 		Args = [Arg1, Arg2]
 	->
-		mercury_type_to_string(VarSet, Arg1, String1),
-		mercury_type_to_string(VarSet, Arg2, String2),
+		String1 = mercury_type_to_string(VarSet, Arg1),
+		String2 = mercury_type_to_string(VarSet, Arg2),
 		string__append_list([String1, ":", String2], String)
 	;
 		(
@@ -1695,134 +1913,178 @@
 		->
 			String = String0
 		;
-			mercury_type_list_to_string(VarSet, Args, ArgsString),
+			ArgsString = mercury_type_list_to_string(VarSet, Args),
 			string__append_list([String0, "(", ArgsString, ")"],
 				String)
 		)
 	).
 
-:- pred output_type(tvarset, bool, (type), io__state, io__state).
-:- mode output_type(in, in, in, di, uo) is det.
-
-output_type(VarSet, AppendVarnums, Type) -->
-	mercury_output_term(Type, VarSet, AppendVarnums).
-
 %-----------------------------------------------------------------------------%
 
 	% Output a mode declaration for a predicate or function.
 
 mercury_output_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes, MaybeDet,
 		Context) -->
-	(	{ PredOrFunc = predicate },
-		mercury_output_pred_mode_subdecl(InstVarSet, Name, Modes,
+	mercury_format_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes,
+		MaybeDet, Context).
+
+mercury_mode_subdecl_to_string(PredOrFunc, InstVarSet, Name, Modes, MaybeDet,
+		Context) = String :-
+	mercury_format_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes,
+		MaybeDet, Context, "", String).
+
+:- pred mercury_format_mode_subdecl(pred_or_func::in, inst_varset::in,
+	sym_name::in, list(mode)::in, maybe(determinism)::in, prog_context::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes,
+		MaybeDet, Context) -->
+	(
+		{ PredOrFunc = predicate },
+		mercury_format_pred_mode_subdecl(InstVarSet, Name, Modes,
 				MaybeDet, Context)
 	;	{ PredOrFunc = function },
 		{ pred_args_to_func_args(Modes, ArgModes, RetMode) },
-		mercury_output_func_mode_subdecl(InstVarSet, Name, ArgModes,
+		mercury_format_func_mode_subdecl(InstVarSet, Name, ArgModes,
 				RetMode, MaybeDet, Context)
 	).
 
 	% Output a mode declaration for a predicate.
 
 mercury_output_pred_mode_decl(VarSet, PredName, Modes, MaybeDet, Context) -->
-	mercury_output_pred_mode_decl_2(VarSet, PredName, Modes, MaybeDet,
+	mercury_format_pred_mode_decl_2(VarSet, PredName, Modes, MaybeDet,
 		Context, ":- ", ".\n").
 
-:- pred mercury_output_pred_mode_decl_2(inst_varset, sym_name, list(mode),
-		maybe(determinism), prog_context, string, string, 
-		io__state, io__state).
-:- mode mercury_output_pred_mode_decl_2(in, in, in, in, in, in, in, 
-		di, uo) is det.
+mercury_pred_mode_decl_to_string(VarSet, PredName, Modes, MaybeDet, Context)
+		= String :-
+	mercury_format_pred_mode_decl_2(VarSet, PredName, Modes, MaybeDet,
+		Context, ":- ", ".\n", "", String).
+
+:- pred mercury_format_pred_mode_decl_2(inst_varset::in, sym_name::in,
+	list(mode)::in, maybe(determinism)::in, prog_context::in,
+	string::in, string::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_pred_mode_decl_2(VarSet, PredName, Modes, MaybeDet, Context,
+mercury_format_pred_mode_decl_2(VarSet, PredName, Modes, MaybeDet, Context,
 		StartString, Separator) -->
-	io__write_string(StartString),
-	io__write_string("mode "),
-	mercury_output_pred_mode_subdecl(VarSet, PredName, Modes, MaybeDet,
+	add_string(StartString),
+	add_string("mode "),
+	mercury_format_pred_mode_subdecl(VarSet, PredName, Modes, MaybeDet,
 		Context),
-	io__write_string(Separator).
+	add_string(Separator).
 
 mercury_output_pred_mode_subdecl(VarSet, PredName, Modes, MaybeDet,
+		Context) -->
+	mercury_format_pred_mode_subdecl(VarSet, PredName, Modes, MaybeDet,
+		Context).
+
+mercury_pred_mode_subdecl_to_string(VarSet, PredName, Modes, MaybeDet, Context)
+		= String :-
+	mercury_format_pred_mode_subdecl(VarSet, PredName, Modes, MaybeDet,
+		Context, "", String).
+
+:- pred mercury_format_pred_mode_subdecl(inst_varset::in, sym_name::in,
+	list(mode)::in, maybe(determinism)::in, prog_context::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_pred_mode_subdecl(VarSet, PredName, Modes, MaybeDet,
 		_Context) -->
 	(
-		{ Modes \= [] }
-	->
-		mercury_output_sym_name(PredName),
-		io__write_string("("),
-		mercury_output_mode_list(Modes, VarSet),
-		io__write_string(")")
+		{ Modes = [_|_] },
+		mercury_format_sym_name(PredName),
+		add_string("("),
+		mercury_format_mode_list(Modes, VarSet),
+		add_string(")")
 	;
-		mercury_output_bracketed_sym_name(PredName)
+		{ Modes = [] },
+		mercury_format_bracketed_sym_name(PredName)
 	),
-	mercury_output_det_annotation(MaybeDet).
+	mercury_format_det_annotation(MaybeDet).
 
 	% Output a mode declaration for a function.
 
 mercury_output_func_mode_decl(VarSet, FuncName, Modes, RetMode, MaybeDet,
 		Context) -->
-	mercury_output_func_mode_decl_2(VarSet, FuncName, Modes, RetMode,
+	mercury_format_func_mode_decl_2(VarSet, FuncName, Modes, RetMode,
 		MaybeDet, Context, ":- ", ".\n").
 
-:- pred mercury_output_func_mode_decl_2(inst_varset, sym_name, list(mode), mode,
-		maybe(determinism), prog_context, string, string,
-		io__state, io__state).
-:- mode mercury_output_func_mode_decl_2(in, in, in, in, in, in, in, in,
-	di, uo) is det.
+mercury_func_mode_decl_to_string(VarSet, FuncName, Modes, RetMode, MaybeDet,
+		Context) = String :-
+	mercury_format_func_mode_decl_2(VarSet, FuncName, Modes, RetMode,
+		MaybeDet, Context, ":- ", ".\n", "", String).
+
+:- pred mercury_format_func_mode_decl_2(inst_varset::in, sym_name::in,
+	list(mode)::in, (mode)::in, maybe(determinism)::in, prog_context::in,
+	string::in, string::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_func_mode_decl_2(VarSet, FuncName, Modes, RetMode, MaybeDet,
+mercury_format_func_mode_decl_2(VarSet, FuncName, Modes, RetMode, MaybeDet,
 		Context, StartString, Separator) -->
-	io__write_string(StartString),
-	io__write_string("mode "),
-	mercury_output_func_mode_subdecl(VarSet, FuncName, Modes, RetMode,
+	add_string(StartString),
+	add_string("mode "),
+	mercury_format_func_mode_subdecl(VarSet, FuncName, Modes, RetMode,
 		MaybeDet, Context),
-	io__write_string(Separator).
+	add_string(Separator).
 
 mercury_output_func_mode_subdecl(VarSet, FuncName, Modes, RetMode, MaybeDet,
+		Context) -->
+	mercury_format_func_mode_subdecl(VarSet, FuncName, Modes, RetMode,
+		MaybeDet, Context).
+
+mercury_func_mode_subdecl_to_string(VarSet, FuncName, Modes, RetMode, MaybeDet,
+		Context) = String :-
+	mercury_format_func_mode_subdecl(VarSet, FuncName, Modes, RetMode,
+		MaybeDet, Context, "", String).
+
+:- pred mercury_format_func_mode_subdecl(inst_varset::in, sym_name::in,
+	list(mode)::in, (mode)::in, maybe(determinism)::in, prog_context::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_func_mode_subdecl(VarSet, FuncName, Modes, RetMode, MaybeDet,
 		_Context) -->
 	(
-		{ Modes \= [] }
-	->
-		mercury_output_sym_name(FuncName),
-		io__write_string("("),
-		mercury_output_mode_list(Modes, VarSet),
-		io__write_string(")")
-	;
-		mercury_output_bracketed_sym_name(FuncName)
-	),
-	io__write_string(" = "),
-	mercury_output_mode(RetMode, VarSet),
-	mercury_output_det_annotation(MaybeDet).
+		{ Modes = [_|_] },
+		mercury_format_sym_name(FuncName),
+		add_string("("),
+		mercury_format_mode_list(Modes, VarSet),
+		add_string(")")
+	;
+		{ Modes = [] },
+		mercury_format_bracketed_sym_name(FuncName)
+	),
+	add_string(" = "),
+	mercury_format_mode(RetMode, VarSet),
+	mercury_format_det_annotation(MaybeDet).
 
-:- pred mercury_output_det_annotation(maybe(determinism), io__state, io__state).
-:- mode mercury_output_det_annotation(in, di, uo) is det.
+:- pred mercury_format_det_annotation(maybe(determinism)::in, U::di, U::uo)
+	is det <= output(U).
 
-mercury_output_det_annotation(MaybeDet) -->
+mercury_format_det_annotation(MaybeDet) -->
 	(
 		{ MaybeDet = no },
 		[]
 	;
 		{ MaybeDet = yes(Det) },
-		io__write_string(" is "),
-		mercury_output_det(Det)
+		add_string(" is "),
+		add_string(mercury_det_to_string(Det))
 	).
+
+mercury_output_det(Detism) -->
+	mercury_format_det(Detism).
+
+mercury_det_to_string(det) = "det".
+mercury_det_to_string(semidet) = "semidet".
+mercury_det_to_string(nondet) = "nondet".
+mercury_det_to_string(multidet) = "multi".
+mercury_det_to_string(cc_multidet) = "cc_multi".
+mercury_det_to_string(cc_nondet) = "cc_nondet".
+mercury_det_to_string(failure) = "failure".
+mercury_det_to_string(erroneous) = "erroneous".
 
-mercury_output_det(det) -->
-	io__write_string("det").
-mercury_output_det(semidet) -->
-	io__write_string("semidet").
-mercury_output_det(nondet) -->
-	io__write_string("nondet").
-mercury_output_det(multidet) -->
-	io__write_string("multi").
-mercury_output_det(cc_multidet) -->
-	io__write_string("cc_multi").
-mercury_output_det(cc_nondet) -->
-	io__write_string("cc_nondet").
-mercury_output_det(failure) -->
-	io__write_string("failure").
-mercury_output_det(erroneous) -->
-	io__write_string("erroneous").
+:- pred mercury_format_det(determinism::in,
+	U::di, U::uo) is det <= output(U).
 
+mercury_format_det(Detism) -->
+	add_string(mercury_det_to_string(Detism)).
+
 %-----------------------------------------------------------------------------%
 
 	% Output a clause.
@@ -1837,8 +2099,8 @@
 		{ Args = [Arg | Args0] }
 	->
 		io__write_string("("),
-		mercury_output_term(Arg, VarSet, no),
-		mercury_output_remaining_terms(Args0, VarSet, no),
+		mercury_format_term(Arg, VarSet, no),
+		mercury_format_remaining_terms(Args0, VarSet, no),
 		io__write_string(")")
 	;
 		[]
@@ -1864,8 +2126,8 @@
 		{ Args = [Arg | Args0] }
 	->
 		io__write_string("("),
-		mercury_output_term(Arg, VarSet, no),
-		mercury_output_remaining_terms(Args0, VarSet, no),
+		mercury_format_term(Arg, VarSet, no),
+		mercury_format_remaining_terms(Args0, VarSet, no),
 		io__write_string(")")
 	;
 		[]
@@ -1874,9 +2136,9 @@
 	(
 		{ Body = true - _Context0 }
 	->
-		mercury_output_term(Result, VarSet, no, next_to_graphic_token)
+		mercury_format_term(Result, VarSet, no, next_to_graphic_token)
 	;
-		mercury_output_term(Result, VarSet, no),
+		mercury_format_term(Result, VarSet, no),
 		io__write_string(" :-\n\t"),
 		mercury_output_goal(Body, VarSet, 1)
 	).
@@ -1898,7 +2160,7 @@
 	io__write_string("true").
 
 mercury_output_goal_2(implies(G1,G2), VarSet, Indent) -->
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	io__write_string("("),
 	mercury_output_newline(Indent1),
 	mercury_output_goal(G1, VarSet, Indent1),
@@ -1910,7 +2172,7 @@
 	io__write_string(")").
 
 mercury_output_goal_2(equivalent(G1,G2), VarSet, Indent) -->
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	io__write_string("("),
 	mercury_output_newline(Indent1),
 	mercury_output_goal(G1, VarSet, Indent1),
@@ -1928,7 +2190,7 @@
 		io__write_string("some ["),
 		mercury_output_vars(Vars, VarSet, no),
 		io__write_string("] ("),
-		{ Indent1 is Indent + 1 },
+		{ Indent1 = Indent + 1 },
 		mercury_output_newline(Indent1),
 		mercury_output_goal(Goal, VarSet, Indent1),
 		mercury_output_newline(Indent),
@@ -1942,7 +2204,7 @@
 		io__write_string("all ["),
 		mercury_output_vars(Vars, VarSet, no),
 		io__write_string("] ("),
-		{ Indent1 is Indent + 1 },
+		{ Indent1 = Indent + 1 },
 		mercury_output_newline(Indent1),
 		mercury_output_goal(Goal, VarSet, Indent1),
 		mercury_output_newline(Indent),
@@ -1952,7 +2214,7 @@
 mercury_output_goal_2(if_then_else(Vars, A, B, C), VarSet, Indent) -->
 	io__write_string("(if"),
 	mercury_output_some(Vars, VarSet),
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	mercury_output_newline(Indent1),
 	mercury_output_goal(A, VarSet, Indent1),
 	mercury_output_newline(Indent),
@@ -1969,7 +2231,7 @@
 mercury_output_goal_2(if_then(Vars, A, B), VarSet, Indent) -->
 	io__write_string("(if"),
 	mercury_output_some(Vars, VarSet),
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	mercury_output_newline(Indent1),
 	mercury_output_goal(A, VarSet, Indent1),
 	mercury_output_newline(Indent),
@@ -1981,7 +2243,7 @@
 
 mercury_output_goal_2(not(Goal), VarSet, Indent) -->
 	io__write_string("\\+ ("),
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	mercury_output_newline(Indent1),
 	mercury_output_goal(Goal, VarSet, Indent1),
 	mercury_output_newline(Indent),
@@ -1995,17 +2257,16 @@
 
 mercury_output_goal_2((A & B), VarSet, Indent) -->
 	io__write_string("("),
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	mercury_output_newline(Indent1),
 	mercury_output_goal(A, VarSet, Indent1),
 	mercury_output_par_conj(B, VarSet, Indent),
 	mercury_output_newline(Indent),
 	io__write_string(")").
 
-
 mercury_output_goal_2((A;B), VarSet, Indent) -->
 	io__write_string("("),
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	mercury_output_newline(Indent1),
 	mercury_output_goal(A, VarSet, Indent1),
 	mercury_output_disj(B, VarSet, Indent),
@@ -2022,7 +2283,6 @@
 	io__write_string(" = "),
 	mercury_output_term(B, VarSet, no, next_to_graphic_token).
 
-
 :- pred mercury_output_call(sym_name, list(prog_term), prog_varset, int,
 	io__state, io__state).
 :- mode mercury_output_call(in, in, in, in, di, uo) is det.
@@ -2049,7 +2309,7 @@
 mercury_output_disj(Goal, VarSet, Indent) -->
 	mercury_output_newline(Indent),
 	io__write_string(";"),
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	mercury_output_newline(Indent1),
 	(
 		{ Goal = (A;B) - _Context }
@@ -2067,7 +2327,7 @@
 mercury_output_par_conj(Goal, VarSet, Indent) -->
 	mercury_output_newline(Indent),
 	io__write_string("&"),
-	{ Indent1 is Indent + 1 },
+	{ Indent1 = Indent + 1 },
 	mercury_output_newline(Indent1),
 	(
 		{ Goal = (A & B) - _Context }
@@ -2095,46 +2355,60 @@
 %-----------------------------------------------------------------------------%
 
 mercury_output_pragma_foreign_decl(Lang, ForeignDeclString) -->
-	io__write_string(":- pragma foreign_decl("),
-	mercury_output_foreign_language_string(Lang),
-	io__write_string(", "),
-	mercury_output_foreign_code_string(ForeignDeclString),
-	io__write_string(").\n").
+	mercury_format_pragma_foreign_decl(Lang, ForeignDeclString).
 
-:- pred mercury_output_foreign_language_string(foreign_language::in,
-		io__state::di, io__state::uo) is det.
-mercury_output_foreign_language_string(Lang) -->
-	io__write_string("""" ++ foreign_language_string(Lang) ++ """").
+mercury_pragma_foreign_decl_to_string(Lang, ForeignDeclString) = String :-
+	mercury_format_pragma_foreign_decl(Lang, ForeignDeclString,
+		"", String).
+
+:- pred mercury_format_pragma_foreign_decl(foreign_language::in, string::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_pragma_foreign_decl(Lang, ForeignDeclString) -->
+	add_string(":- pragma foreign_decl("),
+	mercury_format_foreign_language_string(Lang),
+	add_string(", "),
+	mercury_format_foreign_code_string(ForeignDeclString),
+	add_string(").\n").
 
+:- pred mercury_format_foreign_language_string(foreign_language::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_foreign_language_string(Lang) -->
+	add_string("""" ++ foreign_language_string(Lang) ++ """").
+
 %-----------------------------------------------------------------------------%
 
 % The code here is similar to the code for term_io__quote_string,
 % but \n and \t are output directly, rather than escaped.
 % Any changes here may require corresponding changes to term_io and vice versa.
+
+:- pred mercury_format_foreign_code_string(string::in, 
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_foreign_code_string(S) -->
+	add_string(""""),
+	mercury_format_escaped_string(S),
+	add_string("""").
+
+:- pred mercury_format_escaped_string(string::in,
+	U::di, U::uo) is det <= output(U).
 
-:- pred mercury_output_foreign_code_string(string::in, 
-		io__state::di, io__state::uo) is det.
-mercury_output_foreign_code_string(S) -->
-	io__write_char('"'),
-	mercury_write_escaped_string(S),
-	io__write_char('"').
-
-:- pred mercury_write_escaped_string(string::in, io__state::di, io__state::uo)
-	is det.
-mercury_write_escaped_string(String) -->
-	string__foldl(mercury_write_escaped_char, String).
-
-:- pred mercury_write_escaped_char(char::in, io__state::di, io__state::uo)
-	is det.
-mercury_write_escaped_char(Char) -->
+mercury_format_escaped_string(String) -->
+	string__foldl(mercury_format_escaped_char, String).
+
+:- pred mercury_format_escaped_char(char::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_escaped_char(Char) -->
 	( { escape_special_char(Char, QuoteChar) } ->
-		io__write_char('\\'),
-		io__write_char(QuoteChar)
+		add_char('\\'),
+		add_char(QuoteChar)
 	; { mercury_is_source_char(Char) } ->
-		io__write_char(Char)
+		add_char(Char)
 	;
 		{ mercury_escape_char(Char, String) },
-		io__write_string(String)
+		add_string(String)
 	).
 
 :- pred mercury_escape_char(char, string).
@@ -2244,15 +2518,29 @@
 
 mercury_output_pragma_foreign_body_code(Lang, ForeignCodeString) -->
 	io__write_string(":- pragma foreign_code("),
-	mercury_output_foreign_language_string(Lang),
-	mercury_output_foreign_code_string(ForeignCodeString),
+	mercury_format_foreign_language_string(Lang),
+	mercury_format_foreign_code_string(ForeignCodeString),
 	io__write_string(").\n").
 
 %-----------------------------------------------------------------------------%
 
-	% Output the given pragma foreign_code declaration
 mercury_output_pragma_foreign_code(Attributes, PredName, PredOrFunc, Vars0,
 		VarSet, PragmaCode) -->
+	mercury_format_pragma_foreign_code(Attributes, PredName, PredOrFunc,
+		Vars0, VarSet, PragmaCode).
+
+mercury_pragma_foreign_code_to_string(Attributes, PredName, PredOrFunc, Vars0,
+		VarSet, PragmaCode) = String :-
+	mercury_format_pragma_foreign_code(Attributes, PredName, PredOrFunc,
+		Vars0, VarSet, PragmaCode, "", String).
+
+:- pred mercury_format_pragma_foreign_code(pragma_foreign_proc_attributes::in,
+	sym_name::in, pred_or_func::in, list(pragma_var)::in, prog_varset::in,
+	pragma_foreign_code_impl::in, U::di, U::uo) is det <= output(U).
+
+	% Output the given pragma foreign_code declaration
+mercury_format_pragma_foreign_code(Attributes, PredName, PredOrFunc, Vars0,
+		VarSet, PragmaCode) -->
 	(
 		{ PragmaCode = import(C_Function, _, _, _) },
 		% The predicate or function arguments in a `:- pragma import'
@@ -2261,32 +2549,30 @@
 			(func(pragma_var(_, _, ImportMode)) = ImportMode),
 			Vars0) },
 
-		mercury_output_pragma_import(PredName, PredOrFunc,
+		mercury_format_pragma_import(PredName, PredOrFunc,
 			ImportModes, Attributes, C_Function)
 	;
 		{ PragmaCode = ordinary(_, _) },
-		mercury_output_pragma_foreign_code_2(Attributes, PredName,
+		mercury_format_pragma_foreign_code_2(Attributes, PredName,
 			PredOrFunc, Vars0, VarSet, PragmaCode)
 	;
 		{ PragmaCode = nondet(_, _, _, _, _, _, _, _, _) },
-		mercury_output_pragma_foreign_code_2(Attributes, PredName,
+		mercury_format_pragma_foreign_code_2(Attributes, PredName,
 			PredOrFunc, Vars0, VarSet, PragmaCode)
 	).
 
-:- pred mercury_output_pragma_foreign_code_2(
-		pragma_foreign_proc_attributes, sym_name,
-		pred_or_func, list(pragma_var), prog_varset,
-		pragma_foreign_code_impl, io__state, io__state).
-:- mode mercury_output_pragma_foreign_code_2(
-		in, in, in, in, in, in, di, uo) is det.
+:- pred mercury_format_pragma_foreign_code_2(
+	pragma_foreign_proc_attributes::in, sym_name::in, pred_or_func::in,
+	list(pragma_var)::in, prog_varset::in, pragma_foreign_code_impl::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_pragma_foreign_code_2(Attributes, PredName, PredOrFunc, Vars0,
+mercury_format_pragma_foreign_code_2(Attributes, PredName, PredOrFunc, Vars0,
 		VarSet, PragmaCode) -->
-	io__write_string(":- pragma foreign_proc("),
+	add_string(":- pragma foreign_proc("),
 	{ foreign_language(Attributes, Lang) },
-	mercury_output_foreign_language_string(Lang),
-	io__write_string(", "),
-	mercury_output_sym_name(PredName),
+	mercury_format_foreign_language_string(Lang),
+	add_string(", "),
+	mercury_format_sym_name(PredName),
 	{
 		PredOrFunc = predicate,
 		Vars = Vars0,
@@ -2299,77 +2585,75 @@
 	( { Vars = [] } ->
 		[]
 	;
-		io__write_string("("),
-		mercury_output_pragma_foreign_code_vars(Vars, VarSet),
-		io__write_string(")")
+		add_string("("),
+		mercury_format_pragma_foreign_code_vars(Vars, VarSet),
+		add_string(")")
 	),
 	(
 		{ PredOrFunc = predicate }
 	;
 		{ PredOrFunc = function },
-		io__write_string(" = ("),
-		mercury_output_pragma_foreign_code_vars(ResultVars, VarSet),
-		io__write_string(")")
-	),
-	io__write_string(", "),
-	mercury_output_pragma_foreign_attributes(Attributes),
-	io__write_string(", "),
+		add_string(" = ("),
+		mercury_format_pragma_foreign_code_vars(ResultVars, VarSet),
+		add_string(")")
+	),
+	add_string(", "),
+	mercury_format_pragma_foreign_attributes(Attributes),
+	add_string(", "),
 	(
 		{ PragmaCode = ordinary(C_Code, _) },
-		mercury_output_foreign_code_string(C_Code)
+		mercury_format_foreign_code_string(C_Code)
 	;
 		{ PragmaCode = nondet(Fields, _, First, _,
 			Later, _, Treat, Shared, _) },
-		io__write_string("local_vars("),
-		mercury_output_foreign_code_string(Fields),
-		io__write_string("), "),
-		io__write_string("first_code("),
-		mercury_output_foreign_code_string(First),
-		io__write_string("), "),
-		io__write_string("retry_code("),
-		mercury_output_foreign_code_string(Later),
-		io__write_string("), "),
+		add_string("local_vars("),
+		mercury_format_foreign_code_string(Fields),
+		add_string("), "),
+		add_string("first_code("),
+		mercury_format_foreign_code_string(First),
+		add_string("), "),
+		add_string("retry_code("),
+		mercury_format_foreign_code_string(Later),
+		add_string("), "),
 		(
 			{ Treat = share },
-			io__write_string("shared_code(")
+			add_string("shared_code(")
 		;
 			{ Treat = duplicate },
-			io__write_string("duplicated_code(")
+			add_string("duplicated_code(")
 		;
 			{ Treat = automatic },
-			io__write_string("common_code(")
+			add_string("common_code(")
 		),
-		mercury_output_foreign_code_string(Shared),
-		io__write_string(")")
+		mercury_format_foreign_code_string(Shared),
+		add_string(")")
 	;
 		{ PragmaCode = import(_, _, _, _) },
 		% This should be handle in mercury_output_pragma_foreign_code.
 		{ error("mercury_output_pragma_foreign_code_2") }
 	),
-	io__write_string(").\n").
+	add_string(").\n").
 
 %-----------------------------------------------------------------------------%
 
 	% Output the varnames of the pragma vars
-:- pred mercury_output_pragma_foreign_code_vars(list(pragma_var), prog_varset,
-		io__state, io__state).
-:- mode mercury_output_pragma_foreign_code_vars(in, in, di, uo) is det.
+:- pred mercury_format_pragma_foreign_code_vars(list(pragma_var)::in,
+	prog_varset::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_pragma_foreign_code_vars([], _) --> [].
-mercury_output_pragma_foreign_code_vars([V|Vars], VarSet) -->
+mercury_format_pragma_foreign_code_vars([], _) --> [].
+mercury_format_pragma_foreign_code_vars([V|Vars], VarSet) -->
 	{ V = pragma_var(_Var, VarName, Mode) },
-	io__write_string(VarName),
-	io__write_string(" :: "),
+	add_string(VarName),
+	add_string(" :: "),
 		% XXX Fake the inst varset
 	{ varset__init(InstVarSet) },
-	mercury_output_mode(Mode, InstVarSet),
-	(	{ Vars = [] }
-	->
+	mercury_format_mode(Mode, InstVarSet),
+	( { Vars = [] } ->
 		[]
 	;
-		io__write_string(", ")
+		add_string(", ")
 	),
-	mercury_output_pragma_foreign_code_vars(Vars, VarSet).
+	mercury_format_pragma_foreign_code_vars(Vars, VarSet).
 
 %-----------------------------------------------------------------------------%
 
@@ -2436,181 +2720,192 @@
 	io__write_string(", "),
 	io__write_int(ModeNum),
 	io__write_string(", ["),
-	mercury_output_int_list(UnusedArgs),
+	mercury_format_int_list(UnusedArgs),
 	io__write_string("]).\n").
-
-:- pred mercury_output_int_list(list(int)::in,
-		io__state::di, io__state::uo) is det.
 
-mercury_output_int_list([]) --> [].
-mercury_output_int_list([First | Rest]) -->
-	io__write_int(First),
-	mercury_output_int_list_2(Rest).
+:- pred mercury_format_int_list(list(int)::in,
+	U::di, U::uo) is det <= output(U).
 
-:- pred mercury_output_int_list_2(list(int)::in,
-		io__state::di, io__state::uo) is det.
+mercury_format_int_list([]) --> [].
+mercury_format_int_list([First | Rest]) -->
+	add_int(First),
+	mercury_format_int_list_2(Rest).
+
+:- pred mercury_format_int_list_2(list(int)::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_int_list_2([]) --> [].
+mercury_format_int_list_2([First | Rest]) -->
+	add_string(", "),
+	add_int(First),
+	mercury_format_int_list_2(Rest).
 
-mercury_output_int_list_2([]) --> [].
-mercury_output_int_list_2([First | Rest]) -->
-	io__write_string(", "),
-	io__write_int(First),
-	mercury_output_int_list_2(Rest).
-
 %-----------------------------------------------------------------------------%
 
 mercury_output_pragma_decl(PredName, Arity, PredOrFunc, PragmaName) -->
+	mercury_format_pragma_decl(PredName, Arity, PredOrFunc, PragmaName).
+
+mercury_pragma_decl_to_string(PredName, Arity, PredOrFunc, PragmaName)
+		= String :-
+	mercury_format_pragma_decl(PredName, Arity, PredOrFunc, PragmaName,
+		"", String).
+
+:- pred mercury_format_pragma_decl(sym_name::in, int::in, pred_or_func::in,
+	string::in, U::di, U::uo) is det <= output(U).
+
+mercury_format_pragma_decl(PredName, Arity, PredOrFunc, PragmaName) -->
 	{ PredOrFunc = predicate,
 		DeclaredArity = Arity
 	; PredOrFunc = function,
 		DeclaredArity is Arity - 1
 	},
-	io__write_string(":- pragma "),
-	io__write_string(PragmaName),
-	io__write_string("("),
-	mercury_output_bracketed_sym_name(PredName, next_to_graphic_token),
-	io__write_string("/"),
-	io__write_int(DeclaredArity),
-	io__write_string(").\n").
+	add_string(":- pragma "),
+	add_string(PragmaName),
+	add_string("("),
+	mercury_format_bracketed_sym_name(PredName, next_to_graphic_token),
+	add_string("/"),
+	add_int(DeclaredArity),
+	add_string(").\n").
 
 %-----------------------------------------------------------------------------%
 
-:- pred mercury_output_pragma_import(sym_name, pred_or_func, list(mode),
-	pragma_foreign_proc_attributes, string, io__state, io__state).
-:- mode mercury_output_pragma_import(in, in, in, in, in, di, uo) is det.
+:- pred mercury_format_pragma_import(sym_name::in, pred_or_func::in,
+	list(mode)::in, pragma_foreign_proc_attributes::in, string::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_pragma_import(Name, PredOrFunc, ModeList, Attributes,
+mercury_format_pragma_import(Name, PredOrFunc, ModeList, Attributes,
 		C_Function) -->
 	{ varset__init(Varset) }, % the varset isn't really used.
-	io__write_string(":- pragma import("),
-	mercury_output_sym_name(Name),
+	add_string(":- pragma import("),
+	mercury_format_sym_name(Name),
 	(
 		{ PredOrFunc = function },
 		{ pred_args_to_func_args(ModeList, ArgModes, RetMode) },
-		io__write_string("("),
-		mercury_output_mode_list(ArgModes, Varset),
-		io__write_string(") = "),
-		mercury_output_mode(RetMode, Varset)
+		add_string("("),
+		mercury_format_mode_list(ArgModes, Varset),
+		add_string(") = "),
+		mercury_format_mode(RetMode, Varset)
 	;
 		{ PredOrFunc = predicate },
-		io__write_string("("),
-		mercury_output_mode_list(ModeList, Varset),
-		io__write_string(")")
-	),
-	io__write_string(", "),
-	mercury_output_pragma_foreign_attributes(Attributes),
-	io__write_string(", """),
-	io__write_string(C_Function),
-	io__write_string(""").\n").
+		add_string("("),
+		mercury_format_mode_list(ModeList, Varset),
+		add_string(")")
+	),
+	add_string(", "),
+	mercury_format_pragma_foreign_attributes(Attributes),
+	add_string(", """),
+	add_string(C_Function),
+	add_string(""").\n").
+
+:- pred mercury_format_pragma_export(sym_name::in, pred_or_func::in,
+	list(mode)::in, string::in,
+	U::di, U::uo) is det <= output(U).
 
-:- pred mercury_output_pragma_export(sym_name, pred_or_func, list(mode),
-	string, io__state, io__state).
-:- mode mercury_output_pragma_export(in, in, in, in, di, uo) is det.
-
-mercury_output_pragma_export(Name, PredOrFunc, ModeList, C_Function) -->
+mercury_format_pragma_export(Name, PredOrFunc, ModeList, C_Function) -->
 	{ varset__init(Varset) }, % the varset isn't really used.
-	io__write_string(":- pragma export("),
-	mercury_output_sym_name(Name),
+	add_string(":- pragma export("),
+	mercury_format_sym_name(Name),
 	(
 		{ PredOrFunc = function },
 		{ pred_args_to_func_args(ModeList, ArgModes, RetMode) },
-		io__write_string("("),
-		mercury_output_mode_list(ArgModes, Varset),
-		io__write_string(") = "),
-		mercury_output_mode(RetMode, Varset)
+		add_string("("),
+		mercury_format_mode_list(ArgModes, Varset),
+		add_string(") = "),
+		mercury_format_mode(RetMode, Varset)
 	;
 		{ PredOrFunc = predicate },
-		io__write_string("("),
-		mercury_output_mode_list(ModeList, Varset),
-		io__write_string(")")
-	),
-	io__write_string(", "),
-	io__write_string(C_Function),
-	io__write_string(").\n").
+		add_string("("),
+		mercury_format_mode_list(ModeList, Varset),
+		add_string(")")
+	),
+	add_string(", "),
+	add_string(C_Function),
+	add_string(").\n").
 
 %-----------------------------------------------------------------------------%
 
-:- pred mercury_output_pragma_fact_table(sym_name, arity, string,
-		io__state, io__state).
-:- mode mercury_output_pragma_fact_table(in, in, in, di, uo) is det.
-
-mercury_output_pragma_fact_table(Pred, Arity, FileName) -->
-	io__write_string(":- pragma fact_table("),
-	mercury_output_bracketed_sym_name(Pred, next_to_graphic_token),
-	io__write_string("/"),
-	io__write_int(Arity),
-	io__write_string(", "),
-	term_io__quote_string(FileName),
-	io__write_string(").\n").
+:- pred mercury_format_pragma_fact_table(sym_name::in, arity::in, string::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_pragma_fact_table(Pred, Arity, FileName) -->
+	add_string(":- pragma fact_table("),
+	mercury_format_bracketed_sym_name(Pred, next_to_graphic_token),
+	add_string("/"),
+	add_int(Arity),
+	add_string(", "),
+	add_quoted_string(FileName),
+	add_string(").\n").
 
 %-----------------------------------------------------------------------------%
-
-:- pred mercury_output_pragma_owner(sym_name, arity, string, 
-		io__state, io__state).
-:- mode mercury_output_pragma_owner(in, in, in, di, uo) is det.
 
-mercury_output_pragma_owner(Pred, Arity, Owner) -->
-	io__write_string(":- pragma owner("),
-	mercury_output_bracketed_sym_name(Pred, next_to_graphic_token),
-	io__write_string("/"),
-	io__write_int(Arity),
-	io__write_string(", "),
-	term_io__quote_atom(Owner),
-	io__write_string(").\n").
+:- pred mercury_format_pragma_owner(sym_name::in, arity::in, string::in, 
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_pragma_owner(Pred, Arity, Owner) -->
+	add_string(":- pragma owner("),
+	mercury_format_bracketed_sym_name(Pred, next_to_graphic_token),
+	add_string("/"),
+	add_int(Arity),
+	add_string(", "),
+	add_quoted_atom(Owner),
+	add_string(").\n").
+
+:- pred mercury_format_pragma_index(sym_name::in, arity::in, index_spec::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_pragma_index(PredName, Arity, IndexSpec) -->
+	add_string(":- pragma aditi_index("),
+	mercury_format_bracketed_sym_name(PredName, next_to_graphic_token),
+	add_string("/"),
+	add_int(Arity),
+	add_string(", "),
+	mercury_format_index_spec(IndexSpec),
+	add_string(").\n").
 
-:- pred mercury_output_pragma_index(sym_name, arity, index_spec,
-		io__state, io__state). 
-:- mode mercury_output_pragma_index(in, in, in, di, uo) is det.
+mercury_output_index_spec(IndexSpec) -->
+	mercury_format_index_spec(IndexSpec).
 
-mercury_output_pragma_index(PredName, Arity, IndexSpec) -->
-	io__write_string(":- pragma aditi_index("),
-	mercury_output_bracketed_sym_name(PredName, next_to_graphic_token),
-	io__write_string("/"),
-	io__write_int(Arity),
-	io__write_string(", "),
-	mercury_output_index_spec(IndexSpec),
-	io__write_string(").\n").
+:- pred mercury_format_index_spec(index_spec::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_index_spec(IndexSpec) -->
+mercury_format_index_spec(IndexSpec) -->
 	{ IndexSpec = index_spec(IndexType, Attrs) },
-	io__write(IndexType),
-	io__write_string(", ["),
-	mercury_output_int_list(Attrs),
-	io__write_string("]").
+	add_index_type(IndexType),
+	add_string(", ["),
+	mercury_format_int_list(Attrs),
+	add_string("]").
 
 %-----------------------------------------------------------------------------%
 
 mercury_output_newline(Indent) -->
 	io__write_char('\n'),
-	mercury_output_tabs(Indent).
+	mercury_format_tabs(Indent).
 
-:- pred mercury_output_tabs(int, io__state, io__state).
-:- mode mercury_output_tabs(in, di, uo) is det.
+:- pred mercury_format_tabs(int::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_tabs(Indent) -->
-	(
-		{ Indent = 0 }
-	->
+mercury_format_tabs(Indent) -->
+	( { Indent = 0 } ->
 		[]
 	;
-		io__write_char('\t'),
-		{ Indent1 is Indent - 1 },
-		mercury_output_tabs(Indent1)
+		add_string("\t"),
+		{ Indent1 = Indent - 1 },
+		mercury_format_tabs(Indent1)
 	).
 
 %-----------------------------------------------------------------------------%
 
-:- pred mercury_output_pragma_foreign_attributes(
-		pragma_foreign_proc_attributes, io__state, io__state).
-:- mode mercury_output_pragma_foreign_attributes(in, di, uo) is det.
+:- pred mercury_format_pragma_foreign_attributes(
+	pragma_foreign_proc_attributes::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_pragma_foreign_attributes(Attributes) -->
+mercury_format_pragma_foreign_attributes(Attributes) -->
 	% This is one case where it is a bad idea to use field
 	% accessors.  
 	{ attributes_to_strings(Attributes, AttrStrings) },
-	io__write_string("["),
-	io__write_list(AttrStrings, ", ", io__write_string),
-	io__write_string("]").
-
+	add_string("["),
+	add_list(AttrStrings, ", ", add_string),
+	add_string("]").
 
 %-----------------------------------------------------------------------------%
 
@@ -2619,147 +2914,175 @@
 mercury_output_term(Term, VarSet, AppendVarnums) -->
 	mercury_output_term(Term, VarSet, AppendVarnums,
 		not_next_to_graphic_token).
+
+mercury_output_term(Term, VarSet, AppendVarnums, NextToGraphicToken) -->
+	mercury_format_term(Term, VarSet, AppendVarnums, NextToGraphicToken).
+
+mercury_term_to_string(Term, VarSet, AppendVarnums) =
+	mercury_term_to_string(Term, VarSet, AppendVarnums,
+		not_next_to_graphic_token).
+
+mercury_term_to_string(Term, VarSet, AppendVarnums, NextToGraphicToken)
+		= String :-
+	mercury_format_term(Term, VarSet, AppendVarnums, NextToGraphicToken,
+		"", String).
+
+:- pred mercury_format_term(term(T)::in, varset(T)::in, bool::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_term(term__variable(Var), VarSet, AppendVarnums, _) -->
-	mercury_output_var(Var, VarSet, AppendVarnums).
-mercury_output_term(term__functor(Functor, Args, _), VarSet, AppendVarnums,
+mercury_format_term(Term, VarSet, AppendVarnums) -->
+	mercury_format_term(Term, VarSet, AppendVarnums,
+		not_next_to_graphic_token).
+
+:- pred mercury_format_term(term(T)::in, varset(T)::in, bool::in,
+	needs_quotes::in, U::di, U::uo) is det <= output(U).
+
+mercury_format_term(term__variable(Var), VarSet, AppendVarnums, _) -->
+	mercury_format_var(Var, VarSet, AppendVarnums).
+mercury_format_term(term__functor(Functor, Args, _), VarSet, AppendVarnums,
 		NextToGraphicToken) -->
 	(
 	    	{ Functor = term__atom("") },
 		{ Args = [F, X | Xs] }
 	->
-		mercury_output_term(F, VarSet, AppendVarnums,
+		mercury_format_term(F, VarSet, AppendVarnums,
 			NextToGraphicToken),
-		io__write_string("("),
-		mercury_output_term(X, VarSet, AppendVarnums),
-		mercury_output_remaining_terms(Xs, VarSet, AppendVarnums),
-		io__write_string(")")
+		add_string("("),
+		mercury_format_term(X, VarSet, AppendVarnums),
+		mercury_format_remaining_terms(Xs, VarSet, AppendVarnums),
+		add_string(")")
 	;
 	    	{ Functor = term__atom(".") },
 		{ Args = [X, Xs] }
 	->
-		io__write_string("["),
-		mercury_output_term(X, VarSet, AppendVarnums),
-		mercury_output_list_args(Xs, VarSet, AppendVarnums),
-		io__write_string("]")
+		add_string("["),
+		mercury_format_term(X, VarSet, AppendVarnums),
+		mercury_format_list_args(Xs, VarSet, AppendVarnums),
+		add_string("]")
 	;
 		{ Functor = term__atom("{}") },
 		{ Args = [X] }
 	->
 		% A unary tuple is usually a DCG escape,
 		% so add some extra space.
-		io__write_string("{ "),
-		mercury_output_term(X, VarSet, AppendVarnums),
-		io__write_string(" }")
+		add_string("{ "),
+		mercury_format_term(X, VarSet, AppendVarnums),
+		add_string(" }")
 	;
 		{ Functor = term__atom("{}") },
 		{ Args = [X | Xs] }
 	->
-		io__write_string("{"),
-		mercury_output_term(X, VarSet, AppendVarnums),
-		mercury_output_remaining_terms(Xs, VarSet, AppendVarnums),
-		io__write_string("}")
+		add_string("{"),
+		mercury_format_term(X, VarSet, AppendVarnums),
+		mercury_format_remaining_terms(Xs, VarSet, AppendVarnums),
+		add_string("}")
 	;
 		{ Args = [PrefixArg] },
 		{ Functor = term__atom(FunctorName) },
 		{ mercury_unary_prefix_op(FunctorName) }
 	->
-		io__write_string("("),
-		io__write_string(FunctorName),
-		io__write_string(" "),
-		mercury_output_term(PrefixArg, VarSet, AppendVarnums),
-		io__write_string(")")
+		add_string("("),
+		add_string(FunctorName),
+		add_string(" "),
+		mercury_format_term(PrefixArg, VarSet, AppendVarnums),
+		add_string(")")
 	;
 		{ Args = [PostfixArg] },
 		{ Functor = term__atom(FunctorName) },
 		{ mercury_unary_postfix_op(FunctorName) }
 	->
-		io__write_string("("),
-		mercury_output_term(PostfixArg, VarSet, AppendVarnums),
-		io__write_string(" "),
-		io__write_string(FunctorName),
-		io__write_string(")")
+		add_string("("),
+		mercury_format_term(PostfixArg, VarSet, AppendVarnums),
+		add_string(" "),
+		add_string(FunctorName),
+		add_string(")")
 	;
 		{ Args = [Arg1, Arg2] },
 		{ Functor = term__atom(FunctorName) },
 		{ mercury_infix_op(FunctorName) }
 	->
-		io__write_string("("),
+		add_string("("),
 		( { FunctorName = ":" } ->
-			mercury_output_term(Arg1, VarSet, AppendVarnums,
+			mercury_format_term(Arg1, VarSet, AppendVarnums,
 				next_to_graphic_token),
-			io__write_string(":"),
-			mercury_output_term(Arg2, VarSet, AppendVarnums,
+			add_string(":"),
+			mercury_format_term(Arg2, VarSet, AppendVarnums,
 				next_to_graphic_token)
 		;
-			mercury_output_term(Arg1, VarSet, AppendVarnums,
+			mercury_format_term(Arg1, VarSet, AppendVarnums,
 				not_next_to_graphic_token),
-			io__write_string(" "),
-			io__write_string(FunctorName),
-			io__write_string(" "),
-			mercury_output_term(Arg2, VarSet, AppendVarnums,
+			add_string(" "),
+			add_string(FunctorName),
+			add_string(" "),
+			mercury_format_term(Arg2, VarSet, AppendVarnums,
 				not_next_to_graphic_token)
 		),
-		io__write_string(")")
+		add_string(")")
 	;
 		{ Args = [Y | Ys] }
 	->
-		mercury_output_constant(Functor, NextToGraphicToken),
-		io__write_string("("),
-		mercury_output_term(Y, VarSet, AppendVarnums),
-		mercury_output_remaining_terms(Ys, VarSet, AppendVarnums),
-		io__write_string(")")
+		mercury_format_constant(Functor, NextToGraphicToken),
+		add_string("("),
+		mercury_format_term(Y, VarSet, AppendVarnums),
+		mercury_format_remaining_terms(Ys, VarSet, AppendVarnums),
+		add_string(")")
 	;
-		mercury_output_bracketed_constant(Functor, NextToGraphicToken)
+		mercury_format_bracketed_constant(Functor, NextToGraphicToken)
 	).
 
-:- pred mercury_output_list_args(term(T), varset(T), bool,
-		io__state, io__state).
-:- mode mercury_output_list_args(in, in, in, di, uo) is det.
+:- pred mercury_format_list_args(term(T)::in, varset(T)::in, bool::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_list_args(Term, VarSet, AppendVarnums) -->
+mercury_format_list_args(Term, VarSet, AppendVarnums) -->
 	(
 	    	{ Term = term__functor(term__atom("."), Args, _) },
 		{ Args = [X, Xs] }
 	->
-		io__write_string(", "),
-		mercury_output_term(X, VarSet, AppendVarnums),
-		mercury_output_list_args(Xs, VarSet, AppendVarnums)
+		add_string(", "),
+		mercury_format_term(X, VarSet, AppendVarnums),
+		mercury_format_list_args(Xs, VarSet, AppendVarnums)
 	;
 		{ Term = term__functor(term__atom("[]"), [], _) }
 	->
 		[]
 	;
-		io__write_string(" | "),
-		mercury_output_term(Term, VarSet, AppendVarnums)
+		add_string(" | "),
+		mercury_format_term(Term, VarSet, AppendVarnums)
 	).
 
-:- pred mercury_output_remaining_terms(list(term(T)), varset(T), bool,
-	io__state, io__state).
-:- mode mercury_output_remaining_terms(in, in, in, di, uo) is det.
+:- pred mercury_format_remaining_terms(list(term(T))::in, varset(T)::in,
+	bool::in, U::di, U::uo) is det <= output(U).
 
-mercury_output_remaining_terms([], _VarSet, _AppendVarnums) --> [].
-mercury_output_remaining_terms([Term | Terms], VarSet, AppendVarnums) -->
-	io__write_string(", "),
-	mercury_output_term(Term, VarSet, AppendVarnums),
-	mercury_output_remaining_terms(Terms, VarSet, AppendVarnums).
+mercury_format_remaining_terms([], _VarSet, _AppendVarnums) --> [].
+mercury_format_remaining_terms([Term | Terms], VarSet, AppendVarnums) -->
+	add_string(", "),
+	mercury_format_term(Term, VarSet, AppendVarnums),
+	mercury_format_remaining_terms(Terms, VarSet, AppendVarnums).
 
 	% output a comma-separated list of variables
 
-mercury_output_vars([], _VarSet, _AppendVarnum) --> [].
-mercury_output_vars([Var | Vars], VarSet, AppendVarnum) -->
-	mercury_output_var(Var, VarSet, AppendVarnum),
-	mercury_output_vars_2(Vars, VarSet, AppendVarnum).
+mercury_output_vars(Vars, VarSet, AppendVarnum) -->
+	mercury_format_vars(Vars, VarSet, AppendVarnum).
 
-:- pred mercury_output_vars_2(list(var(T)), varset(T), bool,
-		io__state, io__state).
-:- mode mercury_output_vars_2(in, in, in, di, uo) is det.
+mercury_vars_to_string(Vars, VarSet, AppendVarnum) = String :-
+	mercury_format_vars(Vars, VarSet, AppendVarnum, "", String).
 
-mercury_output_vars_2([], _VarSet, _AppendVarnum) --> [].
-mercury_output_vars_2([Var | Vars], VarSet, AppendVarnum) -->
-	io__write_string(", "),
-	mercury_output_var(Var, VarSet, AppendVarnum),
-	mercury_output_vars_2(Vars, VarSet, AppendVarnum).
+:- pred mercury_format_vars(list(var(T))::in, varset(T)::in,
+	bool::in, U::di, U::uo) is det <= output(U).
+
+mercury_format_vars([], _VarSet, _AppendVarnum) --> [].
+mercury_format_vars([Var | Vars], VarSet, AppendVarnum) -->
+	mercury_format_var(Var, VarSet, AppendVarnum),
+	mercury_format_vars_2(Vars, VarSet, AppendVarnum).
+
+:- pred mercury_format_vars_2(list(var(T))::in, varset(T)::in,
+	bool::in, U::di, U::uo) is det <= output(U).
+
+mercury_format_vars_2([], _VarSet, _AppendVarnum) --> [].
+mercury_format_vars_2([Var | Vars], VarSet, AppendVarnum) -->
+	add_string(", "),
+	mercury_format_var(Var, VarSet, AppendVarnum),
+	mercury_format_vars_2(Vars, VarSet, AppendVarnum).
 
 	% Output a single variable.
 	% Variables that didn't have names are given the name "V_<n>"
@@ -2768,16 +3091,25 @@
 	% name changed to start with `V__' to avoid name clashes.
 
 mercury_output_var(Var, VarSet, AppendVarnum) -->
+	mercury_format_var(Var, VarSet, AppendVarnum).
+
+mercury_var_to_string(Var, VarSet, AppendVarnum) = String :-
+	mercury_format_var(Var, VarSet, AppendVarnum, "", String).
+
+:- pred mercury_format_var(var(T)::in, varset(T)::in,
+	bool::in, U::di, U::uo) is det <= output(U).
+
+mercury_format_var(Var, VarSet, AppendVarnum) -->
 	(
 		{ varset__search_name(VarSet, Var, Name) }
 	->
 		{ mercury_convert_var_name(Name, ConvertedName) },
-		io__write_string(ConvertedName),
+		add_string(ConvertedName),
 		(
 			{ AppendVarnum = yes },
 			{ term__var_to_int(Var, VarNum) },
-			io__write_string("_"),
-			io__write_int(VarNum)
+			add_string("_"),
+			add_int(VarNum)
 		;
 			{ AppendVarnum = no }
 		)
@@ -2785,49 +3117,47 @@
 		{ term__var_to_int(Var, Id) },
 		{ string__int_to_string(Id, Num) },
 		{ string__append("V_", Num, VarName) },
-		io__write_string(VarName)
+		add_string(VarName)
 	).
 
-:- pred mercury_output_bracketed_constant(const, io__state, io__state).
-:- mode mercury_output_bracketed_constant(in, di, uo) is det.
+:- pred mercury_format_bracketed_constant(const::in, U::di, U::uo) is det
+	<= output(U).
 
-mercury_output_bracketed_constant(Const) -->
-	mercury_output_bracketed_constant(Const, not_next_to_graphic_token).
+mercury_format_bracketed_constant(Const) -->
+	mercury_format_bracketed_constant(Const, not_next_to_graphic_token).
 
-:- pred mercury_output_bracketed_constant(const, needs_quotes,
-					io__state, io__state).
-:- mode mercury_output_bracketed_constant(in, in, di, uo) is det.
+:- pred mercury_format_bracketed_constant(const::in, needs_quotes::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_bracketed_constant(Const, NextToGraphicToken) -->
+mercury_format_bracketed_constant(Const, NextToGraphicToken) -->
 	( { Const = term__atom(Op), mercury_op(Op) } ->
-		io__write_string("("),
-		term_io__quote_atom(Op),
-		io__write_string(")")
+		add_string("("),
+		add_quoted_atom(Op),
+		add_string(")")
 	;
-		mercury_output_constant(Const, NextToGraphicToken)
+		mercury_format_constant(Const, NextToGraphicToken)
 	).
 
-:- pred mercury_output_constant(const, needs_quotes, io__state, io__state).
-:- mode mercury_output_constant(in, in, di, uo) is det.
+:- pred mercury_format_constant(const::in, needs_quotes::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_constant(Const, NextToGraphicToken) -->
+mercury_format_constant(Const, NextToGraphicToken) -->
 	( { Const = term__atom(Atom) } ->
-		mercury_quote_atom(Atom, NextToGraphicToken)
+		mercury_format_quoted_atom(Atom, NextToGraphicToken)
 	;
-		term_io__write_constant(Const)
+		add_constant(Const)
 	).
 
-:- pred mercury_output_bracketed_atom(string, needs_quotes,
-				io__state, io__state).
-:- mode mercury_output_bracketed_atom(in, in, di, uo) is det.
+:- pred mercury_format_bracketed_atom(string::in, needs_quotes::in,
+	U::di, U::uo) is det <= output(U).
 
-mercury_output_bracketed_atom(Name, NextToGraphicToken) -->
+mercury_format_bracketed_atom(Name, NextToGraphicToken) -->
 	( { mercury_op(Name) } ->
-		io__write_string("("),
-		term_io__quote_atom(Name),
-		io__write_string(")")
+		add_string("("),
+		add_quoted_atom(Name),
+		add_string(")")
 	;
-		mercury_quote_atom(Name, NextToGraphicToken)
+		mercury_format_quoted_atom(Name, NextToGraphicToken)
 	).
 
 	%
@@ -2841,41 +3171,77 @@
 mercury_output_sym_name(SymName) -->
 	mercury_output_sym_name(SymName, not_next_to_graphic_token).
 
+:- pred mercury_output_sym_name(sym_name, needs_quotes, io__state, io__state).
+:- mode mercury_output_sym_name(in, in, di, uo) is det.
+
+mercury_output_sym_name(Name, NextToGraphicToken) -->
+	mercury_format_sym_name(Name, NextToGraphicToken).
+
 mercury_output_bracketed_sym_name(SymName) -->
 	mercury_output_bracketed_sym_name(SymName, not_next_to_graphic_token).
 
 mercury_output_bracketed_sym_name(Name, NextToGraphicToken) -->
-	(	{ Name = qualified(ModuleName, Name2) },
-		io__write_char('('),
-		mercury_output_bracketed_sym_name(ModuleName,
+	mercury_format_bracketed_sym_name(Name, NextToGraphicToken).
+
+:- pred mercury_format_bracketed_sym_name(sym_name::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_bracketed_sym_name(Name) -->
+	mercury_format_bracketed_sym_name(Name, not_next_to_graphic_token).
+
+:- pred mercury_format_bracketed_sym_name(sym_name::in, needs_quotes::in,
+	U::di, U::uo) is det <= output(U).
+
+mercury_format_bracketed_sym_name(Name, NextToGraphicToken) -->
+	(
+		{ Name = qualified(ModuleName, Name2) },
+		add_string("("),
+		mercury_format_bracketed_sym_name(ModuleName,
 			next_to_graphic_token),
-		io__write_char(':'),
-		mercury_output_bracketed_atom(Name2, next_to_graphic_token),
-		io__write_char(')')
+		add_string(":"),
+		mercury_format_bracketed_atom(Name2, next_to_graphic_token),
+		add_string(")")
 	;
 		{ Name = unqualified(Name2) },
-		mercury_output_bracketed_atom(Name2, NextToGraphicToken)
+		mercury_format_bracketed_atom(Name2, NextToGraphicToken)
 	).
 
-:- pred mercury_output_sym_name(sym_name, needs_quotes, io__state, io__state).
-:- mode mercury_output_sym_name(in, in, di, uo) is det.
+:- pred mercury_format_sym_name(sym_name::in, U::di, U::uo)
+	is det <= output(U).
 
-mercury_output_sym_name(Name, NextToGraphicToken) -->
-	(	{ Name = qualified(ModuleName, PredName) },
-		mercury_output_bracketed_sym_name(ModuleName,
+mercury_format_sym_name(SymName) -->
+	mercury_format_sym_name(SymName, not_next_to_graphic_token).
+
+:- pred mercury_format_sym_name(sym_name::in, needs_quotes::in, U::di, U::uo)
+	is det <= output(U).
+
+mercury_format_sym_name(Name, NextToGraphicToken) -->
+	(
+		{ Name = qualified(ModuleName, PredName) },
+		mercury_format_bracketed_sym_name(ModuleName,
 			next_to_graphic_token),
-		io__write_char(':'),
-		mercury_quote_atom(PredName,
-			next_to_graphic_token)
+		add_string(":"),
+		mercury_format_quoted_atom(PredName, next_to_graphic_token)
 	;
 		{ Name = unqualified(PredName) },
-		mercury_quote_atom(PredName, NextToGraphicToken)
+		mercury_format_quoted_atom(PredName, NextToGraphicToken)
 	).
 
 :- pred mercury_quote_atom(string, needs_quotes, io__state, io__state).
 :- mode mercury_quote_atom(in, in, di, uo) is det.
 
 mercury_quote_atom(Name, NextToGraphicToken) -->
+	mercury_format_quoted_atom(Name, NextToGraphicToken).
+
+:- func mercury_quoted_atom_to_string(string, needs_quotes) = string.
+
+mercury_quoted_atom_to_string(Name, NextToGraphicToken) = String :-
+	mercury_format_quoted_atom(Name, NextToGraphicToken, "", String).
+
+:- pred mercury_format_quoted_atom(string::in, needs_quotes::in, U::di, U::uo)
+	is det <= output(U).
+
+mercury_format_quoted_atom(Name, NextToGraphicToken) -->
 	%
 	% If the symname is composed of only graphic token chars,
 	% then term_io__quote_atom will not quote it; but if
@@ -2890,11 +3256,11 @@
 		{ \+ (  list__member(Char, Chars),
 			\+ lexer__graphic_token_char(Char)) }
 	->
-		io__write_string("'"),
-		term_io__write_escaped_string(Name),
-		io__write_string("'")
+		add_string("'"),
+		add_escaped_string(Name),
+		add_string("'")
 	;
-		term_io__quote_atom(Name)
+		add_quoted_atom(Name)
 	).
 
 %-----------------------------------------------------------------------------%
@@ -3104,6 +3470,189 @@
 		io__write_string("\n")
 	;
 		[]
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- typeclass output(U) where [
+	pred add_string(string::in, U::di, U::uo) is det,
+	pred add_strings(list(string)::in, U::di, U::uo) is det,
+	pred add_char(char::in, U::di, U::uo) is det,
+	pred add_int(int::in, U::di, U::uo) is det,
+	pred add_float(float::in, U::di, U::uo) is det,
+	pred add_purity_prefix(purity::in, U::di, U::uo) is det,
+	pred add_quoted_atom(string::in, U::di, U::uo) is det,
+	pred add_quoted_string(string::in, U::di, U::uo) is det,
+	pred add_constant(const::in, U::di, U::uo) is det,
+	pred add_class_id(class_id::in, U::di, U::uo) is det,
+	pred add_eval_method(eval_method::in, U::di, U::uo) is det,
+	pred add_lambda_eval_method(lambda_eval_method::in, U::di, U::uo)
+		is det,
+	pred add_index_type(index_type::in, U::di, U::uo) is det,
+	pred add_escaped_string(string::in, U::di, U::uo) is det,
+	pred add_format(string::in, list(io__poly_type)::in,
+		U::di, U::uo) is det,
+	pred add_list(list(T)::in, string::in,
+		pred(T, U, U)::pred(in, di, uo) is det,
+		U::di, U::uo) is det
+].
+
+:- instance output(io__state) where [
+	pred(add_string/3) is io__write_string,
+	pred(add_strings/3) is io__write_strings,
+	pred(add_char/3) is io__write_char,
+	pred(add_int/3) is io__write_int,
+	pred(add_float/3) is io__write_float,
+	pred(add_purity_prefix/3) is write_purity_prefix,
+	pred(add_quoted_atom/3) is term_io__quote_atom,
+	pred(add_quoted_string/3) is term_io__quote_string,
+	pred(add_constant/3) is term_io__write_constant,
+	pred(add_class_id/3) is io__write,
+	pred(add_eval_method/3) is io__write,
+	pred(add_lambda_eval_method/3) is io__write,
+	pred(add_index_type/3) is io__write,
+	pred(add_escaped_string/3) is term_io__write_escaped_string,
+	pred(add_format/4) is io__format,
+	pred(add_list/5) is io__write_list
+].
+
+:- instance output(string) where [
+	pred(add_string/3) is output_string,
+	pred(add_strings/3) is output_strings,
+	pred(add_char/3) is output_char,
+	pred(add_int/3) is output_int,
+	pred(add_float/3) is output_float,
+	pred(add_purity_prefix/3) is output_purity_prefix,
+	pred(add_quoted_atom/3) is output_quoted_atom,
+	pred(add_quoted_string/3) is output_quoted_string,
+	pred(add_constant/3) is output_constant,
+	pred(add_class_id/3) is output_class_id,
+	pred(add_eval_method/3) is output_eval_method,
+	pred(add_lambda_eval_method/3) is output_lambda_eval_method,
+	pred(add_index_type/3) is output_index_type,
+	pred(add_escaped_string/3) is output_escaped_string,
+	pred(add_format/4) is output_format,
+	pred(add_list/5) is output_list
+].
+
+:- pred output_string(string::in, string::di, string::uo) is det.
+
+output_string(S, Str0, Str) :-
+	string__append(Str0, S, Str).
+
+:- pred output_strings(list(string)::in, string::di, string::uo) is det.
+
+output_strings(Strs, Str0, Str) :-
+	string__append_list([Str0 | Strs], Str).
+
+:- pred output_char(char::in, string::di, string::uo) is det.
+
+output_char(C, Str0, Str) :-
+	string__char_to_string(C, S),
+	string__append(Str0, S, Str).
+
+:- pred output_int(int::in, string::di, string::uo) is det.
+
+output_int(I, Str0, Str) :-
+	string__int_to_string(I, S),
+	string__append(Str0, S, Str).
+
+:- pred output_float(float::in, string::di, string::uo) is det.
+
+output_float(F, Str0, Str) :-
+	string__float_to_string(F, S),
+	string__append(Str0, S, Str).
+
+:- pred output_purity_prefix(purity::in, string::di, string::uo) is det.
+
+output_purity_prefix(P, Str0, Str) :-
+	S = purity_prefix_to_string(P),
+	string__append(Str0, S, Str).
+
+:- pred output_quoted_atom(string::in, string::di, string::uo) is det.
+
+output_quoted_atom(A, Str0, Str) :-
+	QA = term_io__quoted_atom(A),
+	string__append(Str0, QA, Str).
+
+:- pred output_quoted_string(string::in, string::di, string::uo) is det.
+
+output_quoted_string(A, Str0, Str) :-
+	QA = term_io__quoted_string(A),
+	string__append(Str0, QA, Str).
+
+:- pred output_constant(const::in, string::di, string::uo) is det.
+
+output_constant(C, Str0, Str) :-
+	CS = term_io__format_constant(C),
+	string__append(Str0, CS, Str).
+
+:- pred output_escaped_string(string::in, string::di, string::uo) is det.
+
+output_escaped_string(S, Str0, Str) :-
+	ES = term_io__escaped_string(S),
+	string__append(Str0, ES, Str).
+
+:- pred output_class_id(class_id::in, string::di, string::uo) is det.
+
+output_class_id(class_id(Name, Arity)) -->
+	output_string("class_id("),
+	mercury_format_sym_name(Name),
+	output_string(", "),
+	output_int(Arity),
+	output_string(")").
+
+:- pred output_eval_method(eval_method::in, string::di, string::uo) is det.
+
+output_eval_method(eval_normal) -->
+	output_string("eval_normal").
+output_eval_method(eval_loop_check) -->
+	output_string("eval_loop_check").
+output_eval_method(eval_memo) -->
+	output_string("eval_memo").
+output_eval_method(eval_table_io) -->
+	output_string("eval_table_io").
+output_eval_method(eval_minimal) -->
+	output_string("eval_minimal").
+
+:- pred output_lambda_eval_method(lambda_eval_method::in,
+	string::di, string::uo) is det.
+
+output_lambda_eval_method(normal) -->
+	output_string("normal").
+output_lambda_eval_method(aditi_top_down) -->
+	output_string("aditi_top_down").
+output_lambda_eval_method(aditi_bottom_up) -->
+	output_string("aditi_bottom_up").
+
+:- pred output_index_type(index_type::in, string::di, string::uo) is det.
+
+output_index_type(unique_B_tree) -->
+	output_string("unique_B_tree").
+output_index_type(non_unique_B_tree) -->
+	output_string("non_unique_B_tree").
+
+:- pred output_format(string::in, list(io__poly_type)::in,
+	string::di, string::uo) is det.
+
+output_format(Format, Items, Str0, Str) :-
+	S = string__format(Format, Items),
+	string__append(Str0, S, Str).
+
+:- pred output_list(list(T)::in, string::in,
+	pred(T, string, string)::pred(in, di, uo) is det,
+	string::di, string::uo) is det.
+
+output_list([], _, _, Str, Str).
+output_list([Item | Items], Sep, Pred, Str0, Str) :-
+	Pred(Item, Str0, Str1),
+	(
+		Items = [],
+		Str = Str1
+	;
+		Items = [_|_],
+		output_string(Sep, Str1, Str2),
+		output_list(Items, Sep, Pred, Str2, Str)
 	).
 
 %-----------------------------------------------------------------------------%
Index: compiler/prog_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_util.m,v
retrieving revision 1.53
diff -u -b -r1.53 prog_util.m
--- compiler/prog_util.m	2001/06/27 05:04:26	1.53
+++ compiler/prog_util.m	2001/08/02 13:30:11
@@ -448,7 +448,7 @@
 		SubstToString = lambda([SubstElem::in, SubstStr::out] is det, (
 			SubstElem = Var - Type,
 			varset__lookup_name(VarSet, Var, VarName),
-			mercury_type_to_string(VarSet, Type, TypeString),
+			TypeString = mercury_type_to_string(VarSet, Type),
 			string__append_list([VarName, " = ", TypeString],
 				SubstStr)
 		)),
Index: compiler/purity.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/purity.m,v
retrieving revision 1.36
diff -u -b -r1.36 purity.m
--- compiler/purity.m	2001/07/31 14:29:54	1.36
+++ compiler/purity.m	2001/07/31 23:38:29
@@ -170,6 +170,8 @@
 :- pred write_purity_prefix(purity, io__state, io__state).
 :- mode write_purity_prefix(in, di, uo) is det.
 
+:- func purity_prefix_to_string(purity) = string.
+
 %  Get a purity name as a string.
 :- pred purity_name(purity, string).
 :- mode purity_name(in, out) is det.
@@ -298,6 +300,14 @@
 	;
 		write_purity(Purity),
 		io__write_string(" ")
+	).
+
+purity_prefix_to_string(Purity) = String :-
+	( Purity = pure ->
+		String = ""
+	;
+		purity_name(Purity, PurityName),
+		String = string__append(PurityName, " ")
 	).
 
 write_purity(Purity) -->
Index: compiler/typecheck.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/typecheck.m,v
retrieving revision 1.306
diff -u -b -r1.306 typecheck.m
--- compiler/typecheck.m	2001/07/20 14:14:25	1.306
+++ compiler/typecheck.m	2001/07/28 08:29:01
@@ -4665,14 +4665,14 @@
 	io__write_string("  `"),
 	mercury_output_var(X, VarSet, no),
 	io__write_string("'"),
-	write_type_of_var(TypeCheckInfo, TypeAssignSet, X),
+	write_type_of_var(TypeCheckInfo, Context, TypeAssignSet, X),
 	io__write_string(",\n"),
 
 	prog_out__write_context(Context),
 	io__write_string("  `"),
 	mercury_output_var(Y, VarSet, no),
 	io__write_string("'"),
-	write_type_of_var(TypeCheckInfo, TypeAssignSet, Y),
+	write_type_of_var(TypeCheckInfo, Context, TypeAssignSet, Y),
 	io__write_string(".\n"),
 
 	write_type_assign_set_msg(TypeAssignSet, VarSet).
@@ -4705,7 +4705,7 @@
 	prog_out__write_context(Context),
 	io__write_string("  "),
 	write_argument_name(VarSet, Var),
-	write_type_of_var(TypeCheckInfo, TypeAssignSet, Var),
+	write_type_of_var(TypeCheckInfo, Context, TypeAssignSet, Var),
 	io__write_string(",\n"),
 
 	prog_out__write_context(Context),
@@ -4765,7 +4765,7 @@
 	prog_out__write_context(Context),
 	io__write_string("  "),
 	write_argument_name(VarSet, Var),
-	write_type_of_var(TypeCheckInfo, TypeAssignSet, Var),
+	write_type_of_var(TypeCheckInfo, Context, TypeAssignSet, Var),
 	io__write_string(",\n"),
 
 	prog_out__write_context(Context),
@@ -4869,7 +4869,8 @@
 			prog_out__write_context(Context),
 			io__write_string("  "),
 			write_argument_name(VarSet, Var),
-			write_type_of_var(TypeCheckInfo, TypeAssignSet, Var),
+			write_type_of_var(TypeCheckInfo, Context,
+				TypeAssignSet, Var),
 			io__write_string(",\n")
 		;
 			[]
@@ -4992,7 +4993,7 @@
 	prog_out__write_context(Context),
 	io__write_string("  "),
 	write_argument_name(VarSet, Var),
-	write_type_of_var(TypeCheckInfo, TypeAssignSet, Var),
+	write_type_of_var(TypeCheckInfo, Context, TypeAssignSet, Var),
 	write_types_of_vars(Vars, VarSet, Context, TypeCheckInfo,
 		TypeAssignSet).
 
@@ -5031,20 +5032,22 @@
 		io__write_string("'")
 	).
 
-:- pred write_type_of_var(typecheck_info, type_assign_set, prog_var,
-				io__state, io__state).
-:- mode write_type_of_var(typecheck_info_no_io, in, in, di, uo) is det.
+:- pred write_type_of_var(typecheck_info, prog_context, type_assign_set,
+	prog_var, io__state, io__state).
+:- mode write_type_of_var(typecheck_info_no_io, in, in, in, di, uo) is det.
 
-write_type_of_var(_TypeCheckInfo, TypeAssignSet, Var) -->
+write_type_of_var(_TypeCheckInfo, Context, TypeAssignSet, Var) -->
 	{ get_type_stuff(TypeAssignSet, Var, TypeStuffList) },
-	( { TypeStuffList = [SingleTypeStuff] } ->
-		{ SingleTypeStuff = type_stuff(VType, TVarSet, TBinding) },
+	{ TypeStrs0 = list__map(typestuff_to_typestr, TypeStuffList) },
+	{ list__sort_and_remove_dups(TypeStrs0, TypeStrs) },
+	( { TypeStrs = [TypeStr] } ->
 		io__write_string(" has type `"),
-		write_type_b(VType, TVarSet, TBinding),
+		io__write_string(TypeStr),
 		io__write_string("'")
 	;
-		io__write_string(" has overloaded type { "),
-		write_type_stuff_list(TypeStuffList),
+		io__write_string(" has overloaded type {\n"),
+		write_types_list(Context, TypeStrs),
+		prog_out__write_context(Context),
 		io__write_string(" }")
 	).
 
@@ -5273,6 +5276,14 @@
 	{ strip_builtin_qualifiers_from_type(Type2, Type3) },
 	mercury_output_term(Type3, TypeVarSet, no).
 
+:- func typestuff_to_typestr(type_stuff) = string.
+
+typestuff_to_typestr(TypeStuff) = TypeStr :-
+	TypeStuff = type_stuff(Type0, TypeVarSet, TypeBindings),
+	term__apply_rec_substitution(Type0, TypeBindings, Type1),
+	strip_builtin_qualifiers_from_type(Type1, Type),
+	TypeStr = mercury_term_to_string(Type, TypeVarSet, no).
+
 %-----------------------------------------------------------------------------%
 
 :- pred report_error_var(typecheck_info, prog_var, type, type_assign_set,
@@ -5371,11 +5382,20 @@
 	),
 	write_args_type_assign_set_msg(ArgTypeAssignSet0, VarSet).
 
-:- pred write_type_stuff_list(list(type_stuff), io__state, io__state).
-:- mode write_type_stuff_list(in, di, uo) is det.
+:- pred write_types_list(prog_context::in, list(string)::in,
+	io__state::di, io__state::uo) is det.
 
-write_type_stuff_list(Ts) -->
-	io__write_list(Ts, ", ", write_type_stuff).
+write_types_list(_Context, []) --> [].
+write_types_list(Context, [Type | Types]) -->
+	prog_out__write_context(Context),
+	io__write_string("   "),
+	io__write_string(Type),
+	( { Types = [] } ->
+		io__write_string("\n")
+	;
+		io__write_string(",\n"),
+		write_types_list(Context, Types)
+	).
 
 :- pred write_type_stuff(type_stuff, io__state, io__state).
 :- mode write_type_stuff(in, di, uo) is det.
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
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/graphics
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/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/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
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 java
cvs diff: Diffing library
Index: library/string.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/string.m,v
retrieving revision 1.150
diff -u -b -r1.150 string.m
--- library/string.m	2001/08/01 00:31:18	1.150
+++ library/string.m	2001/08/01 00:34:01
@@ -33,7 +33,7 @@
 :- pred string__append(string, string, string).
 :- mode string__append(in, in, in) is semidet.	% implied
 :- mode string__append(in, out, in) is semidet.
-:- mode string__append(in, in, out) is det.
+:- mode string__append(in, in, uo) is det.
 :- mode string__append(out, out, in) is multi.
 %	Append two strings together.
 %
@@ -358,12 +358,12 @@
 %	substring, whereas string__substring may take time proportional
 %	to the length of the whole string.
 
-:- func string__append_list(list(string)) = string.
+:- func string__append_list(list(string)::in) = (string::uo) is det.
 :- pred string__append_list(list(string), string).
-:- mode string__append_list(in, out) is det.
+:- mode string__append_list(in, uo) is det.
 %	Append a list of strings together.
 
-:- func string__join_list(string, list(string)) = string.
+:- func string__join_list(string::in, list(string)::in) = (string::uo) is det.
 %	string__join_list(Separator, Strings) = JoinedString:
 %	Appends together the strings in Strings, putting Separator between
 %	adjacent strings. If Strings is the empty list, returns the empty
@@ -940,7 +940,7 @@
 
 	% Implementation of string__append_list that uses C as this
 	% minimises the amount of garbage created.
-:- pragma foreign_proc("C", string__append_list(Strs::in) = (Str::out),
+:- pragma foreign_proc("C", string__append_list(Strs::in) = (Str::uo),
 		[will_not_call_mercury, thread_safe], "{
 	MR_Word	list = Strs;
 	MR_Word	tmp;
@@ -971,7 +971,7 @@
 
 	% Implementation of string__join_list that uses C as this
 	% minimises the amount of garbage created.
-:- pragma foreign_proc("C", string__join_list(Sep::in, Strs::in) = (Str::out),
+:- pragma foreign_proc("C", string__join_list(Sep::in, Strs::in) = (Str::uo),
 		[will_not_call_mercury, thread_safe], "{
 	MR_Word	list = Strs;
 	MR_Word	tmp;
@@ -1891,7 +1891,7 @@
 	string__append_iii(S1, S2, S3).
 string__append(S1::in, S2::out, S3::in) :-
 	string__append_ioi(S1, S2, S3).
-string__append(S1::in, S2::in, S3::out) :-
+string__append(S1::in, S2::in, S3::uo) :-
 	string__append_iio(S1, S2, S3).
 string__append(S1::out, S2::out, S3::in) :-
 	string__append_ooi(S1, S2, S3).
@@ -1948,10 +1948,10 @@
 	}
 }").
 
-:- pred string__append_iio(string::in, string::in, string::out) is det.
+:- pred string__append_iio(string::in, string::in, string::uo) is det.
 
 :- pragma foreign_proc("C",
-	string__append_iio(S1::in, S2::in, S3::out),
+	string__append_iio(S1::in, S2::in, S3::uo),
 		[will_not_call_mercury, thread_safe], "{
 	size_t len_1, len_2;
 	len_1 = strlen(S1);
@@ -1962,7 +1962,7 @@
 }").
 
 :- pragma foreign_proc("MC++",
-	string__append_iio(S1::in, S2::in, S3::out),
+	string__append_iio(S1::in, S2::in, S3::uo),
 		[will_not_call_mercury, thread_safe], "{
 	S3 = System::String::Concat(S1, S2);
 }").
Index: library/term_io.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/term_io.m,v
retrieving revision 1.59
diff -u -b -r1.59 term_io.m
--- library/term_io.m	2000/09/18 11:52:22	1.59
+++ library/term_io.m	2001/07/25 17:20:57
@@ -61,6 +61,9 @@
 %		Writes a constant (integer, float, string, or atom)
 %		to stdout.
 
+:- func term_io__format_constant(const) = string.
+	% Like term_io__write_constant, but return the result in a string.
+
 :- pred term_io__write_variable(var(T), varset(T), io__state, io__state).
 :- mode term_io__write_variable(in, in, di, uo) is det.
 %		Writes a variable to stdout.
@@ -70,11 +73,17 @@
 	% Given a string S, write S in double-quotes, with characters
 	% escaped if necessary, to stdout.
 
+:- func term_io__quoted_string(string) = string.
+	% Like term_io__quote_string, but return the result in a string.
+
 :- pred term_io__quote_atom(string, io__state, io__state).
 :- mode term_io__quote_atom(in, di, uo) is det.
 	% Given an atom-name A, write A, enclosed in single-quotes if necessary,
 	% with characters escaped if necessary, to stdout.
 
+:- func term_io__quoted_atom(string) = string.
+	% Like term_io__quote_atom, but return the result in a string.
+
 :- pred term_io__quote_char(char, io__state, io__state).
 :- mode term_io__quote_char(in, di, uo) is det.
 	% Given a character C, write C in single-quotes,
@@ -85,12 +94,18 @@
 	% Given a character C, write C, escaped if necessary, to stdout.
 	% The character is not enclosed in quotes.
 
+:- func term_io__escaped_char(char) = string.
+	% Like term_io__write_escaped_char, but return the result in a string.
+
 :- pred term_io__write_escaped_string(string, io__state, io__state).
 :- mode term_io__write_escaped_string(in, di, uo) is det.
 	% Given a string S, write S, with characters
 	% escaped if necessary, to stdout.
 	% The string is not enclosed in quotes.
 
+:- func term_io__escaped_string(string) = string.
+	% Like term_io__write_escaped_char, but return the result in a string.
+
 	% `term_io__quote_single_char' is the old (misleading) name for
 	% `term_io__write_escaped_char'.  Use the latter instead.
 :- pragma obsolete(term_io__quote_single_char/3).
@@ -116,11 +131,13 @@
 		io__state, io__state).
 :- mode term_io__quote_atom(in, in, di, uo) is det.
 
+:- func term_io__quoted_atom(string, adjacent_to_graphic_token) = string.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- implementation.
-:- import_module std_util, require, list, string, int, char.
+:- import_module bool, std_util, require, list, string, int, char.
 :- import_module lexer, parser, ops.
 
 term_io__read_term(Result) -->
@@ -420,6 +437,20 @@
 term_io__write_constant(term__string(S), _) -->
 	term_io__quote_string(S).
 
+term_io__format_constant(Const) =
+	term_io__format_constant(Const, not_adjacent_to_graphic_token).
+
+:- func term_io__format_constant(const, adjacent_to_graphic_token) = string.
+
+term_io__format_constant(term__integer(I), _) =
+	string__int_to_string(I).
+term_io__format_constant(term__float(F), _) =
+	string__float_to_string(F).
+term_io__format_constant(term__atom(A), NextToGraphicToken) =
+	term_io__quoted_atom(A, NextToGraphicToken).
+term_io__format_constant(term__string(S), _) =
+	term_io__quoted_string(S).
+
 %-----------------------------------------------------------------------------%
 
 term_io__quote_char(C) -->
@@ -430,33 +461,57 @@
 term_io__quote_atom(S) -->
 	term_io__quote_atom(S, not_adjacent_to_graphic_token).
 
+term_io__quoted_atom(S) =
+	term_io__quoted_atom(S, not_adjacent_to_graphic_token).
+
 term_io__quote_atom(S, NextToGraphicToken) -->
+	{ ShouldQuote = should_atom_be_quoted(S, NextToGraphicToken) },
+	( { ShouldQuote = no } ->
+		io__write_string(S)
+	;
+		io__write_char(''''),
+		term_io__write_escaped_string(S),
+		io__write_char('''')
+	).
+
+term_io__quoted_atom(S, NextToGraphicToken) = String :-
+	ShouldQuote = should_atom_be_quoted(S, NextToGraphicToken),
+	( ShouldQuote = no ->
+		String = S
+	;
+		ES = term_io__escaped_string(S),
+		String = string__append_list(["'", ES, "'"])
+	).
+
+:- func should_atom_be_quoted(string, adjacent_to_graphic_token) = bool.
+
+should_atom_be_quoted(S, NextToGraphicToken) = ShouldQuote :-
 	(
 		% I didn't make these rules up: see ISO Prolog 6.3.1.3
 		% and 6.4.2.
 		(
 			% letter digit token (6.4.2)
-			{ string__first_char(S, FirstChar, Rest) },
-			{ char__is_lower(FirstChar) },
-			{ string__is_alnum_or_underscore(Rest) }
+			string__first_char(S, FirstChar, Rest),
+			char__is_lower(FirstChar),
+			string__is_alnum_or_underscore(Rest)
 		;
 			% semicolon token (6.4.2)
-			{ S = ";" }
+			S = ";"
 		;
 			% cut token (6.4.2)
-			{ S = "!" }
+			S = "!"
 		;
 			% graphic token (6.4.2)
-			{ string__to_char_list(S, Chars) },
-			{ \+ (  list__member(Char, Chars),
-				\+ lexer__graphic_token_char(Char)) },
-			{ Chars \= [] },
+			string__to_char_list(S, Chars),
+			\+ (  list__member(Char, Chars),
+				\+ lexer__graphic_token_char(Char)),
+			Chars \= [],
 			%
 			% We need to quote tokens starting with '#',
 			% because Mercury uses '#' to start source line
 			% number indicators.
 			% 
-			{ Chars \= ['#' | _] },
+			Chars \= ['#' | _],
 			%
 			% If the token could be the last token in a term,
 			% and the term could be followed with ".\n",
@@ -466,21 +521,19 @@
 			% unquoted if we're sure it won't be adjacent
 			% to any graphic token.
 			%
-			{ NextToGraphicToken = not_adjacent_to_graphic_token }
+			NextToGraphicToken = not_adjacent_to_graphic_token
 		;
 			% 6.3.1.3: atom = open list, close list ;
-			{ S = "[]" }
+			S = "[]"
 		;
 			% 6.3.1.3: atom = open curly, close curly ;
-			{ S = "{}" }
+			S = "{}"
 		)
 	->
-		io__write_string(S)
+		ShouldQuote = no
 	;
 		% anything else must be output as a quoted token (6.4.2)
-		io__write_char(''''),
-		term_io__write_escaped_string(S),
-		io__write_char('''')
+		ShouldQuote = yes
 	).
 
 	% Note: the code here is similar to code in
@@ -492,9 +545,20 @@
 	term_io__write_escaped_string(S),
 	io__write_char('"').
 
+term_io__quoted_string(S) =
+	string__append_list(["""", term_io__escaped_string(S), """"]).
+
 term_io__write_escaped_string(String) -->
 	string__foldl(term_io__write_escaped_char, String).
 
+term_io__escaped_string(String) =
+	string__foldl(term_io__add_escaped_char, String, "").
+
+:- func term_io__add_escaped_char(char, string) = string.
+
+term_io__add_escaped_char(Char, String0) = String :-
+	String = string__append(String0, string__char_to_string(Char)).
+
 term_io__quote_single_char(Char) -->
 	term_io__write_escaped_char(Char).
 
@@ -511,6 +575,16 @@
 	;
 		{ mercury_escape_char(Char, String) },
 		io__write_string(String)
+	).
+
+term_io__escaped_char(Char) = String :-
+	( mercury_escape_special_char(Char, QuoteChar) ->
+		String = string__append("\\",
+			string__char_to_string(QuoteChar))
+	; is_mercury_source_char(Char) ->
+		String = string__char_to_string(Char)
+	;
+		mercury_escape_char(Char, String)
 	).
 
 :- pred mercury_escape_char(char, string).
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 tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
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/structure_reuse
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
Index: tests/invalid/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/Mmakefile,v
retrieving revision 1.92
diff -u -b -r1.92 Mmakefile
--- tests/invalid/Mmakefile	2001/07/10 10:45:35	1.92
+++ tests/invalid/Mmakefile	2001/07/29 02:28:11
@@ -70,6 +70,7 @@
 	not_a_switch.m \
 	nullary_ho_func_error.m \
 	occurs.m \
+	overloading.m \
 	polymorphic_unification.m \
 	pragma_c_code_and_clauses1.m \
 	pragma_c_code_and_clauses2.m \
Index: tests/invalid/overloading.err_exp
===================================================================
RCS file: overloading.err_exp
diff -N overloading.err_exp
--- /dev/null	Fri Dec  1 02:25:58 2000
+++ overloading.err_exp	Sat Jul 28 20:19:24 2001
@@ -0,0 +1,29 @@
+overloading.m:050: In clause for predicate `overloading:p/4':
+overloading.m:050:   in unification of variable `OptInfo'
+overloading.m:050:   and term `opt_info(MustHaveOwnSlot, EverOnStack, CurIntervalId, V_17, Counter1, StartMap0, EndMap0, VarsMap0, SuccMap0)':
+overloading.m:050:   type error in argument(s) of functor `opt_info/9'.
+overloading.m:050:   variable `OptInfo' has type `(overloading:opt_info)',
+overloading.m:050:   functor `opt_info/9' has type 
+overloading.m:050:   `opt_info((set:set((term:var((term:generic))))), (set:set((term:var((term:generic))))), (tree234:tree234((term:var((term:generic))), (tree234:tree234((overloading:goal_path), string)))), (overloading:interval_id), (counter:counter), (tree234:tree234((overloading:interval_id), (overloading:anchor))), (tree234:tree234((overloading:interval_id), (overloading:anchor))), (tree234:tree234((overloading:interval_id), (set:set((term:var((term:generic))))))), (tree234:tree234((overloading:interval_id), (list:list((overloading:interval_id)))))) :: (overloading:opt_info)',
+overloading.m:050:   variable `MustHaveOwnSlot' has type `(set:set((term:var((term:generic)))))',
+overloading.m:050:   variable `EverOnStack' has type `(set:set((term:var((term:generic)))))',
+overloading.m:050:   variable `CurIntervalId' has type `(overloading:interval_id)',
+overloading.m:050:   argument has type `'<any>'',
+overloading.m:050:   variable `Counter1' has type `(counter:counter)',
+overloading.m:050:   variable `StartMap0' has overloaded type {
+overloading.m:050:    (pred (tree234:tree234(V_V_1, V_V_2))),
+overloading.m:050:    (tree234:tree234(K, V))
+overloading.m:050:    },
+overloading.m:050:   variable `EndMap0' has overloaded type {
+overloading.m:050:    (pred (tree234:tree234((overloading:interval_id), (overloading:anchor)))),
+overloading.m:050:    (tree234:tree234((overloading:interval_id), (overloading:anchor)))
+overloading.m:050:    },
+overloading.m:050:   variable `VarsMap0' has overloaded type {
+overloading.m:050:    (pred (tree234:tree234((overloading:interval_id), (set:set((term:var((term:generic)))))))),
+overloading.m:050:    (tree234:tree234((overloading:interval_id), (set:set((term:var((term:generic)))))))
+overloading.m:050:    },
+overloading.m:050:   variable `SuccMap0' has overloaded type {
+overloading.m:050:    (pred (tree234:tree234(V_V_1, V_V_2))),
+overloading.m:050:    (tree234:tree234(K, V))
+overloading.m:050:    }.
+For more information, try recompiling with `-E'.
Index: tests/invalid/overloading.m
===================================================================
RCS file: overloading.m
diff -N overloading.m
--- /dev/null	Fri Dec  1 02:25:58 2000
+++ overloading.m	Wed Jul 25 22:06:35 2001
@@ -0,0 +1,56 @@
+:- module overloading.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+:- import_module int, counter, list, set, map, term.
+
+main -->
+	{ q(A, B, C) },
+	{ p(A, B, C, T) },
+	io__write(T),
+	io__nl.
+
+:- type var_save_map	==	map(var, save_map).
+:- type save_map	== 	map(goal_path, string).
+:- type goal_path	--->	goal_path(string).
+:- type anchor		--->	anchor(string).
+:- type interval_id	--->	interval_id(int).
+
+:- type opt_info --->
+	opt_info(
+		must_have_own_slot	::	set(var),
+		ever_on_stack		::	set(var),
+		var_save_map		::	var_save_map,
+		cur_interval		::	interval_id,
+		interval_counter	::	counter,
+		interval_start		::	map(interval_id, anchor),
+		interval_end		::	map(interval_id, anchor),
+		interval_vars		::	map(interval_id,
+							set(var)),
+		interval_succ		::	map(interval_id,
+							list(interval_id))
+	).
+
+:- pred p(set(var)::in, set(var)::in, set(var)::in, opt_info::out) is det.
+
+p(MustHaveOwnSlot, EverOnStack, OutputVars, OptInfo) :-
+	Counter0 = counter__init(1),
+	counter__allocate(CurInterval, Counter0, Counter1),
+	CurIntervalId = interval_id(CurInterval),
+	EndMap0 = map__det_insert(map__init, CurIntervalId, anchor("end")),
+	StartMap0 = map__init,
+	VarsMap0 = map__det_insert(map__init, CurIntervalId, OutputVars),
+	SuccMap0 = map__init,
+	OptInfo = opt_info(MustHaveOwnSlot, EverOnStack,
+		CurIntervalId, map__init, Counter1, StartMap0, EndMap0,
+		VarsMap0, SuccMap0).
+
+:- pred q(set(var)::out, set(var)::out, set(var)::out) is det.
+
+:- external(q/3).
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
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
cvs diff: Diffing util
--------------------------------------------------------------------------
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