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