%---------------------------------------------------------------------------% % 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_", where 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. %---------------------------------------------------------------------------%