View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  1985-2018, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI, Amsterdam
    9    All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37/*
   38Consult, derivates and basic things.   This  module  is  loaded  by  the
   39C-written  bootstrap  compiler.
   40
   41The $:- directive  is  executed  by  the  bootstrap  compiler,  but  not
   42inserted  in  the  intermediate  code  file.   Used  to print diagnostic
   43messages and start the Prolog defined compiler for  the  remaining  boot
   44modules.
   45
   46If you want  to  debug  this  module,  put  a  '$:-'(trace).   directive
   47somewhere.   The  tracer will work properly under boot compilation as it
   48will use the C defined write predicate  to  print  goals  and  does  not
   49attempt to call the Prolog defined trace interceptor.
   50*/
   51
   52                /********************************
   53                *    LOAD INTO MODULE SYSTEM    *
   54                ********************************/
   55
   56:- '$set_source_module'(system).   57
   58'$boot_message'(_Format, _Args) :-
   59    current_prolog_flag(verbose, silent),
   60    !.
   61'$boot_message'(Format, Args) :-
   62    format(Format, Args),
   63    !.
   64
   65'$:-'('$boot_message'('Loading boot file ...~n', [])).
   66
   67
   68                /********************************
   69                *          DIRECTIVES           *
   70                *********************************/
   71
   72:- meta_predicate
   73    dynamic(:),
   74    multifile(:),
   75    public(:),
   76    module_transparent(:),
   77    discontiguous(:),
   78    volatile(:),
   79    thread_local(:),
   80    noprofile(:),
   81    non_terminal(:),
   82    '$clausable'(:),
   83    '$iso'(:),
   84    '$hide'(:).
 dynamic +Spec is det
 multifile +Spec is det
 module_transparent +Spec is det
 discontiguous +Spec is det
 volatile +Spec is det
 thread_local +Spec is det
 noprofile(+Spec) is det
 public +Spec is det
 non_terminal(+Spec) is det
Predicate versions of standard directives that set predicate attributes. These predicates bail out with an error on the first failure (typically permission errors).
  100dynamic(Spec)            :- '$set_pattr'(Spec, pred, (dynamic)).
  101multifile(Spec)          :- '$set_pattr'(Spec, pred, (multifile)).
  102module_transparent(Spec) :- '$set_pattr'(Spec, pred, (transparent)).
  103discontiguous(Spec)      :- '$set_pattr'(Spec, pred, (discontiguous)).
  104volatile(Spec)           :- '$set_pattr'(Spec, pred, (volatile)).
  105thread_local(Spec)       :- '$set_pattr'(Spec, pred, (thread_local)).
  106noprofile(Spec)          :- '$set_pattr'(Spec, pred, (noprofile)).
  107public(Spec)             :- '$set_pattr'(Spec, pred, (public)).
  108non_terminal(Spec)       :- '$set_pattr'(Spec, pred, (non_terminal)).
  109'$iso'(Spec)             :- '$set_pattr'(Spec, pred, (iso)).
  110'$clausable'(Spec)       :- '$set_pattr'(Spec, pred, (clausable)).
  111
  112'$set_pattr'(M:Pred, How, Attr) :-
  113    '$set_pattr'(Pred, M, How, Attr).
  114
  115'$set_pattr'(X, _, _, _) :-
  116    var(X),
  117    throw(error(instantiation_error, _)).
  118'$set_pattr'([], _, _, _) :- !.
  119'$set_pattr'([H|T], M, How, Attr) :-           % ISO
  120    !,
  121    '$set_pattr'(H, M, How, Attr),
  122    '$set_pattr'(T, M, How, Attr).
  123'$set_pattr'((A,B), M, How, Attr) :-           % ISO and traditional
  124    !,
  125    '$set_pattr'(A, M, How, Attr),
  126    '$set_pattr'(B, M, How, Attr).
  127'$set_pattr'(M:T, _, How, Attr) :-
  128    !,
  129    '$set_pattr'(T, M, How, Attr).
  130'$set_pattr'(A, M, pred, Attr) :-
  131    !,
  132    '$set_predicate_attribute'(M:A, Attr, true).
  133'$set_pattr'(A, M, directive, Attr) :-
  134    !,
  135    catch('$set_predicate_attribute'(M:A, Attr, true),
  136          error(E, _),
  137          print_message(error, error(E, context((Attr)/1,_)))).
 $pattr_directive(+Spec, +Module) is det
This implements the directive version of dynamic/1, multifile/1, etc. This version catches and prints errors. If the directive specifies multiple predicates, processing after an error continues with the remaining predicates.
  146'$pattr_directive'(dynamic(Spec), M) :-
  147    '$set_pattr'(Spec, M, directive, (dynamic)).
  148'$pattr_directive'(multifile(Spec), M) :-
  149    '$set_pattr'(Spec, M, directive, (multifile)).
  150'$pattr_directive'(module_transparent(Spec), M) :-
  151    '$set_pattr'(Spec, M, directive, (transparent)).
  152'$pattr_directive'(discontiguous(Spec), M) :-
  153    '$set_pattr'(Spec, M, directive, (discontiguous)).
  154'$pattr_directive'(volatile(Spec), M) :-
  155    '$set_pattr'(Spec, M, directive, (volatile)).
  156'$pattr_directive'(thread_local(Spec), M) :-
  157    '$set_pattr'(Spec, M, directive, (thread_local)).
  158'$pattr_directive'(noprofile(Spec), M) :-
  159    '$set_pattr'(Spec, M, directive, (noprofile)).
  160'$pattr_directive'(public(Spec), M) :-
  161    '$set_pattr'(Spec, M, directive, (public)).
 $hide(:PI)
Predicates protected this way are never visible in the tracer.
  168'$hide'(Pred) :-
  169    '$set_predicate_attribute'(Pred, trace, false).
  170
  171
  172                /********************************
  173                *       CALLING, CONTROL        *
  174                *********************************/
  175
  176:- noprofile((call/1,
  177              catch/3,
  178              once/1,
  179              ignore/1,
  180              call_cleanup/2,
  181              call_cleanup/3,
  182              setup_call_cleanup/3,
  183              setup_call_catcher_cleanup/4)).  184
  185:- meta_predicate
  186    ';'(0,0),
  187    ','(0,0),
  188    @(0,+),
  189    call(0),
  190    call(1,?),
  191    call(2,?,?),
  192    call(3,?,?,?),
  193    call(4,?,?,?,?),
  194    call(5,?,?,?,?,?),
  195    call(6,?,?,?,?,?,?),
  196    call(7,?,?,?,?,?,?,?),
  197    not(0),
  198    \+(0),
  199    '->'(0,0),
  200    '*->'(0,0),
  201    once(0),
  202    ignore(0),
  203    catch(0,?,0),
  204    reset(0,?,-),
  205    setup_call_cleanup(0,0,0),
  206    setup_call_catcher_cleanup(0,0,?,0),
  207    call_cleanup(0,0),
  208    call_cleanup(0,?,0),
  209    catch_with_backtrace(0,?,0),
  210    '$meta_call'(0).  211
  212:- '$iso'((call/1, (\+)/1, once/1, (;)/2, (',')/2, (->)/2, catch/3)).  213
  214% The control structures are always compiled, both   if they appear in a
  215% clause body and if they are handed  to   call/1.  The only way to call
  216% these predicates is by means of  call/2..   In  that case, we call the
  217% hole control structure again to get it compiled by call/1 and properly
  218% deal  with  !,  etc.  Another  reason  for  having  these  things   as
  219% predicates is to be able to define   properties for them, helping code
  220% analyzers.
  221
  222(M0:If ; M0:Then) :- !, call(M0:(If ; Then)).
  223(M1:If ; M2:Then) :-    call(M1:(If ; M2:Then)).
  224(G1   , G2)       :-    call((G1   , G2)).
  225(If  -> Then)     :-    call((If  -> Then)).
  226(If *-> Then)     :-    call((If *-> Then)).
  227@(Goal,Module)    :-    @(Goal,Module).
 $meta_call(:Goal)
Interpreted meta-call implementation. By default, call/1 compiles its argument into a temporary clause. This realises better performance if the (complex) goal does a lot of backtracking because this interpreted version needs to re-interpret the remainder of the goal after backtracking.

This implementation is used by reset/3 because the continuation cannot be captured if it contains a such a compiled temporary clause.

  241'$meta_call'(M:G) :-
  242    prolog_current_choice(Ch),
  243    '$meta_call'(G, M, Ch).
  244
  245'$meta_call'(Var, _, _) :-
  246    var(Var),
  247    !,
  248    '$instantiation_error'(Var).
  249'$meta_call'((A,B), M, Ch) :-
  250    !,
  251    '$meta_call'(A, M, Ch),
  252    '$meta_call'(B, M, Ch).
  253'$meta_call'((I->T;E), M, Ch) :-
  254    !,
  255    (   prolog_current_choice(Ch2),
  256        '$meta_call'(I, M, Ch2)
  257    ->  '$meta_call'(T, M, Ch)
  258    ;   '$meta_call'(E, M, Ch)
  259    ).
  260'$meta_call'((I*->T;E), M, Ch) :-
  261    !,
  262    (   prolog_current_choice(Ch2),
  263        '$meta_call'(I, M, Ch2)
  264    *-> '$meta_call'(T, M, Ch)
  265    ;   '$meta_call'(E, M, Ch)
  266    ).
  267'$meta_call'((I->T), M, Ch) :-
  268    !,
  269    (   prolog_current_choice(Ch2),
  270        '$meta_call'(I, M, Ch2)
  271    ->  '$meta_call'(T, M, Ch)
  272    ).
  273'$meta_call'((I*->T), M, Ch) :-
  274    !,
  275    prolog_current_choice(Ch2),
  276    '$meta_call'(I, M, Ch2),
  277    '$meta_call'(T, M, Ch).
  278'$meta_call'((A;B), M, Ch) :-
  279    !,
  280    (   '$meta_call'(A, M, Ch)
  281    ;   '$meta_call'(B, M, Ch)
  282    ).
  283'$meta_call'(\+(G), M, _) :-
  284    !,
  285    prolog_current_choice(Ch),
  286    \+ '$meta_call'(G, M, Ch).
  287'$meta_call'(call(G), M, _) :-
  288    !,
  289    prolog_current_choice(Ch),
  290    '$meta_call'(G, M, Ch).
  291'$meta_call'(M:G, _, Ch) :-
  292    !,
  293    '$meta_call'(G, M, Ch).
  294'$meta_call'(!, _, Ch) :-
  295    prolog_cut_to(Ch).
  296'$meta_call'(G, M, _Ch) :-
  297    call(M:G).
 call(:Closure, ?A)
 call(:Closure, ?A1, ?A2)
 call(:Closure, ?A1, ?A2, ?A3)
 call(:Closure, ?A1, ?A2, ?A3, ?A4)
 call(:Closure, ?A1, ?A2, ?A3, ?A4, ?A5)
 call(:Closure, ?A1, ?A2, ?A3, ?A4, ?A5, ?A6)
 call(:Closure, ?A1, ?A2, ?A3, ?A4, ?A5, ?A6, ?A7)
Arity 2..8 is demanded by the ISO standard. Higher arities are supported, but handled by the compiler. This implies they are not backed up by predicates and analyzers thus cannot ask for their properties. Analyzers should hard-code handling of call/2..
  313:- '$iso'((call/2,
  314           call/3,
  315           call/4,
  316           call/5,
  317           call/6,
  318           call/7,
  319           call/8)).  320
  321call(Goal) :-                           % make these available as predicates
  322    Goal.
  323call(Goal, A) :-
  324    call(Goal, A).
  325call(Goal, A, B) :-
  326    call(Goal, A, B).
  327call(Goal, A, B, C) :-
  328    call(Goal, A, B, C).
  329call(Goal, A, B, C, D) :-
  330    call(Goal, A, B, C, D).
  331call(Goal, A, B, C, D, E) :-
  332    call(Goal, A, B, C, D, E).
  333call(Goal, A, B, C, D, E, F) :-
  334    call(Goal, A, B, C, D, E, F).
  335call(Goal, A, B, C, D, E, F, G) :-
  336    call(Goal, A, B, C, D, E, F, G).
 not :Goal is semidet
Pre-ISO version of \+/1. Note that some systems define not/1 as a logically more sound version of \+/1.
  343not(Goal) :-
  344    \+ Goal.
 \+ :Goal is semidet
Predicate version that allows for meta-calling.
  350\+ Goal :-
  351    \+ Goal.
 once(:Goal) is semidet
ISO predicate, acting as call((Goal, !)).
  357once(Goal) :-
  358    Goal,
  359    !.
 ignore(:Goal) is det
Call Goal, cut choice-points on success and succeed on failure. intended for calling side-effects and proceed on failure.
  366ignore(Goal) :-
  367    Goal,
  368    !.
  369ignore(_Goal).
  370
  371:- '$iso'((false/0)).
  372
  373%!  false.
  374%
  375%   Synonym for fail/0, providing a declarative reading.
  376
  377false :-    fail.
 catch(:Goal, +Catcher, :Recover)
ISO compliant exception handling.
  384catch(_Goal, _Catcher, _Recover) :-
  385    '$catch'.                       % Maps to I_CATCH, I_EXITCATCH
 prolog_cut_to(+Choice)
Cut all choice points after Choice
  391prolog_cut_to(_Choice) :-
  392    '$cut'.                         % Maps to I_CUTCHP
 reset(:Goal, ?Ball, -Continue)
Delimited continuation support.
  398reset(_Goal, _Ball, _Cont) :-
  399    '$reset'.
 shift(+Ball)
Shift control back to the enclosing reset/3
  405shift(Ball) :-
  406    '$shift'(Ball).
 call_continuation(+Continuation:list)
Call a continuation as created by shift/1. The continuation is a list of '$cont$'(Clause, PC, EnvironmentArg, ...) structures. The predicate '$call_one_tail_body'/1 creates a frame from the continuation and calls this.

Note that we can technically also push the entire continuation onto the environment and call it. Doing it incrementally as below exploits last-call optimization and therefore possible quadratic expansion of the continuation.

  420call_continuation([]).
  421call_continuation([TB|Rest]) :-
  422    (   Rest == []
  423    ->  '$call_continuation'(TB)
  424    ;   '$call_continuation'(TB),
  425        call_continuation(Rest)
  426    ).
 catch_with_backtrace(:Goal, ?Ball, :Recover)
As catch/3, but tell library(prolog_stack) to record a backtrace in case of an exception.
  433catch_with_backtrace(Goal, Ball, Recover) :-
  434    catch(Goal, Ball, Recover),
  435    '$no_lco'.
  436
  437'$no_lco'.
 $recover_and_rethrow(:Goal, +Term)
This goal is used to wrap the catch/3 recover handler if the exception is not supposed to be `catchable'. An example of an uncachable exception is '$aborted', used by abort/0. Note that we cut to ensure that the exception is not delayed forever because the recover handler leaves a choicepoint.
  447:- public '$recover_and_rethrow'/2.  448
  449'$recover_and_rethrow'(Goal, Exception) :-
  450    call_cleanup(Goal, throw(Exception)),
  451    !.
 setup_call_cleanup(:Setup, :Goal, :Cleanup)
 setup_call_catcher_cleanup(:Setup, :Goal, +Catcher, :Cleanup)
 call_cleanup(:Goal, :Cleanup)
 call_cleanup(:Goal, +Catcher, :Cleanup)
Call Cleanup once after Goal is finished (deterministic success, failure, exception or cut). The call to '$call_cleanup' is translated to I_CALLCLEANUP. This instruction relies on the exact stack layout left by setup_call_catcher_cleanup/4. Also the predicate name is used by the kernel cleanup mechanism and can only be changed together with the kernel.
  466setup_call_catcher_cleanup(Setup, _Goal, _Catcher, _Cleanup) :-
  467    '$sig_atomic'(Setup),
  468    '$call_cleanup'.
  469
  470setup_call_cleanup(Setup, Goal, Cleanup) :-
  471    setup_call_catcher_cleanup(Setup, Goal, _Catcher, Cleanup).
  472
  473call_cleanup(Goal, Cleanup) :-
  474    setup_call_catcher_cleanup(true, Goal, _Catcher, Cleanup).
  475
  476call_cleanup(Goal, Catcher, Cleanup) :-
  477    setup_call_catcher_cleanup(true, Goal, Catcher, Cleanup).
  478
  479                 /*******************************
  480                 *       INITIALIZATION         *
  481                 *******************************/
  482
  483:- meta_predicate
  484    initialization(0, +).  485
  486:- multifile '$init_goal'/3.  487:- dynamic   '$init_goal'/3.
 initialization(:Goal, +When)
Register Goal to be executed if a saved state is restored. In addition, the goal is executed depending on When:
now
Execute immediately
after_load
Execute after loading the file in which it appears. This is initialization/1.
restore_state
Do not execute immediately, but only when restoring the state. Not allowed in a sandboxed environment.
prepare_state
Called before saving a state. Can be used to clean the environment (see also volatile/1) or eagerly execute goals that are normally executed lazily.
program
Works as -g goal goals.
main
Starts the application. Only last declaration is used.

Note that all goals are executed when a program is restored.

  513initialization(Goal, When) :-
  514    '$must_be'(oneof(atom, initialization_type,
  515                     [ now,
  516                       after_load,
  517                       restore,
  518                       restore_state,
  519                       prepare_state,
  520                       program,
  521                       main
  522                     ]), When),
  523    '$initialization_context'(Source, Ctx),
  524    '$initialization'(When, Goal, Source, Ctx).
  525
  526'$initialization'(now, Goal, _Source, Ctx) :-
  527    '$run_init_goal'(Goal, Ctx),
  528    '$compile_init_goal'(-, Goal, Ctx).
  529'$initialization'(after_load, Goal, Source, Ctx) :-
  530    (   Source \== (-)
  531    ->  '$compile_init_goal'(Source, Goal, Ctx)
  532    ;   throw(error(context_error(nodirective,
  533                                  initialization(Goal, after_load)),
  534                    _))
  535    ).
  536'$initialization'(restore, Goal, Source, Ctx) :- % deprecated
  537    '$initialization'(restore_state, Goal, Source, Ctx).
  538'$initialization'(restore_state, Goal, _Source, Ctx) :-
  539    (   \+ current_prolog_flag(sandboxed_load, true)
  540    ->  '$compile_init_goal'(-, Goal, Ctx)
  541    ;   '$permission_error'(register, initialization(restore), Goal)
  542    ).
  543'$initialization'(prepare_state, Goal, _Source, Ctx) :-
  544    (   \+ current_prolog_flag(sandboxed_load, true)
  545    ->  '$compile_init_goal'(when(prepare_state), Goal, Ctx)
  546    ;   '$permission_error'(register, initialization(restore), Goal)
  547    ).
  548'$initialization'(program, Goal, _Source, Ctx) :-
  549    (   \+ current_prolog_flag(sandboxed_load, true)
  550    ->  '$compile_init_goal'(when(program), Goal, Ctx)
  551    ;   '$permission_error'(register, initialization(restore), Goal)
  552    ).
  553'$initialization'(main, Goal, _Source, Ctx) :-
  554    (   \+ current_prolog_flag(sandboxed_load, true)
  555    ->  '$compile_init_goal'(when(main), Goal, Ctx)
  556    ;   '$permission_error'(register, initialization(restore), Goal)
  557    ).
  558
  559
  560'$compile_init_goal'(Source, Goal, Ctx) :-
  561    atom(Source),
  562    Source \== (-),
  563    !,
  564    '$store_admin_clause'(system:'$init_goal'(Source, Goal, Ctx),
  565                          _Layout, Source, Ctx).
  566'$compile_init_goal'(Source, Goal, Ctx) :-
  567    assertz('$init_goal'(Source, Goal, Ctx)).
 $run_initialization(?File, +Options) is det
 $run_initialization(?File, +Action, +Options) is det
Run initialization directives for all files if File is unbound, or for a specified file. Note that '$run_initialization'/2 is called from runInitialization() in pl-wic.c for .qlf files. The '$run_initialization'/3 is called with Action set to loaded when called for a QLF file.
  579'$run_initialization'(_, loaded, _) :- !.
  580'$run_initialization'(File, _Action, Options) :-
  581    '$run_initialization'(File, Options).
  582
  583'$run_initialization'(File, Options) :-
  584    setup_call_cleanup(
  585        '$start_run_initialization'(Options, Restore),
  586        '$run_initialization_2'(File),
  587        '$end_run_initialization'(Restore)).
  588
  589'$start_run_initialization'(Options, OldSandBoxed) :-
  590    '$push_input_context'(initialization),
  591    '$set_sandboxed_load'(Options, OldSandBoxed).
  592'$end_run_initialization'(OldSandBoxed) :-
  593    set_prolog_flag(sandboxed_load, OldSandBoxed),
  594    '$pop_input_context'.
  595
  596'$run_initialization_2'(File) :-
  597    (   '$init_goal'(File, Goal, Ctx),
  598        File \= when(_),
  599        '$run_init_goal'(Goal, Ctx),
  600        fail
  601    ;   true
  602    ).
  603
  604'$run_init_goal'(Goal, Ctx) :-
  605    (   catch_with_backtrace('$run_init_goal'(Goal), E,
  606                             '$initialization_error'(E, Goal, Ctx))
  607    ->  true
  608    ;   '$initialization_failure'(Goal, Ctx)
  609    ).
  610
  611:- multifile prolog:sandbox_allowed_goal/1.  612
  613'$run_init_goal'(Goal) :-
  614    current_prolog_flag(sandboxed_load, false),
  615    !,
  616    call(Goal).
  617'$run_init_goal'(Goal) :-
  618    prolog:sandbox_allowed_goal(Goal),
  619    call(Goal).
  620
  621'$initialization_context'(Source, Ctx) :-
  622    (   source_location(File, Line)
  623    ->  Ctx = File:Line,
  624        '$input_context'(Context),
  625        '$top_file'(Context, File, Source)
  626    ;   Ctx = (-),
  627        File = (-)
  628    ).
  629
  630'$top_file'([input(include, F1, _, _)|T], _, F) :-
  631    !,
  632    '$top_file'(T, F1, F).
  633'$top_file'(_, F, F).
  634
  635
  636'$initialization_error'(E, Goal, Ctx) :-
  637    print_message(error, initialization_error(Goal, E, Ctx)).
  638
  639'$initialization_failure'(Goal, Ctx) :-
  640    print_message(warning, initialization_failure(Goal, Ctx)).
 $clear_source_admin(+File) is det
Removes source adminstration related to File
See also
- Called from destroySourceFile() in pl-proc.c
  648:- public '$clear_source_admin'/1.  649
  650'$clear_source_admin'(File) :-
  651    retractall('$init_goal'(_, _, File:_)),
  652    retractall('$load_context_module'(File, _, _)),
  653    retractall('$resolved_source_path'(_, File)).
  654
  655
  656                 /*******************************
  657                 *            STREAM            *
  658                 *******************************/
  659
  660:- '$iso'(stream_property/2).  661stream_property(Stream, Property) :-
  662    nonvar(Stream),
  663    nonvar(Property),
  664    !,
  665    '$stream_property'(Stream, Property).
  666stream_property(Stream, Property) :-
  667    nonvar(Stream),
  668    !,
  669    '$stream_properties'(Stream, Properties),
  670    '$member'(Property, Properties).
  671stream_property(Stream, Property) :-
  672    nonvar(Property),
  673    !,
  674    (   Property = alias(Alias),
  675        atom(Alias)
  676    ->  '$alias_stream'(Alias, Stream)
  677    ;   '$streams_properties'(Property, Pairs),
  678        '$member'(Stream-Property, Pairs)
  679    ).
  680stream_property(Stream, Property) :-
  681    '$streams_properties'(Property, Pairs),
  682    '$member'(Stream-Properties, Pairs),
  683    '$member'(Property, Properties).
  684
  685
  686                /********************************
  687                *            MODULES            *
  688                *********************************/
  689
  690%       '$prefix_module'(+Module, +Context, +Term, -Prefixed)
  691%       Tags `Term' with `Module:' if `Module' is not the context module.
  692
  693'$prefix_module'(Module, Module, Head, Head) :- !.
  694'$prefix_module'(Module, _, Head, Module:Head).
 default_module(+Me, -Super) is multi
Is true if `Super' is `Me' or a super (auto import) module of `Me'.
  700default_module(Me, Super) :-
  701    (   atom(Me)
  702    ->  (   var(Super)
  703        ->  '$default_module'(Me, Super)
  704        ;   '$default_module'(Me, Super), !
  705        )
  706    ;   '$type_error'(module, Me)
  707    ).
  708
  709'$default_module'(Me, Me).
  710'$default_module'(Me, Super) :-
  711    import_module(Me, S),
  712    '$default_module'(S, Super).
  713
  714
  715                /********************************
  716                *      TRACE AND EXCEPTIONS     *
  717                *********************************/
  718
  719:- user:dynamic((exception/3,
  720                 prolog_event_hook/1)).  721:- user:multifile((exception/3,
  722                   prolog_event_hook/1)).
 $undefined_procedure(+Module, +Name, +Arity, -Action) is det
This predicate is called from C on undefined predicates. First allows the user to take care of it using exception/3. Else try to give a DWIM warning. Otherwise fail. C will print an error message.
  731:- public
  732    '$undefined_procedure'/4.  733
  734'$undefined_procedure'(Module, Name, Arity, Action) :-
  735    '$prefix_module'(Module, user, Name/Arity, Pred),
  736    user:exception(undefined_predicate, Pred, Action0),
  737    !,
  738    Action = Action0.
  739'$undefined_procedure'(Module, Name, Arity, Action) :-
  740    current_prolog_flag(autoload, true),
  741    '$autoload'(Module, Name, Arity),
  742    !,
  743    Action = retry.
  744'$undefined_procedure'(_, _, _, error).
  745
  746'$autoload'(Module, Name, Arity) :-
  747    source_location(File, _Line),
  748    !,
  749    setup_call_cleanup(
  750        '$start_aux'(File, Context),
  751        '$autoload2'(Module, Name, Arity),
  752        '$end_aux'(File, Context)).
  753'$autoload'(Module, Name, Arity) :-
  754    '$autoload2'(Module, Name, Arity).
  755
  756'$autoload2'(Module, Name, Arity) :-
  757    '$find_library'(Module, Name, Arity, LoadModule, Library),
  758    functor(Head, Name, Arity),
  759    '$update_autoload_level'([autoload(true)], Old),
  760    (   current_prolog_flag(verbose_autoload, true)
  761    ->  Level = informational
  762    ;   Level = silent
  763    ),
  764    print_message(Level, autoload(Module:Name/Arity, Library)),
  765    '$compilation_mode'(OldComp, database),
  766    (   Module == LoadModule
  767    ->  ensure_loaded(Module:Library)
  768    ;   (   '$get_predicate_attribute'(LoadModule:Head, defined, 1),
  769            \+ '$loading'(Library)
  770        ->  Module:import(LoadModule:Name/Arity)
  771        ;   use_module(Module:Library, [Name/Arity])
  772        )
  773    ),
  774    '$set_compilation_mode'(OldComp),
  775    '$set_autoload_level'(Old),
  776    '$c_current_predicate'(_, Module:Head).
 $loading(+Library)
True if the library is being loaded. Just testing that the predicate is defined is not good enough as the file may be partly loaded. Calling use_module/2 at any time has two drawbacks: it queries the filesystem, causing slowdown and it stops libraries being autoloaded from a saved state where the library is already loaded, but the source may not be accessible.
  787'$loading'(Library) :-
  788    current_prolog_flag(threads, true),
  789    '$loading_file'(FullFile, _Queue, _LoadThread),
  790    file_name_extension(Library, _, FullFile),
  791    !.
  792
  793%        handle debugger 'w', 'p' and <N> depth options.
  794
  795'$set_debugger_write_options'(write) :-
  796    !,
  797    create_prolog_flag(debugger_write_options,
  798                       [ quoted(true),
  799                         attributes(dots),
  800                         spacing(next_argument)
  801                       ], []).
  802'$set_debugger_write_options'(print) :-
  803    !,
  804    create_prolog_flag(debugger_write_options,
  805                       [ quoted(true),
  806                         portray(true),
  807                         max_depth(10),
  808                         attributes(portray),
  809                         spacing(next_argument)
  810                       ], []).
  811'$set_debugger_write_options'(Depth) :-
  812    current_prolog_flag(debugger_write_options, Options0),
  813    (   '$select'(max_depth(_), Options0, Options)
  814    ->  true
  815    ;   Options = Options0
  816    ),
  817    create_prolog_flag(debugger_write_options,
  818                       [max_depth(Depth)|Options], []).
  819
  820
  821                /********************************
  822                *        SYSTEM MESSAGES        *
  823                *********************************/
 $confirm(Spec)
Ask the user to confirm a question. Spec is a term as used for print_message/2.
  830'$confirm'(Spec) :-
  831    print_message(query, Spec),
  832    between(0, 5, _),
  833        get_single_char(Answer),
  834        (   '$in_reply'(Answer, 'yYjJ \n')
  835        ->  !,
  836            print_message(query, if_tty([yes-[]]))
  837        ;   '$in_reply'(Answer, 'nN')
  838        ->  !,
  839            print_message(query, if_tty([no-[]])),
  840            fail
  841        ;   print_message(help, query(confirm)),
  842            fail
  843        ).
  844
  845'$in_reply'(Code, Atom) :-
  846    char_code(Char, Code),
  847    sub_atom(Atom, _, _, _, Char),
  848    !.
  849
  850:- dynamic
  851    user:portray/1.  852:- multifile
  853    user:portray/1.  854
  855
  856                 /*******************************
  857                 *       FILE_SEARCH_PATH       *
  858                 *******************************/
  859
  860:- dynamic user:file_search_path/2.  861:- multifile user:file_search_path/2.  862
  863user:(file_search_path(library, Dir) :-
  864        library_directory(Dir)).
  865user:file_search_path(swi, Home) :-
  866    current_prolog_flag(home, Home).
  867user:file_search_path(foreign, swi(ArchLib)) :-
  868    current_prolog_flag(arch, Arch),
  869    atom_concat('lib/', Arch, ArchLib).
  870user:file_search_path(foreign, swi(SoLib)) :-
  871    (   current_prolog_flag(windows, true)
  872    ->  SoLib = bin
  873    ;   SoLib = lib
  874    ).
  875user:file_search_path(path, Dir) :-
  876    getenv('PATH', Path),
  877    (   current_prolog_flag(windows, true)
  878    ->  atomic_list_concat(Dirs, (;), Path)
  879    ;   atomic_list_concat(Dirs, :, Path)
  880    ),
  881    '$member'(Dir, Dirs),
  882    '$no-null-bytes'(Dir).
  883
  884'$no-null-bytes'(Dir) :-
  885    sub_atom(Dir, _, _, _, '\u0000'),
  886    !,
  887    print_message(warning, null_byte_in_path(Dir)),
  888    fail.
  889'$no-null-bytes'(_).
 expand_file_search_path(+Spec, -Expanded) is nondet
Expand a search path. The system uses depth-first search upto a specified depth. If this depth is exceeded an exception is raised. TBD: bread-first search?
  897expand_file_search_path(Spec, Expanded) :-
  898    catch('$expand_file_search_path'(Spec, Expanded, 0, []),
  899          loop(Used),
  900          throw(error(loop_error(Spec), file_search(Used)))).
  901
  902'$expand_file_search_path'(Spec, Expanded, N, Used) :-
  903    functor(Spec, Alias, 1),
  904    !,
  905    user:file_search_path(Alias, Exp0),
  906    NN is N + 1,
  907    (   NN > 16
  908    ->  throw(loop(Used))
  909    ;   true
  910    ),
  911    '$expand_file_search_path'(Exp0, Exp1, NN, [Alias=Exp0|Used]),
  912    arg(1, Spec, Segments),
  913    '$segments_to_atom'(Segments, File),
  914    '$make_path'(Exp1, File, Expanded).
  915'$expand_file_search_path'(Spec, Path, _, _) :-
  916    '$segments_to_atom'(Spec, Path).
  917
  918'$make_path'(Dir, '.', Path) :-
  919    !,
  920    Path = Dir.
  921'$make_path'(Dir, File, Path) :-
  922    sub_atom(Dir, _, _, 0, /),
  923    !,
  924    atom_concat(Dir, File, Path).
  925'$make_path'(Dir, File, Path) :-
  926    atomic_list_concat([Dir, /, File], Path).
  927
  928
  929                /********************************
  930                *         FILE CHECKING         *
  931                *********************************/
 absolute_file_name(+Term, -AbsoluteFile, +Options) is nondet
Translate path-specifier into a full path-name. This predicate originates from Quintus was introduced in SWI-Prolog very early and has re-appeared in SICStus 3.9.0, where they changed argument order and added some options. We addopted the SICStus argument order, but still accept the original argument order for compatibility reasons.
  942absolute_file_name(Spec, Options, Path) :-
  943    '$is_options'(Options),
  944    \+ '$is_options'(Path),
  945    !,
  946    absolute_file_name(Spec, Path, Options).
  947absolute_file_name(Spec, Path, Options) :-
  948    '$must_be'(options, Options),
  949                    % get the valid extensions
  950    (   '$select_option'(extensions(Exts), Options, Options1)
  951    ->  '$must_be'(list, Exts)
  952    ;   '$option'(file_type(Type), Options)
  953    ->  '$must_be'(atom, Type),
  954        '$file_type_extensions'(Type, Exts),
  955        Options1 = Options
  956    ;   Options1 = Options,
  957        Exts = ['']
  958    ),
  959    '$canonicalise_extensions'(Exts, Extensions),
  960                    % unless specified otherwise, ask regular file
  961    (   nonvar(Type)
  962    ->  Options2 = Options1
  963    ;   '$merge_options'(_{file_type:regular}, Options1, Options2)
  964    ),
  965                    % Det or nondet?
  966    (   '$select_option'(solutions(Sols), Options2, Options3)
  967    ->  '$must_be'(oneof(atom, solutions, [first,all]), Sols)
  968    ;   Sols = first,
  969        Options3 = Options2
  970    ),
  971                    % Errors or not?
  972    (   '$select_option'(file_errors(FileErrors), Options3, Options4)
  973    ->  '$must_be'(oneof(atom, file_errors, [error,fail]), FileErrors)
  974    ;   FileErrors = error,
  975        Options4 = Options3
  976    ),
  977                    % Expand shell patterns?
  978    (   atomic(Spec),
  979        '$select_option'(expand(Expand), Options4, Options5),
  980        '$must_be'(boolean, Expand)
  981    ->  expand_file_name(Spec, List),
  982        '$member'(Spec1, List)
  983    ;   Spec1 = Spec,
  984        Options5 = Options4
  985    ),
  986                    % Search for files
  987    (   Sols == first
  988    ->  (   '$chk_file'(Spec1, Extensions, Options5, true, Path)
  989        ->  !       % also kill choice point of expand_file_name/2
  990        ;   (   FileErrors == fail
  991            ->  fail
  992            ;   '$current_module'('$bags', _File),
  993                findall(P,
  994                        '$chk_file'(Spec1, Extensions, [access(exist)],
  995                                    false, P),
  996                        Candidates),
  997                '$abs_file_error'(Spec, Candidates, Options5)
  998            )
  999        )
 1000    ;   '$chk_file'(Spec1, Extensions, Options5, false, Path)
 1001    ).
 1002
 1003'$abs_file_error'(Spec, Candidates, Conditions) :-
 1004    '$member'(F, Candidates),
 1005    '$member'(C, Conditions),
 1006    '$file_condition'(C),
 1007    '$file_error'(C, Spec, F, E, Comment),
 1008    !,
 1009    throw(error(E, context(_, Comment))).
 1010'$abs_file_error'(Spec, _, _) :-
 1011    '$existence_error'(source_sink, Spec).
 1012
 1013'$file_error'(file_type(directory), Spec, File, Error, Comment) :-
 1014    \+ exists_directory(File),
 1015    !,
 1016    Error = existence_error(directory, Spec),
 1017    Comment = not_a_directory(File).
 1018'$file_error'(file_type(_), Spec, File, Error, Comment) :-
 1019    exists_directory(File),
 1020    !,
 1021    Error = existence_error(file, Spec),
 1022    Comment = directory(File).
 1023'$file_error'(access(OneOrList), Spec, File, Error, _) :-
 1024    '$one_or_member'(Access, OneOrList),
 1025    \+ access_file(File, Access),
 1026    Error = permission_error(Access, source_sink, Spec).
 1027
 1028'$one_or_member'(Elem, List) :-
 1029    is_list(List),
 1030    !,
 1031    '$member'(Elem, List).
 1032'$one_or_member'(Elem, Elem).
 1033
 1034
 1035'$file_type_extensions'(source, Exts) :-       % SICStus 3.9 compatibility
 1036    !,
 1037    '$file_type_extensions'(prolog, Exts).
 1038'$file_type_extensions'(Type, Exts) :-
 1039    '$current_module'('$bags', _File),
 1040    !,
 1041    findall(Ext, user:prolog_file_type(Ext, Type), Exts0),
 1042    (   Exts0 == [],
 1043        \+ '$ft_no_ext'(Type)
 1044    ->  '$domain_error'(file_type, Type)
 1045    ;   true
 1046    ),
 1047    '$append'(Exts0, [''], Exts).
 1048'$file_type_extensions'(prolog, [pl, '']). % findall is not yet defined ...
 1049
 1050'$ft_no_ext'(txt).
 1051'$ft_no_ext'(executable).
 1052'$ft_no_ext'(directory).
 user:prolog_file_type(?Extension, ?Type)
Define type of file based on the extension. This is used by absolute_file_name/3 and may be used to extend the list of extensions used for some type.

Note that qlf must be last when searching for Prolog files. Otherwise use_module/1 will consider the file as not-loaded because the .qlf file is not the loaded file. Must be fixed elsewhere.

 1065:- multifile(user:prolog_file_type/2). 1066:- dynamic(user:prolog_file_type/2). 1067
 1068user:prolog_file_type(pl,       prolog).
 1069user:prolog_file_type(prolog,   prolog).
 1070user:prolog_file_type(qlf,      prolog).
 1071user:prolog_file_type(qlf,      qlf).
 1072user:prolog_file_type(Ext,      executable) :-
 1073    current_prolog_flag(shared_object_extension, Ext).
 1074user:prolog_file_type(dylib,    executable) :-
 1075    current_prolog_flag(apple,  true).
 $chk_file(+Spec, +Extensions, +Cond, +UseCache, -FullName)
File is a specification of a Prolog source file. Return the full path of the file.
 1082'$chk_file'(Spec, _Extensions, _Cond, _Cache, _FullName) :-
 1083    \+ ground(Spec),
 1084    !,
 1085    '$instantiation_error'(Spec).
 1086'$chk_file'(Spec, Extensions, Cond, Cache, FullName) :-
 1087    compound(Spec),
 1088    functor(Spec, _, 1),
 1089    !,
 1090    '$relative_to'(Cond, cwd, CWD),
 1091    '$chk_alias_file'(Spec, Extensions, Cond, Cache, CWD, FullName).
 1092'$chk_file'(Segments, Ext, Cond, Cache, FullName) :-    % allow a/b/...
 1093    \+ atomic(Segments),
 1094    !,
 1095    '$segments_to_atom'(Segments, Atom),
 1096    '$chk_file'(Atom, Ext, Cond, Cache, FullName).
 1097'$chk_file'(File, Exts, Cond, _, FullName) :-
 1098    is_absolute_file_name(File),
 1099    !,
 1100    '$extend_file'(File, Exts, Extended),
 1101    '$file_conditions'(Cond, Extended),
 1102    '$absolute_file_name'(Extended, FullName).
 1103'$chk_file'(File, Exts, Cond, _, FullName) :-
 1104    '$relative_to'(Cond, source, Dir),
 1105    atomic_list_concat([Dir, /, File], AbsFile),
 1106    '$extend_file'(AbsFile, Exts, Extended),
 1107    '$file_conditions'(Cond, Extended),
 1108    !,
 1109    '$absolute_file_name'(Extended, FullName).
 1110'$chk_file'(File, Exts, Cond, _, FullName) :-
 1111    '$extend_file'(File, Exts, Extended),
 1112    '$file_conditions'(Cond, Extended),
 1113    '$absolute_file_name'(Extended, FullName).
 1114
 1115'$segments_to_atom'(Atom, Atom) :-
 1116    atomic(Atom),
 1117    !.
 1118'$segments_to_atom'(Segments, Atom) :-
 1119    '$segments_to_list'(Segments, List, []),
 1120    !,
 1121    atomic_list_concat(List, /, Atom).
 1122
 1123'$segments_to_list'(A/B, H, T) :-
 1124    '$segments_to_list'(A, H, T0),
 1125    '$segments_to_list'(B, T0, T).
 1126'$segments_to_list'(A, [A|T], T) :-
 1127    atomic(A).
 $relative_to(+Condition, +Default, -Dir)
Determine the directory to work from. This can be specified explicitely using one or more relative_to(FileOrDir) options or implicitely relative to the working directory or current source-file.
 1137'$relative_to'(Conditions, Default, Dir) :-
 1138    (   '$option'(relative_to(FileOrDir), Conditions)
 1139    *-> (   exists_directory(FileOrDir)
 1140        ->  Dir = FileOrDir
 1141        ;   atom_concat(Dir, /, FileOrDir)
 1142        ->  true
 1143        ;   file_directory_name(FileOrDir, Dir)
 1144        )
 1145    ;   Default == cwd
 1146    ->  '$cwd'(Dir)
 1147    ;   Default == source
 1148    ->  source_location(ContextFile, _Line),
 1149        file_directory_name(ContextFile, Dir)
 1150    ).
 $chk_alias_file(+Spec, +Exts, +Cond, +Cache, +CWD, -FullFile) is nondet
 1155:- dynamic
 1156    '$search_path_file_cache'/3,    % SHA1, Time, Path
 1157    '$search_path_gc_time'/1.       % Time
 1158:- volatile
 1159    '$search_path_file_cache'/3,
 1160    '$search_path_gc_time'/1. 1161
 1162:- create_prolog_flag(file_search_cache_time, 10, []). 1163
 1164'$chk_alias_file'(Spec, Exts, Cond, true, CWD, FullFile) :-
 1165    !,
 1166    findall(Exp, expand_file_search_path(Spec, Exp), Expansions),
 1167    Cache = cache(Exts, Cond, CWD, Expansions),
 1168    variant_sha1(Spec+Cache, SHA1),
 1169    get_time(Now),
 1170    current_prolog_flag(file_search_cache_time, TimeOut),
 1171    (   '$search_path_file_cache'(SHA1, CachedTime, FullFile),
 1172        CachedTime > Now - TimeOut,
 1173        '$file_conditions'(Cond, FullFile)
 1174    ->  '$search_message'(file_search(cache(Spec, Cond), FullFile))
 1175    ;   '$member'(Expanded, Expansions),
 1176        '$extend_file'(Expanded, Exts, LibFile),
 1177        (   '$file_conditions'(Cond, LibFile),
 1178            '$absolute_file_name'(LibFile, FullFile),
 1179            '$cache_file_found'(SHA1, Now, TimeOut, FullFile)
 1180        ->  '$search_message'(file_search(found(Spec, Cond), FullFile))
 1181        ;   '$search_message'(file_search(tried(Spec, Cond), LibFile)),
 1182            fail
 1183        )
 1184    ).
 1185'$chk_alias_file'(Spec, Exts, Cond, false, _CWD, FullFile) :-
 1186    expand_file_search_path(Spec, Expanded),
 1187    '$extend_file'(Expanded, Exts, LibFile),
 1188    '$file_conditions'(Cond, LibFile),
 1189    '$absolute_file_name'(LibFile, FullFile).
 1190
 1191'$cache_file_found'(_, _, TimeOut, _) :-
 1192    TimeOut =:= 0,
 1193    !.
 1194'$cache_file_found'(SHA1, Now, TimeOut, FullFile) :-
 1195    '$search_path_file_cache'(SHA1, Saved, FullFile),
 1196    !,
 1197    (   Now - Saved < TimeOut/2
 1198    ->  true
 1199    ;   retractall('$search_path_file_cache'(SHA1, _, _)),
 1200        asserta('$search_path_file_cache'(SHA1, Now, FullFile))
 1201    ).
 1202'$cache_file_found'(SHA1, Now, TimeOut, FullFile) :-
 1203    'gc_file_search_cache'(TimeOut),
 1204    asserta('$search_path_file_cache'(SHA1, Now, FullFile)).
 1205
 1206'gc_file_search_cache'(TimeOut) :-
 1207    get_time(Now),
 1208    '$search_path_gc_time'(Last),
 1209    Now-Last < TimeOut/2,
 1210    !.
 1211'gc_file_search_cache'(TimeOut) :-
 1212    get_time(Now),
 1213    retractall('$search_path_gc_time'(_)),
 1214    assertz('$search_path_gc_time'(Now)),
 1215    Before is Now - TimeOut,
 1216    (   '$search_path_file_cache'(SHA1, Cached, FullFile),
 1217        Cached < Before,
 1218        retractall('$search_path_file_cache'(SHA1, Cached, FullFile)),
 1219        fail
 1220    ;   true
 1221    ).
 1222
 1223
 1224'$search_message'(Term) :-
 1225    current_prolog_flag(verbose_file_search, true),
 1226    !,
 1227    print_message(informational, Term).
 1228'$search_message'(_).
 $file_conditions(+Condition, +Path)
Verify Path satisfies Condition.
 1235'$file_conditions'(List, File) :-
 1236    is_list(List),
 1237    !,
 1238    \+ ( '$member'(C, List),
 1239         '$file_condition'(C),
 1240         \+ '$file_condition'(C, File)
 1241       ).
 1242'$file_conditions'(Map, File) :-
 1243    \+ (  get_dict(Key, Map, Value),
 1244          C =.. [Key,Value],
 1245          '$file_condition'(C),
 1246         \+ '$file_condition'(C, File)
 1247       ).
 1248
 1249'$file_condition'(file_type(directory), File) :-
 1250    !,
 1251    exists_directory(File).
 1252'$file_condition'(file_type(_), File) :-
 1253    !,
 1254    \+ exists_directory(File).
 1255'$file_condition'(access(Accesses), File) :-
 1256    !,
 1257    \+ (  '$one_or_member'(Access, Accesses),
 1258          \+ access_file(File, Access)
 1259       ).
 1260
 1261'$file_condition'(exists).
 1262'$file_condition'(file_type(_)).
 1263'$file_condition'(access(_)).
 1264
 1265'$extend_file'(File, Exts, FileEx) :-
 1266    '$ensure_extensions'(Exts, File, Fs),
 1267    '$list_to_set'(Fs, FsSet),
 1268    '$member'(FileEx, FsSet).
 1269
 1270'$ensure_extensions'([], _, []).
 1271'$ensure_extensions'([E|E0], F, [FE|E1]) :-
 1272    file_name_extension(F, E, FE),
 1273    '$ensure_extensions'(E0, F, E1).
 $list_to_set(+List, -Set) is det
Turn list into a set, keeping the left-most copy of duplicate elements. Note that library(lists) provides an O(N*log(N)) version, but sets of file name extensions should be short enough for this not to matter.
 1282'$list_to_set'(List, Set) :-
 1283    '$list_to_set'(List, [], Set).
 1284
 1285'$list_to_set'([], _, []).
 1286'$list_to_set'([H|T], Seen, R) :-
 1287    memberchk(H, Seen),
 1288    !,
 1289    '$list_to_set'(T, R).
 1290'$list_to_set'([H|T], Seen, [H|R]) :-
 1291    '$list_to_set'(T, [H|Seen], R).
 1292
 1293/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 1294Canonicalise the extension list. Old SWI-Prolog   require  `.pl', etc, which
 1295the Quintus compatibility  requests  `pl'.   This  layer  canonicalises  all
 1296extensions to .ext
 1297- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 1298
 1299'$canonicalise_extensions'([], []) :- !.
 1300'$canonicalise_extensions'([H|T], [CH|CT]) :-
 1301    !,
 1302    '$must_be'(atom, H),
 1303    '$canonicalise_extension'(H, CH),
 1304    '$canonicalise_extensions'(T, CT).
 1305'$canonicalise_extensions'(E, [CE]) :-
 1306    '$canonicalise_extension'(E, CE).
 1307
 1308'$canonicalise_extension'('', '') :- !.
 1309'$canonicalise_extension'(DotAtom, DotAtom) :-
 1310    sub_atom(DotAtom, 0, _, _, '.'),
 1311    !.
 1312'$canonicalise_extension'(Atom, DotAtom) :-
 1313    atom_concat('.', Atom, DotAtom).
 1314
 1315
 1316                /********************************
 1317                *            CONSULT            *
 1318                *********************************/
 1319
 1320:- dynamic
 1321    user:library_directory/1,
 1322    user:prolog_load_file/2. 1323:- multifile
 1324    user:library_directory/1,
 1325    user:prolog_load_file/2. 1326
 1327:- prompt(_, '|: '). 1328
 1329:- thread_local
 1330    '$compilation_mode_store'/1,    % database, wic, qlf
 1331    '$directive_mode_store'/1.      % database, wic, qlf
 1332:- volatile
 1333    '$compilation_mode_store'/1,
 1334    '$directive_mode_store'/1. 1335
 1336'$compilation_mode'(Mode) :-
 1337    (   '$compilation_mode_store'(Val)
 1338    ->  Mode = Val
 1339    ;   Mode = database
 1340    ).
 1341
 1342'$set_compilation_mode'(Mode) :-
 1343    retractall('$compilation_mode_store'(_)),
 1344    assertz('$compilation_mode_store'(Mode)).
 1345
 1346'$compilation_mode'(Old, New) :-
 1347    '$compilation_mode'(Old),
 1348    (   New == Old
 1349    ->  true
 1350    ;   '$set_compilation_mode'(New)
 1351    ).
 1352
 1353'$directive_mode'(Mode) :-
 1354    (   '$directive_mode_store'(Val)
 1355    ->  Mode = Val
 1356    ;   Mode = database
 1357    ).
 1358
 1359'$directive_mode'(Old, New) :-
 1360    '$directive_mode'(Old),
 1361    (   New == Old
 1362    ->  true
 1363    ;   '$set_directive_mode'(New)
 1364    ).
 1365
 1366'$set_directive_mode'(Mode) :-
 1367    retractall('$directive_mode_store'(_)),
 1368    assertz('$directive_mode_store'(Mode)).
 $compilation_level(-Level) is det
True when Level reflects the nesting in files compiling other files. 0 if no files are being loaded.
 1376'$compilation_level'(Level) :-
 1377    '$input_context'(Stack),
 1378    '$compilation_level'(Stack, Level).
 1379
 1380'$compilation_level'([], 0).
 1381'$compilation_level'([Input|T], Level) :-
 1382    (   arg(1, Input, see)
 1383    ->  '$compilation_level'(T, Level)
 1384    ;   '$compilation_level'(T, Level0),
 1385        Level is Level0+1
 1386    ).
 compiling
Is true if SWI-Prolog is generating a state or qlf file or executes a `call' directive while doing this.
 1394compiling :-
 1395    \+ (   '$compilation_mode'(database),
 1396           '$directive_mode'(database)
 1397       ).
 1398
 1399:- meta_predicate
 1400    '$ifcompiling'(0). 1401
 1402'$ifcompiling'(G) :-
 1403    (   '$compilation_mode'(database)
 1404    ->  true
 1405    ;   call(G)
 1406    ).
 1407
 1408                /********************************
 1409                *         READ SOURCE           *
 1410                *********************************/
 $load_msg_level(+Action, +NestingLevel, -StartVerbose, -EndVerbose)
 1414'$load_msg_level'(Action, Nesting, Start, Done) :-
 1415    '$update_autoload_level'([], 0),
 1416    !,
 1417    current_prolog_flag(verbose_load, Type0),
 1418    '$load_msg_compat'(Type0, Type),
 1419    (   '$load_msg_level'(Action, Nesting, Type, Start, Done)
 1420    ->  true
 1421    ).
 1422'$load_msg_level'(_, _, silent, silent).
 1423
 1424'$load_msg_compat'(true, normal) :- !.
 1425'$load_msg_compat'(false, silent) :- !.
 1426'$load_msg_compat'(X, X).
 1427
 1428'$load_msg_level'(load_file,    _, full,   informational, informational).
 1429'$load_msg_level'(include_file, _, full,   informational, informational).
 1430'$load_msg_level'(load_file,    _, normal, silent,        informational).
 1431'$load_msg_level'(include_file, _, normal, silent,        silent).
 1432'$load_msg_level'(load_file,    0, brief,  silent,        informational).
 1433'$load_msg_level'(load_file,    _, brief,  silent,        silent).
 1434'$load_msg_level'(include_file, _, brief,  silent,        silent).
 1435'$load_msg_level'(load_file,    _, silent, silent,        silent).
 1436'$load_msg_level'(include_file, _, silent, silent,        silent).
 $source_term(+From, -Read, -RLayout, -Term, -TLayout, -Stream, +Options) is nondet
Read Prolog terms from the input From. Terms are returned on backtracking. Associated resources (i.e., streams) are closed due to setup_call_cleanup/3.
Arguments:
From- is either a term stream(Id, Stream) or a file specification.
Read- is the raw term as read from the input.
Term- is the term after term-expansion. If a term is expanded into the empty list, this is returned too. This is required to be able to return the raw term in Read
Stream- is the stream from which Read is read
Options- provides additional options:
encoding(Enc)
Encoding used to open From
syntax_errors(+ErrorMode)
process_comments(+Boolean)
term_position(-Pos)
 1459'$source_term'(From, Read, RLayout, Term, TLayout, Stream, Options) :-
 1460    '$source_term'(From, Read, RLayout, Term, TLayout, Stream, [], Options),
 1461    (   Term == end_of_file
 1462    ->  !, fail
 1463    ;   Term \== begin_of_file
 1464    ).
 1465
 1466'$source_term'(Input, _,_,_,_,_,_,_) :-
 1467    \+ ground(Input),
 1468    !,
 1469    '$instantiation_error'(Input).
 1470'$source_term'(stream(Id, In, Opts),
 1471               Read, RLayout, Term, TLayout, Stream, Parents, Options) :-
 1472    !,
 1473    '$record_included'(Parents, Id, Id, 0.0, Message),
 1474    setup_call_cleanup(
 1475        '$open_source'(stream(Id, In, Opts), In, State, Parents, Options),
 1476        '$term_in_file'(In, Read, RLayout, Term, TLayout, Stream,
 1477                        [Id|Parents], Options),
 1478        '$close_source'(State, Message)).
 1479'$source_term'(File,
 1480               Read, RLayout, Term, TLayout, Stream, Parents, Options) :-
 1481    absolute_file_name(File, Path,
 1482                       [ file_type(prolog),
 1483                         access(read)
 1484                       ]),
 1485    time_file(Path, Time),
 1486    '$record_included'(Parents, File, Path, Time, Message),
 1487    setup_call_cleanup(
 1488        '$open_source'(Path, In, State, Parents, Options),
 1489        '$term_in_file'(In, Read, RLayout, Term, TLayout, Stream,
 1490                        [Path|Parents], Options),
 1491        '$close_source'(State, Message)).
 1492
 1493:- thread_local
 1494    '$load_input'/2. 1495:- volatile
 1496    '$load_input'/2. 1497
 1498'$open_source'(stream(Id, In, Opts), In,
 1499               restore(In, StreamState, Id, Ref, Opts), Parents, Options) :-
 1500    !,
 1501    '$context_type'(Parents, ContextType),
 1502    '$push_input_context'(ContextType),
 1503    '$set_encoding'(In, Options),
 1504    '$prepare_load_stream'(In, Id, StreamState),
 1505    asserta('$load_input'(stream(Id), In), Ref).
 1506'$open_source'(Path, In, close(In, Path, Ref), Parents, Options) :-
 1507    '$context_type'(Parents, ContextType),
 1508    '$push_input_context'(ContextType),
 1509    open(Path, read, In),
 1510    '$set_encoding'(In, Options),
 1511    asserta('$load_input'(Path, In), Ref).
 1512
 1513'$context_type'([], load_file) :- !.
 1514'$context_type'(_, include).
 1515
 1516'$close_source'(close(In, Id, Ref), Message) :-
 1517    erase(Ref),
 1518    '$end_consult'(Id),
 1519    call_cleanup(
 1520        close(In),
 1521        '$pop_input_context'),
 1522    '$close_message'(Message).
 1523'$close_source'(restore(In, StreamState, Id, Ref, Opts), Message) :-
 1524    erase(Ref),
 1525    '$end_consult'(Id),
 1526    call_cleanup(
 1527        '$restore_load_stream'(In, StreamState, Opts),
 1528        '$pop_input_context'),
 1529    '$close_message'(Message).
 1530
 1531'$close_message'(message(Level, Msg)) :-
 1532    !,
 1533    '$print_message'(Level, Msg).
 1534'$close_message'(_).
 $term_in_file(+In, -Read, -RLayout, -Term, -TLayout, -Stream, +Parents, +Options) is multi
True when Term is an expanded term from In. Read is a raw term (before term-expansion). Stream is the actual stream, which starts at In, but may change due to processing included files.
See also
- '$source_term'/8 for details.
 1546'$term_in_file'(In, Read, RLayout, Term, TLayout, Stream, Parents, Options) :-
 1547    Parents \= [_,_|_],
 1548    (   '$load_input'(_, Input)
 1549    ->  stream_property(Input, file_name(File))
 1550    ),
 1551    '$set_source_location'(File, 0),
 1552    '$expanded_term'(In,
 1553                     begin_of_file, 0-0, Read, RLayout, Term, TLayout,
 1554                     Stream, Parents, Options).
 1555'$term_in_file'(In, Read, RLayout, Term, TLayout, Stream, Parents, Options) :-
 1556    '$skip_script_line'(In, Options),
 1557    '$read_clause_options'(Options, ReadOptions),
 1558    repeat,
 1559      read_clause(In, Raw,
 1560                  [ variable_names(Bindings),
 1561                    term_position(Pos),
 1562                    subterm_positions(RawLayout)
 1563                  | ReadOptions
 1564                  ]),
 1565      b_setval('$term_position', Pos),
 1566      b_setval('$variable_names', Bindings),
 1567      (   Raw == end_of_file
 1568      ->  !,
 1569          (   Parents = [_,_|_]     % Included file
 1570          ->  fail
 1571          ;   '$expanded_term'(In,
 1572                               Raw, RawLayout, Read, RLayout, Term, TLayout,
 1573                               Stream, Parents, Options)
 1574          )
 1575      ;   '$expanded_term'(In, Raw, RawLayout, Read, RLayout, Term, TLayout,
 1576                           Stream, Parents, Options)
 1577      ).
 1578
 1579'$read_clause_options'([], []).
 1580'$read_clause_options'([H|T0], List) :-
 1581    (   '$read_clause_option'(H)
 1582    ->  List = [H|T]
 1583    ;   List = T
 1584    ),
 1585    '$read_clause_options'(T0, T).
 1586
 1587'$read_clause_option'(syntax_errors(_)).
 1588'$read_clause_option'(term_position(_)).
 1589'$read_clause_option'(process_comment(_)).
 1590
 1591'$expanded_term'(In, Raw, RawLayout, Read, RLayout, Term, TLayout,
 1592                 Stream, Parents, Options) :-
 1593    E = error(_,_),
 1594    catch('$expand_term'(Raw, RawLayout, Expanded, ExpandedLayout), E,
 1595          '$print_message_fail'(E)),
 1596    (   Expanded \== []
 1597    ->  '$expansion_member'(Expanded, ExpandedLayout, Term1, Layout1)
 1598    ;   Term1 = Expanded,
 1599        Layout1 = ExpandedLayout
 1600    ),
 1601    (   nonvar(Term1), Term1 = (:-Directive), nonvar(Directive)
 1602    ->  (   Directive = include(File),
 1603            '$current_source_module'(Module),
 1604            '$valid_directive'(Module:include(File))
 1605        ->  stream_property(In, encoding(Enc)),
 1606            '$add_encoding'(Enc, Options, Options1),
 1607            '$source_term'(File, Read, RLayout, Term, TLayout,
 1608                           Stream, Parents, Options1)
 1609        ;   Directive = encoding(Enc)
 1610        ->  set_stream(In, encoding(Enc)),
 1611            fail
 1612        ;   Term = Term1,
 1613            Stream = In,
 1614            Read = Raw
 1615        )
 1616    ;   Term = Term1,
 1617        TLayout = Layout1,
 1618        Stream = In,
 1619        Read = Raw,
 1620        RLayout = RawLayout
 1621    ).
 1622
 1623'$expansion_member'(Var, Layout, Var, Layout) :-
 1624    var(Var),
 1625    !.
 1626'$expansion_member'([], _, _, _) :- !, fail.
 1627'$expansion_member'(List, ListLayout, Term, Layout) :-
 1628    is_list(List),
 1629    !,
 1630    (   var(ListLayout)
 1631    ->  '$member'(Term, List)
 1632    ;   is_list(ListLayout)
 1633    ->  '$member_rep2'(Term, Layout, List, ListLayout)
 1634    ;   Layout = ListLayout,
 1635        '$member'(Term, List)
 1636    ).
 1637'$expansion_member'(X, Layout, X, Layout).
 1638
 1639% pairwise member, repeating last element of the second
 1640% list.
 1641
 1642'$member_rep2'(H1, H2, [H1|_], [H2|_]).
 1643'$member_rep2'(H1, H2, [_|T1], [T2]) :-
 1644    !,
 1645    '$member_rep2'(H1, H2, T1, [T2]).
 1646'$member_rep2'(H1, H2, [_|T1], [_|T2]) :-
 1647    '$member_rep2'(H1, H2, T1, T2).
 $add_encoding(+Enc, +Options0, -Options)
 1651'$add_encoding'(Enc, Options0, Options) :-
 1652    (   Options0 = [encoding(Enc)|_]
 1653    ->  Options = Options0
 1654    ;   Options = [encoding(Enc)|Options0]
 1655    ).
 1656
 1657
 1658:- multifile
 1659    '$included'/4.                  % Into, Line, File, LastModified
 1660:- dynamic
 1661    '$included'/4.
 $record_included(+Parents, +File, +Path, +Time, -Message) is det
Record that we included File into the head of Parents. This is troublesome when creating a QLF file because this may happen before we opened the QLF file (and we do not yet know how to open the file because we do not yet know whether this is a module file or not).

I think that the only sensible solution is to have a special statement for this, that may appear both inside and outside QLF `parts'.

 1675'$record_included'([Parent|Parents], File, Path, Time,
 1676                   message(DoneMsgLevel,
 1677                           include_file(done(Level, file(File, Path))))) :-
 1678    source_location(SrcFile, Line),
 1679    !,
 1680    '$compilation_level'(Level),
 1681    '$load_msg_level'(include_file, Level, StartMsgLevel, DoneMsgLevel),
 1682    '$print_message'(StartMsgLevel,
 1683                     include_file(start(Level,
 1684                                        file(File, Path)))),
 1685    '$last'([Parent|Parents], Owner),
 1686    (   (   '$compilation_mode'(database)
 1687        ;   '$qlf_current_source'(Owner)
 1688        )
 1689    ->  '$store_admin_clause'(
 1690            system:'$included'(Parent, Line, Path, Time),
 1691            _, Owner, SrcFile:Line)
 1692    ;   '$qlf_include'(Owner, Parent, Line, Path, Time)
 1693    ).
 1694'$record_included'(_, _, _, _, true).
 $master_file(+File, -MasterFile)
Find the primary load file from included files.
 1700'$master_file'(File, MasterFile) :-
 1701    '$included'(MasterFile0, _Line, File, _Time),
 1702    !,
 1703    '$master_file'(MasterFile0, MasterFile).
 1704'$master_file'(File, File).
 1705
 1706
 1707'$skip_script_line'(_In, Options) :-
 1708    '$option'(check_script(false), Options),
 1709    !.
 1710'$skip_script_line'(In, _Options) :-
 1711    (   peek_char(In, #)
 1712    ->  skip(In, 10)
 1713    ;   true
 1714    ).
 1715
 1716'$set_encoding'(Stream, Options) :-
 1717    '$option'(encoding(Enc), Options),
 1718    !,
 1719    Enc \== default,
 1720    set_stream(Stream, encoding(Enc)).
 1721'$set_encoding'(_, _).
 1722
 1723
 1724'$prepare_load_stream'(In, Id, state(HasName,HasPos)) :-
 1725    (   stream_property(In, file_name(_))
 1726    ->  HasName = true,
 1727        (   stream_property(In, position(_))
 1728        ->  HasPos = true
 1729        ;   HasPos = false,
 1730            set_stream(In, record_position(true))
 1731        )
 1732    ;   HasName = false,
 1733        set_stream(In, file_name(Id)),
 1734        (   stream_property(In, position(_))
 1735        ->  HasPos = true
 1736        ;   HasPos = false,
 1737            set_stream(In, record_position(true))
 1738        )
 1739    ).
 1740
 1741'$restore_load_stream'(In, _State, Options) :-
 1742    memberchk(close(true), Options),
 1743    !,
 1744    close(In).
 1745'$restore_load_stream'(In, state(HasName, HasPos), _Options) :-
 1746    (   HasName == false
 1747    ->  set_stream(In, file_name(''))
 1748    ;   true
 1749    ),
 1750    (   HasPos == false
 1751    ->  set_stream(In, record_position(false))
 1752    ;   true
 1753    ).
 1754
 1755
 1756                 /*******************************
 1757                 *          DERIVED FILES       *
 1758                 *******************************/
 1759
 1760:- dynamic
 1761    '$derived_source_db'/3.         % Loaded, DerivedFrom, Time
 1762
 1763'$register_derived_source'(_, '-') :- !.
 1764'$register_derived_source'(Loaded, DerivedFrom) :-
 1765    retractall('$derived_source_db'(Loaded, _, _)),
 1766    time_file(DerivedFrom, Time),
 1767    assert('$derived_source_db'(Loaded, DerivedFrom, Time)).
 1768
 1769%       Auto-importing dynamic predicates is not very elegant and
 1770%       leads to problems with qsave_program/[1,2]
 1771
 1772'$derived_source'(Loaded, DerivedFrom, Time) :-
 1773    '$derived_source_db'(Loaded, DerivedFrom, Time).
 1774
 1775
 1776                /********************************
 1777                *       LOAD PREDICATES         *
 1778                *********************************/
 1779
 1780:- meta_predicate
 1781    ensure_loaded(:),
 1782    [:|+],
 1783    consult(:),
 1784    use_module(:),
 1785    use_module(:, +),
 1786    reexport(:),
 1787    reexport(:, +),
 1788    load_files(:),
 1789    load_files(:, +).
 ensure_loaded(+FileOrListOfFiles)
Load specified files, provided they where not loaded before. If the file is a module file import the public predicates into the context module.
 1797ensure_loaded(Files) :-
 1798    load_files(Files, [if(not_loaded)]).
 use_module(+FileOrListOfFiles)
Very similar to ensure_loaded/1, but insists on the loaded file to be a module file. If the file is already imported, but the public predicates are not yet imported into the context module, then do so.
 1807use_module(Files) :-
 1808    load_files(Files, [ if(not_loaded),
 1809                        must_be_module(true)
 1810                      ]).
 use_module(+File, +ImportList)
As use_module/1, but takes only one file argument and imports only the specified predicates rather than all public predicates.
 1817use_module(File, Import) :-
 1818    load_files(File, [ if(not_loaded),
 1819                       must_be_module(true),
 1820                       imports(Import)
 1821                     ]).
 reexport(+Files)
As use_module/1, exporting all imported predicates.
 1827reexport(Files) :-
 1828    load_files(Files, [ if(not_loaded),
 1829                        must_be_module(true),
 1830                        reexport(true)
 1831                      ]).
 reexport(+File, +ImportList)
As use_module/1, re-exporting all imported predicates.
 1837reexport(File, Import) :-
 1838    load_files(File, [ if(not_loaded),
 1839                       must_be_module(true),
 1840                       imports(Import),
 1841                       reexport(true)
 1842                     ]).
 1843
 1844
 1845[X] :-
 1846    !,
 1847    consult(X).
 1848[M:F|R] :-
 1849    consult(M:[F|R]).
 1850
 1851consult(M:X) :-
 1852    X == user,
 1853    !,
 1854    flag('$user_consult', N, N+1),
 1855    NN is N + 1,
 1856    atom_concat('user://', NN, Id),
 1857    load_files(M:Id, [stream(user_input), check_script(false), silent(false)]).
 1858consult(List) :-
 1859    load_files(List, [expand(true)]).
 load_files(:File, +Options)
Common entry for all the consult derivates. File is the raw user specified file specification, possibly tagged with the module.
 1866load_files(Files) :-
 1867    load_files(Files, []).
 1868load_files(Module:Files, Options) :-
 1869    '$must_be'(list, Options),
 1870    '$load_files'(Files, Module, Options).
 1871
 1872'$load_files'(X, _, _) :-
 1873    var(X),
 1874    !,
 1875    '$instantiation_error'(X).
 1876'$load_files'([], _, _) :- !.
 1877'$load_files'(Id, Module, Options) :-   % load_files(foo, [stream(In)])
 1878    '$option'(stream(_), Options),
 1879    !,
 1880    (   atom(Id)
 1881    ->  '$load_file'(Id, Module, Options)
 1882    ;   throw(error(type_error(atom, Id), _))
 1883    ).
 1884'$load_files'(List, Module, Options) :-
 1885    List = [_|_],
 1886    !,
 1887    '$must_be'(list, List),
 1888    '$load_file_list'(List, Module, Options).
 1889'$load_files'(File, Module, Options) :-
 1890    '$load_one_file'(File, Module, Options).
 1891
 1892'$load_file_list'([], _, _).
 1893'$load_file_list'([File|Rest], Module, Options) :-
 1894    E = error(_,_),
 1895    catch('$load_one_file'(File, Module, Options), E,
 1896          '$print_message'(error, E)),
 1897    '$load_file_list'(Rest, Module, Options).
 1898
 1899
 1900'$load_one_file'(Spec, Module, Options) :-
 1901    atomic(Spec),
 1902    '$option'(expand(Expand), Options, false),
 1903    Expand == true,
 1904    !,
 1905    expand_file_name(Spec, Expanded),
 1906    (   Expanded = [Load]
 1907    ->  true
 1908    ;   Load = Expanded
 1909    ),
 1910    '$load_files'(Load, Module, [expand(false)|Options]).
 1911'$load_one_file'(File, Module, Options) :-
 1912    strip_module(Module:File, Into, PlainFile),
 1913    '$load_file'(PlainFile, Into, Options).
 $noload(+Condition, +FullFile, +Options) is semidet
True of FullFile should not be loaded.
 1920'$noload'(true, _, _) :-
 1921    !,
 1922    fail.
 1923'$noload'(not_loaded, FullFile, _) :-
 1924    source_file(FullFile),
 1925    !.
 1926'$noload'(changed, Derived, _) :-
 1927    '$derived_source'(_FullFile, Derived, LoadTime),
 1928    time_file(Derived, Modified),
 1929    Modified @=< LoadTime,
 1930    !.
 1931'$noload'(changed, FullFile, Options) :-
 1932    '$time_source_file'(FullFile, LoadTime, user),
 1933    '$modified_id'(FullFile, Modified, Options),
 1934    Modified @=< LoadTime,
 1935    !.
 $qlf_file(+Spec, +PlFile, -LoadFile, -Mode, +Options) is det
Determine how to load the source. LoadFile is the file to be loaded, Mode is how to load it. Mode is one of
compile
Normal source compilation
qcompile
Compile from source, creating a QLF file in the process
qload
Load from QLF file.
stream
Load from a stream. Content can be a source or QLF file.
Arguments:
Spec- is the original search specification
PlFile- is the resolved absolute path to the Prolog file.
 1954'$qlf_file'(Spec, _, Spec, stream, Options) :-
 1955    '$option'(stream(_), Options),      % stream: no choice
 1956    !.
 1957'$qlf_file'(Spec, FullFile, FullFile, compile, _) :-
 1958    '$spec_extension'(Spec, Ext),       % user explicitly specified
 1959    user:prolog_file_type(Ext, prolog),
 1960    !.
 1961'$qlf_file'(Spec, FullFile, LoadFile, Mode, Options) :-
 1962    '$compilation_mode'(database),
 1963    file_name_extension(Base, PlExt, FullFile),
 1964    user:prolog_file_type(PlExt, prolog),
 1965    user:prolog_file_type(QlfExt, qlf),
 1966    file_name_extension(Base, QlfExt, QlfFile),
 1967    (   access_file(QlfFile, read),
 1968        (   '$qlf_out_of_date'(FullFile, QlfFile, Why)
 1969        ->  (   access_file(QlfFile, write)
 1970            ->  print_message(informational,
 1971                              qlf(recompile(Spec, FullFile, QlfFile, Why))),
 1972                Mode = qcompile
 1973            ;   print_message(warning,
 1974                              qlf(can_not_recompile(Spec, QlfFile, Why))),
 1975                Mode = compile
 1976            ),
 1977            LoadFile = FullFile
 1978        ;   Mode = qload,
 1979            LoadFile = QlfFile
 1980        )
 1981    ->  !
 1982    ;   '$qlf_auto'(FullFile, QlfFile, Options)
 1983    ->  !, Mode = qcompile,
 1984        LoadFile = FullFile
 1985    ).
 1986'$qlf_file'(_, FullFile, FullFile, compile, _).
 $qlf_out_of_date(+PlFile, +QlfFile, -Why) is semidet
True if the QlfFile file is out-of-date because of Why. This predicate is the negation such that we can return the reason.
 1994'$qlf_out_of_date'(PlFile, QlfFile, Why) :-
 1995    (   access_file(PlFile, read)
 1996    ->  time_file(PlFile, PlTime),
 1997        time_file(QlfFile, QlfTime),
 1998        (   PlTime > QlfTime
 1999        ->  Why = old                   % PlFile is newer
 2000        ;   Error = error(Formal,_),
 2001            catch('$qlf_sources'(QlfFile, _Files), Error, true),
 2002            nonvar(Formal)              % QlfFile is incompatible
 2003        ->  Why = Error
 2004        ;   fail                        % QlfFile is up-to-date and ok
 2005        )
 2006    ;   fail                            % can not read .pl; try .qlf
 2007    ).
 $qlf_auto(+PlFile, +QlfFile, +Options) is semidet
True if we create QlfFile using qcompile/2. This is determined by the option qcompile(QlfMode) or, if this is not present, by the prolog_flag qcompile.
 2015:- create_prolog_flag(qcompile, false, [type(atom)]). 2016
 2017'$qlf_auto'(PlFile, QlfFile, Options) :-
 2018    (   memberchk(qcompile(QlfMode), Options)
 2019    ->  true
 2020    ;   current_prolog_flag(qcompile, QlfMode),
 2021        \+ '$in_system_dir'(PlFile)
 2022    ),
 2023    (   QlfMode == auto
 2024    ->  true
 2025    ;   QlfMode == large,
 2026        size_file(PlFile, Size),
 2027        Size > 100000
 2028    ),
 2029    access_file(QlfFile, write).
 2030
 2031'$in_system_dir'(PlFile) :-
 2032    current_prolog_flag(home, Home),
 2033    sub_atom(PlFile, 0, _, _, Home).
 2034
 2035'$spec_extension'(File, Ext) :-
 2036    atom(File),
 2037    file_name_extension(_, Ext, File).
 2038'$spec_extension'(Spec, Ext) :-
 2039    compound(Spec),
 2040    arg(1, Spec, Arg),
 2041    '$spec_extension'(Arg, Ext).
 $load_file(+Spec, +ContextModule, +Options) is det
Load the file Spec into ContextModule controlled by Options. This wrapper deals with two cases before proceeding to the real loader:
 2053:- dynamic
 2054    '$resolved_source_path'/2.                  % ?Spec, ?Path
 2055
 2056'$load_file'(File, Module, Options) :-
 2057    \+ memberchk(stream(_), Options),
 2058    user:prolog_load_file(Module:File, Options),
 2059    !.
 2060'$load_file'(File, Module, Options) :-
 2061    memberchk(stream(_), Options),
 2062    !,
 2063    '$assert_load_context_module'(File, Module, Options),
 2064    '$qdo_load_file'(File, File, Module, Action, Options),
 2065    '$run_initialization'(File, Action, Options).
 2066'$load_file'(File, Module, Options) :-
 2067    '$resolved_source_path'(File, FullFile),
 2068    (   '$source_file_property'(FullFile, from_state, true)
 2069    ;   '$source_file_property'(FullFile, resource, true)
 2070    ;   '$option'(if(If), Options, true),
 2071        '$noload'(If, FullFile, Options)
 2072    ),
 2073    !,
 2074    '$already_loaded'(File, FullFile, Module, Options).
 2075'$load_file'(File, Module, Options) :-
 2076    absolute_file_name(File, FullFile,
 2077                       [ file_type(prolog),
 2078                         access(read)
 2079                       ]),
 2080    '$register_resolved_source_path'(File, FullFile),
 2081    '$mt_load_file'(File, FullFile, Module, Options),
 2082    '$register_resource_file'(FullFile).
 2083
 2084'$register_resolved_source_path'(File, FullFile) :-
 2085    '$resolved_source_path'(File, FullFile),
 2086    !.
 2087'$register_resolved_source_path'(File, FullFile) :-
 2088    compound(File),
 2089    !,
 2090    asserta('$resolved_source_path'(File, FullFile)).
 2091'$register_resolved_source_path'(_, _).
 $translated_source(+Old, +New) is det
Called from loading a QLF state when source files are being renamed.
 2097:- public '$translated_source'/2. 2098'$translated_source'(Old, New) :-
 2099    forall(retract('$resolved_source_path'(File, Old)),
 2100           assertz('$resolved_source_path'(File, New))).
 $register_resource_file(+FullFile) is det
If we load a file from a resource we lock it, so we never have to check the modification again.
 2107'$register_resource_file'(FullFile) :-
 2108    (   sub_atom(FullFile, 0, _, _, 'res://')
 2109    ->  '$set_source_file'(FullFile, resource, true)
 2110    ;   true
 2111    ).
 $already_loaded(+File, +FullFile, +Module, +Options) is det
Called if File is already loaded. If this is a module-file, the module must be imported into the context Module. If it is not a module file, it must be reloaded.
bug
- A file may be associated with multiple modules. How do we find the `main export module'? Currently there is no good way to find out which module is associated to the file as a result of the first :- module/2 term.
 2124'$already_loaded'(_File, FullFile, Module, Options) :-
 2125    '$assert_load_context_module'(FullFile, Module, Options),
 2126    '$current_module'(LoadModules, FullFile),
 2127    !,
 2128    (   atom(LoadModules)
 2129    ->  LoadModule = LoadModules
 2130    ;   LoadModules = [LoadModule|_]
 2131    ),
 2132    '$import_from_loaded_module'(LoadModule, Module, Options).
 2133'$already_loaded'(_, _, user, _) :- !.
 2134'$already_loaded'(File, _, Module, Options) :-
 2135    '$load_file'(File, Module, [if(true)|Options]).
 $mt_load_file(+File, +FullFile, +Module, +Options) is det
Deal with multi-threaded loading of files. The thread that wishes to load the thread first will do so, while other threads will wait until the leader finished and than act as if the file is already loaded.

Synchronisation is handled using a message queue that exists while the file is being loaded. This synchronisation relies on the fact that thread_get_message/1 throws an existence_error if the message queue is destroyed. This is hacky. Events or condition variables would have made a cleaner design.

 2150:- dynamic
 2151    '$loading_file'/3.              % File, Queue, Thread
 2152:- volatile
 2153    '$loading_file'/3. 2154
 2155'$mt_load_file'(File, FullFile, Module, Options) :-
 2156    current_prolog_flag(threads, true),
 2157    !,
 2158    setup_call_cleanup(
 2159        with_mutex('$load_file',
 2160                   '$mt_start_load'(FullFile, Loading, Options)),
 2161        '$mt_do_load'(Loading, File, FullFile, Module, Options),
 2162        '$mt_end_load'(Loading)).
 2163'$mt_load_file'(File, FullFile, Module, Options) :-
 2164    '$option'(if(If), Options, true),
 2165    '$noload'(If, FullFile, Options),
 2166    !,
 2167    '$already_loaded'(File, FullFile, Module, Options).
 2168'$mt_load_file'(File, FullFile, Module, Options) :-
 2169    '$qdo_load_file'(File, FullFile, Module, Action, Options),
 2170    '$run_initialization'(FullFile, Action, Options).
 2171
 2172'$mt_start_load'(FullFile, queue(Queue), _) :-
 2173    '$loading_file'(FullFile, Queue, LoadThread),
 2174    \+ thread_self(LoadThread),
 2175    !.
 2176'$mt_start_load'(FullFile, already_loaded, Options) :-
 2177    '$option'(if(If), Options, true),
 2178    '$noload'(If, FullFile, Options),
 2179    !.
 2180'$mt_start_load'(FullFile, Ref, _) :-
 2181    thread_self(Me),
 2182    message_queue_create(Queue),
 2183    assertz('$loading_file'(FullFile, Queue, Me), Ref).
 2184
 2185'$mt_do_load'(queue(Queue), File, FullFile, Module, Options) :-
 2186    !,
 2187    catch(thread_get_message(Queue, _), error(_,_), true),
 2188    '$already_loaded'(File, FullFile, Module, Options).
 2189'$mt_do_load'(already_loaded, File, FullFile, Module, Options) :-
 2190    !,
 2191    '$already_loaded'(File, FullFile, Module, Options).
 2192'$mt_do_load'(_Ref, File, FullFile, Module, Options) :-
 2193    '$assert_load_context_module'(FullFile, Module, Options),
 2194    '$qdo_load_file'(File, FullFile, Module, Action, Options),
 2195    '$run_initialization'(FullFile, Action, Options).
 2196
 2197'$mt_end_load'(queue(_)) :- !.
 2198'$mt_end_load'(already_loaded) :- !.
 2199'$mt_end_load'(Ref) :-
 2200    clause('$loading_file'(_, Queue, _), _, Ref),
 2201    erase(Ref),
 2202    thread_send_message(Queue, done),
 2203    message_queue_destroy(Queue).
 $qdo_load_file(+Spec, +FullFile, +ContextModule, +Options) is det
Switch to qcompile mode if requested by the option '$qlf'(+Out)
 2210'$qdo_load_file'(File, FullFile, Module, Action, Options) :-
 2211    memberchk('$qlf'(QlfOut), Options),
 2212    '$stage_file'(QlfOut, StageQlf),
 2213    !,
 2214    setup_call_catcher_cleanup(
 2215        '$qstart'(StageQlf, Module, State),
 2216        '$do_load_file'(File, FullFile, Module, Action, Options),
 2217        Catcher,
 2218        '$qend'(State, Catcher, StageQlf, QlfOut)).
 2219'$qdo_load_file'(File, FullFile, Module, Action, Options) :-
 2220    '$do_load_file'(File, FullFile, Module, Action, Options).
 2221
 2222'$qstart'(Qlf, Module, state(OldMode, OldModule)) :-
 2223    '$qlf_open'(Qlf),
 2224    '$compilation_mode'(OldMode, qlf),
 2225    '$set_source_module'(OldModule, Module).
 2226
 2227'$qend'(state(OldMode, OldModule), Catcher, StageQlf, QlfOut) :-
 2228    '$set_source_module'(_, OldModule),
 2229    '$set_compilation_mode'(OldMode),
 2230    '$qlf_close',
 2231    '$install_staged_file'(Catcher, StageQlf, QlfOut, warn).
 2232
 2233'$set_source_module'(OldModule, Module) :-
 2234    '$current_source_module'(OldModule),
 2235    '$set_source_module'(Module).
 $do_load_file(+Spec, +FullFile, +ContextModule, -Action, +Options) is det
Perform the actual loading.
 2242'$do_load_file'(File, FullFile, Module, Action, Options) :-
 2243    '$option'(derived_from(DerivedFrom), Options, -),
 2244    '$register_derived_source'(FullFile, DerivedFrom),
 2245    '$qlf_file'(File, FullFile, Absolute, Mode, Options),
 2246    (   Mode == qcompile
 2247    ->  qcompile(Module:File, Options)
 2248    ;   '$do_load_file_2'(File, Absolute, Module, Action, Options)
 2249    ).
 2250
 2251'$do_load_file_2'(File, Absolute, Module, Action, Options) :-
 2252    '$source_file_property'(Absolute, number_of_clauses, OldClauses),
 2253    statistics(cputime, OldTime),
 2254
 2255    '$setup_load'(ScopedFlags, OldSandBoxed, OldVerbose, OldAutoLevel, OldXRef,
 2256                  Options),
 2257
 2258    '$compilation_level'(Level),
 2259    '$load_msg_level'(load_file, Level, StartMsgLevel, DoneMsgLevel),
 2260    '$print_message'(StartMsgLevel,
 2261                     load_file(start(Level,
 2262                                     file(File, Absolute)))),
 2263
 2264    (   memberchk(stream(FromStream), Options)
 2265    ->  Input = stream
 2266    ;   Input = source
 2267    ),
 2268
 2269    (   Input == stream,
 2270        (   '$option'(format(qlf), Options, source)
 2271        ->  set_stream(FromStream, file_name(Absolute)),
 2272            '$qload_stream'(FromStream, Module, Action, LM, Options)
 2273        ;   '$consult_file'(stream(Absolute, FromStream, []),
 2274                            Module, Action, LM, Options)
 2275        )
 2276    ->  true
 2277    ;   Input == source,
 2278        file_name_extension(_, Ext, Absolute),
 2279        (   user:prolog_file_type(Ext, qlf),
 2280            E = error(_,_),
 2281            catch('$qload_file'(Absolute, Module, Action, LM, Options),
 2282                  E,
 2283                  print_message(warning, E))
 2284        ->  true
 2285        ;   '$consult_file'(Absolute, Module, Action, LM, Options)
 2286        )
 2287    ->  true
 2288    ;   '$print_message'(error, load_file(failed(File))),
 2289        fail
 2290    ),
 2291
 2292    '$import_from_loaded_module'(LM, Module, Options),
 2293
 2294    '$source_file_property'(Absolute, number_of_clauses, NewClauses),
 2295    statistics(cputime, Time),
 2296    ClausesCreated is NewClauses - OldClauses,
 2297    TimeUsed is Time - OldTime,
 2298
 2299    '$print_message'(DoneMsgLevel,
 2300                     load_file(done(Level,
 2301                                    file(File, Absolute),
 2302                                    Action,
 2303                                    LM,
 2304                                    TimeUsed,
 2305                                    ClausesCreated))),
 2306
 2307    '$restore_load'(ScopedFlags, OldSandBoxed, OldVerbose, OldAutoLevel, OldXRef).
 2308
 2309'$setup_load'(ScopedFlags, OldSandBoxed, OldVerbose, OldAutoLevel, OldXRef,
 2310              Options) :-
 2311    '$save_file_scoped_flags'(ScopedFlags),
 2312    '$set_sandboxed_load'(Options, OldSandBoxed),
 2313    '$set_verbose_load'(Options, OldVerbose),
 2314    '$set_optimise_load'(Options),
 2315    '$update_autoload_level'(Options, OldAutoLevel),
 2316    '$set_no_xref'(OldXRef).
 2317
 2318'$restore_load'(ScopedFlags, OldSandBoxed, OldVerbose, OldAutoLevel, OldXRef) :-
 2319    '$set_autoload_level'(OldAutoLevel),
 2320    set_prolog_flag(xref, OldXRef),
 2321    set_prolog_flag(verbose_load, OldVerbose),
 2322    set_prolog_flag(sandboxed_load, OldSandBoxed),
 2323    '$restore_file_scoped_flags'(ScopedFlags).
 $save_file_scoped_flags(-State) is det
 $restore_file_scoped_flags(-State) is det
Save/restore flags that are scoped to a compilation unit.
 2331'$save_file_scoped_flags'(State) :-
 2332    current_predicate(findall/3),          % Not when doing boot compile
 2333    !,
 2334    findall(SavedFlag, '$save_file_scoped_flag'(SavedFlag), State).
 2335'$save_file_scoped_flags'([]).
 2336
 2337'$save_file_scoped_flag'(Flag-Value) :-
 2338    '$file_scoped_flag'(Flag, Default),
 2339    (   current_prolog_flag(Flag, Value)
 2340    ->  true
 2341    ;   Value = Default
 2342    ).
 2343
 2344'$file_scoped_flag'(generate_debug_info, true).
 2345'$file_scoped_flag'(optimise,            false).
 2346'$file_scoped_flag'(xref,                false).
 2347
 2348'$restore_file_scoped_flags'([]).
 2349'$restore_file_scoped_flags'([Flag-Value|T]) :-
 2350    set_prolog_flag(Flag, Value),
 2351    '$restore_file_scoped_flags'(T).
 $import_from_loaded_module(LoadedModule, Module, Options) is det
Import public predicates from LoadedModule into Module
 2358'$import_from_loaded_module'(LoadedModule, Module, Options) :-
 2359    LoadedModule \== Module,
 2360    atom(LoadedModule),
 2361    !,
 2362    '$option'(imports(Import), Options, all),
 2363    '$option'(reexport(Reexport), Options, false),
 2364    '$import_list'(Module, LoadedModule, Import, Reexport).
 2365'$import_from_loaded_module'(_, _, _).
 $set_verbose_load(+Options, -Old) is det
Set the verbose_load flag according to Options and unify Old with the old value.
 2373'$set_verbose_load'(Options, Old) :-
 2374    current_prolog_flag(verbose_load, Old),
 2375    (   memberchk(silent(Silent), Options)
 2376    ->  (   '$negate'(Silent, Level0)
 2377        ->  '$load_msg_compat'(Level0, Level)
 2378        ;   Level = Silent
 2379        ),
 2380        set_prolog_flag(verbose_load, Level)
 2381    ;   true
 2382    ).
 2383
 2384'$negate'(true, false).
 2385'$negate'(false, true).
 $set_sandboxed_load(+Options, -Old) is det
Update the Prolog flag sandboxed_load from Options. Old is unified with the old flag.
Errors
- permission_error(leave, sandbox, -)
 2394'$set_sandboxed_load'(Options, Old) :-
 2395    current_prolog_flag(sandboxed_load, Old),
 2396    (   memberchk(sandboxed(SandBoxed), Options),
 2397        '$enter_sandboxed'(Old, SandBoxed, New),
 2398        New \== Old
 2399    ->  set_prolog_flag(sandboxed_load, New)
 2400    ;   true
 2401    ).
 2402
 2403'$enter_sandboxed'(Old, New, SandBoxed) :-
 2404    (   Old == false, New == true
 2405    ->  SandBoxed = true,
 2406        '$ensure_loaded_library_sandbox'
 2407    ;   Old == true, New == false
 2408    ->  throw(error(permission_error(leave, sandbox, -), _))
 2409    ;   SandBoxed = Old
 2410    ).
 2411'$enter_sandboxed'(false, true, true).
 2412
 2413'$ensure_loaded_library_sandbox' :-
 2414    source_file_property(library(sandbox), module(sandbox)),
 2415    !.
 2416'$ensure_loaded_library_sandbox' :-
 2417    load_files(library(sandbox), [if(not_loaded), silent(true)]).
 2418
 2419'$set_optimise_load'(Options) :-
 2420    (   '$option'(optimise(Optimise), Options)
 2421    ->  set_prolog_flag(optimise, Optimise)
 2422    ;   true
 2423    ).
 2424
 2425'$set_no_xref'(OldXRef) :-
 2426    (   current_prolog_flag(xref, OldXRef)
 2427    ->  true
 2428    ;   OldXRef = false
 2429    ),
 2430    set_prolog_flag(xref, false).
 $update_autoload_level(+Options, -OldLevel)
Update the '$autoload_nesting' and return the old value.
 2437:- thread_local
 2438    '$autoload_nesting'/1. 2439
 2440'$update_autoload_level'(Options, AutoLevel) :-
 2441    '$option'(autoload(Autoload), Options, false),
 2442    (   '$autoload_nesting'(CurrentLevel)
 2443    ->  AutoLevel = CurrentLevel
 2444    ;   AutoLevel = 0
 2445    ),
 2446    (   Autoload == false
 2447    ->  true
 2448    ;   NewLevel is AutoLevel + 1,
 2449        '$set_autoload_level'(NewLevel)
 2450    ).
 2451
 2452'$set_autoload_level'(New) :-
 2453    retractall('$autoload_nesting'(_)),
 2454    asserta('$autoload_nesting'(New)).
 $print_message(+Level, +Term) is det
As print_message/2, but deal with the fact that the message system might not yet be loaded.
 2462'$print_message'(Level, Term) :-
 2463    current_predicate(system:print_message/2),
 2464    !,
 2465    print_message(Level, Term).
 2466'$print_message'(warning, Term) :-
 2467    source_location(File, Line),
 2468    !,
 2469    format(user_error, 'WARNING: ~w:~w: ~p~n', [File, Line, Term]).
 2470'$print_message'(error, Term) :-
 2471    !,
 2472    source_location(File, Line),
 2473    !,
 2474    format(user_error, 'ERROR: ~w:~w: ~p~n', [File, Line, Term]).
 2475'$print_message'(_Level, _Term).
 2476
 2477'$print_message_fail'(E) :-
 2478    '$print_message'(error, E),
 2479    fail.
 $consult_file(+Path, +Module, -Action, -LoadedIn, +Options)
Called from '$do_load_file'/4 using the goal returned by '$consult_goal'/2. This means that the calling conventions must be kept synchronous with '$qload_file'/6.
 2487'$consult_file'(Absolute, Module, What, LM, Options) :-
 2488    '$current_source_module'(Module),   % same module
 2489    !,
 2490    '$consult_file_2'(Absolute, Module, What, LM, Options).
 2491'$consult_file'(Absolute, Module, What, LM, Options) :-
 2492    '$set_source_module'(OldModule, Module),
 2493    '$ifcompiling'('$qlf_start_sub_module'(Module)),
 2494    '$consult_file_2'(Absolute, Module, What, LM, Options),
 2495    '$ifcompiling'('$qlf_end_part'),
 2496    '$set_source_module'(OldModule).
 2497
 2498'$consult_file_2'(Absolute, Module, What, LM, Options) :-
 2499    '$set_source_module'(OldModule, Module),
 2500    '$load_id'(Absolute, Id, Modified, Options),
 2501    '$start_consult'(Id, Modified),
 2502    (   '$derived_source'(Absolute, DerivedFrom, _)
 2503    ->  '$modified_id'(DerivedFrom, DerivedModified, Options),
 2504        '$start_consult'(DerivedFrom, DerivedModified)
 2505    ;   true
 2506    ),
 2507    '$compile_type'(What),
 2508    '$save_lex_state'(LexState, Options),
 2509    '$set_dialect'(Options),
 2510    call_cleanup('$load_file'(Absolute, Id, LM, Options),
 2511                 '$end_consult'(LexState, OldModule)).
 2512
 2513'$end_consult'(LexState, OldModule) :-
 2514    '$restore_lex_state'(LexState),
 2515    '$set_source_module'(OldModule).
 2516
 2517
 2518:- create_prolog_flag(emulated_dialect, swi, [type(atom)]).
 $save_lex_state(-LexState, +Options) is det
 2522'$save_lex_state'(State, Options) :-
 2523    memberchk(scope_settings(false), Options),
 2524    !,
 2525    State = (-).
 2526'$save_lex_state'(lexstate(Style, Dialect), _) :-
 2527    '$style_check'(Style, Style),
 2528    current_prolog_flag(emulated_dialect, Dialect).
 2529
 2530'$restore_lex_state'(-) :- !.
 2531'$restore_lex_state'(lexstate(Style, Dialect)) :-
 2532    '$style_check'(_, Style),
 2533    set_prolog_flag(emulated_dialect, Dialect).
 2534
 2535'$set_dialect'(Options) :-
 2536    memberchk(dialect(Dialect), Options),
 2537    !,
 2538    expects_dialect(Dialect).               % Autoloaded from library
 2539'$set_dialect'(_).
 2540
 2541'$load_id'(stream(Id, _, _), Id, Modified, Options) :-
 2542    !,
 2543    '$modified_id'(Id, Modified, Options).
 2544'$load_id'(Id, Id, Modified, Options) :-
 2545    '$modified_id'(Id, Modified, Options).
 2546
 2547'$modified_id'(_, Modified, Options) :-
 2548    '$option'(modified(Stamp), Options, Def),
 2549    Stamp \== Def,
 2550    !,
 2551    Modified = Stamp.
 2552'$modified_id'(Id, Modified, _) :-
 2553    catch(time_file(Id, Modified),
 2554          error(_, _),
 2555          fail),
 2556    !.
 2557'$modified_id'(_, 0.0, _).
 2558
 2559
 2560'$compile_type'(What) :-
 2561    '$compilation_mode'(How),
 2562    (   How == database
 2563    ->  What = compiled
 2564    ;   How == qlf
 2565    ->  What = '*qcompiled*'
 2566    ;   What = 'boot compiled'
 2567    ).
 $assert_load_context_module(+File, -Module, -Options)
Record the module a file was loaded from (see make/0). The first clause deals with loading from another file. On reload, this clause will be discarded by $start_consult/1. The second clause deals with reload from the toplevel. Here we avoid creating a duplicate dynamic (i.e., not related to a source) clause.
 2577:- dynamic
 2578    '$load_context_module'/3. 2579:- multifile
 2580    '$load_context_module'/3. 2581
 2582'$assert_load_context_module'(_, _, Options) :-
 2583    memberchk(register(false), Options),
 2584    !.
 2585'$assert_load_context_module'(File, Module, Options) :-
 2586    source_location(FromFile, Line),
 2587    !,
 2588    '$master_file'(FromFile, MasterFile),
 2589    '$check_load_non_module'(File, Module),
 2590    '$add_dialect'(Options, Options1),
 2591    '$load_ctx_options'(Options1, Options2),
 2592    '$store_admin_clause'(
 2593        system:'$load_context_module'(File, Module, Options2),
 2594        _Layout, MasterFile, FromFile:Line).
 2595'$assert_load_context_module'(File, Module, Options) :-
 2596    '$check_load_non_module'(File, Module),
 2597    '$add_dialect'(Options, Options1),
 2598    '$load_ctx_options'(Options1, Options2),
 2599    (   clause('$load_context_module'(File, Module, _), true, Ref),
 2600        \+ clause_property(Ref, file(_)),
 2601        erase(Ref)
 2602    ->  true
 2603    ;   true
 2604    ),
 2605    assertz('$load_context_module'(File, Module, Options2)).
 2606
 2607'$add_dialect'(Options0, Options) :-
 2608    current_prolog_flag(emulated_dialect, Dialect), Dialect \== swi,
 2609    !,
 2610    Options = [dialect(Dialect)|Options0].
 2611'$add_dialect'(Options, Options).
 $load_ctx_options(+Options, -CtxOptions) is det
Select the load options that determine the load semantics to perform a proper reload. Delete the others.
 2618'$load_ctx_options'([], []).
 2619'$load_ctx_options'([H|T0], [H|T]) :-
 2620    '$load_ctx_option'(H),
 2621    !,
 2622    '$load_ctx_options'(T0, T).
 2623'$load_ctx_options'([_|T0], T) :-
 2624    '$load_ctx_options'(T0, T).
 2625
 2626'$load_ctx_option'(derived_from(_)).
 2627'$load_ctx_option'(dialect(_)).
 2628'$load_ctx_option'(encoding(_)).
 2629'$load_ctx_option'(imports(_)).
 2630'$load_ctx_option'(reexport(_)).
 $check_load_non_module(+File) is det
Test that a non-module file is not loaded into multiple contexts.
 2638'$check_load_non_module'(File, _) :-
 2639    '$current_module'(_, File),
 2640    !.          % File is a module file
 2641'$check_load_non_module'(File, Module) :-
 2642    '$load_context_module'(File, OldModule, _),
 2643    Module \== OldModule,
 2644    !,
 2645    format(atom(Msg),
 2646           'Non-module file already loaded into module ~w; \c
 2647               trying to load into ~w',
 2648           [OldModule, Module]),
 2649    throw(error(permission_error(load, source, File),
 2650                context(load_files/2, Msg))).
 2651'$check_load_non_module'(_, _).
 $load_file(+Path, +Id, -Module, +Options)
'$load_file'/4 does the actual loading.
state(FirstTerm:boolean, Module:atom, AtEnd:atom, Stop:boolean, Id:atom, Dialect:atom)
 2664'$load_file'(Path, Id, Module, Options) :-
 2665    State = state(true, _, true, false, Id, -),
 2666    (   '$source_term'(Path, _Read, _Layout, Term, Layout,
 2667                       _Stream, Options),
 2668        '$valid_term'(Term),
 2669        (   arg(1, State, true)
 2670        ->  '$first_term'(Term, Layout, Id, State, Options),
 2671            nb_setarg(1, State, false)
 2672        ;   '$compile_term'(Term, Layout, Id)
 2673        ),
 2674        arg(4, State, true)
 2675    ;   '$end_load_file'(State)
 2676    ),
 2677    !,
 2678    arg(2, State, Module).
 2679
 2680'$valid_term'(Var) :-
 2681    var(Var),
 2682    !,
 2683    print_message(error, error(instantiation_error, _)).
 2684'$valid_term'(Term) :-
 2685    Term \== [].
 2686
 2687'$end_load_file'(State) :-
 2688    arg(1, State, true),           % empty file
 2689    !,
 2690    nb_setarg(2, State, Module),
 2691    arg(5, State, Id),
 2692    '$current_source_module'(Module),
 2693    '$ifcompiling'('$qlf_start_file'(Id)),
 2694    '$ifcompiling'('$qlf_end_part').
 2695'$end_load_file'(State) :-
 2696    arg(3, State, End),
 2697    '$end_load_file'(End, State).
 2698
 2699'$end_load_file'(true, _).
 2700'$end_load_file'(end_module, State) :-
 2701    arg(2, State, Module),
 2702    '$check_export'(Module),
 2703    '$ifcompiling'('$qlf_end_part').
 2704'$end_load_file'(end_non_module, _State) :-
 2705    '$ifcompiling'('$qlf_end_part').
 2706
 2707
 2708'$first_term'(?-(Directive), Layout, Id, State, Options) :-
 2709    !,
 2710    '$first_term'(:-(Directive), Layout, Id, State, Options).
 2711'$first_term'(:-(Directive), _Layout, Id, State, Options) :-
 2712    nonvar(Directive),
 2713    (   (   Directive = module(Name, Public)
 2714        ->  Imports = []
 2715        ;   Directive = module(Name, Public, Imports)
 2716        )
 2717    ->  !,
 2718        '$module_name'(Name, Id, Module, Options),
 2719        '$start_module'(Module, Public, State, Options),
 2720        '$module3'(Imports)
 2721    ;   Directive = expects_dialect(Dialect)
 2722    ->  !,
 2723        '$set_dialect'(Dialect, State),
 2724        fail                        % Still consider next term as first
 2725    ).
 2726'$first_term'(Term, Layout, Id, State, Options) :-
 2727    '$start_non_module'(Id, State, Options),
 2728    '$compile_term'(Term, Layout, Id).
 2729
 2730'$compile_term'(Term, Layout, Id) :-
 2731    '$compile_term'(Term, Layout, Id, -).
 2732
 2733'$compile_term'(Var, _Layout, _Id, _Src) :-
 2734    var(Var),
 2735    !,
 2736    '$instantiation_error'(Var).
 2737'$compile_term'((?-Directive), _Layout, Id, _) :-
 2738    !,
 2739    '$execute_directive'(Directive, Id).
 2740'$compile_term'((:-Directive), _Layout, Id, _) :-
 2741    !,
 2742    '$execute_directive'(Directive, Id).
 2743'$compile_term'('$source_location'(File, Line):Term, Layout, Id, _) :-
 2744    !,
 2745    '$compile_term'(Term, Layout, Id, File:Line).
 2746'$compile_term'(Clause, Layout, Id, SrcLoc) :-
 2747    E = error(_,_),
 2748    catch('$store_clause'(Clause, Layout, Id, SrcLoc), E,
 2749          '$print_message'(error, E)).
 2750
 2751'$start_non_module'(Id, _State, Options) :-
 2752    '$option'(must_be_module(true), Options, false),
 2753    !,
 2754    throw(error(domain_error(module_file, Id), _)).
 2755'$start_non_module'(Id, State, _Options) :-
 2756    '$current_source_module'(Module),
 2757    '$ifcompiling'('$qlf_start_file'(Id)),
 2758    '$qset_dialect'(State),
 2759    nb_setarg(2, State, Module),
 2760    nb_setarg(3, State, end_non_module).
 $set_dialect(+Dialect, +State)
Sets the expected dialect. This is difficult if we are compiling a .qlf file using qcompile/1 because the file is already open, while we are looking for the first term to decide wether this is a module or not. We save the dialect and set it after opening the file or module.

Note that expects_dialect/1 itself may be autoloaded from the library.

 2773'$set_dialect'(Dialect, State) :-
 2774    '$compilation_mode'(qlf, database),
 2775    !,
 2776    expects_dialect(Dialect),
 2777    '$compilation_mode'(_, qlf),
 2778    nb_setarg(6, State, Dialect).
 2779'$set_dialect'(Dialect, _) :-
 2780    expects_dialect(Dialect).
 2781
 2782'$qset_dialect'(State) :-
 2783    '$compilation_mode'(qlf),
 2784    arg(6, State, Dialect), Dialect \== (-),
 2785    !,
 2786    '$add_directive_wic'(expects_dialect(Dialect)).
 2787'$qset_dialect'(_).
 2788
 2789
 2790                 /*******************************
 2791                 *           MODULES            *
 2792                 *******************************/
 2793
 2794'$start_module'(Module, _Public, State, _Options) :-
 2795    '$current_module'(Module, OldFile),
 2796    source_location(File, _Line),
 2797    OldFile \== File, OldFile \== [],
 2798    same_file(OldFile, File),
 2799    !,
 2800    nb_setarg(2, State, Module),
 2801    nb_setarg(4, State, true).      % Stop processing
 2802'$start_module'(Module, Public, State, Options) :-
 2803    arg(5, State, File),
 2804    nb_setarg(2, State, Module),
 2805    source_location(_File, Line),
 2806    '$option'(redefine_module(Action), Options, false),
 2807    '$module_class'(File, Class, Super),
 2808    '$redefine_module'(Module, File, Action),
 2809    '$declare_module'(Module, Class, Super, File, Line, false),
 2810    '$export_list'(Public, Module, Ops),
 2811    '$ifcompiling'('$qlf_start_module'(Module)),
 2812    '$export_ops'(Ops, Module, File),
 2813    '$qset_dialect'(State),
 2814    nb_setarg(3, State, end_module).
 $module3(+Spec) is det
Handle the 3th argument of a module declartion.
 2821'$module3'(Var) :-
 2822    var(Var),
 2823    !,
 2824    '$instantiation_error'(Var).
 2825'$module3'([]) :- !.
 2826'$module3'([H|T]) :-
 2827    !,
 2828    '$module3'(H),
 2829    '$module3'(T).
 2830'$module3'(Id) :-
 2831    use_module(library(dialect/Id)).
 $module_name(?Name, +Id, -Module, +Options) is semidet
Determine the module name. There are some cases:
 2845'$module_name'(_, _, Module, Options) :-
 2846    '$option'(module(Module), Options),
 2847    !,
 2848    '$current_source_module'(Context),
 2849    Context \== Module.                     % cause '$first_term'/5 to fail.
 2850'$module_name'(Var, Id, Module, Options) :-
 2851    var(Var),
 2852    !,
 2853    file_base_name(Id, File),
 2854    file_name_extension(Var, _, File),
 2855    '$module_name'(Var, Id, Module, Options).
 2856'$module_name'(Reserved, _, _, _) :-
 2857    '$reserved_module'(Reserved),
 2858    !,
 2859    throw(error(permission_error(load, module, Reserved), _)).
 2860'$module_name'(Module, _Id, Module, _).
 2861
 2862
 2863'$reserved_module'(system).
 2864'$reserved_module'(user).
 $redefine_module(+Module, +File, -Redefine)
 2869'$redefine_module'(_Module, _, false) :- !.
 2870'$redefine_module'(Module, File, true) :-
 2871    !,
 2872    (   module_property(Module, file(OldFile)),
 2873        File \== OldFile
 2874    ->  unload_file(OldFile)
 2875    ;   true
 2876    ).
 2877'$redefine_module'(Module, File, ask) :-
 2878    (   stream_property(user_input, tty(true)),
 2879        module_property(Module, file(OldFile)),
 2880        File \== OldFile,
 2881        '$rdef_response'(Module, OldFile, File, true)
 2882    ->  '$redefine_module'(Module, File, true)
 2883    ;   true
 2884    ).
 2885
 2886'$rdef_response'(Module, OldFile, File, Ok) :-
 2887    repeat,
 2888    print_message(query, redefine_module(Module, OldFile, File)),
 2889    get_single_char(Char),
 2890    '$rdef_response'(Char, Ok0),
 2891    !,
 2892    Ok = Ok0.
 2893
 2894'$rdef_response'(Char, true) :-
 2895    memberchk(Char, `yY`),
 2896    format(user_error, 'yes~n', []).
 2897'$rdef_response'(Char, false) :-
 2898    memberchk(Char, `nN`),
 2899    format(user_error, 'no~n', []).
 2900'$rdef_response'(Char, _) :-
 2901    memberchk(Char, `a`),
 2902    format(user_error, 'abort~n', []),
 2903    abort.
 2904'$rdef_response'(_, _) :-
 2905    print_message(help, redefine_module_reply),
 2906    fail.
 $module_class(+File, -Class, -Super) is det
Determine the initial module from which I inherit. All system and library modules inherit from system, while all normal user modules inherit from user.
 2915'$module_class'(File, Class, system) :-
 2916    current_prolog_flag(home, Home),
 2917    sub_atom(File, 0, Len, _, Home),
 2918    !,
 2919    (   sub_atom(File, Len, _, _, '/boot/')
 2920    ->  Class = system
 2921    ;   Class = library
 2922    ).
 2923'$module_class'(_, user, user).
 2924
 2925'$check_export'(Module) :-
 2926    '$undefined_export'(Module, UndefList),
 2927    (   '$member'(Undef, UndefList),
 2928        strip_module(Undef, _, Local),
 2929        print_message(error,
 2930                      undefined_export(Module, Local)),
 2931        fail
 2932    ;   true
 2933    ).
 $import_list(+TargetModule, +FromModule, +Import, +Reexport) is det
Import from FromModule to TargetModule. Import is one of all, a list of optionally mapped predicate indicators or a term except(Import).
 2942'$import_list'(_, _, Var, _) :-
 2943    var(Var),
 2944    !,
 2945    throw(error(instantitation_error, _)).
 2946'$import_list'(Target, Source, all, Reexport) :-
 2947    !,
 2948    '$exported_ops'(Source, Import, Predicates),
 2949    '$module_property'(Source, exports(Predicates)),
 2950    '$import_all'(Import, Target, Source, Reexport, weak).
 2951'$import_list'(Target, Source, except(Spec), Reexport) :-
 2952    !,
 2953    '$exported_ops'(Source, Export, Predicates),
 2954    '$module_property'(Source, exports(Predicates)),
 2955    (   is_list(Spec)
 2956    ->  true
 2957    ;   throw(error(type_error(list, Spec), _))
 2958    ),
 2959    '$import_except'(Spec, Export, Import),
 2960    '$import_all'(Import, Target, Source, Reexport, weak).
 2961'$import_list'(Target, Source, Import, Reexport) :-
 2962    !,
 2963    is_list(Import),
 2964    !,
 2965    '$import_all'(Import, Target, Source, Reexport, strong).
 2966'$import_list'(_, _, Import, _) :-
 2967    throw(error(type_error(import_specifier, Import))).
 2968
 2969
 2970'$import_except'([], List, List).
 2971'$import_except'([H|T], List0, List) :-
 2972    '$import_except_1'(H, List0, List1),
 2973    '$import_except'(T, List1, List).
 2974
 2975'$import_except_1'(Var, _, _) :-
 2976    var(Var),
 2977    !,
 2978    throw(error(instantitation_error, _)).
 2979'$import_except_1'(PI as N, List0, List) :-
 2980    '$pi'(PI), atom(N),
 2981    !,
 2982    '$canonical_pi'(PI, CPI),
 2983    '$import_as'(CPI, N, List0, List).
 2984'$import_except_1'(op(P,A,N), List0, List) :-
 2985    !,
 2986    '$remove_ops'(List0, op(P,A,N), List).
 2987'$import_except_1'(PI, List0, List) :-
 2988    '$pi'(PI),
 2989    !,
 2990    '$canonical_pi'(PI, CPI),
 2991    '$select'(P, List0, List),
 2992    '$canonical_pi'(CPI, P),
 2993    !.
 2994'$import_except_1'(Except, _, _) :-
 2995    throw(error(type_error(import_specifier, Except), _)).
 2996
 2997'$import_as'(CPI, N, [PI2|T], [CPI as N|T]) :-
 2998    '$canonical_pi'(PI2, CPI),
 2999    !.
 3000'$import_as'(PI, N, [H|T0], [H|T]) :-
 3001    !,
 3002    '$import_as'(PI, N, T0, T).
 3003'$import_as'(PI, _, _, _) :-
 3004    throw(error(existence_error(export, PI), _)).
 3005
 3006'$pi'(N/A) :- atom(N), integer(A), !.
 3007'$pi'(N//A) :- atom(N), integer(A).
 3008
 3009'$canonical_pi'(N//A0, N/A) :-
 3010    A is A0 + 2.
 3011'$canonical_pi'(PI, PI).
 3012
 3013'$remove_ops'([], _, []).
 3014'$remove_ops'([Op|T0], Pattern, T) :-
 3015    subsumes_term(Pattern, Op),
 3016    !,
 3017    '$remove_ops'(T0, Pattern, T).
 3018'$remove_ops'([H|T0], Pattern, [H|T]) :-
 3019    '$remove_ops'(T0, Pattern, T).
 $import_all(+Import, +Context, +Source, +Reexport, +Strength)
 3024'$import_all'(Import, Context, Source, Reexport, Strength) :-
 3025    '$import_all2'(Import, Context, Source, Imported, ImpOps, Strength),
 3026    (   Reexport == true,
 3027        (   '$list_to_conj'(Imported, Conj)
 3028        ->  export(Context:Conj),
 3029            '$ifcompiling'('$add_directive_wic'(export(Context:Conj)))
 3030        ;   true
 3031        ),
 3032        source_location(File, _Line),
 3033        '$export_ops'(ImpOps, Context, File)
 3034    ;   true
 3035    ).
 $import_all2(+Imports, +Context, +Source, -Imported, -ImpOps, +Strength)
 3039'$import_all2'([], _, _, [], [], _).
 3040'$import_all2'([PI as NewName|Rest], Context, Source,
 3041               [NewName/Arity|Imported], ImpOps, Strength) :-
 3042    !,
 3043    '$canonical_pi'(PI, Name/Arity),
 3044    length(Args, Arity),
 3045    Head =.. [Name|Args],
 3046    NewHead =.. [NewName|Args],
 3047    (   '$get_predicate_attribute'(Source:Head, transparent, 1)
 3048    ->  '$set_predicate_attribute'(Context:NewHead, transparent, true)
 3049    ;   true
 3050    ),
 3051    (   source_location(File, Line)
 3052    ->  E = error(_,_),
 3053        catch('$store_admin_clause'((NewHead :- Source:Head),
 3054                                    _Layout, File, File:Line),
 3055              E, '$print_message'(error, E))
 3056    ;   assertz((NewHead :- !, Source:Head)) % ! avoids problems with
 3057    ),                                       % duplicate load
 3058    '$import_all2'(Rest, Context, Source, Imported, ImpOps, Strength).
 3059'$import_all2'([op(P,A,N)|Rest], Context, Source, Imported,
 3060               [op(P,A,N)|ImpOps], Strength) :-
 3061    !,
 3062    '$import_ops'(Context, Source, op(P,A,N)),
 3063    '$import_all2'(Rest, Context, Source, Imported, ImpOps, Strength).
 3064'$import_all2'([Pred|Rest], Context, Source, [Pred|Imported], ImpOps, Strength) :-
 3065    Error = error(_,_),
 3066    catch(Context:'$import'(Source:Pred, Strength), Error,
 3067          print_message(error, Error)),
 3068    '$ifcompiling'('$import_wic'(Source, Pred, Strength)),
 3069    '$import_all2'(Rest, Context, Source, Imported, ImpOps, Strength).
 3070
 3071
 3072'$list_to_conj'([One], One) :- !.
 3073'$list_to_conj'([H|T], (H,Rest)) :-
 3074    '$list_to_conj'(T, Rest).
 $exported_ops(+Module, -Ops, ?Tail) is det
Ops is a list of op(P,A,N) terms representing the operators exported from Module.
 3081'$exported_ops'(Module, Ops, Tail) :-
 3082    '$c_current_predicate'(_, Module:'$exported_op'(_,_,_)),
 3083    !,
 3084    findall(op(P,A,N), Module:'$exported_op'(P,A,N), Ops, Tail).
 3085'$exported_ops'(_, Ops, Ops).
 3086
 3087'$exported_op'(Module, P, A, N) :-
 3088    '$c_current_predicate'(_, Module:'$exported_op'(_,_,_)),
 3089    Module:'$exported_op'(P, A, N).
 $import_ops(+Target, +Source, +Pattern)
Import the operators export from Source into the module table of Target. We only import operators that unify with Pattern.
 3096'$import_ops'(To, From, Pattern) :-
 3097    ground(Pattern),
 3098    !,
 3099    Pattern = op(P,A,N),
 3100    op(P,A,To:N),
 3101    (   '$exported_op'(From, P, A, N)
 3102    ->  true
 3103    ;   print_message(warning, no_exported_op(From, Pattern))
 3104    ).
 3105'$import_ops'(To, From, Pattern) :-
 3106    (   '$exported_op'(From, Pri, Assoc, Name),
 3107        Pattern = op(Pri, Assoc, Name),
 3108        op(Pri, Assoc, To:Name),
 3109        fail
 3110    ;   true
 3111    ).
 $export_list(+Declarations, +Module, -Ops)
Handle the export list of the module declaration for Module associated to File.
 3119'$export_list'(Decls, Module, Ops) :-
 3120    is_list(Decls),
 3121    !,
 3122    '$do_export_list'(Decls, Module, Ops).
 3123'$export_list'(Decls, _, _) :-
 3124    var(Decls),
 3125    throw(error(instantiation_error, _)).
 3126'$export_list'(Decls, _, _) :-
 3127    throw(error(type_error(list, Decls), _)).
 3128
 3129'$do_export_list'([], _, []) :- !.
 3130'$do_export_list'([H|T], Module, Ops) :-
 3131    !,
 3132    E = error(_,_),
 3133    catch('$export1'(H, Module, Ops, Ops1),
 3134          E, ('$print_message'(error, E), Ops = Ops1)),
 3135    '$do_export_list'(T, Module, Ops1).
 3136
 3137'$export1'(Var, _, _, _) :-
 3138    var(Var),
 3139    !,
 3140    throw(error(instantiation_error, _)).
 3141'$export1'(Op, _, [Op|T], T) :-
 3142    Op = op(_,_,_),
 3143    !.
 3144'$export1'(PI0, Module, Ops, Ops) :-
 3145    strip_module(Module:PI0, M, PI),
 3146    (   PI = (_//_)
 3147    ->  non_terminal(M:PI)
 3148    ;   true
 3149    ),
 3150    export(M:PI).
 3151
 3152'$export_ops'([op(Pri, Assoc, Name)|T], Module, File) :-
 3153    E = error(_,_),
 3154    catch(( '$execute_directive'(op(Pri, Assoc, Module:Name), File),
 3155            '$export_op'(Pri, Assoc, Name, Module, File)
 3156          ),
 3157          E, '$print_message'(error, E)),
 3158    '$export_ops'(T, Module, File).
 3159'$export_ops'([], _, _).
 3160
 3161'$export_op'(Pri, Assoc, Name, Module, File) :-
 3162    (   '$get_predicate_attribute'(Module:'$exported_op'(_,_,_), defined, 1)
 3163    ->  true
 3164    ;   '$execute_directive'(discontiguous(Module:'$exported_op'/3), File)
 3165    ),
 3166    '$store_admin_clause'('$exported_op'(Pri, Assoc, Name), _Layout, File, -).
 $execute_directive(:Goal, +File) is det
Execute the argument of :- or ?- while loading a file.
 3172'$execute_directive'(Goal, F) :-
 3173    '$execute_directive_2'(Goal, F).
 3174
 3175'$execute_directive_2'(encoding(Encoding), _F) :-
 3176    !,
 3177    (   '$load_input'(_F, S)
 3178    ->  set_stream(S, encoding(Encoding))
 3179    ).
 3180'$execute_directive_2'(ISO, F) :-
 3181    '$expand_directive'(ISO, Normal),
 3182    !,
 3183    '$execute_directive'(Normal, F).
 3184'$execute_directive_2'(Goal, _) :-
 3185    \+ '$compilation_mode'(database),
 3186    !,
 3187    '$add_directive_wic2'(Goal, Type),
 3188    (   Type == call                % suspend compiling into .qlf file
 3189    ->  '$compilation_mode'(Old, database),
 3190        setup_call_cleanup(
 3191            '$directive_mode'(OldDir, Old),
 3192            '$execute_directive_3'(Goal),
 3193            ( '$set_compilation_mode'(Old),
 3194              '$set_directive_mode'(OldDir)
 3195            ))
 3196    ;   '$execute_directive_3'(Goal)
 3197    ).
 3198'$execute_directive_2'(Goal, _) :-
 3199    '$execute_directive_3'(Goal).
 3200
 3201'$execute_directive_3'(Goal) :-
 3202    '$current_source_module'(Module),
 3203    '$valid_directive'(Module:Goal),
 3204    !,
 3205    (   '$pattr_directive'(Goal, Module)
 3206    ->  true
 3207    ;   Term = error(_,_),
 3208        catch(Module:Goal, Term, '$exception_in_directive'(Term))
 3209    ->  true
 3210    ;   '$print_message'(warning, goal_failed(directive, Module:Goal)),
 3211        fail
 3212    ).
 3213'$execute_directive_3'(_).
 $valid_directive(:Directive) is det
If the flag sandboxed_load is true, this calls prolog:sandbox_allowed_directive/1. This call can deny execution of the directive by throwing an exception.
 3222:- multifile prolog:sandbox_allowed_directive/1. 3223:- multifile prolog:sandbox_allowed_clause/1. 3224:- meta_predicate '$valid_directive'(:). 3225
 3226'$valid_directive'(_) :-
 3227    current_prolog_flag(sandboxed_load, false),
 3228    !.
 3229'$valid_directive'(Goal) :-
 3230    Error = error(Formal, _),
 3231    catch(prolog:sandbox_allowed_directive(Goal), Error, true),
 3232    !,
 3233    (   var(Formal)
 3234    ->  true
 3235    ;   print_message(error, Error),
 3236        fail
 3237    ).
 3238'$valid_directive'(Goal) :-
 3239    print_message(error,
 3240                  error(permission_error(execute,
 3241                                         sandboxed_directive,
 3242                                         Goal), _)),
 3243    fail.
 3244
 3245'$exception_in_directive'(Term) :-
 3246    '$print_message'(error, Term),
 3247    fail.
 3248
 3249%       This predicate deals with the very odd ISO requirement to allow
 3250%       for :- dynamic(a/2, b/3, c/4) instead of the normally used
 3251%       :- dynamic a/2, b/3, c/4 or, if operators are not desirable,
 3252%       :- dynamic((a/2, b/3, c/4)).
 3253
 3254'$expand_directive'(Directive, Expanded) :-
 3255    functor(Directive, Name, Arity),
 3256    Arity > 1,
 3257    '$iso_property_directive'(Name),
 3258    Directive =.. [Name|Args],
 3259    '$mk_normal_args'(Args, Normal),
 3260    Expanded =.. [Name, Normal].
 3261
 3262'$iso_property_directive'(dynamic).
 3263'$iso_property_directive'(multifile).
 3264'$iso_property_directive'(discontiguous).
 3265
 3266'$mk_normal_args'([One], One).
 3267'$mk_normal_args'([H|T0], (H,T)) :-
 3268    '$mk_normal_args'(T0, T).
 3269
 3270
 3271%       Note that the list, consult and ensure_loaded directives are already
 3272%       handled at compile time and therefore should not go into the
 3273%       intermediate code file.
 3274
 3275'$add_directive_wic2'(Goal, Type) :-
 3276    '$common_goal_type'(Goal, Type),
 3277    !,
 3278    (   Type == load
 3279    ->  true
 3280    ;   '$current_source_module'(Module),
 3281        '$add_directive_wic'(Module:Goal)
 3282    ).
 3283'$add_directive_wic2'(Goal, _) :-
 3284    (   '$compilation_mode'(qlf)    % no problem for qlf files
 3285    ->  true
 3286    ;   print_message(error, mixed_directive(Goal))
 3287    ).
 3288
 3289'$common_goal_type'((A,B), Type) :-
 3290    !,
 3291    '$common_goal_type'(A, Type),
 3292    '$common_goal_type'(B, Type).
 3293'$common_goal_type'((A;B), Type) :-
 3294    !,
 3295    '$common_goal_type'(A, Type),
 3296    '$common_goal_type'(B, Type).
 3297'$common_goal_type'((A->B), Type) :-
 3298    !,
 3299    '$common_goal_type'(A, Type),
 3300    '$common_goal_type'(B, Type).
 3301'$common_goal_type'(Goal, Type) :-
 3302    '$goal_type'(Goal, Type).
 3303
 3304'$goal_type'(Goal, Type) :-
 3305    (   '$load_goal'(Goal)
 3306    ->  Type = load
 3307    ;   Type = call
 3308    ).
 3309
 3310'$load_goal'([_|_]).
 3311'$load_goal'(consult(_)).
 3312'$load_goal'(load_files(_)).
 3313'$load_goal'(load_files(_,Options)) :-
 3314    memberchk(qcompile(QlfMode), Options),
 3315    '$qlf_part_mode'(QlfMode).
 3316'$load_goal'(ensure_loaded(_)) :- '$compilation_mode'(wic).
 3317'$load_goal'(use_module(_))    :- '$compilation_mode'(wic).
 3318'$load_goal'(use_module(_, _)) :- '$compilation_mode'(wic).
 3319
 3320'$qlf_part_mode'(part).
 3321'$qlf_part_mode'(true).                 % compatibility
 3322
 3323
 3324                /********************************
 3325                *        COMPILE A CLAUSE       *
 3326                *********************************/
 $store_admin_clause(+Clause, ?Layout, +Owner, +SrcLoc) is det
Store a clause into the database for administrative purposes. This bypasses sanity checking.
 3333'$store_admin_clause'(Clause, Layout, Owner, SrcLoc) :-
 3334    Owner \== (-),
 3335    !,
 3336    setup_call_cleanup(
 3337        '$start_aux'(Owner, Context),
 3338        '$store_admin_clause2'(Clause, Layout, Owner, SrcLoc),
 3339        '$end_aux'(Owner, Context)).
 3340'$store_admin_clause'(Clause, Layout, File, SrcLoc) :-
 3341    '$store_admin_clause2'(Clause, Layout, File, SrcLoc).
 3342
 3343'$store_admin_clause2'(Clause, _Layout, File, SrcLoc) :-
 3344    (   '$compilation_mode'(database)
 3345    ->  '$record_clause'(Clause, File, SrcLoc)
 3346    ;   '$record_clause'(Clause, File, SrcLoc, Ref),
 3347        '$qlf_assert_clause'(Ref, development)
 3348    ).
 $store_clause(+Clause, ?Layout, +Owner, +SrcLoc) is det
Store a clause into the database.
Arguments:
Owner- is the file-id that owns the clause
SrcLoc- is the file:line term where the clause originates from.
 3358'$store_clause'((_, _), _, _, _) :-
 3359    !,
 3360    print_message(error, cannot_redefine_comma),
 3361    fail.
 3362'$store_clause'(Clause, _Layout, File, SrcLoc) :-
 3363    '$valid_clause'(Clause),
 3364    !,
 3365    (   '$compilation_mode'(database)
 3366    ->  '$record_clause'(Clause, File, SrcLoc)
 3367    ;   '$record_clause'(Clause, File, SrcLoc, Ref),
 3368        '$qlf_assert_clause'(Ref, development)
 3369    ).
 3370
 3371'$valid_clause'(_) :-
 3372    current_prolog_flag(sandboxed_load, false),
 3373    !.
 3374'$valid_clause'(Clause) :-
 3375    \+ '$cross_module_clause'(Clause),
 3376    !.
 3377'$valid_clause'(Clause) :-
 3378    Error = error(Formal, _),
 3379    catch(prolog:sandbox_allowed_clause(Clause), Error, true),
 3380    !,
 3381    (   var(Formal)
 3382    ->  true
 3383    ;   print_message(error, Error),
 3384        fail
 3385    ).
 3386'$valid_clause'(Clause) :-
 3387    print_message(error,
 3388                  error(permission_error(assert,
 3389                                         sandboxed_clause,
 3390                                         Clause), _)),
 3391    fail.
 3392
 3393'$cross_module_clause'(Clause) :-
 3394    '$head_module'(Clause, Module),
 3395    \+ '$current_source_module'(Module).
 3396
 3397'$head_module'(Var, _) :-
 3398    var(Var), !, fail.
 3399'$head_module'((Head :- _), Module) :-
 3400    '$head_module'(Head, Module).
 3401'$head_module'(Module:_, Module).
 3402
 3403'$clause_source'('$source_location'(File,Line):Clause, Clause, File:Line) :- !.
 3404'$clause_source'(Clause, Clause, -).
 $store_clause(+Term, +Id) is det
This interface is used by PlDoc (and who knows). Kept for to avoid compatibility issues.
 3411:- public
 3412    '$store_clause'/2. 3413
 3414'$store_clause'(Term, Id) :-
 3415    '$clause_source'(Term, Clause, SrcLoc),
 3416    '$store_clause'(Clause, _, Id, SrcLoc).
 compile_aux_clauses(+Clauses) is det
Compile clauses given the current source location but do not change the notion of the current procedure such that discontiguous warnings are not issued. The clauses are associated with the current file and therefore wiped out if the file is reloaded.

If the cross-referencer is active, we should not (re-)assert the clauses. Actually, we should make them known to the cross-referencer. How do we do that? Maybe we need a different API, such as in:

expand_term_aux(Goal, NewGoal, Clauses)
To be done
- Deal with source code layout?
 3437compile_aux_clauses(_Clauses) :-
 3438    current_prolog_flag(xref, true),
 3439    !.
 3440compile_aux_clauses(Clauses) :-
 3441    source_location(File, _Line),
 3442    '$compile_aux_clauses'(Clauses, File).
 3443
 3444'$compile_aux_clauses'(Clauses, File) :-
 3445    setup_call_cleanup(
 3446        '$start_aux'(File, Context),
 3447        '$store_aux_clauses'(Clauses, File),
 3448        '$end_aux'(File, Context)).
 3449
 3450'$store_aux_clauses'(Clauses, File) :-
 3451    is_list(Clauses),
 3452    !,
 3453    forall('$member'(C,Clauses),
 3454           '$compile_term'(C, _Layout, File)).
 3455'$store_aux_clauses'(Clause, File) :-
 3456    '$compile_term'(Clause, _Layout, File).
 3457
 3458
 3459		 /*******************************
 3460		 *            STAGING		*
 3461		 *******************************/
 $stage_file(+Target, -Stage) is det
 $install_staged_file(+Catcher, +Staged, +Target, +OnError)
Create files using staging, where we first write a temporary file and move it to Target if the file was created successfully. This provides an atomic transition, preventing customers from reading an incomplete file.
 3471'$stage_file'(Target, Stage) :-
 3472    file_directory_name(Target, Dir),
 3473    file_base_name(Target, File),
 3474    current_prolog_flag(pid, Pid),
 3475    format(atom(Stage), '~w/.~w.~d', [Dir,File,Pid]).
 3476
 3477'$install_staged_file'(exit, Staged, Target, error) :-
 3478    !,
 3479    rename_file(Staged, Target).
 3480'$install_staged_file'(exit, Staged, Target, OnError) :-
 3481    !,
 3482    InstallError = error(_,_),
 3483    catch(rename_file(Staged, Target),
 3484          InstallError,
 3485          '$install_staged_error'(OnError, InstallError, Staged, Target)).
 3486'$install_staged_file'(_, Staged, _, _OnError) :-
 3487    E = error(_,_),
 3488    catch(delete_file(Staged), E, true).
 3489
 3490'$install_staged_error'(OnError, Error, Staged, _Target) :-
 3491    E = error(_,_),
 3492    catch(delete_file(Staged), E, true),
 3493    (   OnError = silent
 3494    ->  true
 3495    ;   OnError = fail
 3496    ->  fail
 3497    ;   print_message(warning, Error)
 3498    ).
 3499
 3500
 3501                 /*******************************
 3502                 *             READING          *
 3503                 *******************************/
 3504
 3505:- multifile
 3506    prolog:comment_hook/3.                  % hook for read_clause/3
 3507
 3508
 3509                 /*******************************
 3510                 *       FOREIGN INTERFACE      *
 3511                 *******************************/
 3512
 3513%       call-back from PL_register_foreign().  First argument is the module
 3514%       into which the foreign predicate is loaded and second is a term
 3515%       describing the arguments.
 3516
 3517:- dynamic
 3518    '$foreign_registered'/2. 3519
 3520                 /*******************************
 3521                 *   TEMPORARY TERM EXPANSION   *
 3522                 *******************************/
 3523
 3524% Provide temporary definitions for the boot-loader.  These are replaced
 3525% by the real thing in load.pl
 3526
 3527:- dynamic
 3528    '$expand_goal'/2,
 3529    '$expand_term'/4. 3530
 3531'$expand_goal'(In, In).
 3532'$expand_term'(In, Layout, In, Layout).
 3533
 3534
 3535                 /*******************************
 3536                 *         TYPE SUPPORT         *
 3537                 *******************************/
 3538
 3539'$type_error'(Type, Value) :-
 3540    (   var(Value)
 3541    ->  throw(error(instantiation_error, _))
 3542    ;   throw(error(type_error(Type, Value), _))
 3543    ).
 3544
 3545'$domain_error'(Type, Value) :-
 3546    throw(error(domain_error(Type, Value), _)).
 3547
 3548'$existence_error'(Type, Object) :-
 3549    throw(error(existence_error(Type, Object), _)).
 3550
 3551'$permission_error'(Action, Type, Term) :-
 3552    throw(error(permission_error(Action, Type, Term), _)).
 3553
 3554'$instantiation_error'(_Var) :-
 3555    throw(error(instantiation_error, _)).
 3556
 3557'$uninstantiation_error'(NonVar) :-
 3558    throw(error(uninstantiation_error(NonVar), _)).
 3559
 3560'$must_be'(list, X) :- !,
 3561    '$skip_list'(_, X, Tail),
 3562    (   Tail == []
 3563    ->  true
 3564    ;   '$type_error'(list, Tail)
 3565    ).
 3566'$must_be'(options, X) :- !,
 3567    (   '$is_options'(X)
 3568    ->  true
 3569    ;   '$type_error'(options, X)
 3570    ).
 3571'$must_be'(atom, X) :- !,
 3572    (   atom(X)
 3573    ->  true
 3574    ;   '$type_error'(atom, X)
 3575    ).
 3576'$must_be'(integer, X) :- !,
 3577    (   integer(X)
 3578    ->  true
 3579    ;   '$type_error'(integer, X)
 3580    ).
 3581'$must_be'(callable, X) :- !,
 3582    (   callable(X)
 3583    ->  true
 3584    ;   '$type_error'(callable, X)
 3585    ).
 3586'$must_be'(oneof(Type, Domain, List), X) :- !,
 3587    '$must_be'(Type, X),
 3588    (   memberchk(X, List)
 3589    ->  true
 3590    ;   '$domain_error'(Domain, X)
 3591    ).
 3592'$must_be'(boolean, X) :- !,
 3593    (   (X == true ; X == false)
 3594    ->  true
 3595    ;   '$type_error'(boolean, X)
 3596    ).
 3597% Use for debugging
 3598%'$must_be'(Type, _X) :- format('Unknown $must_be type: ~q~n', [Type]).
 3599
 3600
 3601                /********************************
 3602                *       LIST PROCESSING         *
 3603                *********************************/
 3604
 3605'$member'(El, [H|T]) :-
 3606    '$member_'(T, El, H).
 3607
 3608'$member_'(_, El, El).
 3609'$member_'([H|T], El, _) :-
 3610    '$member_'(T, El, H).
 3611
 3612
 3613'$append'([], L, L).
 3614'$append'([H|T], L, [H|R]) :-
 3615    '$append'(T, L, R).
 3616
 3617'$select'(X, [X|Tail], Tail).
 3618'$select'(Elem, [Head|Tail], [Head|Rest]) :-
 3619    '$select'(Elem, Tail, Rest).
 3620
 3621'$reverse'(L1, L2) :-
 3622    '$reverse'(L1, [], L2).
 3623
 3624'$reverse'([], List, List).
 3625'$reverse'([Head|List1], List2, List3) :-
 3626    '$reverse'(List1, [Head|List2], List3).
 3627
 3628'$delete'([], _, []) :- !.
 3629'$delete'([Elem|Tail], Elem, Result) :-
 3630    !,
 3631    '$delete'(Tail, Elem, Result).
 3632'$delete'([Head|Tail], Elem, [Head|Rest]) :-
 3633    '$delete'(Tail, Elem, Rest).
 3634
 3635'$last'([H|T], Last) :-
 3636    '$last'(T, H, Last).
 3637
 3638'$last'([], Last, Last).
 3639'$last'([H|T], _, Last) :-
 3640    '$last'(T, H, Last).
 length(?List, ?N)
Is true when N is the length of List.
 3647:- '$iso'((length/2)). 3648
 3649length(List, Length) :-
 3650    var(Length),
 3651    !,
 3652    '$skip_list'(Length0, List, Tail),
 3653    (   Tail == []
 3654    ->  Length = Length0                    % +,-
 3655    ;   var(Tail)
 3656    ->  Tail \== Length,                    % avoid length(L,L)
 3657        '$length3'(Tail, Length, Length0)   % -,-
 3658    ;   throw(error(type_error(list, List),
 3659                    context(length/2, _)))
 3660    ).
 3661length(List, Length) :-
 3662    integer(Length),
 3663    Length >= 0,
 3664    !,
 3665    '$skip_list'(Length0, List, Tail),
 3666    (   Tail == []                          % proper list
 3667    ->  Length = Length0
 3668    ;   var(Tail)
 3669    ->  Extra is Length-Length0,
 3670        '$length'(Tail, Extra)
 3671    ;   throw(error(type_error(list, List),
 3672                    context(length/2, _)))
 3673    ).
 3674length(_, Length) :-
 3675    integer(Length),
 3676    !,
 3677    throw(error(domain_error(not_less_than_zero, Length),
 3678                context(length/2, _))).
 3679length(_, Length) :-
 3680    throw(error(type_error(integer, Length),
 3681                context(length/2, _))).
 3682
 3683'$length3'([], N, N).
 3684'$length3'([_|List], N, N0) :-
 3685    N1 is N0+1,
 3686    '$length3'(List, N, N1).
 3687
 3688
 3689                 /*******************************
 3690                 *       OPTION PROCESSING      *
 3691                 *******************************/
 $is_options(@Term) is semidet
True if Term looks like it provides options.
 3697'$is_options'(Map) :-
 3698    is_dict(Map, _),
 3699    !.
 3700'$is_options'(List) :-
 3701    is_list(List),
 3702    (   List == []
 3703    ->  true
 3704    ;   List = [H|_],
 3705        '$is_option'(H, _, _)
 3706    ).
 3707
 3708'$is_option'(Var, _, _) :-
 3709    var(Var), !, fail.
 3710'$is_option'(F, Name, Value) :-
 3711    functor(F, _, 1),
 3712    !,
 3713    F =.. [Name,Value].
 3714'$is_option'(Name=Value, Name, Value).
 $option(?Opt, +Options) is semidet
 3718'$option'(Opt, Options) :-
 3719    is_dict(Options),
 3720    !,
 3721    [Opt] :< Options.
 3722'$option'(Opt, Options) :-
 3723    memberchk(Opt, Options).
 $option(?Opt, +Options, +Default) is det
 3727'$option'(Term, Options, Default) :-
 3728    arg(1, Term, Value),
 3729    functor(Term, Name, 1),
 3730    (   is_dict(Options)
 3731    ->  (   get_dict(Name, Options, GVal)
 3732        ->  Value = GVal
 3733        ;   Value = Default
 3734        )
 3735    ;   functor(Gen, Name, 1),
 3736        arg(1, Gen, GVal),
 3737        (   memberchk(Gen, Options)
 3738        ->  Value = GVal
 3739        ;   Value = Default
 3740        )
 3741    ).
 $select_option(?Opt, +Options, -Rest) is semidet
Select an option from Options.
Arguments:
Rest- is always a map.
 3749'$select_option'(Opt, Options, Rest) :-
 3750    select_dict([Opt], Options, Rest).
 $merge_options(+New, +Default, -Merged) is det
Add/replace options specified in New.
Arguments:
Merged- is always a map.
 3758'$merge_options'(New, Old, Merged) :-
 3759    put_dict(New, Old, Merged).
 3760
 3761
 3762                 /*******************************
 3763                 *   HANDLE TRACER 'L'-COMMAND  *
 3764                 *******************************/
 3765
 3766:- public '$prolog_list_goal'/1. 3767
 3768:- multifile
 3769    user:prolog_list_goal/1. 3770
 3771'$prolog_list_goal'(Goal) :-
 3772    user:prolog_list_goal(Goal),
 3773    !.
 3774'$prolog_list_goal'(Goal) :-
 3775    user:listing(Goal).
 3776
 3777
 3778                 /*******************************
 3779                 *             HALT             *
 3780                 *******************************/
 3781
 3782:- '$iso'((halt/0)). 3783
 3784halt :-
 3785    halt(0).
 at_halt(:Goal)
Register Goal to be called if the system halts.
To be done
- : get location into the error message
 3794:- meta_predicate at_halt(0). 3795:- dynamic        system:term_expansion/2, '$at_halt'/2. 3796:- multifile      system:term_expansion/2, '$at_halt'/2. 3797
 3798system:term_expansion((:- at_halt(Goal)),
 3799                      system:'$at_halt'(Module:Goal, File:Line)) :-
 3800    \+ current_prolog_flag(xref, true),
 3801    source_location(File, Line),
 3802    '$current_source_module'(Module).
 3803
 3804at_halt(Goal) :-
 3805    asserta('$at_halt'(Goal, (-):0)).
 3806
 3807:- public '$run_at_halt'/0. 3808
 3809'$run_at_halt' :-
 3810    forall(clause('$at_halt'(Goal, Src), true, Ref),
 3811           ( '$call_at_halt'(Goal, Src),
 3812             erase(Ref)
 3813           )).
 3814
 3815'$call_at_halt'(Goal, _Src) :-
 3816    catch(Goal, E, true),
 3817    !,
 3818    (   var(E)
 3819    ->  true
 3820    ;   subsumes_term(cancel_halt(_), E)
 3821    ->  '$print_message'(informational, E),
 3822        fail
 3823    ;   '$print_message'(error, E)
 3824    ).
 3825'$call_at_halt'(Goal, _Src) :-
 3826    '$print_message'(warning, goal_failed(at_halt, Goal)).
 cancel_halt(+Reason)
This predicate may be called from at_halt/1 handlers to cancel halting the program. If causes halt/0 to fail rather than terminating the process.
 3834cancel_halt(Reason) :-
 3835    throw(cancel_halt(Reason)).
 3836
 3837
 3838                /********************************
 3839                *      LOAD OTHER MODULES       *
 3840                *********************************/
 3841
 3842:- meta_predicate
 3843    '$load_wic_files'(:). 3844
 3845'$load_wic_files'(Files) :-
 3846    Files = Module:_,
 3847    '$execute_directive'('$set_source_module'(OldM, Module), []),
 3848    '$save_lex_state'(LexState, []),
 3849    '$style_check'(_, 0xC7),                % see style_name/2 in syspred.pl
 3850    '$compilation_mode'(OldC, wic),
 3851    consult(Files),
 3852    '$execute_directive'('$set_source_module'(OldM), []),
 3853    '$execute_directive'('$restore_lex_state'(LexState), []),
 3854    '$set_compilation_mode'(OldC).
 $load_additional_boot_files is det
Called from compileFileList() in pl-wic.c. Gets the files from "-c file ..." and loads them into the module user.
 3862:- public '$load_additional_boot_files'/0. 3863
 3864'$load_additional_boot_files' :-
 3865    current_prolog_flag(argv, Argv),
 3866    '$get_files_argv'(Argv, Files),
 3867    (   Files \== []
 3868    ->  format('Loading additional boot files~n'),
 3869        '$load_wic_files'(user:Files),
 3870        format('additional boot files loaded~n')
 3871    ;   true
 3872    ).
 3873
 3874'$get_files_argv'([], []) :- !.
 3875'$get_files_argv'(['-c'|Files], Files) :- !.
 3876'$get_files_argv'([_|Rest], Files) :-
 3877    '$get_files_argv'(Rest, Files).
 3878
 3879'$:-'(('$boot_message'('Loading Prolog startup files~n', []),
 3880       source_location(File, _Line),
 3881       file_directory_name(File, Dir),
 3882       atom_concat(Dir, '/load.pl', LoadFile),
 3883       '$load_wic_files'(system:[LoadFile]),
 3884       (   current_prolog_flag(windows, true)
 3885       ->  atom_concat(Dir, '/menu.pl', MenuFile),
 3886           '$load_wic_files'(system:[MenuFile])
 3887       ;   true
 3888       ),
 3889       '$boot_message'('SWI-Prolog boot files loaded~n', []),
 3890       '$compilation_mode'(OldC, wic),
 3891       '$execute_directive'('$set_source_module'(user), []),
 3892       '$set_compilation_mode'(OldC)
 3893      ))