diff: changes to io.m

Fergus Henderson fjh at cs.mu.oz.au
Thu Apr 24 10:13:03 AEST 1997


Hi Tom,

Can you please review this one?

-----------------------------------------------------------------------------

Implement io__print.  Improvements to io__write and io__read.
Add stubs for io__read_binary and io__write_binary.

library/io.m:
	Change the implementation of `io__write':
	    - it now writes out terms using list syntax and infix notation
	      when appropriate, just like term_io__write_term
	      (but like term_io__write_term, it doesn't yet take operator
	      precedence into account, so it still outputs some redundant
	      parentheses)
	    - it properly quotes and escapes strings, characters, and atoms
	      (XXX but it does not yet properly parenthesize constants that
	      happen to have the same name as an operator)

	Add `io__print'.  This is similar to `io__write', except that
	if the argument is a single string or character, it is printed
	directly, rather than inside quotes with special characters escaped.

	Rename `io__read_anything' as `io__read', and improve the error
	messages slightly.  The implementation is still dependent on
	term_to_type which is not yet implemented.

	Add `io__write_binary' and `io__read_binary'.  (The current
	implementation is just a pair of stubs that call `io__write'
	and `io__read'; that works, but it kinda defeats the purpose...)

	Provide reasonable documentation for all of the above.

	For backwards compatibility with previous versions of Mercury,
	add versions of `io__read_anything' and `io__write_anything'
	that just call `io__read' and `io__write' respectively,
	but declare them as `pragma obsolete'.


Index: io.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/io.m,v
retrieving revision 1.116
diff -u -r1.116 io.m
--- io.m	1997/04/21 03:34:05	1.116
+++ io.m	1997/04/23 23:55:38
@@ -1,5 +1,5 @@
 %-----------------------------------------------------------------------------%
-% Copyright (C) 1995 University of Melbourne.
+% Copyright (C) 1993-1997 University of Melbourne.
 % This file may only be copied under the terms of the GNU Library General
 % Public License - see the file COPYING.LIB in the Mercury distribution.
 %-----------------------------------------------------------------------------%
@@ -71,6 +71,7 @@
 :- type io__read_result(T)	--->	ok(T)
 				;	eof
 				;	error(string, int).
+					% error message, line number
 
 :- type io__error.	% Use io__error_message to decode it.
 
@@ -128,22 +129,24 @@
 %		You can put back as many characters as you like.
 %		You can even put back something that you didn't actually read.
 
-:- pred io__read_anything(io__read_result(T), io__state, io__state).
-:- mode io__read_anything(out, di, uo) is det.
-%		Reads its argument from the current input stream.
-%		The argument may be of (almost) any type. 
-%		The term read had better be of the right type!
-%		XXX io__read_anything is NOT YET IMPLEMENTED.
-%		It will also probably be renamed io__read.
-
-:- pred io__read_anything(io__input_stream, io__read_result(T),
-							io__state, io__state).
-:- mode io__read_anything(in, out, di, uo) is det.
-%		Reads its argument to the specified stream.
-%		The argument may be of (almost) any type.
-%		The term read had better be of the right type!
-%		XXX io__read_anything is NOT YET IMPLEMENTED.
-%		It will also probably be renamed io__read.
+:- pred io__read(io__read_result(T), io__state, io__state).
+:- mode io__read(out, di, uo) is det.
+:- pred io__read(io__input_stream, io__read_result(T), io__state, io__state).
+:- mode io__read(in, out, di, uo) is det.
+%		Reads a ground term of any type, written using standard
+%		Mercury syntax, from the current or specified input stream.
+%		The type of the term read is determined by the context
+%		in which `io__read' is used.
+%		If there are no more non-whitespace characters before the
+%		end of file, then `io__read' returns `eof'.
+%		If it can read in a syntactically correct ground term
+%		of the correct type, then it returns `ok(Term)'.
+%		If characters on the input stream (up to the next `.' that
+%		is followed by whitespace) do not form a syntactically
+%		correct term, or if the term read is not a ground term,
+%		if the term is not a valid term of the appropriate type,
+%		or if encounters an I/O error, then it returns
+%		`error(Message, LineNumber)'.
 
 :- pred io__ignore_whitespace(io__result, io__state, io__state).
 :- mode io__ignore_whitespace(out, di, uo) is det.
@@ -160,6 +163,43 @@
 
 % Text output predicates.
 
+:- pred io__print(T, io__state, io__state).
+:- mode io__print(in, di, uo) is det.
+:- pred io__print(io__output_stream, T, io__state, io__state).
+:- mode io__print(in, in, di, uo) is det.
+%		io__print/3 writes its argument to the current output stream.
+%		io__print/4 writes its argument to the specified output
+%		stream.  In either case, the argument may be of any type.
+%		The argument is written in a format that is intended to
+%		be human-readable. 
+%
+%		If the argument is just a single string or character, it
+%		will be printed out exactly as is (unquoted).
+%		For higher-order types, or for types defined using the
+%		foreign language interface (pragma c_code), the text output
+%		will only describe the type that is being printed, not the
+%		value.
+
+:- pred io__write(T, io__state, io__state).
+:- mode io__write(in, di, uo) is det.
+:- pred io__write(io__output_stream, T, io__state, io__state).
+:- mode io__write(in, in, di, uo) is det.
+%		io__write/3 writes its argument to the current output stream.
+%		io__write/4 writes its argument to the specified output stream.
+%		The argument may be of any type.
+%		The argument is written in a format that is intended to
+%		be valid Mercury syntax whenever possible.
+%
+%		Strings and characters are always printed out in quotes,
+%		using backslash escapes if necessary.
+%		For higher-order types, or for types defined using the
+%		foreign language interface (pragma c_code), the text output
+%		will only describe the type that is being printed, not the
+%		value, and the result may not be parsable by io__read.
+%		But in all other cases the format used is standard Mercury
+%		syntax, and if you do append a period and newline (".\n"),
+%		then the results can be read in again using `io__read'.
+
 :- pred io__nl(io__state, io__state).
 :- mode io__nl(di, uo) is det.
 %		Writes a newline character to the current output stream.
@@ -174,7 +214,7 @@
 
 :- pred io__write_string(io__output_stream, string, io__state, io__state).
 :- mode io__write_string(in, in, di, uo) is det.
-%		Writes a string to the specified stream.
+%		Writes a string to the specified output stream.
 
 :- pred io__write_strings(list(string), io__state, io__state).
 :- mode io__write_strings(in, di, uo) is det.
@@ -183,7 +223,7 @@
 :- pred io__write_strings(io__output_stream, list(string),
 				io__state, io__state).
 :- mode io__write_strings(in, in, di, uo) is det.
-%		Writes a string to the specified stream.
+%		Writes a list of strings to the specified output stream.
 
 :- pred io__write_char(char, io__state, io__state).
 :- mode io__write_char(in, di, uo) is det.
@@ -191,7 +231,7 @@
 
 :- pred io__write_char(io__output_stream, char, io__state, io__state).
 :- mode io__write_char(in, in, di, uo) is det.
-%		Writes a character to the specified stream.
+%		Writes a character to the specified output stream.
 
 :- pred io__write_int(int, io__state, io__state).
 :- mode io__write_int(in, di, uo) is det.
@@ -199,7 +239,7 @@
 
 :- pred io__write_int(io__output_stream, int, io__state, io__state).
 :- mode io__write_int(in, in, di, uo) is det.
-%		Writes an integer to the specified stream.
+%		Writes an integer to the specified output stream.
 
 :- pred io__write_float(float, io__state, io__state).
 :- mode io__write_float(in, di, uo) is det.
@@ -209,14 +249,14 @@
 :- pred io__write_float(io__output_stream, float, io__state, io__state).
 :- mode io__write_float(in, in, di, uo) is det.
 %	io__write_float(Float, IO0, IO1).
-%		Writes a floating point number to the specified stream.
+%		Writes a floating point number to the specified output stream.
 
 :- pred io__format(string, list(io__poly_type), io__state, io__state).
 :- mode io__format(in, in, di, uo) is det.
 %	io__format(FormatString, Arguments, IO0, IO).
 %		Formats the specified arguments according to
 %		the format string, using string__format, and
-%		then writes the result to standard output.
+%		then writes the result to the current output stream.
 %		(See the documentation of string__format for details.)
 
 :- pred io__format(io__output_stream, string, list(io__poly_type),
@@ -233,25 +273,11 @@
 %	io__write_many(Arguments, IO0, IO).
 %		Writes the specified arguments to the current output stream.
 
-:- pred io__write_many(io__output_stream, list(io__poly_type), io__state, io__state).
+:- pred io__write_many(io__output_stream, list(io__poly_type),
+			io__state, io__state).
 :- mode io__write_many(in, in, di, uo) is det.
 %	io__write_many(Stream, Arguments, IO0, IO).
-%		Writes the specified arguments to the specified stream.
-
-:- pred io__write(T, io__state, io__state).
-:- mode io__write(in, di, uo) is det.
-%		Writes its argument to the current output stream.
-%		The argument may be of (almost) any type.
-%		(Any type except a higher-order predicate type,
-%		or some of the builtin types such as io__state itself.)
-%		XXX Not all quoting of atoms is done correctly.
-
-:- pred io__write(io__output_stream, T, io__state, io__state).
-:- mode io__write(in, in, di, uo) is det.
-%		Writes its argument to the specified stream.
-%		The argument may be of (almost) any type.
-%		(Any type except a higher-order predicate type,
-%		or some of the builtin types such as io__state itself.)
+%		Writes the specified arguments to the specified output stream.
 
 :- pred io__write_list(list(T), string, pred(T, io__state, io__state),
 	io__state, io__state).
@@ -291,7 +317,8 @@
 %		Closes the current input stream.
 %		The current input stream reverts to standard input.
 
-:- pred io__open_input(string, io__res(io__input_stream), io__state, io__state).
+:- pred io__open_input(string, io__res(io__input_stream),
+			io__state, io__state).
 :- mode io__open_input(in, out, di, uo) is det.
 %	io__open_input(File, Result, IO0, IO1).
 %		Attempts to open a file for input.
@@ -454,16 +481,33 @@
 
 % Binary input predicates.
 
+:- pred io__read_binary(io__result(T), io__state, io__state).
+:- mode io__read_binary(out, di, uo) is det.
+%		Reads a binary representation of a term of type T
+%		from the current binary input stream.
+
+:- pred io__read_binary(io__binary_input_stream, io__result(T),
+		io__state, io__state).
+:- mode io__read_binary(in, out, di, uo) is det.
+%		Reads a binary representation of a term of type T
+%		from the specified binary input stream.
+
+%		Note: if you attempt to read a binary representation written
+%		by a different program, or a different version of the same
+%		program, then the results are not guaranteed to be meaningful.
+%		Another caveat is that higher-order types cannot be read. 
+%		(If you try, you will get a runtime error.)
+
 :- pred io__read_byte(io__result(int), io__state, io__state).
 :- mode io__read_byte(out, di, uo) is det.
-%		Reads a single byte from the current binary input
-%		stream and returns it in the bottom 8 bits of an integer.
+%		Reads a single 8-bit byte from the current binary input
+%		stream.
 
 :- pred io__read_byte(io__binary_input_stream, io__result(int),
 				io__state, io__state).
 :- mode io__read_byte(in, out, di, uo) is det.
-%		Reads a single byte from the specified binary input
-%		stream and returns it in the bottom 8 bits of an integer.
+%		Reads a single 8-bit byte from the specified binary input
+%		stream.
 
 :- pred io__putback_byte(int, io__state, io__state).
 :- mode io__putback_byte(in, di, uo) is det.
@@ -485,6 +529,18 @@
 
 % XXX what about wide characters?
 
+:- pred io__write_binary(T, io__state, io__state).
+:- mode io__write_binary(in, di, uo) is det.
+%		Writes a binary representation of a term to the current
+%		binary output stream, in a format suitable for reading
+%		in again with io__read_binary.
+
+:- pred io__write_binary(io__binary_output_stream, T, io__state, io__state).
+:- mode io__write_binary(in, in, di, uo) is det.
+%		Writes a binary representation of a term to the specified
+%		binary output stream, in a format suitable for reading
+%		in again with io__read_binary.
+
 :- pred io__write_byte(int, io__state, io__state).
 :- mode io__write_byte(in, di, uo) is det.
 %		Writes a single byte to the current binary output stream.
@@ -718,7 +774,6 @@
 :- pred io__remove_file(string, io__res, io__state, io__state).
 :- mode io__remove_file(in, out, di, uo) is det.
 
-
 %-----------------------------------------------------------------------------%
 
 % Memory management predicates.
@@ -759,6 +814,36 @@
 %		code.
 
 %-----------------------------------------------------------------------------%
+:- implementation.
+
+% Everything below here is not intended to be part of the public interface,
+% and will not be included in the Mercury library reference manual.
+
+%-----------------------------------------------------------------------------%
+:- interface.
+
+% For backwards compatibility:
+
+:- pragma obsolete(io__read_anything/3).
+:- pred io__read_anything(io__read_result(T), io__state, io__state).
+:- mode io__read_anything(out, di, uo) is det.
+%		Same as io__read/3.
+
+:- pragma obsolete(io__read_anything/4).
+:- pred io__read_anything(io__output_stream, io__read_result(T),
+			io__state, io__state).
+:- mode io__read_anything(in, out, di, uo) is det.
+%		Same as io__read/4.
+
+:- pragma obsolete(io__write_anything/3).
+:- pred io__write_anything(T, io__state, io__state).
+:- mode io__write_anything(in, di, uo) is det.
+%		Same as io__write/3.
+
+:- pragma obsolete(io__write_anything/4).
+:- pred io__write_anything(io__output_stream, T, io__state, io__state).
+:- mode io__write_anything(in, in, di, uo) is det.
+%		Same as io__write/4.
 
 % For use by term_io.m:
 
@@ -781,7 +866,7 @@
 %-----------------------------------------------------------------------------%
 
 :- implementation.
-:- import_module map, dir, term_io, varset, require, time.
+:- import_module map, dir, term, term_io, varset, require, time, uniq_array.
 
 :- type io__state
 	---> 	io__state(
@@ -986,25 +1071,37 @@
 	io__binary_input_stream(Stream),
 	io__putback_byte(Stream, Char).
 
-io__read_anything(X) -->
+io__read_anything(Result) -->
+	io__read(Result).
+
+io__read(Result) -->
 	term_io__read_term(ReadResult),
-	(	{ ReadResult = term(_VarSet, Term) },
+	(	
+		{ ReadResult = term(_VarSet, Term) },
 		( { term_to_type(Term, Type) } ->
-			{ X = ok(Type) }
+			{ Result = ok(Type) }
 		;
-			{ X = error("io__read_anything : the term read was not a valid type", 0) }
+			io__get_line_number(LineNumber),
+			( { \+ term__is_ground(Term) } ->
+				{ Result = error("io__read: the term read was not a ground term", LineNumber) }
+			;
+				{ Result = error("io__read: the term read did not have the right type", LineNumber) }
+			)
 		)
 	;
 		{ ReadResult = eof },
-		{ X = eof }
+		{ Result = eof }
 	;
 		{ ReadResult = error(String, Int) },
-		{ X = error(String, Int) }
+		{ Result = error(String, Int) }
 	).
 
-io__read_anything(Stream, X) -->
+io__read_anything(Stream, Result) -->
+	io__read(Stream, Result).
+
+io__read(Stream, Result) -->
 	io__set_input_stream(Stream, OrigStream),
-	io__read_anything(X),
+	io__read(Result),
 	io__set_input_stream(OrigStream, _Stream).
 
 io__ignore_whitespace(Result) -->
@@ -1076,37 +1173,197 @@
 	io__write_float(Stream, F),
 	io__write_many(Stream, Rest).
 
+io__print(Stream, Term) -->
+	io__set_output_stream(Stream, OrigStream),
+	io__print(Term),
+	io__set_output_stream(OrigStream, _Stream).
+
+io__print(Term) -->
+	% `string' and `char' are special cases for io__print
+	{ type_to_univ(Term, Univ) },
+	( { univ_to_type(Univ, String) } ->
+		io__write_string(String)
+	; { univ_to_type(Univ, Char) } ->
+		io__write_char(Char)
+	;
+		io__print_quoted(Term)
+	).
+
+:- pred io__print_quoted(T, io__state, io__state).
+:- mode io__print_quoted(in, di, uo) is det.
+
+io__print_quoted(Term) -->
+	io__write(Term).
+/*
+When we have type classes, then instead of io__write(Term),
+we will want to do something like
+	( { univ_to_type_class(Univ, Portrayable) } ->
+		portray(Portrayable)
+	;
+		... code like io__write, but which prints
+		    the arguments using io__print_quoted, rather than
+		    io__write ...
+	)
+*/
+
+io__write_anything(Anything) -->
+	io__write(Anything).
+
+io__write_anything(Stream, Anything) -->
+	io__write(Stream, Anything).
+
 io__write(Stream, X) -->
 	io__set_output_stream(Stream, OrigStream),
 	io__write(X),
 	io__set_output_stream(OrigStream, _Stream).
 
+io__write(Term) -->
+	% we need to special-case the builtin types:
+	%	int, char, float, string
+	%	type_info, univ, uniq_array, c_pointer
+	{ type_to_univ(Term, Univ) },
+	( { univ_to_type(Univ, String) } ->
+		term_io__quote_string(String)
+	; { univ_to_type(Univ, Char) } ->
+		term_io__quote_char(Char)
+	; { univ_to_type(Univ, Int) } ->
+		io__write_int(Int)
+	; { univ_to_type(Univ, Float) } ->
+		io__write_float(Float)
+% XXX the following code doesn't work, because we can't use
+% univ_to_type to match on a non-ground type `uniq_array(T)'.
+%	; { univ_to_type(Univ, UniqArray) } ->
+%		io__write_uniq_array(UniqArray)
+	; { univ_to_type(Univ, TypeInfo) } ->
+		io__write_string(type_name(TypeInfo))
+	;
+		io__write_term(Term)
+	),
+	% append type qualifier, if the original value was of type univ
+	( { type_of(Term) = type_of(Univ) } ->
+		io__write_string(" : "),	% XXX TYPE_QUAL_OP
+		io__write(type_of(Term))
+	;
+		[]
+	).
+
+:- pred io__write_uniq_array(uniq_array(T), io__state, io__state).
+:- mode io__write_uniq_array(in, di, uo) is det.
 
+io__write_uniq_array(UniqArray) -->
+	io__write_string("uniq_array("),
+	{ uniq_array__to_list(UniqArray, List) },
+	io__write(List),
+	io__write_string(")").
 
-% We want to call io__write_args as a tail-call, and so that we only
-% put one stack frame up per level of traversal.
-% This is why the code is a little unusual.
-
-io__write(Anything) -->
-	{ expand(Anything, Functor, _Arity, Args) },
-	io__write_string(Functor),
+:- pred io__write_term(T, io__state, io__state).
+:- mode io__write_term(in, di, uo) is det.
+
+io__write_term(Term) -->
+	{ expand(Term, Functor, _Arity, Args) },
+	io__get_op_table(OpTable),
 	(
-		{ Args = [Arg | Args1] }
+		{ Functor = "." },
+		{ Args = [ListHead, ListTail] }
+	->
+		io__write_char('['),
+		io__write(ListHead),
+		io__write_list_tail(ListTail),
+		io__write_char(']')
+	;
+		{ Functor = "[]" },
+		{ Args = [] }
+	->
+		io__write_string("[]")
+	;
+		{ Functor = "{}" },
+		{ Args = [BracedTerm] }
+	->
+		io__write_string("{ "),
+		io__write(BracedTerm),
+		io__write_string(" }")
+	;
+		{ Args = [PrefixArg] },
+		{ ops__lookup_prefix_op(OpTable, Functor, _, _) }
+	->
+		io__write_char('('),
+		term_io__quote_atom(Functor),
+		io__write_char(' '),
+		io__write(PrefixArg),
+		io__write_char(')')
+	;
+		{ Args = [PostfixArg] },
+		{ ops__lookup_postfix_op(OpTable, Functor, _, _) }
+	->
+		io__write_char('('),
+		io__write(PostfixArg),
+		io__write_char(' '),
+		term_io__quote_atom(Functor),
+		io__write_char(')')
+	;
+		{ Args = [Arg1, Arg2] },
+		{ ops__lookup_infix_op(OpTable, Functor, _, _, _) }
+	->
+		io__write_char('('),
+		io__write(Arg1),
+		io__write_char(' '),
+		term_io__quote_atom(Functor),
+		io__write_char(' '),
+		io__write(Arg2),
+		io__write_char(')')
+	;
+		{ Args = [Arg1, Arg2] },
+		{ ops__lookup_binary_prefix_op(OpTable, Functor, _, _, _) }
 	->
-		io__write_string("("),
-		io__write(Arg),
-		io__write_args(Args1)
+		io__write_char('('),
+		term_io__quote_atom(Functor),
+		io__write_char(' '),
+		io__write(Arg1),
+		io__write_char(' '),
+		io__write(Arg2),
+		io__write_char(')')
 	;
+		term_io__quote_atom(Functor),
+		(
+			{ Args = [X|Xs] }
+		->
+			io__write_char('('),
+			io__write(X),
+			io__write_term_args(Xs),
+			io__write_char(')')
+		;
+			[]
+		)
+	).
+
+:- pred io__write_list_tail(univ, io__state, io__state).
+:- mode io__write_list_tail(in, di, uo) is det.
+
+io__write_list_tail(Term) -->
+	( 
+		{ expand(Term, ".", _Arity, [ListHead, ListTail]) }
+	->
+		io__write_string(", "),
+		io__write(ListHead),
+		io__write_list_tail(ListTail)
+	;
+		{ expand(Term, "[]", _Arity, []) }
+	->
 		[]
+	;
+		io__write_string(" | "),
+		io__write(Term)
 	).
 
-:- pred io__write_args(list(univ)::in, io__state::di, io__state::uo) is det.
-io__write_args([]) --> 
-	io__write_string(")").
-io__write_args([Arg | Args]) --> 
+:- pred io__write_term_args(list(univ), io__state, io__state).
+:- mode io__write_term_args(in, di, uo) is det.
+
+	% write the remaining arguments
+io__write_term_args([]) --> [].
+io__write_term_args([X|Xs]) -->
 	io__write_string(", "),
-	io__write(Arg),
-	io__write_args(Args).
+	io__write(X),
+	io__write_term_args(Xs).
 
 %-----------------------------------------------------------------------------%
 
@@ -1125,6 +1382,39 @@
 	io__set_output_stream(Stream, OrigStream),
 	io__write_list(List, Separator, OutputPred),
 	io__set_output_stream(OrigStream, _Stream).
+
+%-----------------------------------------------------------------------------%
+
+io__write_binary(Stream, Term) -->
+	io__set_binary_output_stream(Stream, OrigStream),
+	io__write_binary(Term),
+	io__set_binary_output_stream(OrigStream, _Stream).
+
+io__read_binary(Stream, Result) -->
+	io__set_output_stream(Stream, OrigStream),
+	io__read_binary(Result),
+	io__set_output_stream(OrigStream, _Stream).
+
+io__write_binary(Term) -->
+	% a quick-and-dirty implementation... not very space-efficient
+	% (not really binary!)
+	io__binary_output_stream(Stream),
+	io__write(Stream, Term),
+	io__write_string(Stream, ".\n").
+
+io__read_binary(Result) -->
+	% a quick-and-dirty implementation... not very space-efficient
+	% (not really binary!)
+	io__binary_input_stream(Stream),
+	io__read(Stream, ReadResult),
+	{ io__convert_read_result(ReadResult, Result) }.
+
+:- pred io__convert_read_result(io__read_result(T), io__result(T)).
+:- mode io__convert_read_result(in, out) is det.
+
+io__convert_read_result(ok(T), ok(T)).
+io__convert_read_result(eof, eof).
+io__convert_read_result(error(Error, _Line), error(Error)).
 
 %-----------------------------------------------------------------------------%
 

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list