View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  1997-2021, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI, Amsterdam
    9                              SWI-Prolog Solutions b.v.
   10    All rights reserved.
   11
   12    Redistribution and use in source and binary forms, with or without
   13    modification, are permitted provided that the following conditions
   14    are met:
   15
   16    1. Redistributions of source code must retain the above copyright
   17       notice, this list of conditions and the following disclaimer.
   18
   19    2. Redistributions in binary form must reproduce the above copyright
   20       notice, this list of conditions and the following disclaimer in
   21       the documentation and/or other materials provided with the
   22       distribution.
   23
   24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   25    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   26    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   27    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   28    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   29    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   30    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   31    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   32    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   34    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35    POSSIBILITY OF SUCH DAMAGE.
   36*/
   37
   38:- module('$messages',
   39          [ print_message/2,            % +Kind, +Term
   40            print_message_lines/3,      % +Stream, +Prefix, +Lines
   41            message_to_string/2         % +Term, -String
   42          ]).   43
   44:- multifile
   45    prolog:message//1,              % entire message
   46    prolog:error_message//1,        % 1-st argument of error term
   47    prolog:message_context//1,      % Context of error messages
   48    prolog:deprecated//1,	    % Deprecated features
   49    prolog:message_location//1,     % (File) location of error messages
   50    prolog:message_line_element/2.  % Extend printing
   51:- '$hide'((
   52    prolog:message//1,
   53    prolog:error_message//1,
   54    prolog:message_context//1,
   55    prolog:deprecated//1,
   56    prolog:message_location//1,
   57    prolog:message_line_element/2)).   58
   59:- discontiguous
   60    prolog_message/3.   61
   62:- public
   63    translate_message//1.   64
   65:- create_prolog_flag(message_context, [thread], []).
 translate_message(+Term)// is det
Translate a message Term into message lines. The produced lines is a list of
nl
Emit a newline
Fmt - Args
Emit the result of format(Fmt, Args)
Fmt
Emit the result of format(Fmt)
flush
Used only as last element of the list. Simply flush the output instead of producing a final newline.
at_same_line
Start the messages at the same line (instead of using ~N)
   84translate_message(Term) -->
   85    translate_message2(Term),
   86    !.
   87translate_message(Term) -->
   88    { Term = error(_, _) },
   89    [ 'Unknown exception: ~p'-[Term] ].
   90translate_message(Term) -->
   91    [ 'Unknown message: ~p'-[Term] ].
   92
   93translate_message2(Term) -->
   94    {var(Term)},
   95    !,
   96    [ 'Unknown message: ~p'-[Term] ].
   97translate_message2(Term) -->
   98    prolog:message(Term).
   99translate_message2(Term) -->
  100    prolog_message(Term).
  101translate_message2(error(resource_error(stack), Context)) -->
  102    !,
  103    out_of_stack(Context).
  104translate_message2(error(resource_error(tripwire(Wire, Context)), _)) -->
  105    !,
  106    tripwire_message(Wire, Context).
  107translate_message2(error(existence_error(reset, Ball), SWI)) -->
  108    swi_location(SWI),
  109    tabling_existence_error(Ball, SWI).
  110translate_message2(error(ISO, SWI)) -->
  111    swi_location(SWI),
  112    term_message(ISO),
  113    swi_extra(SWI).
  114translate_message2('$aborted') -->
  115    [ 'Execution Aborted' ].
  116translate_message2(message_lines(Lines), L, T) :- % deal with old C-warning()
  117    make_message_lines(Lines, L, T).
  118translate_message2(format(Fmt, Args)) -->
  119    [ Fmt-Args ].
  120
  121make_message_lines([], T, T) :- !.
  122make_message_lines([Last],  ['~w'-[Last]|T], T) :- !.
  123make_message_lines([L0|LT], ['~w'-[L0],nl|T0], T) :-
  124    make_message_lines(LT, T0, T).
  125
  126term_message(Term) -->
  127    {var(Term)},
  128    !,
  129    [ 'Unknown error term: ~p'-[Term] ].
  130term_message(Term) -->
  131    prolog:error_message(Term).
  132term_message(Term) -->
  133    iso_message(Term).
  134term_message(Term) -->
  135    swi_message(Term).
  136term_message(Term) -->
  137    [ 'Unknown error term: ~p'-[Term] ].
  138
  139iso_message(resource_error(Missing)) -->
  140    [ 'Not enough resources: ~w'-[Missing] ].
  141iso_message(type_error(evaluable, Actual)) -->
  142    { callable(Actual) },
  143    [ 'Arithmetic: `~p'' is not a function'-[Actual] ].
  144iso_message(type_error(free_of_attvar, Actual)) -->
  145    [ 'Type error: `~W'' contains attributed variables'-
  146      [Actual,[portray(true), attributes(portray)]] ].
  147iso_message(type_error(Expected, Actual)) -->
  148    [ 'Type error: `~w'' expected, found `~p'''-[Expected, Actual] ],
  149    type_error_comment(Expected, Actual).
  150iso_message(domain_error(Domain, Actual)) -->
  151    [ 'Domain error: '-[] ], domain(Domain),
  152    [ ' expected, found `~p'''-[Actual] ].
  153iso_message(instantiation_error) -->
  154    [ 'Arguments are not sufficiently instantiated' ].
  155iso_message(uninstantiation_error(Var)) -->
  156    [ 'Uninstantiated argument expected, found ~p'-[Var] ].
  157iso_message(representation_error(What)) -->
  158    [ 'Cannot represent due to `~w'''-[What] ].
  159iso_message(permission_error(Action, Type, Object)) -->
  160    permission_error(Action, Type, Object).
  161iso_message(evaluation_error(Which)) -->
  162    [ 'Arithmetic: evaluation error: `~p'''-[Which] ].
  163iso_message(existence_error(procedure, Proc)) -->
  164    [ 'Unknown procedure: ~q'-[Proc] ],
  165    unknown_proc_msg(Proc).
  166iso_message(existence_error(answer_variable, Var)) -->
  167    [ '$~w was not bound by a previous query'-[Var] ].
  168iso_message(existence_error(matching_rule, Goal)) -->
  169    [ 'No rule matches ~p'-[Goal] ].
  170iso_message(existence_error(Type, Object)) -->
  171    [ '~w `~p'' does not exist'-[Type, Object] ].
  172iso_message(existence_error(Type, Object, In)) --> % not ISO
  173    [ '~w `~p'' does not exist in ~p'-[Type, Object, In] ].
  174iso_message(busy(Type, Object)) -->
  175    [ '~w `~p'' is busy'-[Type, Object] ].
  176iso_message(syntax_error(swi_backslash_newline)) -->
  177    [ 'Deprecated ... \\<newline><white>*.  Use \\c' ].
  178iso_message(syntax_error(Id)) -->
  179    [ 'Syntax error: ' ],
  180    syntax_error(Id).
  181iso_message(occurs_check(Var, In)) -->
  182    [ 'Cannot unify ~p with ~p: would create an infinite tree'-[Var, In] ].
 permission_error(Action, Type, Object)//
Translate permission errors. Most follow te pattern "No permission to Action Type Object", but some are a bit different.
  189permission_error(Action, built_in_procedure, Pred) -->
  190    { user_predicate_indicator(Pred, PI)
  191    },
  192    [ 'No permission to ~w built-in predicate `~p'''-[Action, PI] ],
  193    (   {Action \== export}
  194    ->  [ nl,
  195          'Use :- redefine_system_predicate(+Head) if redefinition is intended'
  196        ]
  197    ;   []
  198    ).
  199permission_error(import_into(Dest), procedure, Pred) -->
  200    [ 'No permission to import ~p into ~w'-[Pred, Dest] ].
  201permission_error(Action, static_procedure, Proc) -->
  202    [ 'No permission to ~w static procedure `~p'''-[Action, Proc] ],
  203    defined_definition('Defined', Proc).
  204permission_error(input, stream, Stream) -->
  205    [ 'No permission to read from output stream `~p'''-[Stream] ].
  206permission_error(output, stream, Stream) -->
  207    [ 'No permission to write to input stream `~p'''-[Stream] ].
  208permission_error(input, text_stream, Stream) -->
  209    [ 'No permission to read bytes from TEXT stream `~p'''-[Stream] ].
  210permission_error(output, text_stream, Stream) -->
  211    [ 'No permission to write bytes to TEXT stream `~p'''-[Stream] ].
  212permission_error(input, binary_stream, Stream) -->
  213    [ 'No permission to read characters from binary stream `~p'''-[Stream] ].
  214permission_error(output, binary_stream, Stream) -->
  215    [ 'No permission to write characters to binary stream `~p'''-[Stream] ].
  216permission_error(open, source_sink, alias(Alias)) -->
  217    [ 'No permission to reuse alias "~p": already taken'-[Alias] ].
  218permission_error(tnot, non_tabled_procedure, Pred) -->
  219    [ 'The argument of tnot/1 is not tabled: ~p'-[Pred] ].
  220permission_error(Action, Type, Object) -->
  221    [ 'No permission to ~w ~w `~p'''-[Action, Type, Object] ].
  222
  223
  224unknown_proc_msg(_:(^)/2) -->
  225    !,
  226    unknown_proc_msg((^)/2).
  227unknown_proc_msg((^)/2) -->
  228    !,
  229    [nl, '  ^/2 can only appear as the 2nd argument of setof/3 and bagof/3'].
  230unknown_proc_msg((:-)/2) -->
  231    !,
  232    [nl, '  Rules must be loaded from a file'],
  233    faq('ToplevelMode').
  234unknown_proc_msg((=>)/2) -->
  235    !,
  236    [nl, '  Rules must be loaded from a file'],
  237    faq('ToplevelMode').
  238unknown_proc_msg((:-)/1) -->
  239    !,
  240    [nl, '  Directives must be loaded from a file'],
  241    faq('ToplevelMode').
  242unknown_proc_msg((?-)/1) -->
  243    !,
  244    [nl, '  ?- is the Prolog prompt'],
  245    faq('ToplevelMode').
  246unknown_proc_msg(Proc) -->
  247    { dwim_predicates(Proc, Dwims) },
  248    (   {Dwims \== []}
  249    ->  [nl, '  However, there are definitions for:', nl],
  250        dwim_message(Dwims)
  251    ;   []
  252    ).
  253
  254dependency_error(shared(Shared), private(Private)) -->
  255    [ 'Shared table for ~p may not depend on private ~p'-[Shared, Private] ].
  256dependency_error(Dep, monotonic(On)) -->
  257    { '$pi_head'(PI, Dep),
  258      '$pi_head'(MPI, On)
  259    },
  260    [ 'Dependent ~p on monotonic predicate ~p is not monotonic or incremental'-
  261      [PI, MPI]
  262    ].
  263
  264faq(Page) -->
  265    [nl, '  See FAQ at https://www.swi-prolog.org/FAQ/', Page, '.txt' ].
  266
  267type_error_comment(_Expected, Actual) -->
  268    { type_of(Actual, Type),
  269      (   sub_atom(Type, 0, 1, _, First),
  270          memberchk(First, [a,e,i,o,u])
  271      ->  Article = an
  272      ;   Article = a
  273      )
  274    },
  275    [ ' (~w ~w)'-[Article, Type] ].
  276
  277type_of(Term, Type) :-
  278    (   attvar(Term)      -> Type = attvar
  279    ;   var(Term)         -> Type = var
  280    ;   atom(Term)        -> Type = atom
  281    ;   integer(Term)     -> Type = integer
  282    ;   string(Term)      -> Type = string
  283    ;   Term == []        -> Type = empty_list
  284    ;   blob(Term, BlobT) -> blob_type(BlobT, Type)
  285    ;   rational(Term)    -> Type = rational
  286    ;   float(Term)       -> Type = float
  287    ;   is_stream(Term)   -> Type = stream
  288    ;   is_dict(Term)     -> Type = dict
  289    ;   is_list(Term)     -> Type = list
  290    ;   cyclic_term(Term) -> Type = cyclic
  291    ;   compound(Term)    -> Type = compound
  292    ;                        Type = unknown
  293    ).
  294
  295blob_type(BlobT, Type) :-
  296    atom_concat(BlobT, '_reference', Type).
  297
  298syntax_error(end_of_clause) -->
  299    [ 'Unexpected end of clause' ].
  300syntax_error(end_of_clause_expected) -->
  301    [ 'End of clause expected' ].
  302syntax_error(end_of_file) -->
  303    [ 'Unexpected end of file' ].
  304syntax_error(end_of_file_in_block_comment) -->
  305    [ 'End of file in /* ... */ comment' ].
  306syntax_error(end_of_file_in_quoted(Quote)) -->
  307    [ 'End of file in quoted ' ],
  308    quoted_type(Quote).
  309syntax_error(illegal_number) -->
  310    [ 'Illegal number' ].
  311syntax_error(long_atom) -->
  312    [ 'Atom too long (see style_check/1)' ].
  313syntax_error(long_string) -->
  314    [ 'String too long (see style_check/1)' ].
  315syntax_error(operator_clash) -->
  316    [ 'Operator priority clash' ].
  317syntax_error(operator_expected) -->
  318    [ 'Operator expected' ].
  319syntax_error(operator_balance) -->
  320    [ 'Unbalanced operator' ].
  321syntax_error(quoted_punctuation) -->
  322    [ 'Operand expected, unquoted comma or bar found' ].
  323syntax_error(list_rest) -->
  324    [ 'Unexpected comma or bar in rest of list' ].
  325syntax_error(cannot_start_term) -->
  326    [ 'Illegal start of term' ].
  327syntax_error(punct(Punct, End)) -->
  328    [ 'Unexpected `~w\' before `~w\''-[Punct, End] ].
  329syntax_error(undefined_char_escape(C)) -->
  330    [ 'Unknown character escape in quoted atom or string: `\\~w\''-[C] ].
  331syntax_error(void_not_allowed) -->
  332    [ 'Empty argument list "()"' ].
  333syntax_error(Message) -->
  334    [ '~w'-[Message] ].
  335
  336quoted_type('\'') --> [atom].
  337quoted_type('\"') --> { current_prolog_flag(double_quotes, Type) }, [Type-[]].
  338quoted_type('\`') --> { current_prolog_flag(back_quotes, Type) }, [Type-[]].
  339
  340domain(range(Low,High)) -->
  341    !,
  342    ['[~q..~q]'-[Low,High] ].
  343domain(Domain) -->
  344    ['`~w\''-[Domain] ].
 tabling_existence_error(+Ball, +Context)//
Called on invalid shift/1 calls. Track those that result from tabling errors.
  351tabling_existence_error(Ball, Context) -->
  352    { table_shift_ball(Ball) },
  353    [ 'Tabling dependency error' ],
  354    swi_extra(Context).
  355
  356table_shift_ball(dependency(_Head)).
  357table_shift_ball(dependency(_Skeleton, _Trie, _Mono)).
  358table_shift_ball(call_info(_Skeleton, _Status)).
  359table_shift_ball(call_info(_GenSkeleton, _Skeleton, _Status)).
 dwim_predicates(+PI, -Dwims)
Find related predicate indicators.
  365dwim_predicates(Module:Name/_Arity, Dwims) :-
  366    !,
  367    findall(Dwim, dwim_predicate(Module:Name, Dwim), Dwims).
  368dwim_predicates(Name/_Arity, Dwims) :-
  369    findall(Dwim, dwim_predicate(user:Name, Dwim), Dwims).
  370
  371dwim_message([]) --> [].
  372dwim_message([M:Head|T]) -->
  373    { hidden_module(M),
  374      !,
  375      functor(Head, Name, Arity)
  376    },
  377    [ '        ~q'-[Name/Arity], nl ],
  378    dwim_message(T).
  379dwim_message([Module:Head|T]) -->
  380    !,
  381    { functor(Head, Name, Arity)
  382    },
  383    [ '        ~q'-[Module:Name/Arity], nl],
  384    dwim_message(T).
  385dwim_message([Head|T]) -->
  386    {functor(Head, Name, Arity)},
  387    [ '        ~q'-[Name/Arity], nl],
  388    dwim_message(T).
  389
  390
  391swi_message(io_error(Op, Stream)) -->
  392    [ 'I/O error in ~w on stream ~p'-[Op, Stream] ].
  393swi_message(thread_error(TID, false)) -->
  394    [ 'Thread ~p died due to failure:'-[TID] ].
  395swi_message(thread_error(TID, exception(Error))) -->
  396    [ 'Thread ~p died abnormally:'-[TID], nl ],
  397    translate_message(Error).
  398swi_message(dependency_error(Tabled, DependsOn)) -->
  399    dependency_error(Tabled, DependsOn).
  400swi_message(shell(execute, Cmd)) -->
  401    [ 'Could not execute `~w'''-[Cmd] ].
  402swi_message(shell(signal(Sig), Cmd)) -->
  403    [ 'Caught signal ~d on `~w'''-[Sig, Cmd] ].
  404swi_message(format(Fmt, Args)) -->
  405    [ Fmt-Args ].
  406swi_message(signal(Name, Num)) -->
  407    [ 'Caught signal ~d (~w)'-[Num, Name] ].
  408swi_message(limit_exceeded(Limit, MaxVal)) -->
  409    [ 'Exceeded ~w limit (~w)'-[Limit, MaxVal] ].
  410swi_message(goal_failed(Goal)) -->
  411    [ 'goal unexpectedly failed: ~p'-[Goal] ].
  412swi_message(shared_object(_Action, Message)) --> % Message = dlerror()
  413    [ '~w'-[Message] ].
  414swi_message(system_error(Error)) -->
  415    [ 'error in system call: ~w'-[Error]
  416    ].
  417swi_message(system_error) -->
  418    [ 'error in system call'
  419    ].
  420swi_message(failure_error(Goal)) -->
  421    [ 'Goal failed: ~p'-[Goal] ].
  422swi_message(timeout_error(Op, Stream)) -->
  423    [ 'Timeout in ~w from ~p'-[Op, Stream] ].
  424swi_message(not_implemented(Type, What)) -->
  425    [ '~w `~p\' is not implemented in this version'-[Type, What] ].
  426swi_message(context_error(nodirective, Goal)) -->
  427    { goal_to_predicate_indicator(Goal, PI) },
  428    [ 'Wrong context: ~p can only be used in a directive'-[PI] ].
  429swi_message(context_error(edit, no_default_file)) -->
  430    (   { current_prolog_flag(windows, true) }
  431    ->  [ 'Edit/0 can only be used after opening a \c
  432               Prolog file by double-clicking it' ]
  433    ;   [ 'Edit/0 can only be used with the "-s file" commandline option'
  434        ]
  435    ),
  436    [ nl, 'Use "?- edit(Topic)." or "?- emacs."' ].
  437swi_message(context_error(function, meta_arg(S))) -->
  438    [ 'Functions are not (yet) supported for meta-arguments of type ~q'-[S] ].
  439swi_message(format_argument_type(Fmt, Arg)) -->
  440    [ 'Illegal argument to format sequence ~~~w: ~p'-[Fmt, Arg] ].
  441swi_message(format(Msg)) -->
  442    [ 'Format error: ~w'-[Msg] ].
  443swi_message(conditional_compilation_error(unterminated, Where)) -->
  444    [ 'Unterminated conditional compilation from '-[] ],
  445    cond_location(Where).
  446swi_message(conditional_compilation_error(no_if, What)) -->
  447    [ ':- ~w without :- if'-[What] ].
  448swi_message(duplicate_key(Key)) -->
  449    [ 'Duplicate key: ~p'-[Key] ].
  450swi_message(initialization_error(failed, Goal, File:Line)) -->
  451    !,
  452    [ '~w:~w: ~p: false'-[File, Line, Goal] ].
  453swi_message(initialization_error(Error, Goal, File:Line)) -->
  454    [ '~w:~w: ~p '-[File, Line, Goal] ],
  455    translate_message(Error).
  456swi_message(determinism_error(PI, det, Found, property)) -->
  457    (   { '$pi_head'(user:PI, Head),
  458          predicate_property(Head, det)
  459        }
  460    ->  [ 'Deterministic procedure ~p'-[PI] ]
  461    ;   [ 'Procedure ~p called from a deterministic procedure'-[PI] ]
  462    ),
  463    det_error(Found).
  464swi_message(determinism_error(PI, det, fail, guard)) -->
  465    [ 'Procedure ~p failed after $-guard'-[PI] ].
  466swi_message(determinism_error(PI, det, fail, guard_in_caller)) -->
  467    [ 'Procedure ~p failed after $-guard in caller'-[PI] ].
  468swi_message(determinism_error(Goal, det, fail, goal)) -->
  469    [ 'Goal ~p failed'-[Goal] ].
  470swi_message(determinism_error(Goal, det, nondet, goal)) -->
  471    [ 'Goal ~p succeeded with a choice point'-[Goal] ].
  472swi_message(qlf_format_error(File, Message)) -->
  473    [ '~w: Invalid QLF file: ~w'-[File, Message] ].
  474
  475det_error(nondet) -->
  476    [ ' succeeded with a choicepoint'- [] ].
  477det_error(fail) -->
  478    [ ' failed'- [] ].
  479
  480
  481cond_location(File:Line) -->
  482    { file_base_name(File, Base) },
  483    [ '~w:~d'-[Base, Line] ].
  484
  485swi_location(X) -->
  486    { var(X)
  487    },
  488    !,
  489    [].
  490swi_location(Context) -->
  491    prolog:message_location(Context),
  492    !.
  493swi_location(context(Caller, _Msg)) -->
  494    { ground(Caller)
  495    },
  496    !,
  497    caller(Caller).
  498swi_location(file(Path, Line, -1, _CharNo)) -->
  499    !,
  500    [ '~w:~d: '-[Path, Line] ].
  501swi_location(file(Path, Line, LinePos, _CharNo)) -->
  502    [ '~w:~d:~d: '-[Path, Line, LinePos] ].
  503swi_location(stream(Stream, Line, LinePos, CharNo)) -->
  504    (   { is_stream(Stream),
  505          stream_property(Stream, file_name(File))
  506        }
  507    ->  swi_location(file(File, Line, LinePos, CharNo))
  508    ;   [ 'Stream ~w:~d:~d '-[Stream, Line, LinePos] ]
  509    ).
  510swi_location(autoload(File:Line)) -->
  511    [ '~w:~w: '-[File, Line] ].
  512swi_location(_) -->
  513    [].
  514
  515caller(system:'$record_clause'/3) -->
  516    !,
  517    [].
  518caller(Module:Name/Arity) -->
  519    !,
  520    (   { \+ hidden_module(Module) }
  521    ->  [ '~q:~q/~w: '-[Module, Name, Arity] ]
  522    ;   [ '~q/~w: '-[Name, Arity] ]
  523    ).
  524caller(Name/Arity) -->
  525    [ '~q/~w: '-[Name, Arity] ].
  526caller(Caller) -->
  527    [ '~p: '-[Caller] ].
  528
  529
  530swi_extra(X) -->
  531    { var(X)
  532    },
  533    !,
  534    [].
  535swi_extra(Context) -->
  536    prolog:message_context(Context).
  537swi_extra(context(_, Msg)) -->
  538    { nonvar(Msg),
  539      Msg \== ''
  540    },
  541    !,
  542    swi_comment(Msg).
  543swi_extra(string(String, CharPos)) -->
  544    { sub_string(String, 0, CharPos, _, Before),
  545      sub_string(String, CharPos, _, 0, After)
  546    },
  547    [ nl, '~w'-[Before], nl, '** here **', nl, '~w'-[After] ].
  548swi_extra(_) -->
  549    [].
  550
  551swi_comment(already_from(Module)) -->
  552    !,
  553    [ ' (already imported from ~q)'-[Module] ].
  554swi_comment(directory(_Dir)) -->
  555    !,
  556    [ ' (is a directory)' ].
  557swi_comment(not_a_directory(_Dir)) -->
  558    !,
  559    [ ' (is not a directory)' ].
  560swi_comment(Msg) -->
  561    [ ' (~w)'-[Msg] ].
  562
  563
  564thread_context -->
  565    { thread_self(Me), Me \== main, thread_property(Me, id(Id)) },
  566    !,
  567    ['[Thread ~w] '-[Id]].
  568thread_context -->
  569    [].
  570
  571                 /*******************************
  572                 *        NORMAL MESSAGES       *
  573                 *******************************/
  574
  575prolog_message(initialization_error(_, E, File:Line)) -->
  576    !,
  577    [ '~w:~d: '-[File, Line],
  578      'Initialization goal raised exception:', nl
  579    ],
  580    translate_message(E).
  581prolog_message(initialization_error(Goal, E, _)) -->
  582    [ 'Initialization goal ~p raised exception:'-[Goal], nl ],
  583    translate_message(E).
  584prolog_message(initialization_failure(_Goal, File:Line)) -->
  585    !,
  586    [ '~w:~d: '-[File, Line],
  587      'Initialization goal failed'-[]
  588    ].
  589prolog_message(initialization_failure(Goal, _)) -->
  590    [ 'Initialization goal failed: ~p'-[Goal]
  591    ].
  592prolog_message(initialization_exception(E)) -->
  593    [ 'Prolog initialisation failed:', nl ],
  594    translate_message(E).
  595prolog_message(init_goal_syntax(Error, Text)) -->
  596    !,
  597    [ '-g ~w: '-[Text] ],
  598    translate_message(Error).
  599prolog_message(init_goal_failed(failed, @(Goal,File:Line))) -->
  600    !,
  601    [ '~w:~w: ~p: false'-[File, Line, Goal] ].
  602prolog_message(init_goal_failed(Error, @(Goal,File:Line))) -->
  603    !,
  604    [ '~w:~w: ~p '-[File, Line, Goal] ],
  605    translate_message(Error).
  606prolog_message(init_goal_failed(failed, Text)) -->
  607    !,
  608    [ '-g ~w: false'-[Text] ].
  609prolog_message(init_goal_failed(Error, Text)) -->
  610    !,
  611    [ '-g ~w: '-[Text] ],
  612    translate_message(Error).
  613prolog_message(unhandled_exception(E)) -->
  614    [ 'Unhandled exception: ' ],
  615    (   translate_message2(E)
  616    ->  []
  617    ;   [ '~p'-[E] ]
  618    ).
  619prolog_message(goal_failed(Context, Goal)) -->
  620    [ 'Goal (~w) failed: ~p'-[Context, Goal] ].
  621prolog_message(no_current_module(Module)) -->
  622    [ '~w is not a current module (created)'-[Module] ].
  623prolog_message(commandline_arg_type(Flag, Arg)) -->
  624    [ 'Bad argument to commandline option -~w: ~w'-[Flag, Arg] ].
  625prolog_message(missing_feature(Name)) -->
  626    [ 'This version of SWI-Prolog does not support ~w'-[Name] ].
  627prolog_message(singletons(_Term, List)) -->
  628    [ 'Singleton variables: ~w'-[List] ].
  629prolog_message(multitons(_Term, List)) -->
  630    [ 'Singleton-marked variables appearing more than once: ~w'-[List] ].
  631prolog_message(profile_no_cpu_time) -->
  632    [ 'No CPU-time info.  Check the SWI-Prolog manual for details' ].
  633prolog_message(non_ascii(Text, Type)) -->
  634    [ 'Unquoted ~w with non-portable characters: ~w'-[Type, Text] ].
  635prolog_message(io_warning(Stream, Message)) -->
  636    { stream_property(Stream, position(Position)),
  637      !,
  638      stream_position_data(line_count, Position, LineNo),
  639      stream_position_data(line_position, Position, LinePos),
  640      (   stream_property(Stream, file_name(File))
  641      ->  Obj = File
  642      ;   Obj = Stream
  643      )
  644    },
  645    [ '~p:~d:~d: ~w'-[Obj, LineNo, LinePos, Message] ].
  646prolog_message(io_warning(Stream, Message)) -->
  647    [ 'stream ~p: ~w'-[Stream, Message] ].
  648prolog_message(option_usage(pldoc)) -->
  649    [ 'Usage: --pldoc[=port]' ].
  650prolog_message(interrupt(begin)) -->
  651    [ 'Action (h for help) ? ', flush ].
  652prolog_message(interrupt(end)) -->
  653    [ 'continue' ].
  654prolog_message(interrupt(trace)) -->
  655    [ 'continue (trace mode)' ].
  656prolog_message(unknown_in_module_user) -->
  657    [ 'Using a non-error value for unknown in the global module', nl,
  658      'causes most of the development environment to stop working.', nl,
  659      'Please use :- dynamic or limit usage of unknown to a module.', nl,
  660      'See https://www.swi-prolog.org/howto/database.html'
  661    ].
  662prolog_message(deprecated(What)) -->
  663    deprecated(What).
  664prolog_message(untable(PI)) -->
  665    [ 'Reconsult: removed tabling for ~p'-[PI] ].
  666
  667
  668                 /*******************************
  669                 *         LOADING FILES        *
  670                 *******************************/
  671
  672prolog_message(modify_active_procedure(Who, What)) -->
  673    [ '~p: modified active procedure ~p'-[Who, What] ].
  674prolog_message(load_file(failed(user:File))) -->
  675    [ 'Failed to load ~p'-[File] ].
  676prolog_message(load_file(failed(Module:File))) -->
  677    [ 'Failed to load ~p into module ~p'-[File, Module] ].
  678prolog_message(load_file(failed(File))) -->
  679    [ 'Failed to load ~p'-[File] ].
  680prolog_message(mixed_directive(Goal)) -->
  681    [ 'Cannot pre-compile mixed load/call directive: ~p'-[Goal] ].
  682prolog_message(cannot_redefine_comma) -->
  683    [ 'Full stop in clause-body?  Cannot redefine ,/2' ].
  684prolog_message(illegal_autoload_index(Dir, Term)) -->
  685    [ 'Illegal term in INDEX file of directory ~w: ~w'-[Dir, Term] ].
  686prolog_message(redefined_procedure(Type, Proc)) -->
  687    [ 'Redefined ~w procedure ~p'-[Type, Proc] ],
  688    defined_definition('Previously defined', Proc).
  689prolog_message(declare_module(Module, abolish(Predicates))) -->
  690    [ 'Loading module ~w abolished: ~p'-[Module, Predicates] ].
  691prolog_message(import_private(Module, Private)) -->
  692    [ 'import/1: ~p is not exported (still imported into ~q)'-
  693      [Private, Module]
  694    ].
  695prolog_message(ignored_weak_import(Into, From:PI)) -->
  696    [ 'Local definition of ~p overrides weak import from ~q'-
  697      [Into:PI, From]
  698    ].
  699prolog_message(undefined_export(Module, PI)) -->
  700    [ 'Exported procedure ~q:~q is not defined'-[Module, PI] ].
  701prolog_message(no_exported_op(Module, Op)) -->
  702    [ 'Operator ~q:~q is not exported (still defined)'-[Module, Op] ].
  703prolog_message(discontiguous((-)/2,_)) -->
  704    prolog_message(minus_in_identifier).
  705prolog_message(discontiguous(Proc,Current)) -->
  706    [ 'Clauses of ', ansi(code, '~p', [Proc]),
  707      ' are not together in the source-file', nl ],
  708    current_definition(Proc, 'Earlier definition at '),
  709    [ 'Current predicate: ', ansi(code, '~p', [Current]), nl,
  710      'Use ', ansi(code, ':- discontiguous ~p.', [Proc]),
  711      ' to suppress this message'
  712    ].
  713prolog_message(decl_no_effect(Goal)) -->
  714    [ 'Deprecated declaration has no effect: ~p'-[Goal] ].
  715prolog_message(load_file(start(Level, File))) -->
  716    [ '~|~t~*+Loading '-[Level] ],
  717    load_file(File),
  718    [ ' ...' ].
  719prolog_message(include_file(start(Level, File))) -->
  720    [ '~|~t~*+include '-[Level] ],
  721    load_file(File),
  722    [ ' ...' ].
  723prolog_message(include_file(done(Level, File))) -->
  724    [ '~|~t~*+included '-[Level] ],
  725    load_file(File).
  726prolog_message(load_file(done(Level, File, Action, Module, Time, Clauses))) -->
  727    [ '~|~t~*+'-[Level] ],
  728    load_file(File),
  729    [ ' ~w'-[Action] ],
  730    load_module(Module),
  731    [ ' ~2f sec, ~D clauses'-[Time, Clauses] ].
  732prolog_message(dwim_undefined(Goal, Alternatives)) -->
  733    { goal_to_predicate_indicator(Goal, Pred)
  734    },
  735    [ 'Unknown procedure: ~q'-[Pred], nl,
  736      '    However, there are definitions for:', nl
  737    ],
  738    dwim_message(Alternatives).
  739prolog_message(dwim_correct(Into)) -->
  740    [ 'Correct to: ~q? '-[Into], flush ].
  741prolog_message(error(loop_error(Spec), file_search(Used))) -->
  742    [ 'File search: too many levels of indirections on: ~p'-[Spec], nl,
  743      '    Used alias expansions:', nl
  744    ],
  745    used_search(Used).
  746prolog_message(minus_in_identifier) -->
  747    [ 'The "-" character should not be used to separate words in an', nl,
  748      'identifier.  Check the SWI-Prolog FAQ for details.'
  749    ].
  750prolog_message(qlf(removed_after_error(File))) -->
  751    [ 'Removed incomplete QLF file ~w'-[File] ].
  752prolog_message(qlf(recompile(Spec,_Pl,_Qlf,Reason))) -->
  753    [ '~p: recompiling QLF file'-[Spec] ],
  754    qlf_recompile_reason(Reason).
  755prolog_message(qlf(can_not_recompile(Spec,QlfFile,_Reason))) -->
  756    [ '~p: can not recompile "~w" (access denied)'-[Spec, QlfFile], nl,
  757      '\tLoading from source'-[]
  758    ].
  759prolog_message(qlf(system_lib_out_of_date(Spec,QlfFile))) -->
  760    [ '~p: can not recompile "~w" (access denied)'-[Spec, QlfFile], nl,
  761      '\tLoading QlfFile'-[]
  762    ].
  763prolog_message(redefine_module(Module, OldFile, File)) -->
  764    [ 'Module "~q" already loaded from ~w.'-[Module, OldFile], nl,
  765      'Wipe and reload from ~w? '-[File], flush
  766    ].
  767prolog_message(redefine_module_reply) -->
  768    [ 'Please answer y(es), n(o) or a(bort)' ].
  769prolog_message(reloaded_in_module(Absolute, OldContext, LM)) -->
  770    [ '~w was previously loaded in module ~w'-[Absolute, OldContext], nl,
  771      '\tnow it is reloaded into module ~w'-[LM] ].
  772prolog_message(expected_layout(Expected, Pos)) -->
  773    [ 'Layout data: expected ~w, found: ~p'-[Expected, Pos] ].
  774
  775defined_definition(Message, Spec) -->
  776    { strip_module(user:Spec, M, Name/Arity),
  777      functor(Head, Name, Arity),
  778      predicate_property(M:Head, file(File)),
  779      predicate_property(M:Head, line_count(Line))
  780    },
  781    !,
  782    [ nl, '~w at ~w:~d'-[Message, File,Line] ].
  783defined_definition(_, _) --> [].
  784
  785used_search([]) -->
  786    [].
  787used_search([Alias=Expanded|T]) -->
  788    [ '        file_search_path(~p, ~p)'-[Alias, Expanded], nl ],
  789    used_search(T).
  790
  791load_file(file(Spec, _Path)) -->
  792    (   {atomic(Spec)}
  793    ->  [ '~w'-[Spec] ]
  794    ;   [ '~p'-[Spec] ]
  795    ).
  796%load_file(file(_, Path)) -->
  797%       [ '~w'-[Path] ].
  798
  799load_module(user) --> !.
  800load_module(system) --> !.
  801load_module(Module) -->
  802    [ ' into ~w'-[Module] ].
  803
  804goal_to_predicate_indicator(Goal, PI) :-
  805    strip_module(Goal, Module, Head),
  806    callable_name_arity(Head, Name, Arity),
  807    user_predicate_indicator(Module:Name/Arity, PI).
  808
  809callable_name_arity(Goal, Name, Arity) :-
  810    compound(Goal),
  811    !,
  812    compound_name_arity(Goal, Name, Arity).
  813callable_name_arity(Goal, Goal, 0) :-
  814    atom(Goal).
  815
  816user_predicate_indicator(Module:PI, PI) :-
  817    hidden_module(Module),
  818    !.
  819user_predicate_indicator(PI, PI).
  820
  821hidden_module(user) :- !.
  822hidden_module(system) :- !.
  823hidden_module(M) :-
  824    sub_atom(M, 0, _, _, $).
  825
  826current_definition(Proc, Prefix) -->
  827    { pi_uhead(Proc, Head),
  828      predicate_property(Head, file(File)),
  829      predicate_property(Head, line_count(Line))
  830    },
  831    [ '~w~w:~d'-[Prefix,File,Line], nl ].
  832current_definition(_, _) --> [].
  833
  834pi_uhead(Module:Name/Arity, Module:Head) :-
  835    !,
  836    atom(Module), atom(Name), integer(Arity),
  837    functor(Head, Name, Arity).
  838pi_uhead(Name/Arity, user:Head) :-
  839    atom(Name), integer(Arity),
  840    functor(Head, Name, Arity).
  841
  842qlf_recompile_reason(old) -->
  843    !,
  844    [ ' (out of date)'-[] ].
  845qlf_recompile_reason(_) -->
  846    [ ' (incompatible with current Prolog version)'-[] ].
  847
  848prolog_message(file_search(cache(Spec, _Cond), Path)) -->
  849    [ 'File search: ~p --> ~p (cache)'-[Spec, Path] ].
  850prolog_message(file_search(found(Spec, Cond), Path)) -->
  851    [ 'File search: ~p --> ~p OK ~p'-[Spec, Path, Cond] ].
  852prolog_message(file_search(tried(Spec, Cond), Path)) -->
  853    [ 'File search: ~p --> ~p NO ~p'-[Spec, Path, Cond] ].
  854
  855                 /*******************************
  856                 *              GC              *
  857                 *******************************/
  858
  859prolog_message(agc(start)) -->
  860    thread_context,
  861    [ 'AGC: ', flush ].
  862prolog_message(agc(done(Collected, Remaining, Time))) -->
  863    [ at_same_line,
  864      'reclaimed ~D atoms in ~3f sec. (remaining: ~D)'-
  865      [Collected, Time, Remaining]
  866    ].
  867prolog_message(cgc(start)) -->
  868    thread_context,
  869    [ 'CGC: ', flush ].
  870prolog_message(cgc(done(CollectedClauses, _CollectedBytes,
  871                        RemainingBytes, Time))) -->
  872    [ at_same_line,
  873      'reclaimed ~D clauses in ~3f sec. (pending: ~D bytes)'-
  874      [CollectedClauses, Time, RemainingBytes]
  875    ].
  876
  877		 /*******************************
  878		 *        STACK OVERFLOW	*
  879		 *******************************/
  880
  881out_of_stack(Context) -->
  882    { human_stack_size(Context.localused,   Local),
  883      human_stack_size(Context.globalused,  Global),
  884      human_stack_size(Context.trailused,   Trail),
  885      human_stack_size(Context.stack_limit, Limit),
  886      LCO is (100*(Context.depth - Context.environments))/Context.depth
  887    },
  888    [ 'Stack limit (~s) exceeded'-[Limit], nl,
  889      '  Stack sizes: local: ~s, global: ~s, trail: ~s'-[Local,Global,Trail], nl,
  890      '  Stack depth: ~D, last-call: ~0f%, Choice points: ~D'-
  891         [Context.depth, LCO, Context.choicepoints], nl
  892    ],
  893    overflow_reason(Context, Resolve),
  894    resolve_overflow(Resolve).
  895
  896human_stack_size(Size, String) :-
  897    Size < 100,
  898    format(string(String), '~dKb', [Size]).
  899human_stack_size(Size, String) :-
  900    Size < 100 000,
  901    Value is Size / 1024,
  902    format(string(String), '~1fMb', [Value]).
  903human_stack_size(Size, String) :-
  904    Value is Size / (1024*1024),
  905    format(string(String), '~1fGb', [Value]).
  906
  907overflow_reason(Context, fix) -->
  908    show_non_termination(Context),
  909    !.
  910overflow_reason(Context, enlarge) -->
  911    { Stack = Context.get(stack) },
  912    !,
  913    [ '  In:'-[], nl ],
  914    stack(Stack).
  915overflow_reason(_Context, enlarge) -->
  916    [ '  Insufficient global stack'-[] ].
  917
  918show_non_termination(Context) -->
  919    (   { Stack = Context.get(cycle) }
  920    ->  [ '  Probable infinite recursion (cycle):'-[], nl ]
  921    ;   { Stack = Context.get(non_terminating) }
  922    ->  [ '  Possible non-terminating recursion:'-[], nl ]
  923    ),
  924    stack(Stack).
  925
  926stack([]) --> [].
  927stack([frame(Depth, M:Goal, _)|T]) -->
  928    [ '    [~D] ~q:'-[Depth, M] ],
  929    stack_goal(Goal),
  930    [ nl ],
  931    stack(T).
  932
  933stack_goal(Goal) -->
  934    { compound(Goal),
  935      !,
  936      compound_name_arity(Goal, Name, Arity)
  937    },
  938    [ '~q('-[Name] ],
  939    stack_goal_args(1, Arity, Goal),
  940    [ ')'-[] ].
  941stack_goal(Goal) -->
  942    [ '~q'-[Goal] ].
  943
  944stack_goal_args(I, Arity, Goal) -->
  945    { I =< Arity,
  946      !,
  947      arg(I, Goal, A),
  948      I2 is I + 1
  949    },
  950    stack_goal_arg(A),
  951    (   { I2 =< Arity }
  952    ->  [ ', '-[] ],
  953        stack_goal_args(I2, Arity, Goal)
  954    ;   []
  955    ).
  956stack_goal_args(_, _, _) -->
  957    [].
  958
  959stack_goal_arg(A) -->
  960    { nonvar(A),
  961      A = [Len|T],
  962      !
  963    },
  964    (   {Len == cyclic_term}
  965    ->  [ '[cyclic list]'-[] ]
  966    ;   {T == []}
  967    ->  [ '[length:~D]'-[Len] ]
  968    ;   [ '[length:~D|~p]'-[Len, T] ]
  969    ).
  970stack_goal_arg(A) -->
  971    { nonvar(A),
  972      A = _/_,
  973      !
  974    },
  975    [ '<compound ~p>'-[A] ].
  976stack_goal_arg(A) -->
  977    [ '~p'-[A] ].
  978
  979resolve_overflow(fix) -->
  980    [].
  981resolve_overflow(enlarge) -->
  982    { current_prolog_flag(stack_limit, LimitBytes),
  983      NewLimit is LimitBytes * 2
  984    },
  985    [ nl,
  986      'Use the --stack_limit=size[KMG] command line option or'-[], nl,
  987      '?- set_prolog_flag(stack_limit, ~I). to double the limit.'-[NewLimit]
  988    ].
  989
  990
  991                 /*******************************
  992                 *        MAKE/AUTOLOAD         *
  993                 *******************************/
  994
  995prolog_message(make(reload(Files))) -->
  996    { length(Files, N)
  997    },
  998    [ 'Make: reloading ~D files'-[N] ].
  999prolog_message(make(done(_Files))) -->
 1000    [ 'Make: finished' ].
 1001prolog_message(make(library_index(Dir))) -->
 1002    [ 'Updating index for library ~w'-[Dir] ].
 1003prolog_message(autoload(Pred, File)) -->
 1004    thread_context,
 1005    [ 'autoloading ~p from ~w'-[Pred, File] ].
 1006prolog_message(autoload(read_index(Dir))) -->
 1007    [ 'Loading autoload index for ~w'-[Dir] ].
 1008prolog_message(autoload(disabled(Loaded))) -->
 1009    [ 'Disabled autoloading (loaded ~D files)'-[Loaded] ].
 1010prolog_message(autoload(already_defined(PI, From))) -->
 1011    [ ansi(code, '~p', [PI]) ],
 1012    (   { '$pi_head'(PI, Head),
 1013          predicate_property(Head, built_in)
 1014        }
 1015    ->  [' is a built-in predicate']
 1016    ;   [ ' is already imported from module ',
 1017          ansi(code, '~p', [From])
 1018        ]
 1019    ).
 1020
 1021swi_message(autoload(Msg)) -->
 1022    [ nl, '  ' ],
 1023    autoload_message(Msg).
 1024
 1025autoload_message(not_exported(PI, Spec, _FullFile, _Exports)) -->
 1026    [ ansi(code, '~w', [Spec]),
 1027      ' does not export ',
 1028      ansi(code, '~p', [PI])
 1029    ].
 1030autoload_message(no_file(Spec)) -->
 1031    [ ansi(code, '~p', [Spec]), ': No such file' ].
 1032
 1033
 1034                 /*******************************
 1035                 *       COMPILER WARNINGS      *
 1036                 *******************************/
 1037
 1038% print warnings about dubious code raised by the compiler.
 1039% TBD: pass in PC to produce exact error locations.
 1040
 1041prolog_message(compiler_warnings(Clause, Warnings0)) -->
 1042    {   print_goal_options(DefOptions),
 1043        (   prolog_load_context(variable_names, VarNames)
 1044        ->  warnings_with_named_vars(Warnings0, VarNames, Warnings),
 1045            Options = [variable_names(VarNames)|DefOptions]
 1046        ;   Options = DefOptions,
 1047            Warnings = Warnings0
 1048        )
 1049    },
 1050    compiler_warnings(Warnings, Clause, Options).
 1051
 1052warnings_with_named_vars([], _, []).
 1053warnings_with_named_vars([H|T0], VarNames, [H|T]) :-
 1054    term_variables(H, Vars),
 1055    '$member'(V1, Vars),
 1056    '$member'(_=V2, VarNames),
 1057    V1 == V2,
 1058    !,
 1059    warnings_with_named_vars(T0, VarNames, T).
 1060warnings_with_named_vars([_|T0], VarNames, T) :-
 1061    warnings_with_named_vars(T0, VarNames, T).
 1062
 1063
 1064compiler_warnings([], _, _) --> [].
 1065compiler_warnings([H|T], Clause, Options) -->
 1066    (   compiler_warning(H, Clause, Options)
 1067    ->  []
 1068    ;   [ 'Unknown compiler warning: ~W'-[H,Options] ]
 1069    ),
 1070    (   {T==[]}
 1071    ->  []
 1072    ;   [nl]
 1073    ),
 1074    compiler_warnings(T, Clause, Options).
 1075
 1076compiler_warning(eq_vv(A,B), _Clause, Options) -->
 1077    (   { A == B }
 1078    ->  [ 'Test is always true: ~W'-[A==B, Options] ]
 1079    ;   [ 'Test is always false: ~W'-[A==B, Options] ]
 1080    ).
 1081compiler_warning(eq_singleton(A,B), _Clause, Options) -->
 1082    [ 'Test is always false: ~W'-[A==B, Options] ].
 1083compiler_warning(neq_vv(A,B), _Clause, Options) -->
 1084    (   { A \== B }
 1085    ->  [ 'Test is always true: ~W'-[A\==B, Options] ]
 1086    ;   [ 'Test is always false: ~W'-[A\==B, Options] ]
 1087    ).
 1088compiler_warning(neq_singleton(A,B), _Clause, Options) -->
 1089    [ 'Test is always true: ~W'-[A\==B, Options] ].
 1090compiler_warning(unify_singleton(A,B), _Clause, Options) -->
 1091    [ 'Unified variable is not used: ~W'-[A=B, Options] ].
 1092compiler_warning(always(Bool, Pred, Arg), _Clause, Options) -->
 1093    { Goal =.. [Pred,Arg] },
 1094    [ 'Test is always ~w: ~W'-[Bool, Goal, Options] ].
 1095compiler_warning(unbalanced_var(V), _Clause, Options) -->
 1096    [ 'Variable not introduced in all branches: ~W'-[V, Options] ].
 1097compiler_warning(branch_singleton(V), _Clause, Options) -->
 1098    [ 'Singleton variable in branch: ~W'-[V, Options] ].
 1099compiler_warning(negation_singleton(V), _Clause, Options) -->
 1100    [ 'Singleton variable in \\+: ~W'-[V, Options] ].
 1101compiler_warning(multiton(V), _Clause, Options) -->
 1102    [ 'Singleton-marked variable appears more than once: ~W'-[V, Options] ].
 1103
 1104print_goal_options(
 1105    [ quoted(true),
 1106      portray(true)
 1107    ]).
 1108
 1109
 1110                 /*******************************
 1111                 *      TOPLEVEL MESSAGES       *
 1112                 *******************************/
 1113
 1114prolog_message(version) -->
 1115    { current_prolog_flag(version_git, Version) },
 1116    !,
 1117    [ '~w'-[Version] ].
 1118prolog_message(version) -->
 1119    { current_prolog_flag(version_data, swi(Major,Minor,Patch,Options))
 1120    },
 1121    (   { memberchk(tag(Tag), Options) }
 1122    ->  [ '~w.~w.~w-~w'-[Major, Minor, Patch, Tag] ]
 1123    ;   [ '~w.~w.~w'-[Major, Minor, Patch] ]
 1124    ).
 1125prolog_message(address_bits) -->
 1126    { current_prolog_flag(address_bits, Bits)
 1127    },
 1128    !,
 1129    [ '~d bits, '-[Bits] ].
 1130prolog_message(threads) -->
 1131    { current_prolog_flag(threads, true)
 1132    },
 1133    !,
 1134    [ 'threaded, ' ].
 1135prolog_message(threads) -->
 1136    [].
 1137prolog_message(copyright) -->
 1138    [ 'SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.', nl,
 1139      'Please run ?- license. for legal details.'
 1140    ].
 1141prolog_message(user_versions) -->
 1142    (   { findall(Msg, prolog:version_msg(Msg), Msgs),
 1143          Msgs \== []
 1144        }
 1145    ->  [nl],
 1146        user_version_messages(Msgs)
 1147    ;   []
 1148    ).
 1149prolog_message(documentaton) -->
 1150    [ 'For online help and background, visit https://www.swi-prolog.org', nl,
 1151      'For built-in help, use ?- help(Topic). or ?- apropos(Word).'
 1152    ].
 1153prolog_message(welcome) -->
 1154    [ 'Welcome to SWI-Prolog (' ],
 1155    prolog_message(threads),
 1156    prolog_message(address_bits),
 1157    ['version ' ],
 1158    prolog_message(version),
 1159    [ ')', nl ],
 1160    prolog_message(copyright),
 1161    [ nl ],
 1162    prolog_message(user_versions),
 1163    [ nl ],
 1164    prolog_message(documentaton),
 1165    [ nl, nl ].
 1166prolog_message(about) -->
 1167    [ 'SWI-Prolog version (' ],
 1168    prolog_message(threads),
 1169    prolog_message(address_bits),
 1170    ['version ' ],
 1171    prolog_message(version),
 1172    [ ')', nl ],
 1173    prolog_message(copyright).
 1174prolog_message(halt) -->
 1175    [ 'halt' ].
 1176prolog_message(break(begin, Level)) -->
 1177    [ 'Break level ~d'-[Level] ].
 1178prolog_message(break(end, Level)) -->
 1179    [ 'Exit break level ~d'-[Level] ].
 1180prolog_message(var_query(_)) -->
 1181    [ '... 1,000,000 ............ 10,000,000 years later', nl, nl,
 1182      '~t~8|>> 42 << (last release gives the question)'
 1183    ].
 1184prolog_message(close_on_abort(Stream)) -->
 1185    [ 'Abort: closed stream ~p'-[Stream] ].
 1186prolog_message(cancel_halt(Reason)) -->
 1187    [ 'Halt cancelled: ~p'-[Reason] ].
 1188
 1189prolog_message(query(QueryResult)) -->
 1190    query_result(QueryResult).
 1191
 1192query_result(no) -->            % failure
 1193    [ ansi(truth(false), 'false.', []) ],
 1194    extra_line.
 1195query_result(yes(true, [])) -->      % prompt_alternatives_on: groundness
 1196    !,
 1197    [ ansi(truth(true), 'true.', []) ],
 1198    extra_line.
 1199query_result(yes(Delays, Residuals)) -->
 1200    result([], Delays, Residuals),
 1201    extra_line.
 1202query_result(done) -->          % user typed <CR>
 1203    extra_line.
 1204query_result(yes(Bindings, Delays, Residuals)) -->
 1205    result(Bindings, Delays, Residuals),
 1206    prompt(yes, Bindings, Delays, Residuals).
 1207query_result(more(Bindings, Delays, Residuals)) -->
 1208    result(Bindings, Delays, Residuals),
 1209    prompt(more, Bindings, Delays, Residuals).
 1210query_result(help) -->
 1211    [ nl, 'Actions:'-[], nl, nl,
 1212      '; (n, r, space, TAB): redo    t:          trace & redo'-[], nl,
 1213      'b:                    break   c (a, RET): exit'-[], nl,
 1214      'w:                    write   p           print'-[], nl,
 1215      'h (?):                help'-[],
 1216      nl, nl
 1217    ].
 1218query_result(action) -->
 1219    [ 'Action? '-[], flush ].
 1220query_result(confirm) -->
 1221    [ 'Please answer \'y\' or \'n\'? '-[], flush ].
 1222query_result(eof) -->
 1223    [ nl ].
 1224query_result(toplevel_open_line) -->
 1225    [].
 1226
 1227prompt(Answer, [], true, []-[]) -->
 1228    !,
 1229    prompt(Answer, empty).
 1230prompt(Answer, _, _, _) -->
 1231    !,
 1232    prompt(Answer, non_empty).
 1233
 1234prompt(yes, empty) -->
 1235    !,
 1236    [ ansi(truth(true), 'true.', []) ],
 1237    extra_line.
 1238prompt(yes, _) -->
 1239    !,
 1240    [ full_stop ],
 1241    extra_line.
 1242prompt(more, empty) -->
 1243    !,
 1244    [ ansi(truth(true), 'true ', []), flush ].
 1245prompt(more, _) -->
 1246    !,
 1247    [ ' '-[], flush ].
 1248
 1249result(Bindings, Delays, Residuals) -->
 1250    { current_prolog_flag(answer_write_options, Options0),
 1251      Options = [partial(true)|Options0],
 1252      GOptions = [priority(999)|Options0]
 1253    },
 1254    wfs_residual_program(Delays, GOptions),
 1255    bindings(Bindings, [priority(699)|Options]),
 1256    (   {Residuals == []-[]}
 1257    ->  bind_delays_sep(Bindings, Delays),
 1258        delays(Delays, GOptions)
 1259    ;   bind_res_sep(Bindings, Residuals),
 1260        residuals(Residuals, GOptions),
 1261        (   {Delays == true}
 1262        ->  []
 1263        ;   [','-[], nl],
 1264            delays(Delays, GOptions)
 1265        )
 1266    ).
 1267
 1268bindings([], _) -->
 1269    [].
 1270bindings([binding(Names,Skel,Subst)|T], Options) -->
 1271    { '$last'(Names, Name) },
 1272    var_names(Names), value(Name, Skel, Subst, Options),
 1273    (   { T \== [] }
 1274    ->  [ ','-[], nl ],
 1275        bindings(T, Options)
 1276    ;   []
 1277    ).
 1278
 1279var_names([Name]) -->
 1280    !,
 1281    [ '~w = '-[Name] ].
 1282var_names([Name1,Name2|T]) -->
 1283    !,
 1284    [ '~w = ~w, '-[Name1, Name2] ],
 1285    var_names([Name2|T]).
 1286
 1287
 1288value(Name, Skel, Subst, Options) -->
 1289    (   { var(Skel), Subst = [Skel=S] }
 1290    ->  { Skel = '$VAR'(Name) },
 1291        [ '~W'-[S, Options] ]
 1292    ;   [ '~W'-[Skel, Options] ],
 1293        substitution(Subst, Options)
 1294    ).
 1295
 1296substitution([], _) --> !.
 1297substitution([N=V|T], Options) -->
 1298    [ ', ', ansi(comment, '% where', []), nl,
 1299      '    ~w = ~W'-[N,V,Options] ],
 1300    substitutions(T, Options).
 1301
 1302substitutions([], _) --> [].
 1303substitutions([N=V|T], Options) -->
 1304    [ ','-[], nl, '    ~w = ~W'-[N,V,Options] ],
 1305    substitutions(T, Options).
 1306
 1307
 1308residuals(Normal-Hidden, Options) -->
 1309    residuals1(Normal, Options),
 1310    bind_res_sep(Normal, Hidden),
 1311    (   {Hidden == []}
 1312    ->  []
 1313    ;   [ansi(comment, '% with pending residual goals', []), nl]
 1314    ),
 1315    residuals1(Hidden, Options).
 1316
 1317residuals1([], _) -->
 1318    [].
 1319residuals1([G|Gs], Options) -->
 1320    (   { Gs \== [] }
 1321    ->  [ '~W,'-[G, Options], nl ],
 1322        residuals1(Gs, Options)
 1323    ;   [ '~W'-[G, Options] ]
 1324    ).
 1325
 1326wfs_residual_program(true, _Options) -->
 1327    !.
 1328wfs_residual_program(Goal, _Options) -->
 1329    { current_prolog_flag(toplevel_list_wfs_residual_program, true),
 1330      '$current_typein_module'(TypeIn),
 1331      (   current_predicate(delays_residual_program/2)
 1332      ->  true
 1333      ;   use_module(library(wfs), [delays_residual_program/2])
 1334      ),
 1335      delays_residual_program(TypeIn:Goal, TypeIn:Program),
 1336      Program \== []
 1337    },
 1338    !,
 1339    [ ansi(comment, '% WFS residual program', []), nl ],
 1340    [ ansi(wfs(residual_program), '~@', ['$messages':list_clauses(Program)]) ].
 1341wfs_residual_program(_, _) --> [].
 1342
 1343delays(true, _Options) -->
 1344    !.
 1345delays(Goal, Options) -->
 1346    { current_prolog_flag(toplevel_list_wfs_residual_program, true)
 1347    },
 1348    !,
 1349    [ ansi(truth(undefined), '~W', [Goal, Options]) ].
 1350delays(_, _Options) -->
 1351    [ ansi(truth(undefined), undefined, []) ].
 1352
 1353:- public list_clauses/1. 1354
 1355list_clauses([]).
 1356list_clauses([H|T]) :-
 1357    (   system_undefined(H)
 1358    ->  true
 1359    ;   portray_clause(user_output, H, [indent(4)])
 1360    ),
 1361    list_clauses(T).
 1362
 1363system_undefined((undefined :- tnot(undefined))).
 1364system_undefined((answer_count_restraint :- tnot(answer_count_restraint))).
 1365system_undefined((radial_restraint :- tnot(radial_restraint))).
 1366
 1367bind_res_sep(_, []) --> !.
 1368bind_res_sep(_, []-[]) --> !.
 1369bind_res_sep([], _) --> !.
 1370bind_res_sep(_, _) --> [','-[], nl].
 1371
 1372bind_delays_sep([], _) --> !.
 1373bind_delays_sep(_, true) --> !.
 1374bind_delays_sep(_, _) --> [','-[], nl].
 1375
 1376extra_line -->
 1377    { current_prolog_flag(toplevel_extra_white_line, true) },
 1378    !,
 1379    ['~N'-[]].
 1380extra_line -->
 1381    [].
 1382
 1383prolog_message(if_tty(Message)) -->
 1384    (   {current_prolog_flag(tty_control, true)}
 1385    ->  [ at_same_line | Message ]
 1386    ;   []
 1387    ).
 1388prolog_message(halt(Reason)) -->
 1389    [ '~w: halt'-[Reason] ].
 1390prolog_message(no_action(Char)) -->
 1391    [ 'Unknown action: ~c (h for help)'-[Char], nl ].
 1392
 1393prolog_message(history(help(Show, Help))) -->
 1394    [ 'History Commands:', nl,
 1395      '    !!.              Repeat last query', nl,
 1396      '    !nr.             Repeat query numbered <nr>', nl,
 1397      '    !str.            Repeat last query starting with <str>', nl,
 1398      '    !?str.           Repeat last query holding <str>', nl,
 1399      '    ^old^new.        Substitute <old> into <new> of last query', nl,
 1400      '    !nr^old^new.     Substitute in query numbered <nr>', nl,
 1401      '    !str^old^new.    Substitute in query starting with <str>', nl,
 1402      '    !?str^old^new.   Substitute in query holding <str>', nl,
 1403      '    ~w.~21|Show history list'-[Show], nl,
 1404      '    ~w.~21|Show this list'-[Help], nl, nl
 1405    ].
 1406prolog_message(history(no_event)) -->
 1407    [ '! No such event' ].
 1408prolog_message(history(bad_substitution)) -->
 1409    [ '! Bad substitution' ].
 1410prolog_message(history(expanded(Event))) -->
 1411    [ '~w.'-[Event] ].
 1412prolog_message(history(history(Events))) -->
 1413    history_events(Events).
 1414
 1415history_events([]) -->
 1416    [].
 1417history_events([Nr/Event|T]) -->
 1418    [ '~t~w   ~8|~W~W'-[ Nr,
 1419                         Event, [partial(true)],
 1420                         '.', [partial(true)]
 1421                       ],
 1422      nl
 1423    ],
 1424    history_events(T).
 1425
 1426
 1427user_version_messages([]) --> [].
 1428user_version_messages([H|T]) -->
 1429    user_version_message(H),
 1430    user_version_messages(T).
 user_version_message(+Term)
 1434user_version_message(Term) -->
 1435    translate_message2(Term), !, [nl].
 1436user_version_message(Atom) -->
 1437    [ '~w'-[Atom], nl ].
 1438
 1439
 1440                 /*******************************
 1441                 *       DEBUGGER MESSAGES      *
 1442                 *******************************/
 1443
 1444prolog_message(spy(Head)) -->
 1445    { goal_to_predicate_indicator(Head, Pred)
 1446    },
 1447    [ 'Spy point on ~p'-[Pred] ].
 1448prolog_message(nospy(Head)) -->
 1449    { goal_to_predicate_indicator(Head, Pred)
 1450    },
 1451    [ 'Spy point removed from ~p'-[Pred] ].
 1452prolog_message(trace_mode(OnOff)) -->
 1453    [ 'Trace mode switched to ~w'-[OnOff] ].
 1454prolog_message(debug_mode(OnOff)) -->
 1455    [ 'Debug mode switched to ~w'-[OnOff] ].
 1456prolog_message(debugging(OnOff)) -->
 1457    [ 'Debug mode is ~w'-[OnOff] ].
 1458prolog_message(spying([])) -->
 1459    !,
 1460    [ 'No spy points' ].
 1461prolog_message(spying(Heads)) -->
 1462    [ 'Spy points (see spy/1) on:', nl ],
 1463    predicate_list(Heads).
 1464prolog_message(trace(Head, [])) -->
 1465    !,
 1466    { goal_to_predicate_indicator(Head, Pred)
 1467    },
 1468    [ '        ~p: Not tracing'-[Pred], nl].
 1469prolog_message(trace(Head, Ports)) -->
 1470    { goal_to_predicate_indicator(Head, Pred)
 1471    },
 1472    [ '        ~p: ~w'-[Pred, Ports], nl].
 1473prolog_message(tracing([])) -->
 1474    !,
 1475    [ 'No traced predicates (see trace/1)' ].
 1476prolog_message(tracing(Heads)) -->
 1477    [ 'Trace points (see trace/1) on:', nl ],
 1478    tracing_list(Heads).
 1479
 1480predicate_list([]) -->                  % TBD: Share with dwim, etc.
 1481    [].
 1482predicate_list([H|T]) -->
 1483    { goal_to_predicate_indicator(H, Pred)
 1484    },
 1485    [ '        ~p'-[Pred], nl],
 1486    predicate_list(T).
 1487
 1488tracing_list([]) -->
 1489    [].
 1490tracing_list([trace(Head, Ports)|T]) -->
 1491    translate_message(trace(Head, Ports)),
 1492    tracing_list(T).
 1493
 1494prolog_message(frame(Frame, backtrace, _PC)) -->
 1495    !,
 1496    { prolog_frame_attribute(Frame, level, Level)
 1497    },
 1498    [ ansi(frame(level), '~t[~D] ~10|', [Level]) ],
 1499    frame_context(Frame),
 1500    frame_goal(Frame).
 1501prolog_message(frame(Frame, choice, PC)) -->
 1502    !,
 1503    prolog_message(frame(Frame, backtrace, PC)).
 1504prolog_message(frame(_, cut_call, _)) --> !, [].
 1505prolog_message(frame(Goal, trace(Port))) -->
 1506    !,
 1507    thread_context,
 1508    [ ' T ' ],
 1509    port(Port),
 1510    goal(Goal).
 1511prolog_message(frame(Frame, Port, _PC)) -->
 1512    frame_flags(Frame),
 1513    port(Port),
 1514    frame_level(Frame),
 1515    frame_context(Frame),
 1516    frame_depth_limit(Port, Frame),
 1517    frame_goal(Frame),
 1518    [ flush ].
 1519
 1520frame_goal(Frame) -->
 1521    { prolog_frame_attribute(Frame, goal, Goal)
 1522    },
 1523    goal(Goal).
 1524
 1525goal(Goal0) -->
 1526    { clean_goal(Goal0, Goal),
 1527      current_prolog_flag(debugger_write_options, Options)
 1528    },
 1529    [ '~W'-[Goal, Options] ].
 1530
 1531frame_level(Frame) -->
 1532    { prolog_frame_attribute(Frame, level, Level)
 1533    },
 1534    [ '(~D) '-[Level] ].
 1535
 1536frame_context(Frame) -->
 1537    (   { current_prolog_flag(debugger_show_context, true),
 1538          prolog_frame_attribute(Frame, context_module, Context)
 1539        }
 1540    ->  [ '[~w] '-[Context] ]
 1541    ;   []
 1542    ).
 1543
 1544frame_depth_limit(fail, Frame) -->
 1545    { prolog_frame_attribute(Frame, depth_limit_exceeded, true)
 1546    },
 1547    !,
 1548    [ '[depth-limit exceeded] ' ].
 1549frame_depth_limit(_, _) -->
 1550    [].
 1551
 1552frame_flags(Frame) -->
 1553    { prolog_frame_attribute(Frame, goal, Goal),
 1554      (   predicate_property(Goal, transparent)
 1555      ->  T = '^'
 1556      ;   T = ' '
 1557      ),
 1558      (   predicate_property(Goal, spying)
 1559      ->  S = '*'
 1560      ;   S = ' '
 1561      )
 1562    },
 1563    [ '~w~w '-[T, S] ].
 1564
 1565port(Port) -->
 1566    { port_name(Port, Name)
 1567    },
 1568    !,
 1569    [ ansi(port(Port), '~w: ', [Name]) ].
 1570
 1571port_name(call,      'Call').
 1572port_name(exit,      'Exit').
 1573port_name(fail,      'Fail').
 1574port_name(redo,      'Redo').
 1575port_name(unify,     'Unify').
 1576port_name(exception, 'Exception').
 1577
 1578clean_goal(M:Goal, Goal) :-
 1579    hidden_module(M),
 1580    !.
 1581clean_goal(M:Goal, Goal) :-
 1582    predicate_property(M:Goal, built_in),
 1583    !.
 1584clean_goal(Goal, Goal).
 1585
 1586
 1587                 /*******************************
 1588                 *        COMPATIBILITY         *
 1589                 *******************************/
 1590
 1591prolog_message(compatibility(renamed(Old, New))) -->
 1592    [ 'The predicate ~p has been renamed to ~p.'-[Old, New], nl,
 1593      'Please update your sources for compatibility with future versions.'
 1594    ].
 1595
 1596
 1597                 /*******************************
 1598                 *            THREADS           *
 1599                 *******************************/
 1600
 1601prolog_message(abnormal_thread_completion(Goal, exception(Ex))) -->
 1602    !,
 1603    [ 'Thread running "~p" died on exception: '-[Goal] ],
 1604    translate_message(Ex).
 1605prolog_message(abnormal_thread_completion(Goal, fail)) -->
 1606    [ 'Thread running "~p" died due to failure'-[Goal] ].
 1607prolog_message(threads_not_died(Running)) -->
 1608    [ 'The following threads wouldn\'t die: ~p'-[Running] ].
 1609
 1610
 1611                 /*******************************
 1612                 *             PACKS            *
 1613                 *******************************/
 1614
 1615prolog_message(pack(attached(Pack, BaseDir))) -->
 1616    [ 'Attached package ~w at ~q'-[Pack, BaseDir] ].
 1617prolog_message(pack(duplicate(Entry, OldDir, Dir))) -->
 1618    [ 'Package ~w already attached at ~q.'-[Entry,OldDir], nl,
 1619      '\tIgnoring version from ~q'- [Entry, OldDir, Dir]
 1620    ].
 1621prolog_message(pack(no_arch(Entry, Arch))) -->
 1622    [ 'Package ~w: no binary for architecture ~w'-[Entry, Arch] ].
 1623
 1624                 /*******************************
 1625                 *             MISC             *
 1626                 *******************************/
 1627
 1628prolog_message(null_byte_in_path(Component)) -->
 1629    [ '0-byte in PATH component: ~p (skipped directory)'-[Component] ].
 1630prolog_message(invalid_tmp_dir(Dir, Reason)) -->
 1631    [ 'Cannot use ~p as temporary file directory: ~w'-[Dir, Reason] ].
 1632prolog_message(ambiguous_stream_pair(Pair)) -->
 1633    [ 'Ambiguous operation on stream pair ~p'-[Pair] ].
 1634prolog_message(backcomp(init_file_moved(FoundFile))) -->
 1635    { absolute_file_name(app_config('init.pl'), InitFile,
 1636                         [ file_errors(fail)
 1637                         ])
 1638    },
 1639    [ 'The location of the config file has moved'-[], nl,
 1640      '  from "~w"'-[FoundFile], nl,
 1641      '  to   "~w"'-[InitFile], nl,
 1642      '  See https://www.swi-prolog.org/modified/config-files.html'-[]
 1643    ].
 1644
 1645		 /*******************************
 1646		 *          DEPRECATED		*
 1647		 *******************************/
 1648
 1649deprecated(Term) -->
 1650    prolog:deprecated(Term),
 1651    !.
 1652deprecated(set_prolog_stack(_Stack,limit)) -->
 1653    [ 'set_prolog_stack/2: limit(Size) sets the combined limit.'-[], nl,
 1654      'See https://www.swi-prolog.org/changes/stack-limit.html'
 1655    ].
 1656
 1657		 /*******************************
 1658		 *           TRIPWIRES		*
 1659		 *******************************/
 1660
 1661tripwire_message(Wire, Context) -->
 1662    [ 'Trapped tripwire ~w for '-[Wire] ],
 1663    tripwire_context(Wire, Context).
 1664
 1665tripwire_context(_, ATrie) -->
 1666    { '$is_answer_trie'(ATrie, _),
 1667      !,
 1668      '$tabling':atrie_goal(ATrie, QGoal),
 1669      user_predicate_indicator(QGoal, Goal)
 1670    },
 1671    [ '~p'-[Goal] ].
 1672tripwire_context(_, Ctx) -->
 1673    [ '~p'-[Ctx] ].
 1674
 1675
 1676		 /*******************************
 1677		 *        DEFAULT THEME		*
 1678		 *******************************/
 1679
 1680:- public default_theme/2. 1681
 1682default_theme(var,                    [fg(red)]).
 1683default_theme(code,                   [fg(blue)]).
 1684default_theme(comment,                [fg(green)]).
 1685default_theme(warning,                [fg(red)]).
 1686default_theme(error,                  [bold, fg(red)]).
 1687default_theme(truth(false),           [bold, fg(red)]).
 1688default_theme(truth(true),            [bold]).
 1689default_theme(truth(undefined),       [bold, fg(cyan)]).
 1690default_theme(wfs(residual_program),  [fg(cyan)]).
 1691default_theme(frame(level),           [bold]).
 1692default_theme(port(call),             [bold, fg(green)]).
 1693default_theme(port(exit),             [bold, fg(green)]).
 1694default_theme(port(fail),             [bold, fg(red)]).
 1695default_theme(port(redo),             [bold, fg(yellow)]).
 1696default_theme(port(unify),            [bold, fg(blue)]).
 1697default_theme(port(exception),        [bold, fg(magenta)]).
 1698default_theme(message(informational), [fg(green)]).
 1699default_theme(message(information),   [fg(green)]).
 1700default_theme(message(debug(_)),      [fg(blue)]).
 1701default_theme(message(Level),         Attrs) :-
 1702    nonvar(Level),
 1703    default_theme(Level, Attrs).
 1704
 1705
 1706                 /*******************************
 1707                 *      PRINTING MESSAGES       *
 1708                 *******************************/
 1709
 1710:- multifile
 1711    user:message_hook/3,
 1712    prolog:message_prefix_hook/2. 1713:- dynamic
 1714    user:message_hook/3,
 1715    prolog:message_prefix_hook/2. 1716:- thread_local
 1717    user:thread_message_hook/3. 1718:- '$hide'((push_msg/1,pop_msg/0)).
 print_message(+Kind, +Term)
Print an error message using a term as generated by the exception system.
 1725print_message(Level, Term) :-
 1726    setup_call_cleanup(
 1727        push_msg(Term),
 1728        print_message_guarded(Level, Term),
 1729        pop_msg),
 1730    !.
 1731print_message(Level, Term) :-
 1732    (   Level \== silent
 1733    ->  format(user_error, 'Recursive ~w message: ~q~n', [Level, Term])
 1734    ;   true
 1735    ).
 1736
 1737push_msg(Term) :-
 1738    nb_current('$inprint_message', Messages),
 1739    !,
 1740    \+ ( '$member'(Msg, Messages),
 1741         Msg =@= Term
 1742       ),
 1743    b_setval('$inprint_message', [Term|Messages]).
 1744push_msg(Term) :-
 1745    b_setval('$inprint_message', [Term]).
 1746
 1747pop_msg :-
 1748    (   nb_current('$inprint_message', [_|Messages]),
 1749        Messages \== []
 1750    ->  b_setval('$inprint_message', Messages)
 1751    ;   nb_delete('$inprint_message'),              % delete history
 1752        b_setval('$inprint_message', [])
 1753    ).
 1754
 1755print_message_guarded(Level, Term) :-
 1756    (   must_print(Level, Term)
 1757    ->  (   translate_message(Term, Lines, [])
 1758        ->  (   nonvar(Term),
 1759                (   notrace(user:thread_message_hook(Term, Level, Lines))
 1760                ->  true
 1761                ;   notrace(user:message_hook(Term, Level, Lines))
 1762                )
 1763            ->  true
 1764            ;   print_system_message(Term, Level, Lines)
 1765            )
 1766        )
 1767    ;   true
 1768    ).
 print_system_message(+Term, +Kind, +Lines)
Print the message if the user did not intecept the message. The first is used for errors and warnings that can be related to source-location. Note that syntax errors have their own source-location and should therefore not be handled this way.
 1777print_system_message(_, silent, _) :- !.
 1778print_system_message(_, informational, _) :-
 1779    current_prolog_flag(verbose, silent),
 1780    !.
 1781print_system_message(_, banner, _) :-
 1782    current_prolog_flag(verbose, silent),
 1783    !.
 1784print_system_message(_, _, []) :- !.
 1785print_system_message(Term, Kind, Lines) :-
 1786    catch(flush_output(user_output), _, true),      % may not exist
 1787    source_location(File, Line),
 1788    Term \= error(syntax_error(_), _),
 1789    msg_property(Kind, location_prefix(File:Line, LocPrefix, LinePrefix)),
 1790    !,
 1791    insert_prefix(Lines, LinePrefix, Ctx, PrefixLines),
 1792    '$append'([ begin(Kind, Ctx),
 1793                LocPrefix,
 1794                nl
 1795              | PrefixLines
 1796              ],
 1797              [ end(Ctx)
 1798              ],
 1799              AllLines),
 1800    msg_property(Kind, stream(Stream)),
 1801    ignore(stream_property(Stream, position(Pos))),
 1802    print_message_lines(Stream, AllLines),
 1803    (   \+ stream_property(Stream, position(Pos)),
 1804        msg_property(Kind, wait(Wait)),
 1805        Wait > 0
 1806    ->  sleep(Wait)
 1807    ;   true
 1808    ).
 1809print_system_message(_, Kind, Lines) :-
 1810    msg_property(Kind, stream(Stream)),
 1811    print_message_lines(Stream, kind(Kind), Lines).
 1812
 1813:- multifile
 1814    user:message_property/2. 1815
 1816msg_property(Kind, Property) :-
 1817    notrace(user:message_property(Kind, Property)),
 1818    !.
 1819msg_property(Kind, prefix(Prefix)) :-
 1820    msg_prefix(Kind, Prefix),
 1821    !.
 1822msg_property(_, prefix('~N')) :- !.
 1823msg_property(query, stream(user_output)) :- !.
 1824msg_property(_, stream(user_error)) :- !.
 1825msg_property(error,
 1826             location_prefix(File:Line,
 1827                             '~NERROR: ~w:~d:'-[File,Line],
 1828                             '~NERROR:    ')) :- !.
 1829msg_property(warning,
 1830             location_prefix(File:Line,
 1831                             '~NWarning: ~w:~d:'-[File,Line],
 1832                             '~NWarning:    ')) :- !.
 1833msg_property(error,   wait(0.1)) :- !.
 1834
 1835msg_prefix(debug(_), Prefix) :-
 1836    msg_context('~N% ', Prefix).
 1837msg_prefix(warning, Prefix) :-
 1838    msg_context('~NWarning: ', Prefix).
 1839msg_prefix(error, Prefix) :-
 1840    msg_context('~NERROR: ', Prefix).
 1841msg_prefix(informational, '~N% ').
 1842msg_prefix(information,   '~N% ').
 msg_context(+Prefix0, -Prefix) is det
Add contextual information to a message. This uses the Prolog flag message_context. Recognised context terms are:

In addition, the hook message_prefix_hook/2 is called that allows for additional context information.

 1856msg_context(Prefix0, Prefix) :-
 1857    current_prolog_flag(message_context, Context),
 1858    is_list(Context),
 1859    !,
 1860    add_message_context(Context, Prefix0, Prefix).
 1861msg_context(Prefix, Prefix).
 1862
 1863add_message_context([], Prefix, Prefix).
 1864add_message_context([H|T], Prefix0, Prefix) :-
 1865    (   add_message_context1(H, Prefix0, Prefix1)
 1866    ->  true
 1867    ;   Prefix1 = Prefix0
 1868    ),
 1869    add_message_context(T, Prefix1, Prefix).
 1870
 1871add_message_context1(Context, Prefix0, Prefix) :-
 1872    prolog:message_prefix_hook(Context, Extra),
 1873    atomics_to_string([Prefix0, Extra, ' '], Prefix).
 1874add_message_context1(time, Prefix0, Prefix) :-
 1875    get_time(Now),
 1876    format_time(string(S), '%T.%3f ', Now),
 1877    string_concat(Prefix0, S, Prefix).
 1878add_message_context1(time(Format), Prefix0, Prefix) :-
 1879    get_time(Now),
 1880    format_time(string(S), Format, Now),
 1881    atomics_to_string([Prefix0, S, ' '], Prefix).
 1882add_message_context1(thread, Prefix0, Prefix) :-
 1883    thread_self(Id0),
 1884    Id0 \== main,
 1885    !,
 1886    (   atom(Id0)
 1887    ->  Id = Id0
 1888    ;   thread_property(Id0, id(Id))
 1889    ),
 1890    format(string(Prefix), '~w[Thread ~w] ', [Prefix0, Id]).
 print_message_lines(+Stream, +PrefixOrKind, +Lines)
Quintus compatibility predicate to print message lines using a prefix.
 1897print_message_lines(Stream, kind(Kind), Lines) :-
 1898    !,
 1899    msg_property(Kind, prefix(Prefix)),
 1900    insert_prefix(Lines, Prefix, Ctx, PrefixLines),
 1901    '$append'([ begin(Kind, Ctx)
 1902              | PrefixLines
 1903              ],
 1904              [ end(Ctx)
 1905              ],
 1906              AllLines),
 1907    print_message_lines(Stream, AllLines).
 1908print_message_lines(Stream, Prefix, Lines) :-
 1909    insert_prefix(Lines, Prefix, _, PrefixLines),
 1910    print_message_lines(Stream, PrefixLines).
 insert_prefix(+Lines, +Prefix, +Ctx, -PrefixedLines)
 1914insert_prefix([at_same_line|Lines0], Prefix, Ctx, Lines) :-
 1915    !,
 1916    prefix_nl(Lines0, Prefix, Ctx, Lines).
 1917insert_prefix(Lines0, Prefix, Ctx, [prefix(Prefix)|Lines]) :-
 1918    prefix_nl(Lines0, Prefix, Ctx, Lines).
 1919
 1920prefix_nl([], _, _, [nl]).
 1921prefix_nl([nl], _, _, [nl]) :- !.
 1922prefix_nl([flush], _, _, [flush]) :- !.
 1923prefix_nl([nl|T0], Prefix, Ctx, [nl, prefix(Prefix)|T]) :-
 1924    !,
 1925    prefix_nl(T0, Prefix, Ctx, T).
 1926prefix_nl([ansi(Attrs,Fmt,Args)|T0], Prefix, Ctx,
 1927          [ansi(Attrs,Fmt,Args,Ctx)|T]) :-
 1928    !,
 1929    prefix_nl(T0, Prefix, Ctx, T).
 1930prefix_nl([H|T0], Prefix, Ctx, [H|T]) :-
 1931    prefix_nl(T0, Prefix, Ctx, T).
 print_message_lines(+Stream, +Lines)
 1935print_message_lines(Stream, Lines) :-
 1936    with_output_to(
 1937        Stream,
 1938        notrace(print_message_lines_guarded(current_output, Lines))).
 1939
 1940print_message_lines_guarded(_, []) :- !.
 1941print_message_lines_guarded(S, [H|T]) :-
 1942    line_element(S, H),
 1943    print_message_lines_guarded(S, T).
 1944
 1945line_element(S, E) :-
 1946    prolog:message_line_element(S, E),
 1947    !.
 1948line_element(S, full_stop) :-
 1949    !,
 1950    '$put_token'(S, '.').           % insert space if needed.
 1951line_element(S, nl) :-
 1952    !,
 1953    nl(S).
 1954line_element(S, prefix(Fmt-Args)) :-
 1955    !,
 1956    safe_format(S, Fmt, Args).
 1957line_element(S, prefix(Fmt)) :-
 1958    !,
 1959    safe_format(S, Fmt, []).
 1960line_element(S, flush) :-
 1961    !,
 1962    flush_output(S).
 1963line_element(S, Fmt-Args) :-
 1964    !,
 1965    safe_format(S, Fmt, Args).
 1966line_element(S, ansi(_, Fmt, Args)) :-
 1967    !,
 1968    safe_format(S, Fmt, Args).
 1969line_element(S, ansi(_, Fmt, Args, _Ctx)) :-
 1970    !,
 1971    safe_format(S, Fmt, Args).
 1972line_element(_, begin(_Level, _Ctx)) :- !.
 1973line_element(_, end(_Ctx)) :- !.
 1974line_element(S, Fmt) :-
 1975    safe_format(S, Fmt, []).
 safe_format(+Stream, +Format, +Args) is det
 1979safe_format(S, Fmt, Args) :-
 1980    E = error(_,_),
 1981    catch(format(S,Fmt,Args), E,
 1982          format_failed(S,Fmt,Args,E)).
 1983
 1984format_failed(S, _Fmt, _Args, E) :-
 1985    E = error(io_error(_,S),_),
 1986    !,
 1987    throw(E).
 1988format_failed(S, Fmt, Args, error(E,_)) :-
 1989    format(S, '~N    [[ EXCEPTION while printing message ~q~n\c
 1990                        ~7|with arguments ~W:~n\c
 1991                        ~7|raised: ~W~n~4|]]~n',
 1992           [ Fmt,
 1993             Args, [quoted(true), max_depth(10)],
 1994             E, [quoted(true), max_depth(10)]
 1995           ]).
 message_to_string(+Term, -String)
Translate an error term into a string
 2001message_to_string(Term, Str) :-
 2002    translate_message(Term, Actions, []),
 2003    !,
 2004    actions_to_format(Actions, Fmt, Args),
 2005    format(string(Str), Fmt, Args).
 2006
 2007actions_to_format([], '', []) :- !.
 2008actions_to_format([nl], '', []) :- !.
 2009actions_to_format([Term, nl], Fmt, Args) :-
 2010    !,
 2011    actions_to_format([Term], Fmt, Args).
 2012actions_to_format([nl|T], Fmt, Args) :-
 2013    !,
 2014    actions_to_format(T, Fmt0, Args),
 2015    atom_concat('~n', Fmt0, Fmt).
 2016actions_to_format([ansi(_Attrs, Fmt0, Args0)|Tail], Fmt, Args) :-
 2017    !,
 2018    actions_to_format(Tail, Fmt1, Args1),
 2019    atom_concat(Fmt0, Fmt1, Fmt),
 2020    append_args(Args0, Args1, Args).
 2021actions_to_format([Fmt0-Args0|Tail], Fmt, Args) :-
 2022    !,
 2023    actions_to_format(Tail, Fmt1, Args1),
 2024    atom_concat(Fmt0, Fmt1, Fmt),
 2025    append_args(Args0, Args1, Args).
 2026actions_to_format([Skip|T], Fmt, Args) :-
 2027    action_skip(Skip),
 2028    !,
 2029    actions_to_format(T, Fmt, Args).
 2030actions_to_format([Term|Tail], Fmt, Args) :-
 2031    atomic(Term),
 2032    !,
 2033    actions_to_format(Tail, Fmt1, Args),
 2034    atom_concat(Term, Fmt1, Fmt).
 2035actions_to_format([Term|Tail], Fmt, Args) :-
 2036    actions_to_format(Tail, Fmt1, Args1),
 2037    atom_concat('~w', Fmt1, Fmt),
 2038    append_args([Term], Args1, Args).
 2039
 2040action_skip(at_same_line).
 2041action_skip(flush).
 2042action_skip(begin(_Level, _Ctx)).
 2043action_skip(end(_Ctx)).
 2044
 2045append_args(M:Args0, Args1, M:Args) :-
 2046    !,
 2047    strip_module(Args1, _, A1),
 2048    '$append'(Args0, A1, Args).
 2049append_args(Args0, Args1, Args) :-
 2050    strip_module(Args1, _, A1),
 2051    '$append'(Args0, A1, Args).
 2052
 2053
 2054                 /*******************************
 2055                 *    MESSAGES TO PRINT ONCE    *
 2056                 *******************************/
 2057
 2058:- dynamic
 2059    printed/2.
 print_once(Message, Level)
True for messages that must be printed only once.
 2065print_once(compatibility(_), _).
 2066print_once(null_byte_in_path(_), _).
 2067print_once(deprecated(_), _).
 must_print(+Level, +Message)
True if the message must be printed.
 2073must_print(Level, Message) :-
 2074    nonvar(Message),
 2075    print_once(Message, Level),
 2076    !,
 2077    \+ printed(Message, Level),
 2078    assert(printed(Message, Level)).
 2079must_print(_, _)