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-2017, University of Amsterdam
    7                              VU University Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module('$toplevel',
   37          [ '$initialise'/0,            % start Prolog
   38            '$toplevel'/0,              % Prolog top-level (re-entrant)
   39            '$compile'/0,               % `-c' toplevel
   40            '$config'/0,                % --dump-runtime-variables toplevel
   41            initialize/0,               % Run program initialization
   42            version/0,                  % Write initial banner
   43            version/1,                  % Add message to the banner
   44            prolog/0,                   % user toplevel predicate
   45            '$query_loop'/0,            % toplevel predicate
   46            residual_goals/1,           % +Callable
   47            (initialization)/1,         % initialization goal (directive)
   48            '$thread_init'/0,           % initialise thread
   49            (thread_initialization)/1   % thread initialization goal
   50            ]).   51
   52
   53                 /*******************************
   54                 *       FILE_SEARCH_PATH       *
   55                 *******************************/
   56
   57:- multifile user:file_search_path/2.   58
   59user:file_search_path(app_data, PrologAppData) :-
   60    (   current_prolog_flag(windows, true)
   61    ->  catch(win_folder(appdata, AppData), _, fail),
   62        atom_concat(AppData, '/SWI-Prolog', PrologAppData),
   63        (   exists_directory(PrologAppData)
   64        ->  true
   65        ;   catch(make_directory(PrologAppData), _, fail)
   66        )
   67    ;   catch(expand_file_name('~/lib/swipl', [PrologAppData]), _, fail)
   68    ).
   69user:file_search_path(app_preferences, Preferences) :-
   70    (   current_prolog_flag(windows, true)
   71    ->  Preferences = app_data('.')
   72    ;   catch(expand_file_name(~, [UserHome]), _, fail)
   73    ->  Preferences = UserHome
   74    ).
   75user:file_search_path(user_profile, app_preferences('.')).
   76
   77
   78                 /*******************************
   79                 *         VERSION BANNER       *
   80                 *******************************/
   81
   82:- dynamic
   83    prolog:version_msg/1.
 version is det
Print the Prolog banner message and messages registered using version/1.
   90version :-
   91    print_message(banner, welcome).
 version(+Message) is det
Add message to version/0
   97:- multifile
   98    system:term_expansion/2.   99
  100system:term_expansion((:- version(Message)),
  101                      prolog:version_msg(Message)).
  102
  103version(Message) :-
  104    (   prolog:version_msg(Message)
  105    ->  true
  106    ;   assertz(prolog:version_msg(Message))
  107    ).
  108
  109
  110                /********************************
  111                *         INITIALISATION        *
  112                *********************************/
  113
  114%       note: loaded_init_file/2 is used by prolog_load_context/2 to
  115%       confirm we are loading a script.
  116
  117:- dynamic
  118    loaded_init_file/2.             % already loaded init files
  119
  120'$load_init_file'(none) :- !.
  121'$load_init_file'(Base) :-
  122    loaded_init_file(Base, _),
  123    !.
  124'$load_init_file'(InitFile) :-
  125    exists_file(InitFile),
  126    !,
  127    ensure_loaded(user:InitFile).
  128'$load_init_file'(Base) :-
  129    absolute_file_name(user_profile(Base), InitFile,
  130                       [ access(read),
  131                         file_errors(fail)
  132                       ]),
  133    asserta(loaded_init_file(Base, InitFile)),
  134    load_files(user:InitFile,
  135               [ scope_settings(false)
  136               ]).
  137'$load_init_file'(_).
  138
  139'$load_system_init_file' :-
  140    loaded_init_file(system, _),
  141    !.
  142'$load_system_init_file' :-
  143    '$cmd_option_val'(system_init_file, Base),
  144    Base \== none,
  145    current_prolog_flag(home, Home),
  146    file_name_extension(Base, rc, Name),
  147    atomic_list_concat([Home, '/', Name], File),
  148    absolute_file_name(File, Path,
  149                       [ file_type(prolog),
  150                         access(read),
  151                         file_errors(fail)
  152                       ]),
  153    asserta(loaded_init_file(system, Path)),
  154    load_files(user:Path,
  155               [ silent(true),
  156                 scope_settings(false)
  157               ]),
  158    !.
  159'$load_system_init_file'.
  160
  161'$load_script_file' :-
  162    loaded_init_file(script, _),
  163    !.
  164'$load_script_file' :-
  165    '$cmd_option_val'(script_file, OsFiles),
  166    load_script_files(OsFiles).
  167
  168load_script_files([]).
  169load_script_files([OsFile|More]) :-
  170    prolog_to_os_filename(File, OsFile),
  171    (   absolute_file_name(File, Path,
  172                           [ file_type(prolog),
  173                             access(read),
  174                             file_errors(fail)
  175                           ])
  176    ->  asserta(loaded_init_file(script, Path)),
  177        load_files(user:Path, []),
  178        load_files(More)
  179    ;   throw(error(existence_error(script_file, File), _))
  180    ).
  181
  182
  183                 /*******************************
  184                 *       AT_INITIALISATION      *
  185                 *******************************/
  186
  187:- meta_predicate
  188    initialization(0).  189
  190:- '$iso'((initialization)/1).
 initialization :Goal
Runs Goal after loading the file in which this directive appears as well as after restoring a saved state.
See also
- initialization/2
  199initialization(Goal) :-
  200    Goal = _:G,
  201    prolog:initialize_now(G, Use),
  202    !,
  203    print_message(warning, initialize_now(G, Use)),
  204    initialization(Goal, now).
  205initialization(Goal) :-
  206    initialization(Goal, after_load).
  207
  208:- multifile
  209    prolog:initialize_now/2,
  210    prolog:message//1.  211
  212prolog:initialize_now(load_foreign_library(_),
  213                      'use :- use_foreign_library/1 instead').
  214prolog:initialize_now(load_foreign_library(_,_),
  215                      'use :- use_foreign_library/2 instead').
  216
  217prolog:message(initialize_now(Goal, Use)) -->
  218    [ 'Initialization goal ~p will be executed'-[Goal],nl,
  219      'immediately for backward compatibility reasons', nl,
  220      '~w'-[Use]
  221    ].
  222
  223'$run_initialization' :-
  224    '$run_initialization'(_, []),
  225    '$thread_init'.
 initialize
Run goals registered with :- initialization(Goal, program).. Stop with an exception if a goal fails or raises an exception.
  232initialize :-
  233    forall('$init_goal'(when(program), Goal, Ctx),
  234           run_initialize(Goal, Ctx)).
  235
  236run_initialize(Goal, Ctx) :-
  237    (   catch(Goal, E, true),
  238        (   var(E)
  239        ->  true
  240        ;   throw(error(initialization_error(E, Goal, Ctx), _))
  241        )
  242    ;   throw(error(initialization_error(failed, Goal, Ctx), _))
  243    ).
  244
  245
  246                 /*******************************
  247                 *     THREAD INITIALIZATION    *
  248                 *******************************/
  249
  250:- meta_predicate
  251    thread_initialization(0).  252:- dynamic
  253    '$at_thread_initialization'/1.
 thread_initialization :Goal
Run Goal now and everytime a new thread is created.
  259thread_initialization(Goal) :-
  260    assert('$at_thread_initialization'(Goal)),
  261    call(Goal),
  262    !.
  263
  264'$thread_init' :-
  265    (   '$at_thread_initialization'(Goal),
  266        (   call(Goal)
  267        ->  fail
  268        ;   fail
  269        )
  270    ;   true
  271    ).
  272
  273
  274                 /*******************************
  275                 *     FILE SEARCH PATH (-p)    *
  276                 *******************************/
 $set_file_search_paths is det
Process -p PathSpec options.
  282'$set_file_search_paths' :-
  283    '$cmd_option_val'(search_paths, Paths),
  284    (   '$member'(Path, Paths),
  285        atom_chars(Path, Chars),
  286        (   phrase('$search_path'(Name, Aliases), Chars)
  287        ->  '$reverse'(Aliases, Aliases1),
  288            forall('$member'(Alias, Aliases1),
  289                   asserta(user:file_search_path(Name, Alias)))
  290        ;   print_message(error, commandline_arg_type(p, Path))
  291        ),
  292        fail ; true
  293    ).
  294
  295'$search_path'(Name, Aliases) -->
  296    '$string'(NameChars),
  297    [=],
  298    !,
  299    {atom_chars(Name, NameChars)},
  300    '$search_aliases'(Aliases).
  301
  302'$search_aliases'([Alias|More]) -->
  303    '$string'(AliasChars),
  304    path_sep,
  305    !,
  306    { '$make_alias'(AliasChars, Alias) },
  307    '$search_aliases'(More).
  308'$search_aliases'([Alias]) -->
  309    '$string'(AliasChars),
  310    '$eos',
  311    !,
  312    { '$make_alias'(AliasChars, Alias) }.
  313
  314path_sep -->
  315    { current_prolog_flag(windows, true)
  316    },
  317    !,
  318    [;].
  319path_sep -->
  320    [:].
  321
  322'$string'([]) --> [].
  323'$string'([H|T]) --> [H], '$string'(T).
  324
  325'$eos'([], []).
  326
  327'$make_alias'(Chars, Alias) :-
  328    catch(term_to_atom(Alias, Chars), _, fail),
  329    (   atom(Alias)
  330    ;   functor(Alias, F, 1),
  331        F \== /
  332    ),
  333    !.
  334'$make_alias'(Chars, Alias) :-
  335    atom_chars(Alias, Chars).
  336
  337
  338                 /*******************************
  339                 *   LOADING ASSIOCIATED FILES  *
  340                 *******************************/
 argv_files(-Files) is det
Update the Prolog flag argv, extracting the leading directory and files.
  347argv_files(Files) :-
  348    current_prolog_flag(argv, Argv),
  349    no_option_files(Argv, Argv1, Files),
  350    (   Argv1 \== Argv
  351    ->  set_prolog_flag(argv, Argv1)
  352    ;   true
  353    ).
  354
  355no_option_files([--|Argv], Argv, []) :- !.
  356no_option_files([OsScript|Argv], Argv, [Script]) :-
  357    prolog_to_os_filename(Script, OsScript),
  358    access_file(Script, read),
  359    catch(setup_call_cleanup(
  360              open(Script, read, In),
  361              ( get_char(In, '#'),
  362                get_char(In, '!')
  363              ),
  364              close(In)),
  365          _, fail),
  366    !.
  367no_option_files([OsFile|Argv0], Argv, [File|T]) :-
  368    file_name_extension(_, Ext, OsFile),
  369    user:prolog_file_type(Ext, prolog),
  370    !,
  371    prolog_to_os_filename(File, OsFile),
  372    no_option_files(Argv0, Argv, T).
  373no_option_files(Argv, Argv, []).
  374
  375clean_argv :-
  376    (   current_prolog_flag(argv, [--|Argv])
  377    ->  set_prolog_flag(argv, Argv)
  378    ;   true
  379    ).
 associated_files(-Files)
If SWI-Prolog is started as <exe> <file>.<ext>, where <ext> is the extension registered for associated files, set the Prolog flag associated_file, switch to the directory holding the file and -if possible- adjust the window title.
  388associated_files([]) :-
  389    current_prolog_flag(saved_program_class, runtime),
  390    !,
  391    clean_argv.
  392associated_files(Files) :-
  393    '$set_prolog_file_extension',
  394    argv_files(Files),
  395    (   Files = [File|_]
  396    ->  absolute_file_name(File, AbsFile),
  397        set_prolog_flag(associated_file, AbsFile),
  398        set_working_directory(File),
  399        set_window_title(Files)
  400    ;   true
  401    ).
 set_working_directory(+File)
When opening as a GUI application, e.g., by opening a file from the Finder/Explorer/..., we typically want to change working directory to the location of the primary file. We currently detect that we are a GUI app by the Prolog flag console_menu, which is set by swipl-win[.exe].
  411set_working_directory(File) :-
  412    current_prolog_flag(console_menu, true),
  413    access_file(File, read),
  414    !,
  415    file_directory_name(File, Dir),
  416    working_directory(_, Dir).
  417set_working_directory(_).
  418
  419set_window_title([File|More]) :-
  420    current_predicate(system:window_title/2),
  421    !,
  422    (   More == []
  423    ->  Extra = []
  424    ;   Extra = ['...']
  425    ),
  426    atomic_list_concat(['SWI-Prolog --', File | Extra], ' ', Title),
  427    system:window_title(_, Title).
  428set_window_title(_).
 start_pldoc
If the option --pldoc[=port] is given, load the PlDoc system.
  436start_pldoc :-
  437    '$cmd_option_val'(pldoc_server, Server),
  438    (   Server == ''
  439    ->  call((doc_server(_), doc_browser))
  440    ;   catch(atom_number(Server, Port), _, fail)
  441    ->  call(doc_server(Port))
  442    ;   print_message(error, option_usage(pldoc)),
  443        halt(1)
  444    ).
  445start_pldoc.
 load_associated_files(+Files)
Load Prolog files specified from the commandline.
  452load_associated_files(Files) :-
  453    (   '$member'(File, Files),
  454        load_files(user:File, [expand(false)]),
  455        fail
  456    ;   true
  457    ).
  458
  459hkey('HKEY_CURRENT_USER/Software/SWI/Prolog').
  460hkey('HKEY_LOCAL_MACHINE/Software/SWI/Prolog').
  461
  462'$set_prolog_file_extension' :-
  463    current_prolog_flag(windows, true),
  464    hkey(Key),
  465    catch(win_registry_get_value(Key, fileExtension, Ext0),
  466          _, fail),
  467    !,
  468    (   atom_concat('.', Ext, Ext0)
  469    ->  true
  470    ;   Ext = Ext0
  471    ),
  472    (   user:prolog_file_type(Ext, prolog)
  473    ->  true
  474    ;   asserta(user:prolog_file_type(Ext, prolog))
  475    ).
  476'$set_prolog_file_extension'.
  477
  478
  479                /********************************
  480                *        TOPLEVEL GOALS         *
  481                *********************************/
 $initialise is semidet
Called from PL_initialise() to do the Prolog part of the initialization. If an exception occurs, this is printed and '$initialise' fails.
  489'$initialise' :-
  490    catch(initialise_prolog, E, initialise_error(E)).
  491
  492initialise_error('$aborted') :- !.
  493initialise_error(E) :-
  494    print_message(error, initialization_exception(E)),
  495    fail.
  496
  497initialise_prolog :-
  498    '$clean_history',
  499    '$run_initialization',
  500    '$load_system_init_file',
  501    set_toplevel,
  502    '$set_file_search_paths',
  503    init_debug_flags,
  504    start_pldoc,
  505    attach_packs,
  506    '$cmd_option_val'(init_file, OsFile),
  507    prolog_to_os_filename(File, OsFile),
  508    '$load_init_file'(File),
  509    catch(setup_colors, E, print_message(warning, E)),
  510    '$load_script_file',
  511    associated_files(Files),
  512    load_associated_files(Files),
  513    '$cmd_option_val'(goals, Goals),
  514    (   Goals == [],
  515        \+ '$init_goal'(when(_), _, _)
  516    ->  version                                 % default interactive run
  517    ;   run_init_goals(Goals),
  518        (   load_only
  519        ->  version
  520        ;   run_program_init,
  521            run_main_init
  522        )
  523    ).
  524
  525set_toplevel :-
  526    '$cmd_option_val'(toplevel, TopLevelAtom),
  527    catch(term_to_atom(TopLevel, TopLevelAtom), E,
  528          (print_message(error, E),
  529           halt(1))),
  530    create_prolog_flag(toplevel_goal, TopLevel, [type(term)]).
  531
  532load_only :-
  533    current_prolog_flag(os_argv, OSArgv),
  534    memberchk('-l', OSArgv),
  535    current_prolog_flag(argv, Argv),
  536    \+ memberchk('-l', Argv).
 run_init_goals(+Goals) is det
Run registered initialization goals on order. If a goal fails, execution is halted.
  543run_init_goals([]).
  544run_init_goals([H|T]) :-
  545    run_init_goal(H),
  546    run_init_goals(T).
  547
  548run_init_goal(Text) :-
  549    catch(term_to_atom(Goal, Text), E,
  550          (   print_message(error, init_goal_syntax(E, Text)),
  551              halt(2)
  552          )),
  553    run_init_goal(Goal, Text).
 run_program_init is det
Run goals registered using
  559run_program_init :-
  560    forall('$init_goal'(when(program), Goal, Ctx),
  561           run_init_goal(Goal, @(Goal,Ctx))).
  562
  563run_main_init :-
  564    findall(Goal-Ctx, '$init_goal'(when(main), Goal, Ctx), Pairs),
  565    '$last'(Pairs, Goal-Ctx),
  566    !,
  567    (   current_prolog_flag(toplevel_goal, default)
  568    ->  set_prolog_flag(toplevel_goal, halt)
  569    ;   true
  570    ),
  571    run_init_goal(Goal, @(Goal,Ctx)).
  572run_main_init.
  573
  574run_init_goal(Goal, Ctx) :-
  575    (   catch_with_backtrace(user:Goal, E, true)
  576    ->  (   var(E)
  577        ->  true
  578        ;   print_message(error, init_goal_failed(E, Ctx)),
  579            halt(2)
  580        )
  581    ;   (   current_prolog_flag(verbose, silent)
  582        ->  Level = silent
  583        ;   Level = error
  584        ),
  585        print_message(Level, init_goal_failed(failed, Ctx)),
  586        halt(1)
  587    ).
 init_debug_flags is det
Initialize the various Prolog flags that control the debugger and toplevel.
  594init_debug_flags :-
  595    once(print_predicate(_, [print], PrintOptions)),
  596    create_prolog_flag(answer_write_options, PrintOptions, []),
  597    create_prolog_flag(prompt_alternatives_on, determinism, []),
  598    create_prolog_flag(toplevel_extra_white_line, true, []),
  599    create_prolog_flag(toplevel_print_factorized, false, []),
  600    create_prolog_flag(print_write_options,
  601                       [ portray(true), quoted(true), numbervars(true) ],
  602                       []),
  603    create_prolog_flag(toplevel_residue_vars, false, []),
  604    create_prolog_flag(toplevel_list_wfs_residual_program, true, []),
  605    '$set_debugger_write_options'(print).
 setup_backtrace
Initialise printing a backtrace.
  611setup_backtrace :-
  612    (   \+ current_prolog_flag(backtrace, false),
  613        load_setup_file(library(prolog_stack))
  614    ->  true
  615    ;   true
  616    ).
 setup_colors is det
Setup interactive usage by enabling colored output.
  622setup_colors :-
  623    (   \+ current_prolog_flag(color_term, false),
  624        stream_property(user_input, tty(true)),
  625        stream_property(user_error, tty(true)),
  626        stream_property(user_output, tty(true)),
  627        \+ getenv('TERM', dumb),
  628        load_setup_file(user:library(ansi_term))
  629    ->  true
  630    ;   true
  631    ).
 setup_history
Enable per-directory persistent history.
  637setup_history :-
  638    (   \+ current_prolog_flag(save_history, false),
  639        stream_property(user_input, tty(true)),
  640        \+ current_prolog_flag(readline, false),
  641        load_setup_file(library(prolog_history))
  642    ->  prolog_history(enable)
  643    ;   true
  644    ),
  645    set_default_history,
  646    '$load_history'.
 setup_readline
Setup line editing.
  652setup_readline :-
  653    (   current_prolog_flag(readline, swipl_win)
  654    ->  true
  655    ;   stream_property(user_input, tty(true)),
  656        current_prolog_flag(tty_control, true),
  657        \+ getenv('TERM', dumb),
  658        (   current_prolog_flag(readline, ReadLine)
  659        ->  true
  660        ;   ReadLine = true
  661        ),
  662        readline_library(ReadLine, Library),
  663        load_setup_file(library(Library))
  664    ->  set_prolog_flag(readline, Library)
  665    ;   set_prolog_flag(readline, false)
  666    ).
  667
  668readline_library(true, Library) :-
  669    !,
  670    preferred_readline(Library).
  671readline_library(false, _) :-
  672    !,
  673    fail.
  674readline_library(Library, Library).
  675
  676preferred_readline(editline).
  677preferred_readline(readline).
 load_setup_file(+File) is semidet
Load a file and fail silently if the file does not exist.
  683load_setup_file(File) :-
  684    catch(load_files(File,
  685                     [ silent(true),
  686                       if(not_loaded)
  687                     ]), _, fail).
  688
  689
  690:- '$hide'('$toplevel'/0).              % avoid in the GUI stacktrace
 $toplevel
Called from PL_toplevel()
  696'$toplevel' :-
  697    '$runtoplevel',
  698    print_message(informational, halt).
 $runtoplevel
Actually run the toplevel. The values default and prolog both start the interactive toplevel, where prolog implies the user gave -t prolog.
See also
- prolog/0 is the default interactive toplevel
  708'$runtoplevel' :-
  709    current_prolog_flag(toplevel_goal, TopLevel0),
  710    toplevel_goal(TopLevel0, TopLevel),
  711    user:TopLevel.
  712
  713:- dynamic  setup_done/0.  714:- volatile setup_done/0.  715
  716toplevel_goal(default, '$query_loop') :-
  717    !,
  718    setup_interactive.
  719toplevel_goal(prolog, '$query_loop') :-
  720    !,
  721    setup_interactive.
  722toplevel_goal(Goal, Goal).
  723
  724setup_interactive :-
  725    setup_done,
  726    !.
  727setup_interactive :-
  728    asserta(setup_done),
  729    catch(setup_backtrace, E, print_message(warning, E)),
  730    catch(setup_readline,  E, print_message(warning, E)),
  731    catch(setup_history,   E, print_message(warning, E)).
 $compile
Toplevel called when invoked with -c option.
  737'$compile' :-
  738    (   catch('$compile_', E, (print_message(error, E), halt(1)))
  739    ->  true
  740    ;   print_message(error, error(goal_failed('$compile'), _)),
  741        halt(1)
  742    ).
  743
  744'$compile_' :-
  745    '$load_system_init_file',
  746    '$set_file_search_paths',
  747    init_debug_flags,
  748    '$run_initialization',
  749    attach_packs,
  750    use_module(library(qsave)),
  751    qsave:qsave_toplevel.
 $config
Toplevel when invoked with --dump-runtime-variables
  757'$config' :-
  758    '$load_system_init_file',
  759    '$set_file_search_paths',
  760    init_debug_flags,
  761    '$run_initialization',
  762    load_files(library(prolog_config)),
  763    (   catch(prolog_dump_runtime_variables, E,
  764              (print_message(error, E), halt(1)))
  765    ->  true
  766    ;   print_message(error, error(goal_failed(prolog_dump_runtime_variables),_))
  767    ).
  768
  769
  770                /********************************
  771                *    USER INTERACTIVE LOOP      *
  772                *********************************/
 prolog
Run the Prolog toplevel. This is now the same as break/0, which pretends to be in a break-level if there is a parent environment.
  780prolog :-
  781    break.
  782
  783:- create_prolog_flag(toplevel_mode, backtracking, []).
 $query_loop
Run the normal Prolog query loop. Note that the query is not protected by catch/3. Dealing with unhandled exceptions is done by the C-function query_loop(). This ensures that unhandled exceptions are really unhandled (in Prolog).
  792'$query_loop' :-
  793    current_prolog_flag(toplevel_mode, recursive),
  794    !,
  795    break_level(Level),
  796    read_expanded_query(Level, Query, Bindings),
  797    (   Query == end_of_file
  798    ->  print_message(query, query(eof))
  799    ;   '$call_no_catch'('$execute'(Query, Bindings)),
  800        (   current_prolog_flag(toplevel_mode, recursive)
  801        ->  '$query_loop'
  802        ;   '$switch_toplevel_mode'(backtracking),
  803            '$query_loop'           % Maybe throw('$switch_toplevel_mode')?
  804        )
  805    ).
  806'$query_loop' :-
  807    break_level(BreakLev),
  808    repeat,
  809        read_expanded_query(BreakLev, Query, Bindings),
  810        (   Query == end_of_file
  811        ->  !, print_message(query, query(eof))
  812        ;   '$execute'(Query, Bindings),
  813            (   current_prolog_flag(toplevel_mode, recursive)
  814            ->  !,
  815                '$switch_toplevel_mode'(recursive),
  816                '$query_loop'
  817            ;   fail
  818            )
  819        ).
  820
  821break_level(BreakLev) :-
  822    (   current_prolog_flag(break_level, BreakLev)
  823    ->  true
  824    ;   BreakLev = -1
  825    ).
  826
  827read_expanded_query(BreakLev, ExpandedQuery, ExpandedBindings) :-
  828    '$current_typein_module'(TypeIn),
  829    (   stream_property(user_input, tty(true))
  830    ->  '$system_prompt'(TypeIn, BreakLev, Prompt),
  831        prompt(Old, '|    ')
  832    ;   Prompt = '',
  833        prompt(Old, '')
  834    ),
  835    trim_stacks,
  836    repeat,
  837      read_query(Prompt, Query, Bindings),
  838      prompt(_, Old),
  839      catch(call_expand_query(Query, ExpandedQuery,
  840                              Bindings, ExpandedBindings),
  841            Error,
  842            (print_message(error, Error), fail)),
  843    !.
 read_query(+Prompt, -Goal, -Bindings) is det
Read the next query. The first clause deals with the case where !-based history is enabled. The second is used if we have command line editing.
  852read_query(Prompt, Goal, Bindings) :-
  853    current_prolog_flag(history, N),
  854    integer(N), N > 0,
  855    !,
  856    read_history(h, '!h',
  857                 [trace, end_of_file],
  858                 Prompt, Goal, Bindings).
  859read_query(Prompt, Goal, Bindings) :-
  860    remove_history_prompt(Prompt, Prompt1),
  861    repeat,                                 % over syntax errors
  862    prompt1(Prompt1),
  863    read_query_line(user_input, Line),
  864    '$save_history_line'(Line),             % save raw line (edit syntax errors)
  865    '$current_typein_module'(TypeIn),
  866    catch(read_term_from_atom(Line, Goal,
  867                              [ variable_names(Bindings),
  868                                module(TypeIn)
  869                              ]), E,
  870          (   print_message(error, E),
  871              fail
  872          )),
  873    !,
  874    '$save_history_event'(Line).            % save event (no syntax errors)
 read_query_line(+Input, -Line) is det
  878read_query_line(Input, Line) :-
  879    catch(read_term_as_atom(Input, Line), Error, true),
  880    save_debug_after_read,
  881    (   var(Error)
  882    ->  true
  883    ;   Error = error(syntax_error(_),_)
  884    ->  print_message(error, Error),
  885        fail
  886    ;   print_message(error, Error),
  887        throw(Error)
  888    ).
 read_term_as_atom(+Input, -Line)
Read the next term as an atom and skip to the newline or a non-space character.
  895read_term_as_atom(In, Line) :-
  896    '$raw_read'(In, Line),
  897    (   Line == end_of_file
  898    ->  true
  899    ;   skip_to_nl(In)
  900    ).
 skip_to_nl(+Input) is det
Read input after the term. Skips white space and %... comment until the end of the line or a non-blank character.
  907skip_to_nl(In) :-
  908    repeat,
  909    peek_char(In, C),
  910    (   C == '%'
  911    ->  skip(In, '\n')
  912    ;   char_type(C, space)
  913    ->  get_char(In, _),
  914        C == '\n'
  915    ;   true
  916    ),
  917    !.
  918
  919remove_history_prompt('', '') :- !.
  920remove_history_prompt(Prompt0, Prompt) :-
  921    atom_chars(Prompt0, Chars0),
  922    clean_history_prompt_chars(Chars0, Chars1),
  923    delete_leading_blanks(Chars1, Chars),
  924    atom_chars(Prompt, Chars).
  925
  926clean_history_prompt_chars([], []).
  927clean_history_prompt_chars(['~', !|T], T) :- !.
  928clean_history_prompt_chars([H|T0], [H|T]) :-
  929    clean_history_prompt_chars(T0, T).
  930
  931delete_leading_blanks([' '|T0], T) :-
  932    !,
  933    delete_leading_blanks(T0, T).
  934delete_leading_blanks(L, L).
 set_default_history
Enable !-based numbered command history. This is enabled by default if we are not running under GNU-emacs and we do not have our own line editing.
  943set_default_history :-
  944    current_prolog_flag(history, _),
  945    !.
  946set_default_history :-
  947    (   (   \+ current_prolog_flag(readline, false)
  948        ;   current_prolog_flag(emacs_inferior_process, true)
  949        )
  950    ->  create_prolog_flag(history, 0, [])
  951    ;   create_prolog_flag(history, 25, [])
  952    ).
  953
  954
  955                 /*******************************
  956                 *        TOPLEVEL DEBUG        *
  957                 *******************************/
 save_debug_after_read
Called right after the toplevel read to save the debug status if it was modified from the GUI thread using e.g.
thread_signal(main, gdebug)
bug
- Ideally, the prompt would change if debug mode is enabled. That is hard to realise with all the different console interfaces supported by SWI-Prolog.
  972save_debug_after_read :-
  973    current_prolog_flag(debug, true),
  974    !,
  975    save_debug.
  976save_debug_after_read.
  977
  978save_debug :-
  979    (   tracing,
  980        notrace
  981    ->  Tracing = true
  982    ;   Tracing = false
  983    ),
  984    current_prolog_flag(debug, Debugging),
  985    set_prolog_flag(debug, false),
  986    create_prolog_flag(query_debug_settings,
  987                       debug(Debugging, Tracing), []).
  988
  989restore_debug :-
  990    current_prolog_flag(query_debug_settings, debug(Debugging, Tracing)),
  991    set_prolog_flag(debug, Debugging),
  992    (   Tracing == true
  993    ->  trace
  994    ;   true
  995    ).
  996
  997:- initialization
  998    create_prolog_flag(query_debug_settings, debug(false, false), []).  999
 1000
 1001                /********************************
 1002                *            PROMPTING          *
 1003                ********************************/
 1004
 1005'$system_prompt'(Module, BrekLev, Prompt) :-
 1006    current_prolog_flag(toplevel_prompt, PAtom),
 1007    atom_codes(PAtom, P0),
 1008    (    Module \== user
 1009    ->   '$substitute'('~m', [Module, ': '], P0, P1)
 1010    ;    '$substitute'('~m', [], P0, P1)
 1011    ),
 1012    (    BrekLev > 0
 1013    ->   '$substitute'('~l', ['[', BrekLev, '] '], P1, P2)
 1014    ;    '$substitute'('~l', [], P1, P2)
 1015    ),
 1016    current_prolog_flag(query_debug_settings, debug(Debugging, Tracing)),
 1017    (    Tracing == true
 1018    ->   '$substitute'('~d', ['[trace] '], P2, P3)
 1019    ;    Debugging == true
 1020    ->   '$substitute'('~d', ['[debug] '], P2, P3)
 1021    ;    '$substitute'('~d', [], P2, P3)
 1022    ),
 1023    atom_chars(Prompt, P3).
 1024
 1025'$substitute'(From, T, Old, New) :-
 1026    atom_codes(From, FromCodes),
 1027    phrase(subst_chars(T), T0),
 1028    '$append'(Pre, S0, Old),
 1029    '$append'(FromCodes, Post, S0) ->
 1030    '$append'(Pre, T0, S1),
 1031    '$append'(S1, Post, New),
 1032    !.
 1033'$substitute'(_, _, Old, Old).
 1034
 1035subst_chars([]) -->
 1036    [].
 1037subst_chars([H|T]) -->
 1038    { atomic(H),
 1039      !,
 1040      atom_codes(H, Codes)
 1041    },
 1042    Codes,
 1043    subst_chars(T).
 1044subst_chars([H|T]) -->
 1045    H,
 1046    subst_chars(T).
 1047
 1048
 1049                /********************************
 1050                *           EXECUTION           *
 1051                ********************************/
 $execute(Goal, Bindings) is det
Execute Goal using Bindings.
 1057'$execute'(Var, _) :-
 1058    var(Var),
 1059    !,
 1060    print_message(informational, var_query(Var)).
 1061'$execute'(Goal, Bindings) :-
 1062    '$current_typein_module'(TypeIn),
 1063    '$dwim_correct_goal'(TypeIn:Goal, Bindings, Corrected),
 1064    !,
 1065    setup_call_cleanup(
 1066        '$set_source_module'(M0, TypeIn),
 1067        expand_goal(Corrected, Expanded),
 1068        '$set_source_module'(M0)),
 1069    print_message(silent, toplevel_goal(Expanded, Bindings)),
 1070    '$execute_goal2'(Expanded, Bindings).
 1071'$execute'(_, _) :-
 1072    notrace,
 1073    print_message(query, query(no)).
 1074
 1075'$execute_goal2'(Goal, Bindings) :-
 1076    restore_debug,
 1077     '$current_typein_module'(TypeIn),
 1078    residue_vars(Goal, Vars, TypeIn:Delays),
 1079    deterministic(Det),
 1080    (   save_debug
 1081    ;   restore_debug, fail
 1082    ),
 1083    flush_output(user_output),
 1084    call_expand_answer(Bindings, NewBindings),
 1085    (    \+ \+ write_bindings(NewBindings, Vars, Delays, Det)
 1086    ->   !
 1087    ).
 1088'$execute_goal2'(_, _) :-
 1089    save_debug,
 1090    print_message(query, query(no)).
 1091
 1092residue_vars(Goal, Vars, Delays) :-
 1093    current_prolog_flag(toplevel_residue_vars, true),
 1094    !,
 1095    '$wfs_call'(call_residue_vars(Goal, Vars), Delays).
 1096residue_vars(Goal, [], Delays) :-
 1097    toplevel_call(Goal, Delays).
 1098
 1099toplevel_call(Goal, Delays) :-
 1100    '$wfs_call'(Goal, Delays),
 1101    no_lco.
 1102
 1103no_lco.
Write bindings resulting from a query. The flag prompt_alternatives_on determines whether the user is prompted for alternatives. groundness gives the classical behaviour, determinism is considered more adequate and informative.

Succeeds if the user accepts the answer and fails otherwise.

Arguments:
ResidueVars- are the residual constraints and provided if the prolog flag toplevel_residue_vars is set to project.
 1119write_bindings(Bindings, ResidueVars, Delays, Det) :-
 1120    '$current_typein_module'(TypeIn),
 1121    translate_bindings(Bindings, Bindings1, ResidueVars, TypeIn:Residuals),
 1122    omit_qualifier(Delays, TypeIn, Delays1),
 1123    write_bindings2(Bindings1, Residuals, Delays1, Det).
 1124
 1125write_bindings2([], Residuals, Delays, _) :-
 1126    current_prolog_flag(prompt_alternatives_on, groundness),
 1127    !,
 1128    print_message(query, query(yes(Delays, Residuals))).
 1129write_bindings2(Bindings, Residuals, Delays, true) :-
 1130    current_prolog_flag(prompt_alternatives_on, determinism),
 1131    !,
 1132    print_message(query, query(yes(Bindings, Delays, Residuals))).
 1133write_bindings2(Bindings, Residuals, Delays, _Det) :-
 1134    repeat,
 1135        print_message(query, query(more(Bindings, Delays, Residuals))),
 1136        get_respons(Action),
 1137    (   Action == redo
 1138    ->  !, fail
 1139    ;   Action == show_again
 1140    ->  fail
 1141    ;   !,
 1142        print_message(query, query(done))
 1143    ).
 residual_goals(:NonTerminal)
Directive that registers NonTerminal as a collector for residual goals.
 1150:- multifile
 1151    residual_goal_collector/1. 1152
 1153:- meta_predicate
 1154    residual_goals(2). 1155
 1156residual_goals(NonTerminal) :-
 1157    throw(error(context_error(nodirective, residual_goals(NonTerminal)), _)).
 1158
 1159system:term_expansion((:- residual_goals(NonTerminal)),
 1160                      '$toplevel':residual_goal_collector(M2:Head)) :-
 1161    prolog_load_context(module, M),
 1162    strip_module(M:NonTerminal, M2, Head),
 1163    '$must_be'(callable, Head).
 prolog:residual_goals// is det
DCG that collects residual goals that are not associated with the answer through attributed variables.
 1170:- public prolog:residual_goals//0. 1171
 1172prolog:residual_goals -->
 1173    { findall(NT, residual_goal_collector(NT), NTL) },
 1174    collect_residual_goals(NTL).
 1175
 1176collect_residual_goals([]) --> [].
 1177collect_residual_goals([H|T]) -->
 1178    ( call(H) -> [] ; [] ),
 1179    collect_residual_goals(T).
 prolog:translate_bindings(+Bindings0, -Bindings, +ResidueVars, +ResidualGoals, -Residuals) is det
Translate the raw variable bindings resulting from successfully completing a query into a binding list and list of residual goals suitable for human consumption.
Arguments:
Bindings- is a list of binding(Vars,Value,Substitutions), where Vars is a list of variable names. E.g. binding(['A','B'],42,[])` means that both the variable A and B have the value 42. Values may contain terms '$VAR'(Name) to indicate sharing with a given variable. Value is always an acyclic term. If cycles appear in the answer, Substitutions contains a list of substitutions that restore the original term.
Residuals- is a pair of two lists representing residual goals. The first element of the pair are residuals related to the query variables and the second are related that are disconnected from the query.
 1204:- public
 1205    prolog:translate_bindings/5. 1206:- meta_predicate
 1207    prolog:translate_bindings(+, -, +, +, :). 1208
 1209prolog:translate_bindings(Bindings0, Bindings, ResVars, ResGoals, Residuals) :-
 1210    translate_bindings(Bindings0, Bindings, ResVars, ResGoals, Residuals).
 1211
 1212translate_bindings(Bindings0, Bindings, ResidueVars, Residuals) :-
 1213    prolog:residual_goals(ResidueGoals, []),
 1214    translate_bindings(Bindings0, Bindings, ResidueVars, ResidueGoals,
 1215                       Residuals).
 1216
 1217translate_bindings(Bindings0, Bindings, [], [], _:[]-[]) :-
 1218    term_attvars(Bindings0, []),
 1219    !,
 1220    join_same_bindings(Bindings0, Bindings1),
 1221    factorize_bindings(Bindings1, Bindings2),
 1222    bind_vars(Bindings2, Bindings3),
 1223    filter_bindings(Bindings3, Bindings).
 1224translate_bindings(Bindings0, Bindings, ResidueVars, ResGoals0,
 1225                   TypeIn:Residuals-HiddenResiduals) :-
 1226    project_constraints(Bindings0, ResidueVars),
 1227    hidden_residuals(ResidueVars, Bindings0, HiddenResiduals0),
 1228    omit_qualifiers(HiddenResiduals0, TypeIn, HiddenResiduals),
 1229    copy_term(Bindings0+ResGoals0, Bindings1+ResGoals1, Residuals0),
 1230    '$append'(ResGoals1, Residuals0, Residuals1),
 1231    omit_qualifiers(Residuals1, TypeIn, Residuals),
 1232    join_same_bindings(Bindings1, Bindings2),
 1233    factorize_bindings(Bindings2, Bindings3),
 1234    bind_vars(Bindings3, Bindings4),
 1235    filter_bindings(Bindings4, Bindings).
 1236
 1237hidden_residuals(ResidueVars, Bindings, Goal) :-
 1238    term_attvars(ResidueVars, Remaining),
 1239    term_attvars(Bindings, QueryVars),
 1240    subtract_vars(Remaining, QueryVars, HiddenVars),
 1241    copy_term(HiddenVars, _, Goal).
 1242
 1243subtract_vars(All, Subtract, Remaining) :-
 1244    sort(All, AllSorted),
 1245    sort(Subtract, SubtractSorted),
 1246    ord_subtract(AllSorted, SubtractSorted, Remaining).
 1247
 1248ord_subtract([], _Not, []).
 1249ord_subtract([H1|T1], L2, Diff) :-
 1250    diff21(L2, H1, T1, Diff).
 1251
 1252diff21([], H1, T1, [H1|T1]).
 1253diff21([H2|T2], H1, T1, Diff) :-
 1254    compare(Order, H1, H2),
 1255    diff3(Order, H1, T1, H2, T2, Diff).
 1256
 1257diff12([], _H2, _T2, []).
 1258diff12([H1|T1], H2, T2, Diff) :-
 1259    compare(Order, H1, H2),
 1260    diff3(Order, H1, T1, H2, T2, Diff).
 1261
 1262diff3(<,  H1, T1,  H2, T2, [H1|Diff]) :-
 1263    diff12(T1, H2, T2, Diff).
 1264diff3(=, _H1, T1, _H2, T2, Diff) :-
 1265    ord_subtract(T1, T2, Diff).
 1266diff3(>,  H1, T1, _H2, T2, Diff) :-
 1267    diff21(T2, H1, T1, Diff).
 project_constraints(+Bindings, +ResidueVars) is det
Call <module>:project_attributes/2 if the Prolog flag toplevel_residue_vars is set to project.
 1275project_constraints(Bindings, ResidueVars) :-
 1276    !,
 1277    term_attvars(Bindings, AttVars),
 1278    phrase(attribute_modules(AttVars), Modules0),
 1279    sort(Modules0, Modules),
 1280    term_variables(Bindings, QueryVars),
 1281    project_attributes(Modules, QueryVars, ResidueVars).
 1282project_constraints(_, _).
 1283
 1284project_attributes([], _, _).
 1285project_attributes([M|T], QueryVars, ResidueVars) :-
 1286    (   current_predicate(M:project_attributes/2),
 1287        catch(M:project_attributes(QueryVars, ResidueVars), E,
 1288              print_message(error, E))
 1289    ->  true
 1290    ;   true
 1291    ),
 1292    project_attributes(T, QueryVars, ResidueVars).
 1293
 1294attribute_modules([]) --> [].
 1295attribute_modules([H|T]) -->
 1296    { get_attrs(H, Attrs) },
 1297    attrs_modules(Attrs),
 1298    attribute_modules(T).
 1299
 1300attrs_modules([]) --> [].
 1301attrs_modules(att(Module, _, More)) -->
 1302    [Module],
 1303    attrs_modules(More).
 join_same_bindings(Bindings0, Bindings)
Join variables that are bound to the same value. Note that we return the last value. This is because the factorization may be different and ultimately the names will be printed as V1 = V2, ... VN = Value. Using the last, Value has the factorization of VN.
 1314join_same_bindings([], []).
 1315join_same_bindings([Name=V0|T0], [[Name|Names]=V|T]) :-
 1316    take_same_bindings(T0, V0, V, Names, T1),
 1317    join_same_bindings(T1, T).
 1318
 1319take_same_bindings([], Val, Val, [], []).
 1320take_same_bindings([Name=V1|T0], V0, V, [Name|Names], T) :-
 1321    V0 == V1,
 1322    !,
 1323    take_same_bindings(T0, V1, V, Names, T).
 1324take_same_bindings([Pair|T0], V0, V, Names, [Pair|T]) :-
 1325    take_same_bindings(T0, V0, V, Names, T).
 omit_qualifiers(+QGoals, +TypeIn, -Goals) is det
Omit unneeded module qualifiers from QGoals relative to the given module TypeIn.
 1334omit_qualifiers([], _, []).
 1335omit_qualifiers([Goal0|Goals0], TypeIn, [Goal|Goals]) :-
 1336    omit_qualifier(Goal0, TypeIn, Goal),
 1337    omit_qualifiers(Goals0, TypeIn, Goals).
 1338
 1339omit_qualifier(M:G0, TypeIn, G) :-
 1340    M == TypeIn,
 1341    !,
 1342    omit_meta_qualifiers(G0, TypeIn, G).
 1343omit_qualifier(M:G0, TypeIn, G) :-
 1344    predicate_property(TypeIn:G0, imported_from(M)),
 1345    \+ predicate_property(G0, transparent),
 1346    !,
 1347    G0 = G.
 1348omit_qualifier(_:G0, _, G) :-
 1349    predicate_property(G0, built_in),
 1350    \+ predicate_property(G0, transparent),
 1351    !,
 1352    G0 = G.
 1353omit_qualifier(M:G0, _, M:G) :-
 1354    atom(M),
 1355    !,
 1356    omit_meta_qualifiers(G0, M, G).
 1357omit_qualifier(G0, TypeIn, G) :-
 1358    omit_meta_qualifiers(G0, TypeIn, G).
 1359
 1360omit_meta_qualifiers(V, _, V) :-
 1361    var(V),
 1362    !.
 1363omit_meta_qualifiers((QA,QB), TypeIn, (A,B)) :-
 1364    !,
 1365    omit_qualifier(QA, TypeIn, A),
 1366    omit_qualifier(QB, TypeIn, B).
 1367omit_meta_qualifiers(tnot(QA), TypeIn, tnot(A)) :-
 1368    !,
 1369    omit_qualifier(QA, TypeIn, A).
 1370omit_meta_qualifiers(freeze(V, QGoal), TypeIn, freeze(V, Goal)) :-
 1371    callable(QGoal),
 1372    !,
 1373    omit_qualifier(QGoal, TypeIn, Goal).
 1374omit_meta_qualifiers(when(Cond, QGoal), TypeIn, when(Cond, Goal)) :-
 1375    callable(QGoal),
 1376    !,
 1377    omit_qualifier(QGoal, TypeIn, Goal).
 1378omit_meta_qualifiers(G, _, G).
 bind_vars(+BindingsIn, -Bindings)
Bind variables to '$VAR'(Name), so they are printed by the names used in the query. Note that by binding in the reverse order, variables bound to one another come out in the natural order.
 1387bind_vars(Bindings0, Bindings) :-
 1388    bind_query_vars(Bindings0, Bindings, SNames),
 1389    bind_skel_vars(Bindings, Bindings, SNames, 1, _).
 1390
 1391bind_query_vars([], [], []).
 1392bind_query_vars([binding(Names,Var,[Var2=Cycle])|T0],
 1393                [binding(Names,Cycle,[])|T], [Name|SNames]) :-
 1394    Var == Var2,                   % also implies var(Var)
 1395    !,
 1396    '$last'(Names, Name),
 1397    Var = '$VAR'(Name),
 1398    bind_query_vars(T0, T, SNames).
 1399bind_query_vars([B|T0], [B|T], AllNames) :-
 1400    B = binding(Names,Var,Skel),
 1401    bind_query_vars(T0, T, SNames),
 1402    (   var(Var), \+ attvar(Var), Skel == []
 1403    ->  AllNames = [Name|SNames],
 1404        '$last'(Names, Name),
 1405        Var = '$VAR'(Name)
 1406    ;   AllNames = SNames
 1407    ).
 1408
 1409
 1410
 1411bind_skel_vars([], _, _, N, N).
 1412bind_skel_vars([binding(_,_,Skel)|T], Bindings, SNames, N0, N) :-
 1413    bind_one_skel_vars(Skel, Bindings, SNames, N0, N1),
 1414    bind_skel_vars(T, Bindings, SNames, N1, N).
 bind_one_skel_vars(+Subst, +Bindings, +VarName, +N0, -N)
Give names to the factorized variables that do not have a name yet. This introduces names _S<N>, avoiding duplicates. If a factorized variable shares with another binding, use the name of that variable.
To be done
- Consider the call below. We could remove either of the A = x(1). Which is best?
?- A = x(1), B = a(A,A).
A = x(1),
B = a(A, A), % where
    A = x(1).
 1433bind_one_skel_vars([], _, _, N, N).
 1434bind_one_skel_vars([Var=Value|T], Bindings, Names, N0, N) :-
 1435    (   var(Var)
 1436    ->  (   '$member'(binding(Names, VVal, []), Bindings),
 1437            same_term(Value, VVal)
 1438        ->  '$last'(Names, VName),
 1439            Var = '$VAR'(VName),
 1440            N2 = N0
 1441        ;   between(N0, infinite, N1),
 1442            atom_concat('_S', N1, Name),
 1443            \+ memberchk(Name, Names),
 1444            !,
 1445            Var = '$VAR'(Name),
 1446            N2 is N1 + 1
 1447        )
 1448    ;   N2 = N0
 1449    ),
 1450    bind_one_skel_vars(T, Bindings, Names, N2, N).
 factorize_bindings(+Bindings0, -Factorized)
Factorize cycles and sharing in the bindings.
 1457factorize_bindings([], []).
 1458factorize_bindings([Name=Value|T0], [binding(Name, Skel, Subst)|T]) :-
 1459    '$factorize_term'(Value, Skel, Subst0),
 1460    (   current_prolog_flag(toplevel_print_factorized, true)
 1461    ->  Subst = Subst0
 1462    ;   only_cycles(Subst0, Subst)
 1463    ),
 1464    factorize_bindings(T0, T).
 1465
 1466
 1467only_cycles([], []).
 1468only_cycles([B|T0], List) :-
 1469    (   B = (Var=Value),
 1470        Var = Value,
 1471        acyclic_term(Var)
 1472    ->  only_cycles(T0, List)
 1473    ;   List = [B|T],
 1474        only_cycles(T0, T)
 1475    ).
 filter_bindings(+Bindings0, -Bindings)
Remove bindings that must not be printed. There are two of them: Variables whose name start with '_' and variables that are only bound to themselves (or, unbound).
 1484filter_bindings([], []).
 1485filter_bindings([H0|T0], T) :-
 1486    hide_vars(H0, H),
 1487    (   (   arg(1, H, [])
 1488        ;   self_bounded(H)
 1489        )
 1490    ->  filter_bindings(T0, T)
 1491    ;   T = [H|T1],
 1492        filter_bindings(T0, T1)
 1493    ).
 1494
 1495hide_vars(binding(Names0, Skel, Subst), binding(Names, Skel, Subst)) :-
 1496    hide_names(Names0, Skel, Subst, Names).
 1497
 1498hide_names([], _, _, []).
 1499hide_names([Name|T0], Skel, Subst, T) :-
 1500    (   sub_atom(Name, 0, _, _, '_'),
 1501        current_prolog_flag(toplevel_print_anon, false),
 1502        sub_atom(Name, 1, 1, _, Next),
 1503        char_type(Next, prolog_var_start)
 1504    ->  true
 1505    ;   Subst == [],
 1506        Skel == '$VAR'(Name)
 1507    ),
 1508    !,
 1509    hide_names(T0, Skel, Subst, T).
 1510hide_names([Name|T0], Skel, Subst, [Name|T]) :-
 1511    hide_names(T0, Skel, Subst, T).
 1512
 1513self_bounded(binding([Name], Value, [])) :-
 1514    Value == '$VAR'(Name).
 get_respons(-Action)
Read the continuation entered by the user.
 1520get_respons(Action) :-
 1521    repeat,
 1522        flush_output(user_output),
 1523        get_single_char(Char),
 1524        answer_respons(Char, Action),
 1525        (   Action == again
 1526        ->  print_message(query, query(action)),
 1527            fail
 1528        ;   !
 1529        ).
 1530
 1531answer_respons(Char, again) :-
 1532    '$in_reply'(Char, '?h'),
 1533    !,
 1534    print_message(help, query(help)).
 1535answer_respons(Char, redo) :-
 1536    '$in_reply'(Char, ';nrNR \t'),
 1537    !,
 1538    print_message(query, if_tty([ansi(bold, ';', [])])).
 1539answer_respons(Char, redo) :-
 1540    '$in_reply'(Char, 'tT'),
 1541    !,
 1542    trace,
 1543    save_debug,
 1544    print_message(query, if_tty([ansi(bold, '; [trace]', [])])).
 1545answer_respons(Char, continue) :-
 1546    '$in_reply'(Char, 'ca\n\ryY.'),
 1547    !,
 1548    print_message(query, if_tty([ansi(bold, '.', [])])).
 1549answer_respons(0'b, show_again) :-
 1550    !,
 1551    break.
 1552answer_respons(Char, show_again) :-
 1553    print_predicate(Char, Pred, Options),
 1554    !,
 1555    print_message(query, if_tty(['~w'-[Pred]])),
 1556    set_prolog_flag(answer_write_options, Options).
 1557answer_respons(-1, show_again) :-
 1558    !,
 1559    print_message(query, halt('EOF')),
 1560    halt(0).
 1561answer_respons(Char, again) :-
 1562    print_message(query, no_action(Char)).
 1563
 1564print_predicate(0'w, [write], [ quoted(true),
 1565                                spacing(next_argument)
 1566                              ]).
 1567print_predicate(0'p, [print], [ quoted(true),
 1568                                portray(true),
 1569                                max_depth(10),
 1570                                spacing(next_argument)
 1571                              ]).
 1572
 1573
 1574                 /*******************************
 1575                 *          EXPANSION           *
 1576                 *******************************/
 1577
 1578:- user:dynamic(expand_query/4). 1579:- user:multifile(expand_query/4). 1580
 1581call_expand_query(Goal, Expanded, Bindings, ExpandedBindings) :-
 1582    user:expand_query(Goal, Expanded, Bindings, ExpandedBindings),
 1583    !.
 1584call_expand_query(Goal, Expanded, Bindings, ExpandedBindings) :-
 1585    toplevel_variables:expand_query(Goal, Expanded, Bindings, ExpandedBindings),
 1586    !.
 1587call_expand_query(Goal, Goal, Bindings, Bindings).
 1588
 1589
 1590:- user:dynamic(expand_answer/2). 1591:- user:multifile(expand_answer/2). 1592
 1593call_expand_answer(Goal, Expanded) :-
 1594    user:expand_answer(Goal, Expanded),
 1595    !.
 1596call_expand_answer(Goal, Expanded) :-
 1597    toplevel_variables:expand_answer(Goal, Expanded),
 1598    !.
 1599call_expand_answer(Goal, Goal)