Add some new utility predicates for use with streams.

Estimated hours taken: 2
Branches: main

Add some new utility predicates for use with streams.

library/stream.m:
	Add the predicate stream.format/5, an analogue of io.format,
	that writes formatted output using an arbitrary string writer.

	Add a predicate stream.ignore_whitespace/4 that can be used
	to skip past whitespace in a putback char reader stream.

library/Mercury.options:
	Don't warn about unknown format calls in the stream module.

	Unrelated change: remove a workaround that was put in place
	before the addition of the `--no-warn-obsolete' option.

compiler/format_call.m:
	Also analyse calls to stream.format/5.

tests/hard_coded/Mmakefile:
tests/hard_coded/stream_format.{m,exp}:
tests/hard_coded/stream_ignore_ws.{m,exp,data}:
	Test stream.format/5 and stream.ignore_whitespace/3.

tests/invalid/string_format_bad.{m,exp}:
tests/invalid/string_format_unknown.{m,exp}:
	Check that we emit messages for bad/unknown calls to stream.format/5.
This commit is contained in:
Julien Fischer
2006-11-09 00:47:27 +00:00
parent 4c2188612c
commit ae375664b9
14 changed files with 158 additions and 36 deletions

View File

@@ -9,11 +9,11 @@
% File: format_call.m.
% Author: zs.
%
% The job of this module is to generate warnings about calls to string.format
% and io.format in which the format string and the supplied lists of values
% do not agree. The difficult part of this job is actually finding the values
% of the variables representing the format string and the list of values to
% be printed.
% The job of this module is to generate warnings about calls to
% string.format, io.format and stream.format in which the format string and
% the supplied lists of values do not agree. The difficult part of this job
% is actually finding the values of the variables representing the format
% string and the list of values to be printed.
%
% The general approach is a backwards traversal of the procedure body. During
% this traversal, we assign an id to every conjunction (considering a cond and
@@ -194,6 +194,11 @@ is_format_call(ModuleName, Name, Args, FormatStringVar, FormattedValuesVar) :-
( Args = [FormatStringVar, FormattedValuesVar, _IOIn, _IOOut]
; Args = [_Stream, FormatStringVar, FormattedValuesVar, _IOIn, _IOOut]
)
; ModuleName = mercury_std_lib_module_name("stream") ->
% Since we do this check after polymorphism there will have been
% a typeclassinfo inserted at the front of the argument list.
Args = [_TC_InfoForStream, _Stream, FormatStringVar,
FormattedValuesVar, _StateIn, _StateOut]
;
fail
).

View File

@@ -2777,7 +2777,8 @@ case_list_contains_trace([Case0 | Cases0], [Case | Cases], !ContainsTrace) :-
% typeclass_infos.
format_calls :: bool,
% Do we have any calls to
% string.format and io.format?
% string.format, stream.format and
% io.format?
inside_dupl_for_switch :: bool,
% Are we currently inside a goal
% that was duplicated for a switch?

View File

@@ -21,8 +21,10 @@ MCFLAGS-std_util += --no-halt-at-warn
MCFLAGS-dir += --no-halt-at-warn
MCFLAGS-exception += --no-halt-at-warn
# We need a better way to ignore obsolete procedures.
MCFLAGS-bintree_set += --no-halt-at-warn
# Ignore warnings about obsolete procedures from this module since
# the entire module is obsolete.
#
MCFLAGS-bintree_set += --no-warn-obsolete
# io.m uses library features that are supported by POSIX but which are not
# part of ANSI C, such as `struct stat', fileno(), and putenv().
@@ -33,6 +35,7 @@ MGNUCFLAGS-io = --no-ansi
# in terms of io.format/4, and string.format/2 in terms of string.format/3.
# varset.trans_opt includes the relevant part of string.opt.
MCFLAGS-io = --no-warn-unknown-format-calls
MCFLAGS-stream = --no-warn-unknown-format-calls
MCFLAGS-string = --no-warn-unknown-format-calls
MCFLAGS-mer_std = --no-warn-nothing-exported

View File

@@ -20,6 +20,8 @@
:- interface.
:- import_module bool.
:- import_module char.
:- import_module list.
:- import_module string.
%-----------------------------------------------------------------------------%
@@ -29,6 +31,11 @@
:- type stream.name == string.
:- type stream.result(Error)
---> ok
; eof
; error(Error).
:- type stream.result(T, Error)
---> ok(T)
; eof
@@ -269,6 +276,22 @@
in(pred(in, out, in, out, di, uo) is cc_multi), in, out, di, uo)
is cc_multi.
%-----------------------------------------------------------------------------%
%
% Misc. operations on streams
%
% A version of io.format that works for arbitrary string writers.
%
:- pred stream.format(Stream::in, string::in, list(poly_type)::in,
State::di, State::uo) is det <= stream.writer(Stream, string, State).
% Discard all the whitespace from the specified stream.
%
:- pred stream.ignore_whitespace(Stream::in, stream.result(Error)::out,
State::di, State::uo)
is det <= stream.putback(Stream, char, State, Error).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -347,6 +370,32 @@ stream.input_stream_fold2_state_maybe_stop(Stream, Pred, T0, Res, !S) :-
Res = error(T0, Error)
).
%-----------------------------------------------------------------------------%
stream.format(Stream, FormatString, Arguments, !State) :-
string.format(FormatString, Arguments, String),
put(Stream, String, !State).
%-----------------------------------------------------------------------------%
stream.ignore_whitespace(Stream, Result, !State) :-
get(Stream, CharResult, !State),
(
CharResult = error(Error),
Result = error(Error)
;
CharResult = eof,
Result = eof
;
CharResult = ok(Char),
( is_whitespace(Char) ->
stream.ignore_whitespace(Stream, Result, !State)
;
unget(Stream, Char, !State),
Result = ok
)
).
%-----------------------------------------------------------------------------%
:- end_module stream.
%-----------------------------------------------------------------------------%

View File

@@ -185,6 +185,8 @@ ORDINARY_PROGS= \
solver_ite_inits \
space \
stable_sort \
stream_format \
stream_ignore_ws \
stream_test \
string_alignment \
string_alignment_bug \
@@ -578,6 +580,9 @@ nonascii_gen: nonascii_gen.c
stream_test.out: stream_test
./stream_test < stream_test.data > stream_test.out
stream_ignore_ws.out: stream_ignore_ws
./stream_ignore_ws < stream_ignore_ws.data > stream_ignore_ws.out
# The trace_goal_env_1 and trace_goal_env_2 test cases differ from each other
# only in that the latter is executed with the TRACE_ABC environment variable
# set.

View File

@@ -0,0 +1 @@
foo561a3.141000

View File

@@ -0,0 +1,17 @@
:- module stream_format.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module list.
:- import_module stream.
:- import_module string.
main(!IO) :-
io.stdout_stream(Stdout, !IO),
stream.format(Stdout, "%s%d%c%f\n",
[s("foo"), i(561), c('a'), f(3.141)], !IO).

View File

@@ -0,0 +1,7 @@
foo bar baz

View File

@@ -0,0 +1 @@
foo bar baz

View File

@@ -0,0 +1,24 @@
:- module stream_ignore_ws.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module stream.
main(!IO) :-
io.stdin_stream(Stdin, !IO),
stream.ignore_whitespace(Stdin, IgnoreResult, !IO),
( IgnoreResult = ok ->
io.read_file_as_string(Stdin, MaybePartialRes, !IO),
( MaybePartialRes = ok(String) ->
io.write_string(String, !IO)
;
io.write_string("io.read_file_as_string FAILED\n", !IO)
)
;
io.write_string("stream.ignore_whitespace FAILED\n", !IO)
).

View File

@@ -1,16 +1,19 @@
string_format_bad.m:020: Mismatched format and values in call to
string_format_bad.m:020: `string.format'/3:
string_format_bad.m:020: format string invalid.
string_format_bad.m:022: Mismatched format and values in call to
string_format_bad.m:022: `string.format'/3:
string_format_bad.m:022: invalid conversion specifier.
string_format_bad.m:025: Mismatched format and values in call to `io.format'/4:
string_format_bad.m:025: invalid conversion specifier.
string_format_bad.m:026: Mismatched format and values in call to `io.format'/5:
string_format_bad.m:021: Mismatched format and values in call to
string_format_bad.m:021: `string.format'/3:
string_format_bad.m:021: format string invalid.
string_format_bad.m:023: Mismatched format and values in call to
string_format_bad.m:023: `string.format'/3:
string_format_bad.m:023: invalid conversion specifier.
string_format_bad.m:026: Mismatched format and values in call to `io.format'/4:
string_format_bad.m:026: invalid conversion specifier.
string_format_bad.m:027: Mismatched format and values in call to `io.format'/4:
string_format_bad.m:027: Mismatched format and values in call to `io.format'/5:
string_format_bad.m:027: invalid conversion specifier.
string_format_bad.m:036: Mismatched format and values in call to `io.format'/5:
string_format_bad.m:036: invalid conversion specifier.
string_format_bad.m:041: Mismatched format and values in call to `io.format'/5:
string_format_bad.m:041: invalid conversion specifier.
string_format_bad.m:028: Mismatched format and values in call to
string_format_bad.m:028: `stream.format'/5:
string_format_bad.m:028: invalid conversion specifier.
string_format_bad.m:029: Mismatched format and values in call to `io.format'/4:
string_format_bad.m:029: invalid conversion specifier.
string_format_bad.m:038: Mismatched format and values in call to `io.format'/5:
string_format_bad.m:038: invalid conversion specifier.
string_format_bad.m:043: Mismatched format and values in call to `io.format'/5:
string_format_bad.m:043: invalid conversion specifier.

View File

@@ -14,6 +14,7 @@
:- import_module float.
:- import_module int.
:- import_module list.
:- import_module stream.
:- import_module string.
main(!IO) :-
@@ -24,6 +25,7 @@ main(!IO) :-
io.stdout_stream(OutputStream, !IO),
io.format("%d", [s("x3")], !IO),
io.format(OutputStream, "%d", [s("x4")], !IO),
stream.format(OutputStream, "%d", [s("x4")], !IO),
io.format("%w", [i(5)], !IO),
io.write_string(p(s("five")), !IO),
F6 = "%s %f",

View File

@@ -1,18 +1,20 @@
string_format_unknown.m:021: Unknown format string in call to
string_format_unknown.m:021: `string.format'/3.
string_format_unknown.m:023: Mismatched format and values in call to
string_format_unknown.m:023: `string.format'/3:
string_format_unknown.m:023: invalid conversion specifier.
string_format_unknown.m:026: Mismatched format and values in call to
string_format_unknown.m:026: `io.format'/4:
string_format_unknown.m:026: invalid conversion specifier.
string_format_unknown.m:022: Unknown format string in call to
string_format_unknown.m:022: `string.format'/3.
string_format_unknown.m:024: Mismatched format and values in call to
string_format_unknown.m:024: `string.format'/3:
string_format_unknown.m:024: invalid conversion specifier.
string_format_unknown.m:027: Mismatched format and values in call to
string_format_unknown.m:027: `io.format'/5:
string_format_unknown.m:027: `io.format'/4:
string_format_unknown.m:027: invalid conversion specifier.
string_format_unknown.m:028: Mismatched format and values in call to
string_format_unknown.m:028: `io.format'/4:
string_format_unknown.m:028: `io.format'/5:
string_format_unknown.m:028: invalid conversion specifier.
string_format_unknown.m:038: Unknown format values in call to `io.format'/5.
string_format_unknown.m:043: Mismatched format and values in call to
string_format_unknown.m:043: `io.format'/5:
string_format_unknown.m:043: invalid conversion specifier.
string_format_unknown.m:029: Mismatched format and values in call to
string_format_unknown.m:029: `io.format'/4:
string_format_unknown.m:029: invalid conversion specifier.
string_format_unknown.m:039: Unknown format values in call to `io.format'/5.
string_format_unknown.m:040: Unknown format values in call to
string_format_unknown.m:040: `stream.format'/5.
string_format_unknown.m:045: Mismatched format and values in call to
string_format_unknown.m:045: `io.format'/5:
string_format_unknown.m:045: invalid conversion specifier.

View File

@@ -14,6 +14,7 @@
:- import_module float.
:- import_module int.
:- import_module list.
:- import_module stream.
:- import_module string.
main(!IO) :-
@@ -36,6 +37,7 @@ main(!IO) :-
V6 = [s("six"), V6A],
copy(V6, C6),
io.format(OutputStream, F6, C6, !IO),
stream.format(OutputStream, F6, C6, !IO),
make_bool(7, T7),
F7 = "%d %s %d",
(