View source with formatted comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  1985-2016, 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_variables,
   37          [ print_toplevel_variables/0,
   38            verbose_expansion/1,
   39            '$switch_toplevel_mode'/1           % +Mode
   40          ]).   41
   42:- dynamic
   43    verbose/0.   44
   45% define the operator globally
   46:- op(1, fx, user:($)).   47
   48:- public
   49    expand_query/4,         % +Query0, -Query, +Bindings0, -Bindings
   50    expand_answer/2.        % +Answer0, -Answer
   51
   52%!  expand_query(+Query0, -Query, +Bindings0, -Bindings) is det.
   53%
   54%   These predicates realise reuse of   toplevel variables using the
   55%   $Var notation. These hooks are   normally called by toplevel.pl.
   56%   If the user defines rules for these   hooks  in the user module,
   57%   these implementations may be  called  (or   not)  to  define the
   58%   interaction with the user hooks.
   59
   60expand_query(Query, Expanded, Bindings, ExpandedBindings) :-
   61    phrase(expand_vars(Bindings, Query, Expanded), NewBindings),
   62    term_variables(Expanded, Free),
   63    delete_bound_vars(Bindings, Free, ExpandedBindings0),
   64    '$append'(ExpandedBindings0, NewBindings, ExpandedBindings),
   65    (   verbose,
   66        Query \=@= Expanded
   67    ->  print_query(Expanded, ExpandedBindings)
   68    ;   true
   69    ).
   70
   71print_query(Query, Bindings) :-
   72    bind_vars(Bindings),
   73    writeq(Query), write('.'), nl,
   74    fail.                           % undo bind_vars/2.
   75print_query(_, _).
   76
   77bind_vars([]).
   78bind_vars([Name=Value|Rest]) :-
   79    Name = Value,
   80    bind_vars(Rest).
   81
   82%!  expand_vars(+Bindings, +Query, -Expanded)//
   83%
   84%   Replace $Var terms inside Query by   the  toplevel variable term
   85%   and unify the result with  Expanded. NewBindings gets Name=Value
   86%   terms for toplevel variables that are bound to non-ground terms.
   87
   88expand_vars(_, Var, Var) -->
   89    { var(Var) },
   90    !.
   91expand_vars(_, Atomic, Atomic) -->
   92    { atomic(Atomic) },
   93    !.
   94expand_vars(Bindings, $(Var), Value) -->
   95    { name_var(Var, Bindings, Name),
   96      (   toplevel_var(Name, Value)
   97      ->  !
   98      ;   throw(error(existence_error(answer_variable, Name), _))
   99      )
  100    },
  101    [ Name = Value ].
  102expand_vars(Bindings, Term, Expanded) -->
  103    { compound_name_arity(Term, Name, Arity),
  104      !,
  105      compound_name_arity(Expanded, Name, Arity),
  106      End is Arity + 1
  107    },
  108    expand_args(1, End, Bindings, Term, Expanded).
  109
  110expand_args(End, End, _, _, _) --> !.
  111expand_args(Arg0, End, Bindings, T0, T) -->
  112    { arg(Arg0, T0, V0),
  113      arg(Arg0, T, V1),
  114      Arg1 is Arg0 + 1
  115    },
  116    expand_vars(Bindings, V0, V1),
  117    expand_args(Arg1, End, Bindings, T0, T).
  118
  119name_var(Var, [VarName = TheVar|_], VarName) :-
  120    Var == TheVar,
  121    !.
  122name_var(Var, [_|T], Name) :-
  123    name_var(Var, T, Name).
  124
  125
  126delete_bound_vars([], _, []).
  127delete_bound_vars([H|T0], Free, [H|T1]) :-
  128    H = (_Name = Value),
  129    v_member(Value, Free),
  130    !,
  131    delete_bound_vars(T0, Free, T1).
  132delete_bound_vars([_|T0], Free, T1) :-
  133    delete_bound_vars(T0, Free, T1).
  134
  135v_member(V, [H|T]) :-
  136    (   V == H
  137    ;   v_member(V, T)
  138    ).
  139
  140%!  expand_answer(+Answer0, -Answer) is det.
  141%
  142%   Save toplevel variable bindings.
  143
  144expand_answer(Bindings, Bindings) :-
  145    assert_bindings(Bindings).
  146
  147assert_bindings([]).
  148assert_bindings([Var = Value|Tail]) :-
  149    assert_binding(Var, Value),
  150    assert_bindings(Tail).
  151
  152assert_binding(Var, Value) :-
  153    (   ( nonvar(Value) ; attvar(Value))
  154    ->  update_var(Var, Value)
  155    ;   true
  156    ).
  157
  158update_var(Name, Value) :-
  159    current_prolog_flag(toplevel_mode, recursive),
  160    !,
  161    (   nb_current('$topvar', Bindings),
  162        Bindings \== []
  163    ->  true
  164    ;   Bindings = '$topvar'{}
  165    ),
  166    put_dict(Name, Bindings, Value, NewBindings),
  167    b_setval('$topvar', NewBindings).
  168update_var(Name, Value) :-
  169    delete_var(Name),
  170    set_var(Name, Value).
  171
  172delete_var(Name) :-
  173    forall(recorded('$topvar', Name = _, Ref), erase(Ref)).
  174
  175set_var(Name, Value) :-
  176    current_prolog_flag(toplevel_var_size, Count),
  177    !,
  178    (   '$term_size'(Value, Count, _)
  179    ->  recorda('$topvar', Name = Value, _)
  180    ;   true
  181    ).
  182set_var(Name, Value) :-
  183    recorda('$topvar', Name = Value, _).
  184
  185toplevel_var(Var, Binding) :-
  186    current_prolog_flag(toplevel_mode, recursive),
  187    !,
  188    nb_current('$topvar', Bindings),
  189    Bindings \== [],
  190    get_dict(Var, Bindings, Binding).
  191toplevel_var(Var, Binding) :-
  192    recorded('$topvar', Var=Binding).
  193
  194%!  '$switch_toplevel_mode'(+Mode) is det.
  195%
  196%   Migrate the variable database when switching   to a new toplevel
  197%   mode. Alternatively we may decide to wipe it as the semantics of
  198%   the variables may be slightly different.
  199
  200'$switch_toplevel_mode'(recursive) :-
  201    findall(Name-Value, retract_topvar(Name, Value), Pairs),
  202    dict_pairs(Bindings, '$topvar', Pairs),
  203    b_setval('$topvar', Bindings).
  204'$switch_toplevel_mode'(backtracking) :-
  205    (   nb_current('$topvar', Dict),
  206        Dict \== []
  207    ->  forall(get_dict(Name, Dict, Value),
  208               recorda('$topvar', Name = Value, _))
  209    ),
  210    nb_delete('$topvar').
  211
  212retract_topvar(Name, Value) :-
  213    recorded('$topvar', Name=Value, Ref),
  214    erase(Ref).
  215
  216%!  print_toplevel_variables
  217%
  218%   Print known bindings for toplevel ($Var) variables.
  219
  220print_toplevel_variables :-
  221    (   toplevel_var(Name, Value)
  222    *-> format('$~w =~t~12|~p~n', [Name, Value]),
  223        fail
  224    ;   format('No defined toplevel variables~n')
  225    ).
  226
  227verbose_expansion(on) :-
  228    !,
  229    retractall(verbose),
  230    asserta(verbose).
  231verbose_expansion(off) :-
  232    retractall(verbose)