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