Files
mercury/compiler/parse_tree_out_term.m
2025-11-29 23:34:40 +11:00

1053 lines
41 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2015-2017, 2020-2025 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% This module converts terms in the parse tree structure
% back into Mercury source text.
%
%---------------------------------------------------------------------------%
:- module parse_tree.parse_tree_out_term.
:- interface.
:- import_module parse_tree.parse_tree_output.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.var_db.
:- import_module parse_tree.var_table.
:- import_module io.
:- import_module list.
:- import_module string.
:- import_module string.builder.
:- import_module term.
:- import_module varset.
%---------------------------------------------------------------------------%
:- type needs_quotes
---> next_to_graphic_token
% Needs quotes, if it is another graphic token.
; not_next_to_graphic_token.
% Doesn't need quotes.
%---------------------------------------------------------------------------%
% Convert a Mercury variable into a Mercury variable name.
% This is tricky because the compiler may introduce new variables
% that either don't have names at all, or whose names end in
% some sequence of primes (eg. Var''').
%
:- pred mercury_convert_var_name(string::in, string::out) is det.
%---------------------------------------------------------------------------%
% Output a single variable.
% Variables that don't have names in the given varset
% are given the name "V_<n>", where <n> is their variable number.
% Variables whose name originally started with `V_' have their name changed
% to start with `V_V_' to avoid name clashes.
%
:- func mercury_var_to_string(var_table, var_name_print, prog_var) = string.
:- pred mercury_output_var(var_table::in, var_name_print::in, prog_var::in,
io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_var(var_table::in, var_name_print::in, prog_var::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_var_to_string_vs(varset(T), var_name_print, var(T)) = string.
:- pred mercury_output_var_vs(varset(T)::in, var_name_print::in, var(T)::in,
io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_var_vs(varset(T)::in, var_name_print::in, var(T)::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_var_to_string_src(var_name_source, var_name_print, prog_var)
= string.
:- pred mercury_output_var_src(var_name_source::in, var_name_print::in,
prog_var::in, io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_var_src(var_name_source::in, var_name_print::in,
prog_var::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_var_raw_to_string(var_name_print, prog_var, string) = string.
:- pred mercury_format_var_raw(var_name_print::in, var(T)::in, string::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
:- pred mercury_format_var_num_only(var(T)::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
% Output a comma-separated list of variables.
%
:- func mercury_vars_to_string(var_table, var_name_print, list(prog_var))
= string.
:- pred mercury_output_vars(var_table::in, var_name_print::in,
list(prog_var)::in, io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_vars(var_table::in, var_name_print::in,
list(prog_var)::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_vars_to_string_vs(varset(T), var_name_print, list(var(T)))
= string.
:- pred mercury_output_vars_vs(varset(T)::in, var_name_print::in,
list(var(T))::in, io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_vars_vs(varset(T)::in, var_name_print::in,
list(var(T))::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_vars_to_string_src(var_name_source, var_name_print,
list(prog_var)) = string.
:- pred mercury_output_vars_src(var_name_source::in, var_name_print::in,
list(prog_var)::in, io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_vars_src(var_name_source::in, var_name_print::in,
list(prog_var)::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
% Output a variable or a list of variables with print_name_only.
%
:- func mercury_var_to_name_only(var_table, prog_var) = string.
:- func mercury_vars_to_name_only(var_table, list(prog_var)) = string.
:- func mercury_var_to_name_only_vs(varset(T), var(T)) = string.
:- func mercury_vars_to_name_only_vs(varset(T), list(var(T))) = string.
:- func mercury_var_to_name_only_src(var_name_source, prog_var) = string.
:- func mercury_vars_to_name_only_src(var_name_source, list(prog_var))
= string.
%---------------------------------------------------------------------------%
:- func describe_error_term(varset(T), term(T)) = string.
%---------------------------------------------------------------------------%
% Output a term.
%
:- func mercury_term_to_string_vs(varset(T), var_name_print, term(T)) = string.
:- pred mercury_output_term_vs(varset(T)::in, var_name_print::in, term(T)::in,
io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_term_vs(varset(T)::in, var_name_print::in, term(T)::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_term_to_string(var_table, var_name_print, prog_term)
= string.
:- pred mercury_output_term(var_table::in, var_name_print::in,
prog_term::in, io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_term(var_table::in, var_name_print::in,
prog_term::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
:- pred mercury_output_term_src(var_name_source::in, var_name_print::in,
prog_term::in, io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_term_src(var_name_source::in, var_name_print::in,
prog_term::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_term_nq_to_string_vs(varset(T), var_name_print, needs_quotes,
term(T)) = string.
:- pred mercury_output_term_nq_vs(varset(T)::in, var_name_print::in,
needs_quotes::in, term(T)::in, io.text_output_stream::in,
io::di, io::uo) is det.
:- pred mercury_format_term_nq_vs(varset(T)::in, var_name_print::in,
needs_quotes::in, term(T)::in, S::in, U::di, U::uo) is det
<= pt_output(S, U).
:- func mercury_term_nq_to_string(var_table, var_name_print,
needs_quotes, prog_term) = string.
:- pred mercury_output_term_nq(var_table::in, var_name_print::in,
needs_quotes::in, prog_term::in, io.text_output_stream::in,
io::di, io::uo) is det.
:- pred mercury_format_term_nq(var_table::in, var_name_print::in,
needs_quotes::in, prog_term::in, S::in, U::di, U::uo) is det
<= pt_output(S, U).
:- func mercury_term_nq_to_string_src(var_name_source, var_name_print,
needs_quotes, prog_term) = string.
:- pred mercury_format_term_nq_src(var_name_source::in, var_name_print::in,
needs_quotes::in, prog_term::in, S::in, U::di, U::uo) is det
<= pt_output(S, U).
:- pred mercury_format_comma_separated_terms_vs(varset(T)::in,
var_name_print::in, term(T)::in, list(term(T))::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
:- pred mercury_format_comma_separated_terms(var_table::in,
var_name_print::in, prog_term::in, list(prog_term)::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_limited_term_to_string_vs(varset(T), var_name_print, int,
term(T)) = string.
:- pred mercury_output_limited_term_vs(varset(T)::in, var_name_print::in,
int::in, term(T)::in, io.text_output_stream::in, io::di, io::uo) is det.
:- pred mercury_format_limited_term_vs(varset(T)::in, var_name_print::in,
int::in, term(T)::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
:- func mercury_limited_term_nq_to_string_vs(varset(T), var_name_print,
needs_quotes, int, term(T)) = string.
:- pred mercury_output_limited_term_nq_vs(varset(T)::in, var_name_print::in,
needs_quotes::in, int::in, term(T)::in, io.text_output_stream::in,
io::di, io::uo) is det.
:- pred mercury_format_limited_term_nq_vs(varset(T)::in, var_name_print::in,
needs_quotes::in, int::in, term(T)::in, S::in, U::di, U::uo) is det
<= pt_output(S, U).
%---------------------------------------------------------------------------%
:- func mercury_bracketed_atom_to_string(needs_quotes, string) = string.
:- pred mercury_format_bracketed_atom(needs_quotes::in, string::in, S::in,
U::di, U::uo) is det <= pt_output(S, U).
:- pred mercury_format_quoted_atom(needs_quotes::in, string::in, S::in,
U::di, U::uo) is det <= pt_output(S, U).
%---------------------------------------------------------------------------%
:- type graphic_char_in_string
---> no_graphic_chars
; some_graphic_chars
; all_graphic_chars.
:- func string_graphic_chars(string) = graphic_char_in_string.
%---------------------------------------------------------------------------%
% Is this string a Mercury operator?
%
:- pred mercury_op(string::in) is semidet.
%---------------------------------------------------------------------------%
:- pragma type_spec_constrained_preds([pt_output(Stream, State)],
apply_to_superclasses,
[subst([Stream => io.text_output_stream, State = io.state]),
subst([Stream => string.builder.handle, State = string.builder.state])]).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module char.
:- import_module int.
:- import_module mercury_term_lexer.
:- import_module ops.
%---------------------------------------------------------------------------%
mercury_convert_var_name(Name, ConvertedName) :-
% We have to be careful that every possible variable is mapped
% to a distinct name. Variables without names are given names
% starting with `V_' followed by a sequence of digits corresponding to
% their variable id. To ensure that names generated this way don't clash
% with any variables whose names originally started with `V_', we add
% another `V_' prefix to those names.
%
% Compiler's internal name Converted name
% ------------------------ --------------
% none V_[0-9]*
% .*'+ V_.*_[0-9]*
% V_.* V_V_.*
% anything else same as original name
%
( if string.remove_suffix(Name, "'", _) then
strip_trailing_primes(Name, StrippedName, NumPrimes),
ConvertedName = "V_" ++ StrippedName ++ "_" ++
string.int_to_string(NumPrimes)
else if string.prefix(Name, "V_") then
ConvertedName = "V_" ++ Name
else
ConvertedName = Name
).
:- pred strip_trailing_primes(string::in, string::out, int::out) is det.
strip_trailing_primes(Name0, Name, Num) :-
% XXX This implementation is O(N^2), but if N is not very small,
% then something is very wrong.
( if string.remove_suffix(Name0, "'", Name1) then
strip_trailing_primes(Name1, Name, Num0),
Num = Num0 + 1
else
Num = 0,
Name = Name0
).
%---------------------------------------------------------------------------%
mercury_var_to_string(VarTable, VarNamePrint, Var) = Str :-
State0 = string.builder.init,
mercury_format_var(VarTable, VarNamePrint, Var,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_output_var(VarTable, VarNamePrint, Var, Stream, !IO) :-
mercury_format_var(VarTable, VarNamePrint, Var, Stream, !IO).
mercury_format_var(VarTable, VarNamePrint, Var, S, !U) :-
( if var_table.search_var_name(VarTable, Var, Name) then
mercury_format_var_raw(VarNamePrint, Var, Name, S, !U)
else
mercury_format_var_num_only(Var, S, !U)
).
%---------------------%
mercury_var_to_string_vs(VarSet, VarNamePrint, Var) = Str :-
State0 = string.builder.init,
mercury_format_var_vs(VarSet, VarNamePrint, Var,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_output_var_vs(VarSet, VarNamePrint, Var, Stream, !IO) :-
mercury_format_var_vs(VarSet, VarNamePrint, Var, Stream, !IO).
mercury_format_var_vs(VarSet, VarNamePrint, Var, S, !U) :-
( if varset.search_name(VarSet, Var, Name) then
mercury_format_var_raw(VarNamePrint, Var, Name, S, !U)
else
mercury_format_var_num_only(Var, S, !U)
).
%---------------------%
mercury_var_to_string_src(VarNameSrc, VarNamePrint, Var) = Str :-
State0 = string.builder.init,
mercury_format_var_src(VarNameSrc, VarNamePrint, Var,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_output_var_src(VarNameSrc, VarNamePrint, Var, Stream, !IO) :-
mercury_format_var_src(VarNameSrc, VarNamePrint, Var, Stream, !IO).
mercury_format_var_src(VarNameSrc, VarNamePrint, Var, S, !U) :-
( if var_db.search_var_name_in_source(VarNameSrc, Var, Name) then
mercury_format_var_raw(VarNamePrint, Var, Name, S, !U)
else
mercury_format_var_num_only(Var, S, !U)
).
%---------------------%
mercury_var_raw_to_string(VarNamePrint, Var, Name) = Str :-
State0 = string.builder.init,
mercury_format_var_raw(VarNamePrint, Var, Name,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_format_var_raw(VarNamePrint, Var, Name, S, !U) :-
( if Name = "" then
% There is nothing else to print.
mercury_format_var_num_only(Var, S, !U)
else
(
VarNamePrint = print_num_only,
mercury_format_var_num_only(Var, S, !U)
;
VarNamePrint = print_name_only,
mercury_convert_var_name(Name, ConvertedName),
add_string(ConvertedName, S, !U)
;
VarNamePrint = print_name_and_num,
mercury_convert_var_name(Name, ConvertedName),
add_string(ConvertedName, S, !U),
term.var_to_int(Var, VarNum),
add_string("_", S, !U),
add_int(VarNum, S, !U)
)
).
mercury_format_var_num_only(Var, S, !U) :-
term.var_to_int(Var, VarNum),
add_string("V_", S, !U),
add_int(VarNum, S, !U).
%---------------------------------------------------------------------------%
mercury_vars_to_string(VarTable, VarNamePrint, Vars) = Str :-
State0 = string.builder.init,
mercury_format_vars(VarTable, VarNamePrint, Vars,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_output_vars(VarTable, VarNamePrint, Vars, Stream, !IO) :-
mercury_format_vars(VarTable, VarNamePrint, Vars, Stream, !IO).
mercury_format_vars(VarTable, VarNamePrint, Vars, S, !U) :-
add_list(mercury_format_var(VarTable, VarNamePrint), ", ", Vars, S, !U).
%---------------------%
mercury_vars_to_string_vs(VarSet, VarNamePrint, Vars) = Str :-
State0 = string.builder.init,
mercury_format_vars_vs(VarSet, VarNamePrint, Vars,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_output_vars_vs(VarTable, VarNamePrint, Vars, Stream, !IO) :-
mercury_format_vars_vs(VarTable, VarNamePrint, Vars, Stream, !IO).
mercury_format_vars_vs(VarSet, VarNamePrint, Vars, S, !U) :-
add_list(mercury_format_var_vs(VarSet, VarNamePrint), ", ", Vars, S, !U).
%---------------------%
mercury_vars_to_string_src(VarNameSrc, VarNamePrint, Vars) = Str :-
State0 = string.builder.init,
mercury_format_vars_src(VarNameSrc, VarNamePrint, Vars,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_output_vars_src(VarNameSrc, VarNamePrint, Vars, Stream, !IO) :-
mercury_format_vars_src(VarNameSrc, VarNamePrint, Vars, Stream, !IO).
mercury_format_vars_src(VarNameSrc, VarNamePrint, Vars, S, !U) :-
add_list(mercury_format_var_src(VarNameSrc, VarNamePrint), ", ", Vars,
S, !U).
%---------------------------------------------------------------------------%
mercury_var_to_name_only(VarTable, Var) =
mercury_var_to_string(VarTable, print_name_only, Var).
mercury_vars_to_name_only(VarTable, Vars) =
mercury_vars_to_string(VarTable, print_name_only, Vars).
%---------------------%
mercury_var_to_name_only_vs(VarSet, Var) =
mercury_var_to_string_vs(VarSet, print_name_only, Var).
mercury_vars_to_name_only_vs(VarSet, Vars) =
mercury_vars_to_string_vs(VarSet, print_name_only, Vars).
%---------------------%
mercury_var_to_name_only_src(VarNameSrc, Var) =
mercury_var_to_string_src(VarNameSrc, print_name_only, Var).
mercury_vars_to_name_only_src(VarNameSrc, Vars) =
mercury_vars_to_string_src(VarNameSrc, print_name_only, Vars).
%---------------------------------------------------------------------------%
describe_error_term(VarSet, Term) =
% We should consider using the algorithms of term_io.write_term instead of
% the ones now in mercury_limited_term_to_string to print terms; it adds
% fewer redundant parentheses.
mercury_limited_term_to_string_vs(VarSet, print_name_only,
max_term_string_size_in_syntax_error, Term).
% The maximum size of the string representation of a term to print
% at syntax errors.
%
:- func max_term_string_size_in_syntax_error = int.
max_term_string_size_in_syntax_error = 80.
%---------------------------------------------------------------------------%
mercury_term_to_string_vs(VarSet, VarNamePrint, Term) =
mercury_term_nq_to_string_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, Term).
mercury_output_term_vs(VarSet, VarNamePrint, Term, Stream, !IO) :-
mercury_output_term_nq_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, Term, Stream, !IO).
mercury_format_term_vs(VarSet, VarNamePrint, Term, S, !U) :-
mercury_format_term_nq_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, Term, S, !U).
%---------------------%
mercury_term_to_string(VarTable, VarNamePrint, Term) =
mercury_term_nq_to_string(VarTable, VarNamePrint,
not_next_to_graphic_token, Term).
mercury_output_term(VarTable, VarNamePrint, Term, Stream, !IO) :-
mercury_output_term_nq(VarTable, VarNamePrint,
not_next_to_graphic_token, Term, Stream, !IO).
mercury_format_term(VarTable, VarNamePrint, Term, S, !U) :-
mercury_format_term_nq(VarTable, VarNamePrint,
not_next_to_graphic_token, Term, S, !U).
%---------------------%
mercury_output_term_src(VarNameSrc, VarNamePrint, Term, Stream, !IO) :-
mercury_format_term_src(VarNameSrc, VarNamePrint, Term, Stream, !IO).
mercury_format_term_src(VarNameSrc, VarNamePrint, Term, S, !U) :-
(
VarNameSrc = vns_varset(VarSet),
mercury_format_term_nq_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, Term, S, !U)
;
VarNameSrc = vns_var_table(VarTable),
mercury_format_term_nq(VarTable, VarNamePrint,
not_next_to_graphic_token, Term, S, !U)
).
%---------------------%
mercury_term_nq_to_string_vs(VarSet, VarNamePrint, NextToGraphicToken, Term)
= Str :-
State0 = string.builder.init,
mercury_format_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken, Term,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_output_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken, Term,
Stream, !IO) :-
mercury_format_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken, Term,
Stream, !IO).
mercury_format_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken, Term,
S, !U) :-
% Please keep in sync with mercury_format_term_nq.
(
Term = term.variable(Var, _),
mercury_format_var_vs(VarSet, VarNamePrint, Var, S, !U)
;
Term = term.functor(Functor, Args, _),
( if
Functor = term.atom(""),
Args = [F, X | Xs]
then
mercury_format_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken,
F, S, !U),
add_string("(", S, !U),
mercury_format_comma_separated_terms_vs(VarSet, VarNamePrint,
X, Xs, S, !U),
add_string(")", S, !U)
else if
Functor = term.atom("[|]"),
Args = [X, Xs]
then
add_string("[", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, X, S, !U),
mercury_format_list_args_vs(VarSet, VarNamePrint, Xs, S, !U),
add_string("]", S, !U)
else if
Functor = term.atom("{}"),
Args = [X | Xs]
then
(
Xs = [],
% A unary tuple is usually a DCG escape,
% so add some extra space.
add_string("{ ", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, X, S, !U),
add_string(" }", S, !U)
;
Xs = [_ | _],
add_string("{", S, !U),
mercury_format_comma_separated_terms_vs(VarSet, VarNamePrint,
X, Xs, S, !U),
add_string("}", S, !U)
)
else if
Functor = term.atom(FunctorName),
mercury_op_table_search_op_infos(FunctorName, OpInfos)
then
(
( Args = []
; Args = [_, _, _ | _]
),
mercury_format_plain_functor_args_nq_vs(VarSet,
VarNamePrint, NextToGraphicToken, Functor, Args, S, !U)
;
Args = [ArgA],
( if OpInfos ^ oi_prefix = pre(_, _) then
add_string("(", S, !U),
add_string(FunctorName, S, !U),
add_string(" ", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, ArgA, S, !U),
add_string(")", S, !U)
else if OpInfos ^ oi_postfix = post(_, _) then
add_string("(", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, ArgA, S, !U),
add_string(" ", S, !U),
add_string(FunctorName, S, !U),
add_string(")", S, !U)
else
mercury_format_plain_functor_args_nq_vs(VarSet,
VarNamePrint, NextToGraphicToken, Functor, Args, S, !U)
)
;
Args = [ArgA, ArgB],
( if OpInfos ^ oi_binary_prefix = bin_pre(_, _, _) then
add_string("(", S, !U),
add_string(FunctorName, S, !U),
add_string(" ", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, ArgA, S, !U),
add_string(" ", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, ArgB, S, !U),
add_string(")", S, !U)
else if OpInfos ^ oi_infix = in(_, _, _) then
( if FunctorName = "." then
mercury_format_term_nq_vs(VarSet, VarNamePrint,
next_to_graphic_token, ArgA, S, !U),
add_string(".", S, !U),
mercury_format_term_nq_vs(VarSet, VarNamePrint,
next_to_graphic_token, ArgB, S, !U)
else
add_string("(", S, !U),
mercury_format_term_nq_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, ArgA, S, !U),
add_string(" ", S, !U),
add_string(FunctorName, S, !U),
add_string(" ", S, !U),
mercury_format_term_nq_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, ArgB, S, !U),
add_string(")", S, !U)
)
else
mercury_format_plain_functor_args_nq_vs(VarSet,
VarNamePrint, NextToGraphicToken, Functor, Args, S, !U)
)
)
else
mercury_format_plain_functor_args_nq_vs(VarSet, VarNamePrint,
NextToGraphicToken, Functor, Args, S, !U)
)
).
:- pred mercury_format_plain_functor_args_nq_vs(varset(T)::in,
var_name_print::in, needs_quotes::in, const::in, list(term(T))::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
mercury_format_plain_functor_args_nq_vs(VarSet, VarNamePrint,
NextToGraphicToken, Functor, Args, S, !U) :-
(
Args = [],
mercury_format_bracketed_constant_ngt(NextToGraphicToken,
Functor, S, !U)
;
Args = [HeadArg | TailArgs],
mercury_format_constant(NextToGraphicToken, Functor, S, !U),
add_string("(", S, !U),
mercury_format_comma_separated_terms_vs(VarSet, VarNamePrint,
HeadArg, TailArgs, S, !U),
add_string(")", S, !U)
).
%---------------------%
mercury_term_nq_to_string(VarTable, VarNamePrint, NextToGraphicToken,
Term) = Str :-
State0 = string.builder.init,
mercury_format_term_nq(VarTable, VarNamePrint, NextToGraphicToken, Term,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_output_term_nq(VarTable, VarNamePrint, NextToGraphicToken,
Term, Stream, !IO) :-
mercury_format_term_nq(VarTable, VarNamePrint, NextToGraphicToken,
Term, Stream, !IO).
mercury_format_term_nq(VarTable, VarNamePrint, NextToGraphicToken, Term,
S, !U) :-
% Please keep in sync with mercury_format_term_nq_vs.
(
Term = term.variable(Var, _),
mercury_format_var(VarTable, VarNamePrint, Var, S, !U)
;
Term = term.functor(Functor, Args, _),
( if
Functor = term.atom(""),
Args = [F, X | Xs]
then
mercury_format_term_nq(VarTable, VarNamePrint, NextToGraphicToken,
F, S, !U),
add_string("(", S, !U),
mercury_format_comma_separated_terms(VarTable, VarNamePrint,
X, Xs, S, !U),
add_string(")", S, !U)
else if
Functor = term.atom("[|]"),
Args = [X, Xs]
then
add_string("[", S, !U),
mercury_format_term(VarTable, VarNamePrint, X, S, !U),
mercury_format_list_args(VarTable, VarNamePrint, Xs, S, !U),
add_string("]", S, !U)
else if
Functor = term.atom("{}"),
Args = [X | Xs]
then
(
Xs = [],
% A unary tuple is usually a DCG escape,
% so add some extra space.
add_string("{ ", S, !U),
mercury_format_term(VarTable, VarNamePrint, X, S, !U),
add_string(" }", S, !U)
;
Xs = [_ | _],
add_string("{", S, !U),
mercury_format_comma_separated_terms(VarTable, VarNamePrint,
X, Xs, S, !U),
add_string("}", S, !U)
)
else if
Functor = term.atom(FunctorName),
mercury_op_table_search_op_infos(FunctorName, OpInfos)
then
(
( Args = []
; Args = [_, _, _ | _]
),
mercury_format_plain_functor_args_nq(VarTable,
VarNamePrint, NextToGraphicToken, Functor, Args, S, !U)
;
Args = [ArgA],
( if OpInfos ^ oi_prefix = pre(_, _) then
add_string("(", S, !U),
add_string(FunctorName, S, !U),
add_string(" ", S, !U),
mercury_format_term(VarTable, VarNamePrint, ArgA, S, !U),
add_string(")", S, !U)
else if OpInfos ^ oi_postfix = post(_, _) then
add_string("(", S, !U),
mercury_format_term(VarTable, VarNamePrint, ArgA, S, !U),
add_string(" ", S, !U),
add_string(FunctorName, S, !U),
add_string(")", S, !U)
else
mercury_format_plain_functor_args_nq(VarTable,
VarNamePrint, NextToGraphicToken, Functor, Args, S, !U)
)
;
Args = [ArgA, ArgB],
( if OpInfos ^ oi_binary_prefix = bin_pre(_, _, _) then
add_string("(", S, !U),
add_string(FunctorName, S, !U),
add_string(" ", S, !U),
mercury_format_term(VarTable, VarNamePrint, ArgA, S, !U),
add_string(" ", S, !U),
mercury_format_term(VarTable, VarNamePrint, ArgB, S, !U),
add_string(")", S, !U)
else if OpInfos ^ oi_infix = in(_, _, _) then
( if FunctorName = "." then
mercury_format_term_nq(VarTable, VarNamePrint,
next_to_graphic_token, ArgA, S, !U),
add_string(".", S, !U),
mercury_format_term_nq(VarTable, VarNamePrint,
next_to_graphic_token, ArgB, S, !U)
else
add_string("(", S, !U),
mercury_format_term_nq(VarTable, VarNamePrint,
not_next_to_graphic_token, ArgA, S, !U),
add_string(" ", S, !U),
add_string(FunctorName, S, !U),
add_string(" ", S, !U),
mercury_format_term_nq(VarTable, VarNamePrint,
not_next_to_graphic_token, ArgB, S, !U),
add_string(")", S, !U)
)
else
mercury_format_plain_functor_args_nq(VarTable,
VarNamePrint, NextToGraphicToken, Functor, Args, S, !U)
)
)
else
mercury_format_plain_functor_args_nq(VarTable, VarNamePrint,
NextToGraphicToken, Functor, Args, S, !U)
)
).
:- pred mercury_format_plain_functor_args_nq(var_table::in,
var_name_print::in, needs_quotes::in, const::in, list(prog_term)::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
mercury_format_plain_functor_args_nq(VarTable, VarNamePrint,
NextToGraphicToken, Functor, Args, S, !U) :-
(
Args = [],
mercury_format_bracketed_constant_ngt(NextToGraphicToken,
Functor, S, !U)
;
Args = [HeadArg | TailArgs],
mercury_format_constant(NextToGraphicToken, Functor, S, !U),
add_string("(", S, !U),
mercury_format_comma_separated_terms(VarTable, VarNamePrint,
HeadArg, TailArgs, S, !U),
add_string(")", S, !U)
).
%---------------------%
:- pred mercury_format_list_args_vs(varset(T)::in, var_name_print::in,
term(T)::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
mercury_format_list_args_vs(VarSet, VarNamePrint, Term, S, !U) :-
% Please keep in sync with mercury_format_list_args_src.
( if
Term = term.functor(term.atom("[|]"), Args, _),
Args = [X, Xs]
then
add_string(", ", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, X, S, !U),
mercury_format_list_args_vs(VarSet, VarNamePrint, Xs, S, !U)
else if
Term = term.functor(term.atom("[]"), [], _)
then
true
else
add_string(" | ", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, Term, S, !U)
).
:- pred mercury_format_list_args(var_table::in, var_name_print::in,
prog_term::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
mercury_format_list_args(VarTable, VarNamePrint, Term, S, !U) :-
% Please keep in sync with mercury_format_list_args.
( if
Term = term.functor(term.atom("[|]"), Args, _),
Args = [X, Xs]
then
add_string(", ", S, !U),
mercury_format_term(VarTable, VarNamePrint, X, S, !U),
mercury_format_list_args(VarTable, VarNamePrint, Xs, S, !U)
else if
Term = term.functor(term.atom("[]"), [], _)
then
true
else
add_string(" | ", S, !U),
mercury_format_term(VarTable, VarNamePrint, Term, S, !U)
).
%---------------------%
mercury_term_nq_to_string_src(VarNameSrc, VarNamePrint, NextToGraphicToken,
Term) = Str :-
(
VarNameSrc = vns_varset(VarSet),
Str = mercury_term_nq_to_string_vs(VarSet, VarNamePrint,
NextToGraphicToken, Term)
;
VarNameSrc = vns_var_table(VarTable),
Str = mercury_term_nq_to_string(VarTable, VarNamePrint,
NextToGraphicToken, Term)
).
mercury_format_term_nq_src(VarNameSrc, VarNamePrint, NextToGraphicToken,
Term, S, !U) :-
(
VarNameSrc = vns_varset(VarSet),
mercury_format_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken,
Term, S, !U)
;
VarNameSrc = vns_var_table(VarTable),
mercury_format_term_nq(VarTable, VarNamePrint, NextToGraphicToken,
Term, S, !U)
).
%---------------------------------------------------------------------------%
mercury_format_comma_separated_terms_vs(VarSet, VarNamePrint,
HeadTerm, TailTerms, S, !U) :-
mercury_format_term_vs(VarSet, VarNamePrint, HeadTerm, S, !U),
mercury_format_remaining_terms_vs(VarSet, VarNamePrint, TailTerms, S, !U).
mercury_format_comma_separated_terms(VarTable, VarNamePrint,
HeadTerm, TailTerms, S, !U) :-
mercury_format_term(VarTable, VarNamePrint, HeadTerm, S, !U),
mercury_format_remaining_terms(VarTable, VarNamePrint, TailTerms, S, !U).
:- pred mercury_format_remaining_terms_vs(varset(T)::in, var_name_print::in,
list(term(T))::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
mercury_format_remaining_terms_vs(_VarSet, _VarNamePrint, [], _S, !U).
mercury_format_remaining_terms_vs(VarSet, VarNamePrint, [Term | Terms],
S, !U) :-
add_string(", ", S, !U),
mercury_format_term_vs(VarSet, VarNamePrint, Term, S, !U),
mercury_format_remaining_terms_vs(VarSet, VarNamePrint, Terms, S, !U).
:- pred mercury_format_remaining_terms(var_table::in, var_name_print::in,
list(prog_term)::in, S::in, U::di, U::uo) is det <= pt_output(S, U).
mercury_format_remaining_terms(_VarTable, _VarNamePrint, [], _S, !U).
mercury_format_remaining_terms(VarTable, VarNamePrint, [Term | Terms],
S, !U) :-
add_string(", ", S, !U),
mercury_format_term(VarTable, VarNamePrint, Term, S, !U),
mercury_format_remaining_terms(VarTable, VarNamePrint, Terms, S, !U).
%---------------------------------------------------------------------------%
:- pred mercury_format_bracketed_constant_ngt(needs_quotes::in, const::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
mercury_format_bracketed_constant_ngt(NextToGraphicToken, Const, S, !U) :-
( if
Const = term.atom(Op),
mercury_op(Op)
then
add_string("(", S, !U),
add_quoted_atom(Op, S, !U),
add_string(")", S, !U)
else
mercury_format_constant(NextToGraphicToken, Const, S, !U)
).
:- pred mercury_format_constant(needs_quotes::in, const::in,
S::in, U::di, U::uo) is det <= pt_output(S, U).
mercury_format_constant(NextToGraphicToken, Const, S, !U) :-
( if Const = term.atom(Atom) then
mercury_format_quoted_atom(NextToGraphicToken, Atom, S, !U)
else
add_constant(Const, S, !U)
).
%---------------------%
mercury_limited_term_to_string_vs(VarSet, VarNamePrint, Limit, Term) =
mercury_limited_term_nq_to_string_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, Limit, Term).
mercury_output_limited_term_vs(VarSet, VarNamePrint, Limit, Term,
Stream, !IO) :-
mercury_output_limited_term_nq_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, Limit, Term, Stream, !IO).
mercury_format_limited_term_vs(VarSet, VarNamePrint, Limit, Term, S, !U) :-
mercury_format_limited_term_nq_vs(VarSet, VarNamePrint,
not_next_to_graphic_token, Limit, Term, S, !U).
%---------------------%
mercury_limited_term_nq_to_string_vs(VarSet, VarNamePrint, NextToGraphicToken,
Limit, Term) = Str :-
% Note that we *could* implement mercury_limited_term_nq_to_string_vs
% in terms of mercury_format_limited_term_nq_vs, but the approach here
% is simpler, because it makes explicit the "try one way, and if that
% gives too long a string, try another way" approach.
FullState0 = string.builder.init,
mercury_format_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken, Term,
string.builder.handle, FullState0, FullState),
( if total_num_code_points_is_at_most(FullState, Limit) then
Str = string.builder.to_string(FullState)
else
(
Term = term.variable(_, _),
% We cannot reduce the length of the string.
Str = string.builder.to_string(FullState)
;
Term = term.functor(Functor, Args, Context),
NoArgTerm = term.functor(Functor, [], Context),
FunctorState0 = string.builder.init,
mercury_format_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken,
NoArgTerm, string.builder.handle, FunctorState0, FunctorState),
FunctorStr = string.builder.to_string(FunctorState),
(
Functor = term.atom(_),
ArityStr = int_to_string(list.length(Args)),
Str = FunctorStr ++ "/" ++ ArityStr
;
( Functor = term.integer(_, _, _, _)
; Functor = term.float(_)
; Functor = term.string(_)
; Functor = term.implementation_defined(_)
),
Str = FunctorStr
)
)
).
mercury_output_limited_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken,
Limit, Term, Stream, !IO) :-
Str = mercury_limited_term_nq_to_string_vs(VarSet, VarNamePrint,
NextToGraphicToken, Limit, Term),
io.write_string(Stream, Str, !IO).
mercury_format_limited_term_nq_vs(VarSet, VarNamePrint, NextToGraphicToken,
Limit, Term, S, !U) :-
Str = mercury_limited_term_nq_to_string_vs(VarSet, VarNamePrint,
NextToGraphicToken, Limit, Term),
add_string(Str, S, !U).
%---------------------%
mercury_bracketed_atom_to_string(NextToGraphicToken, Name) = Str :-
State0 = string.builder.init,
mercury_format_bracketed_atom(NextToGraphicToken, Name,
string.builder.handle, State0, State),
Str = string.builder.to_string(State).
mercury_format_bracketed_atom(NextToGraphicToken, Name, S, !U) :-
( if mercury_op(Name) then
add_string("(", S, !U),
add_quoted_atom(Name, S, !U),
add_string(")", S, !U)
else
mercury_format_quoted_atom(NextToGraphicToken, Name, S, !U)
).
%---------------------------------------------------------------------------%
mercury_format_quoted_atom(NextToGraphicToken, Name, S, !U) :-
% If the symname is composed of only graphic token chars, then
% term_io.quote_atom will not quote it; but if it is next to another
% graphic token, it needs to be quoted, otherwise the two would be
% considered part of one symbol name (e.g. In "int:<", the ":<" parses
% as one token, so when writing out the "<" after the ":" we need
% to quote it.
( if
NextToGraphicToken = next_to_graphic_token,
string.all_match(mercury_term_lexer.graphic_token_char, Name)
then
add_string("'", S, !U),
add_escaped_string(Name, S, !U),
add_string("'", S, !U)
else
add_quoted_atom(Name, S, !U)
).
%---------------------------------------------------------------------------%
:- type graphic_char
---> not_seen_graphic_char
; seen_graphic_char.
:- type non_graphic_char
---> not_seen_non_graphic_char
; seen_non_graphic_char.
string_graphic_chars(Str) = Result :-
string.foldl2(string_graphic_chars_acc, Str,
not_seen_graphic_char, Graphic, not_seen_non_graphic_char, NonGraphic),
(
Graphic = not_seen_graphic_char,
Result = no_graphic_chars
;
Graphic = seen_graphic_char,
(
NonGraphic = not_seen_non_graphic_char,
Result = all_graphic_chars
;
NonGraphic = seen_non_graphic_char,
Result = some_graphic_chars
)
).
:- pred string_graphic_chars_acc(char::in,
graphic_char::in, graphic_char::out,
non_graphic_char::in, non_graphic_char::out) is det.
string_graphic_chars_acc(Char, !Graphic, !NonGraphic) :-
( if mercury_term_lexer.graphic_token_char(Char) then
!:Graphic = seen_graphic_char
else
!:NonGraphic = seen_non_graphic_char
).
%---------------------------------------------------------------------------%
%
% Predicates to test whether a functor is a Mercury operator.
%
mercury_op(Op) :-
ops.mercury_op_table_is_op(Op).
%---------------------------------------------------------------------------%
:- end_module parse_tree.parse_tree_out_term.
%---------------------------------------------------------------------------%