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] ].
  474swi_message(goal_expansion_error(bound, Term)) -->
  475    [ 'Goal expansion bound a variable to ~p'-[Term] ].
  476
  477det_error(nondet) -->
  478    [ ' succeeded with a choicepoint'- [] ].
  479det_error(fail) -->
  480    [ ' failed'- [] ].
  481
  482
  483cond_location(File:Line) -->
  484    { file_base_name(File, Base) },
  485    [ '~w:~d'-[Base, Line] ].
  486
  487swi_location(X) -->
  488    { var(X)
  489    },
  490    !,
  491    [].
  492swi_location(Context) -->
  493    prolog:message_location(Context),
  494    !.
  495swi_location(context(Caller, _Msg)) -->
  496    { ground(Caller)
  497    },
  498    !,
  499    caller(Caller).
  500swi_location(file(Path, Line, -1, _CharNo)) -->
  501    !,
  502    [ '~w:~d: '-[Path, Line] ].
  503swi_location(file(Path, Line, LinePos, _CharNo)) -->
  504    [ '~w:~d:~d: '-[Path, Line, LinePos] ].
  505swi_location(stream(Stream, Line, LinePos, CharNo)) -->
  506    (   { is_stream(Stream),
  507          stream_property(Stream, file_name(File))
  508        }
  509    ->  swi_location(file(File, Line, LinePos, CharNo))
  510    ;   [ 'Stream ~w:~d:~d '-[Stream, Line, LinePos] ]
  511    ).
  512swi_location(autoload(File:Line)) -->
  513    [ '~w:~w: '-[File, Line] ].
  514swi_location(_) -->
  515    [].
  516
  517caller(system:'$record_clause'/3) -->
  518    !,
  519    [].
  520caller(Module:Name/Arity) -->
  521    !,
  522    (   { \+ hidden_module(Module) }
  523    ->  [ '~q:~q/~w: '-[Module, Name, Arity] ]
  524    ;   [ '~q/~w: '-[Name, Arity] ]
  525    ).
  526caller(Name/Arity) -->
  527    [ '~q/~w: '-[Name, Arity] ].
  528caller(Caller) -->
  529    [ '~p: '-[Caller] ].
  530
  531
  532swi_extra(X) -->
  533    { var(X)
  534    },
  535    !,
  536    [].
  537swi_extra(Context) -->
  538    prolog:message_context(Context).
  539swi_extra(context(_, Msg)) -->
  540    { nonvar(Msg),
  541      Msg \== ''
  542    },
  543    !,
  544    swi_comment(Msg).
  545swi_extra(string(String, CharPos)) -->
  546    { sub_string(String, 0, CharPos, _, Before),
  547      sub_string(String, CharPos, _, 0, After)
  548    },
  549    [ nl, '~w'-[Before], nl, '** here **', nl, '~w'-[After] ].
  550swi_extra(_) -->
  551    [].
  552
  553swi_comment(already_from(Module)) -->
  554    !,
  555    [ ' (already imported from ~q)'-[Module] ].
  556swi_comment(directory(_Dir)) -->
  557    !,
  558    [ ' (is a directory)' ].
  559swi_comment(not_a_directory(_Dir)) -->
  560    !,
  561    [ ' (is not a directory)' ].
  562swi_comment(Msg) -->
  563    [ ' (~w)'-[Msg] ].
  564
  565
  566thread_context -->
  567    { thread_self(Me), Me \== main, thread_property(Me, id(Id)) },
  568    !,
  569    ['[Thread ~w] '-[Id]].
  570thread_context -->
  571    [].
  572
  573                 /*******************************
  574                 *        NORMAL MESSAGES       *
  575                 *******************************/
  576
  577prolog_message(initialization_error(_, E, File:Line)) -->
  578    !,
  579    [ '~w:~d: '-[File, Line],
  580      'Initialization goal raised exception:', nl
  581    ],
  582    translate_message(E).
  583prolog_message(initialization_error(Goal, E, _)) -->
  584    [ 'Initialization goal ~p raised exception:'-[Goal], nl ],
  585    translate_message(E).
  586prolog_message(initialization_failure(_Goal, File:Line)) -->
  587    !,
  588    [ '~w:~d: '-[File, Line],
  589      'Initialization goal failed'-[]
  590    ].
  591prolog_message(initialization_failure(Goal, _)) -->
  592    [ 'Initialization goal failed: ~p'-[Goal]
  593    ].
  594prolog_message(initialization_exception(E)) -->
  595    [ 'Prolog initialisation failed:', nl ],
  596    translate_message(E).
  597prolog_message(init_goal_syntax(Error, Text)) -->
  598    !,
  599    [ '-g ~w: '-[Text] ],
  600    translate_message(Error).
  601prolog_message(init_goal_failed(failed, @(Goal,File:Line))) -->
  602    !,
  603    [ '~w:~w: ~p: false'-[File, Line, Goal] ].
  604prolog_message(init_goal_failed(Error, @(Goal,File:Line))) -->
  605    !,
  606    [ '~w:~w: ~p '-[File, Line, Goal] ],
  607    translate_message(Error).
  608prolog_message(init_goal_failed(failed, Text)) -->
  609    !,
  610    [ '-g ~w: false'-[Text] ].
  611prolog_message(init_goal_failed(Error, Text)) -->
  612    !,
  613    [ '-g ~w: '-[Text] ],
  614    translate_message(Error).
  615prolog_message(unhandled_exception(E)) -->
  616    [ 'Unhandled exception: ' ],
  617    (   translate_message2(E)
  618    ->  []
  619    ;   [ '~p'-[E] ]
  620    ).
  621prolog_message(goal_failed(Context, Goal)) -->
  622    [ 'Goal (~w) failed: ~p'-[Context, Goal] ].
  623prolog_message(no_current_module(Module)) -->
  624    [ '~w is not a current module (created)'-[Module] ].
  625prolog_message(commandline_arg_type(Flag, Arg)) -->
  626    [ 'Bad argument to commandline option -~w: ~w'-[Flag, Arg] ].
  627prolog_message(missing_feature(Name)) -->
  628    [ 'This version of SWI-Prolog does not support ~w'-[Name] ].
  629prolog_message(singletons(_Term, List)) -->
  630    [ 'Singleton variables: ~w'-[List] ].
  631prolog_message(multitons(_Term, List)) -->
  632    [ 'Singleton-marked variables appearing more than once: ~w'-[List] ].
  633prolog_message(profile_no_cpu_time) -->
  634    [ 'No CPU-time info.  Check the SWI-Prolog manual for details' ].
  635prolog_message(non_ascii(Text, Type)) -->
  636    [ 'Unquoted ~w with non-portable characters: ~w'-[Type, Text] ].
  637prolog_message(io_warning(Stream, Message)) -->
  638    { stream_property(Stream, position(Position)),
  639      !,
  640      stream_position_data(line_count, Position, LineNo),
  641      stream_position_data(line_position, Position, LinePos),
  642      (   stream_property(Stream, file_name(File))
  643      ->  Obj = File
  644      ;   Obj = Stream
  645      )
  646    },
  647    [ '~p:~d:~d: ~w'-[Obj, LineNo, LinePos, Message] ].
  648prolog_message(io_warning(Stream, Message)) -->
  649    [ 'stream ~p: ~w'-[Stream, Message] ].
  650prolog_message(option_usage(pldoc)) -->
  651    [ 'Usage: --pldoc[=port]' ].
  652prolog_message(interrupt(begin)) -->
  653    [ 'Action (h for help) ? ', flush ].
  654prolog_message(interrupt(end)) -->
  655    [ 'continue' ].
  656prolog_message(interrupt(trace)) -->
  657    [ 'continue (trace mode)' ].
  658prolog_message(unknown_in_module_user) -->
  659    [ 'Using a non-error value for unknown in the global module', nl,
  660      'causes most of the development environment to stop working.', nl,
  661      'Please use :- dynamic or limit usage of unknown to a module.', nl,
  662      'See https://www.swi-prolog.org/howto/database.html'
  663    ].
  664prolog_message(deprecated(What)) -->
  665    deprecated(What).
  666prolog_message(untable(PI)) -->
  667    [ 'Reconsult: removed tabling for ~p'-[PI] ].
  668
  669
  670                 /*******************************
  671                 *         LOADING FILES        *
  672                 *******************************/
  673
  674prolog_message(modify_active_procedure(Who, What)) -->
  675    [ '~p: modified active procedure ~p'-[Who, What] ].
  676prolog_message(load_file(failed(user:File))) -->
  677    [ 'Failed to load ~p'-[File] ].
  678prolog_message(load_file(failed(Module:File))) -->
  679    [ 'Failed to load ~p into module ~p'-[File, Module] ].
  680prolog_message(load_file(failed(File))) -->
  681    [ 'Failed to load ~p'-[File] ].
  682prolog_message(mixed_directive(Goal)) -->
  683    [ 'Cannot pre-compile mixed load/call directive: ~p'-[Goal] ].
  684prolog_message(cannot_redefine_comma) -->
  685    [ 'Full stop in clause-body?  Cannot redefine ,/2' ].
  686prolog_message(illegal_autoload_index(Dir, Term)) -->
  687    [ 'Illegal term in INDEX file of directory ~w: ~w'-[Dir, Term] ].
  688prolog_message(redefined_procedure(Type, Proc)) -->
  689    [ 'Redefined ~w procedure ~p'-[Type, Proc] ],
  690    defined_definition('Previously defined', Proc).
  691prolog_message(declare_module(Module, abolish(Predicates))) -->
  692    [ 'Loading module ~w abolished: ~p'-[Module, Predicates] ].
  693prolog_message(import_private(Module, Private)) -->
  694    [ 'import/1: ~p is not exported (still imported into ~q)'-
  695      [Private, Module]
  696    ].
  697prolog_message(ignored_weak_import(Into, From:PI)) -->
  698    [ 'Local definition of ~p overrides weak import from ~q'-
  699      [Into:PI, From]
  700    ].
  701prolog_message(undefined_export(Module, PI)) -->
  702    [ 'Exported procedure ~q:~q is not defined'-[Module, PI] ].
  703prolog_message(no_exported_op(Module, Op)) -->
  704    [ 'Operator ~q:~q is not exported (still defined)'-[Module, Op] ].
  705prolog_message(discontiguous((-)/2,_)) -->
  706    prolog_message(minus_in_identifier).
  707prolog_message(discontiguous(Proc,Current)) -->
  708    [ 'Clauses of ', ansi(code, '~p', [Proc]),
  709      ' are not together in the source-file', nl ],
  710    current_definition(Proc, 'Earlier definition at '),
  711    [ 'Current predicate: ', ansi(code, '~p', [Current]), nl,
  712      'Use ', ansi(code, ':- discontiguous ~p.', [Proc]),
  713      ' to suppress this message'
  714    ].
  715prolog_message(decl_no_effect(Goal)) -->
  716    [ 'Deprecated declaration has no effect: ~p'-[Goal] ].
  717prolog_message(load_file(start(Level, File))) -->
  718    [ '~|~t~*+Loading '-[Level] ],
  719    load_file(File),
  720    [ ' ...' ].
  721prolog_message(include_file(start(Level, File))) -->
  722    [ '~|~t~*+include '-[Level] ],
  723    load_file(File),
  724    [ ' ...' ].
  725prolog_message(include_file(done(Level, File))) -->
  726    [ '~|~t~*+included '-[Level] ],
  727    load_file(File).
  728prolog_message(load_file(done(Level, File, Action, Module, Time, Clauses))) -->
  729    [ '~|~t~*+'-[Level] ],
  730    load_file(File),
  731    [ ' ~w'-[Action] ],
  732    load_module(Module),
  733    [ ' ~2f sec, ~D clauses'-[Time, Clauses] ].
  734prolog_message(dwim_undefined(Goal, Alternatives)) -->
  735    { goal_to_predicate_indicator(Goal, Pred)
  736    },
  737    [ 'Unknown procedure: ~q'-[Pred], nl,
  738      '    However, there are definitions for:', nl
  739    ],
  740    dwim_message(Alternatives).
  741prolog_message(dwim_correct(Into)) -->
  742    [ 'Correct to: ~q? '-[Into], flush ].
  743prolog_message(error(loop_error(Spec), file_search(Used))) -->
  744    [ 'File search: too many levels of indirections on: ~p'-[Spec], nl,
  745      '    Used alias expansions:', nl
  746    ],
  747    used_search(Used).
  748prolog_message(minus_in_identifier) -->
  749    [ 'The "-" character should not be used to separate words in an', nl,
  750      'identifier.  Check the SWI-Prolog FAQ for details.'
  751    ].
  752prolog_message(qlf(removed_after_error(File))) -->
  753    [ 'Removed incomplete QLF file ~w'-[File] ].
  754prolog_message(qlf(recompile(Spec,_Pl,_Qlf,Reason))) -->
  755    [ '~p: recompiling QLF file'-[Spec] ],
  756    qlf_recompile_reason(Reason).
  757prolog_message(qlf(can_not_recompile(Spec,QlfFile,_Reason))) -->
  758    [ '~p: can not recompile "~w" (access denied)'-[Spec, QlfFile], nl,
  759      '\tLoading from source'-[]
  760    ].
  761prolog_message(qlf(system_lib_out_of_date(Spec,QlfFile))) -->
  762    [ '~p: can not recompile "~w" (access denied)'-[Spec, QlfFile], nl,
  763      '\tLoading QlfFile'-[]
  764    ].
  765prolog_message(redefine_module(Module, OldFile, File)) -->
  766    [ 'Module "~q" already loaded from ~w.'-[Module, OldFile], nl,
  767      'Wipe and reload from ~w? '-[File], flush
  768    ].
  769prolog_message(redefine_module_reply) -->
  770    [ 'Please answer y(es), n(o) or a(bort)' ].
  771prolog_message(reloaded_in_module(Absolute, OldContext, LM)) -->
  772    [ '~w was previously loaded in module ~w'-[Absolute, OldContext], nl,
  773      '\tnow it is reloaded into module ~w'-[LM] ].
  774prolog_message(expected_layout(Expected, Pos)) -->
  775    [ 'Layout data: expected ~w, found: ~p'-[Expected, Pos] ].
  776
  777defined_definition(Message, Spec) -->
  778    { strip_module(user:Spec, M, Name/Arity),
  779      functor(Head, Name, Arity),
  780      predicate_property(M:Head, file(File)),
  781      predicate_property(M:Head, line_count(Line))
  782    },
  783    !,
  784    [ nl, '~w at ~w:~d'-[Message, File,Line] ].
  785defined_definition(_, _) --> [].
  786
  787used_search([]) -->
  788    [].
  789used_search([Alias=Expanded|T]) -->
  790    [ '        file_search_path(~p, ~p)'-[Alias, Expanded], nl ],
  791    used_search(T).
  792
  793load_file(file(Spec, _Path)) -->
  794    (   {atomic(Spec)}
  795    ->  [ '~w'-[Spec] ]
  796    ;   [ '~p'-[Spec] ]
  797    ).
  798%load_file(file(_, Path)) -->
  799%       [ '~w'-[Path] ].
  800
  801load_module(user) --> !.
  802load_module(system) --> !.
  803load_module(Module) -->
  804    [ ' into ~w'-[Module] ].
  805
  806goal_to_predicate_indicator(Goal, PI) :-
  807    strip_module(Goal, Module, Head),
  808    callable_name_arity(Head, Name, Arity),
  809    user_predicate_indicator(Module:Name/Arity, PI).
  810
  811callable_name_arity(Goal, Name, Arity) :-
  812    compound(Goal),
  813    !,
  814    compound_name_arity(Goal, Name, Arity).
  815callable_name_arity(Goal, Goal, 0) :-
  816    atom(Goal).
  817
  818user_predicate_indicator(Module:PI, PI) :-
  819    hidden_module(Module),
  820    !.
  821user_predicate_indicator(PI, PI).
  822
  823hidden_module(user) :- !.
  824hidden_module(system) :- !.
  825hidden_module(M) :-
  826    sub_atom(M, 0, _, _, $).
  827
  828current_definition(Proc, Prefix) -->
  829    { pi_uhead(Proc, Head),
  830      predicate_property(Head, file(File)),
  831      predicate_property(Head, line_count(Line))
  832    },
  833    [ '~w~w:~d'-[Prefix,File,Line], nl ].
  834current_definition(_, _) --> [].
  835
  836pi_uhead(Module:Name/Arity, Module:Head) :-
  837    !,
  838    atom(Module), atom(Name), integer(Arity),
  839    functor(Head, Name, Arity).
  840pi_uhead(Name/Arity, user:Head) :-
  841    atom(Name), integer(Arity),
  842    functor(Head, Name, Arity).
  843
  844qlf_recompile_reason(old) -->
  845    !,
  846    [ ' (out of date)'-[] ].
  847qlf_recompile_reason(_) -->
  848    [ ' (incompatible with current Prolog version)'-[] ].
  849
  850prolog_message(file_search(cache(Spec, _Cond), Path)) -->
  851    [ 'File search: ~p --> ~p (cache)'-[Spec, Path] ].
  852prolog_message(file_search(found(Spec, Cond), Path)) -->
  853    [ 'File search: ~p --> ~p OK ~p'-[Spec, Path, Cond] ].
  854prolog_message(file_search(tried(Spec, Cond), Path)) -->
  855    [ 'File search: ~p --> ~p NO ~p'-[Spec, Path, Cond] ].
  856
  857                 /*******************************
  858                 *              GC              *
  859                 *******************************/
  860
  861prolog_message(agc(start)) -->
  862    thread_context,
  863    [ 'AGC: ', flush ].
  864prolog_message(agc(done(Collected, Remaining, Time))) -->
  865    [ at_same_line,
  866      'reclaimed ~D atoms in ~3f sec. (remaining: ~D)'-
  867      [Collected, Time, Remaining]
  868    ].
  869prolog_message(cgc(start)) -->
  870    thread_context,
  871    [ 'CGC: ', flush ].
  872prolog_message(cgc(done(CollectedClauses, _CollectedBytes,
  873                        RemainingBytes, Time))) -->
  874    [ at_same_line,
  875      'reclaimed ~D clauses in ~3f sec. (pending: ~D bytes)'-
  876      [CollectedClauses, Time, RemainingBytes]
  877    ].
  878
  879		 /*******************************
  880		 *        STACK OVERFLOW	*
  881		 *******************************/
  882
  883out_of_stack(Context) -->
  884    { human_stack_size(Context.localused,   Local),
  885      human_stack_size(Context.globalused,  Global),
  886      human_stack_size(Context.trailused,   Trail),
  887      human_stack_size(Context.stack_limit, Limit),
  888      LCO is (100*(Context.depth - Context.environments))/Context.depth
  889    },
  890    [ 'Stack limit (~s) exceeded'-[Limit], nl,
  891      '  Stack sizes: local: ~s, global: ~s, trail: ~s'-[Local,Global,Trail], nl,
  892      '  Stack depth: ~D, last-call: ~0f%, Choice points: ~D'-
  893         [Context.depth, LCO, Context.choicepoints], nl
  894    ],
  895    overflow_reason(Context, Resolve),
  896    resolve_overflow(Resolve).
  897
  898human_stack_size(Size, String) :-
  899    Size < 100,
  900    format(string(String), '~dKb', [Size]).
  901human_stack_size(Size, String) :-
  902    Size < 100 000,
  903    Value is Size / 1024,
  904    format(string(String), '~1fMb', [Value]).
  905human_stack_size(Size, String) :-
  906    Value is Size / (1024*1024),
  907    format(string(String), '~1fGb', [Value]).
  908
  909overflow_reason(Context, fix) -->
  910    show_non_termination(Context),
  911    !.
  912overflow_reason(Context, enlarge) -->
  913    { Stack = Context.get(stack) },
  914    !,
  915    [ '  In:'-[], nl ],
  916    stack(Stack).
  917overflow_reason(_Context, enlarge) -->
  918    [ '  Insufficient global stack'-[] ].
  919
  920show_non_termination(Context) -->
  921    (   { Stack = Context.get(cycle) }
  922    ->  [ '  Probable infinite recursion (cycle):'-[], nl ]
  923    ;   { Stack = Context.get(non_terminating) }
  924    ->  [ '  Possible non-terminating recursion:'-[], nl ]
  925    ),
  926    stack(Stack).
  927
  928stack([]) --> [].
  929stack([frame(Depth, M:Goal, _)|T]) -->
  930    [ '    [~D] ~q:'-[Depth, M] ],
  931    stack_goal(Goal),
  932    [ nl ],
  933    stack(T).
  934
  935stack_goal(Goal) -->
  936    { compound(Goal),
  937      !,
  938      compound_name_arity(Goal, Name, Arity)
  939    },
  940    [ '~q('-[Name] ],
  941    stack_goal_args(1, Arity, Goal),
  942    [ ')'-[] ].
  943stack_goal(Goal) -->
  944    [ '~q'-[Goal] ].
  945
  946stack_goal_args(I, Arity, Goal) -->
  947    { I =< Arity,
  948      !,
  949      arg(I, Goal, A),
  950      I2 is I + 1
  951    },
  952    stack_goal_arg(A),
  953    (   { I2 =< Arity }
  954    ->  [ ', '-[] ],
  955        stack_goal_args(I2, Arity, Goal)
  956    ;   []
  957    ).
  958stack_goal_args(_, _, _) -->
  959    [].
  960
  961stack_goal_arg(A) -->
  962    { nonvar(A),
  963      A = [Len|T],
  964      !
  965    },
  966    (   {Len == cyclic_term}
  967    ->  [ '[cyclic list]'-[] ]
  968    ;   {T == []}
  969    ->  [ '[length:~D]'-[Len] ]
  970    ;   [ '[length:~D|~p]'-[Len, T] ]
  971    ).
  972stack_goal_arg(A) -->
  973    { nonvar(A),
  974      A = _/_,
  975      !
  976    },
  977    [ '<compound ~p>'-[A] ].
  978stack_goal_arg(A) -->
  979    [ '~p'-[A] ].
  980
  981resolve_overflow(fix) -->
  982    [].
  983resolve_overflow(enlarge) -->
  984    { current_prolog_flag(stack_limit, LimitBytes),
  985      NewLimit is LimitBytes * 2
  986    },
  987    [ nl,
  988      'Use the --stack_limit=size[KMG] command line option or'-[], nl,
  989      '?- set_prolog_flag(stack_limit, ~I). to double the limit.'-[NewLimit]
  990    ].
  991
  992
  993                 /*******************************
  994                 *        MAKE/AUTOLOAD         *
  995                 *******************************/
  996
  997prolog_message(make(reload(Files))) -->
  998    { length(Files, N)
  999    },
 1000    [ 'Make: reloading ~D files'-[N] ].
 1001prolog_message(make(done(_Files))) -->
 1002    [ 'Make: finished' ].
 1003prolog_message(make(library_index(Dir))) -->
 1004    [ 'Updating index for library ~w'-[Dir] ].
 1005prolog_message(autoload(Pred, File)) -->
 1006    thread_context,
 1007    [ 'autoloading ~p from ~w'-[Pred, File] ].
 1008prolog_message(autoload(read_index(Dir))) -->
 1009    [ 'Loading autoload index for ~w'-[Dir] ].
 1010prolog_message(autoload(disabled(Loaded))) -->
 1011    [ 'Disabled autoloading (loaded ~D files)'-[Loaded] ].
 1012prolog_message(autoload(already_defined(PI, From))) -->
 1013    [ ansi(code, '~p', [PI]) ],
 1014    (   { '$pi_head'(PI, Head),
 1015          predicate_property(Head, built_in)
 1016        }
 1017    ->  [' is a built-in predicate']
 1018    ;   [ ' is already imported from module ',
 1019          ansi(code, '~p', [From])
 1020        ]
 1021    ).
 1022
 1023swi_message(autoload(Msg)) -->
 1024    [ nl, '  ' ],
 1025    autoload_message(Msg).
 1026
 1027autoload_message(not_exported(PI, Spec, _FullFile, _Exports)) -->
 1028    [ ansi(code, '~w', [Spec]),
 1029      ' does not export ',
 1030      ansi(code, '~p', [PI])
 1031    ].
 1032autoload_message(no_file(Spec)) -->
 1033    [ ansi(code, '~p', [Spec]), ': No such file' ].
 1034
 1035
 1036                 /*******************************
 1037                 *       COMPILER WARNINGS      *
 1038                 *******************************/
 1039
 1040% print warnings about dubious code raised by the compiler.
 1041% TBD: pass in PC to produce exact error locations.
 1042
 1043prolog_message(compiler_warnings(Clause, Warnings0)) -->
 1044    {   print_goal_options(DefOptions),
 1045        (   prolog_load_context(variable_names, VarNames)
 1046        ->  warnings_with_named_vars(Warnings0, VarNames, Warnings),
 1047            Options = [variable_names(VarNames)|DefOptions]
 1048        ;   Options = DefOptions,
 1049            Warnings = Warnings0
 1050        )
 1051    },
 1052    compiler_warnings(Warnings, Clause, Options).
 1053
 1054warnings_with_named_vars([], _, []).
 1055warnings_with_named_vars([H|T0], VarNames, [H|T]) :-
 1056    term_variables(H, Vars),
 1057    '$member'(V1, Vars),
 1058    '$member'(_=V2, VarNames),
 1059    V1 == V2,
 1060    !,
 1061    warnings_with_named_vars(T0, VarNames, T).
 1062warnings_with_named_vars([_|T0], VarNames, T) :-
 1063    warnings_with_named_vars(T0, VarNames, T).
 1064
 1065
 1066compiler_warnings([], _, _) --> [].
 1067compiler_warnings([H|T], Clause, Options) -->
 1068    (   compiler_warning(H, Clause, Options)
 1069    ->  []
 1070    ;   [ 'Unknown compiler warning: ~W'-[H,Options] ]
 1071    ),
 1072    (   {T==[]}
 1073    ->  []
 1074    ;   [nl]
 1075    ),
 1076    compiler_warnings(T, Clause, Options).
 1077
 1078compiler_warning(eq_vv(A,B), _Clause, Options) -->
 1079    (   { A == B }
 1080    ->  [ 'Test is always true: ~W'-[A==B, Options] ]
 1081    ;   [ 'Test is always false: ~W'-[A==B, Options] ]
 1082    ).
 1083compiler_warning(eq_singleton(A,B), _Clause, Options) -->
 1084    [ 'Test is always false: ~W'-[A==B, Options] ].
 1085compiler_warning(neq_vv(A,B), _Clause, Options) -->
 1086    (   { A \== B }
 1087    ->  [ 'Test is always true: ~W'-[A\==B, Options] ]
 1088    ;   [ 'Test is always false: ~W'-[A\==B, Options] ]
 1089    ).
 1090compiler_warning(neq_singleton(A,B), _Clause, Options) -->
 1091    [ 'Test is always true: ~W'-[A\==B, Options] ].
 1092compiler_warning(unify_singleton(A,B), _Clause, Options) -->
 1093    [ 'Unified variable is not used: ~W'-[A=B, Options] ].
 1094compiler_warning(always(Bool, Pred, Arg), _Clause, Options) -->
 1095    { Goal =.. [Pred,Arg] },
 1096    [ 'Test is always ~w: ~W'-[Bool, Goal, Options] ].
 1097compiler_warning(unbalanced_var(V), _Clause, Options) -->
 1098    [ 'Variable not introduced in all branches: ~W'-[V, Options] ].
 1099compiler_warning(branch_singleton(V), _Clause, Options) -->
 1100    [ 'Singleton variable in branch: ~W'-[V, Options] ].
 1101compiler_warning(negation_singleton(V), _Clause, Options) -->
 1102    [ 'Singleton variable in \\+: ~W'-[V, Options] ].
 1103compiler_warning(multiton(V), _Clause, Options) -->
 1104    [ 'Singleton-marked variable appears more than once: ~W'-[V, Options] ].
 1105
 1106print_goal_options(
 1107    [ quoted(true),
 1108      portray(true)
 1109    ]).
 1110
 1111
 1112                 /*******************************
 1113                 *      TOPLEVEL MESSAGES       *
 1114                 *******************************/
 1115
 1116prolog_message(version) -->
 1117    { current_prolog_flag(version_git, Version) },
 1118    !,
 1119    [ '~w'-[Version] ].
 1120prolog_message(version) -->
 1121    { current_prolog_flag(version_data, swi(Major,Minor,Patch,Options))
 1122    },
 1123    (   { memberchk(tag(Tag), Options) }
 1124    ->  [ '~w.~w.~w-~w'-[Major, Minor, Patch, Tag] ]
 1125    ;   [ '~w.~w.~w'-[Major, Minor, Patch] ]
 1126    ).
 1127prolog_message(address_bits) -->
 1128    { current_prolog_flag(address_bits, Bits)
 1129    },
 1130    !,
 1131    [ '~d bits, '-[Bits] ].
 1132prolog_message(threads) -->
 1133    { current_prolog_flag(threads, true)
 1134    },
 1135    !,
 1136    [ 'threaded, ' ].
 1137prolog_message(threads) -->
 1138    [].
 1139prolog_message(copyright) -->
 1140    [ 'SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.', nl,
 1141      'Please run ?- license. for legal details.'
 1142    ].
 1143prolog_message(user_versions) -->
 1144    (   { findall(Msg, prolog:version_msg(Msg), Msgs),
 1145          Msgs \== []
 1146        }
 1147    ->  [nl],
 1148        user_version_messages(Msgs)
 1149    ;   []
 1150    ).
 1151prolog_message(documentaton) -->
 1152    [ 'For online help and background, visit https://www.swi-prolog.org', nl,
 1153      'For built-in help, use ?- help(Topic). or ?- apropos(Word).'
 1154    ].
 1155prolog_message(welcome) -->
 1156    [ 'Welcome to SWI-Prolog (' ],
 1157    prolog_message(threads),
 1158    prolog_message(address_bits),
 1159    ['version ' ],
 1160    prolog_message(version),
 1161    [ ')', nl ],
 1162    prolog_message(copyright),
 1163    [ nl ],
 1164    prolog_message(user_versions),
 1165    [ nl ],
 1166    prolog_message(documentaton),
 1167    [ nl, nl ].
 1168prolog_message(about) -->
 1169    [ 'SWI-Prolog version (' ],
 1170    prolog_message(threads),
 1171    prolog_message(address_bits),
 1172    ['version ' ],
 1173    prolog_message(version),
 1174    [ ')', nl ],
 1175    prolog_message(copyright).
 1176prolog_message(halt) -->
 1177    [ 'halt' ].
 1178prolog_message(break(begin, Level)) -->
 1179    [ 'Break level ~d'-[Level] ].
 1180prolog_message(break(end, Level)) -->
 1181    [ 'Exit break level ~d'-[Level] ].
 1182prolog_message(var_query(_)) -->
 1183    [ '... 1,000,000 ............ 10,000,000 years later', nl, nl,
 1184      '~t~8|>> 42 << (last release gives the question)'
 1185    ].
 1186prolog_message(close_on_abort(Stream)) -->
 1187    [ 'Abort: closed stream ~p'-[Stream] ].
 1188prolog_message(cancel_halt(Reason)) -->
 1189    [ 'Halt cancelled: ~p'-[Reason] ].
 1190prolog_message(on_error(halt(Status))) -->
 1191    { statistics(errors, Errors),
 1192      statistics(warnings, Warnings)
 1193    },
 1194    [ 'Halting with status ~w due to ~D errors and ~D warnings'-
 1195      [Status, Errors, Warnings] ].
 1196
 1197prolog_message(query(QueryResult)) -->
 1198    query_result(QueryResult).
 1199
 1200query_result(no) -->            % failure
 1201    [ ansi(truth(false), 'false.', []) ],
 1202    extra_line.
 1203query_result(yes(true, [])) -->      % prompt_alternatives_on: groundness
 1204    !,
 1205    [ ansi(truth(true), 'true.', []) ],
 1206    extra_line.
 1207query_result(yes(Delays, Residuals)) -->
 1208    result([], Delays, Residuals),
 1209    extra_line.
 1210query_result(done) -->          % user typed <CR>
 1211    extra_line.
 1212query_result(yes(Bindings, Delays, Residuals)) -->
 1213    result(Bindings, Delays, Residuals),
 1214    prompt(yes, Bindings, Delays, Residuals).
 1215query_result(more(Bindings, Delays, Residuals)) -->
 1216    result(Bindings, Delays, Residuals),
 1217    prompt(more, Bindings, Delays, Residuals).
 1218query_result(help) -->
 1219    [ nl, 'Actions:'-[], nl, nl,
 1220      '; (n, r, space, TAB): redo    t:          trace & redo'-[], nl,
 1221      'b:                    break   c (a, RET): exit'-[], nl,
 1222      'w:                    write   p           print'-[], nl,
 1223      'h (?):                help'-[],
 1224      nl, nl
 1225    ].
 1226query_result(action) -->
 1227    [ 'Action? '-[], flush ].
 1228query_result(confirm) -->
 1229    [ 'Please answer \'y\' or \'n\'? '-[], flush ].
 1230query_result(eof) -->
 1231    [ nl ].
 1232query_result(toplevel_open_line) -->
 1233    [].
 1234
 1235prompt(Answer, [], true, []-[]) -->
 1236    !,
 1237    prompt(Answer, empty).
 1238prompt(Answer, _, _, _) -->
 1239    !,
 1240    prompt(Answer, non_empty).
 1241
 1242prompt(yes, empty) -->
 1243    !,
 1244    [ ansi(truth(true), 'true.', []) ],
 1245    extra_line.
 1246prompt(yes, _) -->
 1247    !,
 1248    [ full_stop ],
 1249    extra_line.
 1250prompt(more, empty) -->
 1251    !,
 1252    [ ansi(truth(true), 'true ', []), flush ].
 1253prompt(more, _) -->
 1254    !,
 1255    [ ' '-[], flush ].
 1256
 1257result(Bindings, Delays, Residuals) -->
 1258    { current_prolog_flag(answer_write_options, Options0),
 1259      Options = [partial(true)|Options0],
 1260      GOptions = [priority(999)|Options0]
 1261    },
 1262    wfs_residual_program(Delays, GOptions),
 1263    bindings(Bindings, [priority(699)|Options]),
 1264    (   {Residuals == []-[]}
 1265    ->  bind_delays_sep(Bindings, Delays),
 1266        delays(Delays, GOptions)
 1267    ;   bind_res_sep(Bindings, Residuals),
 1268        residuals(Residuals, GOptions),
 1269        (   {Delays == true}
 1270        ->  []
 1271        ;   [','-[], nl],
 1272            delays(Delays, GOptions)
 1273        )
 1274    ).
 1275
 1276bindings([], _) -->
 1277    [].
 1278bindings([binding(Names,Skel,Subst)|T], Options) -->
 1279    { '$last'(Names, Name) },
 1280    var_names(Names), value(Name, Skel, Subst, Options),
 1281    (   { T \== [] }
 1282    ->  [ ','-[], nl ],
 1283        bindings(T, Options)
 1284    ;   []
 1285    ).
 1286
 1287var_names([Name]) -->
 1288    !,
 1289    [ '~w = '-[Name] ].
 1290var_names([Name1,Name2|T]) -->
 1291    !,
 1292    [ '~w = ~w, '-[Name1, Name2] ],
 1293    var_names([Name2|T]).
 1294
 1295
 1296value(Name, Skel, Subst, Options) -->
 1297    (   { var(Skel), Subst = [Skel=S] }
 1298    ->  { Skel = '$VAR'(Name) },
 1299        [ '~W'-[S, Options] ]
 1300    ;   [ '~W'-[Skel, Options] ],
 1301        substitution(Subst, Options)
 1302    ).
 1303
 1304substitution([], _) --> !.
 1305substitution([N=V|T], Options) -->
 1306    [ ', ', ansi(comment, '% where', []), nl,
 1307      '    ~w = ~W'-[N,V,Options] ],
 1308    substitutions(T, Options).
 1309
 1310substitutions([], _) --> [].
 1311substitutions([N=V|T], Options) -->
 1312    [ ','-[], nl, '    ~w = ~W'-[N,V,Options] ],
 1313    substitutions(T, Options).
 1314
 1315
 1316residuals(Normal-Hidden, Options) -->
 1317    residuals1(Normal, Options),
 1318    bind_res_sep(Normal, Hidden),
 1319    (   {Hidden == []}
 1320    ->  []
 1321    ;   [ansi(comment, '% with pending residual goals', []), nl]
 1322    ),
 1323    residuals1(Hidden, Options).
 1324
 1325residuals1([], _) -->
 1326    [].
 1327residuals1([G|Gs], Options) -->
 1328    (   { Gs \== [] }
 1329    ->  [ '~W,'-[G, Options], nl ],
 1330        residuals1(Gs, Options)
 1331    ;   [ '~W'-[G, Options] ]
 1332    ).
 1333
 1334wfs_residual_program(true, _Options) -->
 1335    !.
 1336wfs_residual_program(Goal, _Options) -->
 1337    { current_prolog_flag(toplevel_list_wfs_residual_program, true),
 1338      '$current_typein_module'(TypeIn),
 1339      (   current_predicate(delays_residual_program/2)
 1340      ->  true
 1341      ;   use_module(library(wfs), [delays_residual_program/2])
 1342      ),
 1343      delays_residual_program(TypeIn:Goal, TypeIn:Program),
 1344      Program \== []
 1345    },
 1346    !,
 1347    [ ansi(comment, '% WFS residual program', []), nl ],
 1348    [ ansi(wfs(residual_program), '~@', ['$messages':list_clauses(Program)]) ].
 1349wfs_residual_program(_, _) --> [].
 1350
 1351delays(true, _Options) -->
 1352    !.
 1353delays(Goal, Options) -->
 1354    { current_prolog_flag(toplevel_list_wfs_residual_program, true)
 1355    },
 1356    !,
 1357    [ ansi(truth(undefined), '~W', [Goal, Options]) ].
 1358delays(_, _Options) -->
 1359    [ ansi(truth(undefined), undefined, []) ].
 1360
 1361:- public list_clauses/1. 1362
 1363list_clauses([]).
 1364list_clauses([H|T]) :-
 1365    (   system_undefined(H)
 1366    ->  true
 1367    ;   portray_clause(user_output, H, [indent(4)])
 1368    ),
 1369    list_clauses(T).
 1370
 1371system_undefined((undefined :- tnot(undefined))).
 1372system_undefined((answer_count_restraint :- tnot(answer_count_restraint))).
 1373system_undefined((radial_restraint :- tnot(radial_restraint))).
 1374
 1375bind_res_sep(_, []) --> !.
 1376bind_res_sep(_, []-[]) --> !.
 1377bind_res_sep([], _) --> !.
 1378bind_res_sep(_, _) --> [','-[], nl].
 1379
 1380bind_delays_sep([], _) --> !.
 1381bind_delays_sep(_, true) --> !.
 1382bind_delays_sep(_, _) --> [','-[], nl].
 1383
 1384extra_line -->
 1385    { current_prolog_flag(toplevel_extra_white_line, true) },
 1386    !,
 1387    ['~N'-[]].
 1388extra_line -->
 1389    [].
 1390
 1391prolog_message(if_tty(Message)) -->
 1392    (   {current_prolog_flag(tty_control, true)}
 1393    ->  [ at_same_line | Message ]
 1394    ;   []
 1395    ).
 1396prolog_message(halt(Reason)) -->
 1397    [ '~w: halt'-[Reason] ].
 1398prolog_message(no_action(Char)) -->
 1399    [ 'Unknown action: ~c (h for help)'-[Char], nl ].
 1400
 1401prolog_message(history(help(Show, Help))) -->
 1402    [ 'History Commands:', nl,
 1403      '    !!.              Repeat last query', nl,
 1404      '    !nr.             Repeat query numbered <nr>', nl,
 1405      '    !str.            Repeat last query starting with <str>', nl,
 1406      '    !?str.           Repeat last query holding <str>', nl,
 1407      '    ^old^new.        Substitute <old> into <new> of last query', nl,
 1408      '    !nr^old^new.     Substitute in query numbered <nr>', nl,
 1409      '    !str^old^new.    Substitute in query starting with <str>', nl,
 1410      '    !?str^old^new.   Substitute in query holding <str>', nl,
 1411      '    ~w.~21|Show history list'-[Show], nl,
 1412      '    ~w.~21|Show this list'-[Help], nl, nl
 1413    ].
 1414prolog_message(history(no_event)) -->
 1415    [ '! No such event' ].
 1416prolog_message(history(bad_substitution)) -->
 1417    [ '! Bad substitution' ].
 1418prolog_message(history(expanded(Event))) -->
 1419    [ '~w.'-[Event] ].
 1420prolog_message(history(history(Events))) -->
 1421    history_events(Events).
 1422
 1423history_events([]) -->
 1424    [].
 1425history_events([Nr/Event|T]) -->
 1426    [ '~t~w   ~8|~W~W'-[ Nr,
 1427                         Event, [partial(true)],
 1428                         '.', [partial(true)]
 1429                       ],
 1430      nl
 1431    ],
 1432    history_events(T).
 1433
 1434
 1435user_version_messages([]) --> [].
 1436user_version_messages([H|T]) -->
 1437    user_version_message(H),
 1438    user_version_messages(T).
 user_version_message(+Term)
 1442user_version_message(Term) -->
 1443    translate_message2(Term), !, [nl].
 1444user_version_message(Atom) -->
 1445    [ '~w'-[Atom], nl ].
 1446
 1447
 1448                 /*******************************
 1449                 *       DEBUGGER MESSAGES      *
 1450                 *******************************/
 1451
 1452prolog_message(spy(Head)) -->
 1453    { goal_to_predicate_indicator(Head, Pred)
 1454    },
 1455    [ 'Spy point on ~p'-[Pred] ].
 1456prolog_message(nospy(Head)) -->
 1457    { goal_to_predicate_indicator(Head, Pred)
 1458    },
 1459    [ 'Spy point removed from ~p'-[Pred] ].
 1460prolog_message(trace_mode(OnOff)) -->
 1461    [ 'Trace mode switched to ~w'-[OnOff] ].
 1462prolog_message(debug_mode(OnOff)) -->
 1463    [ 'Debug mode switched to ~w'-[OnOff] ].
 1464prolog_message(debugging(OnOff)) -->
 1465    [ 'Debug mode is ~w'-[OnOff] ].
 1466prolog_message(spying([])) -->
 1467    !,
 1468    [ 'No spy points' ].
 1469prolog_message(spying(Heads)) -->
 1470    [ 'Spy points (see spy/1) on:', nl ],
 1471    predicate_list(Heads).
 1472prolog_message(trace(Head, [])) -->
 1473    !,
 1474    { goal_to_predicate_indicator(Head, Pred)
 1475    },
 1476    [ '        ~p: Not tracing'-[Pred], nl].
 1477prolog_message(trace(Head, Ports)) -->
 1478    { goal_to_predicate_indicator(Head, Pred)
 1479    },
 1480    [ '        ~p: ~w'-[Pred, Ports], nl].
 1481prolog_message(tracing([])) -->
 1482    !,
 1483    [ 'No traced predicates (see trace/1)' ].
 1484prolog_message(tracing(Heads)) -->
 1485    [ 'Trace points (see trace/1) on:', nl ],
 1486    tracing_list(Heads).
 1487
 1488predicate_list([]) -->                  % TBD: Share with dwim, etc.
 1489    [].
 1490predicate_list([H|T]) -->
 1491    { goal_to_predicate_indicator(H, Pred)
 1492    },
 1493    [ '        ~p'-[Pred], nl],
 1494    predicate_list(T).
 1495
 1496tracing_list([]) -->
 1497    [].
 1498tracing_list([trace(Head, Ports)|T]) -->
 1499    translate_message(trace(Head, Ports)),
 1500    tracing_list(T).
 1501
 1502prolog_message(frame(Frame, backtrace, _PC)) -->
 1503    !,
 1504    { prolog_frame_attribute(Frame, level, Level)
 1505    },
 1506    [ ansi(frame(level), '~t[~D] ~10|', [Level]) ],
 1507    frame_context(Frame),
 1508    frame_goal(Frame).
 1509prolog_message(frame(Frame, choice, PC)) -->
 1510    !,
 1511    prolog_message(frame(Frame, backtrace, PC)).
 1512prolog_message(frame(_, cut_call, _)) --> !, [].
 1513prolog_message(frame(Goal, trace(Port))) -->
 1514    !,
 1515    thread_context,
 1516    [ ' T ' ],
 1517    port(Port),
 1518    goal(Goal).
 1519prolog_message(frame(Goal, trace(Port, Id))) -->
 1520    !,
 1521    thread_context,
 1522    [ ' T ' ],
 1523    port(Port, Id),
 1524    goal(Goal).
 1525prolog_message(frame(Frame, Port, _PC)) -->
 1526    frame_flags(Frame),
 1527    port(Port),
 1528    frame_level(Frame),
 1529    frame_context(Frame),
 1530    frame_depth_limit(Port, Frame),
 1531    frame_goal(Frame),
 1532    [ flush ].
 1533
 1534frame_goal(Frame) -->
 1535    { prolog_frame_attribute(Frame, goal, Goal)
 1536    },
 1537    goal(Goal).
 1538
 1539goal(Goal0) -->
 1540    { clean_goal(Goal0, Goal),
 1541      current_prolog_flag(debugger_write_options, Options)
 1542    },
 1543    [ '~W'-[Goal, Options] ].
 1544
 1545frame_level(Frame) -->
 1546    { prolog_frame_attribute(Frame, level, Level)
 1547    },
 1548    [ '(~D) '-[Level] ].
 1549
 1550frame_context(Frame) -->
 1551    (   { current_prolog_flag(debugger_show_context, true),
 1552          prolog_frame_attribute(Frame, context_module, Context)
 1553        }
 1554    ->  [ '[~w] '-[Context] ]
 1555    ;   []
 1556    ).
 1557
 1558frame_depth_limit(fail, Frame) -->
 1559    { prolog_frame_attribute(Frame, depth_limit_exceeded, true)
 1560    },
 1561    !,
 1562    [ '[depth-limit exceeded] ' ].
 1563frame_depth_limit(_, _) -->
 1564    [].
 1565
 1566frame_flags(Frame) -->
 1567    { prolog_frame_attribute(Frame, goal, Goal),
 1568      (   predicate_property(Goal, transparent)
 1569      ->  T = '^'
 1570      ;   T = ' '
 1571      ),
 1572      (   predicate_property(Goal, spying)
 1573      ->  S = '*'
 1574      ;   S = ' '
 1575      )
 1576    },
 1577    [ '~w~w '-[T, S] ].
 1578
 1579% trace/1,2 context handling
 1580port(Port, _Id-Level) -->
 1581    [ '[~d] '-Level ],
 1582    port(Port).
 1583
 1584port(Port) -->
 1585    { port_name(Port, Name)
 1586    },
 1587    !,
 1588    [ ansi(port(Port), '~w: ', [Name]) ].
 1589
 1590port_name(call,      'Call').
 1591port_name(exit,      'Exit').
 1592port_name(fail,      'Fail').
 1593port_name(redo,      'Redo').
 1594port_name(unify,     'Unify').
 1595port_name(exception, 'Exception').
 1596
 1597clean_goal(M:Goal, Goal) :-
 1598    hidden_module(M),
 1599    !.
 1600clean_goal(M:Goal, Goal) :-
 1601    predicate_property(M:Goal, built_in),
 1602    !.
 1603clean_goal(Goal, Goal).
 1604
 1605
 1606                 /*******************************
 1607                 *        COMPATIBILITY         *
 1608                 *******************************/
 1609
 1610prolog_message(compatibility(renamed(Old, New))) -->
 1611    [ 'The predicate ~p has been renamed to ~p.'-[Old, New], nl,
 1612      'Please update your sources for compatibility with future versions.'
 1613    ].
 1614
 1615
 1616                 /*******************************
 1617                 *            THREADS           *
 1618                 *******************************/
 1619
 1620prolog_message(abnormal_thread_completion(Goal, exception(Ex))) -->
 1621    !,
 1622    [ 'Thread running "~p" died on exception: '-[Goal] ],
 1623    translate_message(Ex).
 1624prolog_message(abnormal_thread_completion(Goal, fail)) -->
 1625    [ 'Thread running "~p" died due to failure'-[Goal] ].
 1626prolog_message(threads_not_died(Running)) -->
 1627    [ 'The following threads wouldn\'t die: ~p'-[Running] ].
 1628
 1629
 1630                 /*******************************
 1631                 *             PACKS            *
 1632                 *******************************/
 1633
 1634prolog_message(pack(attached(Pack, BaseDir))) -->
 1635    [ 'Attached package ~w at ~q'-[Pack, BaseDir] ].
 1636prolog_message(pack(duplicate(Entry, OldDir, Dir))) -->
 1637    [ 'Package ~w already attached at ~q.'-[Entry,OldDir], nl,
 1638      '\tIgnoring version from ~q'- [Dir]
 1639    ].
 1640prolog_message(pack(no_arch(Entry, Arch))) -->
 1641    [ 'Package ~w: no binary for architecture ~w'-[Entry, Arch] ].
 1642
 1643                 /*******************************
 1644                 *             MISC             *
 1645                 *******************************/
 1646
 1647prolog_message(null_byte_in_path(Component)) -->
 1648    [ '0-byte in PATH component: ~p (skipped directory)'-[Component] ].
 1649prolog_message(invalid_tmp_dir(Dir, Reason)) -->
 1650    [ 'Cannot use ~p as temporary file directory: ~w'-[Dir, Reason] ].
 1651prolog_message(ambiguous_stream_pair(Pair)) -->
 1652    [ 'Ambiguous operation on stream pair ~p'-[Pair] ].
 1653prolog_message(backcomp(init_file_moved(FoundFile))) -->
 1654    { absolute_file_name(app_config('init.pl'), InitFile,
 1655                         [ file_errors(fail)
 1656                         ])
 1657    },
 1658    [ 'The location of the config file has moved'-[], nl,
 1659      '  from "~w"'-[FoundFile], nl,
 1660      '  to   "~w"'-[InitFile], nl,
 1661      '  See https://www.swi-prolog.org/modified/config-files.html'-[]
 1662    ].
 1663
 1664		 /*******************************
 1665		 *          DEPRECATED		*
 1666		 *******************************/
 1667
 1668deprecated(Term) -->
 1669    prolog:deprecated(Term),
 1670    !.
 1671deprecated(set_prolog_stack(_Stack,limit)) -->
 1672    [ 'set_prolog_stack/2: limit(Size) sets the combined limit.'-[], nl,
 1673      'See https://www.swi-prolog.org/changes/stack-limit.html'
 1674    ].
 1675
 1676		 /*******************************
 1677		 *           TRIPWIRES		*
 1678		 *******************************/
 1679
 1680tripwire_message(Wire, Context) -->
 1681    [ 'Trapped tripwire ~w for '-[Wire] ],
 1682    tripwire_context(Wire, Context).
 1683
 1684tripwire_context(_, ATrie) -->
 1685    { '$is_answer_trie'(ATrie, _),
 1686      !,
 1687      '$tabling':atrie_goal(ATrie, QGoal),
 1688      user_predicate_indicator(QGoal, Goal)
 1689    },
 1690    [ '~p'-[Goal] ].
 1691tripwire_context(_, Ctx) -->
 1692    [ '~p'-[Ctx] ].
 1693
 1694
 1695		 /*******************************
 1696		 *        DEFAULT THEME		*
 1697		 *******************************/
 1698
 1699:- public default_theme/2. 1700
 1701default_theme(var,                    [fg(red)]).
 1702default_theme(code,                   [fg(blue)]).
 1703default_theme(comment,                [fg(green)]).
 1704default_theme(warning,                [fg(red)]).
 1705default_theme(error,                  [bold, fg(red)]).
 1706default_theme(truth(false),           [bold, fg(red)]).
 1707default_theme(truth(true),            [bold]).
 1708default_theme(truth(undefined),       [bold, fg(cyan)]).
 1709default_theme(wfs(residual_program),  [fg(cyan)]).
 1710default_theme(frame(level),           [bold]).
 1711default_theme(port(call),             [bold, fg(green)]).
 1712default_theme(port(exit),             [bold, fg(green)]).
 1713default_theme(port(fail),             [bold, fg(red)]).
 1714default_theme(port(redo),             [bold, fg(yellow)]).
 1715default_theme(port(unify),            [bold, fg(blue)]).
 1716default_theme(port(exception),        [bold, fg(magenta)]).
 1717default_theme(message(informational), [fg(green)]).
 1718default_theme(message(information),   [fg(green)]).
 1719default_theme(message(debug(_)),      [fg(blue)]).
 1720default_theme(message(Level),         Attrs) :-
 1721    nonvar(Level),
 1722    default_theme(Level, Attrs).
 1723
 1724
 1725                 /*******************************
 1726                 *      PRINTING MESSAGES       *
 1727                 *******************************/
 1728
 1729:- multifile
 1730    user:message_hook/3,
 1731    prolog:message_prefix_hook/2. 1732:- dynamic
 1733    user:message_hook/3,
 1734    prolog:message_prefix_hook/2. 1735:- thread_local
 1736    user:thread_message_hook/3. 1737:- '$hide'((push_msg/1,pop_msg/0)).
 print_message(+Kind, +Term)
Print an error message using a term as generated by the exception system.
 1744print_message(Level, Term) :-
 1745    setup_call_cleanup(
 1746        push_msg(Term),
 1747        print_message_guarded(Level, Term),
 1748        pop_msg),
 1749    !.
 1750print_message(Level, Term) :-
 1751    (   Level \== silent
 1752    ->  format(user_error, 'Recursive ~w message: ~q~n', [Level, Term])
 1753    ;   true
 1754    ).
 1755
 1756push_msg(Term) :-
 1757    nb_current('$inprint_message', Messages),
 1758    !,
 1759    \+ ( '$member'(Msg, Messages),
 1760         Msg =@= Term
 1761       ),
 1762    b_setval('$inprint_message', [Term|Messages]).
 1763push_msg(Term) :-
 1764    b_setval('$inprint_message', [Term]).
 1765
 1766pop_msg :-
 1767    (   nb_current('$inprint_message', [_|Messages]),
 1768        Messages \== []
 1769    ->  b_setval('$inprint_message', Messages)
 1770    ;   nb_delete('$inprint_message'),              % delete history
 1771        b_setval('$inprint_message', [])
 1772    ).
 1773
 1774print_message_guarded(Level, Term) :-
 1775    (   must_print(Level, Term)
 1776    ->  (   translate_message(Term, Lines, [])
 1777        ->  (   nonvar(Term),
 1778                (   notrace(user:thread_message_hook(Term, Level, Lines))
 1779                ->  true
 1780                ;   notrace(user:message_hook(Term, Level, Lines))
 1781                )
 1782            ->  true
 1783            ;   '$inc_message_count'(Level),
 1784                print_system_message(Term, Level, Lines),
 1785                maybe_halt_on_error(Level)
 1786            )
 1787        )
 1788    ;   true
 1789    ).
 1790
 1791maybe_halt_on_error(error) :-
 1792    current_prolog_flag(on_error, halt),
 1793    !,
 1794    halt(1).
 1795maybe_halt_on_error(warning) :-
 1796    current_prolog_flag(on_warning, halt),
 1797    !,
 1798    halt(1).
 1799maybe_halt_on_error(_).
 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.
 1809print_system_message(_, silent, _) :- !.
 1810print_system_message(_, informational, _) :-
 1811    current_prolog_flag(verbose, silent),
 1812    !.
 1813print_system_message(_, banner, _) :-
 1814    current_prolog_flag(verbose, silent),
 1815    !.
 1816print_system_message(_, _, []) :- !.
 1817print_system_message(Term, Kind, Lines) :-
 1818    catch(flush_output(user_output), _, true),      % may not exist
 1819    source_location(File, Line),
 1820    Term \= error(syntax_error(_), _),
 1821    msg_property(Kind, location_prefix(File:Line, LocPrefix, LinePrefix)),
 1822    !,
 1823    insert_prefix(Lines, LinePrefix, Ctx, PrefixLines),
 1824    '$append'([ begin(Kind, Ctx),
 1825                LocPrefix,
 1826                nl
 1827              | PrefixLines
 1828              ],
 1829              [ end(Ctx)
 1830              ],
 1831              AllLines),
 1832    msg_property(Kind, stream(Stream)),
 1833    ignore(stream_property(Stream, position(Pos))),
 1834    print_message_lines(Stream, AllLines),
 1835    (   \+ stream_property(Stream, position(Pos)),
 1836        msg_property(Kind, wait(Wait)),
 1837        Wait > 0
 1838    ->  sleep(Wait)
 1839    ;   true
 1840    ).
 1841print_system_message(_, Kind, Lines) :-
 1842    msg_property(Kind, stream(Stream)),
 1843    print_message_lines(Stream, kind(Kind), Lines).
 1844
 1845:- multifile
 1846    user:message_property/2. 1847
 1848msg_property(Kind, Property) :-
 1849    notrace(user:message_property(Kind, Property)),
 1850    !.
 1851msg_property(Kind, prefix(Prefix)) :-
 1852    msg_prefix(Kind, Prefix),
 1853    !.
 1854msg_property(_, prefix('~N')) :- !.
 1855msg_property(query, stream(user_output)) :- !.
 1856msg_property(_, stream(user_error)) :- !.
 1857msg_property(error,
 1858             location_prefix(File:Line,
 1859                             '~NERROR: ~w:~d:'-[File,Line],
 1860                             '~NERROR:    ')) :- !.
 1861msg_property(warning,
 1862             location_prefix(File:Line,
 1863                             '~NWarning: ~w:~d:'-[File,Line],
 1864                             '~NWarning:    ')) :- !.
 1865msg_property(error,   wait(0.1)) :- !.
 1866
 1867msg_prefix(debug(_), Prefix) :-
 1868    msg_context('~N% ', Prefix).
 1869msg_prefix(warning, Prefix) :-
 1870    msg_context('~NWarning: ', Prefix).
 1871msg_prefix(error, Prefix) :-
 1872    msg_context('~NERROR: ', Prefix).
 1873msg_prefix(informational, '~N% ').
 1874msg_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.

 1888msg_context(Prefix0, Prefix) :-
 1889    current_prolog_flag(message_context, Context),
 1890    is_list(Context),
 1891    !,
 1892    add_message_context(Context, Prefix0, Prefix).
 1893msg_context(Prefix, Prefix).
 1894
 1895add_message_context([], Prefix, Prefix).
 1896add_message_context([H|T], Prefix0, Prefix) :-
 1897    (   add_message_context1(H, Prefix0, Prefix1)
 1898    ->  true
 1899    ;   Prefix1 = Prefix0
 1900    ),
 1901    add_message_context(T, Prefix1, Prefix).
 1902
 1903add_message_context1(Context, Prefix0, Prefix) :-
 1904    prolog:message_prefix_hook(Context, Extra),
 1905    atomics_to_string([Prefix0, Extra, ' '], Prefix).
 1906add_message_context1(time, Prefix0, Prefix) :-
 1907    get_time(Now),
 1908    format_time(string(S), '%T.%3f ', Now),
 1909    string_concat(Prefix0, S, Prefix).
 1910add_message_context1(time(Format), Prefix0, Prefix) :-
 1911    get_time(Now),
 1912    format_time(string(S), Format, Now),
 1913    atomics_to_string([Prefix0, S, ' '], Prefix).
 1914add_message_context1(thread, Prefix0, Prefix) :-
 1915    thread_self(Id0),
 1916    Id0 \== main,
 1917    !,
 1918    (   atom(Id0)
 1919    ->  Id = Id0
 1920    ;   thread_property(Id0, id(Id))
 1921    ),
 1922    format(string(Prefix), '~w[Thread ~w] ', [Prefix0, Id]).
 print_message_lines(+Stream, +PrefixOrKind, +Lines)
Quintus compatibility predicate to print message lines using a prefix.
 1929print_message_lines(Stream, kind(Kind), Lines) :-
 1930    !,
 1931    msg_property(Kind, prefix(Prefix)),
 1932    insert_prefix(Lines, Prefix, Ctx, PrefixLines),
 1933    '$append'([ begin(Kind, Ctx)
 1934              | PrefixLines
 1935              ],
 1936              [ end(Ctx)
 1937              ],
 1938              AllLines),
 1939    print_message_lines(Stream, AllLines).
 1940print_message_lines(Stream, Prefix, Lines) :-
 1941    insert_prefix(Lines, Prefix, _, PrefixLines),
 1942    print_message_lines(Stream, PrefixLines).
 insert_prefix(+Lines, +Prefix, +Ctx, -PrefixedLines)
 1946insert_prefix([at_same_line|Lines0], Prefix, Ctx, Lines) :-
 1947    !,
 1948    prefix_nl(Lines0, Prefix, Ctx, Lines).
 1949insert_prefix(Lines0, Prefix, Ctx, [prefix(Prefix)|Lines]) :-
 1950    prefix_nl(Lines0, Prefix, Ctx, Lines).
 1951
 1952prefix_nl([], _, _, [nl]).
 1953prefix_nl([nl], _, _, [nl]) :- !.
 1954prefix_nl([flush], _, _, [flush]) :- !.
 1955prefix_nl([nl|T0], Prefix, Ctx, [nl, prefix(Prefix)|T]) :-
 1956    !,
 1957    prefix_nl(T0, Prefix, Ctx, T).
 1958prefix_nl([ansi(Attrs,Fmt,Args)|T0], Prefix, Ctx,
 1959          [ansi(Attrs,Fmt,Args,Ctx)|T]) :-
 1960    !,
 1961    prefix_nl(T0, Prefix, Ctx, T).
 1962prefix_nl([H|T0], Prefix, Ctx, [H|T]) :-
 1963    prefix_nl(T0, Prefix, Ctx, T).
 print_message_lines(+Stream, +Lines)
 1967print_message_lines(Stream, Lines) :-
 1968    with_output_to(
 1969        Stream,
 1970        notrace(print_message_lines_guarded(current_output, Lines))).
 1971
 1972print_message_lines_guarded(_, []) :- !.
 1973print_message_lines_guarded(S, [H|T]) :-
 1974    line_element(S, H),
 1975    print_message_lines_guarded(S, T).
 1976
 1977line_element(S, E) :-
 1978    prolog:message_line_element(S, E),
 1979    !.
 1980line_element(S, full_stop) :-
 1981    !,
 1982    '$put_token'(S, '.').           % insert space if needed.
 1983line_element(S, nl) :-
 1984    !,
 1985    nl(S).
 1986line_element(S, prefix(Fmt-Args)) :-
 1987    !,
 1988    safe_format(S, Fmt, Args).
 1989line_element(S, prefix(Fmt)) :-
 1990    !,
 1991    safe_format(S, Fmt, []).
 1992line_element(S, flush) :-
 1993    !,
 1994    flush_output(S).
 1995line_element(S, Fmt-Args) :-
 1996    !,
 1997    safe_format(S, Fmt, Args).
 1998line_element(S, ansi(_, Fmt, Args)) :-
 1999    !,
 2000    safe_format(S, Fmt, Args).
 2001line_element(S, ansi(_, Fmt, Args, _Ctx)) :-
 2002    !,
 2003    safe_format(S, Fmt, Args).
 2004line_element(_, begin(_Level, _Ctx)) :- !.
 2005line_element(_, end(_Ctx)) :- !.
 2006line_element(S, Fmt) :-
 2007    safe_format(S, Fmt, []).
 safe_format(+Stream, +Format, +Args) is det
 2011safe_format(S, Fmt, Args) :-
 2012    E = error(_,_),
 2013    catch(format(S,Fmt,Args), E,
 2014          format_failed(S,Fmt,Args,E)).
 2015
 2016format_failed(S, _Fmt, _Args, E) :-
 2017    E = error(io_error(_,S),_),
 2018    !,
 2019    throw(E).
 2020format_failed(S, Fmt, Args, error(E,_)) :-
 2021    format(S, '~N    [[ EXCEPTION while printing message ~q~n\c
 2022                        ~7|with arguments ~W:~n\c
 2023                        ~7|raised: ~W~n~4|]]~n',
 2024           [ Fmt,
 2025             Args, [quoted(true), max_depth(10)],
 2026             E, [quoted(true), max_depth(10)]
 2027           ]).
 message_to_string(+Term, -String)
Translate an error term into a string
 2033message_to_string(Term, Str) :-
 2034    translate_message(Term, Actions, []),
 2035    !,
 2036    actions_to_format(Actions, Fmt, Args),
 2037    format(string(Str), Fmt, Args).
 2038
 2039actions_to_format([], '', []) :- !.
 2040actions_to_format([nl], '', []) :- !.
 2041actions_to_format([Term, nl], Fmt, Args) :-
 2042    !,
 2043    actions_to_format([Term], Fmt, Args).
 2044actions_to_format([nl|T], Fmt, Args) :-
 2045    !,
 2046    actions_to_format(T, Fmt0, Args),
 2047    atom_concat('~n', Fmt0, Fmt).
 2048actions_to_format([ansi(_Attrs, Fmt0, Args0)|Tail], Fmt, Args) :-
 2049    !,
 2050    actions_to_format(Tail, Fmt1, Args1),
 2051    atom_concat(Fmt0, Fmt1, Fmt),
 2052    append_args(Args0, Args1, Args).
 2053actions_to_format([Fmt0-Args0|Tail], Fmt, Args) :-
 2054    !,
 2055    actions_to_format(Tail, Fmt1, Args1),
 2056    atom_concat(Fmt0, Fmt1, Fmt),
 2057    append_args(Args0, Args1, Args).
 2058actions_to_format([Skip|T], Fmt, Args) :-
 2059    action_skip(Skip),
 2060    !,
 2061    actions_to_format(T, Fmt, Args).
 2062actions_to_format([Term|Tail], Fmt, Args) :-
 2063    atomic(Term),
 2064    !,
 2065    actions_to_format(Tail, Fmt1, Args),
 2066    atom_concat(Term, Fmt1, Fmt).
 2067actions_to_format([Term|Tail], Fmt, Args) :-
 2068    actions_to_format(Tail, Fmt1, Args1),
 2069    atom_concat('~w', Fmt1, Fmt),
 2070    append_args([Term], Args1, Args).
 2071
 2072action_skip(at_same_line).
 2073action_skip(flush).
 2074action_skip(begin(_Level, _Ctx)).
 2075action_skip(end(_Ctx)).
 2076
 2077append_args(M:Args0, Args1, M:Args) :-
 2078    !,
 2079    strip_module(Args1, _, A1),
 2080    '$append'(Args0, A1, Args).
 2081append_args(Args0, Args1, Args) :-
 2082    strip_module(Args1, _, A1),
 2083    '$append'(Args0, A1, Args).
 2084
 2085
 2086                 /*******************************
 2087                 *    MESSAGES TO PRINT ONCE    *
 2088                 *******************************/
 2089
 2090:- dynamic
 2091    printed/2.
 print_once(Message, Level)
True for messages that must be printed only once.
 2097print_once(compatibility(_), _).
 2098print_once(null_byte_in_path(_), _).
 2099print_once(deprecated(_), _).
 must_print(+Level, +Message)
True if the message must be printed.
 2105must_print(Level, Message) :-
 2106    nonvar(Message),
 2107    print_once(Message, Level),
 2108    !,
 2109    \+ printed(Message, Level),
 2110    assert(printed(Message, Level)).
 2111must_print(_, _)