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-2024, 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    phrase(expand_vars(Bindings, Query, Expanded), NewBindings).
   94expand_vars(Bindings, Query, Query, Bindings).
   95
   96expand_vars(_, Var, Var) -->
   97    { var(Var) },
   98    !.
   99expand_vars(_, Atomic, Atomic) -->
  100    { atomic(Atomic) },
  101    !.
  102expand_vars(Bindings, $(Var), Value) -->
  103    { name_var(Var, Bindings, Name),
  104      (   toplevel_var(Name, Value)
  105      ->  !
  106      ;   throw(error(existence_error(answer_variable, Name), _))
  107      )
  108    },
  109    [ Name = Value ].
  110expand_vars(Bindings, Term, Expanded) -->
  111    { compound_name_arity(Term, Name, Arity),
  112      !,
  113      compound_name_arity(Expanded, Name, Arity),
  114      End is Arity + 1
  115    },
  116    expand_args(1, End, Bindings, Term, Expanded).
  117
  118expand_args(End, End, _, _, _) --> !.
  119expand_args(Arg0, End, Bindings, T0, T) -->
  120    { arg(Arg0, T0, V0),
  121      arg(Arg0, T, V1),
  122      Arg1 is Arg0 + 1
  123    },
  124    expand_vars(Bindings, V0, V1),
  125    expand_args(Arg1, End, Bindings, T0, T).
  126
  127name_var(Var, [VarName = TheVar|_], VarName) :-
  128    Var == TheVar,
  129    !.
  130name_var(Var, [_|T], Name) :-
  131    name_var(Var, T, Name).
  132
  133
  134delete_bound_vars([], _, []).
  135delete_bound_vars([H|T0], Free, [H|T1]) :-
  136    H = (_Name = Value),
  137    v_member(Value, Free),
  138    !,
  139    delete_bound_vars(T0, Free, T1).
  140delete_bound_vars([_|T0], Free, T1) :-
  141    delete_bound_vars(T0, Free, T1).
  142
  143v_member(V, [H|T]) :-
  144    (   V == H
  145    ;   v_member(V, T)
  146    ).
 $save_toplevel_vars(+Bindings) is det
Save toplevel variable bindings.
  152'$save_toplevel_vars'(Bindings) :-
  153    (   current_prolog_flag(toplevel_var_size, Count),
  154        Count > 0
  155    ->  assert_bindings(Bindings)
  156    ;   true
  157    ).
  158
  159assert_bindings([]).
  160assert_bindings([Var = Value|Tail]) :-
  161    assert_binding(Var, Value),
  162    assert_bindings(Tail).
  163
  164assert_binding(Var, Value) :-
  165    (   ( nonvar(Value) ; attvar(Value))
  166    ->  update_var(Var, Value)
  167    ;   true
  168    ).
  169
  170update_var(Name, Value) :-
  171    current_prolog_flag(toplevel_mode, recursive),
  172    !,
  173    (   nb_current('$topvar', Bindings),
  174        Bindings \== []
  175    ->  true
  176    ;   Bindings = '$topvar'{}
  177    ),
  178    put_dict(Name, Bindings, Value, NewBindings),
  179    b_setval('$topvar', NewBindings).
  180update_var(Name, Value) :-
  181    delete_var(Name),
  182    set_var(Name, Value).
  183
  184delete_var(Name) :-
  185    forall(recorded('$topvar', Name = _, Ref), erase(Ref)).
  186
  187set_var(Name, Value) :-
  188    current_prolog_flag(toplevel_var_size, Count),
  189    !,
  190    (   '$term_size'(Value, Count, _)
  191    ->  recorda('$topvar', Name = Value, _)
  192    ;   true
  193    ).
  194set_var(Name, Value) :-
  195    recorda('$topvar', Name = Value, _).
  196
  197toplevel_var(Var, Binding) :-
  198    current_prolog_flag(toplevel_mode, recursive),
  199    !,
  200    nb_current('$topvar', Bindings),
  201    Bindings \== [],
  202    get_dict(Var, Bindings, Binding).
  203toplevel_var(Var, Binding) :-
  204    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.
  212'$switch_toplevel_mode'(recursive) :-
  213    findall(Name-Value, retract_topvar(Name, Value), Pairs),
  214    dict_pairs(Bindings, '$topvar', Pairs),
  215    b_setval('$topvar', Bindings).
  216'$switch_toplevel_mode'(backtracking) :-
  217    (   nb_current('$topvar', Dict),
  218        Dict \== []
  219    ->  forall(get_dict(Name, Dict, Value),
  220               recorda('$topvar', Name = Value, _))
  221    ),
  222    nb_delete('$topvar').
  223
  224retract_topvar(Name, Value) :-
  225    recorded('$topvar', Name=Value, Ref),
  226    erase(Ref).
 print_toplevel_variables
Print known bindings for toplevel ($Var) variables.
  232print_toplevel_variables :-
  233    (   toplevel_var(Name, Value)
  234    *-> format('$~w =~t~12|~p~n', [Name, Value]),
  235        fail
  236    ;   format('No defined toplevel variables~n')
  237    ).
  238
  239verbose_expansion(on) :-
  240    !,
  241    retractall(verbose),
  242    asserta(verbose).
  243verbose_expansion(off) :-
  244    retractall(verbose)