35
36:- module(toplevel_variables,
37 [ print_toplevel_variables/0,
38 verbose_expansion/1,
39 '$switch_toplevel_mode'/1 40 ]). 41
42:- dynamic
43 verbose/0. 44
46:- op(1, fx, user:($)). 47
48:- public
49 expand_query/4, 50 expand_answer/2. 51
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. 75print_query(_, _).
76
77bind_vars([]).
78bind_vars([Name=Value|Rest]) :-
79 Name = Value,
80 bind_vars(Rest).
81
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
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
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
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)