mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
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:
@@ -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
|
||||
).
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
%-----------------------------------------------------------------------------%
|
||||
|
||||
@@ -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.
|
||||
|
||||
1
tests/hard_coded/stream_format.exp
Normal file
1
tests/hard_coded/stream_format.exp
Normal file
@@ -0,0 +1 @@
|
||||
foo561a3.141000
|
||||
17
tests/hard_coded/stream_format.m
Normal file
17
tests/hard_coded/stream_format.m
Normal 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).
|
||||
7
tests/hard_coded/stream_ignore_ws.data
Normal file
7
tests/hard_coded/stream_ignore_ws.data
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
foo bar baz
|
||||
1
tests/hard_coded/stream_ignore_ws.exp
Normal file
1
tests/hard_coded/stream_ignore_ws.exp
Normal file
@@ -0,0 +1 @@
|
||||
foo bar baz
|
||||
24
tests/hard_coded/stream_ignore_ws.m
Normal file
24
tests/hard_coded/stream_ignore_ws.m
Normal 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)
|
||||
).
|
||||
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user