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