View source with formatted 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% Lang, Term versions
   59:- multifile
   60    prolog:message//2,              % entire message
   61    prolog:error_message//2,        % 1-st argument of error term
   62    prolog:message_context//2,      % Context of error messages
   63    prolog:message_location//2,	    % (File) location of error messages
   64    prolog:deprecated//2.	    % Deprecated features
   65:- '$hide'((
   66    prolog:message//2,
   67    prolog:error_message//2,
   68    prolog:message_context//2,
   69    prolog:deprecated//2,
   70    prolog:message_location//2)).   71
   72:- discontiguous
   73    prolog_message/3.   74
   75:- public
   76    translate_message//1,           % +Message (deprecated)
   77    prolog:translate_message//1.    % +Message
   78
   79:- create_prolog_flag(message_context, [thread], []).   80
   81%!  translate_message(+Term)// is det.
   82%
   83%   Translate a message Term into message lines. The produced lines
   84%   is a list of
   85%
   86%       - nl
   87%         Emit a newline
   88%       - Fmt-Args
   89%         Emit the result of format(Fmt, Args)
   90%       - Fmt
   91%         Emit the result of format(Fmt)
   92%       - ansi(Code, Fmt, Args)
   93%         Use ansi_format/3 for color output.
   94%       - flush
   95%         Used only as last element of the list.   Simply flush the
   96%         output instead of producing a final newline.
   97%       - at_same_line
   98%         Start the messages at the same line (instead of using ~N)
   99%
  100%   @deprecated  Use  code  for   message    translation   should   call
  101%   prolog:translate_message//1.
  102
  103prolog:translate_message(Term) -->
  104    translate_message(Term).
  105
  106%!  translate_message(+Term)// is det.
  107%
  108%   Translate a message term into  message   lines.  This version may be
  109%   called from user and library definitions for message translation.
  110
  111translate_message(Term) -->
  112    { nonvar(Term) },
  113    (   { message_lang(Lang) },
  114        prolog:message(Lang, Term)
  115    ;   prolog:message(Term)
  116    ),
  117    !.
  118translate_message(Term) -->
  119    { nonvar(Term) },
  120    translate_message2(Term),
  121    !.
  122translate_message(Term) -->
  123    { nonvar(Term),
  124      Term = error(_, _)
  125    },
  126    [ 'Unknown exception: ~p'-[Term] ].
  127translate_message(Term) -->
  128    [ 'Unknown message: ~p'-[Term] ].
  129
  130translate_message2(Term) -->
  131    prolog_message(Term).
  132translate_message2(error(resource_error(stack), Context)) -->
  133    !,
  134    out_of_stack(Context).
  135translate_message2(error(resource_error(tripwire(Wire, Context)), _)) -->
  136    !,
  137    tripwire_message(Wire, Context).
  138translate_message2(error(existence_error(reset, Ball), SWI)) -->
  139    swi_location(SWI),
  140    tabling_existence_error(Ball, SWI).
  141translate_message2(error(ISO, SWI)) -->
  142    swi_location(SWI),
  143    term_message(ISO),
  144    swi_extra(SWI).
  145translate_message2('$aborted') -->
  146    [ 'Execution Aborted' ].
  147translate_message2(message_lines(Lines), L, T) :- % deal with old C-warning()
  148    make_message_lines(Lines, L, T).
  149translate_message2(format(Fmt, Args)) -->
  150    [ Fmt-Args ].
  151
  152make_message_lines([], T, T) :- !.
  153make_message_lines([Last],  ['~w'-[Last]|T], T) :- !.
  154make_message_lines([L0|LT], ['~w'-[L0],nl|T0], T) :-
  155    make_message_lines(LT, T0, T).
  156
  157%!  term_message(+Term)//
  158%
  159%   Deal  with  the  formal  argument    of  error(Format,  ImplDefined)
  160%   exception  terms.  The  `ImplDefined`   argument    is   handled  by
  161%   swi_location//2.
  162
  163:- public term_message//1.  164term_message(Term) -->
  165    {var(Term)},
  166    !,
  167    [ 'Unknown error term: ~p'-[Term] ].
  168term_message(Term) -->
  169    { message_lang(Lang) },
  170    prolog:error_message(Lang, Term),
  171    !.
  172term_message(Term) -->
  173    prolog:error_message(Term),
  174    !.
  175term_message(Term) -->
  176    iso_message(Term).
  177term_message(Term) -->
  178    swi_message(Term).
  179term_message(Term) -->
  180    [ 'Unknown error term: ~p'-[Term] ].
  181
  182iso_message(resource_error(c_stack)) -->
  183    out_of_c_stack.
  184iso_message(resource_error(Missing)) -->
  185    [ 'Not enough resources: ~w'-[Missing] ].
  186iso_message(type_error(evaluable, Actual)) -->
  187    { callable(Actual) },
  188    [ 'Arithmetic: `~p'' is not a function'-[Actual] ].
  189iso_message(type_error(free_of_attvar, Actual)) -->
  190    [ 'Type error: `~W'' contains attributed variables'-
  191      [Actual,[portray(true), attributes(portray)]] ].
  192iso_message(type_error(Expected, Actual)) -->
  193    [ 'Type error: `~w'' expected, found `~p'''-[Expected, Actual] ],
  194    type_error_comment(Expected, Actual).
  195iso_message(domain_error(Domain, Actual)) -->
  196    [ 'Domain error: '-[] ], domain(Domain),
  197    [ ' expected, found `~p'''-[Actual] ].
  198iso_message(instantiation_error) -->
  199    [ 'Arguments are not sufficiently instantiated' ].
  200iso_message(uninstantiation_error(Var)) -->
  201    [ 'Uninstantiated argument expected, found ~p'-[Var] ].
  202iso_message(representation_error(What)) -->
  203    [ 'Cannot represent due to `~w'''-[What] ].
  204iso_message(permission_error(Action, Type, Object)) -->
  205    permission_error(Action, Type, Object).
  206iso_message(evaluation_error(Which)) -->
  207    [ 'Arithmetic: evaluation error: `~p'''-[Which] ].
  208iso_message(existence_error(procedure, Proc)) -->
  209    [ 'Unknown procedure: ~q'-[Proc] ],
  210    unknown_proc_msg(Proc).
  211iso_message(existence_error(answer_variable, Var)) -->
  212    [ '$~w was not bound by a previous query'-[Var] ].
  213iso_message(existence_error(matching_rule, Goal)) -->
  214    [ 'No rule matches ~p'-[Goal] ].
  215iso_message(existence_error(Type, Object)) -->
  216    [ '~w `~p'' does not exist'-[Type, Object] ].
  217iso_message(existence_error(Type, Object, In)) --> % not ISO
  218    [ '~w `~p'' does not exist in ~p'-[Type, Object, In] ].
  219iso_message(busy(Type, Object)) -->
  220    [ '~w `~p'' is busy'-[Type, Object] ].
  221iso_message(syntax_error(swi_backslash_newline)) -->
  222    [ 'Deprecated ... \\<newline><white>*.  Use \\c' ].
  223iso_message(syntax_error(Id)) -->
  224    [ 'Syntax error: ' ],
  225    syntax_error(Id).
  226iso_message(occurs_check(Var, In)) -->
  227    [ 'Cannot unify ~p with ~p: would create an infinite tree'-[Var, In] ].
  228
  229%!  permission_error(Action, Type, Object)//
  230%
  231%   Translate  permission  errors.  Most  follow    te  pattern  "No
  232%   permission to Action Type Object", but some are a bit different.
  233
  234permission_error(Action, built_in_procedure, Pred) -->
  235    { user_predicate_indicator(Pred, PI)
  236    },
  237    [ 'No permission to ~w built-in predicate `~p'''-[Action, PI] ],
  238    (   {Action \== export}
  239    ->  [ nl,
  240          'Use :- redefine_system_predicate(+Head) if redefinition is intended'
  241        ]
  242    ;   []
  243    ).
  244permission_error(import_into(Dest), procedure, Pred) -->
  245    [ 'No permission to import ~p into ~w'-[Pred, Dest] ].
  246permission_error(Action, static_procedure, Proc) -->
  247    [ 'No permission to ~w static procedure `~p'''-[Action, Proc] ],
  248    defined_definition('Defined', Proc).
  249permission_error(input, stream, Stream) -->
  250    [ 'No permission to read from output stream `~p'''-[Stream] ].
  251permission_error(output, stream, Stream) -->
  252    [ 'No permission to write to input stream `~p'''-[Stream] ].
  253permission_error(input, text_stream, Stream) -->
  254    [ 'No permission to read bytes from TEXT stream `~p'''-[Stream] ].
  255permission_error(output, text_stream, Stream) -->
  256    [ 'No permission to write bytes to TEXT stream `~p'''-[Stream] ].
  257permission_error(input, binary_stream, Stream) -->
  258    [ 'No permission to read characters from binary stream `~p'''-[Stream] ].
  259permission_error(output, binary_stream, Stream) -->
  260    [ 'No permission to write characters to binary stream `~p'''-[Stream] ].
  261permission_error(open, source_sink, alias(Alias)) -->
  262    [ 'No permission to reuse alias "~p": already taken'-[Alias] ].
  263permission_error(tnot, non_tabled_procedure, Pred) -->
  264    [ 'The argument of tnot/1 is not tabled: ~p'-[Pred] ].
  265permission_error(Action, Type, Object) -->
  266    [ 'No permission to ~w ~w `~p'''-[Action, Type, Object] ].
  267
  268
  269unknown_proc_msg(_:(^)/2) -->
  270    !,
  271    unknown_proc_msg((^)/2).
  272unknown_proc_msg((^)/2) -->
  273    !,
  274    [nl, '  ^/2 can only appear as the 2nd argument of setof/3 and bagof/3'].
  275unknown_proc_msg((:-)/2) -->
  276    !,
  277    [nl, '  Rules must be loaded from a file'],
  278    faq('ToplevelMode').
  279unknown_proc_msg((=>)/2) -->
  280    !,
  281    [nl, '  Rules must be loaded from a file'],
  282    faq('ToplevelMode').
  283unknown_proc_msg((:-)/1) -->
  284    !,
  285    [nl, '  Directives must be loaded from a file'],
  286    faq('ToplevelMode').
  287unknown_proc_msg((?-)/1) -->
  288    !,
  289    [nl, '  ?- is the Prolog prompt'],
  290    faq('ToplevelMode').
  291unknown_proc_msg(Proc) -->
  292    { dwim_predicates(Proc, Dwims) },
  293    (   {Dwims \== []}
  294    ->  [nl, '  However, there are definitions for:', nl],
  295        dwim_message(Dwims)
  296    ;   []
  297    ).
  298
  299dependency_error(shared(Shared), private(Private)) -->
  300    [ 'Shared table for ~p may not depend on private ~p'-[Shared, Private] ].
  301dependency_error(Dep, monotonic(On)) -->
  302    { '$pi_head'(PI, Dep),
  303      '$pi_head'(MPI, On)
  304    },
  305    [ 'Dependent ~p on monotonic predicate ~p is not monotonic or incremental'-
  306      [PI, MPI]
  307    ].
  308
  309faq(Page) -->
  310    [nl, '  See FAQ at https://www.swi-prolog.org/FAQ/', Page, '.txt' ].
  311
  312type_error_comment(_Expected, Actual) -->
  313    { type_of(Actual, Type),
  314      (   sub_atom(Type, 0, 1, _, First),
  315          memberchk(First, [a,e,i,o,u])
  316      ->  Article = an
  317      ;   Article = a
  318      )
  319    },
  320    [ ' (~w ~w)'-[Article, Type] ].
  321
  322type_of(Term, Type) :-
  323    (   attvar(Term)      -> Type = attvar
  324    ;   var(Term)         -> Type = var
  325    ;   atom(Term)        -> Type = atom
  326    ;   integer(Term)     -> Type = integer
  327    ;   string(Term)      -> Type = string
  328    ;   Term == []        -> Type = empty_list
  329    ;   blob(Term, BlobT) -> blob_type(BlobT, Type)
  330    ;   rational(Term)    -> Type = rational
  331    ;   float(Term)       -> Type = float
  332    ;   is_stream(Term)   -> Type = stream
  333    ;   is_dict(Term)     -> Type = dict
  334    ;   is_list(Term)     -> Type = list
  335    ;   cyclic_term(Term) -> Type = cyclic
  336    ;   compound(Term)    -> Type = compound
  337    ;                        Type = unknown
  338    ).
  339
  340blob_type(BlobT, Type) :-
  341    atom_concat(BlobT, '_reference', Type).
  342
  343syntax_error(end_of_clause) -->
  344    [ 'Unexpected end of clause' ].
  345syntax_error(end_of_clause_expected) -->
  346    [ 'End of clause expected' ].
  347syntax_error(end_of_file) -->
  348    [ 'Unexpected end of file' ].
  349syntax_error(end_of_file_in_block_comment) -->
  350    [ 'End of file in /* ... */ comment' ].
  351syntax_error(end_of_file_in_quoted(Quote)) -->
  352    [ 'End of file in quoted ' ],
  353    quoted_type(Quote).
  354syntax_error(illegal_number) -->
  355    [ 'Illegal number' ].
  356syntax_error(long_atom) -->
  357    [ 'Atom too long (see style_check/1)' ].
  358syntax_error(long_string) -->
  359    [ 'String too long (see style_check/1)' ].
  360syntax_error(operator_clash) -->
  361    [ 'Operator priority clash' ].
  362syntax_error(operator_expected) -->
  363    [ 'Operator expected' ].
  364syntax_error(operator_balance) -->
  365    [ 'Unbalanced operator' ].
  366syntax_error(quoted_punctuation) -->
  367    [ 'Operand expected, unquoted comma or bar found' ].
  368syntax_error(list_rest) -->
  369    [ 'Unexpected comma or bar in rest of list' ].
  370syntax_error(cannot_start_term) -->
  371    [ 'Illegal start of term' ].
  372syntax_error(punct(Punct, End)) -->
  373    [ 'Unexpected `~w\' before `~w\''-[Punct, End] ].
  374syntax_error(undefined_char_escape(C)) -->
  375    [ 'Unknown character escape in quoted atom or string: `\\~w\''-[C] ].
  376syntax_error(void_not_allowed) -->
  377    [ 'Empty argument list "()"' ].
  378syntax_error(Message) -->
  379    [ '~w'-[Message] ].
  380
  381quoted_type('\'') --> [atom].
  382quoted_type('\"') --> { current_prolog_flag(double_quotes, Type) }, [Type-[]].
  383quoted_type('\`') --> { current_prolog_flag(back_quotes, Type) }, [Type-[]].
  384
  385domain(range(Low,High)) -->
  386    !,
  387    ['[~q..~q]'-[Low,High] ].
  388domain(Domain) -->
  389    ['`~w\''-[Domain] ].
  390
  391%!  tabling_existence_error(+Ball, +Context)//
  392%
  393%   Called on invalid shift/1  calls.  Track   those  that  result  from
  394%   tabling errors.
  395
  396tabling_existence_error(Ball, Context) -->
  397    { table_shift_ball(Ball) },
  398    [ 'Tabling dependency error' ],
  399    swi_extra(Context).
  400
  401table_shift_ball(dependency(_Head)).
  402table_shift_ball(dependency(_Skeleton, _Trie, _Mono)).
  403table_shift_ball(call_info(_Skeleton, _Status)).
  404table_shift_ball(call_info(_GenSkeleton, _Skeleton, _Status)).
  405
  406%!  dwim_predicates(+PI, -Dwims)
  407%
  408%   Find related predicate indicators.
  409
  410dwim_predicates(Module:Name/_Arity, Dwims) :-
  411    !,
  412    findall(Dwim, dwim_predicate(Module:Name, Dwim), Dwims).
  413dwim_predicates(Name/_Arity, Dwims) :-
  414    findall(Dwim, dwim_predicate(user:Name, Dwim), Dwims).
  415
  416dwim_message([]) --> [].
  417dwim_message([M:Head|T]) -->
  418    { hidden_module(M),
  419      !,
  420      functor(Head, Name, Arity)
  421    },
  422    [ '        ~q'-[Name/Arity], nl ],
  423    dwim_message(T).
  424dwim_message([Module:Head|T]) -->
  425    !,
  426    { functor(Head, Name, Arity)
  427    },
  428    [ '        ~q'-[Module:Name/Arity], nl],
  429    dwim_message(T).
  430dwim_message([Head|T]) -->
  431    {functor(Head, Name, Arity)},
  432    [ '        ~q'-[Name/Arity], nl],
  433    dwim_message(T).
  434
  435
  436swi_message(io_error(Op, Stream)) -->
  437    [ 'I/O error in ~w on stream ~p'-[Op, Stream] ].
  438swi_message(thread_error(TID, false)) -->
  439    [ 'Thread ~p died due to failure:'-[TID] ].
  440swi_message(thread_error(TID, exception(Error))) -->
  441    [ 'Thread ~p died abnormally:'-[TID], nl ],
  442    translate_message(Error).
  443swi_message(dependency_error(Tabled, DependsOn)) -->
  444    dependency_error(Tabled, DependsOn).
  445swi_message(shell(execute, Cmd)) -->
  446    [ 'Could not execute `~w'''-[Cmd] ].
  447swi_message(shell(signal(Sig), Cmd)) -->
  448    [ 'Caught signal ~d on `~w'''-[Sig, Cmd] ].
  449swi_message(format(Fmt, Args)) -->
  450    [ Fmt-Args ].
  451swi_message(signal(Name, Num)) -->
  452    [ 'Caught signal ~d (~w)'-[Num, Name] ].
  453swi_message(limit_exceeded(Limit, MaxVal)) -->
  454    [ 'Exceeded ~w limit (~w)'-[Limit, MaxVal] ].
  455swi_message(goal_failed(Goal)) -->
  456    [ 'goal unexpectedly failed: ~p'-[Goal] ].
  457swi_message(shared_object(_Action, Message)) --> % Message = dlerror()
  458    [ '~w'-[Message] ].
  459swi_message(system_error(Error)) -->
  460    [ 'error in system call: ~w'-[Error]
  461    ].
  462swi_message(system_error) -->
  463    [ 'error in system call'
  464    ].
  465swi_message(failure_error(Goal)) -->
  466    [ 'Goal failed: ~p'-[Goal] ].
  467swi_message(timeout_error(Op, Stream)) -->
  468    [ 'Timeout in ~w from ~p'-[Op, Stream] ].
  469swi_message(not_implemented(Type, What)) -->
  470    [ '~w `~p\' is not implemented in this version'-[Type, What] ].
  471swi_message(context_error(nodirective, Goal)) -->
  472    { goal_to_predicate_indicator(Goal, PI) },
  473    [ 'Wrong context: ~p can only be used in a directive'-[PI] ].
  474swi_message(context_error(edit, no_default_file)) -->
  475    (   { current_prolog_flag(windows, true) }
  476    ->  [ 'Edit/0 can only be used after opening a \c
  477               Prolog file by double-clicking it' ]
  478    ;   [ 'Edit/0 can only be used with the "-s file" commandline option'
  479        ]
  480    ),
  481    [ nl, 'Use "?- edit(Topic)." or "?- emacs."' ].
  482swi_message(context_error(function, meta_arg(S))) -->
  483    [ 'Functions are not (yet) supported for meta-arguments of type ~q'-[S] ].
  484swi_message(format_argument_type(Fmt, Arg)) -->
  485    [ 'Illegal argument to format sequence ~~~w: ~p'-[Fmt, Arg] ].
  486swi_message(format(Msg)) -->
  487    [ 'Format error: ~w'-[Msg] ].
  488swi_message(conditional_compilation_error(unterminated, Where)) -->
  489    [ 'Unterminated conditional compilation from '-[] ],
  490    cond_location(Where).
  491swi_message(conditional_compilation_error(no_if, What)) -->
  492    [ ':- ~w without :- if'-[What] ].
  493swi_message(duplicate_key(Key)) -->
  494    [ 'Duplicate key: ~p'-[Key] ].
  495swi_message(initialization_error(failed, Goal, File:Line)) -->
  496    !,
  497    [ '~w:~w: ~p: false'-[File, Line, Goal] ].
  498swi_message(initialization_error(Error, Goal, File:Line)) -->
  499    [ '~w:~w: ~p '-[File, Line, Goal] ],
  500    translate_message(Error).
  501swi_message(determinism_error(PI, det, Found, property)) -->
  502    (   { '$pi_head'(user:PI, Head),
  503          predicate_property(Head, det)
  504        }
  505    ->  [ 'Deterministic procedure ~p'-[PI] ]
  506    ;   [ 'Procedure ~p called from a deterministic procedure'-[PI] ]
  507    ),
  508    det_error(Found).
  509swi_message(determinism_error(PI, det, fail, guard)) -->
  510    [ 'Procedure ~p failed after $-guard'-[PI] ].
  511swi_message(determinism_error(PI, det, fail, guard_in_caller)) -->
  512    [ 'Procedure ~p failed after $-guard in caller'-[PI] ].
  513swi_message(determinism_error(Goal, det, fail, goal)) -->
  514    [ 'Goal ~p failed'-[Goal] ].
  515swi_message(determinism_error(Goal, det, nondet, goal)) -->
  516    [ 'Goal ~p succeeded with a choice point'-[Goal] ].
  517swi_message(qlf_format_error(File, Message)) -->
  518    [ '~w: Invalid QLF file: ~w'-[File, Message] ].
  519swi_message(goal_expansion_error(bound, Term)) -->
  520    [ 'Goal expansion bound a variable to ~p'-[Term] ].
  521
  522det_error(nondet) -->
  523    [ ' succeeded with a choicepoint'- [] ].
  524det_error(fail) -->
  525    [ ' failed'- [] ].
  526
  527
  528cond_location(File:Line) -->
  529    { file_base_name(File, Base) },
  530    [ '~w:~d'-[Base, Line] ].
  531
  532%!  swi_location(+Term)// is det.
  533%
  534%   Print location information for error(Formal,   ImplDefined) from the
  535%   ImplDefined term.
  536
  537:- public swi_location//1.  538swi_location(X) -->
  539    { var(X) },
  540    !.
  541swi_location(Context) -->
  542    { message_lang(Lang) },
  543    prolog:message_location(Lang, Context),
  544    !.
  545swi_location(Context) -->
  546    prolog:message_location(Context),
  547    !.
  548swi_location(context(Caller, _Msg)) -->
  549    { ground(Caller) },
  550    !,
  551    caller(Caller).
  552swi_location(file(Path, Line, -1, _CharNo)) -->
  553    !,
  554    [ '~w:~d: '-[Path, Line] ].
  555swi_location(file(Path, Line, LinePos, _CharNo)) -->
  556    [ '~w:~d:~d: '-[Path, Line, LinePos] ].
  557swi_location(stream(Stream, Line, LinePos, CharNo)) -->
  558    (   { is_stream(Stream),
  559          stream_property(Stream, file_name(File))
  560        }
  561    ->  swi_location(file(File, Line, LinePos, CharNo))
  562    ;   [ 'Stream ~w:~d:~d '-[Stream, Line, LinePos] ]
  563    ).
  564swi_location(autoload(File:Line)) -->
  565    [ '~w:~w: '-[File, Line] ].
  566swi_location(_) -->
  567    [].
  568
  569caller(system:'$record_clause'/3) -->
  570    !,
  571    [].
  572caller(Module:Name/Arity) -->
  573    !,
  574    (   { \+ hidden_module(Module) }
  575    ->  [ '~q:~q/~w: '-[Module, Name, Arity] ]
  576    ;   [ '~q/~w: '-[Name, Arity] ]
  577    ).
  578caller(Name/Arity) -->
  579    [ '~q/~w: '-[Name, Arity] ].
  580caller(Caller) -->
  581    [ '~p: '-[Caller] ].
  582
  583
  584%!  swi_extra(+Term)// is det.
  585%
  586%   Extract information from the  second   argument  of an error(Formal,
  587%   ImplDefined) that is printed _after_ the core of the message.
  588%
  589%   @see swi_location//1 uses the same term   to insert context _before_
  590%   the core of the message.
  591
  592swi_extra(X) -->
  593    { var(X) },
  594    !,
  595    [].
  596swi_extra(Context) -->
  597    { message_lang(Lang) },
  598    prolog:message_context(Lang, Context),
  599    !.
  600swi_extra(Context) -->
  601    prolog:message_context(Context).
  602swi_extra(context(_, Msg)) -->
  603    { nonvar(Msg),
  604      Msg \== ''
  605    },
  606    !,
  607    swi_comment(Msg).
  608swi_extra(string(String, CharPos)) -->
  609    { sub_string(String, 0, CharPos, _, Before),
  610      sub_string(String, CharPos, _, 0, After)
  611    },
  612    [ nl, '~w'-[Before], nl, '** here **', nl, '~w'-[After] ].
  613swi_extra(_) -->
  614    [].
  615
  616swi_comment(already_from(Module)) -->
  617    !,
  618    [ ' (already imported from ~q)'-[Module] ].
  619swi_comment(directory(_Dir)) -->
  620    !,
  621    [ ' (is a directory)' ].
  622swi_comment(not_a_directory(_Dir)) -->
  623    !,
  624    [ ' (is not a directory)' ].
  625swi_comment(Msg) -->
  626    [ ' (~w)'-[Msg] ].
  627
  628
  629thread_context -->
  630    { thread_self(Me), Me \== main, thread_property(Me, id(Id)) },
  631    !,
  632    ['[Thread ~w] '-[Id]].
  633thread_context -->
  634    [].
  635
  636                 /*******************************
  637                 *        NORMAL MESSAGES       *
  638                 *******************************/
  639
  640prolog_message(welcome) -->
  641    [ 'Welcome to SWI-Prolog (' ],
  642    prolog_message(threads),
  643    prolog_message(address_bits),
  644    ['version ' ],
  645    prolog_message(version),
  646    [ ')', nl ],
  647    prolog_message(copyright),
  648    [ nl ],
  649    translate_message(user_versions),
  650    [ nl ],
  651    prolog_message(documentaton),
  652    [ nl, nl ].
  653prolog_message(user_versions) -->
  654    (   { findall(Msg, prolog:version_msg(Msg), Msgs),
  655          Msgs \== []
  656        }
  657    ->  [nl],
  658        user_version_messages(Msgs)
  659    ;   []
  660    ).
  661prolog_message(deprecated(Term)) -->
  662    { nonvar(Term) },
  663    (   { message_lang(Lang) },
  664        prolog:deprecated(Lang, Term)
  665    ->  []
  666    ;   prolog:deprecated(Term)
  667    ->  []
  668    ;   deprecated(Term)
  669    ).
  670prolog_message(unhandled_exception(E)) -->
  671    { nonvar(E) },
  672    [ 'Unhandled exception: ' ],
  673    (   translate_message(E)
  674    ->  []
  675    ;   [ '~p'-[E] ]
  676    ).
  677
  678%!  prolog_message(+Term)//
  679
  680prolog_message(initialization_error(_, E, File:Line)) -->
  681    !,
  682    [ '~w:~d: '-[File, Line],
  683      'Initialization goal raised exception:', nl
  684    ],
  685    translate_message(E).
  686prolog_message(initialization_error(Goal, E, _)) -->
  687    [ 'Initialization goal ~p raised exception:'-[Goal], nl ],
  688    translate_message(E).
  689prolog_message(initialization_failure(_Goal, File:Line)) -->
  690    !,
  691    [ '~w:~d: '-[File, Line],
  692      'Initialization goal failed'-[]
  693    ].
  694prolog_message(initialization_failure(Goal, _)) -->
  695    [ 'Initialization goal failed: ~p'-[Goal]
  696    ].
  697prolog_message(initialization_exception(E)) -->
  698    [ 'Prolog initialisation failed:', nl ],
  699    translate_message(E).
  700prolog_message(init_goal_syntax(Error, Text)) -->
  701    !,
  702    [ '-g ~w: '-[Text] ],
  703    translate_message(Error).
  704prolog_message(init_goal_failed(failed, @(Goal,File:Line))) -->
  705    !,
  706    [ '~w:~w: ~p: false'-[File, Line, Goal] ].
  707prolog_message(init_goal_failed(Error, @(Goal,File:Line))) -->
  708    !,
  709    [ '~w:~w: ~p '-[File, Line, Goal] ],
  710    translate_message(Error).
  711prolog_message(init_goal_failed(failed, Text)) -->
  712    !,
  713    [ '-g ~w: false'-[Text] ].
  714prolog_message(init_goal_failed(Error, Text)) -->
  715    !,
  716    [ '-g ~w: '-[Text] ],
  717    translate_message(Error).
  718prolog_message(goal_failed(Context, Goal)) -->
  719    [ 'Goal (~w) failed: ~p'-[Context, Goal] ].
  720prolog_message(no_current_module(Module)) -->
  721    [ '~w is not a current module (created)'-[Module] ].
  722prolog_message(commandline_arg_type(Flag, Arg)) -->
  723    [ 'Bad argument to commandline option -~w: ~w'-[Flag, Arg] ].
  724prolog_message(missing_feature(Name)) -->
  725    [ 'This version of SWI-Prolog does not support ~w'-[Name] ].
  726prolog_message(singletons(_Term, List)) -->
  727    [ 'Singleton variables: ~w'-[List] ].
  728prolog_message(multitons(_Term, List)) -->
  729    [ 'Singleton-marked variables appearing more than once: ~w'-[List] ].
  730prolog_message(profile_no_cpu_time) -->
  731    [ 'No CPU-time info.  Check the SWI-Prolog manual for details' ].
  732prolog_message(non_ascii(Text, Type)) -->
  733    [ 'Unquoted ~w with non-portable characters: ~w'-[Type, Text] ].
  734prolog_message(io_warning(Stream, Message)) -->
  735    { stream_property(Stream, position(Position)),
  736      !,
  737      stream_position_data(line_count, Position, LineNo),
  738      stream_position_data(line_position, Position, LinePos),
  739      (   stream_property(Stream, file_name(File))
  740      ->  Obj = File
  741      ;   Obj = Stream
  742      )
  743    },
  744    [ '~p:~d:~d: ~w'-[Obj, LineNo, LinePos, Message] ].
  745prolog_message(io_warning(Stream, Message)) -->
  746    [ 'stream ~p: ~w'-[Stream, Message] ].
  747prolog_message(option_usage(pldoc)) -->
  748    [ 'Usage: --pldoc[=port]' ].
  749prolog_message(interrupt(begin)) -->
  750    [ 'Action (h for help) ? ', flush ].
  751prolog_message(interrupt(end)) -->
  752    [ 'continue' ].
  753prolog_message(interrupt(trace)) -->
  754    [ 'continue (trace mode)' ].
  755prolog_message(unknown_in_module_user) -->
  756    [ 'Using a non-error value for unknown in the global module', nl,
  757      'causes most of the development environment to stop working.', nl,
  758      'Please use :- dynamic or limit usage of unknown to a module.', nl,
  759      'See https://www.swi-prolog.org/howto/database.html'
  760    ].
  761prolog_message(untable(PI)) -->
  762    [ 'Reconsult: removed tabling for ~p'-[PI] ].
  763
  764
  765                 /*******************************
  766                 *         LOADING FILES        *
  767                 *******************************/
  768
  769prolog_message(modify_active_procedure(Who, What)) -->
  770    [ '~p: modified active procedure ~p'-[Who, What] ].
  771prolog_message(load_file(failed(user:File))) -->
  772    [ 'Failed to load ~p'-[File] ].
  773prolog_message(load_file(failed(Module:File))) -->
  774    [ 'Failed to load ~p into module ~p'-[File, Module] ].
  775prolog_message(load_file(failed(File))) -->
  776    [ 'Failed to load ~p'-[File] ].
  777prolog_message(mixed_directive(Goal)) -->
  778    [ 'Cannot pre-compile mixed load/call directive: ~p'-[Goal] ].
  779prolog_message(cannot_redefine_comma) -->
  780    [ 'Full stop in clause-body?  Cannot redefine ,/2' ].
  781prolog_message(illegal_autoload_index(Dir, Term)) -->
  782    [ 'Illegal term in INDEX file of directory ~w: ~w'-[Dir, Term] ].
  783prolog_message(redefined_procedure(Type, Proc)) -->
  784    [ 'Redefined ~w procedure ~p'-[Type, Proc] ],
  785    defined_definition('Previously defined', Proc).
  786prolog_message(declare_module(Module, abolish(Predicates))) -->
  787    [ 'Loading module ~w abolished: ~p'-[Module, Predicates] ].
  788prolog_message(import_private(Module, Private)) -->
  789    [ 'import/1: ~p is not exported (still imported into ~q)'-
  790      [Private, Module]
  791    ].
  792prolog_message(ignored_weak_import(Into, From:PI)) -->
  793    [ 'Local definition of ~p overrides weak import from ~q'-
  794      [Into:PI, From]
  795    ].
  796prolog_message(undefined_export(Module, PI)) -->
  797    [ 'Exported procedure ~q:~q is not defined'-[Module, PI] ].
  798prolog_message(no_exported_op(Module, Op)) -->
  799    [ 'Operator ~q:~q is not exported (still defined)'-[Module, Op] ].
  800prolog_message(discontiguous((-)/2,_)) -->
  801    prolog_message(minus_in_identifier).
  802prolog_message(discontiguous(Proc,Current)) -->
  803    [ 'Clauses of ', ansi(code, '~p', [Proc]),
  804      ' are not together in the source-file', nl ],
  805    current_definition(Proc, 'Earlier definition at '),
  806    [ 'Current predicate: ', ansi(code, '~p', [Current]), nl,
  807      'Use ', ansi(code, ':- discontiguous ~p.', [Proc]),
  808      ' to suppress this message'
  809    ].
  810prolog_message(decl_no_effect(Goal)) -->
  811    [ 'Deprecated declaration has no effect: ~p'-[Goal] ].
  812prolog_message(load_file(start(Level, File))) -->
  813    [ '~|~t~*+Loading '-[Level] ],
  814    load_file(File),
  815    [ ' ...' ].
  816prolog_message(include_file(start(Level, File))) -->
  817    [ '~|~t~*+include '-[Level] ],
  818    load_file(File),
  819    [ ' ...' ].
  820prolog_message(include_file(done(Level, File))) -->
  821    [ '~|~t~*+included '-[Level] ],
  822    load_file(File).
  823prolog_message(load_file(done(Level, File, Action, Module, Time, Clauses))) -->
  824    [ '~|~t~*+'-[Level] ],
  825    load_file(File),
  826    [ ' ~w'-[Action] ],
  827    load_module(Module),
  828    [ ' ~2f sec, ~D clauses'-[Time, Clauses] ].
  829prolog_message(dwim_undefined(Goal, Alternatives)) -->
  830    { goal_to_predicate_indicator(Goal, Pred)
  831    },
  832    [ 'Unknown procedure: ~q'-[Pred], nl,
  833      '    However, there are definitions for:', nl
  834    ],
  835    dwim_message(Alternatives).
  836prolog_message(dwim_correct(Into)) -->
  837    [ 'Correct to: ~q? '-[Into], flush ].
  838prolog_message(error(loop_error(Spec), file_search(Used))) -->
  839    [ 'File search: too many levels of indirections on: ~p'-[Spec], nl,
  840      '    Used alias expansions:', nl
  841    ],
  842    used_search(Used).
  843prolog_message(minus_in_identifier) -->
  844    [ 'The "-" character should not be used to separate words in an', nl,
  845      'identifier.  Check the SWI-Prolog FAQ for details.'
  846    ].
  847prolog_message(qlf(removed_after_error(File))) -->
  848    [ 'Removed incomplete QLF file ~w'-[File] ].
  849prolog_message(qlf(recompile(Spec,_Pl,_Qlf,Reason))) -->
  850    [ '~p: recompiling QLF file'-[Spec] ],
  851    qlf_recompile_reason(Reason).
  852prolog_message(qlf(can_not_recompile(Spec,QlfFile,_Reason))) -->
  853    [ '~p: can not recompile "~w" (access denied)'-[Spec, QlfFile], nl,
  854      '\tLoading from source'-[]
  855    ].
  856prolog_message(qlf(system_lib_out_of_date(Spec,QlfFile))) -->
  857    [ '~p: can not recompile "~w" (access denied)'-[Spec, QlfFile], nl,
  858      '\tLoading QlfFile'-[]
  859    ].
  860prolog_message(redefine_module(Module, OldFile, File)) -->
  861    [ 'Module "~q" already loaded from ~w.'-[Module, OldFile], nl,
  862      'Wipe and reload from ~w? '-[File], flush
  863    ].
  864prolog_message(redefine_module_reply) -->
  865    [ 'Please answer y(es), n(o) or a(bort)' ].
  866prolog_message(reloaded_in_module(Absolute, OldContext, LM)) -->
  867    [ '~w was previously loaded in module ~w'-[Absolute, OldContext], nl,
  868      '\tnow it is reloaded into module ~w'-[LM] ].
  869prolog_message(expected_layout(Expected, Pos)) -->
  870    [ 'Layout data: expected ~w, found: ~p'-[Expected, Pos] ].
  871
  872defined_definition(Message, Spec) -->
  873    { strip_module(user:Spec, M, Name/Arity),
  874      functor(Head, Name, Arity),
  875      predicate_property(M:Head, file(File)),
  876      predicate_property(M:Head, line_count(Line))
  877    },
  878    !,
  879    [ nl, '~w at ~w:~d'-[Message, File,Line] ].
  880defined_definition(_, _) --> [].
  881
  882used_search([]) -->
  883    [].
  884used_search([Alias=Expanded|T]) -->
  885    [ '        file_search_path(~p, ~p)'-[Alias, Expanded], nl ],
  886    used_search(T).
  887
  888load_file(file(Spec, _Path)) -->
  889    (   {atomic(Spec)}
  890    ->  [ '~w'-[Spec] ]
  891    ;   [ '~p'-[Spec] ]
  892    ).
  893%load_file(file(_, Path)) -->
  894%       [ '~w'-[Path] ].
  895
  896load_module(user) --> !.
  897load_module(system) --> !.
  898load_module(Module) -->
  899    [ ' into ~w'-[Module] ].
  900
  901goal_to_predicate_indicator(Goal, PI) :-
  902    strip_module(Goal, Module, Head),
  903    callable_name_arity(Head, Name, Arity),
  904    user_predicate_indicator(Module:Name/Arity, PI).
  905
  906callable_name_arity(Goal, Name, Arity) :-
  907    compound(Goal),
  908    !,
  909    compound_name_arity(Goal, Name, Arity).
  910callable_name_arity(Goal, Goal, 0) :-
  911    atom(Goal).
  912
  913user_predicate_indicator(Module:PI, PI) :-
  914    hidden_module(Module),
  915    !.
  916user_predicate_indicator(PI, PI).
  917
  918hidden_module(user) :- !.
  919hidden_module(system) :- !.
  920hidden_module(M) :-
  921    sub_atom(M, 0, _, _, $).
  922
  923current_definition(Proc, Prefix) -->
  924    { pi_uhead(Proc, Head),
  925      predicate_property(Head, file(File)),
  926      predicate_property(Head, line_count(Line))
  927    },
  928    [ '~w~w:~d'-[Prefix,File,Line], nl ].
  929current_definition(_, _) --> [].
  930
  931pi_uhead(Module:Name/Arity, Module:Head) :-
  932    !,
  933    atom(Module), atom(Name), integer(Arity),
  934    functor(Head, Name, Arity).
  935pi_uhead(Name/Arity, user:Head) :-
  936    atom(Name), integer(Arity),
  937    functor(Head, Name, Arity).
  938
  939qlf_recompile_reason(old) -->
  940    !,
  941    [ ' (out of date)'-[] ].
  942qlf_recompile_reason(_) -->
  943    [ ' (incompatible with current Prolog version)'-[] ].
  944
  945prolog_message(file_search(cache(Spec, _Cond), Path)) -->
  946    [ 'File search: ~p --> ~p (cache)'-[Spec, Path] ].
  947prolog_message(file_search(found(Spec, Cond), Path)) -->
  948    [ 'File search: ~p --> ~p OK ~p'-[Spec, Path, Cond] ].
  949prolog_message(file_search(tried(Spec, Cond), Path)) -->
  950    [ 'File search: ~p --> ~p NO ~p'-[Spec, Path, Cond] ].
  951
  952                 /*******************************
  953                 *              GC              *
  954                 *******************************/
  955
  956prolog_message(agc(start)) -->
  957    thread_context,
  958    [ 'AGC: ', flush ].
  959prolog_message(agc(done(Collected, Remaining, Time))) -->
  960    [ at_same_line,
  961      'reclaimed ~D atoms in ~3f sec. (remaining: ~D)'-
  962      [Collected, Time, Remaining]
  963    ].
  964prolog_message(cgc(start)) -->
  965    thread_context,
  966    [ 'CGC: ', flush ].
  967prolog_message(cgc(done(CollectedClauses, _CollectedBytes,
  968                        RemainingBytes, Time))) -->
  969    [ at_same_line,
  970      'reclaimed ~D clauses in ~3f sec. (pending: ~D bytes)'-
  971      [CollectedClauses, Time, RemainingBytes]
  972    ].
  973
  974		 /*******************************
  975		 *        STACK OVERFLOW	*
  976		 *******************************/
  977
  978out_of_stack(Context) -->
  979    { human_stack_size(Context.localused,   Local),
  980      human_stack_size(Context.globalused,  Global),
  981      human_stack_size(Context.trailused,   Trail),
  982      human_stack_size(Context.stack_limit, Limit),
  983      LCO is (100*(Context.depth - Context.environments))/Context.depth
  984    },
  985    [ 'Stack limit (~s) exceeded'-[Limit], nl,
  986      '  Stack sizes: local: ~s, global: ~s, trail: ~s'-[Local,Global,Trail], nl,
  987      '  Stack depth: ~D, last-call: ~0f%, Choice points: ~D'-
  988         [Context.depth, LCO, Context.choicepoints], nl
  989    ],
  990    overflow_reason(Context, Resolve),
  991    resolve_overflow(Resolve).
  992
  993human_stack_size(Size, String) :-
  994    Size < 100,
  995    format(string(String), '~dKb', [Size]).
  996human_stack_size(Size, String) :-
  997    Size < 100 000,
  998    Value is Size / 1024,
  999    format(string(String), '~1fMb', [Value]).
 1000human_stack_size(Size, String) :-
 1001    Value is Size / (1024*1024),
 1002    format(string(String), '~1fGb', [Value]).
 1003
 1004overflow_reason(Context, fix) -->
 1005    show_non_termination(Context),
 1006    !.
 1007overflow_reason(Context, enlarge) -->
 1008    { Stack = Context.get(stack) },
 1009    !,
 1010    [ '  In:'-[], nl ],
 1011    stack(Stack).
 1012overflow_reason(_Context, enlarge) -->
 1013    [ '  Insufficient global stack'-[] ].
 1014
 1015show_non_termination(Context) -->
 1016    (   { Stack = Context.get(cycle) }
 1017    ->  [ '  Probable infinite recursion (cycle):'-[], nl ]
 1018    ;   { Stack = Context.get(non_terminating) }
 1019    ->  [ '  Possible non-terminating recursion:'-[], nl ]
 1020    ),
 1021    stack(Stack).
 1022
 1023stack([]) --> [].
 1024stack([frame(Depth, M:Goal, _)|T]) -->
 1025    [ '    [~D] ~q:'-[Depth, M] ],
 1026    stack_goal(Goal),
 1027    [ nl ],
 1028    stack(T).
 1029
 1030stack_goal(Goal) -->
 1031    { compound(Goal),
 1032      !,
 1033      compound_name_arity(Goal, Name, Arity)
 1034    },
 1035    [ '~q('-[Name] ],
 1036    stack_goal_args(1, Arity, Goal),
 1037    [ ')'-[] ].
 1038stack_goal(Goal) -->
 1039    [ '~q'-[Goal] ].
 1040
 1041stack_goal_args(I, Arity, Goal) -->
 1042    { I =< Arity,
 1043      !,
 1044      arg(I, Goal, A),
 1045      I2 is I + 1
 1046    },
 1047    stack_goal_arg(A),
 1048    (   { I2 =< Arity }
 1049    ->  [ ', '-[] ],
 1050        stack_goal_args(I2, Arity, Goal)
 1051    ;   []
 1052    ).
 1053stack_goal_args(_, _, _) -->
 1054    [].
 1055
 1056stack_goal_arg(A) -->
 1057    { nonvar(A),
 1058      A = [Len|T],
 1059      !
 1060    },
 1061    (   {Len == cyclic_term}
 1062    ->  [ '[cyclic list]'-[] ]
 1063    ;   {T == []}
 1064    ->  [ '[length:~D]'-[Len] ]
 1065    ;   [ '[length:~D|~p]'-[Len, T] ]
 1066    ).
 1067stack_goal_arg(A) -->
 1068    { nonvar(A),
 1069      A = _/_,
 1070      !
 1071    },
 1072    [ '<compound ~p>'-[A] ].
 1073stack_goal_arg(A) -->
 1074    [ '~p'-[A] ].
 1075
 1076resolve_overflow(fix) -->
 1077    [].
 1078resolve_overflow(enlarge) -->
 1079    { current_prolog_flag(stack_limit, LimitBytes),
 1080      NewLimit is LimitBytes * 2
 1081    },
 1082    [ nl,
 1083      'Use the --stack_limit=size[KMG] command line option or'-[], nl,
 1084      '?- set_prolog_flag(stack_limit, ~I). to double the limit.'-[NewLimit]
 1085    ].
 1086
 1087%!  out_of_c_stack
 1088%
 1089%   The thread's C-stack limit was exceeded. Give  some advice on how to
 1090%   resolve this.
 1091
 1092out_of_c_stack -->
 1093    { statistics(c_stack, Limit), Limit > 0 },
 1094    !,
 1095    [ 'C-stack limit (~D bytes) exceeded.'-[Limit], nl ],
 1096    resolve_c_stack_overflow(Limit).
 1097out_of_c_stack -->
 1098    { statistics(c_stack, Limit), Limit > 0 },
 1099    [ 'C-stack limit exceeded.'-[Limit], nl ],
 1100    resolve_c_stack_overflow(Limit).
 1101
 1102resolve_c_stack_overflow(_Limit) -->
 1103    { thread_self(main) },
 1104    [ 'Use the shell command ' ], code('~w', 'ulimit -s size'),
 1105    [ ' to enlarge the limit.' ].
 1106resolve_c_stack_overflow(_Limit) -->
 1107    [ 'Use the ' ], code('~w', 'c_stack(KBytes)'),
 1108    [ ' option of '], code(thread_create/3), [' to enlarge the limit.' ].
 1109
 1110
 1111                 /*******************************
 1112                 *        MAKE/AUTOLOAD         *
 1113                 *******************************/
 1114
 1115prolog_message(make(reload(Files))) -->
 1116    { length(Files, N)
 1117    },
 1118    [ 'Make: reloading ~D files'-[N] ].
 1119prolog_message(make(done(_Files))) -->
 1120    [ 'Make: finished' ].
 1121prolog_message(make(library_index(Dir))) -->
 1122    [ 'Updating index for library ~w'-[Dir] ].
 1123prolog_message(autoload(Pred, File)) -->
 1124    thread_context,
 1125    [ 'autoloading ~p from ~w'-[Pred, File] ].
 1126prolog_message(autoload(read_index(Dir))) -->
 1127    [ 'Loading autoload index for ~w'-[Dir] ].
 1128prolog_message(autoload(disabled(Loaded))) -->
 1129    [ 'Disabled autoloading (loaded ~D files)'-[Loaded] ].
 1130prolog_message(autoload(already_defined(PI, From))) -->
 1131    code(PI),
 1132    (   { '$pi_head'(PI, Head),
 1133          predicate_property(Head, built_in)
 1134        }
 1135    ->  [' is a built-in predicate']
 1136    ;   [ ' is already imported from module ' ],
 1137        code(From)
 1138    ).
 1139
 1140swi_message(autoload(Msg)) -->
 1141    [ nl, '  ' ],
 1142    autoload_message(Msg).
 1143
 1144autoload_message(not_exported(PI, Spec, _FullFile, _Exports)) -->
 1145    [ ansi(code, '~w', [Spec]),
 1146      ' does not export ',
 1147      ansi(code, '~p', [PI])
 1148    ].
 1149autoload_message(no_file(Spec)) -->
 1150    [ ansi(code, '~p', [Spec]), ': No such file' ].
 1151
 1152
 1153                 /*******************************
 1154                 *       COMPILER WARNINGS      *
 1155                 *******************************/
 1156
 1157% print warnings about dubious code raised by the compiler.
 1158% TBD: pass in PC to produce exact error locations.
 1159
 1160prolog_message(compiler_warnings(Clause, Warnings0)) -->
 1161    {   print_goal_options(DefOptions),
 1162        (   prolog_load_context(variable_names, VarNames)
 1163        ->  warnings_with_named_vars(Warnings0, VarNames, Warnings),
 1164            Options = [variable_names(VarNames)|DefOptions]
 1165        ;   Options = DefOptions,
 1166            Warnings = Warnings0
 1167        )
 1168    },
 1169    compiler_warnings(Warnings, Clause, Options).
 1170
 1171warnings_with_named_vars([], _, []).
 1172warnings_with_named_vars([H|T0], VarNames, [H|T]) :-
 1173    term_variables(H, Vars),
 1174    '$member'(V1, Vars),
 1175    '$member'(_=V2, VarNames),
 1176    V1 == V2,
 1177    !,
 1178    warnings_with_named_vars(T0, VarNames, T).
 1179warnings_with_named_vars([_|T0], VarNames, T) :-
 1180    warnings_with_named_vars(T0, VarNames, T).
 1181
 1182
 1183compiler_warnings([], _, _) --> [].
 1184compiler_warnings([H|T], Clause, Options) -->
 1185    (   compiler_warning(H, Clause, Options)
 1186    ->  []
 1187    ;   [ 'Unknown compiler warning: ~W'-[H,Options] ]
 1188    ),
 1189    (   {T==[]}
 1190    ->  []
 1191    ;   [nl]
 1192    ),
 1193    compiler_warnings(T, Clause, Options).
 1194
 1195compiler_warning(eq_vv(A,B), _Clause, Options) -->
 1196    (   { A == B }
 1197    ->  [ 'Test is always true: ~W'-[A==B, Options] ]
 1198    ;   [ 'Test is always false: ~W'-[A==B, Options] ]
 1199    ).
 1200compiler_warning(eq_singleton(A,B), _Clause, Options) -->
 1201    [ 'Test is always false: ~W'-[A==B, Options] ].
 1202compiler_warning(neq_vv(A,B), _Clause, Options) -->
 1203    (   { A \== B }
 1204    ->  [ 'Test is always true: ~W'-[A\==B, Options] ]
 1205    ;   [ 'Test is always false: ~W'-[A\==B, Options] ]
 1206    ).
 1207compiler_warning(neq_singleton(A,B), _Clause, Options) -->
 1208    [ 'Test is always true: ~W'-[A\==B, Options] ].
 1209compiler_warning(unify_singleton(A,B), _Clause, Options) -->
 1210    [ 'Unified variable is not used: ~W'-[A=B, Options] ].
 1211compiler_warning(always(Bool, Pred, Arg), _Clause, Options) -->
 1212    { Goal =.. [Pred,Arg] },
 1213    [ 'Test is always ~w: ~W'-[Bool, Goal, Options] ].
 1214compiler_warning(unbalanced_var(V), _Clause, Options) -->
 1215    [ 'Variable not introduced in all branches: ~W'-[V, Options] ].
 1216compiler_warning(branch_singleton(V), _Clause, Options) -->
 1217    [ 'Singleton variable in branch: ~W'-[V, Options] ].
 1218compiler_warning(negation_singleton(V), _Clause, Options) -->
 1219    [ 'Singleton variable in \\+: ~W'-[V, Options] ].
 1220compiler_warning(multiton(V), _Clause, Options) -->
 1221    [ 'Singleton-marked variable appears more than once: ~W'-[V, Options] ].
 1222
 1223print_goal_options(
 1224    [ quoted(true),
 1225      portray(true)
 1226    ]).
 1227
 1228
 1229                 /*******************************
 1230                 *      TOPLEVEL MESSAGES       *
 1231                 *******************************/
 1232
 1233prolog_message(version) -->
 1234    { current_prolog_flag(version_git, Version) },
 1235    !,
 1236    [ '~w'-[Version] ].
 1237prolog_message(version) -->
 1238    { current_prolog_flag(version_data, swi(Major,Minor,Patch,Options))
 1239    },
 1240    (   { memberchk(tag(Tag), Options) }
 1241    ->  [ '~w.~w.~w-~w'-[Major, Minor, Patch, Tag] ]
 1242    ;   [ '~w.~w.~w'-[Major, Minor, Patch] ]
 1243    ).
 1244prolog_message(address_bits) -->
 1245    { current_prolog_flag(address_bits, Bits)
 1246    },
 1247    !,
 1248    [ '~d bits, '-[Bits] ].
 1249prolog_message(threads) -->
 1250    { current_prolog_flag(threads, true)
 1251    },
 1252    !,
 1253    [ 'threaded, ' ].
 1254prolog_message(threads) -->
 1255    [].
 1256prolog_message(copyright) -->
 1257    [ 'SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.', nl,
 1258      'Please run ?- license. for legal details.'
 1259    ].
 1260prolog_message(documentaton) -->
 1261    [ 'For online help and background, visit https://www.swi-prolog.org', nl,
 1262      'For built-in help, use ?- help(Topic). or ?- apropos(Word).'
 1263    ].
 1264prolog_message(about) -->
 1265    [ 'SWI-Prolog version (' ],
 1266    prolog_message(threads),
 1267    prolog_message(address_bits),
 1268    ['version ' ],
 1269    prolog_message(version),
 1270    [ ')', nl ],
 1271    prolog_message(copyright).
 1272prolog_message(halt) -->
 1273    [ 'halt' ].
 1274prolog_message(break(begin, Level)) -->
 1275    [ 'Break level ~d'-[Level] ].
 1276prolog_message(break(end, Level)) -->
 1277    [ 'Exit break level ~d'-[Level] ].
 1278prolog_message(var_query(_)) -->
 1279    [ '... 1,000,000 ............ 10,000,000 years later', nl, nl,
 1280      '~t~8|>> 42 << (last release gives the question)'
 1281    ].
 1282prolog_message(close_on_abort(Stream)) -->
 1283    [ 'Abort: closed stream ~p'-[Stream] ].
 1284prolog_message(cancel_halt(Reason)) -->
 1285    [ 'Halt cancelled: ~p'-[Reason] ].
 1286prolog_message(on_error(halt(Status))) -->
 1287    { statistics(errors, Errors),
 1288      statistics(warnings, Warnings)
 1289    },
 1290    [ 'Halting with status ~w due to ~D errors and ~D warnings'-
 1291      [Status, Errors, Warnings] ].
 1292
 1293prolog_message(query(QueryResult)) -->
 1294    query_result(QueryResult).
 1295
 1296query_result(no) -->            % failure
 1297    [ ansi(truth(false), 'false.', []) ],
 1298    extra_line.
 1299query_result(yes(true, [])) -->      % prompt_alternatives_on: groundness
 1300    !,
 1301    [ ansi(truth(true), 'true.', []) ],
 1302    extra_line.
 1303query_result(yes(Delays, Residuals)) -->
 1304    result([], Delays, Residuals),
 1305    extra_line.
 1306query_result(done) -->          % user typed <CR>
 1307    extra_line.
 1308query_result(yes(Bindings, Delays, Residuals)) -->
 1309    result(Bindings, Delays, Residuals),
 1310    prompt(yes, Bindings, Delays, Residuals).
 1311query_result(more(Bindings, Delays, Residuals)) -->
 1312    result(Bindings, Delays, Residuals),
 1313    prompt(more, Bindings, Delays, Residuals).
 1314query_result(help) -->
 1315    [ nl, 'Actions:'-[], nl, nl,
 1316      '; (n, r, space, TAB): redo    t:          trace & redo'-[], nl,
 1317      'b:                    break   c (a, RET): exit'-[], nl,
 1318      'w:                    write   p           print'-[], nl,
 1319      'h (?):                help'-[],
 1320      nl, nl
 1321    ].
 1322query_result(action) -->
 1323    [ 'Action? '-[], flush ].
 1324query_result(confirm) -->
 1325    [ 'Please answer \'y\' or \'n\'? '-[], flush ].
 1326query_result(eof) -->
 1327    [ nl ].
 1328query_result(toplevel_open_line) -->
 1329    [].
 1330
 1331prompt(Answer, [], true, []-[]) -->
 1332    !,
 1333    prompt(Answer, empty).
 1334prompt(Answer, _, _, _) -->
 1335    !,
 1336    prompt(Answer, non_empty).
 1337
 1338prompt(yes, empty) -->
 1339    !,
 1340    [ ansi(truth(true), 'true.', []) ],
 1341    extra_line.
 1342prompt(yes, _) -->
 1343    !,
 1344    [ full_stop ],
 1345    extra_line.
 1346prompt(more, empty) -->
 1347    !,
 1348    [ ansi(truth(true), 'true ', []), flush ].
 1349prompt(more, _) -->
 1350    !,
 1351    [ ' '-[], flush ].
 1352
 1353result(Bindings, Delays, Residuals) -->
 1354    { current_prolog_flag(answer_write_options, Options0),
 1355      Options = [partial(true)|Options0],
 1356      GOptions = [priority(999)|Options0]
 1357    },
 1358    wfs_residual_program(Delays, GOptions),
 1359    bindings(Bindings, [priority(699)|Options]),
 1360    (   {Residuals == []-[]}
 1361    ->  bind_delays_sep(Bindings, Delays),
 1362        delays(Delays, GOptions)
 1363    ;   bind_res_sep(Bindings, Residuals),
 1364        residuals(Residuals, GOptions),
 1365        (   {Delays == true}
 1366        ->  []
 1367        ;   [','-[], nl],
 1368            delays(Delays, GOptions)
 1369        )
 1370    ).
 1371
 1372bindings([], _) -->
 1373    [].
 1374bindings([binding(Names,Skel,Subst)|T], Options) -->
 1375    { '$last'(Names, Name) },
 1376    var_names(Names), value(Name, Skel, Subst, Options),
 1377    (   { T \== [] }
 1378    ->  [ ','-[], nl ],
 1379        bindings(T, Options)
 1380    ;   []
 1381    ).
 1382
 1383var_names([Name]) -->
 1384    !,
 1385    [ '~w = '-[Name] ].
 1386var_names([Name1,Name2|T]) -->
 1387    !,
 1388    [ '~w = ~w, '-[Name1, Name2] ],
 1389    var_names([Name2|T]).
 1390
 1391
 1392value(Name, Skel, Subst, Options) -->
 1393    (   { var(Skel), Subst = [Skel=S] }
 1394    ->  { Skel = '$VAR'(Name) },
 1395        [ '~W'-[S, Options] ]
 1396    ;   [ '~W'-[Skel, Options] ],
 1397        substitution(Subst, Options)
 1398    ).
 1399
 1400substitution([], _) --> !.
 1401substitution([N=V|T], Options) -->
 1402    [ ', ', ansi(comment, '% where', []), nl,
 1403      '    ~w = ~W'-[N,V,Options] ],
 1404    substitutions(T, Options).
 1405
 1406substitutions([], _) --> [].
 1407substitutions([N=V|T], Options) -->
 1408    [ ','-[], nl, '    ~w = ~W'-[N,V,Options] ],
 1409    substitutions(T, Options).
 1410
 1411
 1412residuals(Normal-Hidden, Options) -->
 1413    residuals1(Normal, Options),
 1414    bind_res_sep(Normal, Hidden),
 1415    (   {Hidden == []}
 1416    ->  []
 1417    ;   [ansi(comment, '% with pending residual goals', []), nl]
 1418    ),
 1419    residuals1(Hidden, Options).
 1420
 1421residuals1([], _) -->
 1422    [].
 1423residuals1([G|Gs], Options) -->
 1424    (   { Gs \== [] }
 1425    ->  [ '~W,'-[G, Options], nl ],
 1426        residuals1(Gs, Options)
 1427    ;   [ '~W'-[G, Options] ]
 1428    ).
 1429
 1430wfs_residual_program(true, _Options) -->
 1431    !.
 1432wfs_residual_program(Goal, _Options) -->
 1433    { current_prolog_flag(toplevel_list_wfs_residual_program, true),
 1434      '$current_typein_module'(TypeIn),
 1435      (   current_predicate(delays_residual_program/2)
 1436      ->  true
 1437      ;   use_module(library(wfs), [delays_residual_program/2])
 1438      ),
 1439      delays_residual_program(TypeIn:Goal, TypeIn:Program),
 1440      Program \== []
 1441    },
 1442    !,
 1443    [ ansi(comment, '% WFS residual program', []), nl ],
 1444    [ ansi(wfs(residual_program), '~@', ['$messages':list_clauses(Program)]) ].
 1445wfs_residual_program(_, _) --> [].
 1446
 1447delays(true, _Options) -->
 1448    !.
 1449delays(Goal, Options) -->
 1450    { current_prolog_flag(toplevel_list_wfs_residual_program, true)
 1451    },
 1452    !,
 1453    [ ansi(truth(undefined), '~W', [Goal, Options]) ].
 1454delays(_, _Options) -->
 1455    [ ansi(truth(undefined), undefined, []) ].
 1456
 1457:- public list_clauses/1. 1458
 1459list_clauses([]).
 1460list_clauses([H|T]) :-
 1461    (   system_undefined(H)
 1462    ->  true
 1463    ;   portray_clause(user_output, H, [indent(4)])
 1464    ),
 1465    list_clauses(T).
 1466
 1467system_undefined((undefined :- tnot(undefined))).
 1468system_undefined((answer_count_restraint :- tnot(answer_count_restraint))).
 1469system_undefined((radial_restraint :- tnot(radial_restraint))).
 1470
 1471bind_res_sep(_, []) --> !.
 1472bind_res_sep(_, []-[]) --> !.
 1473bind_res_sep([], _) --> !.
 1474bind_res_sep(_, _) --> [','-[], nl].
 1475
 1476bind_delays_sep([], _) --> !.
 1477bind_delays_sep(_, true) --> !.
 1478bind_delays_sep(_, _) --> [','-[], nl].
 1479
 1480extra_line -->
 1481    { current_prolog_flag(toplevel_extra_white_line, true) },
 1482    !,
 1483    ['~N'-[]].
 1484extra_line -->
 1485    [].
 1486
 1487prolog_message(if_tty(Message)) -->
 1488    (   {current_prolog_flag(tty_control, true)}
 1489    ->  [ at_same_line | Message ]
 1490    ;   []
 1491    ).
 1492prolog_message(halt(Reason)) -->
 1493    [ '~w: halt'-[Reason] ].
 1494prolog_message(no_action(Char)) -->
 1495    [ 'Unknown action: ~c (h for help)'-[Char], nl ].
 1496
 1497prolog_message(history(help(Show, Help))) -->
 1498    [ 'History Commands:', nl,
 1499      '    !!.              Repeat last query', nl,
 1500      '    !nr.             Repeat query numbered <nr>', nl,
 1501      '    !str.            Repeat last query starting with <str>', nl,
 1502      '    !?str.           Repeat last query holding <str>', nl,
 1503      '    ^old^new.        Substitute <old> into <new> of last query', nl,
 1504      '    !nr^old^new.     Substitute in query numbered <nr>', nl,
 1505      '    !str^old^new.    Substitute in query starting with <str>', nl,
 1506      '    !?str^old^new.   Substitute in query holding <str>', nl,
 1507      '    ~w.~21|Show history list'-[Show], nl,
 1508      '    ~w.~21|Show this list'-[Help], nl, nl
 1509    ].
 1510prolog_message(history(no_event)) -->
 1511    [ '! No such event' ].
 1512prolog_message(history(bad_substitution)) -->
 1513    [ '! Bad substitution' ].
 1514prolog_message(history(expanded(Event))) -->
 1515    [ '~w.'-[Event] ].
 1516prolog_message(history(history(Events))) -->
 1517    history_events(Events).
 1518
 1519history_events([]) -->
 1520    [].
 1521history_events([Nr/Event|T]) -->
 1522    [ '~t~w   ~8|~W~W'-[ Nr,
 1523                         Event, [partial(true)],
 1524                         '.', [partial(true)]
 1525                       ],
 1526      nl
 1527    ],
 1528    history_events(T).
 1529
 1530
 1531%!  user_version_messages(+Terms)//
 1532%
 1533%   Helper for the `welcome`  message   to  print information registered
 1534%   using version/1.
 1535
 1536user_version_messages([]) --> [].
 1537user_version_messages([H|T]) -->
 1538    user_version_message(H),
 1539    user_version_messages(T).
 1540
 1541%!  user_version_message(+Term)
 1542
 1543user_version_message(Term) -->
 1544    translate_message(Term), !, [nl].
 1545user_version_message(Atom) -->
 1546    [ '~w'-[Atom], nl ].
 1547
 1548
 1549                 /*******************************
 1550                 *       DEBUGGER MESSAGES      *
 1551                 *******************************/
 1552
 1553prolog_message(spy(Head)) -->
 1554    { goal_to_predicate_indicator(Head, Pred)
 1555    },
 1556    [ 'Spy point on ~p'-[Pred] ].
 1557prolog_message(nospy(Head)) -->
 1558    { goal_to_predicate_indicator(Head, Pred)
 1559    },
 1560    [ 'Spy point removed from ~p'-[Pred] ].
 1561prolog_message(trace_mode(OnOff)) -->
 1562    [ 'Trace mode switched to ~w'-[OnOff] ].
 1563prolog_message(debug_mode(OnOff)) -->
 1564    [ 'Debug mode switched to ~w'-[OnOff] ].
 1565prolog_message(debugging(OnOff)) -->
 1566    [ 'Debug mode is ~w'-[OnOff] ].
 1567prolog_message(spying([])) -->
 1568    !,
 1569    [ 'No spy points' ].
 1570prolog_message(spying(Heads)) -->
 1571    [ 'Spy points (see spy/1) on:', nl ],
 1572    predicate_list(Heads).
 1573prolog_message(trace(Head, [])) -->
 1574    !,
 1575    { goal_to_predicate_indicator(Head, Pred)
 1576    },
 1577    [ '        ~p: Not tracing'-[Pred], nl].
 1578prolog_message(trace(Head, Ports)) -->
 1579    { goal_to_predicate_indicator(Head, Pred)
 1580    },
 1581    [ '        ~p: ~w'-[Pred, Ports], nl].
 1582prolog_message(tracing([])) -->
 1583    !,
 1584    [ 'No traced predicates (see trace/1)' ].
 1585prolog_message(tracing(Heads)) -->
 1586    [ 'Trace points (see trace/1) on:', nl ],
 1587    tracing_list(Heads).
 1588
 1589predicate_list([]) -->                  % TBD: Share with dwim, etc.
 1590    [].
 1591predicate_list([H|T]) -->
 1592    { goal_to_predicate_indicator(H, Pred)
 1593    },
 1594    [ '        ~p'-[Pred], nl],
 1595    predicate_list(T).
 1596
 1597tracing_list([]) -->
 1598    [].
 1599tracing_list([trace(Head, Ports)|T]) -->
 1600    translate_message(trace(Head, Ports)),
 1601    tracing_list(T).
 1602
 1603prolog_message(frame(Frame, backtrace, _PC)) -->
 1604    !,
 1605    { prolog_frame_attribute(Frame, level, Level)
 1606    },
 1607    [ ansi(frame(level), '~t[~D] ~10|', [Level]) ],
 1608    frame_context(Frame),
 1609    frame_goal(Frame).
 1610prolog_message(frame(Frame, choice, PC)) -->
 1611    !,
 1612    prolog_message(frame(Frame, backtrace, PC)).
 1613prolog_message(frame(_, cut_call, _)) --> !, [].
 1614prolog_message(frame(Goal, trace(Port))) -->
 1615    !,
 1616    thread_context,
 1617    [ ' T ' ],
 1618    port(Port),
 1619    goal(Goal).
 1620prolog_message(frame(Goal, trace(Port, Id))) -->
 1621    !,
 1622    thread_context,
 1623    [ ' T ' ],
 1624    port(Port, Id),
 1625    goal(Goal).
 1626prolog_message(frame(Frame, Port, _PC)) -->
 1627    frame_flags(Frame),
 1628    port(Port),
 1629    frame_level(Frame),
 1630    frame_context(Frame),
 1631    frame_depth_limit(Port, Frame),
 1632    frame_goal(Frame),
 1633    [ flush ].
 1634
 1635frame_goal(Frame) -->
 1636    { prolog_frame_attribute(Frame, goal, Goal)
 1637    },
 1638    goal(Goal).
 1639
 1640goal(Goal0) -->
 1641    { clean_goal(Goal0, Goal),
 1642      current_prolog_flag(debugger_write_options, Options)
 1643    },
 1644    [ '~W'-[Goal, Options] ].
 1645
 1646frame_level(Frame) -->
 1647    { prolog_frame_attribute(Frame, level, Level)
 1648    },
 1649    [ '(~D) '-[Level] ].
 1650
 1651frame_context(Frame) -->
 1652    (   { current_prolog_flag(debugger_show_context, true),
 1653          prolog_frame_attribute(Frame, context_module, Context)
 1654        }
 1655    ->  [ '[~w] '-[Context] ]
 1656    ;   []
 1657    ).
 1658
 1659frame_depth_limit(fail, Frame) -->
 1660    { prolog_frame_attribute(Frame, depth_limit_exceeded, true)
 1661    },
 1662    !,
 1663    [ '[depth-limit exceeded] ' ].
 1664frame_depth_limit(_, _) -->
 1665    [].
 1666
 1667frame_flags(Frame) -->
 1668    { prolog_frame_attribute(Frame, goal, Goal),
 1669      (   predicate_property(Goal, transparent)
 1670      ->  T = '^'
 1671      ;   T = ' '
 1672      ),
 1673      (   predicate_property(Goal, spying)
 1674      ->  S = '*'
 1675      ;   S = ' '
 1676      )
 1677    },
 1678    [ '~w~w '-[T, S] ].
 1679
 1680% trace/1,2 context handling
 1681port(Port, _Id-Level) -->
 1682    [ '[~d] '-Level ],
 1683    port(Port).
 1684
 1685port(Port) -->
 1686    { port_name(Port, Name)
 1687    },
 1688    !,
 1689    [ ansi(port(Port), '~w: ', [Name]) ].
 1690
 1691port_name(call,      'Call').
 1692port_name(exit,      'Exit').
 1693port_name(fail,      'Fail').
 1694port_name(redo,      'Redo').
 1695port_name(unify,     'Unify').
 1696port_name(exception, 'Exception').
 1697
 1698clean_goal(M:Goal, Goal) :-
 1699    hidden_module(M),
 1700    !.
 1701clean_goal(M:Goal, Goal) :-
 1702    predicate_property(M:Goal, built_in),
 1703    !.
 1704clean_goal(Goal, Goal).
 1705
 1706
 1707                 /*******************************
 1708                 *        COMPATIBILITY         *
 1709                 *******************************/
 1710
 1711prolog_message(compatibility(renamed(Old, New))) -->
 1712    [ 'The predicate ~p has been renamed to ~p.'-[Old, New], nl,
 1713      'Please update your sources for compatibility with future versions.'
 1714    ].
 1715
 1716
 1717                 /*******************************
 1718                 *            THREADS           *
 1719                 *******************************/
 1720
 1721prolog_message(abnormal_thread_completion(Goal, exception(Ex))) -->
 1722    !,
 1723    [ 'Thread running "~p" died on exception: '-[Goal] ],
 1724    translate_message(Ex).
 1725prolog_message(abnormal_thread_completion(Goal, fail)) -->
 1726    [ 'Thread running "~p" died due to failure'-[Goal] ].
 1727prolog_message(threads_not_died(Running)) -->
 1728    [ 'The following threads wouldn\'t die: ~p'-[Running] ].
 1729
 1730
 1731                 /*******************************
 1732                 *             PACKS            *
 1733                 *******************************/
 1734
 1735prolog_message(pack(attached(Pack, BaseDir))) -->
 1736    [ 'Attached package ~w at ~q'-[Pack, BaseDir] ].
 1737prolog_message(pack(duplicate(Entry, OldDir, Dir))) -->
 1738    [ 'Package ~w already attached at ~q.'-[Entry,OldDir], nl,
 1739      '\tIgnoring version from ~q'- [Dir]
 1740    ].
 1741prolog_message(pack(no_arch(Entry, Arch))) -->
 1742    [ 'Package ~w: no binary for architecture ~w'-[Entry, Arch] ].
 1743
 1744                 /*******************************
 1745                 *             MISC             *
 1746                 *******************************/
 1747
 1748prolog_message(null_byte_in_path(Component)) -->
 1749    [ '0-byte in PATH component: ~p (skipped directory)'-[Component] ].
 1750prolog_message(invalid_tmp_dir(Dir, Reason)) -->
 1751    [ 'Cannot use ~p as temporary file directory: ~w'-[Dir, Reason] ].
 1752prolog_message(ambiguous_stream_pair(Pair)) -->
 1753    [ 'Ambiguous operation on stream pair ~p'-[Pair] ].
 1754prolog_message(backcomp(init_file_moved(FoundFile))) -->
 1755    { absolute_file_name(app_config('init.pl'), InitFile,
 1756                         [ file_errors(fail)
 1757                         ])
 1758    },
 1759    [ 'The location of the config file has moved'-[], nl,
 1760      '  from "~w"'-[FoundFile], nl,
 1761      '  to   "~w"'-[InitFile], nl,
 1762      '  See https://www.swi-prolog.org/modified/config-files.html'-[]
 1763    ].
 1764
 1765		 /*******************************
 1766		 *          DEPRECATED		*
 1767		 *******************************/
 1768
 1769deprecated(set_prolog_stack(_Stack,limit)) -->
 1770    [ 'set_prolog_stack/2: limit(Size) sets the combined limit.'-[], nl,
 1771      'See https://www.swi-prolog.org/changes/stack-limit.html'
 1772    ].
 1773
 1774		 /*******************************
 1775		 *           TRIPWIRES		*
 1776		 *******************************/
 1777
 1778tripwire_message(Wire, Context) -->
 1779    [ 'Trapped tripwire ~w for '-[Wire] ],
 1780    tripwire_context(Wire, Context).
 1781
 1782tripwire_context(_, ATrie) -->
 1783    { '$is_answer_trie'(ATrie, _),
 1784      !,
 1785      '$tabling':atrie_goal(ATrie, QGoal),
 1786      user_predicate_indicator(QGoal, Goal)
 1787    },
 1788    [ '~p'-[Goal] ].
 1789tripwire_context(_, Ctx) -->
 1790    [ '~p'-[Ctx] ].
 1791
 1792
 1793		 /*******************************
 1794		 *     INTERNATIONALIZATION	*
 1795		 *******************************/
 1796
 1797:- create_prolog_flag(message_language, default, []). 1798
 1799%!  message_lang(-Lang) is multi.
 1800%
 1801%   True when Lang is a language id  preferred for messages. Starts with
 1802%   the most specific language (e.g., `nl_BE`) and ends with `en`.
 1803
 1804message_lang(Lang) :-
 1805    current_message_lang(Lang0),
 1806    (   Lang0 == en
 1807    ->  Lang = en
 1808    ;   sub_atom(Lang0, 0, _, _, en_)
 1809    ->  longest_id(Lang0, Lang)
 1810    ;   (   longest_id(Lang0, Lang)
 1811        ;   Lang = en
 1812        )
 1813    ).
 1814
 1815longest_id(Lang, Id) :-
 1816    split_string(Lang, "_-", "", [H|Components]),
 1817    longest_prefix(Components, Taken),
 1818    atomic_list_concat([H|Taken], '_', Id).
 1819
 1820longest_prefix([H|T0], [H|T]) :-
 1821    longest_prefix(T0, T).
 1822longest_prefix(_, []).
 1823
 1824%!  current_message_lang(-Lang) is det.
 1825%
 1826%   Get the current language for messages.
 1827
 1828current_message_lang(Lang) :-
 1829    (   current_prolog_flag(message_language, Lang0),
 1830        Lang0 \== default
 1831    ->  Lang = Lang0
 1832    ;   os_user_lang(Lang0)
 1833    ->  clean_encoding(Lang0, Lang1),
 1834        set_prolog_flag(message_language, Lang1),
 1835        Lang = Lang1
 1836    ;   Lang = en
 1837    ).
 1838
 1839os_user_lang(Lang) :-
 1840    current_prolog_flag(windows, true),
 1841    win_get_user_preferred_ui_languages(name, [Lang|_]).
 1842os_user_lang(Lang) :-
 1843    catch(setlocale(messages, _, ''), _, fail),
 1844    setlocale(messages, Lang, Lang).
 1845os_user_lang(Lang) :-
 1846    getenv('LANG', Lang).
 1847
 1848
 1849clean_encoding(Lang0, Lang) :-
 1850    (   sub_atom(Lang0, A, _, _, '.')
 1851    ->  sub_atom(Lang0, 0, A, _, Lang)
 1852    ;   Lang = Lang0
 1853    ).
 1854
 1855		 /*******************************
 1856		 *          PRIMITIVES		*
 1857		 *******************************/
 1858
 1859code(Term) -->
 1860    code('~p', Term).
 1861
 1862code(Format, Term) -->
 1863    [ ansi(code, Format, [Term]) ].
 1864
 1865
 1866		 /*******************************
 1867		 *        DEFAULT THEME		*
 1868		 *******************************/
 1869
 1870:- public default_theme/2. 1871
 1872default_theme(var,                    [fg(red)]).
 1873default_theme(code,                   [fg(blue)]).
 1874default_theme(comment,                [fg(green)]).
 1875default_theme(warning,                [fg(red)]).
 1876default_theme(error,                  [bold, fg(red)]).
 1877default_theme(truth(false),           [bold, fg(red)]).
 1878default_theme(truth(true),            [bold]).
 1879default_theme(truth(undefined),       [bold, fg(cyan)]).
 1880default_theme(wfs(residual_program),  [fg(cyan)]).
 1881default_theme(frame(level),           [bold]).
 1882default_theme(port(call),             [bold, fg(green)]).
 1883default_theme(port(exit),             [bold, fg(green)]).
 1884default_theme(port(fail),             [bold, fg(red)]).
 1885default_theme(port(redo),             [bold, fg(yellow)]).
 1886default_theme(port(unify),            [bold, fg(blue)]).
 1887default_theme(port(exception),        [bold, fg(magenta)]).
 1888default_theme(message(informational), [fg(green)]).
 1889default_theme(message(information),   [fg(green)]).
 1890default_theme(message(debug(_)),      [fg(blue)]).
 1891default_theme(message(Level),         Attrs) :-
 1892    nonvar(Level),
 1893    default_theme(Level, Attrs).
 1894
 1895
 1896                 /*******************************
 1897                 *      PRINTING MESSAGES       *
 1898                 *******************************/
 1899
 1900:- multifile
 1901    user:message_hook/3,
 1902    prolog:message_prefix_hook/2. 1903:- dynamic
 1904    user:message_hook/3,
 1905    prolog:message_prefix_hook/2. 1906:- thread_local
 1907    user:thread_message_hook/3. 1908:- '$hide'((push_msg/1,pop_msg/0)). 1909
 1910%!  print_message(+Kind, +Term)
 1911%
 1912%   Print an error message using a term as generated by the exception
 1913%   system.
 1914
 1915print_message(Level, Term) :-
 1916    setup_call_cleanup(
 1917        push_msg(Term),
 1918        print_message_guarded(Level, Term),
 1919        pop_msg),
 1920    !.
 1921print_message(Level, Term) :-
 1922    (   Level \== silent
 1923    ->  format(user_error, 'Recursive ~w message: ~q~n', [Level, Term])
 1924    ;   true
 1925    ).
 1926
 1927push_msg(Term) :-
 1928    nb_current('$inprint_message', Messages),
 1929    !,
 1930    \+ ( '$member'(Msg, Messages),
 1931         Msg =@= Term
 1932       ),
 1933    b_setval('$inprint_message', [Term|Messages]).
 1934push_msg(Term) :-
 1935    b_setval('$inprint_message', [Term]).
 1936
 1937pop_msg :-
 1938    (   nb_current('$inprint_message', [_|Messages]),
 1939        Messages \== []
 1940    ->  b_setval('$inprint_message', Messages)
 1941    ;   nb_delete('$inprint_message'),              % delete history
 1942        b_setval('$inprint_message', [])
 1943    ).
 1944
 1945print_message_guarded(Level, Term) :-
 1946    (   must_print(Level, Term)
 1947    ->  (   translate_message(Term, Lines, [])
 1948        ->  (   nonvar(Term),
 1949                (   notrace(user:thread_message_hook(Term, Level, Lines))
 1950                ->  true
 1951                ;   notrace(user:message_hook(Term, Level, Lines))
 1952                )
 1953            ->  true
 1954            ;   '$inc_message_count'(Level),
 1955                print_system_message(Term, Level, Lines),
 1956                maybe_halt_on_error(Level)
 1957            )
 1958        )
 1959    ;   true
 1960    ).
 1961
 1962maybe_halt_on_error(error) :-
 1963    current_prolog_flag(on_error, halt),
 1964    !,
 1965    halt(1).
 1966maybe_halt_on_error(warning) :-
 1967    current_prolog_flag(on_warning, halt),
 1968    !,
 1969    halt(1).
 1970maybe_halt_on_error(_).
 1971
 1972
 1973%!  print_system_message(+Term, +Kind, +Lines)
 1974%
 1975%   Print the message if the user did not intecept the message.
 1976%   The first is used for errors and warnings that can be related
 1977%   to source-location.  Note that syntax errors have their own
 1978%   source-location and should therefore not be handled this way.
 1979
 1980print_system_message(_, silent, _) :- !.
 1981print_system_message(_, informational, _) :-
 1982    current_prolog_flag(verbose, silent),
 1983    !.
 1984print_system_message(_, banner, _) :-
 1985    current_prolog_flag(verbose, silent),
 1986    !.
 1987print_system_message(_, _, []) :- !.
 1988print_system_message(Term, Kind, Lines) :-
 1989    catch(flush_output(user_output), _, true),      % may not exist
 1990    source_location(File, Line),
 1991    Term \= error(syntax_error(_), _),
 1992    msg_property(Kind, location_prefix(File:Line, LocPrefix, LinePrefix)),
 1993    !,
 1994    insert_prefix(Lines, LinePrefix, Ctx, PrefixLines),
 1995    '$append'([ begin(Kind, Ctx),
 1996                LocPrefix,
 1997                nl
 1998              | PrefixLines
 1999              ],
 2000              [ end(Ctx)
 2001              ],
 2002              AllLines),
 2003    msg_property(Kind, stream(Stream)),
 2004    ignore(stream_property(Stream, position(Pos))),
 2005    print_message_lines(Stream, AllLines),
 2006    (   \+ stream_property(Stream, position(Pos)),
 2007        msg_property(Kind, wait(Wait)),
 2008        Wait > 0
 2009    ->  sleep(Wait)
 2010    ;   true
 2011    ).
 2012print_system_message(_, Kind, Lines) :-
 2013    msg_property(Kind, stream(Stream)),
 2014    print_message_lines(Stream, kind(Kind), Lines).
 2015
 2016:- multifile
 2017    user:message_property/2. 2018
 2019msg_property(Kind, Property) :-
 2020    notrace(user:message_property(Kind, Property)),
 2021    !.
 2022msg_property(Kind, prefix(Prefix)) :-
 2023    msg_prefix(Kind, Prefix),
 2024    !.
 2025msg_property(_, prefix('~N')) :- !.
 2026msg_property(query, stream(user_output)) :- !.
 2027msg_property(_, stream(user_error)) :- !.
 2028msg_property(error, tag('ERROR')).
 2029msg_property(warning, tag('Warning')).
 2030msg_property(Level,
 2031             location_prefix(File:Line,
 2032                             Prefix1-[File,Line],
 2033                             PrefixC)) :-
 2034    include_msg_location(Level),
 2035    msg_property(Level, tag(Tag)),
 2036    atomics_to_string(['~N', Tag, ': ~w:~d:'], Prefix1),
 2037    atomics_to_string(['~N', Tag, ':    '  ], PrefixC).
 2038msg_property(error,   wait(0.1)) :- !.
 2039
 2040include_msg_location(warning).
 2041include_msg_location(error).
 2042
 2043msg_prefix(debug(_), Prefix) :-
 2044    msg_context('~N% ', Prefix).
 2045msg_prefix(Level, Prefix) :-
 2046    msg_property(Level, tag(Tag)),
 2047    atomics_to_string(['~N', Tag, ': '], Prefix0),
 2048    msg_context(Prefix0, Prefix).
 2049msg_prefix(informational, '~N% ').
 2050msg_prefix(information,   '~N% ').
 2051
 2052%!  msg_context(+Prefix0, -Prefix) is det.
 2053%
 2054%   Add contextual information to a message.   This uses the Prolog flag
 2055%   `message_context`. Recognised context terms are:
 2056%
 2057%     - time
 2058%     - time(Format)
 2059%     - thread
 2060%
 2061%   In addition, the hook prolog:message_prefix_hook/2   is  called that
 2062%   allows for additional context information.
 2063
 2064msg_context(Prefix0, Prefix) :-
 2065    current_prolog_flag(message_context, Context),
 2066    is_list(Context),
 2067    !,
 2068    add_message_context(Context, Prefix0, Prefix).
 2069msg_context(Prefix, Prefix).
 2070
 2071add_message_context([], Prefix, Prefix).
 2072add_message_context([H|T], Prefix0, Prefix) :-
 2073    (   add_message_context1(H, Prefix0, Prefix1)
 2074    ->  true
 2075    ;   Prefix1 = Prefix0
 2076    ),
 2077    add_message_context(T, Prefix1, Prefix).
 2078
 2079add_message_context1(Context, Prefix0, Prefix) :-
 2080    prolog:message_prefix_hook(Context, Extra),
 2081    atomics_to_string([Prefix0, Extra, ' '], Prefix).
 2082add_message_context1(time, Prefix0, Prefix) :-
 2083    get_time(Now),
 2084    format_time(string(S), '%T.%3f ', Now),
 2085    string_concat(Prefix0, S, Prefix).
 2086add_message_context1(time(Format), Prefix0, Prefix) :-
 2087    get_time(Now),
 2088    format_time(string(S), Format, Now),
 2089    atomics_to_string([Prefix0, S, ' '], Prefix).
 2090add_message_context1(thread, Prefix0, Prefix) :-
 2091    thread_self(Id0),
 2092    Id0 \== main,
 2093    !,
 2094    (   atom(Id0)
 2095    ->  Id = Id0
 2096    ;   thread_property(Id0, id(Id))
 2097    ),
 2098    format(string(Prefix), '~w[Thread ~w] ', [Prefix0, Id]).
 2099
 2100%!  print_message_lines(+Stream, +PrefixOrKind, +Lines)
 2101%
 2102%   Quintus compatibility predicate to print message lines using
 2103%   a prefix.
 2104
 2105print_message_lines(Stream, kind(Kind), Lines) :-
 2106    !,
 2107    msg_property(Kind, prefix(Prefix)),
 2108    insert_prefix(Lines, Prefix, Ctx, PrefixLines),
 2109    '$append'([ begin(Kind, Ctx)
 2110              | PrefixLines
 2111              ],
 2112              [ end(Ctx)
 2113              ],
 2114              AllLines),
 2115    print_message_lines(Stream, AllLines).
 2116print_message_lines(Stream, Prefix, Lines) :-
 2117    insert_prefix(Lines, Prefix, _, PrefixLines),
 2118    print_message_lines(Stream, PrefixLines).
 2119
 2120%!  insert_prefix(+Lines, +Prefix, +Ctx, -PrefixedLines)
 2121
 2122insert_prefix([at_same_line|Lines0], Prefix, Ctx, Lines) :-
 2123    !,
 2124    prefix_nl(Lines0, Prefix, Ctx, Lines).
 2125insert_prefix(Lines0, Prefix, Ctx, [prefix(Prefix)|Lines]) :-
 2126    prefix_nl(Lines0, Prefix, Ctx, Lines).
 2127
 2128prefix_nl([], _, _, [nl]).
 2129prefix_nl([nl], _, _, [nl]) :- !.
 2130prefix_nl([flush], _, _, [flush]) :- !.
 2131prefix_nl([nl|T0], Prefix, Ctx, [nl, prefix(Prefix)|T]) :-
 2132    !,
 2133    prefix_nl(T0, Prefix, Ctx, T).
 2134prefix_nl([ansi(Attrs,Fmt,Args)|T0], Prefix, Ctx,
 2135          [ansi(Attrs,Fmt,Args,Ctx)|T]) :-
 2136    !,
 2137    prefix_nl(T0, Prefix, Ctx, T).
 2138prefix_nl([H|T0], Prefix, Ctx, [H|T]) :-
 2139    prefix_nl(T0, Prefix, Ctx, T).
 2140
 2141%!  print_message_lines(+Stream, +Lines)
 2142
 2143print_message_lines(Stream, Lines) :-
 2144    with_output_to(
 2145        Stream,
 2146        notrace(print_message_lines_guarded(current_output, Lines))).
 2147
 2148print_message_lines_guarded(_, []) :- !.
 2149print_message_lines_guarded(S, [H|T]) :-
 2150    line_element(S, H),
 2151    print_message_lines_guarded(S, T).
 2152
 2153line_element(S, E) :-
 2154    prolog:message_line_element(S, E),
 2155    !.
 2156line_element(S, full_stop) :-
 2157    !,
 2158    '$put_token'(S, '.').           % insert space if needed.
 2159line_element(S, nl) :-
 2160    !,
 2161    nl(S).
 2162line_element(S, prefix(Fmt-Args)) :-
 2163    !,
 2164    safe_format(S, Fmt, Args).
 2165line_element(S, prefix(Fmt)) :-
 2166    !,
 2167    safe_format(S, Fmt, []).
 2168line_element(S, flush) :-
 2169    !,
 2170    flush_output(S).
 2171line_element(S, Fmt-Args) :-
 2172    !,
 2173    safe_format(S, Fmt, Args).
 2174line_element(S, ansi(_, Fmt, Args)) :-
 2175    !,
 2176    safe_format(S, Fmt, Args).
 2177line_element(S, ansi(_, Fmt, Args, _Ctx)) :-
 2178    !,
 2179    safe_format(S, Fmt, Args).
 2180line_element(_, begin(_Level, _Ctx)) :- !.
 2181line_element(_, end(_Ctx)) :- !.
 2182line_element(S, Fmt) :-
 2183    safe_format(S, Fmt, []).
 2184
 2185%!  safe_format(+Stream, +Format, +Args) is det.
 2186
 2187safe_format(S, Fmt, Args) :-
 2188    E = error(_,_),
 2189    catch(format(S,Fmt,Args), E,
 2190          format_failed(S,Fmt,Args,E)).
 2191
 2192format_failed(S, _Fmt, _Args, E) :-
 2193    E = error(io_error(_,S),_),
 2194    !,
 2195    throw(E).
 2196format_failed(S, Fmt, Args, error(E,_)) :-
 2197    format(S, '~N    [[ EXCEPTION while printing message ~q~n\c
 2198                        ~7|with arguments ~W:~n\c
 2199                        ~7|raised: ~W~n~4|]]~n',
 2200           [ Fmt,
 2201             Args, [quoted(true), max_depth(10)],
 2202             E, [quoted(true), max_depth(10)]
 2203           ]).
 2204
 2205%!  message_to_string(+Term, -String)
 2206%
 2207%   Translate an error term into a string
 2208
 2209message_to_string(Term, Str) :-
 2210    translate_message(Term, Actions, []),
 2211    !,
 2212    actions_to_format(Actions, Fmt, Args),
 2213    format(string(Str), Fmt, Args).
 2214
 2215actions_to_format([], '', []) :- !.
 2216actions_to_format([nl], '', []) :- !.
 2217actions_to_format([Term, nl], Fmt, Args) :-
 2218    !,
 2219    actions_to_format([Term], Fmt, Args).
 2220actions_to_format([nl|T], Fmt, Args) :-
 2221    !,
 2222    actions_to_format(T, Fmt0, Args),
 2223    atom_concat('~n', Fmt0, Fmt).
 2224actions_to_format([ansi(_Attrs, Fmt0, Args0)|Tail], Fmt, Args) :-
 2225    !,
 2226    actions_to_format(Tail, Fmt1, Args1),
 2227    atom_concat(Fmt0, Fmt1, Fmt),
 2228    append_args(Args0, Args1, Args).
 2229actions_to_format([Fmt0-Args0|Tail], Fmt, Args) :-
 2230    !,
 2231    actions_to_format(Tail, Fmt1, Args1),
 2232    atom_concat(Fmt0, Fmt1, Fmt),
 2233    append_args(Args0, Args1, Args).
 2234actions_to_format([Skip|T], Fmt, Args) :-
 2235    action_skip(Skip),
 2236    !,
 2237    actions_to_format(T, Fmt, Args).
 2238actions_to_format([Term|Tail], Fmt, Args) :-
 2239    atomic(Term),
 2240    !,
 2241    actions_to_format(Tail, Fmt1, Args),
 2242    atom_concat(Term, Fmt1, Fmt).
 2243actions_to_format([Term|Tail], Fmt, Args) :-
 2244    actions_to_format(Tail, Fmt1, Args1),
 2245    atom_concat('~w', Fmt1, Fmt),
 2246    append_args([Term], Args1, Args).
 2247
 2248action_skip(at_same_line).
 2249action_skip(flush).
 2250action_skip(begin(_Level, _Ctx)).
 2251action_skip(end(_Ctx)).
 2252
 2253append_args(M:Args0, Args1, M:Args) :-
 2254    !,
 2255    strip_module(Args1, _, A1),
 2256    '$append'(Args0, A1, Args).
 2257append_args(Args0, Args1, Args) :-
 2258    strip_module(Args1, _, A1),
 2259    '$append'(Args0, A1, Args).
 2260
 2261
 2262                 /*******************************
 2263                 *    MESSAGES TO PRINT ONCE    *
 2264                 *******************************/
 2265
 2266:- dynamic
 2267    printed/2. 2268
 2269%!  print_once(Message, Level)
 2270%
 2271%   True for messages that must be printed only once.
 2272
 2273print_once(compatibility(_), _).
 2274print_once(null_byte_in_path(_), _).
 2275print_once(deprecated(_), _).
 2276
 2277%!  must_print(+Level, +Message)
 2278%
 2279%   True if the message must be printed.
 2280
 2281must_print(Level, Message) :-
 2282    nonvar(Message),
 2283    print_once(Message, Level),
 2284    !,
 2285    \+ printed(Message, Level),
 2286    assert(printed(Message, Level)).
 2287must_print(_, _)