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-2025, University of Amsterdam
    7                              VU University Amsterdam
    8                              SWI-Prolog Solutions b.v.
    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:- module(toplevel_variables,
   38          [ print_toplevel_variables/0,
   39            verbose_expansion/1,
   40            '$replace_toplevel_vars'/4,
   41            '$save_toplevel_vars'/1,            % +Bindings
   42            '$switch_toplevel_mode'/1           % +Mode
   43          ]).   44
   45:- dynamic
   46    verbose/0.   47
   48% define the operator globally
   49:- op(1, fx, user:($)).
 $replace_toplevel_vars(+Query0, -Query, +Bindings0, -Bindings) is det
These predicates realise reuse of toplevel variables using the $Var notation. These hooks are normally called by toplevel.pl. If the user defines rules for these hooks in the user module, these implementations may be called (or not) to define the interaction with the user hooks.
   59'$replace_toplevel_vars'(Query, Expanded, Bindings, ExpandedBindings) :-
   60    expand_vars(Bindings, Query, Expanded, NewBindings),
   61    term_variables(Expanded, Free),
   62    delete_bound_vars(Bindings, Free, ExpandedBindings0),
   63    '$append'(ExpandedBindings0, NewBindings, ExpandedBindings),
   64    (   verbose,
   65        Query \=@= Expanded
   66    ->  print_query(Expanded, ExpandedBindings)
   67    ;   true
   68    ).
   69
   70print_query(Query, Bindings) :-
   71    bind_vars(Bindings),
   72    writeq(Query), write('.'), nl,
   73    fail.                           % undo bind_vars/2.
   74print_query(_, _).
   75
   76bind_vars([]).
   77bind_vars([Name=Value|Rest]) :-
   78    Name = Value,
   79    bind_vars(Rest).
 expand_vars(+Bindings, +Query, -Expanded, -NewBindings) is det
Replace $Var terms inside Query by the toplevel variable term and unify the result with Expanded. NewBindings gets Name=Value terms for toplevel variables that are bound to non-ground terms.
Errors
- existence_error(answer_variable, Name)
   89expand_vars(Bindings, Query, Expanded, NewBindings) :-
   90    current_prolog_flag(toplevel_var_size, Count),
   91    Count > 0,
   92    !,
   93    do_expand_vars(Bindings, Query, Expanded, NewBindings).
   94expand_vars(Bindings, Query, Query, Bindings).
   95
   96do_expand_vars(Bindings, Query, Expanded, NewBindings) :-
   97    acyclic_term(Bindings),
   98    !,
   99    phrase(expand_vars(Bindings, Query, Expanded), NewBindings).
  100do_expand_vars(Bindings, Query, Expanded, NewBindings) :-
  101    '$factorize_term'(Query, Skel, Assignments),
  102    !,
  103    phrase(expand_vars(Bindings, Skel+Assignments, Expanded+EAssignments),
  104           NewBindings),
  105    rebind(EAssignments).
  106
  107expand_vars(_, Var, Var) -->
  108    { var(Var) },
  109    !.
  110expand_vars(_, Atomic, Atomic) -->
  111    { atomic(Atomic) },
  112    !.
  113expand_vars(Bindings, $(Var), Value) -->
  114    { name_var(Var, Bindings, Name),
  115      (   toplevel_var(Name, Value)
  116      ->  !
  117      ;   throw(error(existence_error(answer_variable, Name), _))
  118      )
  119    },
  120    [ Name = Value ].
  121expand_vars(Bindings, Term, Expanded) -->
  122    { compound_name_arity(Term, Name, Arity),
  123      !,
  124      compound_name_arity(Expanded, Name, Arity),
  125      End is Arity + 1
  126    },
  127    expand_args(1, End, Bindings, Term, Expanded).
  128
  129expand_args(End, End, _, _, _) --> !.
  130expand_args(Arg0, End, Bindings, T0, T) -->
  131    { arg(Arg0, T0, V0),
  132      arg(Arg0, T, V1),
  133      Arg1 is Arg0 + 1
  134    },
  135    expand_vars(Bindings, V0, V1),
  136    expand_args(Arg1, End, Bindings, T0, T).
  137
  138name_var(Var, [VarName = TheVar|_], VarName) :-
  139    Var == TheVar,
  140    !.
  141name_var(Var, [_|T], Name) :-
  142    name_var(Var, T, Name).
  143
  144
  145delete_bound_vars([], _, []).
  146delete_bound_vars([H|T0], Free, [H|T1]) :-
  147    H = (_Name = Value),
  148    v_member(Value, Free),
  149    !,
  150    delete_bound_vars(T0, Free, T1).
  151delete_bound_vars([_|T0], Free, T1) :-
  152    delete_bound_vars(T0, Free, T1).
  153
  154v_member(V, [H|T]) :-
  155    (   V == H
  156    ;   v_member(V, T)
  157    ).
  158
  159rebind([]).
  160rebind([Var=Value|T]) :-
  161    Var = Value,
  162    rebind(T).
 $save_toplevel_vars(+Bindings) is det
Save toplevel variable bindings.
  168'$save_toplevel_vars'(Bindings) :-
  169    (   current_prolog_flag(toplevel_var_size, Count),
  170        Count > 0
  171    ->  assert_bindings(Bindings)
  172    ;   true
  173    ).
  174
  175assert_bindings([]).
  176assert_bindings([Var = Value|Tail]) :-
  177    assert_binding(Var, Value),
  178    assert_bindings(Tail).
  179
  180assert_binding(Var, Value) :-
  181    (   ( nonvar(Value) ; attvar(Value))
  182    ->  update_var(Var, Value)
  183    ;   true
  184    ).
  185
  186update_var(Name, Value) :-
  187    current_prolog_flag(toplevel_mode, recursive),
  188    !,
  189    (   nb_current('$topvar', Bindings),
  190        Bindings \== []
  191    ->  true
  192    ;   Bindings = '$topvar'{}
  193    ),
  194    put_dict(Name, Bindings, Value, NewBindings),
  195    b_setval('$topvar', NewBindings).
  196update_var(Name, Value) :-
  197    delete_var(Name),
  198    set_var(Name, Value).
  199
  200delete_var(Name) :-
  201    forall(recorded('$topvar', Name = _, Ref), erase(Ref)).
  202
  203set_var(Name, Value) :-
  204    current_prolog_flag(toplevel_var_size, Count),
  205    !,
  206    (   '$term_size'(Value, Count, _)
  207    ->  recorda('$topvar', Name = Value, _)
  208    ;   true
  209    ).
  210set_var(Name, Value) :-
  211    recorda('$topvar', Name = Value, _).
  212
  213toplevel_var(Var, Binding) :-
  214    current_prolog_flag(toplevel_mode, recursive),
  215    !,
  216    nb_current('$topvar', Bindings),
  217    Bindings \== [],
  218    get_dict(Var, Bindings, Binding).
  219toplevel_var(Var, Binding) :-
  220    recorded('$topvar', Var=Binding).
 $switch_toplevel_mode(+Mode) is det
Migrate the variable database when switching to a new toplevel mode. Alternatively we may decide to wipe it as the semantics of the variables may be slightly different.
  228'$switch_toplevel_mode'(recursive) :-
  229    findall(Name-Value, retract_topvar(Name, Value), Pairs),
  230    dict_pairs(Bindings, '$topvar', Pairs),
  231    b_setval('$topvar', Bindings).
  232'$switch_toplevel_mode'(backtracking) :-
  233    (   nb_current('$topvar', Dict),
  234        Dict \== []
  235    ->  forall(get_dict(Name, Dict, Value),
  236               recorda('$topvar', Name = Value, _))
  237    ),
  238    nb_delete('$topvar').
  239
  240retract_topvar(Name, Value) :-
  241    recorded('$topvar', Name=Value, Ref),
  242    erase(Ref).
 print_toplevel_variables
Print known bindings for toplevel ($Var) variables.
  248print_toplevel_variables :-
  249    (   toplevel_var(Name, Value)
  250    *-> format('$~w =~t~12|~p~n', [Name, Value]),
  251        fail
  252    ;   format('No defined toplevel variables~n')
  253    ).
  254
  255verbose_expansion(on) :-
  256    !,
  257    retractall(verbose),
  258    asserta(verbose).
  259verbose_expansion(off) :-
  260    retractall(verbose)