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/projects/xpce/
    6    Copyright (c)  2006-2022, 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(prolog_xref,
   39          [ xref_source/1,              % +Source
   40            xref_source/2,              % +Source, +Options
   41            xref_called/3,              % ?Source, ?Callable, ?By
   42            xref_called/4,              % ?Source, ?Callable, ?By, ?Cond
   43            xref_called/5,              % ?Source, ?Callable, ?By, ?Cond, ?Line
   44            xref_defined/3,             % ?Source. ?Callable, -How
   45            xref_definition_line/2,     % +How, -Line
   46            xref_exported/2,            % ?Source, ?Callable
   47            xref_module/2,              % ?Source, ?Module
   48            xref_uses_file/3,           % ?Source, ?Spec, ?Path
   49            xref_op/2,                  % ?Source, ?Op
   50            xref_prolog_flag/4,         % ?Source, ?Flag, ?Value, ?Line
   51            xref_comment/3,             % ?Source, ?Title, ?Comment
   52            xref_comment/4,             % ?Source, ?Head, ?Summary, ?Comment
   53            xref_mode/3,                % ?Source, ?Mode, ?Det
   54            xref_option/2,              % ?Source, ?Option
   55            xref_clean/1,               % +Source
   56            xref_current_source/1,      % ?Source
   57            xref_done/2,                % +Source, -When
   58            xref_built_in/1,            % ?Callable
   59            xref_source_file/3,         % +Spec, -Path, +Source
   60            xref_source_file/4,         % +Spec, -Path, +Source, +Options
   61            xref_public_list/3,         % +File, +Src, +Options
   62            xref_public_list/4,         % +File, -Path, -Export, +Src
   63            xref_public_list/6,         % +File, -Path, -Module, -Export, -Meta, +Src
   64            xref_public_list/7,         % +File, -Path, -Module, -Export, -Public, -Meta, +Src
   65            xref_meta/3,                % +Source, +Goal, -Called
   66            xref_meta/2,                % +Goal, -Called
   67            xref_hook/1,                % ?Callable
   68                                        % XPCE class references
   69            xref_used_class/2,          % ?Source, ?ClassName
   70            xref_defined_class/3        % ?Source, ?ClassName, -How
   71          ]).   72:- autoload(library(apply),[maplist/2,partition/4,maplist/3]).   73:- autoload(library(debug),[debug/3]).   74:- autoload(library(dialect),[expects_dialect/1]).   75:- autoload(library(error),[must_be/2,instantiation_error/1]).   76:- autoload(library(lists),[member/2,append/2,append/3,select/3]).   77:- autoload(library(modules),[in_temporary_module/3]).   78:- autoload(library(operators),[push_op/3]).   79:- autoload(library(option),[option/2,option/3]).   80:- autoload(library(ordsets),[ord_intersect/2,ord_intersection/3]).   81:- autoload(library(prolog_code), [pi_head/2]).   82:- autoload(library(prolog_source),
   83	    [ prolog_canonical_source/2,
   84	      prolog_open_source/2,
   85	      prolog_close_source/1,
   86	      prolog_read_source_term/4
   87	    ]).   88
   89:- if(exists_source(library(shlib))).   90:- autoload(library(shlib),[current_foreign_library/2]).   91:- endif.   92:- autoload(library(solution_sequences),[distinct/2,limit/2]).   93
   94:- if(exists_source(library(pldoc))).   95:- use_module(library(pldoc), []).      % Must be loaded before doc_process
   96:- use_module(library(pldoc/doc_process)).   97
   98:- endif.   99
  100:- predicate_options(xref_source/2, 2,
  101                     [ silent(boolean),
  102                       module(atom),
  103                       register_called(oneof([all,non_iso,non_built_in])),
  104                       comments(oneof([store,collect,ignore])),
  105                       process_include(boolean)
  106                     ]).  107
  108
  109:- dynamic
  110    called/5,                       % Head, Src, From, Cond, Line
  111    (dynamic)/3,                    % Head, Src, Line
  112    (thread_local)/3,               % Head, Src, Line
  113    (multifile)/3,                  % Head, Src, Line
  114    (public)/3,                     % Head, Src, Line
  115    defined/3,                      % Head, Src, Line
  116    meta_goal/3,                    % Head, Called, Src
  117    foreign/3,                      % Head, Src, Line
  118    constraint/3,                   % Head, Src, Line
  119    imported/3,                     % Head, Src, From
  120    exported/2,                     % Head, Src
  121    xmodule/2,                      % Module, Src
  122    uses_file/3,                    % Spec, Src, Path
  123    xop/2,                          % Src, Op
  124    source/2,                       % Src, Time
  125    used_class/2,                   % Name, Src
  126    defined_class/5,                % Name, Super, Summary, Src, Line
  127    (mode)/2,                       % Mode, Src
  128    xoption/2,                      % Src, Option
  129    xflag/4,                        % Name, Value, Src, Line
  130
  131    module_comment/3,               % Src, Title, Comment
  132    pred_comment/4,                 % Head, Src, Summary, Comment
  133    pred_comment_link/3,            % Head, Src, HeadTo
  134    pred_mode/3.                    % Head, Src, Det
  135
  136:- create_prolog_flag(xref, false, [type(boolean)]).  137
  138/** <module> Prolog cross-referencer data collection
  139
  140This library collects information on defined and used objects in Prolog
  141source files. Typically these are predicates, but we expect the library
  142to deal with other types of objects in the future. The library is a
  143building block for tools doing dependency tracking in applications.
  144Dependency tracking is useful to reveal the structure of an unknown
  145program or detect missing components at compile time, but also for
  146program transformation or minimising a program saved state by only
  147saving the reachable objects.
  148
  149The library is exploited by two graphical tools in the SWI-Prolog
  150environment: the XPCE front-end started by gxref/0, and
  151library(prolog_colour), which exploits this library for its syntax
  152highlighting.
  153
  154For all predicates described below, `Source` is the source that is
  155processed. This is normally a filename in any notation acceptable to the
  156file loading predicates (see load_files/2). Input handling is done by
  157the library(prolog_source), which may be hooked to process any source
  158that can be translated into a Prolog stream holding Prolog source text.
  159`Callable` is a callable term (see callable/1). Callables do not
  160carry a module qualifier unless the referred predicate is not in the
  161module defined by `Source`.
  162
  163@bug    meta_predicate/1 declarations take the module into consideration.
  164        Predicates that are both available as meta-predicate and normal
  165        (in different modules) are handled as meta-predicate in all
  166        places.
  167@see	Where this library analyses _source text_, library(prolog_codewalk)
  168	may be used to analyse _loaded code_.  The library(check) exploits
  169        library(prolog_codewalk) to report on e.g., undefined
  170        predicates.
  171*/
  172
  173:- predicate_options(xref_source_file/4, 4,
  174                     [ file_type(oneof([txt,prolog,directory])),
  175                       silent(boolean)
  176                     ]).  177:- predicate_options(xref_public_list/3, 3,
  178                     [ path(-atom),
  179                       module(-atom),
  180                       exports(-list(any)),
  181                       public(-list(any)),
  182                       meta(-list(any)),
  183                       silent(boolean)
  184                     ]).  185
  186
  187                 /*******************************
  188                 *            HOOKS             *
  189                 *******************************/
  190
  191%!  prolog:called_by(+Goal, +Module, +Context, -Called) is semidet.
  192%
  193%   True when Called is a list of callable terms called from Goal,
  194%   handled by the predicate Module:Goal and executed in the context
  195%   of the module Context.  Elements of Called may be qualified.  If
  196%   not, they are called in the context of the module Context.
  197
  198%!  prolog:called_by(+Goal, -ListOfCalled)
  199%
  200%   If this succeeds, the cross-referencer assumes Goal may call any
  201%   of the goals in  ListOfCalled.  If   this  call  fails,  default
  202%   meta-goal analysis is used to determine additional called goals.
  203%
  204%   @deprecated     New code should use prolog:called_by/4
  205
  206%!  prolog:meta_goal(+Goal, -Pattern)
  207%
  208%   Define meta-predicates. See  the  examples   in  this  file  for
  209%   details.
  210
  211%!  prolog:hook(Goal)
  212%
  213%   True if Goal is a hook that  is called spontaneously (e.g., from
  214%   foreign code).
  215
  216:- multifile
  217    prolog:called_by/4,             % +Goal, +Module, +Context, -Called
  218    prolog:called_by/2,             % +Goal, -Called
  219    prolog:meta_goal/2,             % +Goal, -Pattern
  220    prolog:hook/1,                  % +Callable
  221    prolog:generated_predicate/1,   % :PI
  222    prolog:no_autoload_module/1.    % Module is not suitable for autoloading.
  223
  224:- meta_predicate
  225    prolog:generated_predicate(:).  226
  227:- dynamic
  228    meta_goal/2.  229
  230:- meta_predicate
  231    process_predicates(2, +, +).  232
  233                 /*******************************
  234                 *           BUILT-INS          *
  235                 *******************************/
  236
  237%!  hide_called(:Callable, +Src) is semidet.
  238%
  239%   True when the cross-referencer should   not  include Callable as
  240%   being   called.   This   is    determined     by    the   option
  241%   =register_called=.
  242
  243hide_called(Callable, Src) :-
  244    xoption(Src, register_called(Which)),
  245    !,
  246    mode_hide_called(Which, Callable).
  247hide_called(Callable, _) :-
  248    mode_hide_called(non_built_in, Callable).
  249
  250mode_hide_called(all, _) :- !, fail.
  251mode_hide_called(non_iso, _:Goal) :-
  252    goal_name_arity(Goal, Name, Arity),
  253    current_predicate(system:Name/Arity),
  254    predicate_property(system:Goal, iso).
  255mode_hide_called(non_built_in, _:Goal) :-
  256    goal_name_arity(Goal, Name, Arity),
  257    current_predicate(system:Name/Arity),
  258    predicate_property(system:Goal, built_in).
  259mode_hide_called(non_built_in, M:Goal) :-
  260    goal_name_arity(Goal, Name, Arity),
  261    current_predicate(M:Name/Arity),
  262    predicate_property(M:Goal, built_in).
  263
  264%!  built_in_predicate(+Callable)
  265%
  266%   True if Callable is a built-in
  267
  268system_predicate(Goal) :-
  269    goal_name_arity(Goal, Name, Arity),
  270    current_predicate(system:Name/Arity),   % avoid autoloading
  271    predicate_property(system:Goal, built_in),
  272    !.
  273
  274
  275                /********************************
  276                *            TOPLEVEL           *
  277                ********************************/
  278
  279verbose(Src) :-
  280    \+ xoption(Src, silent(true)).
  281
  282:- thread_local
  283    xref_input/2.                   % File, Stream
  284
  285
  286%!  xref_source(+Source) is det.
  287%!  xref_source(+Source, +Options) is det.
  288%
  289%   Generate the cross-reference data  for   Source  if  not already
  290%   done and the source is not modified.  Checking for modifications
  291%   is only done for files.  Options processed:
  292%
  293%     * silent(+Boolean)
  294%     If =true= (default =false=), emit warning messages.
  295%     * module(+Module)
  296%     Define the initial context module to work in.
  297%     * register_called(+Which)
  298%     Determines which calls are registerd.  Which is one of
  299%     =all=, =non_iso= or =non_built_in=.
  300%     * comments(+CommentHandling)
  301%     How to handle comments.  If =store=, comments are stored into
  302%     the database as if the file was compiled. If =collect=,
  303%     comments are entered to the xref database and made available
  304%     through xref_mode/2 and xref_comment/4.  If =ignore=,
  305%     comments are simply ignored. Default is to =collect= comments.
  306%     * process_include(+Boolean)
  307%     Process the content of included files (default is `true`).
  308%
  309%   @param Source   File specification or XPCE buffer
  310
  311xref_source(Source) :-
  312    xref_source(Source, []).
  313
  314xref_source(Source, Options) :-
  315    prolog_canonical_source(Source, Src),
  316    (   last_modified(Source, Modified)
  317    ->  (   source(Src, Modified)
  318        ->  true
  319        ;   xref_clean(Src),
  320            assert(source(Src, Modified)),
  321            do_xref(Src, Options)
  322        )
  323    ;   xref_clean(Src),
  324        get_time(Now),
  325        assert(source(Src, Now)),
  326        do_xref(Src, Options)
  327    ).
  328
  329do_xref(Src, Options) :-
  330    must_be(list, Options),
  331    setup_call_cleanup(
  332        xref_setup(Src, In, Options, State),
  333        collect(Src, Src, In, Options),
  334        xref_cleanup(State)).
  335
  336last_modified(Source, Modified) :-
  337    prolog:xref_source_time(Source, Modified),
  338    !.
  339last_modified(Source, Modified) :-
  340    atom(Source),
  341    \+ is_global_url(Source),
  342    exists_file(Source),
  343    time_file(Source, Modified).
  344
  345is_global_url(File) :-
  346    sub_atom(File, B, _, _, '://'),
  347    !,
  348    B > 1,
  349    sub_atom(File, 0, B, _, Scheme),
  350    atom_codes(Scheme, Codes),
  351    maplist(between(0'a, 0'z), Codes).
  352
  353xref_setup(Src, In, Options, state(In, Dialect, Xref, [SRef|HRefs])) :-
  354    maplist(assert_option(Src), Options),
  355    assert_default_options(Src),
  356    current_prolog_flag(emulated_dialect, Dialect),
  357    prolog_open_source(Src, In),
  358    set_initial_mode(In, Options),
  359    asserta(xref_input(Src, In), SRef),
  360    set_xref(Xref),
  361    (   verbose(Src)
  362    ->  HRefs = []
  363    ;   asserta((user:thread_message_hook(_,Level,_) :-
  364                     hide_message(Level)),
  365                Ref),
  366        HRefs = [Ref]
  367    ).
  368
  369hide_message(warning).
  370hide_message(error).
  371hide_message(informational).
  372
  373assert_option(_, Var) :-
  374    var(Var),
  375    !,
  376    instantiation_error(Var).
  377assert_option(Src, silent(Boolean)) :-
  378    !,
  379    must_be(boolean, Boolean),
  380    assert(xoption(Src, silent(Boolean))).
  381assert_option(Src, register_called(Which)) :-
  382    !,
  383    must_be(oneof([all,non_iso,non_built_in]), Which),
  384    assert(xoption(Src, register_called(Which))).
  385assert_option(Src, comments(CommentHandling)) :-
  386    !,
  387    must_be(oneof([store,collect,ignore]), CommentHandling),
  388    assert(xoption(Src, comments(CommentHandling))).
  389assert_option(Src, module(Module)) :-
  390    !,
  391    must_be(atom, Module),
  392    assert(xoption(Src, module(Module))).
  393assert_option(Src, process_include(Boolean)) :-
  394    !,
  395    must_be(boolean, Boolean),
  396    assert(xoption(Src, process_include(Boolean))).
  397
  398assert_default_options(Src) :-
  399    (   xref_option_default(Opt),
  400        generalise_term(Opt, Gen),
  401        (   xoption(Src, Gen)
  402        ->  true
  403        ;   assertz(xoption(Src, Opt))
  404        ),
  405        fail
  406    ;   true
  407    ).
  408
  409xref_option_default(silent(false)).
  410xref_option_default(register_called(non_built_in)).
  411xref_option_default(comments(collect)).
  412xref_option_default(process_include(true)).
  413
  414%!  xref_cleanup(+State) is det.
  415%
  416%   Restore processing state according to the saved State.
  417
  418xref_cleanup(state(In, Dialect, Xref, Refs)) :-
  419    prolog_close_source(In),
  420    set_prolog_flag(emulated_dialect, Dialect),
  421    set_prolog_flag(xref, Xref),
  422    maplist(erase, Refs).
  423
  424set_xref(Xref) :-
  425    current_prolog_flag(xref, Xref),
  426    set_prolog_flag(xref, true).
  427
  428%!  set_initial_mode(+Stream, +Options) is det.
  429%
  430%   Set  the  initial  mode  for  processing    this   file  in  the
  431%   cross-referencer. If the file is loaded, we use information from
  432%   the previous load context, setting   the  appropriate module and
  433%   dialect.
  434
  435set_initial_mode(_Stream, Options) :-
  436    option(module(Module), Options),
  437    !,
  438    '$set_source_module'(Module).
  439set_initial_mode(Stream, _) :-
  440    stream_property(Stream, file_name(Path)),
  441    source_file_property(Path, load_context(M, _, Opts)),
  442    !,
  443    '$set_source_module'(M),
  444    (   option(dialect(Dialect), Opts)
  445    ->  expects_dialect(Dialect)
  446    ;   true
  447    ).
  448set_initial_mode(_, _) :-
  449    '$set_source_module'(user).
  450
  451%!  xref_input_stream(-Stream) is det.
  452%
  453%   Current input stream for cross-referencer.
  454
  455xref_input_stream(Stream) :-
  456    xref_input(_, Var),
  457    !,
  458    Stream = Var.
  459
  460%!  xref_push_op(Source, +Prec, +Type, :Name)
  461%
  462%   Define operators into the default source module and register
  463%   them to be undone by pop_operators/0.
  464
  465xref_push_op(Src, P, T, N0) :-
  466    '$current_source_module'(M0),
  467    strip_module(M0:N0, M, N),
  468    (   is_list(N),
  469        N \== []
  470    ->  maplist(push_op(Src, P, T, M), N)
  471    ;   push_op(Src, P, T, M, N)
  472    ).
  473
  474push_op(Src, P, T, M0, N0) :-
  475    strip_module(M0:N0, M, N),
  476    Name = M:N,
  477    valid_op(op(P,T,Name)),
  478    push_op(P, T, Name),
  479    assert_op(Src, op(P,T,Name)),
  480    debug(xref(op), ':- ~w.', [op(P,T,Name)]).
  481
  482valid_op(op(P,T,M:N)) :-
  483    atom(M),
  484    valid_op_name(N),
  485    integer(P),
  486    between(0, 1200, P),
  487    atom(T),
  488    op_type(T).
  489
  490valid_op_name(N) :-
  491    atom(N),
  492    !.
  493valid_op_name(N) :-
  494    N == [].
  495
  496op_type(xf).
  497op_type(yf).
  498op_type(fx).
  499op_type(fy).
  500op_type(xfx).
  501op_type(xfy).
  502op_type(yfx).
  503
  504%!  xref_set_prolog_flag(+Flag, +Value, +Src, +Line)
  505%
  506%   Called when a directive sets a Prolog flag.
  507
  508xref_set_prolog_flag(Flag, Value, Src, Line) :-
  509    atom(Flag),
  510    !,
  511    assertz(xflag(Flag, Value, Src, Line)).
  512xref_set_prolog_flag(_, _, _, _).
  513
  514%!  xref_clean(+Source) is det.
  515%
  516%   Reset the database for the given source.
  517
  518xref_clean(Source) :-
  519    prolog_canonical_source(Source, Src),
  520    retractall(called(_, Src, _Origin, _Cond, _Line)),
  521    retractall(dynamic(_, Src, Line)),
  522    retractall(multifile(_, Src, Line)),
  523    retractall(public(_, Src, Line)),
  524    retractall(defined(_, Src, Line)),
  525    retractall(meta_goal(_, _, Src)),
  526    retractall(foreign(_, Src, Line)),
  527    retractall(constraint(_, Src, Line)),
  528    retractall(imported(_, Src, _From)),
  529    retractall(exported(_, Src)),
  530    retractall(uses_file(_, Src, _)),
  531    retractall(xmodule(_, Src)),
  532    retractall(xop(Src, _)),
  533    retractall(xoption(Src, _)),
  534    retractall(xflag(_Name, _Value, Src, Line)),
  535    retractall(source(Src, _)),
  536    retractall(used_class(_, Src)),
  537    retractall(defined_class(_, _, _, Src, _)),
  538    retractall(mode(_, Src)),
  539    retractall(module_comment(Src, _, _)),
  540    retractall(pred_comment(_, Src, _, _)),
  541    retractall(pred_comment_link(_, Src, _)),
  542    retractall(pred_mode(_, Src, _)).
  543
  544
  545                 /*******************************
  546                 *          READ RESULTS        *
  547                 *******************************/
  548
  549%!  xref_current_source(?Source)
  550%
  551%   Check what sources have been analysed.
  552
  553xref_current_source(Source) :-
  554    source(Source, _Time).
  555
  556
  557%!  xref_done(+Source, -Time) is det.
  558%
  559%   Cross-reference executed at Time
  560
  561xref_done(Source, Time) :-
  562    prolog_canonical_source(Source, Src),
  563    source(Src, Time).
  564
  565
  566%!  xref_called(?Source, ?Called, ?By) is nondet.
  567%!  xref_called(?Source, ?Called, ?By, ?Cond) is nondet.
  568%!  xref_called(?Source, ?Called, ?By, ?Cond, ?Line) is nondet.
  569%
  570%   True  when  By  is  called  from    Called   in  Source.  Note  that
  571%   xref_called/3  and  xref_called/4  use  distinct/2  to  return  only
  572%   distinct `Called-By` pairs. The  xref_called/5   version  may return
  573%   duplicate `Called-By` if Called is called   from multiple clauses in
  574%   By, but at most one call per clause.
  575%
  576%   @arg By is a head term or one of the reserved terms
  577%   `'<directive>'(Line)` or `'<public>'(Line)`, indicating the call
  578%   is from an (often initialization/1) directive or there is a public/1
  579%   directive that claims the predicate is called from in some
  580%   untractable way.
  581%   @arg Cond is the (accumulated) condition as defined by
  582%   ``:- if(Cond)`` under which the calling code is compiled.
  583%   @arg Line is the _start line_ of the calling clause.
  584
  585xref_called(Source, Called, By) :-
  586    xref_called(Source, Called, By, _).
  587
  588xref_called(Source, Called, By, Cond) :-
  589    canonical_source(Source, Src),
  590    distinct(Called-By, called(Called, Src, By, Cond, _)).
  591
  592xref_called(Source, Called, By, Cond, Line) :-
  593    canonical_source(Source, Src),
  594    called(Called, Src, By, Cond, Line).
  595
  596%!  xref_defined(?Source, +Goal, ?How) is nondet.
  597%
  598%   Test if Goal is accessible in Source.   If this is the case, How
  599%   specifies the reason why the predicate  is accessible. Note that
  600%   this predicate does not deal with built-in or global predicates,
  601%   just locally defined and imported ones.  How   is  one of of the
  602%   terms below. Location is one of Line (an integer) or File:Line
  603%   if the definition comes from an included (using :-
  604%   include(File)) directive.
  605%
  606%     * dynamic(Location)
  607%     * thread_local(Location)
  608%     * multifile(Location)
  609%     * public(Location)
  610%     * local(Location)
  611%     * foreign(Location)
  612%     * constraint(Location)
  613%     * imported(From)
  614
  615xref_defined(Source, Called, How) :-
  616    nonvar(Source),
  617    !,
  618    canonical_source(Source, Src),
  619    xref_defined2(How, Src, Called).
  620xref_defined(Source, Called, How) :-
  621    xref_defined2(How, Src, Called),
  622    canonical_source(Source, Src).
  623
  624xref_defined2(dynamic(Line), Src, Called) :-
  625    dynamic(Called, Src, Line).
  626xref_defined2(thread_local(Line), Src, Called) :-
  627    thread_local(Called, Src, Line).
  628xref_defined2(multifile(Line), Src, Called) :-
  629    multifile(Called, Src, Line).
  630xref_defined2(public(Line), Src, Called) :-
  631    public(Called, Src, Line).
  632xref_defined2(local(Line), Src, Called) :-
  633    defined(Called, Src, Line).
  634xref_defined2(foreign(Line), Src, Called) :-
  635    foreign(Called, Src, Line).
  636xref_defined2(constraint(Line), Src, Called) :-
  637    constraint(Called, Src, Line).
  638xref_defined2(imported(From), Src, Called) :-
  639    imported(Called, Src, From).
  640
  641
  642%!  xref_definition_line(+How, -Line)
  643%
  644%   If the 3th argument of xref_defined contains line info, return
  645%   this in Line.
  646
  647xref_definition_line(local(Line),        Line).
  648xref_definition_line(dynamic(Line),      Line).
  649xref_definition_line(thread_local(Line), Line).
  650xref_definition_line(multifile(Line),    Line).
  651xref_definition_line(public(Line),       Line).
  652xref_definition_line(constraint(Line),   Line).
  653xref_definition_line(foreign(Line),      Line).
  654
  655
  656%!  xref_exported(?Source, ?Head) is nondet.
  657%
  658%   True when Source exports Head.
  659
  660xref_exported(Source, Called) :-
  661    prolog_canonical_source(Source, Src),
  662    exported(Called, Src).
  663
  664%!  xref_module(?Source, ?Module) is nondet.
  665%
  666%   True if Module is defined in Source.
  667
  668xref_module(Source, Module) :-
  669    nonvar(Source),
  670    !,
  671    prolog_canonical_source(Source, Src),
  672    xmodule(Module, Src).
  673xref_module(Source, Module) :-
  674    xmodule(Module, Src),
  675    prolog_canonical_source(Source, Src).
  676
  677%!  xref_uses_file(?Source, ?Spec, ?Path) is nondet.
  678%
  679%   True when Source tries to load a file using Spec.
  680%
  681%   @param Spec is a specification for absolute_file_name/3
  682%   @param Path is either an absolute file name of the target
  683%          file or the atom =|<not_found>|=.
  684
  685xref_uses_file(Source, Spec, Path) :-
  686    prolog_canonical_source(Source, Src),
  687    uses_file(Spec, Src, Path).
  688
  689%!  xref_op(?Source, Op) is nondet.
  690%
  691%   Give the operators active inside the module. This is intended to
  692%   setup the environment for incremental parsing of a term from the
  693%   source-file.
  694%
  695%   @param Op       Term of the form op(Priority, Type, Name)
  696
  697xref_op(Source, Op) :-
  698    prolog_canonical_source(Source, Src),
  699    xop(Src, Op).
  700
  701%!  xref_prolog_flag(?Source, ?Flag, ?Value, ?Line) is nondet.
  702%
  703%   True when Flag is set  to  Value   at  Line  in  Source. This is
  704%   intended to support incremental  parsing  of   a  term  from the
  705%   source-file.
  706
  707xref_prolog_flag(Source, Flag, Value, Line) :-
  708    prolog_canonical_source(Source, Src),
  709    xflag(Flag, Value, Src, Line).
  710
  711xref_built_in(Head) :-
  712    system_predicate(Head).
  713
  714xref_used_class(Source, Class) :-
  715    prolog_canonical_source(Source, Src),
  716    used_class(Class, Src).
  717
  718xref_defined_class(Source, Class, local(Line, Super, Summary)) :-
  719    prolog_canonical_source(Source, Src),
  720    defined_class(Class, Super, Summary, Src, Line),
  721    integer(Line),
  722    !.
  723xref_defined_class(Source, Class, file(File)) :-
  724    prolog_canonical_source(Source, Src),
  725    defined_class(Class, _, _, Src, file(File)).
  726
  727:- thread_local
  728    current_cond/1,
  729    source_line/1,
  730    current_test_unit/2.  731
  732current_source_line(Line) :-
  733    source_line(Var),
  734    !,
  735    Line = Var.
  736
  737%!  collect(+Source, +File, +Stream, +Options)
  738%
  739%   Process data from Source. If File  \== Source, we are processing
  740%   an included file. Stream is the stream   from  shich we read the
  741%   program.
  742
  743collect(Src, File, In, Options) :-
  744    (   Src == File
  745    ->  SrcSpec = Line
  746    ;   SrcSpec = (File:Line)
  747    ),
  748    option(comments(CommentHandling), Options, collect),
  749    (   CommentHandling == ignore
  750    ->  CommentOptions = [],
  751        Comments = []
  752    ;   CommentHandling == store
  753    ->  CommentOptions = [ process_comment(true) ],
  754        Comments = []
  755    ;   CommentOptions = [ comments(Comments) ]
  756    ),
  757    repeat,
  758        catch(prolog_read_source_term(
  759                  In, Term, Expanded,
  760                  [ term_position(TermPos)
  761                  | CommentOptions
  762                  ]),
  763              E, report_syntax_error(E, Src, [])),
  764        update_condition(Term),
  765        stream_position_data(line_count, TermPos, Line),
  766        setup_call_cleanup(
  767            asserta(source_line(SrcSpec), Ref),
  768            catch(process(Expanded, Comments, Term, TermPos, Src, EOF),
  769                  E, print_message(error, E)),
  770            erase(Ref)),
  771        EOF == true,
  772    !.
  773
  774report_syntax_error(E, _, _) :-
  775    fatal_error(E),
  776    throw(E).
  777report_syntax_error(_, _, Options) :-
  778    option(silent(true), Options),
  779    !,
  780    fail.
  781report_syntax_error(E, Src, _Options) :-
  782    (   verbose(Src)
  783    ->  print_message(error, E)
  784    ;   true
  785    ),
  786    fail.
  787
  788fatal_error(time_limit_exceeded).
  789fatal_error(error(resource_error(_),_)).
  790
  791%!  update_condition(+Term) is det.
  792%
  793%   Update the condition under which the current code is compiled.
  794
  795update_condition((:-Directive)) :-
  796    !,
  797    update_cond(Directive).
  798update_condition(_).
  799
  800update_cond(if(Cond)) :-
  801    !,
  802    asserta(current_cond(Cond)).
  803update_cond(else) :-
  804    retract(current_cond(C0)),
  805    !,
  806    assert(current_cond(\+C0)).
  807update_cond(elif(Cond)) :-
  808    retract(current_cond(C0)),
  809    !,
  810    assert(current_cond((\+C0,Cond))).
  811update_cond(endif) :-
  812    retract(current_cond(_)),
  813    !.
  814update_cond(_).
  815
  816%!  current_condition(-Condition) is det.
  817%
  818%   Condition is the current compilation condition as defined by the
  819%   :- if/1 directive and friends.
  820
  821current_condition(Condition) :-
  822    \+ current_cond(_),
  823    !,
  824    Condition = true.
  825current_condition(Condition) :-
  826    findall(C, current_cond(C), List),
  827    list_to_conj(List, Condition).
  828
  829list_to_conj([], true).
  830list_to_conj([C], C) :- !.
  831list_to_conj([H|T], (H,C)) :-
  832    list_to_conj(T, C).
  833
  834
  835                 /*******************************
  836                 *           PROCESS            *
  837                 *******************************/
  838
  839%!  process(+Expanded, +Comments, +Term, +TermPos, +Src, -EOF) is det.
  840%
  841%   Process a source term that has  been   subject  to term expansion as
  842%   well as its optional leading structured comments.
  843%
  844%   @arg TermPos is the term position that describes the start of the
  845%   term.  We need this to find _leading_ comments.
  846%   @arg EOF is unified with a boolean to indicate whether or not
  847%   processing was stopped because `end_of_file` was processed.
  848
  849process(Expanded, Comments, Term0, TermPos, Src, EOF) :-
  850    is_list(Expanded),                          % term_expansion into list.
  851    !,
  852    (   member(Term, Expanded),
  853        process(Term, Term0, Src),
  854        Term == end_of_file
  855    ->  EOF = true
  856    ;   EOF = false
  857    ),
  858    xref_comments(Comments, TermPos, Src).
  859process(end_of_file, _, _, _, _, true) :-
  860    !.
  861process(Term, Comments, Term0, TermPos, Src, false) :-
  862    process(Term, Term0, Src),
  863    xref_comments(Comments, TermPos, Src).
  864
  865%!  process(+Term, +Term0, +Src) is det.
  866
  867process(_, Term0, _) :-
  868    ignore_raw_term(Term0),
  869    !.
  870process(Term, _Term0, Src) :-
  871    process(Term, Src).
  872
  873ignore_raw_term((:- predicate_options(_,_,_))).
  874
  875%!  process(+Term, +Src) is det.
  876
  877process(Var, _) :-
  878    var(Var),
  879    !.                    % Warn?
  880process(end_of_file, _) :- !.
  881process((:- Directive), Src) :-
  882    !,
  883    process_directive(Directive, Src),
  884    !.
  885process((?- Directive), Src) :-
  886    !,
  887    process_directive(Directive, Src),
  888    !.
  889process((Head :- Body), Src) :-
  890    !,
  891    assert_defined(Src, Head),
  892    process_body(Body, Head, Src).
  893process((Left => Body), Src) :-
  894    !,
  895    (   nonvar(Left),
  896        Left = (Head, Guard)
  897    ->  assert_defined(Src, Head),
  898        process_body(Guard, Head, Src),
  899        process_body(Body, Head, Src)
  900    ;   assert_defined(Src, Left),
  901        process_body(Body, Left, Src)
  902    ).
  903process(?=>(Head, Body), Src) :-
  904    !,
  905    assert_defined(Src, Head),
  906    process_body(Body, Head, Src).
  907process('$source_location'(_File, _Line):Clause, Src) :-
  908    !,
  909    process(Clause, Src).
  910process(Term, Src) :-
  911    process_chr(Term, Src),
  912    !.
  913process(M:(Head :- Body), Src) :-
  914    !,
  915    process((M:Head :- M:Body), Src).
  916process(Head, Src) :-
  917    assert_defined(Src, Head).
  918
  919
  920                 /*******************************
  921                 *            COMMENTS          *
  922                 *******************************/
  923
  924%!  xref_comments(+Comments, +FilePos, +Src) is det.
  925
  926xref_comments([], _Pos, _Src).
  927:- if(current_predicate(parse_comment/3)).  928xref_comments([Pos-Comment|T], TermPos, Src) :-
  929    (   Pos @> TermPos              % comments inside term
  930    ->  true
  931    ;   stream_position_data(line_count, Pos, Line),
  932        FilePos = Src:Line,
  933        (   parse_comment(Comment, FilePos, Parsed)
  934        ->  assert_comments(Parsed, Src)
  935        ;   true
  936        ),
  937        xref_comments(T, TermPos, Src)
  938    ).
  939
  940assert_comments([], _).
  941assert_comments([H|T], Src) :-
  942    assert_comment(H, Src),
  943    assert_comments(T, Src).
  944
  945assert_comment(section(_Id, Title, Comment), Src) :-
  946    assertz(module_comment(Src, Title, Comment)).
  947assert_comment(predicate(PI, Summary, Comment), Src) :-
  948    pi_to_head(PI, Src, Head),
  949    assertz(pred_comment(Head, Src, Summary, Comment)).
  950assert_comment(link(PI, PITo), Src) :-
  951    pi_to_head(PI, Src, Head),
  952    pi_to_head(PITo, Src, HeadTo),
  953    assertz(pred_comment_link(Head, Src, HeadTo)).
  954assert_comment(mode(Head, Det), Src) :-
  955    assertz(pred_mode(Head, Src, Det)).
  956
  957pi_to_head(PI, Src, Head) :-
  958    pi_to_head(PI, Head0),
  959    (   Head0 = _:_
  960    ->  strip_module(Head0, M, Plain),
  961        (   xmodule(M, Src)
  962        ->  Head = Plain
  963        ;   Head = M:Plain
  964        )
  965    ;   Head = Head0
  966    ).
  967:- endif.  968
  969%!  xref_comment(?Source, ?Title, ?Comment) is nondet.
  970%
  971%   Is true when Source has a section comment with Title and Comment
  972
  973xref_comment(Source, Title, Comment) :-
  974    canonical_source(Source, Src),
  975    module_comment(Src, Title, Comment).
  976
  977%!  xref_comment(?Source, ?Head, ?Summary, ?Comment) is nondet.
  978%
  979%   Is true when Head in Source has the given PlDoc comment.
  980
  981xref_comment(Source, Head, Summary, Comment) :-
  982    canonical_source(Source, Src),
  983    (   pred_comment(Head, Src, Summary, Comment)
  984    ;   pred_comment_link(Head, Src, HeadTo),
  985        pred_comment(HeadTo, Src, Summary, Comment)
  986    ).
  987
  988%!  xref_mode(?Source, ?Mode, ?Det) is nondet.
  989%
  990%   Is  true  when  Source  provides  a   predicate  with  Mode  and
  991%   determinism.
  992
  993xref_mode(Source, Mode, Det) :-
  994    canonical_source(Source, Src),
  995    pred_mode(Mode, Src, Det).
  996
  997%!  xref_option(?Source, ?Option) is nondet.
  998%
  999%   True when Source was processed using Option. Options are defined
 1000%   with xref_source/2.
 1001
 1002xref_option(Source, Option) :-
 1003    canonical_source(Source, Src),
 1004    xoption(Src, Option).
 1005
 1006
 1007                 /********************************
 1008                 *           DIRECTIVES         *
 1009                 ********************************/
 1010
 1011process_directive(Var, _) :-
 1012    var(Var),
 1013    !.                    % error, but that isn't our business
 1014process_directive(Dir, _Src) :-
 1015    debug(xref(directive), 'Processing :- ~q', [Dir]),
 1016    fail.
 1017process_directive((A,B), Src) :-       % TBD: what about other control
 1018    !,
 1019    process_directive(A, Src),      % structures?
 1020    process_directive(B, Src).
 1021process_directive(List, Src) :-
 1022    is_list(List),
 1023    !,
 1024    process_directive(consult(List), Src).
 1025process_directive(use_module(File, Import), Src) :-
 1026    process_use_module2(File, Import, Src, false).
 1027process_directive(autoload(File, Import), Src) :-
 1028    process_use_module2(File, Import, Src, false).
 1029process_directive(require(Import), Src) :-
 1030    process_requires(Import, Src).
 1031process_directive(expects_dialect(Dialect), Src) :-
 1032    process_directive(use_module(library(dialect/Dialect)), Src),
 1033    expects_dialect(Dialect).
 1034process_directive(reexport(File, Import), Src) :-
 1035    process_use_module2(File, Import, Src, true).
 1036process_directive(reexport(Modules), Src) :-
 1037    process_use_module(Modules, Src, true).
 1038process_directive(autoload(Modules), Src) :-
 1039    process_use_module(Modules, Src, false).
 1040process_directive(use_module(Modules), Src) :-
 1041    process_use_module(Modules, Src, false).
 1042process_directive(consult(Modules), Src) :-
 1043    process_use_module(Modules, Src, false).
 1044process_directive(ensure_loaded(Modules), Src) :-
 1045    process_use_module(Modules, Src, false).
 1046process_directive(load_files(Files, _Options), Src) :-
 1047    process_use_module(Files, Src, false).
 1048process_directive(include(Files), Src) :-
 1049    process_include(Files, Src).
 1050process_directive(dynamic(Dynamic), Src) :-
 1051    process_predicates(assert_dynamic, Dynamic, Src).
 1052process_directive(dynamic(Dynamic, _Options), Src) :-
 1053    process_predicates(assert_dynamic, Dynamic, Src).
 1054process_directive(thread_local(Dynamic), Src) :-
 1055    process_predicates(assert_thread_local, Dynamic, Src).
 1056process_directive(multifile(Dynamic), Src) :-
 1057    process_predicates(assert_multifile, Dynamic, Src).
 1058process_directive(public(Public), Src) :-
 1059    process_predicates(assert_public, Public, Src).
 1060process_directive(export(Export), Src) :-
 1061    process_predicates(assert_export, Export, Src).
 1062process_directive(import(Import), Src) :-
 1063    process_import(Import, Src).
 1064process_directive(module(Module, Export), Src) :-
 1065    assert_module(Src, Module),
 1066    assert_module_export(Src, Export).
 1067process_directive(module(Module, Export, Import), Src) :-
 1068    assert_module(Src, Module),
 1069    assert_module_export(Src, Export),
 1070    assert_module3(Import, Src).
 1071process_directive(begin_tests(Unit, _Options), Src) :-
 1072    enter_test_unit(Unit, Src).
 1073process_directive(begin_tests(Unit), Src) :-
 1074    enter_test_unit(Unit, Src).
 1075process_directive(end_tests(Unit), Src) :-
 1076    leave_test_unit(Unit, Src).
 1077process_directive('$set_source_module'(system), Src) :-
 1078    assert_module(Src, system).     % hack for handling boot/init.pl
 1079process_directive(pce_begin_class_definition(Name, Meta, Super, Doc), Src) :-
 1080    assert_defined_class(Src, Name, Meta, Super, Doc).
 1081process_directive(pce_autoload(Name, From), Src) :-
 1082    assert_defined_class(Src, Name, imported_from(From)).
 1083
 1084process_directive(op(P, A, N), Src) :-
 1085    xref_push_op(Src, P, A, N).
 1086process_directive(set_prolog_flag(Flag, Value), Src) :-
 1087    (   Flag == character_escapes
 1088    ->  set_prolog_flag(character_escapes, Value)
 1089    ;   true
 1090    ),
 1091    current_source_line(Line),
 1092    xref_set_prolog_flag(Flag, Value, Src, Line).
 1093process_directive(style_check(X), _) :-
 1094    style_check(X).
 1095process_directive(encoding(Enc), _) :-
 1096    (   xref_input_stream(Stream)
 1097    ->  catch(set_stream(Stream, encoding(Enc)), _, true)
 1098    ;   true                        % can this happen?
 1099    ).
 1100process_directive(pce_expansion:push_compile_operators, _) :-
 1101    '$current_source_module'(SM),
 1102    call(pce_expansion:push_compile_operators(SM)). % call to avoid xref
 1103process_directive(pce_expansion:pop_compile_operators, _) :-
 1104    call(pce_expansion:pop_compile_operators).
 1105process_directive(meta_predicate(Meta), Src) :-
 1106    process_meta_predicate(Meta, Src).
 1107process_directive(arithmetic_function(FSpec), Src) :-
 1108    arith_callable(FSpec, Goal),
 1109    !,
 1110    current_source_line(Line),
 1111    assert_called(Src, '<directive>'(Line), Goal, Line).
 1112process_directive(format_predicate(_, Goal), Src) :-
 1113    !,
 1114    current_source_line(Line),
 1115    assert_called(Src, '<directive>'(Line), Goal, Line).
 1116process_directive(if(Cond), Src) :-
 1117    !,
 1118    current_source_line(Line),
 1119    assert_called(Src, '<directive>'(Line), Cond, Line).
 1120process_directive(elif(Cond), Src) :-
 1121    !,
 1122    current_source_line(Line),
 1123    assert_called(Src, '<directive>'(Line), Cond, Line).
 1124process_directive(else, _) :- !.
 1125process_directive(endif, _) :- !.
 1126process_directive(Goal, Src) :-
 1127    current_source_line(Line),
 1128    process_body(Goal, '<directive>'(Line), Src).
 1129
 1130%!  process_meta_predicate(+Decl, +Src)
 1131%
 1132%   Create meta_goal/3 facts from the meta-goal declaration.
 1133
 1134process_meta_predicate((A,B), Src) :-
 1135    !,
 1136    process_meta_predicate(A, Src),
 1137    process_meta_predicate(B, Src).
 1138process_meta_predicate(Decl, Src) :-
 1139    process_meta_head(Src, Decl).
 1140
 1141process_meta_head(Src, Decl) :-         % swapped arguments for maplist
 1142    compound(Decl),
 1143    compound_name_arity(Decl, Name, Arity),
 1144    compound_name_arity(Head, Name, Arity),
 1145    meta_args(1, Arity, Decl, Head, Meta),
 1146    (   (   prolog:meta_goal(Head, _)
 1147        ;   prolog:called_by(Head, _, _, _)
 1148        ;   prolog:called_by(Head, _)
 1149        ;   meta_goal(Head, _)
 1150        )
 1151    ->  true
 1152    ;   assert(meta_goal(Head, Meta, Src))
 1153    ).
 1154
 1155meta_args(I, Arity, _, _, []) :-
 1156    I > Arity,
 1157    !.
 1158meta_args(I, Arity, Decl, Head, [H|T]) :-               % 0
 1159    arg(I, Decl, 0),
 1160    !,
 1161    arg(I, Head, H),
 1162    I2 is I + 1,
 1163    meta_args(I2, Arity, Decl, Head, T).
 1164meta_args(I, Arity, Decl, Head, [H|T]) :-               % ^
 1165    arg(I, Decl, ^),
 1166    !,
 1167    arg(I, Head, EH),
 1168    setof_goal(EH, H),
 1169    I2 is I + 1,
 1170    meta_args(I2, Arity, Decl, Head, T).
 1171meta_args(I, Arity, Decl, Head, [//(H)|T]) :-
 1172    arg(I, Decl, //),
 1173    !,
 1174    arg(I, Head, H),
 1175    I2 is I + 1,
 1176    meta_args(I2, Arity, Decl, Head, T).
 1177meta_args(I, Arity, Decl, Head, [H+A|T]) :-             % I --> H+I
 1178    arg(I, Decl, A),
 1179    integer(A), A > 0,
 1180    !,
 1181    arg(I, Head, H),
 1182    I2 is I + 1,
 1183    meta_args(I2, Arity, Decl, Head, T).
 1184meta_args(I, Arity, Decl, Head, Meta) :-
 1185    I2 is I + 1,
 1186    meta_args(I2, Arity, Decl, Head, Meta).
 1187
 1188
 1189              /********************************
 1190              *             BODY              *
 1191              ********************************/
 1192
 1193%!  xref_meta(+Source, +Head, -Called) is semidet.
 1194%
 1195%   True when Head calls Called in Source.
 1196%
 1197%   @arg    Called is a list of called terms, terms of the form
 1198%           Term+Extra or terms of the form //(Term).
 1199
 1200xref_meta(Source, Head, Called) :-
 1201    canonical_source(Source, Src),
 1202    xref_meta_src(Head, Called, Src).
 1203
 1204%!  xref_meta(+Head, -Called) is semidet.
 1205%!  xref_meta_src(+Head, -Called, +Src) is semidet.
 1206%
 1207%   True when Called is a  list  of   terms  called  from Head. Each
 1208%   element in Called can be of the  form Term+Int, which means that
 1209%   Term must be extended with Int additional arguments. The variant
 1210%   xref_meta/3 first queries the local context.
 1211%
 1212%   @tbd    Split predifined in several categories.  E.g., the ISO
 1213%           predicates cannot be redefined.
 1214%   @tbd    Rely on the meta_predicate property for many predicates.
 1215%   @deprecated     New code should use xref_meta/3.
 1216
 1217xref_meta_src(Head, Called, Src) :-
 1218    meta_goal(Head, Called, Src),
 1219    !.
 1220xref_meta_src(Head, Called, _) :-
 1221    xref_meta(Head, Called),
 1222    !.
 1223xref_meta_src(Head, Called, _) :-
 1224    compound(Head),
 1225    compound_name_arity(Head, Name, Arity),
 1226    apply_pred(Name),
 1227    Arity > 5,
 1228    !,
 1229    Extra is Arity - 1,
 1230    arg(1, Head, G),
 1231    Called = [G+Extra].
 1232xref_meta_src(Head, Called, _) :-
 1233    predicate_property('$xref_tmp':Head, meta_predicate(Meta)),
 1234    !,
 1235    Meta =.. [_|Args],
 1236    meta_args(Args, 1, Head, Called).
 1237
 1238meta_args([], _, _, []).
 1239meta_args([H0|T0], I, Head, [H|T]) :-
 1240    xargs(H0, N),
 1241    !,
 1242    arg(I, Head, A),
 1243    (   N == 0
 1244    ->  H = A
 1245    ;   H = (A+N)
 1246    ),
 1247    I2 is I+1,
 1248    meta_args(T0, I2, Head, T).
 1249meta_args([_|T0], I, Head, T) :-
 1250    I2 is I+1,
 1251    meta_args(T0, I2, Head, T).
 1252
 1253xargs(N, N) :- integer(N), !.
 1254xargs(//, 2).
 1255xargs(^, 0).
 1256
 1257apply_pred(call).                               % built-in
 1258apply_pred(maplist).                            % library(apply_macros)
 1259
 1260xref_meta((A, B),               [A, B]).
 1261xref_meta((A; B),               [A, B]).
 1262xref_meta((A| B),               [A, B]).
 1263xref_meta((A -> B),             [A, B]).
 1264xref_meta((A *-> B),            [A, B]).
 1265xref_meta(findall(_V,G,_L),     [G]).
 1266xref_meta(findall(_V,G,_L,_T),  [G]).
 1267xref_meta(findnsols(_N,_V,G,_L),    [G]).
 1268xref_meta(findnsols(_N,_V,G,_L,_T), [G]).
 1269xref_meta(setof(_V, EG, _L),    [G]) :-
 1270    setof_goal(EG, G).
 1271xref_meta(bagof(_V, EG, _L),    [G]) :-
 1272    setof_goal(EG, G).
 1273xref_meta(forall(A, B),         [A, B]).
 1274xref_meta(maplist(G,_),         [G+1]).
 1275xref_meta(maplist(G,_,_),       [G+2]).
 1276xref_meta(maplist(G,_,_,_),     [G+3]).
 1277xref_meta(maplist(G,_,_,_,_),   [G+4]).
 1278xref_meta(map_list_to_pairs(G,_,_), [G+2]).
 1279xref_meta(map_assoc(G, _),      [G+1]).
 1280xref_meta(map_assoc(G, _, _),   [G+2]).
 1281xref_meta(checklist(G, _L),     [G+1]).
 1282xref_meta(sublist(G, _, _),     [G+1]).
 1283xref_meta(include(G, _, _),     [G+1]).
 1284xref_meta(exclude(G, _, _),     [G+1]).
 1285xref_meta(partition(G, _, _, _, _),     [G+2]).
 1286xref_meta(partition(G, _, _, _),[G+1]).
 1287xref_meta(call(G),              [G]).
 1288xref_meta(call(G, _),           [G+1]).
 1289xref_meta(call(G, _, _),        [G+2]).
 1290xref_meta(call(G, _, _, _),     [G+3]).
 1291xref_meta(call(G, _, _, _, _),  [G+4]).
 1292xref_meta(not(G),               [G]).
 1293xref_meta(notrace(G),           [G]).
 1294xref_meta('$notrace'(G),        [G]).
 1295xref_meta(\+(G),                [G]).
 1296xref_meta(ignore(G),            [G]).
 1297xref_meta(once(G),              [G]).
 1298xref_meta(initialization(G),    [G]).
 1299xref_meta(initialization(G,_),  [G]).
 1300xref_meta(retract(Rule),        [G]) :- head_of(Rule, G).
 1301xref_meta(clause(G, _),         [G]).
 1302xref_meta(clause(G, _, _),      [G]).
 1303xref_meta(phrase(G, _A),        [//(G)]).
 1304xref_meta(phrase(G, _A, _R),    [//(G)]).
 1305xref_meta(call_dcg(G, _A, _R),  [//(G)]).
 1306xref_meta(phrase_from_file(G,_),[//(G)]).
 1307xref_meta(catch(A, _, B),       [A, B]).
 1308xref_meta(catch_with_backtrace(A, _, B), [A, B]).
 1309xref_meta(thread_create(A,_,_), [A]).
 1310xref_meta(thread_create(A,_),   [A]).
 1311xref_meta(thread_signal(_,A),   [A]).
 1312xref_meta(thread_idle(A,_),     [A]).
 1313xref_meta(thread_at_exit(A),    [A]).
 1314xref_meta(thread_initialization(A), [A]).
 1315xref_meta(engine_create(_,A,_), [A]).
 1316xref_meta(engine_create(_,A,_,_), [A]).
 1317xref_meta(transaction(A),       [A]).
 1318xref_meta(transaction(A,B,_),   [A,B]).
 1319xref_meta(snapshot(A),          [A]).
 1320xref_meta(predsort(A,_,_),      [A+3]).
 1321xref_meta(call_cleanup(A, B),   [A, B]).
 1322xref_meta(call_cleanup(A, _, B),[A, B]).
 1323xref_meta(setup_call_cleanup(A, B, C),[A, B, C]).
 1324xref_meta(setup_call_catcher_cleanup(A, B, _, C),[A, B, C]).
 1325xref_meta(call_residue_vars(A,_), [A]).
 1326xref_meta(with_mutex(_,A),      [A]).
 1327xref_meta(assume(G),            [G]).   % library(debug)
 1328xref_meta(assertion(G),         [G]).   % library(debug)
 1329xref_meta(freeze(_, G),         [G]).
 1330xref_meta(when(C, A),           [C, A]).
 1331xref_meta(time(G),              [G]).   % development system
 1332xref_meta(call_time(G, _),      [G]).   % development system
 1333xref_meta(call_time(G, _, _),   [G]).   % development system
 1334xref_meta(profile(G),           [G]).
 1335xref_meta(at_halt(G),           [G]).
 1336xref_meta(call_with_time_limit(_, G), [G]).
 1337xref_meta(call_with_depth_limit(G, _, _), [G]).
 1338xref_meta(call_with_inference_limit(G, _, _), [G]).
 1339xref_meta(alarm(_, G, _),       [G]).
 1340xref_meta(alarm(_, G, _, _),    [G]).
 1341xref_meta('$add_directive_wic'(G), [G]).
 1342xref_meta(with_output_to(_, G), [G]).
 1343xref_meta(if(G),                [G]).
 1344xref_meta(elif(G),              [G]).
 1345xref_meta(meta_options(G,_,_),  [G+1]).
 1346xref_meta(on_signal(_,_,H),     [H+1]) :- H \== default.
 1347xref_meta(distinct(G),          [G]).   % library(solution_sequences)
 1348xref_meta(distinct(_, G),       [G]).
 1349xref_meta(order_by(_, G),       [G]).
 1350xref_meta(limit(_, G),          [G]).
 1351xref_meta(offset(_, G),         [G]).
 1352xref_meta(reset(G,_,_),         [G]).
 1353xref_meta(prolog_listen(Ev,G),  [G+N]) :- event_xargs(Ev, N).
 1354xref_meta(prolog_listen(Ev,G,_),[G+N]) :- event_xargs(Ev, N).
 1355xref_meta(tnot(G),		[G]).
 1356xref_meta(not_exists(G),	[G]).
 1357xref_meta(with_tty_raw(G),	[G]).
 1358xref_meta(residual_goals(G),    [G+2]).
 1359
 1360                                        % XPCE meta-predicates
 1361xref_meta(pce_global(_, new(_)), _) :- !, fail.
 1362xref_meta(pce_global(_, B),     [B+1]).
 1363xref_meta(ifmaintainer(G),      [G]).   % used in manual
 1364xref_meta(listen(_, G),         [G]).   % library(broadcast)
 1365xref_meta(listen(_, _, G),      [G]).
 1366xref_meta(in_pce_thread(G),     [G]).
 1367
 1368xref_meta(G, Meta) :-                   % call user extensions
 1369    prolog:meta_goal(G, Meta).
 1370xref_meta(G, Meta) :-                   % Generated from :- meta_predicate
 1371    meta_goal(G, Meta).
 1372
 1373setof_goal(EG, G) :-
 1374    var(EG), !, G = EG.
 1375setof_goal(_^EG, G) :-
 1376    !,
 1377    setof_goal(EG, G).
 1378setof_goal(G, G).
 1379
 1380event_xargs(abort,            0).
 1381event_xargs(erase,            1).
 1382event_xargs(break,            3).
 1383event_xargs(frame_finished,   1).
 1384event_xargs(thread_exit,      1).
 1385event_xargs(this_thread_exit, 0).
 1386event_xargs(PI,               2) :- pi_to_head(PI, _).
 1387
 1388%!  head_of(+Rule, -Head)
 1389%
 1390%   Get the head for a retract call.
 1391
 1392head_of(Var, _) :-
 1393    var(Var), !, fail.
 1394head_of((Head :- _), Head).
 1395head_of(Head, Head).
 1396
 1397%!  xref_hook(?Callable)
 1398%
 1399%   Definition of known hooks.  Hooks  that   can  be  called in any
 1400%   module are unqualified.  Other  hooks   are  qualified  with the
 1401%   module where they are called.
 1402
 1403xref_hook(Hook) :-
 1404    prolog:hook(Hook).
 1405xref_hook(Hook) :-
 1406    hook(Hook).
 1407
 1408
 1409hook(attr_portray_hook(_,_)).
 1410hook(attr_unify_hook(_,_)).
 1411hook(attribute_goals(_,_,_)).
 1412hook(goal_expansion(_,_)).
 1413hook(term_expansion(_,_)).
 1414hook(resource(_,_,_)).
 1415hook('$pred_option'(_,_,_,_)).
 1416
 1417hook(emacs_prolog_colours:goal_classification(_,_)).
 1418hook(emacs_prolog_colours:term_colours(_,_)).
 1419hook(emacs_prolog_colours:goal_colours(_,_)).
 1420hook(emacs_prolog_colours:style(_,_)).
 1421hook(emacs_prolog_colours:identify(_,_)).
 1422hook(pce_principal:pce_class(_,_,_,_,_,_)).
 1423hook(pce_principal:send_implementation(_,_,_)).
 1424hook(pce_principal:get_implementation(_,_,_,_)).
 1425hook(pce_principal:pce_lazy_get_method(_,_,_)).
 1426hook(pce_principal:pce_lazy_send_method(_,_,_)).
 1427hook(pce_principal:pce_uses_template(_,_)).
 1428hook(prolog:locate_clauses(_,_)).
 1429hook(prolog:message(_,_,_)).
 1430hook(prolog:error_message(_,_,_)).
 1431hook(prolog:message_location(_,_,_)).
 1432hook(prolog:message_context(_,_,_)).
 1433hook(prolog:message_line_element(_,_)).
 1434hook(prolog:debug_control_hook(_)).
 1435hook(prolog:help_hook(_)).
 1436hook(prolog:show_profile_hook(_,_)).
 1437hook(prolog:general_exception(_,_)).
 1438hook(prolog:predicate_summary(_,_)).
 1439hook(prolog:residual_goals(_,_)).
 1440hook(prolog_edit:load).
 1441hook(prolog_edit:locate(_,_,_)).
 1442hook(shlib:unload_all_foreign_libraries).
 1443hook(system:'$foreign_registered'(_, _)).
 1444hook(predicate_options:option_decl(_,_,_)).
 1445hook(user:exception(_,_,_)).
 1446hook(user:file_search_path(_,_)).
 1447hook(user:library_directory(_)).
 1448hook(user:message_hook(_,_,_)).
 1449hook(user:portray(_)).
 1450hook(user:prolog_clause_name(_,_)).
 1451hook(user:prolog_list_goal(_)).
 1452hook(user:prolog_predicate_name(_,_)).
 1453hook(user:prolog_trace_interception(_,_,_,_)).
 1454hook(user:prolog_exception_hook(_,_,_,_)).
 1455hook(sandbox:safe_primitive(_)).
 1456hook(sandbox:safe_meta_predicate(_)).
 1457hook(sandbox:safe_meta(_,_)).
 1458hook(sandbox:safe_global_variable(_)).
 1459hook(sandbox:safe_directive(_)).
 1460
 1461
 1462%!  arith_callable(+Spec, -Callable)
 1463%
 1464%   Translate argument of arithmetic_function/1 into a callable term
 1465
 1466arith_callable(Var, _) :-
 1467    var(Var), !, fail.
 1468arith_callable(Module:Spec, Module:Goal) :-
 1469    !,
 1470    arith_callable(Spec, Goal).
 1471arith_callable(Name/Arity, Goal) :-
 1472    PredArity is Arity + 1,
 1473    functor(Goal, Name, PredArity).
 1474
 1475%!  process_body(+Body, +Origin, +Src) is det.
 1476%
 1477%   Process a callable body (body of  a clause or directive). Origin
 1478%   describes the origin of the call. Partial evaluation may lead to
 1479%   non-determinism, which is why we backtrack over process_goal/3.
 1480%
 1481%   We limit the number of explored paths   to  100 to avoid getting
 1482%   trapped in this analysis.
 1483
 1484process_body(Body, Origin, Src) :-
 1485    forall(limit(100, process_goal(Body, Origin, Src, _Partial)),
 1486           true).
 1487
 1488%!  process_goal(+Goal, +Origin, +Src, ?Partial) is multi.
 1489%
 1490%   Xref Goal. The argument Partial is bound   to  `true` if there was a
 1491%   partial evalation inside Goal that has bound variables.
 1492
 1493process_goal(Var, _, _, _) :-
 1494    var(Var),
 1495    !.
 1496process_goal(_:Goal, _, _, _) :-
 1497    var(Goal),
 1498    !.
 1499process_goal(Goal, Origin, Src, P) :-
 1500    Goal = (_,_),                               % problems
 1501    !,
 1502    phrase(conjunction(Goal), Goals),
 1503    process_conjunction(Goals, Origin, Src, P).
 1504process_goal(Goal, Origin, Src, _) :-           % Final disjunction, no
 1505    Goal = (_;_),                               % problems
 1506    !,
 1507    phrase(disjunction(Goal), Goals),
 1508    forall(member(G, Goals),
 1509           process_body(G, Origin, Src)).
 1510process_goal(Goal, Origin, Src, P) :-
 1511    (   (   xmodule(M, Src)
 1512        ->  true
 1513        ;   M = user
 1514        ),
 1515        pi_head(PI, M:Goal),
 1516        (   current_predicate(PI),
 1517            predicate_property(M:Goal, imported_from(IM))
 1518        ->  true
 1519        ;   PI = M:Name/Arity,
 1520            '$find_library'(M, Name, Arity, IM, _Library)
 1521        ->  true
 1522        ;   IM = M
 1523        ),
 1524        prolog:called_by(Goal, IM, M, Called)
 1525    ;   prolog:called_by(Goal, Called)
 1526    ),
 1527    !,
 1528    must_be(list, Called),
 1529    current_source_line(Here),
 1530    assert_called(Src, Origin, Goal, Here),
 1531    process_called_list(Called, Origin, Src, P).
 1532process_goal(Goal, Origin, Src, _) :-
 1533    process_xpce_goal(Goal, Origin, Src),
 1534    !.
 1535process_goal(load_foreign_library(File), _Origin, Src, _) :-
 1536    process_foreign(File, Src).
 1537process_goal(load_foreign_library(File, _Init), _Origin, Src, _) :-
 1538    process_foreign(File, Src).
 1539process_goal(use_foreign_library(File), _Origin, Src, _) :-
 1540    process_foreign(File, Src).
 1541process_goal(use_foreign_library(File, _Init), _Origin, Src, _) :-
 1542    process_foreign(File, Src).
 1543process_goal(Goal, Origin, Src, P) :-
 1544    xref_meta_src(Goal, Metas, Src),
 1545    !,
 1546    current_source_line(Here),
 1547    assert_called(Src, Origin, Goal, Here),
 1548    process_called_list(Metas, Origin, Src, P).
 1549process_goal(Goal, Origin, Src, _) :-
 1550    asserting_goal(Goal, Rule),
 1551    !,
 1552    current_source_line(Here),
 1553    assert_called(Src, Origin, Goal, Here),
 1554    process_assert(Rule, Origin, Src).
 1555process_goal(Goal, Origin, Src, P) :-
 1556    partial_evaluate(Goal, P),
 1557    current_source_line(Here),
 1558    assert_called(Src, Origin, Goal, Here).
 1559
 1560disjunction(Var)   --> {var(Var), !}, [Var].
 1561disjunction((A;B)) --> !, disjunction(A), disjunction(B).
 1562disjunction(G)     --> [G].
 1563
 1564conjunction(Var)   --> {var(Var), !}, [Var].
 1565conjunction((A,B)) --> !, conjunction(A), conjunction(B).
 1566conjunction(G)     --> [G].
 1567
 1568shares_vars(RVars, T) :-
 1569    term_variables(T, TVars0),
 1570    sort(TVars0, TVars),
 1571    ord_intersect(RVars, TVars).
 1572
 1573process_conjunction([], _, _, _).
 1574process_conjunction([Disj|Rest], Origin, Src, P) :-
 1575    nonvar(Disj),
 1576    Disj = (_;_),
 1577    Rest \== [],
 1578    !,
 1579    phrase(disjunction(Disj), Goals),
 1580    term_variables(Rest, RVars0),
 1581    sort(RVars0, RVars),
 1582    partition(shares_vars(RVars), Goals, Sharing, NonSHaring),
 1583    forall(member(G, NonSHaring),
 1584           process_body(G, Origin, Src)),
 1585    (   Sharing == []
 1586    ->  true
 1587    ;   maplist(term_variables, Sharing, GVars0),
 1588        append(GVars0, GVars1),
 1589        sort(GVars1, GVars),
 1590        ord_intersection(GVars, RVars, SVars),
 1591        VT =.. [v|SVars],
 1592        findall(VT,
 1593                (   member(G, Sharing),
 1594                    process_goal(G, Origin, Src, PS),
 1595                    PS == true
 1596                ),
 1597                Alts0),
 1598        (   Alts0 == []
 1599        ->  true
 1600        ;   (   true
 1601            ;   P = true,
 1602                sort(Alts0, Alts1),
 1603                variants(Alts1, 10, Alts),
 1604                member(VT, Alts)
 1605            )
 1606        )
 1607    ),
 1608    process_conjunction(Rest, Origin, Src, P).
 1609process_conjunction([H|T], Origin, Src, P) :-
 1610    process_goal(H, Origin, Src, P),
 1611    process_conjunction(T, Origin, Src, P).
 1612
 1613
 1614process_called_list([], _, _, _).
 1615process_called_list([H|T], Origin, Src, P) :-
 1616    process_meta(H, Origin, Src, P),
 1617    process_called_list(T, Origin, Src, P).
 1618
 1619process_meta(A+N, Origin, Src, P) :-
 1620    !,
 1621    (   extend(A, N, AX)
 1622    ->  process_goal(AX, Origin, Src, P)
 1623    ;   true
 1624    ).
 1625process_meta(//(A), Origin, Src, P) :-
 1626    !,
 1627    process_dcg_goal(A, Origin, Src, P).
 1628process_meta(G, Origin, Src, P) :-
 1629    process_goal(G, Origin, Src, P).
 1630
 1631%!  process_dcg_goal(+Grammar, +Origin, +Src, ?Partial) is det.
 1632%
 1633%   Process  meta-arguments  that  are  tagged   with  //,  such  as
 1634%   phrase/3.
 1635
 1636process_dcg_goal(Var, _, _, _) :-
 1637    var(Var),
 1638    !.
 1639process_dcg_goal((A,B), Origin, Src, P) :-
 1640    !,
 1641    process_dcg_goal(A, Origin, Src, P),
 1642    process_dcg_goal(B, Origin, Src, P).
 1643process_dcg_goal((A;B), Origin, Src, P) :-
 1644    !,
 1645    process_dcg_goal(A, Origin, Src, P),
 1646    process_dcg_goal(B, Origin, Src, P).
 1647process_dcg_goal((A|B), Origin, Src, P) :-
 1648    !,
 1649    process_dcg_goal(A, Origin, Src, P),
 1650    process_dcg_goal(B, Origin, Src, P).
 1651process_dcg_goal((A->B), Origin, Src, P) :-
 1652    !,
 1653    process_dcg_goal(A, Origin, Src, P),
 1654    process_dcg_goal(B, Origin, Src, P).
 1655process_dcg_goal((A*->B), Origin, Src, P) :-
 1656    !,
 1657    process_dcg_goal(A, Origin, Src, P),
 1658    process_dcg_goal(B, Origin, Src, P).
 1659process_dcg_goal({Goal}, Origin, Src, P) :-
 1660    !,
 1661    process_goal(Goal, Origin, Src, P).
 1662process_dcg_goal(List, _Origin, _Src, _) :-
 1663    is_list(List),
 1664    !.               % terminal
 1665process_dcg_goal(List, _Origin, _Src, _) :-
 1666    string(List),
 1667    !.                % terminal
 1668process_dcg_goal(Callable, Origin, Src, P) :-
 1669    extend(Callable, 2, Goal),
 1670    !,
 1671    process_goal(Goal, Origin, Src, P).
 1672process_dcg_goal(_, _, _, _).
 1673
 1674
 1675extend(Var, _, _) :-
 1676    var(Var), !, fail.
 1677extend(M:G, N, M:GX) :-
 1678    !,
 1679    callable(G),
 1680    extend(G, N, GX).
 1681extend(G, N, GX) :-
 1682    (   compound(G)
 1683    ->  compound_name_arguments(G, Name, Args),
 1684        length(Rest, N),
 1685        append(Args, Rest, NArgs),
 1686        compound_name_arguments(GX, Name, NArgs)
 1687    ;   atom(G)
 1688    ->  length(NArgs, N),
 1689        compound_name_arguments(GX, G, NArgs)
 1690    ).
 1691
 1692asserting_goal(assert(Rule), Rule).
 1693asserting_goal(asserta(Rule), Rule).
 1694asserting_goal(assertz(Rule), Rule).
 1695asserting_goal(assert(Rule,_), Rule).
 1696asserting_goal(asserta(Rule,_), Rule).
 1697asserting_goal(assertz(Rule,_), Rule).
 1698
 1699process_assert(0, _, _) :- !.           % catch variables
 1700process_assert((_:-Body), Origin, Src) :-
 1701    !,
 1702    process_body(Body, Origin, Src).
 1703process_assert(_, _, _).
 1704
 1705%!  variants(+SortedList, +Max, -Variants) is det.
 1706
 1707variants([], _, []).
 1708variants([H|T], Max, List) :-
 1709    variants(T, H, Max, List).
 1710
 1711variants([], H, _, [H]).
 1712variants(_, _, 0, []) :- !.
 1713variants([H|T], V, Max, List) :-
 1714    (   H =@= V
 1715    ->  variants(T, V, Max, List)
 1716    ;   List = [V|List2],
 1717        Max1 is Max-1,
 1718        variants(T, H, Max1, List2)
 1719    ).
 1720
 1721%!  partial_evaluate(+Goal, ?Parrial) is det.
 1722%
 1723%   Perform partial evaluation on Goal to trap cases such as below.
 1724%
 1725%     ==
 1726%           T = hello(X),
 1727%           findall(T, T, List),
 1728%     ==
 1729%
 1730%   @tbd    Make this user extensible? What about non-deterministic
 1731%           bindings?
 1732
 1733partial_evaluate(Goal, P) :-
 1734    eval(Goal),
 1735    !,
 1736    P = true.
 1737partial_evaluate(_, _).
 1738
 1739eval(X = Y) :-
 1740    unify_with_occurs_check(X, Y).
 1741
 1742		 /*******************************
 1743		 *        PLUNIT SUPPORT	*
 1744		 *******************************/
 1745
 1746enter_test_unit(Unit, _Src) :-
 1747    current_source_line(Line),
 1748    asserta(current_test_unit(Unit, Line)).
 1749
 1750leave_test_unit(Unit, _Src) :-
 1751    retractall(current_test_unit(Unit, _)).
 1752
 1753
 1754                 /*******************************
 1755                 *          XPCE STUFF          *
 1756                 *******************************/
 1757
 1758pce_goal(new(_,_), new(-, new)).
 1759pce_goal(send(_,_), send(arg, msg)).
 1760pce_goal(send_class(_,_,_), send_class(arg, arg, msg)).
 1761pce_goal(get(_,_,_), get(arg, msg, -)).
 1762pce_goal(get_class(_,_,_,_), get_class(arg, arg, msg, -)).
 1763pce_goal(get_chain(_,_,_), get_chain(arg, msg, -)).
 1764pce_goal(get_object(_,_,_), get_object(arg, msg, -)).
 1765
 1766process_xpce_goal(G, Origin, Src) :-
 1767    pce_goal(G, Process),
 1768    !,
 1769    current_source_line(Here),
 1770    assert_called(Src, Origin, G, Here),
 1771    (   arg(I, Process, How),
 1772        arg(I, G, Term),
 1773        process_xpce_arg(How, Term, Origin, Src),
 1774        fail
 1775    ;   true
 1776    ).
 1777
 1778process_xpce_arg(new, Term, Origin, Src) :-
 1779    callable(Term),
 1780    process_new(Term, Origin, Src).
 1781process_xpce_arg(arg, Term, Origin, Src) :-
 1782    compound(Term),
 1783    process_new(Term, Origin, Src).
 1784process_xpce_arg(msg, Term, Origin, Src) :-
 1785    compound(Term),
 1786    (   arg(_, Term, Arg),
 1787        process_xpce_arg(arg, Arg, Origin, Src),
 1788        fail
 1789    ;   true
 1790    ).
 1791
 1792process_new(_M:_Term, _, _) :- !.       % TBD: Calls on other modules!
 1793process_new(Term, Origin, Src) :-
 1794    assert_new(Src, Origin, Term),
 1795    (   compound(Term),
 1796        arg(_, Term, Arg),
 1797        process_xpce_arg(arg, Arg, Origin, Src),
 1798        fail
 1799    ;   true
 1800    ).
 1801
 1802assert_new(_, _, Term) :-
 1803    \+ callable(Term),
 1804    !.
 1805assert_new(Src, Origin, Control) :-
 1806    functor_name(Control, Class),
 1807    pce_control_class(Class),
 1808    !,
 1809    forall(arg(_, Control, Arg),
 1810           assert_new(Src, Origin, Arg)).
 1811assert_new(Src, Origin, Term) :-
 1812    compound(Term),
 1813    arg(1, Term, Prolog),
 1814    Prolog == @(prolog),
 1815    (   Term =.. [message, _, Selector | T],
 1816        atom(Selector)
 1817    ->  Called =.. [Selector|T],
 1818        process_body(Called, Origin, Src)
 1819    ;   Term =.. [?, _, Selector | T],
 1820        atom(Selector)
 1821    ->  append(T, [_R], T2),
 1822        Called =.. [Selector|T2],
 1823        process_body(Called, Origin, Src)
 1824    ),
 1825    fail.
 1826assert_new(_, _, @(_)) :- !.
 1827assert_new(Src, _, Term) :-
 1828    functor_name(Term, Name),
 1829    assert_used_class(Src, Name).
 1830
 1831
 1832pce_control_class(and).
 1833pce_control_class(or).
 1834pce_control_class(if).
 1835pce_control_class(not).
 1836
 1837
 1838                /********************************
 1839                *       INCLUDED MODULES        *
 1840                ********************************/
 1841
 1842%!  process_use_module(+Modules, +Src, +Rexport) is det.
 1843
 1844process_use_module(_Module:_Files, _, _) :- !.  % loaded in another module
 1845process_use_module([], _, _) :- !.
 1846process_use_module([H|T], Src, Reexport) :-
 1847    !,
 1848    process_use_module(H, Src, Reexport),
 1849    process_use_module(T, Src, Reexport).
 1850process_use_module(library(pce), Src, Reexport) :-     % bit special
 1851    !,
 1852    xref_public_list(library(pce), Path, Exports, Src),
 1853    forall(member(Import, Exports),
 1854           process_pce_import(Import, Src, Path, Reexport)).
 1855process_use_module(File, Src, Reexport) :-
 1856    load_module_if_needed(File),
 1857    (   xoption(Src, silent(Silent))
 1858    ->  Extra = [silent(Silent)]
 1859    ;   Extra = [silent(true)]
 1860    ),
 1861    (   xref_public_list(File, Src,
 1862                         [ path(Path),
 1863                           module(M),
 1864                           exports(Exports),
 1865                           public(Public),
 1866                           meta(Meta)
 1867                         | Extra
 1868                         ])
 1869    ->  assert(uses_file(File, Src, Path)),
 1870        assert_import(Src, Exports, _, Path, Reexport),
 1871        assert_xmodule_callable(Exports, M, Src, Path),
 1872        assert_xmodule_callable(Public, M, Src, Path),
 1873        maplist(process_meta_head(Src), Meta),
 1874        (   File = library(chr)     % hacky
 1875        ->  assert(mode(chr, Src))
 1876        ;   true
 1877        )
 1878    ;   assert(uses_file(File, Src, '<not_found>'))
 1879    ).
 1880
 1881process_pce_import(Name/Arity, Src, Path, Reexport) :-
 1882    atom(Name),
 1883    integer(Arity),
 1884    !,
 1885    functor(Term, Name, Arity),
 1886    (   \+ system_predicate(Term),
 1887        \+ Term = pce_error(_)      % hack!?
 1888    ->  assert_import(Src, [Name/Arity], _, Path, Reexport)
 1889    ;   true
 1890    ).
 1891process_pce_import(op(P,T,N), Src, _, _) :-
 1892    xref_push_op(Src, P, T, N).
 1893
 1894%!  process_use_module2(+File, +Import, +Src, +Reexport) is det.
 1895%
 1896%   Process use_module/2 and reexport/2.
 1897
 1898process_use_module2(File, Import, Src, Reexport) :-
 1899    load_module_if_needed(File),
 1900    (   xref_source_file(File, Path, Src)
 1901    ->  assert(uses_file(File, Src, Path)),
 1902        (   catch(public_list(Path, _, Meta, Export, _Public, []), _, fail)
 1903        ->  assert_import(Src, Import, Export, Path, Reexport),
 1904            forall((  member(Head, Meta),
 1905                      imported(Head, _, Path)
 1906                   ),
 1907                   process_meta_head(Src, Head))
 1908        ;   true
 1909        )
 1910    ;   assert(uses_file(File, Src, '<not_found>'))
 1911    ).
 1912
 1913
 1914%!  load_module_if_needed(+File)
 1915%
 1916%   Load a module explicitly if  it   is  not  suitable for autoloading.
 1917%   Typically this is the case  if   the  module provides essential term
 1918%   and/or goal expansion rulses.
 1919
 1920load_module_if_needed(File) :-
 1921    prolog:no_autoload_module(File),
 1922    !,
 1923    use_module(File, []).
 1924load_module_if_needed(_).
 1925
 1926prolog:no_autoload_module(library(apply_macros)).
 1927prolog:no_autoload_module(library(arithmetic)).
 1928prolog:no_autoload_module(library(record)).
 1929prolog:no_autoload_module(library(persistency)).
 1930prolog:no_autoload_module(library(pldoc)).
 1931prolog:no_autoload_module(library(settings)).
 1932prolog:no_autoload_module(library(debug)).
 1933prolog:no_autoload_module(library(plunit)).
 1934
 1935
 1936%!  process_requires(+Import, +Src)
 1937
 1938process_requires(Import, Src) :-
 1939    is_list(Import),
 1940    !,
 1941    require_list(Import, Src).
 1942process_requires(Var, _Src) :-
 1943    var(Var),
 1944    !.
 1945process_requires((A,B), Src) :-
 1946    !,
 1947    process_requires(A, Src),
 1948    process_requires(B, Src).
 1949process_requires(PI, Src) :-
 1950    requires(PI, Src).
 1951
 1952require_list([], _).
 1953require_list([H|T], Src) :-
 1954    requires(H, Src),
 1955    require_list(T, Src).
 1956
 1957requires(PI, _Src) :-
 1958    '$pi_head'(PI, Head),
 1959    '$get_predicate_attribute'(system:Head, defined, 1),
 1960    !.
 1961requires(PI, Src) :-
 1962    '$pi_head'(PI, Head),
 1963    '$pi_head'(Name/Arity, Head),
 1964    '$find_library'(_Module, Name, Arity, _LoadModule, Library),
 1965    (   imported(Head, Src, Library)
 1966    ->  true
 1967    ;   assertz(imported(Head, Src, Library))
 1968    ).
 1969
 1970
 1971%!  xref_public_list(+Spec, +Source, +Options) is semidet.
 1972%
 1973%   Find meta-information about File. This predicate reads all terms
 1974%   upto the first term that is not  a directive. It uses the module
 1975%   and  meta_predicate  directives  to   assemble  the  information
 1976%   in Options.  Options processed:
 1977%
 1978%     * path(-Path)
 1979%     Path is the full path name of the referenced file.
 1980%     * module(-Module)
 1981%     Module is the module defines in Spec.
 1982%     * exports(-Exports)
 1983%     Exports is a list of predicate indicators and operators
 1984%     collected from the module/2 term and reexport declarations.
 1985%     * public(-Public)
 1986%     Public declarations of the file.
 1987%     * meta(-Meta)
 1988%     Meta is a list of heads as they appear in meta_predicate/1
 1989%     declarations.
 1990%     * silent(+Boolean)
 1991%     Do not print any messages or raise exceptions on errors.
 1992%
 1993%   The information collected by this predicate   is  cached. The cached
 1994%   data is considered valid as long  as   the  modification time of the
 1995%   file does not change.
 1996%
 1997%   @param Source is the file from which Spec is referenced.
 1998
 1999xref_public_list(File, Src, Options) :-
 2000    option(path(Path), Options, _),
 2001    option(module(Module), Options, _),
 2002    option(exports(Exports), Options, _),
 2003    option(public(Public), Options, _),
 2004    option(meta(Meta), Options, _),
 2005    xref_source_file(File, Path, Src, Options),
 2006    public_list(Path, Module, Meta, Exports, Public, Options).
 2007
 2008%!  xref_public_list(+File, -Path, -Export, +Src) is semidet.
 2009%!  xref_public_list(+File, -Path, -Module, -Export, -Meta, +Src) is semidet.
 2010%!  xref_public_list(+File, -Path, -Module, -Export, -Public, -Meta, +Src) is semidet.
 2011%
 2012%   Find meta-information about File. This predicate reads all terms
 2013%   upto the first term that is not  a directive. It uses the module
 2014%   and  meta_predicate  directives  to   assemble  the  information
 2015%   described below.
 2016%
 2017%   These predicates fail if File is not a module-file.
 2018%
 2019%   @param  Path is the canonical path to File
 2020%   @param  Module is the module defined in Path
 2021%   @param  Export is a list of predicate indicators.
 2022%   @param  Meta is a list of heads as they appear in
 2023%           meta_predicate/1 declarations.
 2024%   @param  Src is the place from which File is referenced.
 2025%   @deprecated New code should use xref_public_list/3, which
 2026%           unifies all variations using an option list.
 2027
 2028xref_public_list(File, Path, Export, Src) :-
 2029    xref_source_file(File, Path, Src),
 2030    public_list(Path, _, _, Export, _, []).
 2031xref_public_list(File, Path, Module, Export, Meta, Src) :-
 2032    xref_source_file(File, Path, Src),
 2033    public_list(Path, Module, Meta, Export, _, []).
 2034xref_public_list(File, Path, Module, Export, Public, Meta, Src) :-
 2035    xref_source_file(File, Path, Src),
 2036    public_list(Path, Module, Meta, Export, Public, []).
 2037
 2038%!  public_list(+Path, -Module, -Meta, -Export, -Public, +Options)
 2039%
 2040%   Read the public information for Path.  Options supported are:
 2041%
 2042%     - silent(+Boolean)
 2043%       If `true`, ignore (syntax) errors.  If not specified the default
 2044%       is inherited from xref_source/2.
 2045
 2046:- dynamic  public_list_cache/6. 2047:- volatile public_list_cache/6. 2048
 2049public_list(Path, Module, Meta, Export, Public, _Options) :-
 2050    public_list_cache(Path, Modified,
 2051                      Module0, Meta0, Export0, Public0),
 2052    time_file(Path, ModifiedNow),
 2053    (   abs(Modified-ModifiedNow) < 0.0001
 2054    ->  !,
 2055        t(Module,Meta,Export,Public) = t(Module0,Meta0,Export0,Public0)
 2056    ;   retractall(public_list_cache(Path, _, _, _, _, _)),
 2057        fail
 2058    ).
 2059public_list(Path, Module, Meta, Export, Public, Options) :-
 2060    public_list_nc(Path, Module0, Meta0, Export0, Public0, Options),
 2061    (   Error = error(_,_),
 2062        catch(time_file(Path, Modified), Error, fail)
 2063    ->  asserta(public_list_cache(Path, Modified,
 2064                                  Module0, Meta0, Export0, Public0))
 2065    ;   true
 2066    ),
 2067    t(Module,Meta,Export,Public) = t(Module0,Meta0,Export0,Public0).
 2068
 2069public_list_nc(Path, Module, Meta, Export, Public, Options) :-
 2070    in_temporary_module(
 2071        TempModule,
 2072        true,
 2073        public_list_diff(TempModule, Path, Module,
 2074                         Meta, [], Export, [], Public, [], Options)).
 2075
 2076
 2077public_list_diff(TempModule,
 2078                 Path, Module, Meta, MT, Export, Rest, Public, PT, Options) :-
 2079    setup_call_cleanup(
 2080        public_list_setup(TempModule, Path, In, State),
 2081        phrase(read_directives(In, Options, [true]), Directives),
 2082        public_list_cleanup(In, State)),
 2083    public_list(Directives, Path, Module, Meta, MT, Export, Rest, Public, PT).
 2084
 2085public_list_setup(TempModule, Path, In, state(OldM, OldXref)) :-
 2086    prolog_open_source(Path, In),
 2087    '$set_source_module'(OldM, TempModule),
 2088    set_xref(OldXref).
 2089
 2090public_list_cleanup(In, state(OldM, OldXref)) :-
 2091    '$set_source_module'(OldM),
 2092    set_prolog_flag(xref, OldXref),
 2093    prolog_close_source(In).
 2094
 2095
 2096read_directives(In, Options, State) -->
 2097    {  repeat,
 2098       catch(prolog_read_source_term(In, Term, Expanded,
 2099                                     [ process_comment(true),
 2100                                       syntax_errors(error)
 2101                                     ]),
 2102             E, report_syntax_error(E, -, Options))
 2103    -> nonvar(Term),
 2104       Term = (:-_)
 2105    },
 2106    !,
 2107    terms(Expanded, State, State1),
 2108    read_directives(In, Options, State1).
 2109read_directives(_, _, _) --> [].
 2110
 2111terms(Var, State, State) --> { var(Var) }, !.
 2112terms([H|T], State0, State) -->
 2113    !,
 2114    terms(H, State0, State1),
 2115    terms(T, State1, State).
 2116terms((:-if(Cond)), State0, [True|State0]) -->
 2117    !,
 2118    { eval_cond(Cond, True) }.
 2119terms((:-elif(Cond)), [True0|State], [True|State]) -->
 2120    !,
 2121    { eval_cond(Cond, True1),
 2122      elif(True0, True1, True)
 2123    }.
 2124terms((:-else), [True0|State], [True|State]) -->
 2125    !,
 2126    { negate(True0, True) }.
 2127terms((:-endif), [_|State], State) -->  !.
 2128terms(H, State, State) -->
 2129    (   {State = [true|_]}
 2130    ->  [H]
 2131    ;   []
 2132    ).
 2133
 2134eval_cond(Cond, true) :-
 2135    catch(Cond, _, fail),
 2136    !.
 2137eval_cond(_, false).
 2138
 2139elif(true,  _,    else_false) :- !.
 2140elif(false, true, true) :- !.
 2141elif(True,  _,    True).
 2142
 2143negate(true,       false).
 2144negate(false,      true).
 2145negate(else_false, else_false).
 2146
 2147public_list([(:- module(Module, Export0))|Decls], Path,
 2148            Module, Meta, MT, Export, Rest, Public, PT) :-
 2149    !,
 2150    (   is_list(Export0)
 2151    ->  append(Export0, Reexport, Export)
 2152    ;   Reexport = Export
 2153    ),
 2154    public_list_(Decls, Path, Meta, MT, Reexport, Rest, Public, PT).
 2155public_list([(:- encoding(_))|Decls], Path,
 2156            Module, Meta, MT, Export, Rest, Public, PT) :-
 2157    public_list(Decls, Path, Module, Meta, MT, Export, Rest, Public, PT).
 2158
 2159public_list_([], _, Meta, Meta, Export, Export, Public, Public).
 2160public_list_([(:-(Dir))|T], Path, Meta, MT, Export, Rest, Public, PT) :-
 2161    public_list_1(Dir, Path, Meta, MT0, Export, Rest0, Public, PT0),
 2162    !,
 2163    public_list_(T, Path, MT0, MT, Rest0, Rest, PT0, PT).
 2164public_list_([_|T], Path, Meta, MT, Export, Rest, Public, PT) :-
 2165    public_list_(T, Path, Meta, MT, Export, Rest, Public, PT).
 2166
 2167public_list_1(reexport(Spec), Path, Meta, MT, Reexport, Rest, Public, PT) :-
 2168    reexport_files(Spec, Path, Meta, MT, Reexport, Rest, Public, PT).
 2169public_list_1(reexport(Spec, Import), Path, Meta, Meta, Reexport, Rest, Public, Public) :-
 2170    public_from_import(Import, Spec, Path, Reexport, Rest).
 2171public_list_1(meta_predicate(Decl), _Path, Meta, MT, Export, Export, Public, Public) :-
 2172    phrase(meta_decls(Decl), Meta, MT).
 2173public_list_1(public(Decl), _Path, Meta, Meta, Export, Export, Public, PT) :-
 2174    phrase(public_decls(Decl), Public, PT).
 2175
 2176%!  reexport_files(+Files, +Src,
 2177%!                 -Meta, ?MetaTail, -Exports, ?ExportsTail,
 2178%!                 -Public, ?PublicTail)
 2179
 2180reexport_files([], _, Meta, Meta, Export, Export, Public, Public) :- !.
 2181reexport_files([H|T], Src, Meta, MT, Export, ET, Public, PT) :-
 2182    !,
 2183    xref_source_file(H, Path, Src),
 2184    public_list(Path, _Module, Meta0, Export0, Public0, []),
 2185    append(Meta0, MT1, Meta),
 2186    append(Export0, ET1, Export),
 2187    append(Public0, PT1, Public),
 2188    reexport_files(T, Src, MT1, MT, ET1, ET, PT1, PT).
 2189reexport_files(Spec, Src, Meta, MT, Export, ET, Public, PT) :-
 2190    xref_source_file(Spec, Path, Src),
 2191    public_list(Path, _Module, Meta0, Export0, Public0, []),
 2192    append(Meta0, MT, Meta),
 2193    append(Export0, ET, Export),
 2194    append(Public0, PT, Public).
 2195
 2196public_from_import(except(Map), Path, Src, Export, Rest) :-
 2197    !,
 2198    xref_public_list(Path, _, AllExports, Src),
 2199    except(Map, AllExports, NewExports),
 2200    append(NewExports, Rest, Export).
 2201public_from_import(Import, _, _, Export, Rest) :-
 2202    import_name_map(Import, Export, Rest).
 2203
 2204
 2205%!  except(+Remove, +AllExports, -Exports)
 2206
 2207except([], Exports, Exports).
 2208except([PI0 as NewName|Map], Exports0, Exports) :-
 2209    !,
 2210    canonical_pi(PI0, PI),
 2211    map_as(Exports0, PI, NewName, Exports1),
 2212    except(Map, Exports1, Exports).
 2213except([PI0|Map], Exports0, Exports) :-
 2214    canonical_pi(PI0, PI),
 2215    select(PI2, Exports0, Exports1),
 2216    same_pi(PI, PI2),
 2217    !,
 2218    except(Map, Exports1, Exports).
 2219
 2220
 2221map_as([PI|T], Repl, As, [PI2|T])  :-
 2222    same_pi(Repl, PI),
 2223    !,
 2224    pi_as(PI, As, PI2).
 2225map_as([H|T0], Repl, As, [H|T])  :-
 2226    map_as(T0, Repl, As, T).
 2227
 2228pi_as(_/Arity, Name, Name/Arity).
 2229pi_as(_//Arity, Name, Name//Arity).
 2230
 2231import_name_map([], L, L).
 2232import_name_map([_/Arity as NewName|T0], [NewName/Arity|T], Tail) :-
 2233    !,
 2234    import_name_map(T0, T, Tail).
 2235import_name_map([_//Arity as NewName|T0], [NewName//Arity|T], Tail) :-
 2236    !,
 2237    import_name_map(T0, T, Tail).
 2238import_name_map([H|T0], [H|T], Tail) :-
 2239    import_name_map(T0, T, Tail).
 2240
 2241canonical_pi(Name//Arity0, PI) :-
 2242    integer(Arity0),
 2243    !,
 2244    PI = Name/Arity,
 2245    Arity is Arity0 + 2.
 2246canonical_pi(PI, PI).
 2247
 2248same_pi(Canonical, PI2) :-
 2249    canonical_pi(PI2, Canonical).
 2250
 2251meta_decls(Var) -->
 2252    { var(Var) },
 2253    !.
 2254meta_decls((A,B)) -->
 2255    !,
 2256    meta_decls(A),
 2257    meta_decls(B).
 2258meta_decls(A) -->
 2259    [A].
 2260
 2261public_decls(Var) -->
 2262    { var(Var) },
 2263    !.
 2264public_decls((A,B)) -->
 2265    !,
 2266    public_decls(A),
 2267    public_decls(B).
 2268public_decls(A) -->
 2269    [A].
 2270
 2271                 /*******************************
 2272                 *             INCLUDE          *
 2273                 *******************************/
 2274
 2275process_include([], _) :- !.
 2276process_include([H|T], Src) :-
 2277    !,
 2278    process_include(H, Src),
 2279    process_include(T, Src).
 2280process_include(File, Src) :-
 2281    callable(File),
 2282    !,
 2283    (   once(xref_input(ParentSrc, _)),
 2284        xref_source_file(File, Path, ParentSrc)
 2285    ->  (   (   uses_file(_, Src, Path)
 2286            ;   Path == Src
 2287            )
 2288        ->  true
 2289        ;   assert(uses_file(File, Src, Path)),
 2290            (   xoption(Src, process_include(true))
 2291            ->  findall(O, xoption(Src, O), Options),
 2292                setup_call_cleanup(
 2293                    open_include_file(Path, In, Refs),
 2294                    collect(Src, Path, In, Options),
 2295                    close_include(In, Refs))
 2296            ;   true
 2297            )
 2298        )
 2299    ;   assert(uses_file(File, Src, '<not_found>'))
 2300    ).
 2301process_include(_, _).
 2302
 2303%!  open_include_file(+Path, -In, -Refs)
 2304%
 2305%   Opens an :- include(File) referenced file.   Note that we cannot
 2306%   use prolog_open_source/2 because we   should  _not_ safe/restore
 2307%   the lexical context.
 2308
 2309open_include_file(Path, In, [Ref]) :-
 2310    once(xref_input(_, Parent)),
 2311    stream_property(Parent, encoding(Enc)),
 2312    '$push_input_context'(xref_include),
 2313    catch((   prolog:xref_open_source(Path, In)
 2314          ->  catch(set_stream(In, encoding(Enc)),
 2315                    error(_,_), true)       % deal with non-file input
 2316          ;   include_encoding(Enc, Options),
 2317              open(Path, read, In, Options)
 2318          ), E,
 2319          ( '$pop_input_context', throw(E))),
 2320    catch((   peek_char(In, #)              % Deal with #! script
 2321          ->  skip(In, 10)
 2322          ;   true
 2323          ), E,
 2324          ( close_include(In, []), throw(E))),
 2325    asserta(xref_input(Path, In), Ref).
 2326
 2327include_encoding(wchar_t, []) :- !.
 2328include_encoding(Enc, [encoding(Enc)]).
 2329
 2330
 2331close_include(In, Refs) :-
 2332    maplist(erase, Refs),
 2333    close(In, [force(true)]),
 2334    '$pop_input_context'.
 2335
 2336%!  process_foreign(+Spec, +Src)
 2337%
 2338%   Process a load_foreign_library/1 call.
 2339
 2340process_foreign(Spec, Src) :-
 2341    ground(Spec),
 2342    current_foreign_library(Spec, Defined),
 2343    !,
 2344    (   xmodule(Module, Src)
 2345    ->  true
 2346    ;   Module = user
 2347    ),
 2348    process_foreign_defined(Defined, Module, Src).
 2349process_foreign(_, _).
 2350
 2351process_foreign_defined([], _, _).
 2352process_foreign_defined([H|T], M, Src) :-
 2353    (   H = M:Head
 2354    ->  assert_foreign(Src, Head)
 2355    ;   assert_foreign(Src, H)
 2356    ),
 2357    process_foreign_defined(T, M, Src).
 2358
 2359
 2360                 /*******************************
 2361                 *          CHR SUPPORT         *
 2362                 *******************************/
 2363
 2364/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 2365This part of the file supports CHR. Our choice is between making special
 2366hooks to make CHR expansion work and  then handle the (complex) expanded
 2367code or process the  CHR  source   directly.  The  latter looks simpler,
 2368though I don't like the idea  of   adding  support for libraries to this
 2369module.  A  file  is  supposed  to  be  a    CHR   file  if  it  uses  a
 2370use_module(library(chr) or contains a :-   constraint/1 directive. As an
 2371extra bonus we get the source-locations right :-)
 2372- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 2373
 2374process_chr(@(_Name, Rule), Src) :-
 2375    mode(chr, Src),
 2376    process_chr(Rule, Src).
 2377process_chr(pragma(Rule, _Pragma), Src) :-
 2378    mode(chr, Src),
 2379    process_chr(Rule, Src).
 2380process_chr(<=>(Head, Body), Src) :-
 2381    mode(chr, Src),
 2382    chr_head(Head, Src, H),
 2383    chr_body(Body, H, Src).
 2384process_chr(==>(Head, Body), Src) :-
 2385    mode(chr, Src),
 2386    chr_head(Head, H, Src),
 2387    chr_body(Body, H, Src).
 2388process_chr((:- chr_constraint(_)), Src) :-
 2389    (   mode(chr, Src)
 2390    ->  true
 2391    ;   assert(mode(chr, Src))
 2392    ).
 2393
 2394chr_head(X, _, _) :-
 2395    var(X),
 2396    !.                      % Illegal.  Warn?
 2397chr_head(\(A,B), Src, H) :-
 2398    chr_head(A, Src, H),
 2399    process_body(B, H, Src).
 2400chr_head((H0,B), Src, H) :-
 2401    chr_defined(H0, Src, H),
 2402    process_body(B, H, Src).
 2403chr_head(H0, Src, H) :-
 2404    chr_defined(H0, Src, H).
 2405
 2406chr_defined(X, _, _) :-
 2407    var(X),
 2408    !.
 2409chr_defined(#(C,_Id), Src, C) :-
 2410    !,
 2411    assert_constraint(Src, C).
 2412chr_defined(A, Src, A) :-
 2413    assert_constraint(Src, A).
 2414
 2415chr_body(X, From, Src) :-
 2416    var(X),
 2417    !,
 2418    process_body(X, From, Src).
 2419chr_body('|'(Guard, Goals), H, Src) :-
 2420    !,
 2421    chr_body(Guard, H, Src),
 2422    chr_body(Goals, H, Src).
 2423chr_body(G, From, Src) :-
 2424    process_body(G, From, Src).
 2425
 2426assert_constraint(_, Head) :-
 2427    var(Head),
 2428    !.
 2429assert_constraint(Src, Head) :-
 2430    constraint(Head, Src, _),
 2431    !.
 2432assert_constraint(Src, Head) :-
 2433    generalise_term(Head, Term),
 2434    current_source_line(Line),
 2435    assert(constraint(Term, Src, Line)).
 2436
 2437
 2438                /********************************
 2439                *       PHASE 1 ASSERTIONS      *
 2440                ********************************/
 2441
 2442%!  assert_called(+Src, +From, +Head, +Line) is det.
 2443%
 2444%   Assert the fact that Head is called by From in Src. We do not
 2445%   assert called system predicates.
 2446
 2447assert_called(_, _, Var, _) :-
 2448    var(Var),
 2449    !.
 2450assert_called(Src, From, Goal, Line) :-
 2451    var(From),
 2452    !,
 2453    assert_called(Src, '<unknown>', Goal, Line).
 2454assert_called(_, _, Goal, _) :-
 2455    expand_hide_called(Goal),
 2456    !.
 2457assert_called(Src, Origin, M:G, Line) :-
 2458    !,
 2459    (   atom(M),
 2460        callable(G)
 2461    ->  current_condition(Cond),
 2462        (   xmodule(M, Src)         % explicit call to own module
 2463        ->  assert_called(Src, Origin, G, Line)
 2464        ;   called(M:G, Src, Origin, Cond, Line) % already registered
 2465        ->  true
 2466        ;   hide_called(M:G, Src)           % not interesting (now)
 2467        ->  true
 2468        ;   generalise(Origin, OTerm),
 2469            generalise(G, GTerm)
 2470        ->  assert(called(M:GTerm, Src, OTerm, Cond, Line))
 2471        ;   true
 2472        )
 2473    ;   true                        % call to variable module
 2474    ).
 2475assert_called(Src, _, Goal, _) :-
 2476    (   xmodule(M, Src)
 2477    ->  M \== system
 2478    ;   M = user
 2479    ),
 2480    hide_called(M:Goal, Src),
 2481    !.
 2482assert_called(Src, Origin, Goal, Line) :-
 2483    current_condition(Cond),
 2484    (   called(Goal, Src, Origin, Cond, Line)
 2485    ->  true
 2486    ;   generalise(Origin, OTerm),
 2487        generalise(Goal, Term)
 2488    ->  assert(called(Term, Src, OTerm, Cond, Line))
 2489    ;   true
 2490    ).
 2491
 2492
 2493%!  expand_hide_called(:Callable) is semidet.
 2494%
 2495%   Goals that should not turn up as being called. Hack. Eventually
 2496%   we should deal with that using an XPCE plugin.
 2497
 2498expand_hide_called(pce_principal:send_implementation(_, _, _)).
 2499expand_hide_called(pce_principal:get_implementation(_, _, _, _)).
 2500expand_hide_called(pce_principal:pce_lazy_get_method(_,_,_)).
 2501expand_hide_called(pce_principal:pce_lazy_send_method(_,_,_)).
 2502
 2503assert_defined(Src, Goal) :-
 2504    Goal = test(_Test),
 2505    current_test_unit(Unit, Line),
 2506    assert_called(Src, '<test_unit>'(Unit), Goal, Line),
 2507    fail.
 2508assert_defined(Src, Goal) :-
 2509    Goal = test(_Test, _Options),
 2510    current_test_unit(Unit, Line),
 2511    assert_called(Src, '<test_unit>'(Unit), Goal, Line),
 2512    fail.
 2513assert_defined(Src, Goal) :-
 2514    defined(Goal, Src, _),
 2515    !.
 2516assert_defined(Src, Goal) :-
 2517    generalise(Goal, Term),
 2518    current_source_line(Line),
 2519    assert(defined(Term, Src, Line)).
 2520
 2521assert_foreign(Src, Goal) :-
 2522    foreign(Goal, Src, _),
 2523    !.
 2524assert_foreign(Src, Goal) :-
 2525    generalise(Goal, Term),
 2526    current_source_line(Line),
 2527    assert(foreign(Term, Src, Line)).
 2528
 2529%!  assert_import(+Src, +Import, +ExportList, +From, +Reexport) is det.
 2530%
 2531%   Asserts imports into Src. Import   is  the import specification,
 2532%   ExportList is the list of known   exported predicates or unbound
 2533%   if this need not be checked and From  is the file from which the
 2534%   public predicates come. If  Reexport   is  =true=, re-export the
 2535%   imported predicates.
 2536%
 2537%   @tbd    Tighter type-checking on Import.
 2538
 2539assert_import(_, [], _, _, _) :- !.
 2540assert_import(Src, [H|T], Export, From, Reexport) :-
 2541    !,
 2542    assert_import(Src, H, Export, From, Reexport),
 2543    assert_import(Src, T, Export, From, Reexport).
 2544assert_import(Src, except(Except), Export, From, Reexport) :-
 2545    !,
 2546    is_list(Export),
 2547    !,
 2548    except(Except, Export, Import),
 2549    assert_import(Src, Import, _All, From, Reexport).
 2550assert_import(Src, Import as Name, Export, From, Reexport) :-
 2551    !,
 2552    pi_to_head(Import, Term0),
 2553    rename_goal(Term0, Name, Term),
 2554    (   in_export_list(Term0, Export)
 2555    ->  assert(imported(Term, Src, From)),
 2556        assert_reexport(Reexport, Src, Term)
 2557    ;   current_source_line(Line),
 2558        assert_called(Src, '<directive>'(Line), Term0, Line)
 2559    ).
 2560assert_import(Src, Import, Export, From, Reexport) :-
 2561    pi_to_head(Import, Term),
 2562    !,
 2563    (   in_export_list(Term, Export)
 2564    ->  assert(imported(Term, Src, From)),
 2565        assert_reexport(Reexport, Src, Term)
 2566    ;   current_source_line(Line),
 2567        assert_called(Src, '<directive>'(Line), Term, Line)
 2568    ).
 2569assert_import(Src, op(P,T,N), _, _, _) :-
 2570    xref_push_op(Src, P,T,N).
 2571
 2572in_export_list(_Head, Export) :-
 2573    var(Export),
 2574    !.
 2575in_export_list(Head, Export) :-
 2576    member(PI, Export),
 2577    pi_to_head(PI, Head).
 2578
 2579assert_reexport(false, _, _) :- !.
 2580assert_reexport(true, Src, Term) :-
 2581    assert(exported(Term, Src)).
 2582
 2583%!  process_import(:Import, +Src)
 2584%
 2585%   Process an import/1 directive
 2586
 2587process_import(M:PI, Src) :-
 2588    pi_to_head(PI, Head),
 2589    !,
 2590    (   atom(M),
 2591        current_module(M),
 2592        module_property(M, file(From))
 2593    ->  true
 2594    ;   From = '<unknown>'
 2595    ),
 2596    assert(imported(Head, Src, From)).
 2597process_import(_, _).
 2598
 2599%!  assert_xmodule_callable(PIs, Module, Src, From)
 2600%
 2601%   We can call all exports  and   public  predicates of an imported
 2602%   module using Module:Goal.
 2603%
 2604%   @tbd    Should we distinguish this from normal imported?
 2605
 2606assert_xmodule_callable([], _, _, _).
 2607assert_xmodule_callable([PI|T], M, Src, From) :-
 2608    (   pi_to_head(M:PI, Head)
 2609    ->  assert(imported(Head, Src, From))
 2610    ;   true
 2611    ),
 2612    assert_xmodule_callable(T, M, Src, From).
 2613
 2614
 2615%!  assert_op(+Src, +Op) is det.
 2616%
 2617%   @param Op       Ground term op(Priority, Type, Name).
 2618
 2619assert_op(Src, op(P,T,M:N)) :-
 2620    (   '$current_source_module'(M)
 2621    ->  Name = N
 2622    ;   Name = M:N
 2623    ),
 2624    (   xop(Src, op(P,T,Name))
 2625    ->  true
 2626    ;   assert(xop(Src, op(P,T,Name)))
 2627    ).
 2628
 2629%!  assert_module(+Src, +Module)
 2630%
 2631%   Assert we are loading code into Module.  This is also used to
 2632%   exploit local term-expansion and other rules.
 2633
 2634assert_module(Src, Module) :-
 2635    xmodule(Module, Src),
 2636    !.
 2637assert_module(Src, Module) :-
 2638    '$set_source_module'(Module),
 2639    assert(xmodule(Module, Src)),
 2640    (   module_property(Module, class(system))
 2641    ->  retractall(xoption(Src, register_called(_))),
 2642        assert(xoption(Src, register_called(all)))
 2643    ;   true
 2644    ).
 2645
 2646assert_module_export(_, []) :- !.
 2647assert_module_export(Src, [H|T]) :-
 2648    !,
 2649    assert_module_export(Src, H),
 2650    assert_module_export(Src, T).
 2651assert_module_export(Src, PI) :-
 2652    pi_to_head(PI, Term),
 2653    !,
 2654    assert(exported(Term, Src)).
 2655assert_module_export(Src, op(P, A, N)) :-
 2656    xref_push_op(Src, P, A, N).
 2657
 2658%!  assert_module3(+Import, +Src)
 2659%
 2660%   Handle 3th argument of module/3 declaration.
 2661
 2662assert_module3([], _) :- !.
 2663assert_module3([H|T], Src) :-
 2664    !,
 2665    assert_module3(H, Src),
 2666    assert_module3(T, Src).
 2667assert_module3(Option, Src) :-
 2668    process_use_module(library(dialect/Option), Src, false).
 2669
 2670
 2671%!  process_predicates(:Closure, +Predicates, +Src)
 2672%
 2673%   Process areguments of dynamic,  etc.,   using  call(Closure, PI,
 2674%   Src).  Handles  both  lists  of    specifications  and  (PI,...)
 2675%   specifications.
 2676
 2677process_predicates(Closure, Preds, Src) :-
 2678    is_list(Preds),
 2679    !,
 2680    process_predicate_list(Preds, Closure, Src).
 2681process_predicates(Closure, as(Preds, _Options), Src) :-
 2682    !,
 2683    process_predicates(Closure, Preds, Src).
 2684process_predicates(Closure, Preds, Src) :-
 2685    process_predicate_comma(Preds, Closure, Src).
 2686
 2687process_predicate_list([], _, _).
 2688process_predicate_list([H|T], Closure, Src) :-
 2689    (   nonvar(H)
 2690    ->  call(Closure, H, Src)
 2691    ;   true
 2692    ),
 2693    process_predicate_list(T, Closure, Src).
 2694
 2695process_predicate_comma(Var, _, _) :-
 2696    var(Var),
 2697    !.
 2698process_predicate_comma(M:(A,B), Closure, Src) :-
 2699    !,
 2700    process_predicate_comma(M:A, Closure, Src),
 2701    process_predicate_comma(M:B, Closure, Src).
 2702process_predicate_comma((A,B), Closure, Src) :-
 2703    !,
 2704    process_predicate_comma(A, Closure, Src),
 2705    process_predicate_comma(B, Closure, Src).
 2706process_predicate_comma(as(Spec, _Options), Closure, Src) :-
 2707    !,
 2708    process_predicate_comma(Spec, Closure, Src).
 2709process_predicate_comma(A, Closure, Src) :-
 2710    call(Closure, A, Src).
 2711
 2712
 2713assert_dynamic(PI, Src) :-
 2714    pi_to_head(PI, Term),
 2715    (   thread_local(Term, Src, _)  % dynamic after thread_local has
 2716    ->  true                        % no effect
 2717    ;   current_source_line(Line),
 2718        assert(dynamic(Term, Src, Line))
 2719    ).
 2720
 2721assert_thread_local(PI, Src) :-
 2722    pi_to_head(PI, Term),
 2723    current_source_line(Line),
 2724    assert(thread_local(Term, Src, Line)).
 2725
 2726assert_multifile(PI, Src) :-                    % :- multifile(Spec)
 2727    pi_to_head(PI, Term),
 2728    current_source_line(Line),
 2729    assert(multifile(Term, Src, Line)).
 2730
 2731assert_public(PI, Src) :-                       % :- public(Spec)
 2732    pi_to_head(PI, Term),
 2733    current_source_line(Line),
 2734    assert_called(Src, '<public>'(Line), Term, Line),
 2735    assert(public(Term, Src, Line)).
 2736
 2737assert_export(PI, Src) :-                       % :- export(Spec)
 2738    pi_to_head(PI, Term),
 2739    !,
 2740    assert(exported(Term, Src)).
 2741
 2742%!  pi_to_head(+PI, -Head) is semidet.
 2743%
 2744%   Translate Name/Arity or Name//Arity to a callable term. Fails if
 2745%   PI is not a predicate indicator.
 2746
 2747pi_to_head(Var, _) :-
 2748    var(Var), !, fail.
 2749pi_to_head(M:PI, M:Term) :-
 2750    !,
 2751    pi_to_head(PI, Term).
 2752pi_to_head(Name/Arity, Term) :-
 2753    functor(Term, Name, Arity).
 2754pi_to_head(Name//DCGArity, Term) :-
 2755    Arity is DCGArity+2,
 2756    functor(Term, Name, Arity).
 2757
 2758
 2759assert_used_class(Src, Name) :-
 2760    used_class(Name, Src),
 2761    !.
 2762assert_used_class(Src, Name) :-
 2763    assert(used_class(Name, Src)).
 2764
 2765assert_defined_class(Src, Name, _Meta, _Super, _) :-
 2766    defined_class(Name, _, _, Src, _),
 2767    !.
 2768assert_defined_class(_, _, _, -, _) :- !.               % :- pce_extend_class
 2769assert_defined_class(Src, Name, Meta, Super, Summary) :-
 2770    current_source_line(Line),
 2771    (   Summary == @(default)
 2772    ->  Atom = ''
 2773    ;   is_list(Summary)
 2774    ->  atom_codes(Atom, Summary)
 2775    ;   string(Summary)
 2776    ->  atom_concat(Summary, '', Atom)
 2777    ),
 2778    assert(defined_class(Name, Super, Atom, Src, Line)),
 2779    (   Meta = @(_)
 2780    ->  true
 2781    ;   assert_used_class(Src, Meta)
 2782    ),
 2783    assert_used_class(Src, Super).
 2784
 2785assert_defined_class(Src, Name, imported_from(_File)) :-
 2786    defined_class(Name, _, _, Src, _),
 2787    !.
 2788assert_defined_class(Src, Name, imported_from(File)) :-
 2789    assert(defined_class(Name, _, '', Src, file(File))).
 2790
 2791
 2792                /********************************
 2793                *            UTILITIES          *
 2794                ********************************/
 2795
 2796%!  generalise(+Callable, -General)
 2797%
 2798%   Generalise a callable term.
 2799
 2800generalise(Var, Var) :-
 2801    var(Var),
 2802    !.                    % error?
 2803generalise(pce_principal:send_implementation(Id, _, _),
 2804           pce_principal:send_implementation(Id, _, _)) :-
 2805    atom(Id),
 2806    !.
 2807generalise(pce_principal:get_implementation(Id, _, _, _),
 2808           pce_principal:get_implementation(Id, _, _, _)) :-
 2809    atom(Id),
 2810    !.
 2811generalise('<directive>'(Line), '<directive>'(Line)) :- !.
 2812generalise(test(Test), test(Test)) :-
 2813    current_test_unit(_,_),
 2814    ground(Test),
 2815    !.
 2816generalise(test(Test, _), test(Test, _)) :-
 2817    current_test_unit(_,_),
 2818    ground(Test),
 2819    !.
 2820generalise('<test_unit>'(Line), '<test_unit>'(Line)) :- !.
 2821generalise(Module:Goal0, Module:Goal) :-
 2822    atom(Module),
 2823    !,
 2824    generalise(Goal0, Goal).
 2825generalise(Term0, Term) :-
 2826    callable(Term0),
 2827    generalise_term(Term0, Term).
 2828
 2829
 2830                 /*******************************
 2831                 *      SOURCE MANAGEMENT       *
 2832                 *******************************/
 2833
 2834/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 2835This section of the file contains   hookable  predicates to reason about
 2836sources. The built-in code here  can  only   deal  with  files. The XPCE
 2837library(pce_prolog_xref) provides hooks to deal with XPCE objects, so we
 2838can do cross-referencing on PceEmacs edit   buffers.  Other examples for
 2839hooking can be databases, (HTTP) URIs, etc.
 2840- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 2841
 2842:- multifile
 2843    prolog:xref_source_directory/2, % +Source, -Dir
 2844    prolog:xref_source_file/3.      % +Spec, -Path, +Options
 2845
 2846
 2847%!  xref_source_file(+Spec, -File, +Src) is semidet.
 2848%!  xref_source_file(+Spec, -File, +Src, +Options) is semidet.
 2849%
 2850%   Find named source file from Spec, relative to Src.
 2851
 2852xref_source_file(Plain, File, Source) :-
 2853    xref_source_file(Plain, File, Source, []).
 2854
 2855xref_source_file(QSpec, File, Source, Options) :-
 2856    nonvar(QSpec), QSpec = _:Spec,
 2857    !,
 2858    must_be(acyclic, Spec),
 2859    xref_source_file(Spec, File, Source, Options).
 2860xref_source_file(Spec, File, Source, Options) :-
 2861    nonvar(Spec),
 2862    prolog:xref_source_file(Spec, File,
 2863                            [ relative_to(Source)
 2864                            | Options
 2865                            ]),
 2866    !.
 2867xref_source_file(Plain, File, Source, Options) :-
 2868    atom(Plain),
 2869    \+ is_absolute_file_name(Plain),
 2870    (   prolog:xref_source_directory(Source, Dir)
 2871    ->  true
 2872    ;   atom(Source),
 2873        file_directory_name(Source, Dir)
 2874    ),
 2875    atomic_list_concat([Dir, /, Plain], Spec0),
 2876    absolute_file_name(Spec0, Spec),
 2877    do_xref_source_file(Spec, File, Options),
 2878    !.
 2879xref_source_file(Spec, File, Source, Options) :-
 2880    do_xref_source_file(Spec, File,
 2881                        [ relative_to(Source)
 2882                        | Options
 2883                        ]),
 2884    !.
 2885xref_source_file(_, _, _, Options) :-
 2886    option(silent(true), Options),
 2887    !,
 2888    fail.
 2889xref_source_file(Spec, _, Src, _Options) :-
 2890    verbose(Src),
 2891    print_message(warning, error(existence_error(file, Spec), _)),
 2892    fail.
 2893
 2894do_xref_source_file(Spec, File, Options) :-
 2895    nonvar(Spec),
 2896    option(file_type(Type), Options, prolog),
 2897    absolute_file_name(Spec, File,
 2898                       [ file_type(Type),
 2899                         access(read),
 2900                         file_errors(fail)
 2901                       ]),
 2902    !.
 2903
 2904%!  canonical_source(?Source, ?Src) is det.
 2905%
 2906%   Src is the canonical version of Source if Source is given.
 2907
 2908canonical_source(Source, Src) :-
 2909    (   ground(Source)
 2910    ->  prolog_canonical_source(Source, Src)
 2911    ;   Source = Src
 2912    ).
 2913
 2914%!  goal_name_arity(+Goal, -Name, -Arity)
 2915%
 2916%   Generalized version of  functor/3  that   can  deal  with name()
 2917%   goals.
 2918
 2919goal_name_arity(Goal, Name, Arity) :-
 2920    (   compound(Goal)
 2921    ->  compound_name_arity(Goal, Name, Arity)
 2922    ;   atom(Goal)
 2923    ->  Name = Goal, Arity = 0
 2924    ).
 2925
 2926generalise_term(Specific, General) :-
 2927    (   compound(Specific)
 2928    ->  compound_name_arity(Specific, Name, Arity),
 2929        compound_name_arity(General, Name, Arity)
 2930    ;   General = Specific
 2931    ).
 2932
 2933functor_name(Term, Name) :-
 2934    (   compound(Term)
 2935    ->  compound_name_arity(Term, Name, _)
 2936    ;   atom(Term)
 2937    ->  Name = Term
 2938    ).
 2939
 2940rename_goal(Goal0, Name, Goal) :-
 2941    (   compound(Goal0)
 2942    ->  compound_name_arity(Goal0, _, Arity),
 2943        compound_name_arity(Goal, Name, Arity)
 2944    ;   Goal = Name
 2945    )