From 685eefa206fd57dec7921570f0fb470b6fd9855a Mon Sep 17 00:00:00 2001 From: Zoltan Somogyi Date: Mon, 3 Jul 2023 23:59:21 +0200 Subject: [PATCH] Move base of term_io.m to X_to_string, write_X, format_X. library/term_io.m: Move the base operations of term_io.m to the structure we use in parse_tree_out*.m in the compiler, where for every type X, there is a function X_to_string, and two predicates write_X and format_X, with the former operating on I/O states, and the latter operating on arbitrary streams. The idea is to apply the "don't repeat yourself" principle by having both X_to_string and write_X just call format_X. Apply that principle here as well, with one minor exception, which is that for some values of X, both write_X and format_X are implemented in terms of X_to_string. Impose the X_to_string, write_X, format_X naming scheme. The ancient code already in term_io.m had (each for some values of X) had - some of these functions/predicates missing - inconsistent names, in that write_X/N did I/O while write_X/(N+1) wrote to arbitrary streams - names that were inconsistent in another way, in that write_X/N did I/O of values of type X, but the function to convert X to string was NOT named X_to_string. Keep some of the misnamed functions around permanently, because some of the names for fitting into the new scheme, such as "escaped_string_to_string", would be strange. Keep the rest of the misnamed functions and all the misnamed predicates around temporarily, with commented-out obsolete pragmas. I expect to make these pragmas active when the rest of term_io.m is converted to this scheme. To prepare for that, use string.builder, not string, as the stream.writer instance to implement X_to_string, because of its better algorithmic complexity, which is needed mainly for terms of nontrivial size. Consistently put operations on each X in the order X_to_string, write_X and format_X. NEWS.md: List all the new predicates and functions. configure.ac: Require the installed compiler to contain the fix which allows a typespec pragma for an obsolete predicate or function. browser/interactive_query.m: compiler/hlds_out_util.m: compiler/parse_tree_out_clause.m: compiler/parse_tree_out_cons_id.m: compiler/parse_tree_out_info.m: compiler/parse_tree_out_pragma.m: compiler/parse_tree_out_sym_name.m: compiler/parse_tree_out_type_repn.m: library/pretty_printer.m: library/stream.string_writer.m: library/string.builder.m: mdbcomp/trace_counts.m: Update all references to the newly-obsolete predicates and functions. library/string.to_string.m: Improve variable names. --- NEWS.md | 18 ++ browser/interactive_query.m | 2 +- compiler/hlds_out_util.m | 4 +- compiler/parse_tree_out_clause.m | 2 +- compiler/parse_tree_out_cons_id.m | 4 +- compiler/parse_tree_out_info.m | 8 +- compiler/parse_tree_out_pragma.m | 2 +- compiler/parse_tree_out_sym_name.m | 4 +- compiler/parse_tree_out_type_repn.m | 2 +- configure.ac | 2 +- library/pretty_printer.m | 2 +- library/stream.string_writer.m | 18 +- library/string.builder.m | 18 +- library/string.to_string.m | 2 +- library/term_io.m | 431 +++++++++++++++++----------- mdbcomp/trace_counts.m | 10 +- 16 files changed, 324 insertions(+), 205 deletions(-) diff --git a/NEWS.md b/NEWS.md index bfdc2bd61..d5aa4d346 100644 --- a/NEWS.md +++ b/NEWS.md @@ -921,6 +921,24 @@ Changes to the Mercury standard library ### Changes to the `term_io` module +* The following predicates have been added: + + - func `constant_to_string/2` + - func `escaped_char_to_string/2` + - func `quoted_char_to_string/2` + - pred `format_constant/4` + - pred `format_escaped_char/4` + - pred `format_escaped_string/4` + - pred `format_quoted_atom/4` + - pred `format_quoted_char/4` + - pred `format_quoted_string/4` + - pred `write_quoted_atom/3` + - pred `write_quoted_atom/4` + - pred `write_quoted_char/3` + - pred `write_quoted_char/4` + - pred `write_quoted_string/3` + - pred `write_quoted_string/4` + * The following predicates have been removed: - pred `read_term/3` diff --git a/browser/interactive_query.m b/browser/interactive_query.m index ce9a2cc48..4d4348403 100644 --- a/browser/interactive_query.m +++ b/browser/interactive_query.m @@ -624,7 +624,7 @@ write_comma_var(OutputStream, Var, !IO) :- write_module_import(OutputStream, ModuleName, !IO) :- io.write_string(OutputStream, ":- import_module ", !IO), - term_io.quote_atom(OutputStream, ModuleName, !IO), + term_io.format_quoted_atom(OutputStream, ModuleName, !IO), io.write_string(OutputStream, ".\n", !IO). %---------------------------------------------------------------------------% diff --git a/compiler/hlds_out_util.m b/compiler/hlds_out_util.m index 5ca22f333..b462afa25 100644 --- a/compiler/hlds_out_util.m +++ b/compiler/hlds_out_util.m @@ -657,7 +657,7 @@ functor_cons_id_to_string(ModuleInfo, VarNameSrc, VarNamePrint, % and 'z' should acceptable too. I (zs) think that 'z' should % be acceptable to the scanner and parser (which currently it isn't), % but (z) should not be. - Str = "(" ++ term_io.quoted_char(Char) ++ ")" + Str = "(" ++ term_io.quoted_char_to_string(Char) ++ ")" ; ConsId = string_const(String), Str = functor_to_string(VarNameSrc, VarNamePrint, @@ -795,7 +795,7 @@ cons_id_and_vars_or_arity_to_string(VarTable, Qual, ConsId, MaybeArgVars) String = float_to_string(Float) ; ConsId = char_const(CharConst), - String = term_io.quoted_char(CharConst) + String = term_io.quoted_char_to_string(CharConst) ; ConsId = string_const(StringConst), String = term_io.quoted_string(StringConst) diff --git a/compiler/parse_tree_out_clause.m b/compiler/parse_tree_out_clause.m index afa9168e0..bef04b579 100644 --- a/compiler/parse_tree_out_clause.m +++ b/compiler/parse_tree_out_clause.m @@ -863,7 +863,7 @@ mercury_output_trace_compiletime(CompileTime, Stream, !IO) :- mercury_output_trace_runtime(trace_envvar(EnvVarName), Stream, !IO) :- io.write_string(Stream, "env(", !IO), - term_io.quote_string(Stream, EnvVarName, !IO), + term_io.format_quoted_string(Stream, EnvVarName, !IO), io.write_string(Stream, ")", !IO). %---------------------------------------------------------------------------% diff --git a/compiler/parse_tree_out_cons_id.m b/compiler/parse_tree_out_cons_id.m index ae9e46c38..510a23037 100644 --- a/compiler/parse_tree_out_cons_id.m +++ b/compiler/parse_tree_out_cons_id.m @@ -151,7 +151,7 @@ mercury_format_cons_id(Lang, NeedsBrackets, ConsId, S, !U) :- add_float(Float, S, !U) ; ConsId = char_const(Char), - add_string(term_io.quoted_char(Char), S, !U) + add_string(term_io.quoted_char_to_string(Char), S, !U) ; ConsId = string_const(Str), add_quoted_string(Str, S, !U) @@ -287,7 +287,7 @@ cons_id_and_arity_to_string_maybe_quoted(MangleCons, QuoteCons, ConsId) String = float_to_string(Float) ; ConsId = char_const(CharConst), - String = term_io.quoted_char(CharConst) + String = term_io.quoted_char_to_string(CharConst) ; ConsId = string_const(StringConst), String = term_io.quoted_string(StringConst) diff --git a/compiler/parse_tree_out_info.m b/compiler/parse_tree_out_info.m index 749ff9b36..da1d5803e 100644 --- a/compiler/parse_tree_out_info.m +++ b/compiler/parse_tree_out_info.m @@ -405,13 +405,13 @@ write_purity_prefix(Purity, Stream, !IO) :- io::di, io::uo) is det. write_quoted_atom(Atom, Stream, !IO) :- - term_io.quote_atom(Stream, Atom, !IO). + term_io.format_quoted_atom(Stream, Atom, !IO). :- pred write_quoted_string(string::in, io.text_output_stream::in, io::di, io::uo) is det. write_quoted_string(Str, Stream, !IO) :- - term_io.quote_string(Stream, Str, !IO). + term_io.format_quoted_string(Stream, Str, !IO). :- pred write_constant(const::in, io.text_output_stream::in, io::di, io::uo) is det. @@ -438,7 +438,7 @@ write_lambda_eval_method(LambdaEvalMethod, Stream, !IO) :- io::di, io::uo) is det. write_escaped_string(Str, Stream, !IO) :- - term_io.write_escaped_string(Stream, Str, !IO). + term_io.format_escaped_string(Stream, Str, !IO). %-------------% @@ -568,7 +568,7 @@ output_quoted_string(A, _, Str0, Str) :- :- pred output_constant(const::in, unit::in, string::di, string::uo) is det. output_constant(C, _, Str0, Str) :- - CS = term_io.format_constant(C), + CS = term_io.constant_to_string(C), string.append(Str0, CS, Str). :- pred output_escaped_string(string::in, unit::in, diff --git a/compiler/parse_tree_out_pragma.m b/compiler/parse_tree_out_pragma.m index 6e0cc1100..6f9d6864f 100644 --- a/compiler/parse_tree_out_pragma.m +++ b/compiler/parse_tree_out_pragma.m @@ -473,9 +473,9 @@ mercury_format_escaped_char(S, Char, !U) :- % :- pred escape_special_char(char::in, char::out) is semidet. +escape_special_char('\\', '\\'). escape_special_char('''', ''''). escape_special_char('"', '"'). -escape_special_char('\\', '\\'). escape_special_char('\b', 'b'). % Succeed if Char is a character which is allowed in diff --git a/compiler/parse_tree_out_sym_name.m b/compiler/parse_tree_out_sym_name.m index 6b25dbf19..b773bd66f 100644 --- a/compiler/parse_tree_out_sym_name.m +++ b/compiler/parse_tree_out_sym_name.m @@ -254,9 +254,9 @@ sym_name_to_escaped_string(unqualified(Name)) = write_sym_name(Stream, qualified(Module, Name), !IO) :- write_sym_name(Stream, Module, !IO), io.write_string(Stream, ".", !IO), - term_io.write_escaped_string(Stream, Name, !IO). + term_io.format_escaped_string(Stream, Name, !IO). write_sym_name(Stream, unqualified(Name), !IO) :- - term_io.write_escaped_string(Stream, Name, !IO). + term_io.format_escaped_string(Stream, Name, !IO). write_quoted_sym_name(Stream, SymName, !IO) :- io.write_string(Stream, "'", !IO), diff --git a/compiler/parse_tree_out_type_repn.m b/compiler/parse_tree_out_type_repn.m index b522aef1e..98222a6a4 100644 --- a/compiler/parse_tree_out_type_repn.m +++ b/compiler/parse_tree_out_type_repn.m @@ -912,7 +912,7 @@ foreign_type_assertion_to_string(Assertion) = Str :- io::di, io::uo) is det. mercury_output_functor_name(FunctorName, Stream, !IO) :- - term_io.quote_string(Stream, FunctorName, !IO). + term_io.format_quoted_string(Stream, FunctorName, !IO). % Output one functor's name in a list of functor names. % diff --git a/configure.ac b/configure.ac index 2b5892e04..e9b40517e 100644 --- a/configure.ac +++ b/configure.ac @@ -585,7 +585,7 @@ EOF $BOOTSTRAP_MC \ --verbose \ $link_static_opt conftest \ - --singleton-2023-06-10 \ + --warn-obsolete-transform-2023-07-03 \ --no-ssdb \ &AS_MESSAGE_LOG_FD 2>&1 && test "`./conftest 2>&1 | tr -d '\015'`" = "Hello, world" && diff --git a/library/pretty_printer.m b/library/pretty_printer.m index 2a12a786a..5ae48d9d5 100644 --- a/library/pretty_printer.m +++ b/library/pretty_printer.m @@ -1701,7 +1701,7 @@ set_default_params(Params, !IO) :- %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% -char_to_doc(C) = str(term_io.quoted_char(C)). +char_to_doc(C) = str(term_io.quoted_char_to_string(C)). string_to_doc(S) = str(term_io.quoted_string(S)). diff --git a/library/stream.string_writer.m b/library/stream.string_writer.m index 3c5aaddb6..ad029b891 100644 --- a/library/stream.string_writer.m +++ b/library/stream.string_writer.m @@ -785,7 +785,7 @@ do_write_univ_prio(Stream, NonCanon, Univ, Priority, !State) :- ( TB = type_builtin_string, ( if univ_to_type(Univ, String) then - term_io.quote_string(Stream, String, !State) + term_io.format_quoted_string(Stream, String, !State) else write_ordinary_term(Stream, NonCanon, Univ, Priority, !State) @@ -793,7 +793,7 @@ do_write_univ_prio(Stream, NonCanon, Univ, Priority, !State) :- ; TB = type_builtin_character, ( if univ_to_type(Univ, Char) then - term_io.quote_char(Stream, Char, !State) + term_io.format_quoted_char(Stream, Char, !State) else write_ordinary_term(Stream, NonCanon, Univ, Priority, !State) @@ -1073,7 +1073,7 @@ write_ordinary_term(Stream, NonCanon, Univ, Priority, !State) :- Args = [ArgA], ( if OpInfos ^ oi_prefix = pre(OpPriority, GtOrGeA) then maybe_write_paren(Stream, '(', Priority, OpPriority, !State), - term_io.quote_atom(Stream, Functor, !State), + term_io.format_quoted_atom(Stream, Functor, !State), put(Stream, " ", !State), MinPrioA = min_priority_for_arg(OpPriority, GtOrGeA), do_write_univ_prio(Stream, NonCanon, ArgA, MinPrioA, !State), @@ -1083,7 +1083,7 @@ write_ordinary_term(Stream, NonCanon, Univ, Priority, !State) :- MinPrioA = min_priority_for_arg(OpPriority, GtOrGeA), do_write_univ_prio(Stream, NonCanon, ArgA, MinPrioA, !State), put(Stream, " ", !State), - term_io.quote_atom(Stream, Functor, !State), + term_io.format_quoted_atom(Stream, Functor, !State), maybe_write_paren(Stream, ')', Priority, OpPriority, !State) else write_functor_and_args_prio(Stream, NonCanon, Priority, @@ -1102,7 +1102,7 @@ write_ordinary_term(Stream, NonCanon, Univ, Priority, !State) :- put(Stream, ", ", !State) else put(Stream, " ", !State), - term_io.quote_atom(Stream, Functor, !State), + term_io.format_quoted_atom(Stream, Functor, !State), put(Stream, " ", !State) ), do_write_univ_prio(Stream, NonCanon, ArgB, MinPrioB, !State), @@ -1114,7 +1114,7 @@ write_ordinary_term(Stream, NonCanon, Univ, Priority, !State) :- MinPrioA = min_priority_for_arg(OpPriority, GtOrGeA), MinPrioB = min_priority_for_arg(OpPriority, GtOrGeB), maybe_write_paren(Stream, '(', Priority, OpPriority, !State), - term_io.quote_atom(Stream, Functor, !State), + term_io.format_quoted_atom(Stream, Functor, !State), put(Stream, " ", !State), do_write_univ_prio(Stream, NonCanon, ArgA, MinPrioA, !State), put(Stream, " ", !State), @@ -1160,7 +1160,7 @@ write_functor_and_args_prio(Stream, NonCanon, Priority, Functor, Args, priority_ge(Priority, ops.mercury_op_table_loosest_op_priority) then put(Stream, '(', !State), - term_io.quote_atom(Stream, Functor, !State), + term_io.format_quoted_atom(Stream, Functor, !State), put(Stream, ')', !State) else write_functor_and_args(Stream, NonCanon, Functor, Args, !State) @@ -1185,8 +1185,8 @@ write_functor_and_args_prio(Stream, NonCanon, Priority, Functor, Args, :- pragma inline(pred(write_functor_and_args/6)). write_functor_and_args(Stream, NonCanon, Functor, Args, !State) :- - term_io.quote_atom_agt(Stream, Functor, - maybe_adjacent_to_graphic_token, !State), + AGT = maybe_adjacent_to_graphic_token, + term_io.format_quoted_atom_agt(Stream, Functor, AGT, !State), ( Args = [X | Xs], put(Stream, '(', !State), diff --git a/library/string.builder.m b/library/string.builder.m index ed2827c69..6273357cc 100644 --- a/library/string.builder.m +++ b/library/string.builder.m @@ -16,7 +16,7 @@ % string builder state by calling the init function. You can then use % any instances of stream.writer that write strings or characters to update the % string builder state, using string.builder.handle as the stream argument. -% Once you've finished writing to the string builder you can get the final +% Once you have finished writing to the string builder, you can get the final % string by calling string.builder.to_string/1. % % For example: @@ -78,25 +78,25 @@ init = state([]). :- instance stream.writer(string.builder.handle, string, string.builder.state) where [ ( put(_, String, !State) :- - !.State = state(StringList0), + !.State = state(RevStrings0), copy(String, UniqueString), - StringList = [UniqueString | StringList0], - !:State = state(StringList) + RevStrings = [UniqueString | RevStrings0], + !:State = state(RevStrings) ) ]. :- instance stream.writer(string.builder.handle, char, string.builder.state) where [ ( put(_, Char, !State) :- - !.State = state(StringList0), - StringList = [string.from_char(Char) | StringList0], - !:State = state(StringList) + !.State = state(RevStrings0), + RevStrings = [string.from_char(Char) | RevStrings0], + !:State = state(RevStrings) ) ]. to_string(State) = String :- - State = state(StringList), - String = string.append_list(list.reverse(StringList)). + State = state(RevStrings), + String = string.append_list(list.reverse(RevStrings)). %---------------------------------------------------------------------------% :- end_module string.builder. diff --git a/library/string.to_string.m b/library/string.to_string.m index a614fc59b..a9aab60e2 100644 --- a/library/string.to_string.m +++ b/library/string.to_string.m @@ -109,7 +109,7 @@ value_to_revstrings_prio(NonCanon, OpTable, Priority, X, !Rs) :- ( if dynamic_cast(X, String) then add_revstring(term_io.quoted_string(String), !Rs) else if dynamic_cast(X, Char) then - add_revstring(term_io.quoted_char(Char), !Rs) + add_revstring(term_io.quoted_char_to_string(Char), !Rs) else if dynamic_cast(X, Int) then add_revstring(string.int_to_string(Int), !Rs) else if dynamic_cast(X, UInt) then diff --git a/library/term_io.m b/library/term_io.m index bb18a7ba7..5d55260bd 100644 --- a/library/term_io.m +++ b/library/term_io.m @@ -62,16 +62,21 @@ %---------------------% + % Convert the given constant to a string. + % +:- func format_constant(const) = string. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(func(format_constant/1), [constant_to_string/1]). +:- func constant_to_string(const) = string. + % Writes a constant (integer, float, string, or atom) to % the current output stream, or to the specified output stream. % :- pred write_constant(const::in, io::di, io::uo) is det. :- pred write_constant(io.text_output_stream::in, const::in, io::di, io::uo) is det. - - % Like write_constant, but return the result in a string. - % -:- func format_constant(const) = string. +:- pred format_constant(Stream::in, const::in, State::di, State::uo) is det + <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). %---------------------% @@ -92,32 +97,51 @@ %---------------------% - % Given a character C, write C in single-quotes, escaped if necessary, + % Given a character C, return C, escaped if necessary, in single-quotes. + % +:- func quoted_char(char) = string. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(func(quoted_char/1), [quoted_char_to_string/1]). +:- func quoted_char_to_string(char) = string. + + % Given a character C, write C, escaped if necessary, in single-quotes, % to the current output stream, or to the specified output stream. % :- pred quote_char(char::in, io::di, io::uo) is det. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(quote_char/3), [write_quoted_char/3]). +:- pred write_quoted_char(char::in, io::di, io::uo) is det. +:- pred write_quoted_char(io.text_output_stream::in, char::in, + io::di, io::uo) is det. :- pred quote_char(Stream::in, char::in, State::di, State::uo) is det <= (stream.writer(Stream, string, State), stream.writer(Stream, char, State)). +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(quote_char/4), [format_quoted_char/4]). +:- pred format_quoted_char(Stream::in, char::in, State::di, State::uo) is det + <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). - % Like quote_char, but return the result in a string. +%---------------------% + + % Given a character C, return C, escaped if necessary. + % Do not enclose it in single-quotes. % -:- func quoted_char(char) = string. +:- func escaped_char(char) = string. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(func(escaped_char/1), [escaped_char_to_string/1]). +:- func escaped_char_to_string(char) = string. % Given a character C, write C, escaped if necessary, - % to the current output stream, or to the specified output stream. - % Do not enclose the character in quotes. + % and not enclosed in single-quotes, to the current output stream, + % or to the specified output stream. % :- pred write_escaped_char(char::in, io::di, io::uo) is det. :- pred write_escaped_char(Stream::in, char::in, State::di, State::uo) is det <= (stream.writer(Stream, string, State), stream.writer(Stream, char, State)). +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(write_escaped_char/4), [format_escaped_char/4]). +:- pred format_escaped_char(Stream::in, char::in, State::di, State::uo) is det + <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). - % Like write_escaped_char, but return the result in a string. - % -:- func escaped_char(char) = string. - - % A reversible version of escaped_char. + % A reversible version of escaped_char_to_string. % :- pred string_is_escaped_char(char, string). :- mode string_is_escaped_char(in, out) is det. @@ -125,46 +149,71 @@ %---------------------% - % Given a string S, write S in double-quotes, with characters - % escaped if necessary, to the current output stream, or to the - % specified output stream. - % -:- pred quote_string(string::in, io::di, io::uo) is det. -:- pred quote_string(Stream::in, string::in, State::di, State::uo) is det - <= (stream.writer(Stream, string, State), - stream.writer(Stream, char, State)). - - % Like quote_string, but return the result in a string. + % Given a string S, return a version of S, with its characters escaped + % if necessary, in double-quotes. % :- func quoted_string(string) = string. - % Given a string S, write S, with characters escaped if necessary. - % Do not enclose the string in quotes. Write to the current output stream, + % Given a string S, write a version of S, with its characters escaped + % if necessary, in double-quotes, to the current output stream, % or to the specified output stream. % +:- pred quote_string(string::in, io::di, io::uo) is det. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(quote_string/3), [write_quoted_string/3]). +:- pred write_quoted_string(string::in, io::di, io::uo) is det. +:- pred write_quoted_string(io.text_output_stream::in, string::in, + io::di, io::uo) is det. +:- pred quote_string(Stream::in, string::in, State::di, State::uo) is det + <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(quote_string/4), [format_quoted_string/4]). +:- pred format_quoted_string(Stream::in, string::in, State::di, State::uo) + is det <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). + +%---------------------% + + % Given a string S, return a version of S in which its characters + % are escaped if necessary. Do not enclose the string in quotes. + % +:- func escaped_string(string) = string. + + % Given a string S, write a version of S in which its characters + % are escaped if necessary. Do not enclose the string in quotes. + % Write it to the current output stream, or to the specified output stream. + % :- pred write_escaped_string(string::in, io::di, io::uo) is det. :- pred write_escaped_string(Stream::in, string::in, State::di, State::uo) is det <= (stream.writer(Stream, string, State), stream.writer(Stream, char, State)). - - % Like write_escaped_string, but return the result in a string. - % -:- func escaped_string(string) = string. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(write_escaped_string/4), [format_escaped_string/4]). +:- pred format_escaped_string(Stream::in, string::in, State::di, State::uo) + is det <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). %---------------------% - % Given an atom-name A, write A, enclosed in single-quotes if necessary, - % with characters escaped if necessary. Write to the current output stream, - % or to the specified output stream. + % Given a string S, return a version of S in which its characters + % are escaped if necessary. Enclose the string in quotes. + % +:- func quoted_atom(string) = string. + + % Given a string S, write a version of S in which its characters + % are escaped if necessary. Enclose the string in quotes. + % Write it to the current output stream, or to the specified output stream. % :- pred quote_atom(string::in, io::di, io::uo) is det. +:- pred write_quoted_atom(string::in, io::di, io::uo) is det. +:- pred write_quoted_atom(io.text_output_stream::in, string::in, + io::di, io::uo) is det. + :- pred quote_atom(Stream::in, string::in, State::di, State::uo) is det <= (stream.writer(Stream, string, State), stream.writer(Stream, char, State)). - - % Like quote_atom, but return the result in a string. - % -:- func quoted_atom(string) = string. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(quote_atom/4), [format_quoted_atom/4]). +:- pred format_quoted_atom(Stream::in, string::in, State::di, State::uo) is det + <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% @@ -186,15 +235,25 @@ ---> maybe_adjacent_to_graphic_token ; not_adjacent_to_graphic_token. +:- func quoted_atom_agt(string, adjacent_to_graphic_token) = string. + :- pred quote_atom_agt(string::in, adjacent_to_graphic_token::in, io::di, io::uo) is det. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(quote_atom_agt/4), [write_quoted_atom_agt/4]). +:- pred write_quoted_atom_agt(string::in, + adjacent_to_graphic_token::in, io::di, io::uo) is det. +:- pred write_quoted_atom_agt(io.text_output_stream::in, string::in, + adjacent_to_graphic_token::in, io::di, io::uo) is det. :- pred quote_atom_agt(Stream::in, string::in, adjacent_to_graphic_token::in, State::di, State::uo) is det <= (stream.writer(Stream, string, State), stream.writer(Stream, char, State)). - -:- func quoted_atom_agt(string, adjacent_to_graphic_token) = string. +% NOTE_TO_IMPLEMENTORS OBS :- pragma obsolete(pred(quote_atom_agt/5), [format_quoted_atom_agt/5]). +:- pred format_quoted_atom_agt(Stream::in, string::in, + adjacent_to_graphic_token::in, State::di, State::uo) is det + <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). :- pragma type_spec(pred(term_io.quote_string/4), (Stream = io.text_output_stream, State = io.state)). @@ -206,8 +265,12 @@ (Stream = io.text_output_stream, State = io.state)). :- pragma type_spec(pred(term_io.quote_char/4), (Stream = io.text_output_stream, State = io.state)). +:- pragma type_spec(pred(term_io.format_quoted_char/4), + (Stream = io.text_output_stream, State = io.state)). :- pragma type_spec(pred(term_io.quote_atom_agt/5), (Stream = io.text_output_stream, State = io.state)). +:- pragma type_spec(pred(term_io.format_quoted_atom_agt/5), + (Stream = io.text_output_stream, State = io.state)). %---------------------------------------------------------------------------% @@ -260,6 +323,7 @@ :- import_module mercury_term_lexer. :- import_module require. :- import_module string. +:- import_module string.builder. :- import_module stream.string_writer. %---------------------------------------------------------------------------% @@ -331,7 +395,7 @@ write_term_prio_anon_vars(OutStream, OpTable, Term, Priority, % Terms with these functors should NOT have arguments. ( ArgTerms = [], - write_constant(OutStream, Functor, + format_constant_agt(OutStream, Functor, maybe_adjacent_to_graphic_token, !IO) ; ArgTerms = [_ | _], @@ -442,7 +506,7 @@ write_atom_term_prio_anon_vars(OutStream, OpTable, Atom, ArgTerms, ArgTerms = [ArgTerm1], ( if MaybePrefix = pre(OpPriority, OpGtOrGe) then maybe_write_paren(OutStream, '(', Priority, OpPriority, !IO), - write_constant_atom(OutStream, Atom, !IO), + format_constant_atom(OutStream, Atom, !IO), io.write_char(OutStream, ' ', !IO), NewPriority = min_priority_for_arg(OpPriority, OpGtOrGe), write_term_prio_anon_vars(OutStream, OpTable, ArgTerm1, @@ -454,7 +518,7 @@ write_atom_term_prio_anon_vars(OutStream, OpTable, Atom, ArgTerms, write_term_prio_anon_vars(OutStream, OpTable, ArgTerm1, NewPriority, !VarSet, !Anon, !IO), io.write_char(OutStream, ' ', !IO), - write_constant_atom(OutStream, Atom, !IO), + format_constant_atom(OutStream, Atom, !IO), maybe_write_paren(OutStream, ')', Priority, OpPriority, !IO) else write_atom_term_prio_anon_vars_std(OutStream, OpTable, @@ -485,7 +549,7 @@ write_atom_term_prio_anon_vars(OutStream, OpTable, Atom, ArgTerms, io.write_string(OutStream, Dot, !IO) else io.write_char(OutStream, ' ', !IO), - write_constant_atom(OutStream, Atom, !IO), + format_constant_atom(OutStream, Atom, !IO), io.write_char(OutStream, ' ', !IO) ), RightPriority = min_priority_for_arg(OpPriority, RightGtOrGe), @@ -496,7 +560,7 @@ write_atom_term_prio_anon_vars(OutStream, OpTable, Atom, ArgTerms, MaybeBinPrefix = bin_pre(OpPriority, LeftGtOrGe, RightGtOrGe) then maybe_write_paren(OutStream, '(', Priority, OpPriority, !IO), - write_constant_atom(OutStream, Atom, !IO), + format_constant_atom(OutStream, Atom, !IO), io.write_char(OutStream, ' ', !IO), LeftPriority = min_priority_for_arg(OpPriority, LeftGtOrGe), write_term_prio_anon_vars(OutStream, OpTable, ArgTerm1, @@ -529,10 +593,10 @@ write_atom_term_prio_anon_vars_std(OutStream, OpTable, Atom, ArgTerms, priority_ge(Priority, ops.loosest_op_priority(OpTable)) then io.write_char(OutStream, '(', !IO), - write_constant_atom(OutStream, Atom, !IO), + format_constant_atom(OutStream, Atom, !IO), io.write_char(OutStream, ')', !IO) else - write_constant_atom(OutStream, Atom, !IO) + format_constant_atom(OutStream, Atom, !IO) ), ( ArgTerms = [HeadArgTerm | TailArgTerms], @@ -615,83 +679,77 @@ starts_with_digit(functor(atom(Op), Args, _)) :- %---------------------------------------------------------------------------% +format_constant(Const) = + constant_to_string(Const). + +constant_to_string(Const) = Str :- + AGT = not_adjacent_to_graphic_token, + State0 = string.builder.init, + format_constant_agt(string.builder.handle, Const, AGT, State0, State), + Str = string.builder.to_string(State). + write_constant(Const, !IO) :- io.output_stream(OutStream, !IO), write_constant(OutStream, Const, !IO). write_constant(OutStream, Const, !IO) :- - write_constant(OutStream, Const, not_adjacent_to_graphic_token, !IO). + AGT = not_adjacent_to_graphic_token, + format_constant_agt(OutStream, Const, AGT, !IO). -:- pred write_constant_atom(io.text_output_stream::in, string::in, - io::di, io::uo) is det. -:- pragma inline(pred(write_constant_atom/4)). +format_constant(Stream, Const, !State) :- + AGT = not_adjacent_to_graphic_token, + format_constant_agt(Stream, Const, AGT, !State). -write_constant_atom(OutStream, Atom, !IO) :- - NGT = not_adjacent_to_graphic_token, - term_io.quote_atom_agt(OutStream, Atom, NGT, !IO). +:- pred format_constant_agt(Stream::in, const::in, + adjacent_to_graphic_token::in, State::di, State::uo) is det + <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). -:- pred write_constant(io.text_output_stream::in, const::in, - adjacent_to_graphic_token::in, io::di, io::uo) is det. - -write_constant(OutStream, Const, NGT, !IO) :- +format_constant_agt(Stream, Const, AGT, !State) :- ( Const = term.integer(Base, Int, Signedness, Size), Prefix = integer_base_prefix(Base), IntStr = integer.to_base_string(Int, integer_base_int(Base)), Suffix = integer_signedness_and_size_suffix(Signedness, Size), - io.write_string(OutStream, Prefix, !IO), - io.write_string(OutStream, IntStr, !IO), - io.write_string(OutStream, Suffix, !IO) + stream.put(Stream, Prefix, !State), + stream.put(Stream, IntStr, !State), + stream.put(Stream, Suffix, !State) ; Const = term.float(Float), - io.write_float(OutStream, Float, !IO) + put_float(Stream, Float, !State) ; Const = term.atom(Atom), - term_io.quote_atom_agt(OutStream, Atom, NGT, !IO) + term_io.format_quoted_atom_agt(Stream, Atom, AGT, !State) ; Const = term.string(Str), - term_io.quote_string(OutStream, Str, !IO) + term_io.format_quoted_string(Stream, Str, !State) ; Const = term.implementation_defined(ImplDef), - io.write_char(OutStream, '$', !IO), - io.write_string(OutStream, ImplDef, !IO) + stream.put(Stream, '$', !State), + put(Stream, ImplDef, !State) ). -format_constant(Const) = - term_io.format_constant_agt(Const, not_adjacent_to_graphic_token). + % This does the job of format_constant just for atom constants. + % +:- pred format_constant_atom(Stream::in, string::in, State::di, State::uo) + is det <= (stream.writer(Stream, string, State), + stream.writer(Stream, char, State)). +:- pragma inline(pred(format_constant_atom/4)). -:- func format_constant_agt(const, adjacent_to_graphic_token) = string. - -format_constant_agt(Const, AdjacentToGraphicToken) = Str :- - ( - Const = term.integer(Base, I, Signedness, Size), - Str = integer_base_prefix(Base) ++ - to_base_string(I, integer_base_int(Base)) ++ - integer_signedness_and_size_suffix(Signedness, Size) - ; - Const = term.float(F), - Str = string.float_to_string(F) - ; - Const = term.atom(A), - Str = term_io.quoted_atom_agt(A, AdjacentToGraphicToken) - ; - Const = term.string(S), - Str = term_io.quoted_string(S) - ; - Const = term.implementation_defined(N), - Str = "$" ++ N - ). +format_constant_atom(Stream, Atom, !IO) :- + AGT = not_adjacent_to_graphic_token, + term_io.format_quoted_atom_agt(Stream, Atom, AGT, !IO). :- func integer_signedness_and_size_suffix(term.signedness, term.integer_size) = string. -integer_signedness_and_size_suffix(signed, size_word) = "". -integer_signedness_and_size_suffix(signed, size_8_bit) = "i8". -integer_signedness_and_size_suffix(signed, size_16_bit) = "i16". -integer_signedness_and_size_suffix(signed, size_32_bit) = "i32". -integer_signedness_and_size_suffix(signed, size_64_bit) = "i64". -integer_signedness_and_size_suffix(unsigned, size_word) = "u". -integer_signedness_and_size_suffix(unsigned, size_8_bit) = "u8". +integer_signedness_and_size_suffix(signed, size_word) = "". +integer_signedness_and_size_suffix(signed, size_8_bit) = "i8". +integer_signedness_and_size_suffix(signed, size_16_bit) = "i16". +integer_signedness_and_size_suffix(signed, size_32_bit) = "i32". +integer_signedness_and_size_suffix(signed, size_64_bit) = "i64". +integer_signedness_and_size_suffix(unsigned, size_word) = "u". +integer_signedness_and_size_suffix(unsigned, size_8_bit) = "u8". integer_signedness_and_size_suffix(unsigned, size_16_bit) = "u16". integer_signedness_and_size_suffix(unsigned, size_32_bit) = "u32". integer_signedness_and_size_suffix(unsigned, size_64_bit) = "u64". @@ -790,23 +848,45 @@ write_variable_anon_vars(OutStream, OpTable, Var, !VarSet, !Anon, !IO) :- %---------------------------------------------------------------------------% +quoted_char(C) = + quoted_char_to_string(C). + +quoted_char_to_string(C) = + string.format("'%s'", [s(term_io.escaped_char_to_string(C))]). + quote_char(C, !IO) :- + write_quoted_char(C, !IO). + +write_quoted_char(C, !IO) :- io.output_stream(OutStream, !IO), - io.write_string(OutStream, term_io.quoted_char(C), !IO). + format_quoted_char(OutStream, C, !IO). + +write_quoted_char(OutStream, C, !IO) :- + format_quoted_char(OutStream, C, !IO). quote_char(Stream, C, !State) :- - stream.put(Stream, term_io.quoted_char(C), !State). + format_quoted_char(Stream, C, !State). -quoted_char(C) = - string.format("'%s'", [s(term_io.escaped_char(C))]). +format_quoted_char(Stream, C, !State) :- + stream.put(Stream, term_io.quoted_char_to_string(C), !State). + +%---------------------% + +escaped_char(Char) = + escaped_char_to_string(Char). + +escaped_char_to_string(Char) = String :- + string_is_escaped_char(Char, String). write_escaped_char(Char, !IO) :- io.output_stream(Stream, !IO), - term_io.write_escaped_char(Stream, Char, !IO). + term_io.format_escaped_char(Stream, Char, !IO). write_escaped_char(Stream, Char, !State) :- - % Note: the code of add_escaped_char and write_escaped_char - % should be kept in sync. The code of both is similar to code in + format_escaped_char(Stream, Char, !State). + +format_escaped_char(Stream, Char, !State) :- + % Note: the code of format_escaped_char is similar to code in % compiler/parse_tree_out_pragma.m and MR_escape_string_quote % in runtime/mercury_string.c; any changes here may require similar % changes in those spots. @@ -819,9 +899,6 @@ write_escaped_char(Stream, Char, !State) :- stream.put(Stream, mercury_escape_char(Char), !State) ). -escaped_char(Char) = String :- - string_is_escaped_char(Char, String). - :- pragma promise_equivalent_clauses(pred(string_is_escaped_char/2)). string_is_escaped_char(Char::in, String::out) :- @@ -874,85 +951,106 @@ is_mercury_source_char(Char) :- % Note: the code here is similar to code in compiler/parse_tree_out_pragma.m; % any changes here may require similar changes there. -quote_string(S, !IO) :- - io.output_stream(Stream, !IO), - term_io.quote_string(Stream, S, !IO). +quoted_string(Str0) = Str :- + State0 = string.builder.init, + format_quoted_string(string.builder.handle, Str0, State0, State), + Str = string.builder.to_string(State). -quote_string(Stream, S, !State) :- +quote_string(Str, !IO) :- + io.output_stream(OutStream, !IO), + term_io.format_quoted_string(OutStream, Str, !IO). + +write_quoted_string(Str, !IO) :- + io.output_stream(OutStream, !IO), + format_quoted_string(OutStream, Str, !IO). + +write_quoted_string(OutStream, Str, !State) :- + format_quoted_string(OutStream, Str, !State). + +quote_string(Stream, Str, !State) :- + format_quoted_string(Stream, Str, !State). + +format_quoted_string(Stream, Str, !State) :- stream.put(Stream, '"', !State), - term_io.write_escaped_string(Stream, S, !State), + term_io.format_escaped_string(Stream, Str, !State), stream.put(Stream, '"', !State). -quoted_string(S) = - string.append_list(["""", term_io.escaped_string(S), """"]). +%---------------------% -write_escaped_string(String, !IO) :- +escaped_string(Str0) = Str :- + State0 = string.builder.init, + format_escaped_string(string.builder.handle, Str0, State0, State), + Str = string.builder.to_string(State). + +write_escaped_string(Str, !IO) :- io.output_stream(Stream, !IO), - term_io.write_escaped_string(Stream, String, !IO). + term_io.format_escaped_string(Stream, Str, !IO). -write_escaped_string(Stream, String, !State) :- +write_escaped_string(Stream, Str, !State) :- + format_escaped_string(Stream, Str, !State). + +format_escaped_string(Stream, Str, !State) :- % XXX ILSEQ Decide what to do with ill-formed sequences. - string.foldl(term_io.write_escaped_char(Stream), String, !State). - -escaped_string(String0) = String :- - % XXX ILSEQ Decide what to do with ill-formed sequences. - string.foldl(add_escaped_char, String0, [], RevStrings), - list.reverse(RevStrings, Strings), - string.append_list(Strings, String). - -:- pred add_escaped_char(char::in, list(string)::in, list(string)::out) is det. - -add_escaped_char(Char, RevStrings0, RevStrings) :- - % Note: the code of add_escaped_char and write_escaped_char - % should be kept in sync. The code of both is similar to code in - % compiler/parse_tree_out_pragma.m; any changes here may require - % similar changes there. - ( if mercury_escape_special_char(Char, QuoteChar) then - RevStrings = [from_char_list(['\\', QuoteChar]) | RevStrings0] - else if is_mercury_source_char(Char) then - RevStrings = [string.char_to_string(Char) | RevStrings0] - else - RevStrings = [mercury_escape_char(Char) | RevStrings0] - ). + string.foldl(term_io.format_escaped_char(Stream), Str, !State). %---------------------------------------------------------------------------% +quoted_atom(Str0) = Str :- + State0 = string.builder.init, + format_quoted_atom(string.builder.handle, Str0, State0, State), + Str = string.builder.to_string(State). + quote_atom(Str, !IO) :- - term_io.quote_atom_agt(Str, not_adjacent_to_graphic_token, !IO). + term_io.write_quoted_atom(Str, !IO). -quote_atom(Stream, S, !State) :- - term_io.quote_atom_agt(Stream, S, not_adjacent_to_graphic_token, !State). +write_quoted_atom(Str, !IO) :- + AGT = not_adjacent_to_graphic_token, + term_io.write_quoted_atom_agt(Str, AGT, !IO). -quoted_atom(S) = - term_io.quoted_atom_agt(S, not_adjacent_to_graphic_token). +write_quoted_atom(OutStream, Str, !IO) :- + AGT = not_adjacent_to_graphic_token, + term_io.write_quoted_atom_agt(OutStream, Str, AGT, !IO). -quote_atom_agt(Str, AdjacentToGraphicToken, !IO) :- +quote_atom(Stream, Str, !State) :- + format_quoted_atom(Stream, Str, !State). + +format_quoted_atom(Stream, Str, !State) :- + AGT = not_adjacent_to_graphic_token, + term_io.format_quoted_atom_agt(Stream, Str, AGT, !State). + +%---------------------% + +quoted_atom_agt(Str0, AGT) = Str :- + State0 = string.builder.init, + format_quoted_atom_agt(string.builder.handle, Str0, AGT, State0, State), + Str = string.builder.to_string(State). + +quote_atom_agt(Str, AGT, !IO) :- io.output_stream(Stream, !IO), - term_io.quote_atom_agt(Stream, Str, AdjacentToGraphicToken, !IO). + term_io.write_quoted_atom_agt(Stream, Str, AGT, !IO). -quote_atom_agt(Stream, S, AdjacentToGraphicToken, !State) :- - ShouldQuote = should_atom_be_quoted(S, AdjacentToGraphicToken), +write_quoted_atom_agt(Str, AGT, !IO) :- + io.output_stream(OutStream, !IO), + write_quoted_atom_agt(OutStream, Str, AGT, !IO). + +write_quoted_atom_agt(OutStream, Str, AGT, !IO) :- + format_quoted_atom_agt(OutStream, Str, AGT, !IO). + +quote_atom_agt(Stream, Str, AGT, !State) :- + term_io.format_quoted_atom_agt(Stream, Str, AGT, !State). + +format_quoted_atom_agt(Stream, Str, AGT, !State) :- + ShouldQuote = should_atom_be_quoted(Str, AGT), ( ShouldQuote = no, - stream.put(Stream, S, !State) + stream.put(Stream, Str, !State) ; ShouldQuote = yes, stream.put(Stream, '''', !State), - term_io.write_escaped_string(Stream, S, !State), + term_io.format_escaped_string(Stream, Str, !State), stream.put(Stream, '''', !State) ). -quoted_atom_agt(S, AdjacentToGraphicToken) = String :- - ShouldQuote = should_atom_be_quoted(S, AdjacentToGraphicToken), - ( - ShouldQuote = no, - String = S - ; - ShouldQuote = yes, - 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, AdjacentToGraphicToken) = ShouldQuote :- @@ -1091,14 +1189,20 @@ encode_escaped_char(Char::out, Str::in) :- % EscapeChar that can be used after a backslash in string literals or % atoms to represent Char. % - % Note: the code here is similar to code in compiler/mercury_to_mercury.m; - % any changes here may require similar changes there. - % Likewise for the similar code in library/rtti_implementation.m. + % Note: the code here is similar (but not identical) to + % + % - escape_special_char in compiler/parse_tree_out_pragma.m, and + % - quote_special_escape_char in library/rtti_implementation.m. + % + % Any changes here may require similar changes there. % :- pred mercury_escape_special_char(char, char). :- mode mercury_escape_special_char(in, out) is semidet. :- mode mercury_escape_special_char(out, in) is semidet. +mercury_escape_special_char('\\', '\\'). +mercury_escape_special_char('''', ''''). +mercury_escape_special_char('"', '"'). mercury_escape_special_char('\a', 'a'). mercury_escape_special_char('\b', 'b'). mercury_escape_special_char('\f', 'f'). @@ -1106,9 +1210,6 @@ mercury_escape_special_char('\n', 'n'). mercury_escape_special_char('\r', 'r'). mercury_escape_special_char('\t', 't'). mercury_escape_special_char('\v', 'v'). -mercury_escape_special_char('\\', '\\'). -mercury_escape_special_char('''', ''''). -mercury_escape_special_char('"', '"'). %---------------------------------------------------------------------------% :- end_module term_io. diff --git a/mdbcomp/trace_counts.m b/mdbcomp/trace_counts.m index 20fbb353e..80045b9ad 100644 --- a/mdbcomp/trace_counts.m +++ b/mdbcomp/trace_counts.m @@ -879,7 +879,7 @@ write_proc_label_and_file_trace_counts(OutputStream, ProcLabelInContext, else ModuleName = sym_name_to_string(ModuleNameSym), io.write_string(OutputStream, "module ", !IO), - term_io.quote_atom(OutputStream, ModuleName, !IO), + term_io.format_quoted_atom(OutputStream, ModuleName, !IO), io.write_string(OutputStream, "\n", !IO), !:CurModuleNameSym = ModuleNameSym ), @@ -887,7 +887,7 @@ write_proc_label_and_file_trace_counts(OutputStream, ProcLabelInContext, true else io.write_string(OutputStream, "file ", !IO), - term_io.quote_atom(OutputStream, FileName, !IO), + term_io.format_quoted_atom(OutputStream, FileName, !IO), io.write_string(OutputStream, "\n", !IO), !:CurFileName = FileName ), @@ -920,7 +920,7 @@ write_proc_label(OutputStream, ProcLabel, !IO) :- else DeclModule = sym_name_to_string(DeclModuleSym), io.write_string(OutputStream, "pprocdecl ", !IO), - term_io.quote_atom(OutputStream, DeclModule, !IO), + term_io.format_quoted_atom(OutputStream, DeclModule, !IO), io.write_string(OutputStream, " ", !IO) ) ; @@ -930,11 +930,11 @@ write_proc_label(OutputStream, ProcLabel, !IO) :- else DeclModule = sym_name_to_string(DeclModuleSym), io.write_string(OutputStream, "fprocdecl ", !IO), - term_io.quote_atom(OutputStream, DeclModule, !IO), + term_io.format_quoted_atom(OutputStream, DeclModule, !IO), io.write_string(OutputStream, " ", !IO) ) ), - term_io.quote_atom(OutputStream, Name, !IO), + term_io.format_quoted_atom(OutputStream, Name, !IO), io.format(OutputStream, " %d %d\n", [i(Arity), i(Mode)], !IO) ; % We don't record trace counts in special preds.